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
@@ -35,6 +35,19 @@ function registerAlias(pi: ExtensionAPI, toolDef: any, aliasName: string, canoni
35
35
  });
36
36
  }
37
37
 
38
+ /**
39
+ * Read a tool result's structured payload, accommodating MCP's `details` →
40
+ * `structuredContent` rename (#4472, #4477). In-process executions still
41
+ * deliver the payload on `result.details`; MCP-routed executions deliver it
42
+ * on `result.structuredContent` (post `adaptExecutorResult` transform). All
43
+ * `renderResult` callbacks in this file route through this helper so a future
44
+ * field rename only needs to be applied in one place.
45
+ */
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- result shape varies by tool
47
+ function readDetails(result: any): any {
48
+ return result?.details ?? result?.structuredContent;
49
+ }
50
+
38
51
  export function registerDbTools(pi: ExtensionAPI): void {
39
52
  // ─── gsd_decision_save (formerly gsd_save_decision) ─────────────────────
40
53
 
@@ -110,7 +123,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
110
123
  return new Text(text, 0, 0);
111
124
  },
112
125
  renderResult(result: any, _options: any, theme: any) {
113
- const d = result.details;
126
+ const d = readDetails(result);
114
127
  if (result.isError || d?.error) {
115
128
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
116
129
  }
@@ -188,7 +201,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
188
201
  return new Text(text, 0, 0);
189
202
  },
190
203
  renderResult(result: any, _options: any, theme: any) {
191
- const d = result.details;
204
+ const d = readDetails(result);
192
205
  if (result.isError || d?.error) {
193
206
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
194
207
  }
@@ -273,7 +286,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
273
286
  return new Text(text, 0, 0);
274
287
  },
275
288
  renderResult(result: any, _options: any, theme: any) {
276
- const d = result.details;
289
+ const d = readDetails(result);
277
290
  if (result.isError || d?.error) {
278
291
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
279
292
  }
@@ -322,7 +335,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
322
335
  return new Text(text, 0, 0);
323
336
  },
324
337
  renderResult(result: any, _options: any, theme: any) {
325
- const d = result.details;
338
+ const d = readDetails(result);
326
339
  if (result.isError || d?.error) {
327
340
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
328
341
  }
@@ -406,7 +419,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
406
419
  return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
407
420
  },
408
421
  renderResult(result: any, _options: any, theme: any) {
409
- const d = result.details;
422
+ const d = readDetails(result);
410
423
  if (result.isError || d?.error) {
411
424
  return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
412
425
  }
@@ -1074,13 +1087,31 @@ export function registerDbTools(pi: ExtensionAPI): void {
1074
1087
  text += theme.fg("dim", ` → ${args.verdict ?? ""}`);
1075
1088
  return new Text(text, 0, 0);
1076
1089
  },
1090
+ /**
1091
+ * Render the save_gate_result tool output for the TUI.
1092
+ *
1093
+ * Prefers structured fields, but falls back to `content[0].text` when the
1094
+ * structured payload is empty. Defensive: the structural fix on this
1095
+ * branch plumbs `details` through MCP via `structuredContent`, but older
1096
+ * hosts, a future handler that forgets `structuredContent`, or any drop
1097
+ * of non-standard return fields would otherwise render as
1098
+ * "undefined: undefined". Same fallback applies to error rendering, and
1099
+ * we strip a leading `Error:` from the fallback text to avoid producing
1100
+ * `Error: Error: ...`.
1101
+ */
1077
1102
  renderResult(result: any, _options: any, theme: any) {
1078
- const d = result.details;
1103
+ const d = readDetails(result);
1079
1104
  if (result.isError || d?.error) {
1080
- return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
1105
+ const rawMsg = d?.error ?? result.content?.[0]?.text ?? "unknown";
1106
+ const msg = rawMsg.replace(/^\s*Error:\s*/i, "");
1107
+ return new Text(theme.fg("error", `Error: ${msg}`), 0, 0);
1108
+ }
1109
+ if (!d?.gateId || !d?.verdict) {
1110
+ const text = result.content?.[0]?.text ?? "Gate result saved";
1111
+ return new Text(theme.fg("success", text), 0, 0);
1081
1112
  }
1082
- const color = d?.verdict === "flag" ? "warning" : "success";
1083
- return new Text(theme.fg(color, `${d?.gateId}: ${d?.verdict}`), 0, 0);
1113
+ const color = d.verdict === "flag" ? "warning" : "success";
1114
+ return new Text(theme.fg(color, `${d.gateId}: ${d.verdict}`), 0, 0);
1084
1115
  },
1085
1116
  };
1086
1117
 
@@ -0,0 +1,109 @@
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
+
6
+ import { Type } from "@sinclair/typebox";
7
+ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
8
+
9
+ import { executeGsdExec } from "../tools/exec-tool.js";
10
+ import { executeExecSearch } from "../tools/exec-search-tool.js";
11
+ import { executeResume } from "../tools/resume-tool.js";
12
+ import { loadEffectiveGSDPreferences } from "../preferences.js";
13
+ import { logWarning } from "../workflow-logger.js";
14
+
15
+ export function registerExecTools(pi: ExtensionAPI): void {
16
+ pi.registerTool({
17
+ name: "gsd_exec",
18
+ label: "Exec (Sandboxed)",
19
+ description:
20
+ "Run a short script (bash/node/python) in a subprocess. Full stdout/stderr persist to " +
21
+ ".gsd/exec/<id>.{stdout,stderr,meta.json}; only a short digest returns in context. Use " +
22
+ "this instead of reading many files or emitting large tool outputs — e.g. have the script " +
23
+ "count/grep/summarize and log the finding. Enabled by default; opt out via " +
24
+ "preferences.context_mode.enabled=false.",
25
+ promptSnippet:
26
+ "Run a bash/node/python script in a sandbox; full output is saved to disk and only a digest returns",
27
+ promptGuidelines: [
28
+ "Prefer gsd_exec for analyses that would otherwise read >3 files or produce large tool output.",
29
+ "Write scripts that log the finding (counts, matches, summaries) rather than raw dumps.",
30
+ "The digest is the last ~300 chars of stdout — size your log output accordingly.",
31
+ "Need the full output? Read the stdout_path returned in details (file on local disk).",
32
+ ],
33
+ parameters: Type.Object({
34
+ runtime: Type.Union(
35
+ [Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")],
36
+ { description: "Interpreter: bash (-c), node (-e), or python3 (-c)." },
37
+ ),
38
+ script: Type.String({ description: "Script body. Keep output small (log the finding, not the data)." }),
39
+ purpose: Type.Optional(Type.String({ description: "Short label recorded in meta.json for later review." })),
40
+ timeout_ms: Type.Optional(
41
+ Type.Number({
42
+ description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
43
+ minimum: 1_000,
44
+ maximum: 600_000,
45
+ }),
46
+ ),
47
+ }),
48
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
49
+ let prefs: Awaited<ReturnType<typeof loadEffectiveGSDPreferences>> | null = null;
50
+ try {
51
+ prefs = loadEffectiveGSDPreferences();
52
+ } catch (err) {
53
+ logWarning("tool", `gsd_exec could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
54
+ }
55
+ return executeGsdExec(params as Parameters<typeof executeGsdExec>[0], {
56
+ baseDir: process.cwd(),
57
+ preferences: prefs?.preferences ?? null,
58
+ });
59
+ },
60
+ });
61
+
62
+ pi.registerTool({
63
+ name: "gsd_exec_search",
64
+ label: "Search gsd_exec History",
65
+ description:
66
+ "List prior gsd_exec runs (most recent first) from .gsd/exec/*.meta.json. Useful for " +
67
+ "rediscovering the stdout_path of an earlier run without re-executing it. Read-only.",
68
+ promptSnippet: "Search prior gsd_exec runs by substring, runtime, or failing-only filter",
69
+ promptGuidelines: [
70
+ "Use this before re-running an expensive analysis — the prior run's stdout file may still answer.",
71
+ "The preview shows the trailing ~300 chars of stdout; read stdout_path for the full transcript.",
72
+ ],
73
+ parameters: Type.Object({
74
+ query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
75
+ runtime: Type.Optional(
76
+ Type.Union([Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")], {
77
+ description: "Restrict to one runtime.",
78
+ }),
79
+ ),
80
+ failing_only: Type.Optional(Type.Boolean({ description: "Only non-zero exit codes and timeouts." })),
81
+ limit: Type.Optional(Type.Number({ description: "Max results (default 20, cap 200)", minimum: 1, maximum: 200 })),
82
+ }),
83
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
84
+ return executeExecSearch(params as Parameters<typeof executeExecSearch>[0], {
85
+ baseDir: process.cwd(),
86
+ });
87
+ },
88
+ });
89
+
90
+ pi.registerTool({
91
+ name: "gsd_resume",
92
+ label: "Resume (Read Snapshot)",
93
+ description:
94
+ "Return the contents of .gsd/last-snapshot.md — a ≤2 KB digest of top memories, recent " +
95
+ "gsd_exec runs, and active context, written automatically on session_before_compact. Use " +
96
+ "this after compaction or session resume to re-orient quickly.",
97
+ promptSnippet: "Read the pre-compaction snapshot to re-orient after context loss",
98
+ promptGuidelines: [
99
+ "Call this right after a session resumes if you feel you've lost durable context.",
100
+ "The snapshot is a summary — use memory_query or gsd_exec_search for detail.",
101
+ ],
102
+ parameters: Type.Object({}),
103
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
104
+ return executeResume(params as Parameters<typeof executeResume>[0], {
105
+ baseDir: process.cwd(),
106
+ });
107
+ },
108
+ });
109
+ }
@@ -8,6 +8,7 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
8
8
  import { loadEcosystemExtensions } from "../ecosystem/loader.js";
9
9
  import { registerDbTools } from "./db-tools.js";
10
10
  import { registerDynamicTools } from "./dynamic-tools.js";
11
+ import { registerExecTools } from "./exec-tools.js";
11
12
  import { registerJournalTools } from "./journal-tools.js";
12
13
  import { registerMemoryTools } from "./memory-tools.js";
13
14
  import { registerQueryTools } from "./query-tools.js";
@@ -100,6 +101,7 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
100
101
  ["journal-tools", () => registerJournalTools(pi)],
101
102
  ["query-tools", () => registerQueryTools(pi)],
102
103
  ["memory-tools", () => registerMemoryTools(pi)],
104
+ ["exec-tools", () => registerExecTools(pi)],
103
105
  ["shortcuts", () => registerShortcuts(pi)],
104
106
  ["hooks", () => registerHooks(pi, ecosystemHandlers)],
105
107
  ["ecosystem", () => {
@@ -18,7 +18,7 @@ import { loadToolApiKeys } from "../commands-config.js";
18
18
  import { loadFile, saveFile, formatContinue } from "../files.js";
19
19
  import { deriveState } from "../state.js";
20
20
  import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
21
- import { hideFooter } from "../auto-dashboard.js";
21
+
22
22
  import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
23
23
  import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
24
24
  import { saveActivityLog } from "../activity-log.js";
@@ -48,7 +48,9 @@ export function registerHooks(
48
48
  initNotificationStore(process.cwd());
49
49
  installNotifyInterceptor(ctx);
50
50
  initNotificationWidget(ctx);
51
- initHealthWidget(ctx);
51
+ if (!isAutoActive()) {
52
+ initHealthWidget(ctx);
53
+ }
52
54
  resetWriteGateState();
53
55
  resetToolCallLoopGuard();
54
56
  resetAskUserQuestionsCache();
@@ -90,7 +92,7 @@ export function registerHooks(
90
92
  }
91
93
  loadToolApiKeys();
92
94
  if (isAutoActive()) {
93
- ctx.ui.setFooter(hideFooter);
95
+ ctx.ui.setWidget("gsd-health", undefined);
94
96
  }
95
97
  });
96
98
 
@@ -113,7 +115,7 @@ export function registerHooks(
113
115
  }
114
116
  loadToolApiKeys();
115
117
  if (isAutoActive()) {
116
- ctx.ui.setFooter(hideFooter);
118
+ ctx.ui.setWidget("gsd-health", undefined);
117
119
  }
118
120
  });
119
121
 
@@ -225,6 +227,42 @@ export function registerHooks(
225
227
  }));
226
228
  });
227
229
 
230
+ // Context-mode snapshot: write .gsd/last-snapshot.md before compaction so
231
+ // agents can call gsd_resume (or Read the file) to re-orient. Opt-in via
232
+ // preferences.context_mode.enabled. Runs after the auto-cancel handler
233
+ // above — if that one returned cancel:true, pi still fires us but the
234
+ // compaction won't actually happen; the snapshot is still useful then,
235
+ // since auto may pause and resume later.
236
+ pi.on("session_before_compact", async () => {
237
+ try {
238
+ const { loadEffectiveGSDPreferences } = await import("../preferences.js");
239
+ const { isContextModeEnabled } = await import("../preferences-types.js");
240
+ const prefs = loadEffectiveGSDPreferences();
241
+ if (!isContextModeEnabled(prefs?.preferences)) return;
242
+ const { writeCompactionSnapshot } = await import("../compaction-snapshot.js");
243
+ const { ensureDbOpen } = await import("./dynamic-tools.js");
244
+ await ensureDbOpen();
245
+ const basePath = process.cwd();
246
+ let activeContext: string | null = null;
247
+ try {
248
+ const state = await deriveState(basePath);
249
+ if (state.activeMilestone && state.activeSlice && state.activeTask) {
250
+ activeContext =
251
+ `Active: ${state.activeMilestone.id} / ${state.activeSlice.id} / ${state.activeTask.id}` +
252
+ (state.activeTask.title ? ` — ${state.activeTask.title}` : "");
253
+ }
254
+ } catch {
255
+ /* non-fatal */
256
+ }
257
+ writeCompactionSnapshot(basePath, { activeContext });
258
+ } catch (err) {
259
+ safetyLogWarning(
260
+ "context-mode",
261
+ `failed to write compaction snapshot: ${err instanceof Error ? err.message : String(err)}`,
262
+ );
263
+ }
264
+ });
265
+
228
266
  pi.on("session_shutdown", async (_event, ctx: ExtensionContext) => {
229
267
  if (isParallelActive()) {
230
268
  try {
@@ -117,9 +117,21 @@ function normalizeWriteGateSnapshot(value: unknown): WriteGateSnapshot {
117
117
  };
118
118
  }
119
119
 
120
+ const EMPTY_SNAPSHOT: WriteGateSnapshot = {
121
+ verifiedDepthMilestones: [],
122
+ activeQueuePhase: false,
123
+ pendingGateId: null,
124
+ };
125
+
120
126
  export function loadWriteGateSnapshot(basePath: string = process.cwd()): WriteGateSnapshot {
121
127
  const path = writeGateSnapshotPath(basePath);
122
- if (!existsSync(path)) return currentWriteGateSnapshot();
128
+ if (!existsSync(path)) {
129
+ // When persist mode is active and the file has been deleted, treat it as a
130
+ // full state reset so deleting the file clears the HARD BLOCK gate.
131
+ // In non-persist mode the file is never written, so fall back to in-memory.
132
+ if (shouldPersistWriteGateSnapshot()) return EMPTY_SNAPSHOT;
133
+ return currentWriteGateSnapshot();
134
+ }
123
135
  try {
124
136
  return normalizeWriteGateSnapshot(JSON.parse(readFileSync(path, "utf-8")));
125
137
  } catch {