@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.eed73bea
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.
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
- package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
- package/dist/resources/extensions/gsd/auto-dispatch.js +17 -14
- package/dist/resources/extensions/gsd/auto-prompts.js +43 -12
- package/dist/resources/extensions/gsd/auto-recovery.js +13 -6
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -3
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +75 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
- package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
- package/dist/resources/extensions/gsd/db/queries.js +60 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +4 -4
- package/dist/resources/extensions/gsd/guided-flow-queue.js +59 -5
- package/dist/resources/extensions/gsd/health-widget.js +55 -29
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -2
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/session-forensics.js +11 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +52 -3
- package/dist/resources/extensions/gsd/tools/complete-slice.js +34 -3
- package/dist/resources/extensions/gsd/tools/complete-task.js +78 -16
- package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +25 -3
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{796.e0bdc932325d7e03.js → 796.3976108148518f7d.js} +3 -3
- package/dist/web/standalone/.next/static/chunks/{webpack-f46ea08200a0227e.js → webpack-7c1d97e39be2da11.js} +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +1 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +2 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +21 -9
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +3 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +34 -20
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -17
- package/src/resources/extensions/gsd/auto-prompts.ts +54 -12
- package/src/resources/extensions/gsd/auto-recovery.ts +13 -6
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +9 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +82 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
- package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
- package/src/resources/extensions/gsd/db/queries.ts +79 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +5 -5
- package/src/resources/extensions/gsd/guided-flow-queue.ts +82 -4
- package/src/resources/extensions/gsd/health-widget.ts +69 -32
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/session-forensics.ts +11 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +76 -8
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +119 -1
- package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
- package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
- package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +30 -3
- package/src/resources/extensions/gsd/tools/complete-task.ts +86 -16
- package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +25 -3
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → SzEuqWX37DR9MEpEuQjP1}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → SzEuqWX37DR9MEpEuQjP1}/_ssgManifest.js +0 -0
|
@@ -92,13 +92,27 @@ const CONTEXT_MODE_GUIDANCE_BY_LANE = {
|
|
|
92
92
|
orchestration: "Use `gsd_resume` before resuming orchestration, `gsd_exec_search` to reuse prior runs, and `gsd_exec` for noisy coordination checks.",
|
|
93
93
|
docs: "Use `gsd_resume` for prior context, `gsd_exec_search` for saved evidence, and `gsd_exec` for noisy doc validation commands.",
|
|
94
94
|
};
|
|
95
|
-
// Per-unit overrides win over the lane default.
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
// Per-unit overrides win over the lane default. Some units intentionally run
|
|
96
|
+
// with narrower tool contracts than their shared Context Mode lane, so their
|
|
97
|
+
// guidance must name only tools the unit can actually call.
|
|
98
|
+
export const CONTEXT_MODE_GUIDANCE_BY_UNIT = {
|
|
99
|
+
"discuss-milestone": "Use `ask_user_questions` to continue the milestone interview, then persist outcomes with `gsd_summary_save`, `gsd_decision_save`, `gsd_requirement_save`, `gsd_requirement_update`, `gsd_plan_milestone`, or `gsd_milestone_generate_id` as appropriate.",
|
|
100
|
+
"discuss-slice": "Use `ask_user_questions` to continue the slice interview, then persist outcomes with `gsd_summary_save` or `gsd_decision_save` as appropriate.",
|
|
101
|
+
"discuss-project": "Use `ask_user_questions` to continue the project interview, then persist outcomes with `gsd_summary_save`, `gsd_decision_save`, or `gsd_requirement_save` as appropriate.",
|
|
102
|
+
"discuss-requirements": "Use `ask_user_questions` to continue the requirements interview, then persist outcomes with `gsd_requirement_save` or `gsd_summary_save` as appropriate.",
|
|
103
|
+
"replan-slice": "Use `gsd_replan_slice` to persist the revised slice plan, and `gsd_decision_save` for planning decisions that need durable rationale.",
|
|
104
|
+
"reassess-roadmap": "Use `gsd_milestone_status` to inspect current milestone state, then `gsd_reassess_roadmap` to persist the roadmap reassessment.",
|
|
101
105
|
"run-uat": "Use `gsd_uat_exec` for acceptance checks so evidence is typed as UAT-owned, and `gsd_resume` after compaction or resume.",
|
|
106
|
+
"research-project": "Dispatch parallel scout subagents for stack, features, architecture, and pitfalls research; each writes one file under `.gsd/research/` (`STACK.md`, `FEATURES.md`, `ARCHITECTURE.md`, `PITFALLS.md`).",
|
|
107
|
+
"gate-evaluate": "Use `subagent` to dispatch tester agents, then persist each gate with `gsd_save_gate_result`; rely on testers for verification evidence.",
|
|
108
|
+
};
|
|
109
|
+
// Per-unit guidance for the nested render mode (renderMode: "nested"), used when this
|
|
110
|
+
// unit's Context Mode line is embedded into a subagent prompt — e.g. the tester prompts
|
|
111
|
+
// dispatched by gate-evaluate. Must instruct the subagent on what IT should do, not
|
|
112
|
+
// re-state the parent coordinator's dispatch instructions. Falls back to
|
|
113
|
+
// CONTEXT_MODE_GUIDANCE_BY_UNIT then the lane default when no nested entry exists.
|
|
114
|
+
export const CONTEXT_MODE_NESTED_GUIDANCE_BY_UNIT = {
|
|
115
|
+
"gate-evaluate": "Run verification checks to answer the gate question, then persist the verdict with `gsd_save_gate_result`.",
|
|
102
116
|
};
|
|
103
117
|
/**
|
|
104
118
|
* Render the Context Mode instruction lane for a unit type. Unknown unit
|
|
@@ -112,7 +126,9 @@ export function composeContextModeInstructions(unitType, opts) {
|
|
|
112
126
|
if (!manifest || manifest.contextMode === "none")
|
|
113
127
|
return "";
|
|
114
128
|
const lane = CONTEXT_MODE_LANE_LABELS[manifest.contextMode];
|
|
115
|
-
const guidance =
|
|
129
|
+
const guidance = (opts.renderMode === "nested" ? CONTEXT_MODE_NESTED_GUIDANCE_BY_UNIT[unitType] : undefined)
|
|
130
|
+
?? CONTEXT_MODE_GUIDANCE_BY_UNIT[unitType]
|
|
131
|
+
?? CONTEXT_MODE_GUIDANCE_BY_LANE[manifest.contextMode];
|
|
116
132
|
if (opts.renderMode === "nested") {
|
|
117
133
|
return `Context Mode (${lane} lane): ${guidance}`;
|
|
118
134
|
}
|
|
@@ -51,7 +51,13 @@ export const UNIT_REGISTRY = {
|
|
|
51
51
|
scopeClass: "standard",
|
|
52
52
|
phaseChain: ["research"],
|
|
53
53
|
toolContract: {
|
|
54
|
-
allowedGsdTools: [
|
|
54
|
+
allowedGsdTools: [
|
|
55
|
+
"gsd_summary_save",
|
|
56
|
+
"gsd_decision_save",
|
|
57
|
+
"gsd_exec",
|
|
58
|
+
"gsd_exec_search",
|
|
59
|
+
"gsd_resume",
|
|
60
|
+
],
|
|
55
61
|
requiredWorkflowTools: ["gsd_summary_save"],
|
|
56
62
|
},
|
|
57
63
|
},
|
|
@@ -107,7 +113,15 @@ export const UNIT_REGISTRY = {
|
|
|
107
113
|
scopeClass: "section-close",
|
|
108
114
|
phaseChain: ["validation", "planning"],
|
|
109
115
|
toolContract: {
|
|
110
|
-
allowedGsdTools: [
|
|
116
|
+
allowedGsdTools: [
|
|
117
|
+
"gsd_milestone_status",
|
|
118
|
+
"gsd_exec",
|
|
119
|
+
"gsd_exec_search",
|
|
120
|
+
"gsd_resume",
|
|
121
|
+
"gsd_validate_milestone",
|
|
122
|
+
"gsd_reassess_roadmap",
|
|
123
|
+
"subagent",
|
|
124
|
+
],
|
|
111
125
|
requiredWorkflowTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"],
|
|
112
126
|
},
|
|
113
127
|
},
|
|
@@ -118,6 +132,9 @@ export const UNIT_REGISTRY = {
|
|
|
118
132
|
toolContract: {
|
|
119
133
|
allowedGsdTools: [
|
|
120
134
|
"gsd_milestone_status",
|
|
135
|
+
"gsd_exec",
|
|
136
|
+
"gsd_exec_search",
|
|
137
|
+
"gsd_resume",
|
|
121
138
|
"gsd_requirement_update",
|
|
122
139
|
"gsd_summary_save",
|
|
123
140
|
"gsd_complete_milestone",
|
|
@@ -197,6 +214,8 @@ export const UNIT_REGISTRY = {
|
|
|
197
214
|
allowedGsdTools: [
|
|
198
215
|
"gsd_milestone_status",
|
|
199
216
|
"gsd_exec",
|
|
217
|
+
"gsd_exec_search",
|
|
218
|
+
"gsd_resume",
|
|
200
219
|
"gsd_slice_complete",
|
|
201
220
|
"gsd_task_reopen",
|
|
202
221
|
"gsd_replan_slice",
|
|
@@ -366,12 +385,15 @@ export const UNIT_REGISTRY = {
|
|
|
366
385
|
requiredWorkflowTools: ["ask_user_questions"],
|
|
367
386
|
},
|
|
368
387
|
},
|
|
388
|
+
// research-project dispatches 4 parallel scout subagents (Task calls); each scout
|
|
389
|
+
// writes one file under .gsd/research/ directly. The parent coordinator does not
|
|
390
|
+
// call gsd_summary_save or gsd_decision_save — the scouts own their own output.
|
|
369
391
|
"research-project": {
|
|
370
392
|
kind: "primary",
|
|
371
393
|
scopeClass: "standard",
|
|
372
394
|
phaseChain: ["research"],
|
|
373
395
|
toolContract: {
|
|
374
|
-
allowedGsdTools: [
|
|
396
|
+
allowedGsdTools: [],
|
|
375
397
|
requiredWorkflowTools: [],
|
|
376
398
|
},
|
|
377
399
|
},
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Block new workflow entry when completed milestone branches are still unmerged.
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
3
4
|
import { nativeBranchExists, nativeDetectMainBranch, nativeDiffNumstat, nativeIsAncestor, } from "./native-git-bridge.js";
|
|
4
5
|
import { autoWorktreeBranch } from "./auto-worktree.js";
|
|
5
6
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
6
7
|
import { getAllMilestones } from "./gsd-db.js";
|
|
7
8
|
import { resolveMilestoneIntegrationBranch } from "./git-service.js";
|
|
8
9
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
9
|
-
import { captureRootDirtySnapshot } from "./root-write-leak-guard.js";
|
|
10
10
|
import { isClosedStatus } from "./status-guards.js";
|
|
11
11
|
const BLOCKED_COMMANDS = new Set([
|
|
12
12
|
"auto",
|
|
@@ -49,6 +49,33 @@ const UNMERGED_SAFE_PARALLEL_SUBCOMMANDS = new Set([
|
|
|
49
49
|
function isRuntimePath(path) {
|
|
50
50
|
return path === ".gsd" || path.startsWith(".gsd/");
|
|
51
51
|
}
|
|
52
|
+
function captureDirtyPathStatusSnapshot(rootPath) {
|
|
53
|
+
const snapshot = new Map();
|
|
54
|
+
let status = "";
|
|
55
|
+
try {
|
|
56
|
+
status = execFileSync("git", ["status", "--porcelain", "--untracked-files=all"], {
|
|
57
|
+
cwd: rootPath,
|
|
58
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
59
|
+
encoding: "utf-8",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return snapshot;
|
|
64
|
+
}
|
|
65
|
+
for (const line of status.split("\n")) {
|
|
66
|
+
if (!line.trim())
|
|
67
|
+
continue;
|
|
68
|
+
const code = line.slice(0, 2);
|
|
69
|
+
const path = line.slice(3).replace(/^"|"$/g, "");
|
|
70
|
+
if (!path || isRuntimePath(path))
|
|
71
|
+
continue;
|
|
72
|
+
snapshot.set(path, {
|
|
73
|
+
path,
|
|
74
|
+
status: code.trim() || code,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return snapshot;
|
|
78
|
+
}
|
|
52
79
|
function formatCommandLabel(attemptedCommand) {
|
|
53
80
|
const trimmed = attemptedCommand.trim();
|
|
54
81
|
return trimmed ? `/gsd ${trimmed}` : "/gsd";
|
|
@@ -109,7 +136,7 @@ export function isUnmergedMilestoneAllowedCommand(trimmed) {
|
|
|
109
136
|
export async function findUnmergedCompletedMilestones(base) {
|
|
110
137
|
await ensureDbOpen(base);
|
|
111
138
|
const blockers = [];
|
|
112
|
-
|
|
139
|
+
let dirtyByPath = null;
|
|
113
140
|
for (const milestone of getAllMilestones()) {
|
|
114
141
|
if (!isClosedStatus(milestone.status))
|
|
115
142
|
continue;
|
|
@@ -134,13 +161,16 @@ export async function findUnmergedCompletedMilestones(base) {
|
|
|
134
161
|
const uniqueFiles = [...new Set(files)].sort();
|
|
135
162
|
if (uniqueFiles.length === 0)
|
|
136
163
|
continue;
|
|
164
|
+
if (!dirtyByPath)
|
|
165
|
+
dirtyByPath = captureDirtyPathStatusSnapshot(base);
|
|
166
|
+
const dirtySnapshot = dirtyByPath;
|
|
137
167
|
blockers.push({
|
|
138
168
|
milestoneId: milestone.id,
|
|
139
169
|
branch,
|
|
140
170
|
integrationBranch,
|
|
141
171
|
files: uniqueFiles,
|
|
142
172
|
dirtyOverlap: uniqueFiles
|
|
143
|
-
.map((path) =>
|
|
173
|
+
.map((path) => dirtySnapshot.get(path))
|
|
144
174
|
.filter((entry) => Boolean(entry)),
|
|
145
175
|
});
|
|
146
176
|
}
|
|
@@ -5,7 +5,7 @@ import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
|
|
|
5
5
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
6
6
|
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
7
7
|
import { getIsolationMode } from "./preferences.js";
|
|
8
|
-
import { deriveState } from "./state.js";
|
|
8
|
+
import { deriveState, invalidateStateCache } from "./state.js";
|
|
9
9
|
import { detectWorktreeName } from "./worktree.js";
|
|
10
10
|
const VALIDATION_BLOCK_RE = /milestone validation returned needs-(?:attention|remediation)|validation verdict is needs-(?:attention|remediation)/i;
|
|
11
11
|
const VALIDATION_SAFE_DISPATCH_COMMANDS = new Set([
|
|
@@ -116,9 +116,7 @@ export function formatValidationBlockedMessage(state, attemptedCommand = "") {
|
|
|
116
116
|
...blockers,
|
|
117
117
|
].join("\n\n");
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
await ensureDbOpen(base);
|
|
121
|
-
refreshWorkflowDatabaseFromDisk();
|
|
119
|
+
async function deriveValidationBlockState(base) {
|
|
122
120
|
let state = await deriveState(base);
|
|
123
121
|
if (state.activeMilestone &&
|
|
124
122
|
getIsolationMode(base) === "worktree" &&
|
|
@@ -129,5 +127,12 @@ export async function getValidationBlockMessageForBase(base, attemptedCommand =
|
|
|
129
127
|
state = await deriveState(wtPath);
|
|
130
128
|
}
|
|
131
129
|
}
|
|
130
|
+
return state;
|
|
131
|
+
}
|
|
132
|
+
export async function getValidationBlockMessageForBase(base, attemptedCommand = "") {
|
|
133
|
+
await ensureDbOpen(base);
|
|
134
|
+
refreshWorkflowDatabaseFromDisk();
|
|
135
|
+
invalidateStateCache();
|
|
136
|
+
const state = await deriveValidationBlockState(base);
|
|
132
137
|
return formatValidationBlockedMessage(state, attemptedCommand);
|
|
133
138
|
}
|
|
@@ -4,9 +4,11 @@ import { existsSync, realpathSync } from "node:fs";
|
|
|
4
4
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
5
5
|
import { isSafeToAutoResolve } from "./auto-worktree.js";
|
|
6
6
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
7
|
-
import { probeGitConflictState, reconcileGitConflictsOnSignal, } from "./git-conflict-state.js";
|
|
7
|
+
import { listMergeStateBlockers, probeGitConflictState, reconcileGitConflictsOnSignal, } from "./git-conflict-state.js";
|
|
8
8
|
import { deriveState } from "./state.js";
|
|
9
9
|
import { resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
10
|
+
const CLEAN_TARGET_CACHE_TTL_MS = 10_000;
|
|
11
|
+
const cleanTargetProbeCache = new Map();
|
|
10
12
|
function normalizeTargetPath(path) {
|
|
11
13
|
try {
|
|
12
14
|
return realpathSync(path);
|
|
@@ -77,6 +79,25 @@ function formatBlockReason(severity, conflictedPaths, targets) {
|
|
|
77
79
|
}
|
|
78
80
|
async function ensureTargetGitReady(target) {
|
|
79
81
|
const fixesApplied = [];
|
|
82
|
+
const cacheKey = normalizeTargetPath(target);
|
|
83
|
+
const cachedCleanAt = cleanTargetProbeCache.get(cacheKey);
|
|
84
|
+
if (cachedCleanAt !== undefined) {
|
|
85
|
+
if (Date.now() - cachedCleanAt < CLEAN_TARGET_CACHE_TTL_MS) {
|
|
86
|
+
// Merge-state markers (MERGE_HEAD, rebase-apply, rebase-merge) are the most
|
|
87
|
+
// common way a repo transitions from clean to dirty within the TTL window,
|
|
88
|
+
// including when a non-git folder is initialized as a repo mid-TTL and a
|
|
89
|
+
// merge immediately introduces conflicts. Check them here — they are pure
|
|
90
|
+
// existsSync calls with no git subprocess — and fall through to a full probe
|
|
91
|
+
// only when markers are present.
|
|
92
|
+
if (listMergeStateBlockers(cacheKey).length === 0) {
|
|
93
|
+
return { ok: true, fixesApplied };
|
|
94
|
+
}
|
|
95
|
+
cleanTargetProbeCache.delete(cacheKey);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
cleanTargetProbeCache.delete(cacheKey);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
80
101
|
let probe = probeGitConflictState(target);
|
|
81
102
|
for (let attempt = 0; attempt < 3 && probe.status === "dirty"; attempt++) {
|
|
82
103
|
const beforeKey = JSON.stringify({
|
|
@@ -95,6 +116,7 @@ async function ensureTargetGitReady(target) {
|
|
|
95
116
|
break;
|
|
96
117
|
}
|
|
97
118
|
if (probe.status === "unknown") {
|
|
119
|
+
cleanTargetProbeCache.delete(cacheKey);
|
|
98
120
|
return {
|
|
99
121
|
ok: false,
|
|
100
122
|
reason: formatBlockReason("unrecoverable", [], [target]),
|
|
@@ -106,6 +128,7 @@ async function ensureTargetGitReady(target) {
|
|
|
106
128
|
}
|
|
107
129
|
const conflictedPaths = productConflictPaths(probe);
|
|
108
130
|
if (conflictedPaths.length > 0 || probe.checkFailures.length > 0) {
|
|
131
|
+
cleanTargetProbeCache.delete(cacheKey);
|
|
109
132
|
return {
|
|
110
133
|
ok: false,
|
|
111
134
|
reason: formatBlockReason("product-conflicts", conflictedPaths, [target]),
|
|
@@ -115,6 +138,12 @@ async function ensureTargetGitReady(target) {
|
|
|
115
138
|
targets: [target],
|
|
116
139
|
};
|
|
117
140
|
}
|
|
141
|
+
if (probe.status === "clean") {
|
|
142
|
+
cleanTargetProbeCache.set(cacheKey, Date.now());
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
cleanTargetProbeCache.delete(cacheKey);
|
|
146
|
+
}
|
|
118
147
|
return { ok: true, fixesApplied };
|
|
119
148
|
}
|
|
120
149
|
/** Probe and heal a single git root (tests and headless paths). */
|