@factory/droid-sdk 0.2.0 → 0.4.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 (41) hide show
  1. package/README.md +214 -82
  2. package/dist/index.cjs +2345 -692
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +2570 -232
  5. package/dist/index.d.ts +2570 -232
  6. package/dist/index.js +2298 -697
  7. package/dist/index.js.map +1 -1
  8. package/docs/daemon-usage-guide.md +544 -0
  9. package/docs/sdk-usage-guide.md +748 -0
  10. package/examples/abort-session-stream.ts +23 -56
  11. package/examples/daemon-multi-session.ts +67 -0
  12. package/examples/droid-dev-structured-output.ts +5 -5
  13. package/examples/fork-session.ts +33 -7
  14. package/examples/hook-execution.ts +68 -0
  15. package/examples/init-metadata.ts +14 -66
  16. package/examples/interrupt-session.ts +23 -55
  17. package/examples/list-sessions.ts +9 -55
  18. package/examples/multi-turn-session.ts +27 -54
  19. package/examples/permission-handler.ts +27 -84
  20. package/examples/readme-structured-output.ts +26 -0
  21. package/examples/result-metadata.ts +2 -1
  22. package/examples/run.ts +2 -1
  23. package/examples/sdk-mcp-tool.ts +14 -8
  24. package/examples/session-stream.ts +57 -0
  25. package/examples/spec-mode-new-session.ts +39 -99
  26. package/examples/spec-mode-same-session.ts +50 -111
  27. package/examples/structured-output.ts +17 -10
  28. package/examples/test-compact.ts +9 -4
  29. package/examples/test-rewind.ts +49 -117
  30. package/examples/tool-controls.ts +23 -55
  31. package/package.json +3 -1
  32. package/docs/examples/init-metadata.md +0 -79
  33. package/docs/examples/list-sessions.md +0 -64
  34. package/docs/examples/multi-turn-session.md +0 -77
  35. package/docs/examples/one-shot-query.md +0 -73
  36. package/docs/examples/permission-handler.md +0 -102
  37. package/docs/examples/run.md +0 -52
  38. package/docs/examples/spec-mode.md +0 -101
  39. package/docs/examples/tool-controls.md +0 -90
  40. package/docs/typescript-sdk-reference.md +0 -372
  41. package/examples/simple-query.ts +0 -53
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @factory/droid-sdk
2
2
 
3
- TypeScript SDK for the [Factory](https://factory.ai) Droid CLI. Provides a high-level API for interacting with Droid as a subprocess, with streaming message support, multi-turn sessions, spec mode, tool controls, initialization metadata, session forking, session discovery, and tool permission handling.
3
+ TypeScript SDK for the [Factory](https://factory.ai) Droid CLI. Provides a high-level API for interacting with Droid as a subprocess, with one-shot prompts, streaming messages, multi-turn sessions, structured output, SDK-backed MCP tools, spec mode, tool controls, initialization metadata, session forking, session discovery, and tool permission handling.
4
4
 
5
5
  ## Requirements
6
6
 
@@ -15,26 +15,71 @@ npm install @factory/droid-sdk
15
15
 
16
16
  ## Quick Start
17
17
 
18
- Send a one-shot prompt and stream the response:
18
+ Send a one-shot prompt and get the aggregated result:
19
19
 
20
20
  ```ts
21
- import { DroidMessageType, query } from '@factory/droid-sdk';
21
+ import { run } from '@factory/droid-sdk';
22
22
 
23
- const stream = query({
24
- prompt: 'What files are in the current directory?',
23
+ const result = await run('What files are in the current directory?', {
25
24
  cwd: '/my/project',
26
25
  });
27
26
 
28
- for await (const msg of stream) {
29
- if (msg.type === DroidMessageType.AssistantTextDelta) {
30
- process.stdout.write(msg.text);
31
- }
32
- if (msg.type === DroidMessageType.TurnComplete) {
33
- console.log('\nDone!');
27
+ console.log(result.text);
28
+ ```
29
+
30
+ Create a session when you want to stream one or more turns:
31
+
32
+ ```ts
33
+ import { DroidMessageType, createSession } from '@factory/droid-sdk';
34
+
35
+ const session = await createSession({ cwd: '/my/project' });
36
+
37
+ try {
38
+ for await (const msg of session.stream(
39
+ 'What files are in the current directory?'
40
+ )) {
41
+ if (msg.type === DroidMessageType.AssistantTextDelta) {
42
+ process.stdout.write(msg.text);
43
+ }
44
+ if (msg.type === DroidMessageType.Result) {
45
+ console.log('\nDone!');
46
+ }
34
47
  }
48
+ } finally {
49
+ await session.close();
35
50
  }
36
51
  ```
37
52
 
53
+ ## Structured Output
54
+
55
+ Request a JSON object that matches a JSON Schema:
56
+
57
+ ```ts
58
+ import { OutputFormatType, run } from '@factory/droid-sdk';
59
+
60
+ const result = await run('Pick a favorite number between 1 and 42.', {
61
+ cwd: '/my/project',
62
+ outputFormat: {
63
+ type: OutputFormatType.JsonSchema,
64
+ schema: {
65
+ type: 'object',
66
+ properties: {
67
+ favoriteNumber: {
68
+ type: 'number',
69
+ minimum: 1,
70
+ maximum: 42,
71
+ },
72
+ },
73
+ required: ['favoriteNumber'],
74
+ },
75
+ },
76
+ });
77
+
78
+ console.log(result.structuredOutput?.favoriteNumber);
79
+ ```
80
+
81
+ Structured output is available on `run()` and `session.stream(prompt, options)` through the `outputFormat` message option. `run()` parses the final object into `result.structuredOutput`; streaming callers can read and parse the final assistant message themselves.
82
+
38
83
  ## Multi-Turn Sessions
39
84
 
40
85
  Use `createSession()` for persistent conversations with multiple turns:
@@ -43,6 +88,7 @@ Use `createSession()` for persistent conversations with multiple turns:
43
88
  import { createSession, DroidMessageType } from '@factory/droid-sdk';
44
89
 
45
90
  const session = await createSession({ cwd: '/my/project' });
91
+ console.log(session.sessionId);
46
92
 
47
93
  // Streaming turn
48
94
  for await (const msg of session.stream('List all TypeScript files')) {
@@ -51,50 +97,88 @@ for await (const msg of session.stream('List all TypeScript files')) {
51
97
  }
52
98
  }
53
99
 
54
- // Non-streaming turn
55
- const result = await session.send('Summarize the project');
56
- console.log(result.text);
100
+ // Later turns use the same streaming API
101
+ for await (const msg of session.stream('Summarize the project')) {
102
+ if (msg.type === DroidMessageType.AssistantTextDelta) {
103
+ process.stdout.write(msg.text);
104
+ }
105
+ }
57
106
 
58
107
  await session.close();
59
108
  ```
60
109
 
61
- Resume an existing session by ID:
110
+ Use `session.sessionId` to persist the session ID, then resume it later:
62
111
 
63
112
  ```ts
64
113
  import { resumeSession } from '@factory/droid-sdk';
65
114
 
66
- const session = await resumeSession('session-id-here');
67
- const result = await session.send('Continue where we left off');
68
- console.log(result.text);
115
+ const session = await resumeSession(savedSessionId);
116
+ for await (const msg of session.stream('Continue where we left off')) {
117
+ // Handle streamed DroidMessage events.
118
+ }
69
119
  await session.close();
70
120
  ```
71
121
 
72
122
  The returned `DroidSession` also exposes `session.initResult`, which contains the raw `initialize_session` or `load_session` result returned by the JSON-RPC server.
73
123
 
74
- ## Initialization Metadata
124
+ ## SDK-backed MCP Tools
75
125
 
76
- Inspect the raw initialization metadata from `query()`, `createSession()`, and `resumeSession()`:
126
+ Expose in-process TypeScript tools to Droid through MCP:
77
127
 
78
128
  ```ts
79
- import { createSession, query, resumeSession } from '@factory/droid-sdk';
129
+ import { z } from 'zod';
80
130
 
81
- const stream = query({
82
- prompt: 'Reply with "ready" and nothing else.',
131
+ import {
132
+ DroidMessageType,
133
+ ToolConfirmationOutcome,
134
+ createSession,
135
+ createSdkMcpServer,
136
+ tool,
137
+ } from '@factory/droid-sdk';
138
+
139
+ const sdkTools = createSdkMcpServer({
140
+ name: 'sdk-tools',
141
+ tools: [
142
+ tool(
143
+ 'favorite_number',
144
+ 'Returns a favorite number for a person',
145
+ { name: z.string() },
146
+ ({ name }) => `${name}'s favorite number is 42.`
147
+ ),
148
+ ],
149
+ });
150
+
151
+ const session = await createSession({
83
152
  cwd: '/my/project',
153
+ mcpServers: [sdkTools],
154
+ permissionHandler: () => ToolConfirmationOutcome.ProceedOnce,
84
155
  });
85
156
 
86
- console.log(stream.sessionId); // null before initialization
87
- console.log(stream.initResult); // null before initialization
157
+ for await (const msg of session.stream(
158
+ 'Use the favorite_number tool for Ada and tell me the answer.'
159
+ )) {
160
+ if (msg.type === DroidMessageType.AssistantTextDelta) {
161
+ process.stdout.write(msg.text);
162
+ }
163
+ }
164
+
165
+ await session.close();
166
+ ```
167
+
168
+ `createSdkMcpServer()` is managed by the SDK session lifecycle. Use `tool()` with a Zod object shape for typed tool input validation.
88
169
 
89
- const initialized = await stream.initialized;
90
- console.log(initialized.sessionId);
91
- console.log(initialized.settings.modelId);
92
- stream.abort();
170
+ ## Initialization Metadata
171
+
172
+ Inspect the raw initialization metadata from `createSession()` and `resumeSession()`:
173
+
174
+ ```ts
175
+ import { createSession, resumeSession } from '@factory/droid-sdk';
93
176
 
94
177
  const session = await createSession({ cwd: '/my/project' });
178
+ console.log(session.sessionId);
95
179
  console.log(session.initResult.settings.modelId);
96
180
 
97
- const resumed = await resumeSession(session.sessionId, { cwd: '/my/project' });
181
+ const resumed = await resumeSession(session.sessionId);
98
182
  console.log(resumed.initResult.cwd);
99
183
 
100
184
  await resumed.close();
@@ -107,6 +191,7 @@ Start a session directly in spec mode, or enter spec mode later on an existing s
107
191
 
108
192
  ```ts
109
193
  import {
194
+ DroidMessageType,
110
195
  createSession,
111
196
  DroidInteractionMode,
112
197
  ReasoningEffort,
@@ -119,8 +204,13 @@ const session = await createSession({
119
204
  specModeModelId: 'claude-sonnet-4-20250514',
120
205
  });
121
206
 
122
- const plan = await session.send('Draft a plan for adding integration tests');
123
- console.log(plan.text);
207
+ for await (const msg of session.stream(
208
+ 'Draft a plan for adding integration tests'
209
+ )) {
210
+ if (msg.type === DroidMessageType.AssistantTextDelta) {
211
+ process.stdout.write(msg.text);
212
+ }
213
+ }
124
214
 
125
215
  await session.enterSpecMode({
126
216
  specModeReasoningEffort: ReasoningEffort.High,
@@ -164,17 +254,28 @@ await session.close();
164
254
  Fork the current server-side session and continue from the new session ID:
165
255
 
166
256
  ```ts
167
- import { createSession, resumeSession } from '@factory/droid-sdk';
257
+ import {
258
+ DroidMessageType,
259
+ createSession,
260
+ resumeSession,
261
+ } from '@factory/droid-sdk';
168
262
 
169
263
  const session = await createSession({ cwd: '/my/project' });
170
264
 
171
- await session.send('Remember this phrase: mango sunrise');
265
+ for await (const _msg of session.stream(
266
+ 'Remember this phrase: mango sunrise'
267
+ )) {
268
+ // Consume the turn.
269
+ }
172
270
 
173
271
  const { newSessionId } = await session.forkSession();
174
- const fork = await resumeSession(newSessionId, { cwd: '/my/project' });
272
+ const fork = await resumeSession(newSessionId);
175
273
 
176
- const result = await fork.send('What phrase did I ask you to remember?');
177
- console.log(result.text);
274
+ for await (const msg of fork.stream('What phrase did I ask you to remember?')) {
275
+ if (msg.type === DroidMessageType.AssistantTextDelta) {
276
+ process.stdout.write(msg.text);
277
+ }
278
+ }
178
279
 
179
280
  await fork.close();
180
281
  await session.close();
@@ -226,12 +327,11 @@ Handle tool confirmation requests with a custom permission handler:
226
327
  ```ts
227
328
  import {
228
329
  DroidMessageType,
229
- query,
330
+ createSession,
230
331
  ToolConfirmationOutcome,
231
332
  } from '@factory/droid-sdk';
232
333
 
233
- const stream = query({
234
- prompt: 'Create a hello.txt file',
334
+ const session = await createSession({
235
335
  cwd: '/my/project',
236
336
  permissionHandler(params) {
237
337
  console.log('Tool permission requested:', params);
@@ -239,10 +339,14 @@ const stream = query({
239
339
  },
240
340
  });
241
341
 
242
- for await (const msg of stream) {
243
- if (msg.type === DroidMessageType.AssistantTextDelta) {
244
- process.stdout.write(msg.text);
342
+ try {
343
+ for await (const msg of session.stream('Create a hello.txt file')) {
344
+ if (msg.type === DroidMessageType.AssistantTextDelta) {
345
+ process.stdout.write(msg.text);
346
+ }
245
347
  }
348
+ } finally {
349
+ await session.close();
246
350
  }
247
351
  ```
248
352
 
@@ -252,48 +356,46 @@ for await (const msg of stream) {
252
356
 
253
357
  | Function | Description |
254
358
  | ----------------------------- | ---------------------------------------------------------------- |
255
- | `query(options)` | One-shot prompt → async generator of `DroidMessage` events |
359
+ | `run(prompt, options?)` | One-shot prompt → aggregated `DroidResult` |
256
360
  | `createSession(options?)` | Create a new multi-turn session → `DroidSession` |
257
361
  | `resumeSession(id, options?)` | Resume an existing session → `DroidSession` |
258
362
  | `listSessions(options?)` | List droid sessions saved on disk → `Promise<SessionMetadata[]>` |
259
-
260
- ### `query(options): DroidQuery`
261
-
262
- Returns an async generator that yields `DroidMessage` events. The returned `DroidQuery` object also exposes:
263
-
264
- - **`interrupt()`** — gracefully interrupt the agent's current turn
265
- - **`abort()`** — forcefully kill the subprocess
266
- - **`sessionId`** — the session ID (available after initialization)
267
- - **`initResult`** — cached `initialize_session` result, or `null` before initialization
268
- - **`initialized`** — promise that resolves with the `initialize_session` result
269
-
270
- `query(options)` also accepts an `abortSignal` for external cancellation.
363
+ | `createSdkMcpServer(options)` | Create an SDK-managed MCP server for in-process tools |
364
+ | `tool(...)` | Define a typed SDK-backed MCP tool |
271
365
 
272
366
  ### `DroidSession`
273
367
 
274
368
  Returned by `createSession()` and `resumeSession()`. Key methods:
275
369
 
276
- - **`stream(text, options?)`** — send a message, returns async generator of `DroidMessage`
277
- - **`send(text, options?)`** — send a message, returns aggregated `DroidResult`
370
+ - **`stream(prompt, options?)`** — stream `DroidMessage` events for one turn
278
371
  - **`interrupt()`** — interrupt the current turn
279
372
  - **`close()`** — close the session and release resources
280
373
  - **`updateSettings(params)`** — update model, autonomy level, etc.
281
374
  - **`enterSpecMode(params?)`** — switch the current session into spec mode
282
375
  - **`forkSession()`** — create a forked server-side session and return its new session ID
376
+ - **`compactSession(params?)`** — compact session history and return the new session ID
377
+ - **`getContextStats()`** — read current context window utilization
283
378
  - **`addMcpServer(params)`** / **`removeMcpServer(params)`** / **`toggleMcpServer(params)`** — manage MCP servers
284
379
  - **`listMcpServers()`** / **`listMcpTools()`** / **`authenticateMcpServer(params)`** — inspect and authenticate MCP servers
285
380
  - **`listTools(params?)`** — inspect the exec tool catalog and current allow/deny state
286
381
  - **`renameSession(params)`** — rename the current session
382
+ - **`getRewindInfo(params)`** / **`executeRewind(params)`** — inspect and execute file rewind operations
287
383
  - **`sessionId`** — the session ID
288
384
  - **`initResult`** — cached `initialize_session` or `load_session` result
289
385
 
290
386
  ### `DroidResult`
291
387
 
292
- Returned by `session.send()`:
388
+ Returned by `run()`:
293
389
 
390
+ - **`sessionId`** — session that produced the result
294
391
  - **`text`** — concatenated assistant response text
295
392
  - **`messages`** — all `DroidMessage` objects from the turn
296
393
  - **`tokenUsage`** — final token usage, or `null`
394
+ - **`durationMs`** — wall-clock time spent consuming the turn
395
+ - **`turnCount`** — number of completed turns observed while consuming the stream
396
+ - **`error`** — first Droid error event from the turn, or `null`
397
+ - **`structuredOutput`** — parsed structured JSON object, or `null`
398
+ - **`success`** — `true` when no Droid error event was emitted
297
399
 
298
400
  ### `DroidMessage` Types
299
401
 
@@ -307,29 +409,45 @@ if (msg.type === DroidMessageType.AssistantTextDelta) {
307
409
  }
308
410
  ```
309
411
 
310
- | Type | Description |
311
- | ----------------------- | --------------------------------------- |
312
- | `assistant_text_delta` | Streaming text token from the assistant |
313
- | `thinking_text_delta` | Streaming reasoning/thinking token |
314
- | `tool_use` | Tool invocation by the assistant |
315
- | `tool_result` | Result from a tool execution |
316
- | `tool_progress` | Progress update during tool execution |
317
- | `working_state_changed` | Agent working state transition |
318
- | `token_usage_update` | Updated token usage counters |
319
- | `create_message` | Full assistant message created |
320
- | `turn_complete` | Sentinel: agent turn finished |
321
- | `session_title_updated` | Session title changed |
322
- | `mcp_status_changed` | MCP server status changed |
323
- | `mcp_auth_required` | MCP authentication required |
324
- | `mcp_auth_completed` | MCP authentication completed |
325
- | `error` | Error event from the process |
412
+ | Type | Description |
413
+ | -------------------------- | ----------------------------------------------- |
414
+ | `assistant` | Complete assistant message |
415
+ | `user` | Complete user message |
416
+ | `assistant_text_delta` | Streaming text token from the assistant |
417
+ | `assistant_text_complete` | End of an assistant text block |
418
+ | `thinking_text_delta` | Streaming reasoning/thinking token |
419
+ | `thinking_text_complete` | End of a thinking block |
420
+ | `tool_call` | Tool invocation by the assistant |
421
+ | `tool_call_delta` | Streaming tool call input |
422
+ | `tool_result` | Result from a tool execution |
423
+ | `tool_progress` | Progress update during tool execution |
424
+ | `hook` | File hook execution event (started or finished) |
425
+ | `working_state_changed` | Agent working state transition |
426
+ | `token_usage_update` | Updated token usage counters |
427
+ | `result` | End-of-turn sentinel with aggregated metadata |
428
+ | `session_title_updated` | Session title changed |
429
+ | `settings_updated` | Session settings changed |
430
+ | `permission_resolved` | Tool permission request resolved |
431
+ | `mcp_status_changed` | MCP server status changed |
432
+ | `mcp_auth_required` | MCP authentication required |
433
+ | `mcp_auth_completed` | MCP authentication completed |
434
+ | `error` | Error event from the process |
435
+ | `mission_state_changed` | Mission state changed |
436
+ | `mission_features_changed` | Mission features changed |
437
+ | `mission_progress_entry` | Mission progress log changed |
438
+ | `mission_heartbeat` | Mission heartbeat |
439
+ | `mission_worker_started` | Mission worker started |
440
+ | `mission_worker_completed` | Mission worker completed |
326
441
 
327
442
  ### Options
328
443
 
329
- `QueryOptions` and `CreateSessionOptions` accept:
444
+ Session creation options used by `run()` and `createSession()` include:
330
445
 
331
- - **`prompt`** — the user prompt (query only)
332
446
  - **`cwd`** — working directory for the session
447
+ - **`execPath`** — path to `droid` executable (default: `"droid"`)
448
+ - **`execArgs`** — extra CLI arguments for the spawned droid process
449
+ - **`env`** — environment variables for the spawned process
450
+ - **`transport`** — provide a custom transport instead of spawning a process
333
451
  - **`modelId`** — LLM model identifier
334
452
  - **`autonomyLevel`** — `AutonomyLevel` enum value
335
453
  - **`interactionMode`** — `DroidInteractionMode` enum value
@@ -342,12 +460,19 @@ if (msg.type === DroidMessageType.AssistantTextDelta) {
342
460
  - **`permissionHandler`** — callback for tool confirmations
343
461
  - **`askUserHandler`** — callback for interactive questions
344
462
  - **`abortSignal`** — standard `AbortSignal` for cancellation
345
- - **`execPath`** — path to `droid` executable (default: `"droid"`)
346
- - **`transport`** — provide a custom transport instead of spawning a process
463
+
464
+ `resumeSession()` accepts the process, transport, handler, `mcpServers`, and `abortSignal` options needed to reconnect to an existing session, but does not accept new-session-only options such as `modelId` or `interactionMode`. `cwd` is intentionally not accepted on resume: the persisted session's working directory is always used. To run in a different directory, create a new session or fork the existing one.
465
+
466
+ Message APIs (`run()` and `session.stream()`) also accept:
467
+
468
+ - **`images`** — base64 image attachments
469
+ - **`files`** — document/file attachments
470
+ - **`outputFormat`** — structured output request, currently `OutputFormatType.JsonSchema`
471
+ - **`abortSignal`** — standard `AbortSignal` for turn cancellation
347
472
 
348
473
  ### `DroidClient`
349
474
 
350
- Low-level JSON-RPC client for advanced use. Provides typed methods for the underlying protocol operations, including `listTools()` and `renameSession()`. Most users should prefer `query()` and `createSession()`.
475
+ Low-level JSON-RPC client for advanced use. Provides typed methods for the underlying protocol operations, including `listTools()`, `renameSession()`, `getRewindInfo()`, and `executeRewind()`. Most users should prefer `run()` and `createSession()`.
351
476
 
352
477
  ### Error Types
353
478
 
@@ -364,10 +489,15 @@ Low-level JSON-RPC client for advanced use. Provides typed methods for the under
364
489
 
365
490
  See the [`examples/`](./examples) directory for runnable examples:
366
491
 
367
- - **[`simple-query.ts`](./examples/simple-query.ts)** — one-shot query with streaming output
492
+ - **[`session-stream.ts`](./examples/session-stream.ts)** — session streaming output
493
+ - **[`run.ts`](./examples/run.ts)** — one-shot prompt with aggregated result
368
494
  - **[`multi-turn-session.ts`](./examples/multi-turn-session.ts)** — multi-turn session lifecycle
369
495
  - **[`abort-session-stream.ts`](./examples/abort-session-stream.ts)** — cancel an in-flight streaming session turn with `AbortSignal`
370
- - **[`init-metadata.ts`](./examples/init-metadata.ts)** — read initialization and load metadata from query/session APIs
496
+ - **[`interrupt-session.ts`](./examples/interrupt-session.ts)** — interrupt a running session turn
497
+ - **[`init-metadata.ts`](./examples/init-metadata.ts)** — read initialization and load metadata from session APIs
498
+ - **[`result-metadata.ts`](./examples/result-metadata.ts)** — inspect `DroidResult` metadata from `run()`
499
+ - **[`structured-output.ts`](./examples/structured-output.ts)** — request and parse structured output
500
+ - **[`droid-dev-structured-output.ts`](./examples/droid-dev-structured-output.ts)** — structured output smoke test with configurable Droid executable
371
501
  - **[`permission-handler.ts`](./examples/permission-handler.ts)** — custom permission handling
372
502
  - **[`spec-mode-same-session.ts`](./examples/spec-mode-same-session.ts)** — approve a spec and continue in the same session
373
503
  - **[`spec-mode-new-session.ts`](./examples/spec-mode-new-session.ts)** — approve a spec and hand off implementation to a new session
@@ -375,6 +505,8 @@ See the [`examples/`](./examples) directory for runnable examples:
375
505
  - **[`sdk-mcp-tool.ts`](./examples/sdk-mcp-tool.ts)** — expose SDK-defined tools to Droid through MCP
376
506
  - **[`fork-session.ts`](./examples/fork-session.ts)** — fork a session and continue from the new session ID
377
507
  - **[`list-sessions.ts`](./examples/list-sessions.ts)** — discover droid sessions saved on disk
508
+ - **[`test-compact.ts`](./examples/test-compact.ts)** — compact session history
509
+ - **[`test-rewind.ts`](./examples/test-rewind.ts)** — use low-level rewind APIs
378
510
 
379
511
  ## License
380
512