gsd-pi 2.53.0 → 2.54.0-dev.16631ca

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 (200) hide show
  1. package/dist/cli.js +19 -19
  2. package/dist/headless-ui.d.ts +29 -3
  3. package/dist/headless-ui.js +221 -28
  4. package/dist/headless.d.ts +11 -0
  5. package/dist/headless.js +238 -41
  6. package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +2 -2
  7. package/dist/resources/extensions/bg-shell/utilities.js +34 -5
  8. package/dist/resources/extensions/gsd/auto/phases.js +10 -1
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
  10. package/dist/resources/extensions/gsd/auto-model-selection.js +17 -1
  11. package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
  12. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -5
  13. package/dist/web/standalone/.next/BUILD_ID +1 -1
  14. package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
  15. package/dist/web/standalone/.next/build-manifest.json +4 -4
  16. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  17. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  18. package/dist/web/standalone/.next/required-server-files.json +4 -4
  19. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  20. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  22. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  30. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  33. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  34. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  46. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  58. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  86. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  92. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  108. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  110. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  112. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/page.js +2 -2
  129. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app-paths-manifest.json +19 -19
  131. package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
  132. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  133. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/middleware.js +2 -2
  136. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  138. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  139. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  140. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  141. package/dist/web/standalone/.next/static/chunks/4024.82f2e2a838908338.js +9 -0
  142. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  143. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  144. package/dist/web/standalone/.next/static/chunks/app/page-b950e4e384cc62b3.js +1 -0
  145. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  146. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  147. package/dist/web/standalone/.next/static/chunks/{webpack-bca0e732db0dcec3.js → webpack-70adf6e3be5479ce.js} +1 -1
  148. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  149. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  150. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  151. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  152. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  153. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  154. package/dist/web/standalone/server.js +1 -1
  155. package/package.json +1 -1
  156. package/packages/mcp-server/README.md +6 -6
  157. package/packages/mcp-server/package.json +14 -4
  158. package/packages/mcp-server/src/cli.ts +1 -1
  159. package/packages/mcp-server/src/index.ts +1 -1
  160. package/packages/mcp-server/src/mcp-server.test.ts +2 -2
  161. package/packages/mcp-server/src/session-manager.ts +2 -2
  162. package/packages/mcp-server/src/types.ts +1 -1
  163. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -1
  164. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -0
  167. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  168. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +14 -2
  169. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  170. package/packages/pi-coding-agent/package.json +1 -1
  171. package/packages/pi-coding-agent/src/core/model-registry.ts +1 -1
  172. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -2
  173. package/packages/rpc-client/README.md +125 -0
  174. package/packages/rpc-client/examples/basic-usage.ts +13 -0
  175. package/packages/rpc-client/package.json +17 -3
  176. package/packages/rpc-client/src/index.ts +10 -0
  177. package/packages/rpc-client/src/jsonl.ts +64 -0
  178. package/packages/rpc-client/src/rpc-client.test.ts +568 -0
  179. package/packages/rpc-client/src/rpc-client.ts +666 -0
  180. package/packages/rpc-client/src/rpc-types.ts +399 -0
  181. package/packages/rpc-client/tsconfig.examples.json +17 -0
  182. package/packages/rpc-client/tsconfig.json +24 -0
  183. package/pkg/package.json +1 -1
  184. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +2 -2
  185. package/src/resources/extensions/bg-shell/utilities.ts +39 -4
  186. package/src/resources/extensions/gsd/auto/phases.ts +14 -2
  187. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
  188. package/src/resources/extensions/gsd/auto-model-selection.ts +21 -1
  189. package/src/resources/extensions/gsd/auto-prompts.ts +15 -0
  190. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -6
  191. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +139 -0
  192. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +55 -0
  193. package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +48 -0
  194. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +59 -0
  195. package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +0 -9
  196. package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.js +0 -1
  197. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  198. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  199. /package/dist/web/standalone/.next/static/{mWBOLPnUoeaTGiD-vhu5O → 8yiPxQ52ue_s6qdrrAxsH}/_buildManifest.js +0 -0
  200. /package/dist/web/standalone/.next/static/{mWBOLPnUoeaTGiD-vhu5O → 8yiPxQ52ue_s6qdrrAxsH}/_ssgManifest.js +0 -0
@@ -0,0 +1,139 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+
7
+ import { resolvePreferredModelConfig } from "../auto-model-selection.js";
8
+
9
+ function makeTempDir(prefix: string): string {
10
+ return mkdtempSync(join(tmpdir(), prefix));
11
+ }
12
+
13
+ test("resolvePreferredModelConfig synthesizes heavy routing ceiling when models section is absent", () => {
14
+ const originalCwd = process.cwd();
15
+ const originalGsdHome = process.env.GSD_HOME;
16
+ const tempProject = makeTempDir("gsd-routing-project-");
17
+ const tempGsdHome = makeTempDir("gsd-routing-home-");
18
+
19
+ try {
20
+ mkdirSync(join(tempProject, ".gsd"), { recursive: true });
21
+ writeFileSync(
22
+ join(tempProject, ".gsd", "PREFERENCES.md"),
23
+ [
24
+ "---",
25
+ "dynamic_routing:",
26
+ " enabled: true",
27
+ " tier_models:",
28
+ " light: claude-haiku-4-5",
29
+ " standard: claude-sonnet-4-6",
30
+ " heavy: claude-opus-4-6",
31
+ "---",
32
+ ].join("\n"),
33
+ "utf-8",
34
+ );
35
+ process.env.GSD_HOME = tempGsdHome;
36
+ process.chdir(tempProject);
37
+
38
+ const config = resolvePreferredModelConfig("plan-slice", {
39
+ provider: "anthropic",
40
+ id: "claude-sonnet-4-6",
41
+ });
42
+
43
+ assert.deepEqual(config, {
44
+ primary: "claude-opus-4-6",
45
+ fallbacks: [],
46
+ });
47
+ } finally {
48
+ process.chdir(originalCwd);
49
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
50
+ else process.env.GSD_HOME = originalGsdHome;
51
+ rmSync(tempProject, { recursive: true, force: true });
52
+ rmSync(tempGsdHome, { recursive: true, force: true });
53
+ }
54
+ });
55
+
56
+ test("resolvePreferredModelConfig falls back to auto start model when heavy tier is absent", () => {
57
+ const originalCwd = process.cwd();
58
+ const originalGsdHome = process.env.GSD_HOME;
59
+ const tempProject = makeTempDir("gsd-routing-project-");
60
+ const tempGsdHome = makeTempDir("gsd-routing-home-");
61
+
62
+ try {
63
+ mkdirSync(join(tempProject, ".gsd"), { recursive: true });
64
+ writeFileSync(
65
+ join(tempProject, ".gsd", "PREFERENCES.md"),
66
+ [
67
+ "---",
68
+ "dynamic_routing:",
69
+ " enabled: true",
70
+ " tier_models:",
71
+ " light: claude-haiku-4-5",
72
+ " standard: claude-sonnet-4-6",
73
+ "---",
74
+ ].join("\n"),
75
+ "utf-8",
76
+ );
77
+ process.env.GSD_HOME = tempGsdHome;
78
+ process.chdir(tempProject);
79
+
80
+ const config = resolvePreferredModelConfig("execute-task", {
81
+ provider: "openai",
82
+ id: "gpt-5.4",
83
+ });
84
+
85
+ assert.deepEqual(config, {
86
+ primary: "openai/gpt-5.4",
87
+ fallbacks: [],
88
+ });
89
+ } finally {
90
+ process.chdir(originalCwd);
91
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
92
+ else process.env.GSD_HOME = originalGsdHome;
93
+ rmSync(tempProject, { recursive: true, force: true });
94
+ rmSync(tempGsdHome, { recursive: true, force: true });
95
+ }
96
+ });
97
+
98
+ test("resolvePreferredModelConfig keeps explicit phase models as the ceiling", () => {
99
+ const originalCwd = process.cwd();
100
+ const originalGsdHome = process.env.GSD_HOME;
101
+ const tempProject = makeTempDir("gsd-routing-project-");
102
+ const tempGsdHome = makeTempDir("gsd-routing-home-");
103
+
104
+ try {
105
+ mkdirSync(join(tempProject, ".gsd"), { recursive: true });
106
+ writeFileSync(
107
+ join(tempProject, ".gsd", "PREFERENCES.md"),
108
+ [
109
+ "---",
110
+ "models:",
111
+ " planning: claude-sonnet-4-6",
112
+ "dynamic_routing:",
113
+ " enabled: true",
114
+ " tier_models:",
115
+ " heavy: claude-opus-4-6",
116
+ "---",
117
+ ].join("\n"),
118
+ "utf-8",
119
+ );
120
+ process.env.GSD_HOME = tempGsdHome;
121
+ process.chdir(tempProject);
122
+
123
+ const config = resolvePreferredModelConfig("plan-slice", {
124
+ provider: "anthropic",
125
+ id: "claude-opus-4-6",
126
+ });
127
+
128
+ assert.deepEqual(config, {
129
+ primary: "claude-sonnet-4-6",
130
+ fallbacks: [],
131
+ });
132
+ } finally {
133
+ process.chdir(originalCwd);
134
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
135
+ else process.env.GSD_HOME = originalGsdHome;
136
+ rmSync(tempProject, { recursive: true, force: true });
137
+ rmSync(tempGsdHome, { recursive: true, force: true });
138
+ }
139
+ });
@@ -260,6 +260,61 @@ test("runDispatch emits dispatch-stop when dispatch returns stop action", async
260
260
  assert.equal(stopEvents[0].flowId, ic.flowId);
261
261
  });
262
262
 
263
+ test("runDispatch checks prior-slice completion against the project root in worktree mode", async () => {
264
+ const capture = createEventCapture();
265
+ const guardCalls: Array<{ fn: string; args: unknown[] }> = [];
266
+ const deps = makeMockDeps(capture, {
267
+ getMainBranch: (basePath: string) => {
268
+ guardCalls.push({ fn: "getMainBranch", args: [basePath] });
269
+ return "main";
270
+ },
271
+ getPriorSliceCompletionBlocker: (
272
+ basePath: string,
273
+ mainBranch: string,
274
+ unitType: string,
275
+ unitId: string,
276
+ ) => {
277
+ guardCalls.push({
278
+ fn: "getPriorSliceCompletionBlocker",
279
+ args: [basePath, mainBranch, unitType, unitId],
280
+ });
281
+ return null;
282
+ },
283
+ });
284
+ const ic = makeIC(deps, {
285
+ s: {
286
+ ...makeSession(),
287
+ basePath: "/tmp/project/.gsd/worktrees/M029-xoklo9",
288
+ originalBasePath: "/tmp/project",
289
+ } as any,
290
+ });
291
+ const preData: PreDispatchData = {
292
+ state: {
293
+ phase: "executing",
294
+ activeMilestone: { id: "M029-xoklo9", title: "Test", status: "active" },
295
+ activeSlice: { id: "S01", title: "Slice 1" },
296
+ registry: [{ id: "M029-xoklo9", status: "active" }],
297
+ blockers: [],
298
+ } as any,
299
+ mid: "M029-xoklo9",
300
+ midTitle: "Test Milestone",
301
+ };
302
+
303
+ const result = await runDispatch(ic, preData, {
304
+ recentUnits: [],
305
+ stuckRecoveryAttempts: 0,
306
+ });
307
+
308
+ assert.equal(result.action, "next");
309
+ assert.deepEqual(guardCalls, [
310
+ { fn: "getMainBranch", args: ["/tmp/project"] },
311
+ {
312
+ fn: "getPriorSliceCompletionBlocker",
313
+ args: ["/tmp/project", "main", "execute-task", "M001/S01/T01"],
314
+ },
315
+ ]);
316
+ });
317
+
263
318
  test("runUnitPhase emits unit-start and unit-end with causedBy reference", async () => {
264
319
  const capture = createEventCapture();
265
320
 
@@ -0,0 +1,48 @@
1
+ import { describe, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+
7
+ import { buildPlanMilestonePrompt } from "../auto-prompts.ts";
8
+
9
+ function createBase(): string {
10
+ const base = mkdtempSync(join(tmpdir(), "gsd-plan-queue-"));
11
+ mkdirSync(join(base, ".gsd", "milestones", "M010"), { recursive: true });
12
+ return base;
13
+ }
14
+
15
+ function cleanup(base: string): void {
16
+ rmSync(base, { recursive: true, force: true });
17
+ }
18
+
19
+ describe("plan-milestone queue context", () => {
20
+ test("includes queue brief when planning milestone without roadmap context", async () => {
21
+ const base = createBase();
22
+ try {
23
+ writeFileSync(
24
+ join(base, ".gsd", "QUEUE.md"),
25
+ [
26
+ "# Queue",
27
+ "",
28
+ "### M010: Analytics Dashboard — Interactivity, Intelligence & Demo Readiness",
29
+ "**Vision:** Ship a polished analytics dashboard with drilldowns and AI assistance.",
30
+ "",
31
+ "## Scope",
32
+ "- Interactivity",
33
+ "- Intelligence",
34
+ "- Demo readiness",
35
+ "",
36
+ ].join("\n"),
37
+ );
38
+
39
+ const prompt = await buildPlanMilestonePrompt("M010", "M010", base);
40
+
41
+ assert.match(prompt, /Source: `\.gsd\/QUEUE\.md`/);
42
+ assert.match(prompt, /Analytics Dashboard — Interactivity, Intelligence & Demo Readiness/);
43
+ assert.match(prompt, /Ship a polished analytics dashboard/);
44
+ } finally {
45
+ cleanup(base);
46
+ }
47
+ });
48
+ });
@@ -0,0 +1,59 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ import { handleRecoverableExtensionProcessError } from "../bootstrap/register-extension.ts";
5
+
6
+ test("handleRecoverableExtensionProcessError swallows spawn ENOENT", () => {
7
+ let stderr = "";
8
+ const originalWrite = process.stderr.write.bind(process.stderr);
9
+ process.stderr.write = ((chunk: string | Uint8Array) => {
10
+ stderr += String(chunk);
11
+ return true;
12
+ }) as typeof process.stderr.write;
13
+
14
+ try {
15
+ const handled = handleRecoverableExtensionProcessError(
16
+ Object.assign(new Error("missing binary"), {
17
+ code: "ENOENT",
18
+ syscall: "spawn npm",
19
+ path: "npm",
20
+ }),
21
+ );
22
+ assert.equal(handled, true);
23
+ assert.match(stderr, /spawn ENOENT: npm/);
24
+ } finally {
25
+ process.stderr.write = originalWrite;
26
+ }
27
+ });
28
+
29
+ test("handleRecoverableExtensionProcessError swallows uv_cwd ENOENT", () => {
30
+ let stderr = "";
31
+ const originalWrite = process.stderr.write.bind(process.stderr);
32
+ process.stderr.write = ((chunk: string | Uint8Array) => {
33
+ stderr += String(chunk);
34
+ return true;
35
+ }) as typeof process.stderr.write;
36
+
37
+ try {
38
+ const handled = handleRecoverableExtensionProcessError(
39
+ Object.assign(new Error("process.cwd failed"), {
40
+ code: "ENOENT",
41
+ syscall: "uv_cwd",
42
+ }),
43
+ );
44
+ assert.equal(handled, true);
45
+ assert.match(stderr, /ENOENT \(uv_cwd\): process\.cwd failed/);
46
+ } finally {
47
+ process.stderr.write = originalWrite;
48
+ }
49
+ });
50
+
51
+ test("handleRecoverableExtensionProcessError leaves unrelated errors unhandled", () => {
52
+ const handled = handleRecoverableExtensionProcessError(
53
+ Object.assign(new Error("permission denied"), {
54
+ code: "EPERM",
55
+ syscall: "open",
56
+ }),
57
+ );
58
+ assert.equal(handled, false);
59
+ });