@factory/droid-sdk 0.6.0 → 0.7.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 (80) hide show
  1. package/README.md +35 -482
  2. package/dist/chunk-5UXINOXG.mjs +24483 -0
  3. package/dist/chunk-5UXINOXG.mjs.map +1 -0
  4. package/dist/chunk-C3KHERVH.js +24483 -0
  5. package/dist/chunk-C3KHERVH.js.map +1 -0
  6. package/dist/{index-CwXX5IUH.d.cts → index-D_SzTnFR.d.mts} +83826 -81547
  7. package/dist/{index-CwXX5IUH.d.ts → index-D_SzTnFR.d.ts} +83826 -81547
  8. package/dist/index.d.mts +4 -0
  9. package/dist/index.d.ts +4 -93103
  10. package/dist/index.js +821 -11745
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +822 -0
  13. package/dist/index.mjs.map +1 -0
  14. package/dist/node.d.mts +736 -0
  15. package/dist/node.d.ts +736 -0
  16. package/dist/node.js +4601 -0
  17. package/dist/node.js.map +1 -0
  18. package/dist/node.mjs +4601 -0
  19. package/dist/node.mjs.map +1 -0
  20. package/docs/typescript-sdk-reference.md +1260 -0
  21. package/examples/browser/daemon-lifecycle.ts +95 -0
  22. package/examples/browser/daemon-multi-session.ts +66 -0
  23. package/examples/browser/daemon-session.ts +73 -0
  24. package/examples/browser/index.html +68 -0
  25. package/examples/browser/list-sessions.ts +52 -0
  26. package/examples/{abort-session-stream.ts → node/abort-session-stream.ts} +8 -10
  27. package/examples/node/ask-user-elicitation.ts +35 -0
  28. package/examples/node/compact-session.ts +48 -0
  29. package/examples/node/enter-spec-mode.ts +66 -0
  30. package/examples/node/fork-session.ts +45 -0
  31. package/examples/node/hook-execution.ts +94 -0
  32. package/examples/node/image-attachment.ts +35 -0
  33. package/examples/node/init-metadata.ts +24 -0
  34. package/examples/{interrupt-session.ts → node/interrupt-session.ts} +7 -6
  35. package/examples/node/list-sessions.ts +20 -0
  36. package/examples/node/multi-turn-session.ts +33 -0
  37. package/examples/node/observability.ts +88 -0
  38. package/examples/node/permission-handler.ts +55 -0
  39. package/examples/node/rename-session.ts +29 -0
  40. package/examples/node/result-metadata.ts +34 -0
  41. package/examples/node/rewind-session.ts +69 -0
  42. package/examples/node/run.ts +25 -0
  43. package/examples/{sdk-mcp-tool.ts → node/sdk-mcp-tool.ts} +22 -12
  44. package/examples/node/session-settings.ts +35 -0
  45. package/examples/node/session-stream.ts +44 -0
  46. package/examples/node/spec-mode-new-session.ts +92 -0
  47. package/examples/node/spec-mode-same-session.ts +85 -0
  48. package/examples/node/structured-output.ts +73 -0
  49. package/examples/node/tool-controls.ts +26 -0
  50. package/examples/package.json +3 -0
  51. package/package.json +20 -42
  52. package/dist/index.cjs +0 -12135
  53. package/dist/index.cjs.map +0 -1
  54. package/dist/index.d.cts +0 -93103
  55. package/dist/protocol/index.cjs +0 -6466
  56. package/dist/protocol/index.cjs.map +0 -1
  57. package/dist/protocol/index.d.cts +0 -2
  58. package/dist/protocol/index.d.ts +0 -2
  59. package/dist/protocol/index.js +0 -6078
  60. package/dist/protocol/index.js.map +0 -1
  61. package/docs/daemon-usage-guide.md +0 -544
  62. package/docs/sdk-usage-guide.md +0 -748
  63. package/examples/daemon-multi-session.ts +0 -67
  64. package/examples/droid-dev-structured-output.ts +0 -44
  65. package/examples/fork-session.ts +0 -68
  66. package/examples/hook-execution.ts +0 -68
  67. package/examples/init-metadata.ts +0 -24
  68. package/examples/list-sessions.ts +0 -19
  69. package/examples/multi-turn-session.ts +0 -40
  70. package/examples/permission-handler.ts +0 -41
  71. package/examples/readme-structured-output.ts +0 -26
  72. package/examples/result-metadata.ts +0 -63
  73. package/examples/run.ts +0 -39
  74. package/examples/session-stream.ts +0 -57
  75. package/examples/spec-mode-new-session.ts +0 -61
  76. package/examples/spec-mode-same-session.ts +0 -72
  77. package/examples/structured-output.ts +0 -60
  78. package/examples/test-compact.ts +0 -65
  79. package/examples/test-rewind.ts +0 -87
  80. package/examples/tool-controls.ts +0 -37
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Spec mode: approve and implement in the same session.
3
+ *
4
+ * Approving the spec with `ProceedOnce` keeps implementation in the session
5
+ * that planned it. The example prints its session id and reports that no
6
+ * handoff occurred, which is what distinguishes its output from
7
+ * spec-mode-new-session.ts.
8
+ *
9
+ * A handoff would announce itself on the notification envelope: `params.sessionId`
10
+ * on incoming notifications would stop matching `session.id`. The typed message
11
+ * stream carries no session id per message, so the example subscribes with
12
+ * `session.onNotification()` and validates each envelope with
13
+ * `SessionNotificationSchema`.
14
+ *
15
+ * Usage:
16
+ * npx tsx examples/node/spec-mode-same-session.ts
17
+ */
18
+
19
+ import { mkdtemp, readFile, rm } from 'node:fs/promises';
20
+ import { tmpdir } from 'node:os';
21
+ import { join } from 'node:path';
22
+
23
+ import {
24
+ DroidInteractionMode,
25
+ ReasoningEffort,
26
+ SessionNotificationSchema,
27
+ ToolConfirmationOutcome,
28
+ createSession,
29
+ } from '@factory/droid-sdk/node';
30
+
31
+ const tempDir = await mkdtemp(join(tmpdir(), 'droid-sdk-spec-'));
32
+ const outputPath = join(tempDir, 'hello.txt');
33
+
34
+ let handoffSessionId: string | null = null;
35
+
36
+ try {
37
+ const session = await createSession({
38
+ interactionMode: DroidInteractionMode.Spec,
39
+ specModeReasoningEffort: ReasoningEffort.High,
40
+ permissionHandler: () => ToolConfirmationOutcome.ProceedOnce,
41
+ });
42
+
43
+ // The typed message stream carries no per-message session id, and the
44
+ // precise handoff signal the SDK uses internally is not part of the public
45
+ // surface, so a foreign envelope session id is the available proxy. It is
46
+ // only a proxy: any notification scoped to another session also trips it.
47
+ const unsubscribe = session.onNotification((notification) => {
48
+ const parsed = SessionNotificationSchema.safeParse(notification);
49
+ if (!parsed.success) return;
50
+ const envelopeSessionId = parsed.data.params.sessionId;
51
+ if (envelopeSessionId !== undefined && envelopeSessionId !== session.id) {
52
+ handoffSessionId = envelopeSessionId;
53
+ }
54
+ });
55
+
56
+ try {
57
+ for await (const _msg of session.stream(
58
+ `Plan then create ${outputPath} containing "Hello from Droid".`
59
+ )) {
60
+ // Consume the stream until implementation finishes.
61
+ }
62
+ } finally {
63
+ unsubscribe();
64
+ await session.close();
65
+ }
66
+
67
+ console.log(`planning session: ${session.id}`);
68
+ console.log(
69
+ `implementing session: ${handoffSessionId ?? '<same session>'}`
70
+ );
71
+ console.log(await readFile(outputPath, 'utf8'));
72
+ } finally {
73
+ await rm(tempDir, { recursive: true, force: true });
74
+ }
75
+
76
+ // A foreign session id is only a proxy for a handoff, so warn rather than
77
+ // fail: it may mean `ProceedOnce` handed implementation off, or merely that
78
+ // some unrelated session-scoped notification arrived during the run.
79
+ if (handoffSessionId !== null) {
80
+ console.warn(
81
+ `Observed a notification scoped to a different session (${String(handoffSessionId)}). ` +
82
+ 'That may mean implementation was handed off, or that unrelated ' +
83
+ 'session-scoped activity occurred during this run.'
84
+ );
85
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Structured output example.
3
+ *
4
+ * Passes a JSON schema via `outputFormat` and reads the parsed object back
5
+ * from `result.structuredOutput`.
6
+ *
7
+ * Usage:
8
+ * npx tsx examples/node/structured-output.ts
9
+ */
10
+
11
+ import { OutputFormatType, run } from '@factory/droid-sdk/node';
12
+
13
+ interface CodeReview {
14
+ summary: string;
15
+ findings: Array<{
16
+ line: number;
17
+ severity: 'low' | 'medium' | 'high';
18
+ message: string;
19
+ }>;
20
+ }
21
+
22
+ const result = await run(
23
+ `Review this code for correctness issues:
24
+
25
+ function getDisplayName(user) {
26
+ return user.profile.name.trim();
27
+ }`,
28
+ {
29
+ outputFormat: {
30
+ type: OutputFormatType.JsonSchema,
31
+ schema: {
32
+ type: 'object',
33
+ properties: {
34
+ summary: { type: 'string' },
35
+ findings: {
36
+ type: 'array',
37
+ items: {
38
+ type: 'object',
39
+ properties: {
40
+ line: { type: 'number' },
41
+ severity: {
42
+ type: 'string',
43
+ enum: ['low', 'medium', 'high'],
44
+ },
45
+ message: { type: 'string' },
46
+ },
47
+ required: ['line', 'severity', 'message'],
48
+ },
49
+ },
50
+ },
51
+ required: ['summary', 'findings'],
52
+ },
53
+ },
54
+ }
55
+ );
56
+
57
+ if (!result.success) {
58
+ const detail =
59
+ result.structuredOutputError?.message ??
60
+ result.error?.message ??
61
+ 'Unknown error';
62
+ throw new Error(`run() failed (${result.subtype}): ${detail}`);
63
+ }
64
+
65
+ // A successful run can still omit structured output, for example when the
66
+ // model answers in prose instead of the requested schema.
67
+ if (!result.structuredOutput) {
68
+ throw new Error('run() succeeded but returned no structured output.');
69
+ }
70
+
71
+ const review = result.structuredOutput as CodeReview;
72
+
73
+ console.log(JSON.stringify(review, null, 2));
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Tool controls example.
3
+ *
4
+ * Disables tools at session creation, then inspects availability.
5
+ *
6
+ * Usage:
7
+ * npx tsx examples/node/tool-controls.ts
8
+ */
9
+
10
+ import { createSession } from '@factory/droid-sdk/node';
11
+
12
+ const session = await createSession({
13
+ disabledToolIds: ['Execute'],
14
+ });
15
+
16
+ try {
17
+ const tools = await session.listTools();
18
+
19
+ for (const tool of tools) {
20
+ if (['Read', 'Grep', 'Execute'].includes(tool.id)) {
21
+ console.log(`${tool.id}: ${String(tool.allowed)}`);
22
+ }
23
+ }
24
+ } finally {
25
+ await session.close();
26
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@factory/droid-sdk",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "private": false,
5
5
  "description": "TypeScript SDK for the Factory Droid CLI",
6
6
  "keywords": [
@@ -12,32 +12,34 @@
12
12
  "sdk"
13
13
  ],
14
14
  "license": "Apache-2.0",
15
- "type": "module",
16
- "main": "./dist/index.cjs",
17
- "module": "./dist/index.js",
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.mjs",
18
17
  "types": "./dist/index.d.ts",
19
18
  "exports": {
20
19
  ".": {
21
20
  "import": {
22
- "types": "./dist/index.d.ts",
23
- "default": "./dist/index.js"
21
+ "types": "./dist/index.d.mts",
22
+ "default": "./dist/index.mjs"
24
23
  },
25
24
  "require": {
26
- "types": "./dist/index.d.cts",
27
- "default": "./dist/index.cjs"
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
28
27
  }
29
28
  },
30
- "./protocol": {
29
+ "./node": {
31
30
  "import": {
32
- "types": "./dist/protocol/index.d.ts",
33
- "default": "./dist/protocol/index.js"
31
+ "types": "./dist/node.d.mts",
32
+ "default": "./dist/node.mjs"
34
33
  },
35
34
  "require": {
36
- "types": "./dist/protocol/index.d.cts",
37
- "default": "./dist/protocol/index.cjs"
35
+ "types": "./dist/node.d.ts",
36
+ "default": "./dist/node.js"
38
37
  }
39
38
  }
40
39
  },
40
+ "browser": {
41
+ "ws": false
42
+ },
41
43
  "files": [
42
44
  "dist",
43
45
  "docs",
@@ -45,18 +47,6 @@
45
47
  "README.md",
46
48
  "LICENSE"
47
49
  ],
48
- "scripts": {
49
- "build": "tsup",
50
- "prepack": "npm run build",
51
- "typecheck": "tsc --noEmit",
52
- "typecheck:examples": "tsc --noEmit -p tsconfig.examples.json",
53
- "test": "vitest run",
54
- "test:coverage": "vitest run --coverage",
55
- "lint": "eslint src/ tests/ examples/",
56
- "fix": "eslint --fix src/ tests/ examples/",
57
- "format": "prettier --write .",
58
- "format:check": "prettier --check ."
59
- },
60
50
  "repository": {
61
51
  "type": "git",
62
52
  "url": "git+https://github.com/Factory-AI/droid-sdk-typescript.git"
@@ -66,26 +56,14 @@
66
56
  },
67
57
  "dependencies": {
68
58
  "@modelcontextprotocol/sdk": "^1.29.0",
69
- "uuid": "^11.1.0",
59
+ "@opentelemetry/api": "^1.9.0",
60
+ "eventemitter3": "^5.0.1",
61
+ "fast-deep-equal": "^3.1.3",
62
+ "isows": "^1.0.7",
63
+ "uuid": "^9.0.0",
70
64
  "ws": "^8.21.0",
71
65
  "zod": "^3.24.0"
72
66
  },
73
- "devDependencies": {
74
- "@eslint/js": "^9.39.4",
75
- "@types/node": "^22.15.0",
76
- "@types/uuid": "^10.0.0",
77
- "@types/ws": "^8.18.1",
78
- "@vitest/coverage-v8": "^3.1.0",
79
- "eslint": "^9.24.0",
80
- "eslint-import-resolver-typescript": "^4.4.4",
81
- "eslint-plugin-import": "^2.32.0",
82
- "eslint-plugin-unused-imports": "^4.4.1",
83
- "prettier": "^3.8.1",
84
- "tsup": "^8.4.0",
85
- "typescript": "^5.8.0",
86
- "typescript-eslint": "^8.57.2",
87
- "vitest": "^3.1.0"
88
- },
89
67
  "homepage": "https://github.com/Factory-AI/droid-sdk-typescript#readme",
90
68
  "bugs": {
91
69
  "url": "https://github.com/Factory-AI/droid-sdk-typescript/issues"