gsd-pi 2.76.0-dev.4c866b677 → 2.76.0-dev.7218806ab

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 (187) hide show
  1. package/dist/claude-cli-check.js +32 -3
  2. package/dist/mcp-server.d.ts +7 -0
  3. package/dist/mcp-server.js +35 -1
  4. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  5. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  6. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
  7. package/dist/resources/extensions/gsd/auto-start.js +11 -15
  8. package/dist/resources/extensions/gsd/auto.js +13 -17
  9. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
  10. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  11. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  12. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +40 -4
  14. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +12 -1
  15. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  16. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  17. package/dist/resources/extensions/gsd/error-classifier.js +10 -3
  18. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  19. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  20. package/dist/resources/extensions/gsd/gsd-db.js +3 -1
  21. package/dist/resources/extensions/gsd/guided-flow.js +189 -0
  22. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  23. package/dist/resources/extensions/gsd/key-manager.js +6 -0
  24. package/dist/resources/extensions/gsd/model-router.js +36 -3
  25. package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -9
  26. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  27. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  28. package/dist/resources/extensions/gsd/preferences.js +17 -17
  29. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  30. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  31. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  32. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  33. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  34. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  35. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  36. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  37. package/dist/web/standalone/.next/BUILD_ID +1 -1
  38. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  39. package/dist/web/standalone/.next/build-manifest.json +2 -2
  40. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  41. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.html +1 -1
  58. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  65. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  67. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  68. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  69. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  70. package/package.json +1 -1
  71. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  72. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  73. package/packages/mcp-server/dist/remote-questions.js +732 -0
  74. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  75. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  76. package/packages/mcp-server/dist/server.js +18 -1
  77. package/packages/mcp-server/dist/server.js.map +1 -1
  78. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  79. package/packages/mcp-server/dist/workflow-tools.js +64 -25
  80. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  81. package/packages/mcp-server/package.json +2 -1
  82. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  83. package/packages/mcp-server/src/remote-questions.ts +916 -0
  84. package/packages/mcp-server/src/server.ts +19 -1
  85. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  86. package/packages/mcp-server/src/workflow-tools.ts +84 -43
  87. package/packages/mcp-server/tsconfig.test.json +19 -0
  88. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  89. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  90. package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -0
  91. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  92. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  93. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  94. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  95. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  96. package/packages/pi-ai/src/providers/anthropic-shared.ts +3 -1
  97. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  98. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  99. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  100. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  101. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  102. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  103. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  104. package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
  105. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  106. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  107. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  108. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  109. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  110. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  111. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  112. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  113. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  114. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  115. package/packages/pi-coding-agent/dist/core/session-manager.js +9 -5
  116. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/session-manager.test.js +25 -1
  118. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  121. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  122. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  123. package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
  124. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  125. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  126. package/packages/pi-coding-agent/src/core/session-manager.test.ts +36 -1
  127. package/packages/pi-coding-agent/src/core/session-manager.ts +9 -5
  128. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  129. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  130. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  131. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  132. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  133. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
  134. package/src/resources/extensions/gsd/auto-post-unit.ts +0 -1
  135. package/src/resources/extensions/gsd/auto-start.ts +13 -16
  136. package/src/resources/extensions/gsd/auto.ts +12 -17
  137. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
  138. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  139. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  140. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  141. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +42 -4
  142. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +13 -1
  143. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  144. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  145. package/src/resources/extensions/gsd/error-classifier.ts +10 -3
  146. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  147. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  148. package/src/resources/extensions/gsd/gsd-db.ts +3 -1
  149. package/src/resources/extensions/gsd/guided-flow.ts +221 -0
  150. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  151. package/src/resources/extensions/gsd/key-manager.ts +6 -0
  152. package/src/resources/extensions/gsd/model-router.ts +42 -1
  153. package/src/resources/extensions/gsd/pre-execution-checks.ts +36 -10
  154. package/src/resources/extensions/gsd/preferences-types.ts +38 -0
  155. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  156. package/src/resources/extensions/gsd/preferences.ts +17 -17
  157. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  158. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  159. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  160. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  161. package/src/resources/extensions/gsd/tests/exec-history.test.ts +124 -0
  162. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  163. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +64 -0
  164. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  165. package/src/resources/extensions/gsd/tests/key-manager.test.ts +7 -0
  166. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  167. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +234 -0
  168. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  169. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  170. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
  171. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  172. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  173. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  174. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  175. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  176. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  177. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  178. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  179. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  180. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  181. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  182. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  183. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  184. package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
  185. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  186. /package/dist/web/standalone/.next/static/{jDqWYbuP_CG6Kjc-uKwkN → 5qAwYhcU5Fs2VOq_R8lOc}/_buildManifest.js +0 -0
  187. /package/dist/web/standalone/.next/static/{jDqWYbuP_CG6Kjc-uKwkN → 5qAwYhcU5Fs2VOq_R8lOc}/_ssgManifest.js +0 -0
@@ -19,6 +19,18 @@ function registerAlias(pi, toolDef, aliasName, canonicalName) {
19
19
  promptGuidelines: [`Alias for ${canonicalName} — prefer the canonical name.`],
20
20
  });
21
21
  }
22
+ /**
23
+ * Read a tool result's structured payload, accommodating MCP's `details` →
24
+ * `structuredContent` rename (#4472, #4477). In-process executions still
25
+ * deliver the payload on `result.details`; MCP-routed executions deliver it
26
+ * on `result.structuredContent` (post `adaptExecutorResult` transform). All
27
+ * `renderResult` callbacks in this file route through this helper so a future
28
+ * field rename only needs to be applied in one place.
29
+ */
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- result shape varies by tool
31
+ function readDetails(result) {
32
+ return result?.details ?? result?.structuredContent;
33
+ }
22
34
  export function registerDbTools(pi) {
23
35
  // ─── gsd_decision_save (formerly gsd_save_decision) ─────────────────────
24
36
  const decisionSaveExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
@@ -92,7 +104,7 @@ export function registerDbTools(pi) {
92
104
  return new Text(text, 0, 0);
93
105
  },
94
106
  renderResult(result, _options, theme) {
95
- const d = result.details;
107
+ const d = readDetails(result);
96
108
  if (result.isError || d?.error) {
97
109
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
98
110
  }
@@ -175,7 +187,7 @@ export function registerDbTools(pi) {
175
187
  return new Text(text, 0, 0);
176
188
  },
177
189
  renderResult(result, _options, theme) {
178
- const d = result.details;
190
+ const d = readDetails(result);
179
191
  if (result.isError || d?.error) {
180
192
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
181
193
  }
@@ -255,7 +267,7 @@ export function registerDbTools(pi) {
255
267
  return new Text(text, 0, 0);
256
268
  },
257
269
  renderResult(result, _options, theme) {
258
- const d = result.details;
270
+ const d = readDetails(result);
259
271
  if (result.isError || d?.error) {
260
272
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
261
273
  }
@@ -301,7 +313,7 @@ export function registerDbTools(pi) {
301
313
  return new Text(text, 0, 0);
302
314
  },
303
315
  renderResult(result, _options, theme) {
304
- const d = result.details;
316
+ const d = readDetails(result);
305
317
  if (result.isError || d?.error) {
306
318
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
307
319
  }
@@ -382,7 +394,7 @@ export function registerDbTools(pi) {
382
394
  return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
383
395
  },
384
396
  renderResult(result, _options, theme) {
385
- const d = result.details;
397
+ const d = readDetails(result);
386
398
  if (result.isError || d?.error) {
387
399
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
388
400
  }
@@ -967,13 +979,31 @@ export function registerDbTools(pi) {
967
979
  text += theme.fg("dim", ` → ${args.verdict ?? ""}`);
968
980
  return new Text(text, 0, 0);
969
981
  },
982
+ /**
983
+ * Render the save_gate_result tool output for the TUI.
984
+ *
985
+ * Prefers structured fields, but falls back to `content[0].text` when the
986
+ * structured payload is empty. Defensive: the structural fix on this
987
+ * branch plumbs `details` through MCP via `structuredContent`, but older
988
+ * hosts, a future handler that forgets `structuredContent`, or any drop
989
+ * of non-standard return fields would otherwise render as
990
+ * "undefined: undefined". Same fallback applies to error rendering, and
991
+ * we strip a leading `Error:` from the fallback text to avoid producing
992
+ * `Error: Error: ...`.
993
+ */
970
994
  renderResult(result, _options, theme) {
971
- const d = result.details;
995
+ const d = readDetails(result);
972
996
  if (result.isError || d?.error) {
973
- return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
997
+ const rawMsg = d?.error ?? result.content?.[0]?.text ?? "unknown";
998
+ const msg = rawMsg.replace(/^\s*Error:\s*/i, "");
999
+ return new Text(theme.fg("error", `Error: ${msg}`), 0, 0);
1000
+ }
1001
+ if (!d?.gateId || !d?.verdict) {
1002
+ const text = result.content?.[0]?.text ?? "Gate result saved";
1003
+ return new Text(theme.fg("success", text), 0, 0);
974
1004
  }
975
- const color = d?.verdict === "flag" ? "warning" : "success";
976
- return new Text(theme.fg(color, `${d?.gateId}: ${d?.verdict}`), 0, 0);
1005
+ const color = d.verdict === "flag" ? "warning" : "success";
1006
+ return new Text(theme.fg(color, `${d.gateId}: ${d.verdict}`), 0, 0);
977
1007
  },
978
1008
  };
979
1009
  pi.registerTool(saveGateResultTool);
@@ -0,0 +1,93 @@
1
+ // GSD2 — Exec (context-mode) tool registration.
2
+ //
3
+ // Exposes the `gsd_exec` tool over MCP. Opt-in: disabled unless
4
+ // `context_mode.enabled: true` is set in preferences.
5
+ import { Type } from "@sinclair/typebox";
6
+ import { executeGsdExec } from "../tools/exec-tool.js";
7
+ import { executeExecSearch } from "../tools/exec-search-tool.js";
8
+ import { executeResume } from "../tools/resume-tool.js";
9
+ import { loadEffectiveGSDPreferences } from "../preferences.js";
10
+ import { logWarning } from "../workflow-logger.js";
11
+ export function registerExecTools(pi) {
12
+ pi.registerTool({
13
+ name: "gsd_exec",
14
+ label: "Exec (Sandboxed)",
15
+ description: "Run a short script (bash/node/python) in a subprocess. Full stdout/stderr persist to " +
16
+ ".gsd/exec/<id>.{stdout,stderr,meta.json}; only a short digest returns in context. Use " +
17
+ "this instead of reading many files or emitting large tool outputs — e.g. have the script " +
18
+ "count/grep/summarize and log the finding. Enabled by default; opt out via " +
19
+ "preferences.context_mode.enabled=false.",
20
+ promptSnippet: "Run a bash/node/python script in a sandbox; full output is saved to disk and only a digest returns",
21
+ promptGuidelines: [
22
+ "Prefer gsd_exec for analyses that would otherwise read >3 files or produce large tool output.",
23
+ "Write scripts that log the finding (counts, matches, summaries) rather than raw dumps.",
24
+ "The digest is the last ~300 chars of stdout — size your log output accordingly.",
25
+ "Need the full output? Read the stdout_path returned in details (file on local disk).",
26
+ ],
27
+ parameters: Type.Object({
28
+ runtime: Type.Union([Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")], { description: "Interpreter: bash (-c), node (-e), or python3 (-c)." }),
29
+ script: Type.String({ description: "Script body. Keep output small (log the finding, not the data)." }),
30
+ purpose: Type.Optional(Type.String({ description: "Short label recorded in meta.json for later review." })),
31
+ timeout_ms: Type.Optional(Type.Number({
32
+ description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
33
+ minimum: 1_000,
34
+ maximum: 600_000,
35
+ })),
36
+ }),
37
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
38
+ let prefs = null;
39
+ try {
40
+ prefs = loadEffectiveGSDPreferences();
41
+ }
42
+ catch (err) {
43
+ logWarning("tool", `gsd_exec could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
44
+ }
45
+ return executeGsdExec(params, {
46
+ baseDir: process.cwd(),
47
+ preferences: prefs?.preferences ?? null,
48
+ });
49
+ },
50
+ });
51
+ pi.registerTool({
52
+ name: "gsd_exec_search",
53
+ label: "Search gsd_exec History",
54
+ description: "List prior gsd_exec runs (most recent first) from .gsd/exec/*.meta.json. Useful for " +
55
+ "rediscovering the stdout_path of an earlier run without re-executing it. Read-only.",
56
+ promptSnippet: "Search prior gsd_exec runs by substring, runtime, or failing-only filter",
57
+ promptGuidelines: [
58
+ "Use this before re-running an expensive analysis — the prior run's stdout file may still answer.",
59
+ "The preview shows the trailing ~300 chars of stdout; read stdout_path for the full transcript.",
60
+ ],
61
+ parameters: Type.Object({
62
+ query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
63
+ runtime: Type.Optional(Type.Union([Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")], {
64
+ description: "Restrict to one runtime.",
65
+ })),
66
+ failing_only: Type.Optional(Type.Boolean({ description: "Only non-zero exit codes and timeouts." })),
67
+ limit: Type.Optional(Type.Number({ description: "Max results (default 20, cap 200)", minimum: 1, maximum: 200 })),
68
+ }),
69
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
70
+ return executeExecSearch(params, {
71
+ baseDir: process.cwd(),
72
+ });
73
+ },
74
+ });
75
+ pi.registerTool({
76
+ name: "gsd_resume",
77
+ label: "Resume (Read Snapshot)",
78
+ description: "Return the contents of .gsd/last-snapshot.md — a ≤2 KB digest of top memories, recent " +
79
+ "gsd_exec runs, and active context, written automatically on session_before_compact. Use " +
80
+ "this after compaction or session resume to re-orient quickly.",
81
+ promptSnippet: "Read the pre-compaction snapshot to re-orient after context loss",
82
+ promptGuidelines: [
83
+ "Call this right after a session resumes if you feel you've lost durable context.",
84
+ "The snapshot is a summary — use memory_query or gsd_exec_search for detail.",
85
+ ],
86
+ parameters: Type.Object({}),
87
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
88
+ return executeResume(params, {
89
+ baseDir: process.cwd(),
90
+ });
91
+ },
92
+ });
93
+ }
@@ -4,6 +4,7 @@ import { registerWorktreeCommand } from "../worktree-command.js";
4
4
  import { loadEcosystemExtensions } from "../ecosystem/loader.js";
5
5
  import { registerDbTools } from "./db-tools.js";
6
6
  import { registerDynamicTools } from "./dynamic-tools.js";
7
+ import { registerExecTools } from "./exec-tools.js";
7
8
  import { registerJournalTools } from "./journal-tools.js";
8
9
  import { registerMemoryTools } from "./memory-tools.js";
9
10
  import { registerQueryTools } from "./query-tools.js";
@@ -86,6 +87,7 @@ export function registerGsdExtension(pi) {
86
87
  ["journal-tools", () => registerJournalTools(pi)],
87
88
  ["query-tools", () => registerQueryTools(pi)],
88
89
  ["memory-tools", () => registerMemoryTools(pi)],
90
+ ["exec-tools", () => registerExecTools(pi)],
89
91
  ["shortcuts", () => registerShortcuts(pi)],
90
92
  ["hooks", () => registerHooks(pi, ecosystemHandlers)],
91
93
  ["ecosystem", () => {
@@ -13,7 +13,6 @@ import { loadToolApiKeys } from "../commands-config.js";
13
13
  import { loadFile, saveFile, formatContinue } from "../files.js";
14
14
  import { deriveState } from "../state.js";
15
15
  import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
16
- import { hideFooter } from "../auto-dashboard.js";
17
16
  import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
18
17
  import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
19
18
  import { saveActivityLog } from "../activity-log.js";
@@ -37,7 +36,9 @@ export function registerHooks(pi, ecosystemHandlers) {
37
36
  initNotificationStore(process.cwd());
38
37
  installNotifyInterceptor(ctx);
39
38
  initNotificationWidget(ctx);
40
- initHealthWidget(ctx);
39
+ if (!isAutoActive()) {
40
+ initHealthWidget(ctx);
41
+ }
41
42
  resetWriteGateState();
42
43
  resetToolCallLoopGuard();
43
44
  resetAskUserQuestionsCache();
@@ -79,7 +80,7 @@ export function registerHooks(pi, ecosystemHandlers) {
79
80
  }
80
81
  loadToolApiKeys();
81
82
  if (isAutoActive()) {
82
- ctx.ui.setFooter(hideFooter);
83
+ ctx.ui.setWidget("gsd-health", undefined);
83
84
  }
84
85
  });
85
86
  pi.on("session_switch", async (_event, ctx) => {
@@ -101,7 +102,7 @@ export function registerHooks(pi, ecosystemHandlers) {
101
102
  }
102
103
  loadToolApiKeys();
103
104
  if (isAutoActive()) {
104
- ctx.ui.setFooter(hideFooter);
105
+ ctx.ui.setWidget("gsd-health", undefined);
105
106
  }
106
107
  });
107
108
  pi.on("before_agent_start", async (event, ctx) => {
@@ -204,6 +205,41 @@ export function registerHooks(pi, ecosystemHandlers) {
204
205
  nextAction: `Resume task ${state.activeTask.id}: ${state.activeTask.title}.`,
205
206
  }));
206
207
  });
208
+ // Context-mode snapshot: write .gsd/last-snapshot.md before compaction so
209
+ // agents can call gsd_resume (or Read the file) to re-orient. Opt-in via
210
+ // preferences.context_mode.enabled. Runs after the auto-cancel handler
211
+ // above — if that one returned cancel:true, pi still fires us but the
212
+ // compaction won't actually happen; the snapshot is still useful then,
213
+ // since auto may pause and resume later.
214
+ pi.on("session_before_compact", async () => {
215
+ try {
216
+ const { loadEffectiveGSDPreferences } = await import("../preferences.js");
217
+ const { isContextModeEnabled } = await import("../preferences-types.js");
218
+ const prefs = loadEffectiveGSDPreferences();
219
+ if (!isContextModeEnabled(prefs?.preferences))
220
+ return;
221
+ const { writeCompactionSnapshot } = await import("../compaction-snapshot.js");
222
+ const { ensureDbOpen } = await import("./dynamic-tools.js");
223
+ await ensureDbOpen();
224
+ const basePath = process.cwd();
225
+ let activeContext = null;
226
+ try {
227
+ const state = await deriveState(basePath);
228
+ if (state.activeMilestone && state.activeSlice && state.activeTask) {
229
+ activeContext =
230
+ `Active: ${state.activeMilestone.id} / ${state.activeSlice.id} / ${state.activeTask.id}` +
231
+ (state.activeTask.title ? ` — ${state.activeTask.title}` : "");
232
+ }
233
+ }
234
+ catch {
235
+ /* non-fatal */
236
+ }
237
+ writeCompactionSnapshot(basePath, { activeContext });
238
+ }
239
+ catch (err) {
240
+ safetyLogWarning("context-mode", `failed to write compaction snapshot: ${err instanceof Error ? err.message : String(err)}`);
241
+ }
242
+ });
207
243
  pi.on("session_shutdown", async (_event, ctx) => {
208
244
  if (isParallelActive()) {
209
245
  try {
@@ -99,10 +99,21 @@ function normalizeWriteGateSnapshot(value) {
99
99
  pendingGateId: typeof record.pendingGateId === "string" ? record.pendingGateId : null,
100
100
  };
101
101
  }
102
+ const EMPTY_SNAPSHOT = {
103
+ verifiedDepthMilestones: [],
104
+ activeQueuePhase: false,
105
+ pendingGateId: null,
106
+ };
102
107
  export function loadWriteGateSnapshot(basePath = process.cwd()) {
103
108
  const path = writeGateSnapshotPath(basePath);
104
- if (!existsSync(path))
109
+ if (!existsSync(path)) {
110
+ // When persist mode is active and the file has been deleted, treat it as a
111
+ // full state reset so deleting the file clears the HARD BLOCK gate.
112
+ // In non-persist mode the file is never written, so fall back to in-memory.
113
+ if (shouldPersistWriteGateSnapshot())
114
+ return EMPTY_SNAPSHOT;
105
115
  return currentWriteGateSnapshot();
116
+ }
106
117
  try {
107
118
  return normalizeWriteGateSnapshot(JSON.parse(readFileSync(path, "utf-8")));
108
119
  }