@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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/examples/01-basic-query.js +38 -0
  4. package/examples/02-bug-fixer.js +57 -0
  5. package/examples/03-custom-system-prompt.js +41 -0
  6. package/examples/04-read-only-agent.js +38 -0
  7. package/examples/05-find-todos.js +37 -0
  8. package/examples/06-session-resume.js +70 -0
  9. package/examples/07-hooks-pretooluse.js +74 -0
  10. package/examples/08-hooks-posttooluse-audit.js +66 -0
  11. package/examples/09-hooks-block-etc.js +68 -0
  12. package/examples/10-hooks-redirect-sandbox.js +70 -0
  13. package/examples/11-subagents.js +54 -0
  14. package/examples/12-mcp-stdio.js +48 -0
  15. package/examples/13-mcp-http.js +54 -0
  16. package/examples/14-custom-tool.js +84 -0
  17. package/examples/15-custom-tool-unit-converter.js +132 -0
  18. package/examples/16-mcp-github.js +71 -0
  19. package/examples/17-session-store-postgres.js +78 -0
  20. package/examples/18-session-store-redis.js +65 -0
  21. package/examples/19-session-store-s3.js +67 -0
  22. package/examples/20-session-list.js +72 -0
  23. package/examples/21-hooks-notification-slack.js +78 -0
  24. package/examples/22-hooks-webhook-posttooluse.js +78 -0
  25. package/examples/23-hooks-subagent-tracker.js +59 -0
  26. package/examples/24-v2-session-api.js +62 -0
  27. package/examples/README.md +95 -0
  28. package/examples/basic.js +240 -0
  29. package/examples/smoke-test.js +296 -0
  30. package/package.json +52 -0
  31. package/src/ast-tools.js +182 -0
  32. package/src/index.js +70 -0
  33. package/src/instrumenter.js +2921 -0
  34. package/src/loader.js +306 -0
  35. package/src/locate.js +296 -0
  36. 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 |