gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.2be7caf18

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 (182) hide show
  1. package/README.md +3 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto-prompts.js +13 -1
  5. package/dist/resources/extensions/gsd/auto.js +7 -2
  6. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
  7. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
  8. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  9. package/dist/resources/extensions/gsd/guided-flow.js +33 -6
  10. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  11. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  12. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  13. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  14. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  15. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  16. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  17. package/dist/resources/extensions/gsd/quick.js +34 -2
  18. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  19. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  20. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  21. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  22. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  23. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  24. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  25. package/dist/resources/extensions/gsd/unit-runtime.js +11 -0
  26. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  27. package/dist/web/standalone/.next/BUILD_ID +1 -1
  28. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  29. package/dist/web/standalone/.next/build-manifest.json +2 -2
  30. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  31. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/index.html +1 -1
  48. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  55. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  57. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  58. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  59. package/package.json +1 -1
  60. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  61. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  62. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  63. package/packages/mcp-server/src/workflow-tools.test.ts +66 -0
  64. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  65. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  66. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  67. package/packages/pi-coding-agent/dist/core/agent-session.js +3 -0
  68. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  70. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  71. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  72. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  73. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  74. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  75. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  76. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  77. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  78. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  79. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  80. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  81. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  82. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  83. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  84. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  85. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  86. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  87. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
  88. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  89. package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
  90. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  91. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
  92. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  94. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  97. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  98. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  99. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  104. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
  106. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  108. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  110. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  111. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  113. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  114. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  115. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  116. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  118. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  119. package/packages/pi-coding-agent/src/core/agent-session.ts +3 -0
  120. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  121. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  122. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  123. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  124. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  125. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
  126. package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
  127. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  128. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  129. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
  130. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  131. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
  132. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  133. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  134. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  135. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  136. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  137. package/packages/pi-tui/dist/tui.js +18 -8
  138. package/packages/pi-tui/dist/tui.js.map +1 -1
  139. package/packages/pi-tui/src/tui.ts +20 -8
  140. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  141. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  142. package/src/resources/extensions/gsd/auto-prompts.ts +17 -1
  143. package/src/resources/extensions/gsd/auto.ts +11 -2
  144. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
  145. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  146. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  147. package/src/resources/extensions/gsd/guided-flow.ts +39 -6
  148. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  149. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  150. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  151. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  152. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  153. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  154. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  155. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  156. package/src/resources/extensions/gsd/quick.ts +37 -2
  157. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +11 -0
  158. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  159. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  160. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  161. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  162. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  163. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  164. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  165. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  166. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  167. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  168. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
  169. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +17 -0
  170. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  171. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  172. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +7 -0
  173. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  174. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  175. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  176. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  177. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  178. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  179. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  180. package/src/resources/extensions/gsd/unit-runtime.ts +14 -0
  181. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → 3EDDd9ULaybSupPoA_vf-}/_buildManifest.js +0 -0
  182. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → 3EDDd9ULaybSupPoA_vf-}/_ssgManifest.js +0 -0
@@ -0,0 +1,26 @@
1
+ import { isAbsolute, relative, resolve } from "node:path";
2
+ import { normalizePlannedFileReference } from "./files.js";
3
+ function isInsideBase(basePath, candidate) {
4
+ const base = resolve(basePath);
5
+ const abs = resolve(candidate);
6
+ const rel = relative(base, abs);
7
+ return rel === "" || (!!rel && !rel.startsWith("..") && !isAbsolute(rel));
8
+ }
9
+ /**
10
+ * Planning IO fields are execution contracts. Absolute paths are only safe when
11
+ * they stay inside the active working directory; in worktree mode, an absolute
12
+ * path to the original checkout makes executors edit the wrong tree.
13
+ */
14
+ export function validatePlanningPathScope(basePath, fields) {
15
+ for (const { field, values } of fields) {
16
+ for (const raw of values) {
17
+ const candidate = normalizePlannedFileReference(raw);
18
+ if (!isAbsolute(candidate))
19
+ continue;
20
+ if (isInsideBase(basePath, candidate))
21
+ continue;
22
+ return `${field} contains absolute path outside working directory: ${candidate}. Use a path relative to ${basePath}.`;
23
+ }
24
+ }
25
+ return null;
26
+ }
@@ -16,7 +16,7 @@ Dispatch ALL slices simultaneously using the `subagent` tool in **parallel mode*
16
16
 
17
17
  1. Call `subagent` with `tasks: [...]` containing one entry per slice below
18
18
  2. Wait for ALL subagents to complete
19
- 3. Verify each slice's RESEARCH file was written (check the `.gsd/{{mid}}/` directory)
19
+ 3. Verify each slice's RESEARCH file was written (check `.gsd/milestones/{{mid}}/slices/<slice-id>/`)
20
20
  4. If a subagent failed to write its RESEARCH file, retry it **once** individually
21
21
  5. If it fails a second time, write a partial RESEARCH file for that slice with a `## BLOCKER` section explaining the failure — do NOT retry again
22
22
  6. Report which slices completed research and which (if any) needed a blocker note
@@ -39,7 +39,7 @@ If slice research is inlined, trust it. Explore enough code to confirm paths, bo
39
39
  5. Define slice verification before tasks. Non-trivial slices need real tests or executable assertions; boundary contracts need contract-exercising checks. Tests must not read .gitignore/gitignored paths such as `.gsd/`, `.planning/`, or `.audits/`.
40
40
  6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
41
41
  7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
42
- 8. Each task needs a concrete title, Why / Files / Do / Verify / Done when, plus task-plan description, steps, must-haves, verification, inputs, and expected output. Inputs and Expected Output must include concrete backtick-wrapped paths; each task needs at least one output path.
42
+ 8. Each task needs a concrete title, Why / Files / Do / Verify / Done when, plus task-plan description, steps, must-haves, verification, inputs, and expected output. Inputs and Expected Output must include concrete backtick-wrapped paths; each task needs at least one output path. Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands.
43
43
  9. Persist with `gsd_plan_slice` using goal, successCriteria, optional proofLevel/integrationClosure/observabilityImpact, and tasks. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
44
44
  10. Self-audit before finishing: goal/demo closure, requirement coverage, locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
45
45
  11. If planning creates structural decisions, append them to `.gsd/DECISIONS.md`.
@@ -17,11 +17,7 @@ You are executing a GSD quick task — a lightweight, focused unit of work outsi
17
17
  5. Verify your work:
18
18
  - Run tests if applicable.
19
19
  - Verify both happy path and failure modes for non-trivial changes.
20
- 6. Commit your changes atomically:
21
- - Use conventional commit messages (feat:, fix:, refactor:, etc.)
22
- - Stage only relevant files — never commit secrets or runtime files.
23
- - Commit logical units separately if the task involves distinct changes.
24
- - Quick tasks run outside the auto-mode lifecycle — there is no system auto-commit, so commit directly here.
20
+ 6. {{commitInstruction}}
25
21
  7. Write a brief summary to `{{summaryPath}}`:
26
22
  - Quick tasks operate outside the milestone/slice/task DB structure, so `gsd_summary_save` (which requires a `milestone_id`) cannot be used here. Write the file directly.
27
23
 
@@ -27,13 +27,13 @@ Roadmap, slice summaries, assessments, requirements, decisions, and project cont
27
27
  Call `subagent` with `tasks: [...]` containing ALL THREE reviewers simultaneously:
28
28
 
29
29
  **Reviewer A - Requirements Coverage**
30
- Prompt: "Review milestone {{milestoneId}} requirements coverage. Working directory: {{workingDirectory}}. Read `.gsd/{{milestoneId}}/REQUIREMENTS.md` or equivalent. For each requirement, check slice SUMMARY files in `.gsd/{{milestoneId}}/` and mark COVERED, PARTIAL, or MISSING. Output table: Requirement | Status | Evidence. End with one-line verdict: PASS if all covered, NEEDS-ATTENTION if partials exist, FAIL if any missing."
30
+ Prompt: "Review milestone {{milestoneId}} requirements coverage. Working directory: {{workingDirectory}}. Read `.gsd/REQUIREMENTS.md` or use the inlined requirements context. For each requirement, check slice SUMMARY files under `.gsd/milestones/{{milestoneId}}/slices/` and mark COVERED, PARTIAL, or MISSING. Output table: Requirement | Status | Evidence. End with one-line verdict: PASS if all covered, NEEDS-ATTENTION if partials exist, FAIL if any missing."
31
31
 
32
32
  **Reviewer B - Cross-Slice Integration**
33
33
  Prompt: "Review milestone {{milestoneId}} cross-slice integration. Working directory: {{workingDirectory}}. Read `{{roadmapPath}}` and find the boundary map (produces/consumes contracts). For each boundary, confirm producer SUMMARY produced the artifact and consumer SUMMARY consumed it. Output table: Boundary | Producer Summary | Consumer Summary | Status. End with one-line verdict: PASS if all boundaries honored, NEEDS-ATTENTION if any gaps."
34
34
 
35
35
  **Reviewer C - Assessment & Acceptance Criteria**
36
- Prompt: "Review milestone {{milestoneId}} assessment evidence and acceptance criteria. Working directory: {{workingDirectory}}. Read `.gsd/{{milestoneId}}/CONTEXT.md` for criteria. Check slice ASSESSMENT files. Verify each criterion maps to a passing assessment or clear SUMMARY evidence. Then review inlined milestone verification classes. For each non-empty planned class, output table: Class | Planned Check | Evidence | Verdict. Use the exact class names `Contract`, `Integration`, `Operational`, and `UAT` whenever those classes are present. If no verification classes were planned, say that explicitly. Output sections `Acceptance Criteria` with checklist `[ ] Criterion | Evidence`, and `Verification Classes` with the table. End with one-line verdict: PASS if all criteria and classes are covered, NEEDS-ATTENTION if gaps exist."
36
+ Prompt: "Review milestone {{milestoneId}} assessment evidence and acceptance criteria. Working directory: {{workingDirectory}}. Read `.gsd/milestones/{{milestoneId}}/{{milestoneId}}-CONTEXT.md` for criteria. Check slice SUMMARY/UAT files under `.gsd/milestones/{{milestoneId}}/slices/`. Verify each criterion maps to passing evidence. Then review inlined milestone verification classes. For each non-empty planned class, output table: Class | Planned Check | Evidence | Verdict. Use the exact class names `Contract`, `Integration`, `Operational`, and `UAT` whenever those classes are present. If no verification classes were planned, say that explicitly. Output sections `Acceptance Criteria` with checklist `[ ] Criterion | Evidence`, and `Verification Classes` with the table. End with one-line verdict: PASS if all criteria and classes are covered, NEEDS-ATTENTION if gaps exist."
37
37
 
38
38
  ### Step 2 - Synthesize Findings
39
39
 
@@ -8,8 +8,8 @@
8
8
  * Quick tasks live in `.gsd/quick/` and are tracked in STATE.md's
9
9
  * "Quick Tasks Completed" table.
10
10
  */
11
- import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
12
- import { join } from "node:path";
11
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
12
+ import { isAbsolute, join, relative } from "node:path";
13
13
  import { loadPrompt } from "./prompt-loader.js";
14
14
  import { gsdRoot } from "./paths.js";
15
15
  import { GitServiceImpl, runGit } from "./git-service.js";
@@ -64,6 +64,37 @@ function ensureQuickDir(basePath, taskNum, slug) {
64
64
  mkdirSync(taskDir, { recursive: true });
65
65
  return taskDir;
66
66
  }
67
+ function isPathInside(parent, child) {
68
+ const rel = relative(parent, child);
69
+ return rel === "" || (!!rel && !rel.startsWith("..") && !isAbsolute(rel));
70
+ }
71
+ function isExternalGsdRoot(basePath, root) {
72
+ try {
73
+ return !isPathInside(realpathSync(basePath), realpathSync(root));
74
+ }
75
+ catch {
76
+ return !isPathInside(basePath, root);
77
+ }
78
+ }
79
+ export function buildQuickCommitInstruction(basePath, root) {
80
+ const externalState = isExternalGsdRoot(basePath, root);
81
+ if (externalState) {
82
+ return [
83
+ "Commit repo changes atomically, but do not stage or commit `.gsd/quick/...`:",
84
+ " - `.gsd/` resolves outside this git repository, so Git cannot stage quick-task summary files from the project repo.",
85
+ " - Write the quick summary file directly at the requested path; that file is persisted by GSD external state.",
86
+ " - Stage and commit only implementation/test/docs files that live inside the repository.",
87
+ " - If the task only writes quick-task research/summary files and no repository files changed, do not run `git commit`; report that there was nothing in the project repo to commit.",
88
+ ].join("\n");
89
+ }
90
+ return [
91
+ "Commit your changes atomically:",
92
+ " - Use conventional commit messages (feat:, fix:, refactor:, etc.)",
93
+ " - Stage only relevant files — never commit secrets or runtime files.",
94
+ " - Commit logical units separately if the task involves distinct changes.",
95
+ " - Quick tasks run outside the auto-mode lifecycle — there is no system auto-commit, so commit directly here.",
96
+ ].join("\n");
97
+ }
67
98
  function quickReturnStatePath(basePath) {
68
99
  return join(gsdRoot(basePath), "runtime", "quick-return.json");
69
100
  }
@@ -198,6 +229,7 @@ export async function handleQuick(args, ctx, pi) {
198
229
  taskDir: taskDirRel,
199
230
  branch: actualBranch,
200
231
  summaryPath,
232
+ commitInstruction: buildQuickCommitInstruction(basePath, root),
201
233
  date,
202
234
  taskNum: String(taskNum),
203
235
  slug,
@@ -0,0 +1,15 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Shared Context Mode tool result helpers.
3
+ export function contextModeDisabledResult(operation) {
4
+ return {
5
+ content: [
6
+ {
7
+ type: "text",
8
+ text: `${operation} is disabled by \`context_mode.enabled: false\` in preferences. ` +
9
+ "Remove that override or set it to true to re-enable Context Mode tools.",
10
+ },
11
+ ],
12
+ details: { operation, error: "context_mode_disabled" },
13
+ isError: true,
14
+ };
15
+ }
@@ -3,7 +3,12 @@
3
3
  // Scans .gsd/exec/*.meta.json and returns a ranked summary so agents can
4
4
  // re-discover past runs without re-executing. Read-only; no DB writes.
5
5
  import { searchExecHistory } from "../exec-history.js";
6
+ import { isContextModeEnabled } from "../preferences-types.js";
7
+ import { contextModeDisabledResult } from "./context-mode-tool-result.js";
6
8
  export function executeExecSearch(params, opts) {
9
+ if (!isContextModeEnabled(opts.preferences)) {
10
+ return contextModeDisabledResult("gsd_exec_search");
11
+ }
7
12
  const searchOpts = {
8
13
  query: typeof params.query === "string" ? params.query : undefined,
9
14
  runtime: params.runtime,
@@ -5,6 +5,7 @@
5
5
  // for MCP return.
6
6
  import { EXEC_DEFAULTS, runExecSandbox, } from "../exec-sandbox.js";
7
7
  import { isContextModeEnabled } from "../preferences-types.js";
8
+ import { contextModeDisabledResult } from "./context-mode-tool-result.js";
8
9
  export function buildExecOptions(baseDir, cfg, extras) {
9
10
  const allowlist = Array.isArray(cfg?.exec_env_allowlist) ? cfg.exec_env_allowlist : EXEC_DEFAULTS.envAllowlist;
10
11
  const stdoutCap = clampNumber(cfg?.exec_stdout_cap_bytes, EXEC_DEFAULTS.stdoutCapBytes, 4_096, 16_777_216);
@@ -33,19 +34,6 @@ function clampNumber(value, fallback, min, max) {
33
34
  function isEnabled(prefs) {
34
35
  return isContextModeEnabled(prefs);
35
36
  }
36
- function disabledResult() {
37
- return {
38
- content: [
39
- {
40
- type: "text",
41
- text: "gsd_exec is disabled by `context_mode.enabled: false` in preferences. Remove that " +
42
- "override (or set it to true) to re-enable sandboxed tool-output execution.",
43
- },
44
- ],
45
- details: { operation: "gsd_exec", error: "context_mode_disabled" },
46
- isError: true,
47
- };
48
- }
49
37
  function paramError(message) {
50
38
  return {
51
39
  content: [{ type: "text", text: `Error: ${message}` }],
@@ -55,7 +43,7 @@ function paramError(message) {
55
43
  }
56
44
  export async function executeGsdExec(params, deps) {
57
45
  if (!isEnabled(deps.preferences))
58
- return disabledResult();
46
+ return contextModeDisabledResult("gsd_exec");
59
47
  const runtime = params.runtime;
60
48
  if (runtime !== "bash" && runtime !== "node" && runtime !== "python") {
61
49
  return paramError(`invalid runtime "${String(runtime)}" — must be bash | node | python`);
@@ -67,7 +55,7 @@ export async function executeGsdExec(params, deps) {
67
55
  if (Buffer.byteLength(script, "utf8") > 200_000) {
68
56
  return paramError("script exceeds the 200 KB length limit");
69
57
  }
70
- const opts = buildExecOptions(deps.baseDir, deps.preferences?.context_mode, { now: deps.now, generateId: deps.generateId });
58
+ const opts = buildExecOptions(deps.baseDir, deps.preferences?.context_mode, { env: deps.env, now: deps.now, generateId: deps.generateId });
71
59
  const run = deps.run ?? runExecSandbox;
72
60
  try {
73
61
  const result = await run({
@@ -8,6 +8,7 @@ import { renderAllProjections } from "../workflow-projections.js";
8
8
  import { writeManifest } from "../workflow-manifest.js";
9
9
  import { appendEvent } from "../workflow-events.js";
10
10
  import { logWarning } from "../workflow-logger.js";
11
+ import { validatePlanningPathScope } from "../planning-path-scope.js";
11
12
  function validateTasks(value) {
12
13
  if (!Array.isArray(value) || value.length === 0) {
13
14
  throw new Error("tasks must be a non-empty array");
@@ -91,6 +92,14 @@ export async function handlePlanSlice(rawParams, basePath) {
91
92
  catch (err) {
92
93
  return { error: `validation failed: ${err.message}` };
93
94
  }
95
+ const pathScopeError = validatePlanningPathScope(basePath, params.tasks.flatMap((task, index) => [
96
+ { field: `tasks[${index}].files`, values: task.files },
97
+ { field: `tasks[${index}].inputs`, values: task.inputs },
98
+ { field: `tasks[${index}].expectedOutput`, values: task.expectedOutput },
99
+ ]));
100
+ if (pathScopeError) {
101
+ return { error: `validation failed: ${pathScopeError}` };
102
+ }
94
103
  // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
95
104
  // Guards must be inside the transaction so the state they check cannot
96
105
  // change between the read and the write (#2723).
@@ -8,6 +8,7 @@ import { renderAllProjections } from "../workflow-projections.js";
8
8
  import { writeManifest } from "../workflow-manifest.js";
9
9
  import { appendEvent } from "../workflow-events.js";
10
10
  import { logWarning } from "../workflow-logger.js";
11
+ import { validatePlanningPathScope } from "../planning-path-scope.js";
11
12
  function validateParams(params) {
12
13
  if (!isNonEmptyString(params?.milestoneId))
13
14
  throw new Error("milestoneId is required");
@@ -41,6 +42,14 @@ export async function handlePlanTask(rawParams, basePath) {
41
42
  catch (err) {
42
43
  return { error: `validation failed: ${err.message}` };
43
44
  }
45
+ const pathScopeError = validatePlanningPathScope(basePath, [
46
+ { field: "files", values: params.files },
47
+ { field: "inputs", values: params.inputs },
48
+ { field: "expectedOutput", values: params.expectedOutput },
49
+ ]);
50
+ if (pathScopeError) {
51
+ return { error: `validation failed: ${pathScopeError}` };
52
+ }
44
53
  // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
45
54
  // Guards must be inside the transaction so the state they check cannot
46
55
  // change between the read and the write (#2723).
@@ -2,7 +2,12 @@
2
2
  // agents can re-orient after compaction or session resume without
3
3
  // re-deriving project memory state.
4
4
  import { readCompactionSnapshot } from "../compaction-snapshot.js";
5
+ import { isContextModeEnabled } from "../preferences-types.js";
6
+ import { contextModeDisabledResult } from "./context-mode-tool-result.js";
5
7
  export function executeResume(_params, opts) {
8
+ if (!isContextModeEnabled(opts.preferences)) {
9
+ return contextModeDisabledResult("gsd_resume");
10
+ }
6
11
  const snapshot = readCompactionSnapshot(opts.baseDir);
7
12
  if (snapshot == null) {
8
13
  return {
@@ -80,7 +80,15 @@ const CONTEXT_MODE_LANE_LABELS = {
80
80
  orchestration: "orchestration",
81
81
  docs: "documentation",
82
82
  };
83
- const CONTEXT_MODE_GUIDANCE = "Use `gsd_exec` for noisy commands, `gsd_exec_search` before reruns, and `gsd_resume` after compaction or resume.";
83
+ const CONTEXT_MODE_GUIDANCE_BY_LANE = {
84
+ interview: "Use `gsd_resume` to restore prior discussion, `gsd_exec` for noisy discovery, and `gsd_exec_search` before repeating scans.",
85
+ research: "Use `gsd_exec` for noisy research scans, `gsd_exec_search` before reruns, and `gsd_resume` to restore prior findings.",
86
+ planning: "Use `gsd_resume` for planning continuity, `gsd_exec` for noisy checks, and `gsd_exec_search` before rerunning diagnostics.",
87
+ execution: "Use `gsd_exec` for builds, tests, and diagnostics, `gsd_exec_search` before reruns, and `gsd_resume` after compaction or resume.",
88
+ verification: "Use `gsd_exec` for verification commands, `gsd_exec_search` to reuse prior evidence, and `gsd_resume` after compaction or resume.",
89
+ orchestration: "Use `gsd_resume` before resuming orchestration, `gsd_exec_search` to reuse prior runs, and `gsd_exec` for noisy coordination checks.",
90
+ docs: "Use `gsd_resume` for prior context, `gsd_exec_search` for saved evidence, and `gsd_exec` for noisy doc validation commands.",
91
+ };
84
92
  /**
85
93
  * Render the Context Mode instruction lane for a unit type. Unknown unit
86
94
  * types, disabled config, and explicit `contextMode: "none"` all omit the
@@ -93,14 +101,15 @@ export function composeContextModeInstructions(unitType, opts) {
93
101
  if (!manifest || manifest.contextMode === "none")
94
102
  return "";
95
103
  const lane = CONTEXT_MODE_LANE_LABELS[manifest.contextMode];
104
+ const guidance = CONTEXT_MODE_GUIDANCE_BY_LANE[manifest.contextMode];
96
105
  if (opts.renderMode === "nested") {
97
- return `Context Mode (${lane} lane): ${CONTEXT_MODE_GUIDANCE}`;
106
+ return `Context Mode (${lane} lane): ${guidance}`;
98
107
  }
99
108
  return [
100
109
  "## Context Mode",
101
110
  "",
102
111
  `Lane: **${lane} lane**.`,
103
- CONTEXT_MODE_GUIDANCE,
112
+ guidance,
104
113
  ].join("\n");
105
114
  }
106
115
  const SECTION_SEPARATOR = "\n\n---\n\n";
@@ -67,6 +67,17 @@ function withRecordLock(recordPath, fn) {
67
67
  catch { /* best-effort */ }
68
68
  }
69
69
  }
70
+ export const IN_FLIGHT_RUNTIME_PHASES = new Set([
71
+ "dispatched",
72
+ "wrapup-warning-sent",
73
+ "timeout",
74
+ "finalize-timeout",
75
+ "crashed",
76
+ "paused",
77
+ ]);
78
+ export function isInFlightRuntimePhase(phase) {
79
+ return IN_FLIGHT_RUNTIME_PHASES.has(phase);
80
+ }
70
81
  function runtimeDir(basePath) {
71
82
  return join(gsdRoot(basePath), "runtime", "units");
72
83
  }