@secemp/elwood 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +132 -0
- package/examples/01-basic-query.js +38 -0
- package/examples/02-bug-fixer.js +57 -0
- package/examples/03-custom-system-prompt.js +41 -0
- package/examples/04-read-only-agent.js +38 -0
- package/examples/05-find-todos.js +37 -0
- package/examples/06-session-resume.js +70 -0
- package/examples/07-hooks-pretooluse.js +74 -0
- package/examples/08-hooks-posttooluse-audit.js +66 -0
- package/examples/09-hooks-block-etc.js +68 -0
- package/examples/10-hooks-redirect-sandbox.js +70 -0
- package/examples/11-subagents.js +54 -0
- package/examples/12-mcp-stdio.js +48 -0
- package/examples/13-mcp-http.js +54 -0
- package/examples/14-custom-tool.js +84 -0
- package/examples/15-custom-tool-unit-converter.js +132 -0
- package/examples/16-mcp-github.js +71 -0
- package/examples/17-session-store-postgres.js +78 -0
- package/examples/18-session-store-redis.js +65 -0
- package/examples/19-session-store-s3.js +67 -0
- package/examples/20-session-list.js +72 -0
- package/examples/21-hooks-notification-slack.js +78 -0
- package/examples/22-hooks-webhook-posttooluse.js +78 -0
- package/examples/23-hooks-subagent-tracker.js +59 -0
- package/examples/24-v2-session-api.js +62 -0
- package/examples/README.md +95 -0
- package/examples/basic.js +240 -0
- package/examples/smoke-test.js +296 -0
- package/package.json +52 -0
- package/src/ast-tools.js +182 -0
- package/src/index.js +70 -0
- package/src/instrumenter.js +2921 -0
- package/src/loader.js +306 -0
- package/src/locate.js +296 -0
- package/src/query.js +2168 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 19-session-store-s3.js
|
|
3
|
+
*
|
|
4
|
+
* Equivalent of the official examples/session-stores/s3/demo.ts
|
|
5
|
+
*
|
|
6
|
+
* Official version:
|
|
7
|
+
* import { S3Client } from '@aws-sdk/client-s3';
|
|
8
|
+
* import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
9
|
+
* import { S3SessionStore } from './src/S3SessionStore.ts';
|
|
10
|
+
*
|
|
11
|
+
* const client = new S3Client({ region, endpoint, forcePathStyle });
|
|
12
|
+
* const store = new S3SessionStore({ bucket, prefix: 'demo', client });
|
|
13
|
+
*
|
|
14
|
+
* for await (const m of query({
|
|
15
|
+
* prompt, options: { sessionStore: store, resume, maxTurns: 1 }
|
|
16
|
+
* })) { ... }
|
|
17
|
+
*
|
|
18
|
+
* This elwood version shows how to use an S3-backed session store
|
|
19
|
+
* with elwood's query() function. The session store adapter is identical
|
|
20
|
+
* to the official example since it is a pure S3 adapter.
|
|
21
|
+
*
|
|
22
|
+
* Prerequisites:
|
|
23
|
+
* - ANTHROPIC_API_KEY set in environment
|
|
24
|
+
* - Claude Code CLI installed
|
|
25
|
+
* - S3-compatible endpoint (e.g. MinIO)
|
|
26
|
+
* - SESSION_STORE_S3_BUCKET set
|
|
27
|
+
* - AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY set
|
|
28
|
+
* - npm install @aws-sdk/client-s3
|
|
29
|
+
*
|
|
30
|
+
* Run:
|
|
31
|
+
* SESSION_STORE_S3_ENDPOINT=http://localhost:9000 \
|
|
32
|
+
* SESSION_STORE_S3_BUCKET=claude-sessions \
|
|
33
|
+
* AWS_ACCESS_KEY_ID=minioadmin AWS_SECRET_ACCESS_KEY=minioadmin \
|
|
34
|
+
* node examples/19-session-store-s3.js
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { query } from '../src/index.js';
|
|
38
|
+
|
|
39
|
+
// Note: You would need to implement or import an S3SessionStore adapter.
|
|
40
|
+
// The adapter is identical to the official example since it is pure S3 logic.
|
|
41
|
+
// See: https://github.com/anthropics/claude-agent-sdk-typescript/tree/main/examples/session-stores/s3
|
|
42
|
+
|
|
43
|
+
const bucket = process.env.SESSION_STORE_S3_BUCKET;
|
|
44
|
+
if (!bucket) {
|
|
45
|
+
console.error('Set SESSION_STORE_S3_BUCKET (see header for MinIO setup)');
|
|
46
|
+
console.error(
|
|
47
|
+
'\nFor local testing with MinIO:\n' +
|
|
48
|
+
' docker run -d -p 9000:9000 minio/minio server /data\n' +
|
|
49
|
+
' docker run --rm --network host minio/mc \\\n' +
|
|
50
|
+
' sh -c \'mc alias set local http://localhost:9000 minioadmin minioadmin && mc mb local/claude-sessions\''
|
|
51
|
+
);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log('To use this example, implement or import an S3SessionStore adapter.');
|
|
56
|
+
console.log('The adapter is identical to the official claude-agent-sdk example.');
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log('Usage pattern with elwood:');
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log(' import { query } from "elwood";');
|
|
61
|
+
console.log(' // import { S3Client } from "@aws-sdk/client-s3";');
|
|
62
|
+
console.log(' // import { S3SessionStore } from "./S3SessionStore.js";');
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log(' const client = new S3Client({ region, endpoint, forcePathStyle });');
|
|
65
|
+
console.log(` const store = new S3SessionStore({ bucket: "${bucket}", prefix: "demo", client });`);
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(' // Then use query() exactly as with the official SDK');
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 20-session-list.js
|
|
3
|
+
*
|
|
4
|
+
* Equivalent of the official "list sessions / get session messages" example.
|
|
5
|
+
*
|
|
6
|
+
* Official version:
|
|
7
|
+
* import { listSessions, getSessionMessages } from "@anthropic-ai/claude-agent-sdk";
|
|
8
|
+
*
|
|
9
|
+
* const sessions = await listSessions({ dir: "/path/to/project", limit: 10 });
|
|
10
|
+
* for (const session of sessions) {
|
|
11
|
+
* console.log(`${session.summary} (${session.sessionId})`);
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* const [latest] = await listSessions({ dir: "/path/to/project", limit: 1 });
|
|
15
|
+
* if (latest) {
|
|
16
|
+
* const messages = await getSessionMessages(latest.sessionId, {
|
|
17
|
+
* dir: "/path/to/project", limit: 20
|
|
18
|
+
* });
|
|
19
|
+
* for (const msg of messages) {
|
|
20
|
+
* console.log(`[${msg.type}] ${msg.uuid}`);
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* This elwood version uses the file-system-based session utilities that
|
|
25
|
+
* read from ~/.claude/projects/*.jsonl directly.
|
|
26
|
+
*
|
|
27
|
+
* Prerequisites:
|
|
28
|
+
* - Claude Code CLI installed (sessions are stored in ~/.claude/projects/)
|
|
29
|
+
*
|
|
30
|
+
* Run:
|
|
31
|
+
* node examples/20-session-list.js
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { listSessions, getSessionMessages, getSessionInfo } from '../src/index.js';
|
|
35
|
+
|
|
36
|
+
// List all sessions (most recent first)
|
|
37
|
+
console.log('--- Recent sessions ---');
|
|
38
|
+
const sessions = await listSessions();
|
|
39
|
+
|
|
40
|
+
if (sessions.length === 0) {
|
|
41
|
+
console.log('No sessions found. Run a query first to create one.');
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Show the first 10 sessions
|
|
46
|
+
for (const session of sessions.slice(0, 10)) {
|
|
47
|
+
console.log(` ${session.sessionId} (${session.mtime.toISOString()}) [${session.projectPath}]`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Get details about the most recent session
|
|
51
|
+
const latest = sessions[0];
|
|
52
|
+
console.log(`\n--- Session info: ${latest.sessionId} ---`);
|
|
53
|
+
const info = await getSessionInfo(latest.sessionId);
|
|
54
|
+
if (info) {
|
|
55
|
+
console.log(` File: ${info.filePath}`);
|
|
56
|
+
console.log(` Messages: ${info.messageCount}`);
|
|
57
|
+
console.log(` Last modified: ${info.mtime.toISOString()}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Read messages from the most recent session
|
|
61
|
+
console.log(`\n--- Messages from: ${latest.sessionId} ---`);
|
|
62
|
+
const messages = await getSessionMessages(latest.sessionId);
|
|
63
|
+
for (const msg of messages.slice(0, 5)) {
|
|
64
|
+
const type = msg.type ?? '(unknown)';
|
|
65
|
+
const role = msg.message?.role ?? msg.role ?? '';
|
|
66
|
+
const preview = JSON.stringify(msg).slice(0, 100);
|
|
67
|
+
console.log(` [${type}${role ? '/' + role : ''}] ${preview}...`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (messages.length > 5) {
|
|
71
|
+
console.log(` ... and ${messages.length - 5} more messages`);
|
|
72
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 21-hooks-notification-slack.js
|
|
3
|
+
*
|
|
4
|
+
* Equivalent of the official "forward notifications to Slack" hooks example.
|
|
5
|
+
*
|
|
6
|
+
* Official version:
|
|
7
|
+
* import { query, HookCallback, NotificationHookInput } from "@anthropic-ai/claude-agent-sdk";
|
|
8
|
+
*
|
|
9
|
+
* const notificationHandler: HookCallback = async (input, toolUseID, { signal }) => {
|
|
10
|
+
* const notification = input as NotificationHookInput;
|
|
11
|
+
* try {
|
|
12
|
+
* await fetch("https://hooks.slack.com/services/YOUR/WEBHOOK/URL", {
|
|
13
|
+
* method: "POST",
|
|
14
|
+
* headers: { "Content-Type": "application/json" },
|
|
15
|
+
* body: JSON.stringify({ text: `Agent status: ${notification.message}` }),
|
|
16
|
+
* signal
|
|
17
|
+
* });
|
|
18
|
+
* } catch (error) { ... }
|
|
19
|
+
* return {};
|
|
20
|
+
* };
|
|
21
|
+
*
|
|
22
|
+
* This elwood version forwards agent notifications to a Slack webhook.
|
|
23
|
+
*
|
|
24
|
+
* Prerequisites:
|
|
25
|
+
* - ANTHROPIC_API_KEY set in environment
|
|
26
|
+
* - Claude Code CLI installed
|
|
27
|
+
* - SLACK_WEBHOOK_URL set to your Slack incoming webhook URL
|
|
28
|
+
*
|
|
29
|
+
* Run:
|
|
30
|
+
* SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
|
|
31
|
+
* node examples/21-hooks-notification-slack.js
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { query } from '../src/index.js';
|
|
35
|
+
|
|
36
|
+
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
|
|
37
|
+
if (!SLACK_WEBHOOK_URL) {
|
|
38
|
+
console.error('Set SLACK_WEBHOOK_URL to your Slack incoming webhook URL');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Define a hook callback that sends notifications to Slack
|
|
43
|
+
const notificationHandler = async (input, _toolUseID, { signal }) => {
|
|
44
|
+
const message = input.message ?? '(no message)';
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await fetch(SLACK_WEBHOOK_URL, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: { 'Content-Type': 'application/json' },
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
text: `Agent status: ${message}`,
|
|
52
|
+
}),
|
|
53
|
+
signal,
|
|
54
|
+
});
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
57
|
+
console.log('Notification cancelled');
|
|
58
|
+
} else {
|
|
59
|
+
console.error('Failed to send notification:', error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Return empty object. Notification hooks don't modify agent behavior.
|
|
64
|
+
return {};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Register the hook for Notification events (no matcher needed)
|
|
68
|
+
for await (const message of query({
|
|
69
|
+
prompt: 'Analyze this codebase',
|
|
70
|
+
options: {
|
|
71
|
+
hooks: {
|
|
72
|
+
Notification: [{ hooks: [notificationHandler] }],
|
|
73
|
+
},
|
|
74
|
+
maxTurns: 5,
|
|
75
|
+
},
|
|
76
|
+
})) {
|
|
77
|
+
console.log(message);
|
|
78
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 22-hooks-webhook-posttooluse.js
|
|
3
|
+
*
|
|
4
|
+
* Equivalent of the official "make HTTP requests from hooks" example.
|
|
5
|
+
*
|
|
6
|
+
* Official version:
|
|
7
|
+
* const webhookNotifier: HookCallback = async (input, toolUseID, { signal }) => {
|
|
8
|
+
* if (input.hook_event_name !== "PostToolUse") return {};
|
|
9
|
+
* try {
|
|
10
|
+
* await fetch("https://api.example.com/webhook", {
|
|
11
|
+
* method: "POST",
|
|
12
|
+
* headers: { "Content-Type": "application/json" },
|
|
13
|
+
* body: JSON.stringify({
|
|
14
|
+
* tool: (input as PostToolUseHookInput).tool_name,
|
|
15
|
+
* timestamp: new Date().toISOString()
|
|
16
|
+
* }),
|
|
17
|
+
* signal
|
|
18
|
+
* });
|
|
19
|
+
* } catch (error) { ... }
|
|
20
|
+
* return {};
|
|
21
|
+
* };
|
|
22
|
+
*
|
|
23
|
+
* This elwood version sends a webhook notification after each tool completes.
|
|
24
|
+
*
|
|
25
|
+
* Prerequisites:
|
|
26
|
+
* - ANTHROPIC_API_KEY set in environment
|
|
27
|
+
* - Claude Code CLI installed
|
|
28
|
+
* - WEBHOOK_URL set to your webhook endpoint
|
|
29
|
+
*
|
|
30
|
+
* Run:
|
|
31
|
+
* WEBHOOK_URL=https://api.example.com/webhook node examples/22-hooks-webhook-posttooluse.js
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { query } from '../src/index.js';
|
|
35
|
+
|
|
36
|
+
const WEBHOOK_URL = process.env.WEBHOOK_URL ?? 'https://httpbin.org/post';
|
|
37
|
+
|
|
38
|
+
// Define a webhook notifier that fires after each tool completes
|
|
39
|
+
const webhookNotifier = async (input, _toolUseID, { signal }) => {
|
|
40
|
+
// Only fire after a tool completes (PostToolUse), not before
|
|
41
|
+
if (input.hook_event_name !== 'PostToolUse') return {};
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await fetch(WEBHOOK_URL, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
body: JSON.stringify({
|
|
48
|
+
tool: input.tool_name,
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
}),
|
|
51
|
+
// Pass signal so the request cancels if the hook times out
|
|
52
|
+
signal,
|
|
53
|
+
});
|
|
54
|
+
console.log(`[webhook] Notified about tool: ${input.tool_name}`);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
57
|
+
console.log('[webhook] Request cancelled');
|
|
58
|
+
}
|
|
59
|
+
// Don't re-throw. A failed webhook shouldn't stop the agent.
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Register as a PostToolUse hook
|
|
66
|
+
for await (const message of query({
|
|
67
|
+
prompt: 'Refactor the auth module',
|
|
68
|
+
options: {
|
|
69
|
+
hooks: {
|
|
70
|
+
PostToolUse: [{ hooks: [webhookNotifier] }],
|
|
71
|
+
},
|
|
72
|
+
maxTurns: 5,
|
|
73
|
+
},
|
|
74
|
+
})) {
|
|
75
|
+
if (message.type === 'result') {
|
|
76
|
+
console.log(message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 23-hooks-subagent-tracker.js
|
|
3
|
+
*
|
|
4
|
+
* Equivalent of the official "track subagent activity" hooks example.
|
|
5
|
+
*
|
|
6
|
+
* Official version:
|
|
7
|
+
* import { HookCallback, SubagentStopHookInput } from "@anthropic-ai/claude-agent-sdk";
|
|
8
|
+
*
|
|
9
|
+
* const subagentTracker: HookCallback = async (input, toolUseID, { signal }) => {
|
|
10
|
+
* const subInput = input as SubagentStopHookInput;
|
|
11
|
+
* console.log(`[SUBAGENT] Completed: ${subInput.agent_id}`);
|
|
12
|
+
* console.log(` Transcript: ${subInput.agent_transcript_path}`);
|
|
13
|
+
* console.log(` Tool use ID: ${toolUseID}`);
|
|
14
|
+
* console.log(` Stop hook active: ${subInput.stop_hook_active}`);
|
|
15
|
+
* return {};
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* This elwood version monitors subagent lifecycle using SubagentStop hooks.
|
|
19
|
+
*
|
|
20
|
+
* Prerequisites:
|
|
21
|
+
* - ANTHROPIC_API_KEY set in environment
|
|
22
|
+
* - Claude Code CLI installed
|
|
23
|
+
*
|
|
24
|
+
* Run:
|
|
25
|
+
* node examples/23-hooks-subagent-tracker.js
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { query } from '../src/index.js';
|
|
29
|
+
|
|
30
|
+
// Track subagent activity with a SubagentStop hook
|
|
31
|
+
const subagentTracker = async (input, toolUseID, { signal }) => {
|
|
32
|
+
console.log(`[SUBAGENT] Completed: ${input.agent_id}`);
|
|
33
|
+
console.log(` Transcript: ${input.agent_transcript_path}`);
|
|
34
|
+
console.log(` Tool use ID: ${toolUseID}`);
|
|
35
|
+
console.log(` Stop hook active: ${input.stop_hook_active}`);
|
|
36
|
+
return {};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
for await (const message of query({
|
|
40
|
+
prompt: 'Use the code-reviewer agent to review this codebase',
|
|
41
|
+
options: {
|
|
42
|
+
allowedTools: ['Read', 'Glob', 'Grep', 'Agent'],
|
|
43
|
+
agents: {
|
|
44
|
+
'code-reviewer': {
|
|
45
|
+
description: 'Expert code reviewer.',
|
|
46
|
+
prompt: 'Analyze code quality and suggest improvements.',
|
|
47
|
+
tools: ['Read', 'Glob', 'Grep'],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
hooks: {
|
|
51
|
+
SubagentStop: [{ hooks: [subagentTracker] }],
|
|
52
|
+
},
|
|
53
|
+
maxTurns: 10,
|
|
54
|
+
},
|
|
55
|
+
})) {
|
|
56
|
+
if ('result' in message) {
|
|
57
|
+
console.log(message.result);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 24-v2-session-api.js
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the V2 Session API (UNSTABLE) for multi-turn conversations.
|
|
5
|
+
*
|
|
6
|
+
* The official SDK provides unstable_v2_createSession, unstable_v2_resumeSession,
|
|
7
|
+
* and unstable_v2_prompt. This elwood version wraps the same interface.
|
|
8
|
+
*
|
|
9
|
+
* The V2 API provides a Session object that manages state across multiple
|
|
10
|
+
* send/stream cycles, rather than using separate query() calls with resume.
|
|
11
|
+
*
|
|
12
|
+
* Prerequisites:
|
|
13
|
+
* - ANTHROPIC_API_KEY set in environment
|
|
14
|
+
* - Claude Code CLI installed
|
|
15
|
+
*
|
|
16
|
+
* Run:
|
|
17
|
+
* node examples/24-v2-session-api.js
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
unstable_v2_createSession,
|
|
22
|
+
unstable_v2_prompt,
|
|
23
|
+
} from '../src/index.js';
|
|
24
|
+
|
|
25
|
+
// --- Example 1: One-shot prompt with unstable_v2_prompt ---
|
|
26
|
+
console.log('--- V2 one-shot prompt ---');
|
|
27
|
+
try {
|
|
28
|
+
const result = await unstable_v2_prompt('What is 2 + 2?', {
|
|
29
|
+
model: undefined, // use default model
|
|
30
|
+
});
|
|
31
|
+
console.log('Result:', result);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.log('V2 prompt requires a running session (expected in dry-run):', err.message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// --- Example 2: Multi-turn session with unstable_v2_createSession ---
|
|
37
|
+
console.log('\n--- V2 multi-turn session ---');
|
|
38
|
+
const session = unstable_v2_createSession({});
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// First turn
|
|
42
|
+
await session.send('Remember the number 42.');
|
|
43
|
+
for await (const msg of session.stream()) {
|
|
44
|
+
if (msg.type === 'result') {
|
|
45
|
+
console.log('Turn 1 result:', msg);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Second turn (continues with context from the first)
|
|
51
|
+
await session.send('What number did I tell you to remember?');
|
|
52
|
+
for await (const msg of session.stream()) {
|
|
53
|
+
if (msg.type === 'result') {
|
|
54
|
+
console.log('Turn 2 result:', msg);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.log('V2 session requires API access:', err.message);
|
|
60
|
+
} finally {
|
|
61
|
+
session.close();
|
|
62
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# elwood examples
|
|
2
|
+
|
|
3
|
+
These examples are elwood equivalents of the official `@anthropic-ai/claude-agent-sdk` examples. Each uses `import { ... } from '../src/index.js'` to import from elwood instead of the official SDK.
|
|
4
|
+
|
|
5
|
+
The key difference: elwood runs the Claude Code CLI **in-process** via Babel AST instrumentation rather than spawning a subprocess. The API is the same.
|
|
6
|
+
|
|
7
|
+
## Examples
|
|
8
|
+
|
|
9
|
+
### Core query patterns
|
|
10
|
+
|
|
11
|
+
| File | Official equivalent | Description |
|
|
12
|
+
|------|-------------------|-------------|
|
|
13
|
+
| `01-basic-query.js` | [Overview: basic query](https://code.claude.com/docs/en/agent-sdk/overview) | Simplest possible query with allowedTools |
|
|
14
|
+
| `02-bug-fixer.js` | [Quickstart: bug fixer](https://code.claude.com/docs/en/agent-sdk/quickstart) | Agent that reads, analyzes, and fixes buggy code |
|
|
15
|
+
| `03-custom-system-prompt.js` | [Quickstart: custom prompt](https://code.claude.com/docs/en/agent-sdk/quickstart) | Override the system prompt |
|
|
16
|
+
| `04-read-only-agent.js` | [Overview: permissions](https://code.claude.com/docs/en/agent-sdk/overview) | Read-only agent (Read, Glob, Grep only) |
|
|
17
|
+
| `05-find-todos.js` | [Overview: built-in tools](https://code.claude.com/docs/en/agent-sdk/overview) | Search codebase for TODO comments |
|
|
18
|
+
|
|
19
|
+
### Sessions
|
|
20
|
+
|
|
21
|
+
| File | Official equivalent | Description |
|
|
22
|
+
|------|-------------------|-------------|
|
|
23
|
+
| `06-session-resume.js` | [Overview: sessions](https://code.claude.com/docs/en/agent-sdk/overview) | Capture session ID and resume with full context |
|
|
24
|
+
| `20-session-list.js` | [TypeScript ref: listSessions](https://code.claude.com/docs/en/agent-sdk/typescript) | List sessions and read messages from disk |
|
|
25
|
+
| `24-v2-session-api.js` | V2 Session API (UNSTABLE) | Multi-turn sessions with send/stream |
|
|
26
|
+
|
|
27
|
+
### Hooks
|
|
28
|
+
|
|
29
|
+
| File | Official equivalent | Description |
|
|
30
|
+
|------|-------------------|-------------|
|
|
31
|
+
| `07-hooks-pretooluse.js` | [Hooks: protect .env files](https://code.claude.com/docs/en/agent-sdk/hooks) | PreToolUse hook that blocks writes to .env files |
|
|
32
|
+
| `08-hooks-posttooluse-audit.js` | [Hooks: audit log](https://code.claude.com/docs/en/agent-sdk/hooks) | PostToolUse hook that logs file changes to audit.log |
|
|
33
|
+
| `09-hooks-block-etc.js` | [Hooks: block /etc writes](https://code.claude.com/docs/en/agent-sdk/hooks) | PreToolUse hook that blocks writes to /etc |
|
|
34
|
+
| `10-hooks-redirect-sandbox.js` | [Hooks: redirect to sandbox](https://code.claude.com/docs/en/agent-sdk/hooks) | PreToolUse hook that rewrites file paths to /sandbox |
|
|
35
|
+
| `21-hooks-notification-slack.js` | [Hooks: forward to Slack](https://code.claude.com/docs/en/agent-sdk/hooks) | Notification hook that sends to Slack webhook |
|
|
36
|
+
| `22-hooks-webhook-posttooluse.js` | [Hooks: HTTP webhook](https://code.claude.com/docs/en/agent-sdk/hooks) | PostToolUse hook that sends webhooks |
|
|
37
|
+
| `23-hooks-subagent-tracker.js` | [Hooks: track subagents](https://code.claude.com/docs/en/agent-sdk/hooks) | SubagentStop hook that logs subagent completion |
|
|
38
|
+
|
|
39
|
+
### Subagents
|
|
40
|
+
|
|
41
|
+
| File | Official equivalent | Description |
|
|
42
|
+
|------|-------------------|-------------|
|
|
43
|
+
| `11-subagents.js` | [Overview: subagents](https://code.claude.com/docs/en/agent-sdk/overview) | Spawn a specialized code-reviewer subagent |
|
|
44
|
+
|
|
45
|
+
### MCP servers
|
|
46
|
+
|
|
47
|
+
| File | Official equivalent | Description |
|
|
48
|
+
|------|-------------------|-------------|
|
|
49
|
+
| `12-mcp-stdio.js` | [Overview: MCP](https://code.claude.com/docs/en/agent-sdk/overview) | Connect to Playwright MCP server via stdio |
|
|
50
|
+
| `13-mcp-http.js` | [MCP: HTTP transport](https://code.claude.com/docs/en/agent-sdk/mcp) | Connect to Claude Code docs MCP server via HTTP |
|
|
51
|
+
| `16-mcp-github.js` | [MCP: GitHub](https://code.claude.com/docs/en/agent-sdk/mcp) | Connect to GitHub MCP server with debug logging |
|
|
52
|
+
|
|
53
|
+
### Custom tools
|
|
54
|
+
|
|
55
|
+
| File | Official equivalent | Description |
|
|
56
|
+
|------|-------------------|-------------|
|
|
57
|
+
| `14-custom-tool.js` | [Custom tools: weather](https://code.claude.com/docs/en/agent-sdk/custom-tools) | Weather temperature tool with createSdkMcpServer() |
|
|
58
|
+
| `15-custom-tool-unit-converter.js` | [Custom tools: converter](https://code.claude.com/docs/en/agent-sdk/custom-tools) | Unit converter with enum schemas and error handling |
|
|
59
|
+
|
|
60
|
+
### Session stores
|
|
61
|
+
|
|
62
|
+
| File | Official equivalent | Description |
|
|
63
|
+
|------|-------------------|-------------|
|
|
64
|
+
| `17-session-store-postgres.js` | [examples/session-stores/postgres/demo.ts](https://github.com/anthropics/claude-agent-sdk-typescript/tree/main/examples/session-stores/postgres) | Postgres-backed session store usage guide |
|
|
65
|
+
| `18-session-store-redis.js` | [examples/session-stores/redis/demo.ts](https://github.com/anthropics/claude-agent-sdk-typescript/tree/main/examples/session-stores/redis) | Redis-backed session store usage guide |
|
|
66
|
+
| `19-session-store-s3.js` | [examples/session-stores/s3/demo.ts](https://github.com/anthropics/claude-agent-sdk-typescript/tree/main/examples/session-stores/s3) | S3-backed session store usage guide |
|
|
67
|
+
|
|
68
|
+
### Testing
|
|
69
|
+
|
|
70
|
+
| File | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `smoke-test.js` | Verifies all exports, constants, and API shapes without API calls |
|
|
73
|
+
| `basic.js` | Low-level AST instrumentation example (elwood-specific) |
|
|
74
|
+
|
|
75
|
+
## Running examples
|
|
76
|
+
|
|
77
|
+
Most examples require:
|
|
78
|
+
- `ANTHROPIC_API_KEY` set in environment
|
|
79
|
+
- Claude Code CLI installed (`npm install -g @anthropic-ai/claude-code`)
|
|
80
|
+
|
|
81
|
+
The smoke test requires neither:
|
|
82
|
+
```bash
|
|
83
|
+
node examples/smoke-test.js
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API differences from official SDK
|
|
87
|
+
|
|
88
|
+
| Feature | Official SDK | elwood |
|
|
89
|
+
|---------|-------------|--------|
|
|
90
|
+
| Import path | `@anthropic-ai/claude-agent-sdk` | `../src/index.js` (or `elwood`) |
|
|
91
|
+
| Execution | Subprocess (spawns `claude` binary) | In-process (Babel AST instrumentation) |
|
|
92
|
+
| Tool schemas | Zod schemas (`z.string()`, `z.number()`) | Plain JSON Schema objects |
|
|
93
|
+
| Language | TypeScript (.ts) | JavaScript (.js) |
|
|
94
|
+
| McpServer class | Bundled in SDK | Loaded from claude-code or @modelcontextprotocol/sdk |
|
|
95
|
+
| Session stores | SessionStore interface (typed) | Same interface, used via options.sessionStore |
|