feat(server): migrate all logging to pino
- Add pino with pino-pretty for structured logging
- Create root logger in index.ts with child loggers per module
- Support log level via PASEO_LOG env var and config.json
- Support log format (pretty/json) via PASEO_LOG_FORMAT and config.json
- Replace all console.* in runtime code with appropriate log levels
- Scripts use process.stdout/stderr for output
- Error logging uses correct pattern: logger.error({ err }, msg)
This commit is contained in:
@@ -53,15 +53,6 @@ describe("Claude Agent SDK Commands POC", () => {
|
||||
// Should be an array
|
||||
expect(Array.isArray(commands)).toBe(true);
|
||||
|
||||
// Log what we found
|
||||
console.log(`[Test] Found ${commands.length} commands:`);
|
||||
commands.slice(0, 10).forEach((cmd) => {
|
||||
console.log(` - /${cmd.name}: ${cmd.description} [${cmd.argumentHint}]`);
|
||||
});
|
||||
if (commands.length > 10) {
|
||||
console.log(` ... and ${commands.length - 10} more`);
|
||||
}
|
||||
|
||||
// Verify structure
|
||||
if (commands.length > 0) {
|
||||
const firstCommand = commands[0];
|
||||
|
||||
@@ -57,9 +57,9 @@ class Pushable<T> implements AsyncIterable<T> {
|
||||
}
|
||||
|
||||
async function investigateCommand(commandName: string): Promise<void> {
|
||||
console.log(`\n${"=".repeat(60)}`);
|
||||
console.log(`Investigating: /${commandName}`);
|
||||
console.log("=".repeat(60));
|
||||
process.stdout.write(`\n${"=".repeat(60)}\n`);
|
||||
process.stdout.write(`Investigating: /${commandName}\n`);
|
||||
process.stdout.write(`${"=".repeat(60)}\n`);
|
||||
|
||||
const input = new Pushable<SDKUserMessage>();
|
||||
|
||||
@@ -89,70 +89,70 @@ async function investigateCommand(commandName: string): Promise<void> {
|
||||
let messageCount = 0;
|
||||
for await (const message of claudeQuery) {
|
||||
messageCount++;
|
||||
console.log(`\n--- Message ${messageCount} ---`);
|
||||
console.log(`Type: ${message.type}`);
|
||||
process.stdout.write(`\n--- Message ${messageCount} ---\n`);
|
||||
process.stdout.write(`Type: ${message.type}\n`);
|
||||
|
||||
// Log the full structure based on type
|
||||
switch (message.type) {
|
||||
case "system":
|
||||
console.log(`Subtype: ${message.subtype}`);
|
||||
process.stdout.write(`Subtype: ${message.subtype}\n`);
|
||||
if (message.subtype === "init") {
|
||||
console.log(`Session: ${message.session_id}`);
|
||||
console.log(`Model: ${message.model}`);
|
||||
process.stdout.write(`Session: ${message.session_id}\n`);
|
||||
process.stdout.write(`Model: ${message.model}\n`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "user":
|
||||
console.log(`User message content:`, JSON.stringify(message.message?.content, null, 2));
|
||||
process.stdout.write(`User message content: ${JSON.stringify(message.message?.content, null, 2)}\n`);
|
||||
break;
|
||||
|
||||
case "assistant":
|
||||
console.log(`Assistant message content:`);
|
||||
process.stdout.write("Assistant message content:\n");
|
||||
const content = message.message?.content;
|
||||
if (Array.isArray(content)) {
|
||||
for (const block of content) {
|
||||
console.log(` Block type: ${block.type}`);
|
||||
process.stdout.write(` Block type: ${block.type}\n`);
|
||||
if (block.type === "text") {
|
||||
console.log(` Text: ${block.text}`);
|
||||
process.stdout.write(` Text: ${block.text}\n`);
|
||||
} else if (block.type === "tool_use") {
|
||||
console.log(` Tool: ${block.name}`);
|
||||
console.log(` Input: ${JSON.stringify(block.input, null, 2)}`);
|
||||
process.stdout.write(` Tool: ${block.name}\n`);
|
||||
process.stdout.write(` Input: ${JSON.stringify(block.input, null, 2)}\n`);
|
||||
} else {
|
||||
console.log(` Full block: ${JSON.stringify(block, null, 2)}`);
|
||||
process.stdout.write(` Full block: ${JSON.stringify(block, null, 2)}\n`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(` Content: ${JSON.stringify(content, null, 2)}`);
|
||||
process.stdout.write(` Content: ${JSON.stringify(content, null, 2)}\n`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "stream_event":
|
||||
console.log(`Stream event type: ${message.event?.type}`);
|
||||
process.stdout.write(`Stream event type: ${message.event?.type}\n`);
|
||||
if (message.event?.type === "content_block_delta") {
|
||||
const delta = message.event.delta;
|
||||
if (delta?.type === "text_delta") {
|
||||
console.log(` Text delta: ${delta.text}`);
|
||||
process.stdout.write(` Text delta: ${delta.text}\n`);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "result":
|
||||
console.log(`Result subtype: ${message.subtype}`);
|
||||
process.stdout.write(`Result subtype: ${message.subtype}\n`);
|
||||
if ("errors" in message && message.errors) {
|
||||
console.log(`Errors: ${JSON.stringify(message.errors)}`);
|
||||
process.stdout.write(`Errors: ${JSON.stringify(message.errors)}\n`);
|
||||
}
|
||||
// Check for any other properties
|
||||
const resultKeys = Object.keys(message).filter(k => !["type", "subtype"].includes(k));
|
||||
if (resultKeys.length > 0) {
|
||||
console.log(`Other result properties: ${resultKeys.join(", ")}`);
|
||||
process.stdout.write(`Other result properties: ${resultKeys.join(", ")}\n`);
|
||||
for (const key of resultKeys) {
|
||||
console.log(` ${key}: ${JSON.stringify((message as any)[key], null, 2)}`);
|
||||
process.stdout.write(` ${key}: ${JSON.stringify((message as any)[key], null, 2)}\n`);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`Full message: ${JSON.stringify(message, null, 2)}`);
|
||||
process.stdout.write(`Full message: ${JSON.stringify(message, null, 2)}\n`);
|
||||
}
|
||||
|
||||
if (message.type === "result") {
|
||||
@@ -160,7 +160,7 @@ async function investigateCommand(commandName: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nTotal messages received: ${messageCount}`);
|
||||
process.stdout.write(`\nTotal messages received: ${messageCount}\n`);
|
||||
|
||||
} finally {
|
||||
input.end();
|
||||
@@ -169,7 +169,7 @@ async function investigateCommand(commandName: string): Promise<void> {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("=== Command Output Investigation ===\n");
|
||||
process.stdout.write("=== Command Output Investigation ===\n\n");
|
||||
|
||||
// Test /context - a local command that shows context info
|
||||
await investigateCommand("context");
|
||||
@@ -180,10 +180,10 @@ async function main() {
|
||||
// Test /prompt-engineer - a SKILL (not a local command)
|
||||
await investigateCommand("prompt-engineer");
|
||||
|
||||
console.log("\n=== Investigation Complete ===");
|
||||
process.stdout.write("\n=== Investigation Complete ===\n");
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Fatal error:", error);
|
||||
process.stderr.write(`Fatal error: ${error}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ async function listAvailableCommands(): Promise<SlashCommand[]> {
|
||||
}
|
||||
|
||||
async function executeCommand(commandName: string): Promise<void> {
|
||||
console.log(`\n=== Executing command: /${commandName} ===`);
|
||||
process.stdout.write(`\n=== Executing command: /${commandName} ===\n`);
|
||||
|
||||
// For command execution, we need a proper input stream
|
||||
const input = new Pushable<SDKUserMessage>();
|
||||
@@ -136,12 +136,12 @@ async function executeCommand(commandName: string): Promise<void> {
|
||||
// Iterate the query to process the command
|
||||
let gotSystemInit = false;
|
||||
for await (const message of claudeQuery) {
|
||||
console.log(` [${message.type}]`, message.type === "system" ? message.subtype : "");
|
||||
process.stdout.write(` [${message.type}] ${message.type === "system" ? message.subtype : ""}\n`);
|
||||
|
||||
if (message.type === "system" && message.subtype === "init") {
|
||||
gotSystemInit = true;
|
||||
console.log(" Session:", message.session_id);
|
||||
console.log(" Model:", message.model);
|
||||
process.stdout.write(` Session: ${message.session_id}\n`);
|
||||
process.stdout.write(` Model: ${message.model}\n`);
|
||||
}
|
||||
|
||||
if (message.type === "assistant") {
|
||||
@@ -149,14 +149,14 @@ async function executeCommand(commandName: string): Promise<void> {
|
||||
if (Array.isArray(content)) {
|
||||
for (const block of content) {
|
||||
if (block.type === "text") {
|
||||
console.log(" Response:", block.text.slice(0, 200) + (block.text.length > 200 ? "..." : ""));
|
||||
process.stdout.write(` Response: ${block.text.slice(0, 200)}${block.text.length > 200 ? "..." : ""}\n`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.type === "result") {
|
||||
console.log(" Result:", message.subtype);
|
||||
process.stdout.write(` Result: ${message.subtype}\n`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -167,48 +167,48 @@ async function executeCommand(commandName: string): Promise<void> {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("=== Claude Agent SDK Commands POC ===\n");
|
||||
process.stdout.write("=== Claude Agent SDK Commands POC ===\n\n");
|
||||
|
||||
// PART 1: List available commands using supportedCommands()
|
||||
console.log("=== Part 1: List Available Commands ===\n");
|
||||
process.stdout.write("=== Part 1: List Available Commands ===\n\n");
|
||||
|
||||
try {
|
||||
const commands = await listAvailableCommands();
|
||||
|
||||
console.log(`Found ${commands.length} commands:\n`);
|
||||
process.stdout.write(`Found ${commands.length} commands:\n\n`);
|
||||
commands.forEach((cmd, index) => {
|
||||
console.log(` ${index + 1}. /${cmd.name}`);
|
||||
console.log(` Description: ${cmd.description}`);
|
||||
process.stdout.write(` ${index + 1}. /${cmd.name}\n`);
|
||||
process.stdout.write(` Description: ${cmd.description}\n`);
|
||||
if (cmd.argumentHint) {
|
||||
console.log(` Arguments: ${cmd.argumentHint}`);
|
||||
process.stdout.write(` Arguments: ${cmd.argumentHint}\n`);
|
||||
}
|
||||
console.log("");
|
||||
process.stdout.write("\n");
|
||||
});
|
||||
|
||||
// PART 2: Demonstrate command execution (optional - uncomment to test)
|
||||
// Commands are just prompts sent with / prefix
|
||||
console.log("=== Part 2: Command Execution Explanation ===");
|
||||
console.log("");
|
||||
console.log("Commands are executed by sending them as prompts with / prefix.");
|
||||
console.log("For example, to execute the 'help' command:");
|
||||
console.log(' 1. Create a user message with content: "/help"');
|
||||
console.log(" 2. Push it to the input stream");
|
||||
console.log(" 3. Iterate the query to receive responses");
|
||||
console.log("");
|
||||
process.stdout.write("=== Part 2: Command Execution Explanation ===\n");
|
||||
process.stdout.write("\n");
|
||||
process.stdout.write("Commands are executed by sending them as prompts with / prefix.\n");
|
||||
process.stdout.write("For example, to execute the 'help' command:\n");
|
||||
process.stdout.write(' 1. Create a user message with content: "/help"\n');
|
||||
process.stdout.write(" 2. Push it to the input stream\n");
|
||||
process.stdout.write(" 3. Iterate the query to receive responses\n");
|
||||
process.stdout.write("\n");
|
||||
|
||||
// Actually execute a command to demonstrate it works:
|
||||
// Using "context" as it's fast and doesn't require arguments
|
||||
await executeCommand("context");
|
||||
|
||||
} catch (error) {
|
||||
console.error("ERROR:", error);
|
||||
process.stderr.write(`ERROR: ${error}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("=== POC Complete ===");
|
||||
process.stdout.write("=== POC Complete ===\n");
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Fatal error:", error);
|
||||
process.stderr.write(`Fatal error: ${error}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user