gsd-pi 2.82.0-dev.dfbc5f58f → 2.82.0-dev.e7a7f1ed5
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/README.md +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- package/dist/resources/extensions/gsd/auto/phases.js +73 -30
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +10 -16
- package/dist/resources/extensions/gsd/auto-recovery.js +40 -13
- package/dist/resources/extensions/gsd/auto-start.js +3 -3
- package/dist/resources/extensions/gsd/auto-verification.js +17 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +65 -9
- package/dist/resources/extensions/gsd/auto.js +7 -2
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +27 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +16 -4
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
- package/dist/resources/extensions/gsd/git-service.js +6 -2
- package/dist/resources/extensions/gsd/gsd-db.js +20 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +95 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +7 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +17 -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 +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/browse-directories/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 +9 -9
- package/dist/web/standalone/.next/server/middleware-build-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/package.json +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/gsd/auto/phases.ts +83 -37
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +10 -16
- package/src/resources/extensions/gsd/auto-recovery.ts +45 -11
- package/src/resources/extensions/gsd/auto-start.ts +2 -3
- package/src/resources/extensions/gsd/auto-verification.ts +22 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +74 -9
- package/src/resources/extensions/gsd/auto.ts +8 -2
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +36 -6
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +16 -2
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- package/src/resources/extensions/gsd/git-service.ts +6 -3
- package/src/resources/extensions/gsd/gsd-db.ts +18 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +128 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +8 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +76 -5
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +18 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
- /package/dist/web/standalone/.next/static/{q0WYuDVbHeFFYbdd-fei2 → 4dSwdrs__8NwCZggxP9KF}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{q0WYuDVbHeFFYbdd-fei2 → 4dSwdrs__8NwCZggxP9KF}/_ssgManifest.js +0 -0
|
@@ -110,6 +110,49 @@ test("completing-milestone blocks when VALIDATION verdict is needs-attention (#5
|
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
+
test("completing-milestone blocks when VALIDATION verdict is fail (#5920)", async () => {
|
|
114
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-fail-verdict-"));
|
|
115
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
writeFileSync(
|
|
119
|
+
join(base, ".gsd", "milestones", "M001", "M001-VALIDATION.md"),
|
|
120
|
+
[
|
|
121
|
+
"---",
|
|
122
|
+
"verdict: fail",
|
|
123
|
+
"---",
|
|
124
|
+
"",
|
|
125
|
+
"# Validation Report",
|
|
126
|
+
"",
|
|
127
|
+
"Blocking failures remain unresolved.",
|
|
128
|
+
].join("\n"),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const ctx = {
|
|
132
|
+
mid: "M001",
|
|
133
|
+
midTitle: "Test Milestone",
|
|
134
|
+
basePath: base,
|
|
135
|
+
state: { phase: "completing-milestone" } as any,
|
|
136
|
+
prefs: {} as any,
|
|
137
|
+
session: undefined,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = await completingRule!.match(ctx);
|
|
141
|
+
|
|
142
|
+
assert.ok(result !== null, "rule should match");
|
|
143
|
+
assert.equal(result!.action, "stop", "should return stop action");
|
|
144
|
+
if (result!.action === "stop") {
|
|
145
|
+
assert.equal(result!.level, "warning", "should be warning level (pausable)");
|
|
146
|
+
assert.ok(
|
|
147
|
+
result!.reason.includes('verdict is "fail"'),
|
|
148
|
+
"reason should mention fail verdict",
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
} finally {
|
|
152
|
+
rmSync(base, { recursive: true, force: true });
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
113
156
|
test("completing-milestone proceeds normally when VALIDATION verdict is pass (#2675 guard)", async () => {
|
|
114
157
|
const base = mkdtempSync(join(tmpdir(), "gsd-remediation-"));
|
|
115
158
|
mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
|
|
@@ -36,7 +36,7 @@ function makeUatProject(): string {
|
|
|
36
36
|
return base;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
test("run-uat dispatch
|
|
39
|
+
test("run-uat dispatch skips after three attempts without a verdict", async () => {
|
|
40
40
|
const basePath = makeUatProject();
|
|
41
41
|
const rule = DISPATCH_RULES.find((r) => r.name === "run-uat (post-completion)");
|
|
42
42
|
assert.ok(rule, "run-uat dispatch rule is registered");
|
|
@@ -58,8 +58,7 @@ test("run-uat dispatch stops after three attempts without a verdict", async () =
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const capped = await rule.match(ctx as any);
|
|
61
|
-
assert.equal(capped?.action, "
|
|
62
|
-
assert.match(capped?.reason ?? "", /dispatched 3 times/);
|
|
61
|
+
assert.equal(capped?.action, "skip");
|
|
63
62
|
assert.equal(getUatCount(basePath, "M001", "S01"), 4);
|
|
64
63
|
} finally {
|
|
65
64
|
rmSync(basePath, { recursive: true, force: true });
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// GSD-2 — Smart entry routing behavior tests.
|
|
2
|
+
// Verifies guided wizard choices resolve to the correct execution path.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
resolveActiveTaskChoiceRoute,
|
|
9
|
+
resolveGuidedExecuteLaunchMode,
|
|
10
|
+
type ActiveTaskChoice,
|
|
11
|
+
type ActiveTaskRoute,
|
|
12
|
+
type SmartEntryIsolationMode,
|
|
13
|
+
} from "../smart-entry-routing.ts";
|
|
14
|
+
|
|
15
|
+
test("guided execute route enters auto step bootstrap only for worktree isolation", () => {
|
|
16
|
+
const cases: Array<{
|
|
17
|
+
isolationMode: SmartEntryIsolationMode;
|
|
18
|
+
expectedRoute: ActiveTaskRoute;
|
|
19
|
+
}> = [
|
|
20
|
+
{
|
|
21
|
+
isolationMode: "worktree",
|
|
22
|
+
expectedRoute: {
|
|
23
|
+
kind: "auto-bootstrap",
|
|
24
|
+
verboseMode: false,
|
|
25
|
+
options: {
|
|
26
|
+
step: true,
|
|
27
|
+
milestoneLock: "M001",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
isolationMode: "none",
|
|
33
|
+
expectedRoute: {
|
|
34
|
+
kind: "guided-dispatch",
|
|
35
|
+
unitType: "execute-task",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
isolationMode: "branch",
|
|
40
|
+
expectedRoute: {
|
|
41
|
+
kind: "guided-dispatch",
|
|
42
|
+
unitType: "execute-task",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
for (const testCase of cases) {
|
|
48
|
+
assert.deepEqual(
|
|
49
|
+
resolveActiveTaskChoiceRoute({
|
|
50
|
+
choice: "execute",
|
|
51
|
+
isolationMode: testCase.isolationMode,
|
|
52
|
+
milestoneId: "M001",
|
|
53
|
+
}),
|
|
54
|
+
testCase.expectedRoute,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("active task smart entry choices resolve to explicit routes", () => {
|
|
60
|
+
const cases: Array<{
|
|
61
|
+
choice: ActiveTaskChoice;
|
|
62
|
+
expectedRoute: ActiveTaskRoute;
|
|
63
|
+
}> = [
|
|
64
|
+
{
|
|
65
|
+
choice: "auto",
|
|
66
|
+
expectedRoute: {
|
|
67
|
+
kind: "auto-bootstrap",
|
|
68
|
+
verboseMode: false,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
choice: "status",
|
|
73
|
+
expectedRoute: {
|
|
74
|
+
kind: "status",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
choice: "milestone_actions",
|
|
79
|
+
expectedRoute: {
|
|
80
|
+
kind: "milestone-actions",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const testCase of cases) {
|
|
86
|
+
assert.deepEqual(
|
|
87
|
+
resolveActiveTaskChoiceRoute({
|
|
88
|
+
choice: testCase.choice,
|
|
89
|
+
isolationMode: "worktree",
|
|
90
|
+
milestoneId: "M001",
|
|
91
|
+
}),
|
|
92
|
+
testCase.expectedRoute,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("active task route rejects invalid choices from untyped callers", () => {
|
|
98
|
+
assert.throws(
|
|
99
|
+
() =>
|
|
100
|
+
resolveActiveTaskChoiceRoute({
|
|
101
|
+
choice: "not_yet" as ActiveTaskChoice,
|
|
102
|
+
isolationMode: "worktree",
|
|
103
|
+
milestoneId: "M001",
|
|
104
|
+
}),
|
|
105
|
+
/Invalid ActiveTaskChoice: not_yet/,
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("guided execute launch mode remains a small compatibility helper", () => {
|
|
110
|
+
assert.equal(resolveGuidedExecuteLaunchMode("worktree"), "auto-step");
|
|
111
|
+
assert.equal(resolveGuidedExecuteLaunchMode("none"), "guided-dispatch");
|
|
112
|
+
assert.equal(resolveGuidedExecuteLaunchMode("branch"), "guided-dispatch");
|
|
113
|
+
});
|
|
@@ -4,7 +4,10 @@ import { readFileSync } from "node:fs";
|
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
|
|
6
6
|
import { _withDetachedAutoKeepaliveForTest } from "../auto.ts";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
_scheduleAutoStartAfterIdleForTest,
|
|
9
|
+
resolveGuidedExecuteLaunchMode,
|
|
10
|
+
} from "../guided-flow.ts";
|
|
8
11
|
|
|
9
12
|
const gsdDir = resolve(import.meta.dirname, "..");
|
|
10
13
|
|
|
@@ -64,6 +67,24 @@ test("bare /gsd stays in the foreground smart-entry flow (#5125 regression)", ()
|
|
|
64
67
|
);
|
|
65
68
|
});
|
|
66
69
|
|
|
70
|
+
test("guided execute uses auto step bootstrap when worktree isolation is enabled", () => {
|
|
71
|
+
assert.equal(
|
|
72
|
+
resolveGuidedExecuteLaunchMode("worktree"),
|
|
73
|
+
"auto-step",
|
|
74
|
+
"guided execute must enter auto bootstrap so the milestone worktree is created before execution",
|
|
75
|
+
);
|
|
76
|
+
assert.equal(
|
|
77
|
+
resolveGuidedExecuteLaunchMode("none"),
|
|
78
|
+
"guided-dispatch",
|
|
79
|
+
"non-isolated projects can keep the foreground guided dispatch path",
|
|
80
|
+
);
|
|
81
|
+
assert.equal(
|
|
82
|
+
resolveGuidedExecuteLaunchMode("branch"),
|
|
83
|
+
"guided-dispatch",
|
|
84
|
+
"this regression fix is scoped to worktree isolation",
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
67
88
|
test("auto bootstrap validates blocked directories before touching .gsd migration state", () => {
|
|
68
89
|
const autoSrc = readGsdFile("auto.ts");
|
|
69
90
|
const autoStartSrc = readGsdFile("auto-start.ts");
|
|
@@ -544,7 +544,7 @@ test("ADR-017 (#5703): live worker lock is not cleared", async (t) => {
|
|
|
544
544
|
|
|
545
545
|
// ─── #5704: unregistered-milestone drift ────────────────────────────────────
|
|
546
546
|
|
|
547
|
-
test("ADR-017 (#5704): unregistered-milestone drift
|
|
547
|
+
test("ADR-017 (#5704): unregistered-milestone drift fails closed without importing markdown", async (t) => {
|
|
548
548
|
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-projmd-"));
|
|
549
549
|
const milestoneDir = join(base, ".gsd", "milestones", "M042");
|
|
550
550
|
mkdirSync(milestoneDir, { recursive: true });
|
|
@@ -571,20 +571,22 @@ test("ADR-017 (#5704): unregistered-milestone drift detected and DB row inserted
|
|
|
571
571
|
// Pre-condition: filesystem has the milestone, DB does NOT.
|
|
572
572
|
assert.equal(getMilestone("M042"), null, "pre: DB has no row for M042");
|
|
573
573
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
574
|
+
await assert.rejects(
|
|
575
|
+
reconcileBeforeDispatch(base, {
|
|
576
|
+
invalidateStateCache: () => {},
|
|
577
|
+
deriveState: async () => makeState(),
|
|
578
|
+
}),
|
|
579
|
+
(err: unknown) => {
|
|
580
|
+
assert.ok(err instanceof ReconciliationFailedError);
|
|
581
|
+
assert.match(String(err.message), /unregistered-milestone/);
|
|
582
|
+
assert.equal(err.failures[0]?.drift.kind, "unregistered-milestone");
|
|
583
|
+
assert.match(String(err.failures[0]?.cause), /M042/);
|
|
584
|
+
assert.match(String(err.failures[0]?.cause), /markdown projection/);
|
|
585
|
+
assert.match(String(err.failures[0]?.cause), /recovery\/migration/);
|
|
586
|
+
return true;
|
|
587
|
+
},
|
|
583
588
|
);
|
|
584
|
-
assert.
|
|
585
|
-
if (milestoneRepaired?.kind === "unregistered-milestone") {
|
|
586
|
-
assert.equal(milestoneRepaired.milestoneId, "M042");
|
|
587
|
-
}
|
|
589
|
+
assert.equal(getMilestone("M042"), null, "post: DB still has no row for M042");
|
|
588
590
|
});
|
|
589
591
|
|
|
590
592
|
test("ADR-017 (#5704): registered milestone (DB row present) → no drift", async (t) => {
|
|
@@ -627,13 +629,14 @@ test("ADR-017 (#5704): registered milestone (DB row present) → no drift", asyn
|
|
|
627
629
|
|
|
628
630
|
// ─── #5705: roadmap-divergence drift ─────────────────────────────────────────
|
|
629
631
|
|
|
630
|
-
test("ADR-017 (#5705): roadmap-divergence
|
|
632
|
+
test("ADR-017 (#5705): roadmap-divergence re-renders projection without syncing depends into DB", async (t) => {
|
|
631
633
|
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-"));
|
|
632
634
|
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
635
|
+
const roadmapPath = join(milestoneDir, "M001-ROADMAP.md");
|
|
633
636
|
mkdirSync(milestoneDir, { recursive: true });
|
|
634
637
|
// ROADMAP.md declares S02 depends on [S01]
|
|
635
638
|
writeFileSync(
|
|
636
|
-
|
|
639
|
+
roadmapPath,
|
|
637
640
|
[
|
|
638
641
|
"# M001: Test",
|
|
639
642
|
"",
|
|
@@ -665,7 +668,12 @@ test("ADR-017 (#5705): roadmap-divergence drift detected and DB depends synced",
|
|
|
665
668
|
});
|
|
666
669
|
|
|
667
670
|
assert.equal(result.ok, true);
|
|
668
|
-
assert.deepEqual(getSlice("M001", "S02")?.depends, [
|
|
671
|
+
assert.deepEqual(getSlice("M001", "S02")?.depends, [], "post: DB depends remains authoritative");
|
|
672
|
+
assert.match(
|
|
673
|
+
readFileSync(roadmapPath, "utf-8"),
|
|
674
|
+
/- \[ \] \*\*S02: Feature\*\* `risk:medium` `depends:\[\]`/,
|
|
675
|
+
"post: ROADMAP projection is regenerated from DB depends",
|
|
676
|
+
);
|
|
669
677
|
const roadmapRepaired = result.repaired.find((d) => d.kind === "roadmap-divergence");
|
|
670
678
|
assert.ok(roadmapRepaired, "repaired list should include the roadmap-divergence drift");
|
|
671
679
|
if (roadmapRepaired?.kind === "roadmap-divergence") {
|
|
@@ -673,13 +681,14 @@ test("ADR-017 (#5705): roadmap-divergence drift detected and DB depends synced",
|
|
|
673
681
|
}
|
|
674
682
|
});
|
|
675
683
|
|
|
676
|
-
test("ADR-017 (#5705): ROADMAP
|
|
684
|
+
test("ADR-017 (#5705): ROADMAP-only slice is removed from projection and not inserted into DB", async (t) => {
|
|
677
685
|
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-newslice-"));
|
|
678
686
|
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
687
|
+
const roadmapPath = join(milestoneDir, "M001-ROADMAP.md");
|
|
679
688
|
mkdirSync(milestoneDir, { recursive: true });
|
|
680
689
|
// ROADMAP.md declares S01 and S02; DB will only have S01.
|
|
681
690
|
writeFileSync(
|
|
682
|
-
|
|
691
|
+
roadmapPath,
|
|
683
692
|
[
|
|
684
693
|
"# M001: Test",
|
|
685
694
|
"",
|
|
@@ -710,10 +719,10 @@ test("ADR-017 (#5705): ROADMAP declares slice missing from DB → slice inserted
|
|
|
710
719
|
});
|
|
711
720
|
|
|
712
721
|
assert.equal(result.ok, true);
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
assert.
|
|
716
|
-
assert.
|
|
722
|
+
assert.equal(getSlice("M001", "S02"), null, "post: S02 still has no DB row");
|
|
723
|
+
const rendered = readFileSync(roadmapPath, "utf-8");
|
|
724
|
+
assert.match(rendered, /- \[ \] \*\*S01: Foundation\*\*/);
|
|
725
|
+
assert.doesNotMatch(rendered, /S02: Feature/, "post: ROADMAP-only S02 removed from projection");
|
|
717
726
|
const roadmapRepaired = result.repaired.find((d) => d.kind === "roadmap-divergence");
|
|
718
727
|
assert.ok(roadmapRepaired, "repaired list should include the roadmap-divergence drift");
|
|
719
728
|
if (roadmapRepaired?.kind === "roadmap-divergence") {
|
|
@@ -721,6 +730,93 @@ test("ADR-017 (#5705): ROADMAP declares slice missing from DB → slice inserted
|
|
|
721
730
|
}
|
|
722
731
|
});
|
|
723
732
|
|
|
733
|
+
test("ADR-017 (#5705): ROADMAP sequence drift re-renders from DB order without mutating DB", async (t) => {
|
|
734
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-sequence-"));
|
|
735
|
+
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
736
|
+
const roadmapPath = join(milestoneDir, "M001-ROADMAP.md");
|
|
737
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
738
|
+
writeFileSync(
|
|
739
|
+
roadmapPath,
|
|
740
|
+
[
|
|
741
|
+
"# M001: Test",
|
|
742
|
+
"",
|
|
743
|
+
"**Vision:** Verify sequence drift",
|
|
744
|
+
"",
|
|
745
|
+
"## Slices",
|
|
746
|
+
"",
|
|
747
|
+
"- [ ] **S02: Feature** `risk:medium` `depends:[]`",
|
|
748
|
+
"- [ ] **S01: Foundation** `risk:medium` `depends:[]`",
|
|
749
|
+
"",
|
|
750
|
+
].join("\n"),
|
|
751
|
+
);
|
|
752
|
+
t.after(() => {
|
|
753
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
754
|
+
rmSync(base, { recursive: true, force: true });
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
758
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
759
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
|
|
760
|
+
insertSlice({ id: "S02", milestoneId: "M001", title: "Feature", status: "pending", risk: "medium", depends: [], demo: "", sequence: 2 });
|
|
761
|
+
|
|
762
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
763
|
+
invalidateStateCache: () => {},
|
|
764
|
+
deriveState: async () => makeState(),
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
assert.equal(result.ok, true);
|
|
768
|
+
assert.equal(getSlice("M001", "S01")?.sequence, 1, "post: S01 DB sequence remains authoritative");
|
|
769
|
+
assert.equal(getSlice("M001", "S02")?.sequence, 2, "post: S02 DB sequence remains authoritative");
|
|
770
|
+
const rendered = readFileSync(roadmapPath, "utf-8");
|
|
771
|
+
assert.ok(
|
|
772
|
+
rendered.indexOf("S01: Foundation") < rendered.indexOf("S02: Feature"),
|
|
773
|
+
"post: ROADMAP projection follows DB sequence",
|
|
774
|
+
);
|
|
775
|
+
assert.ok(result.repaired.some((d) => d.kind === "roadmap-divergence"));
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
test("ADR-017 (#5705): ROADMAP checkbox drift re-renders from DB status without mutating DB", async (t) => {
|
|
779
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-checkbox-"));
|
|
780
|
+
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
781
|
+
const roadmapPath = join(milestoneDir, "M001-ROADMAP.md");
|
|
782
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
783
|
+
writeFileSync(
|
|
784
|
+
roadmapPath,
|
|
785
|
+
[
|
|
786
|
+
"# M001: Test",
|
|
787
|
+
"",
|
|
788
|
+
"**Vision:** Verify checkbox drift",
|
|
789
|
+
"",
|
|
790
|
+
"## Slices",
|
|
791
|
+
"",
|
|
792
|
+
"- [x] **S01: Foundation** `risk:medium` `depends:[]`",
|
|
793
|
+
"",
|
|
794
|
+
].join("\n"),
|
|
795
|
+
);
|
|
796
|
+
t.after(() => {
|
|
797
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
798
|
+
rmSync(base, { recursive: true, force: true });
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
802
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
803
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
|
|
804
|
+
|
|
805
|
+
const result = await reconcileBeforeDispatch(base, {
|
|
806
|
+
invalidateStateCache: () => {},
|
|
807
|
+
deriveState: async () => makeState(),
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
assert.equal(result.ok, true);
|
|
811
|
+
assert.equal(getSlice("M001", "S01")?.status, "pending", "post: DB status remains authoritative");
|
|
812
|
+
assert.match(
|
|
813
|
+
readFileSync(roadmapPath, "utf-8"),
|
|
814
|
+
/- \[ \] \*\*S01: Foundation\*\*/,
|
|
815
|
+
"post: ROADMAP checkbox reflects DB status",
|
|
816
|
+
);
|
|
817
|
+
assert.ok(result.repaired.some((d) => d.kind === "roadmap-divergence"));
|
|
818
|
+
});
|
|
819
|
+
|
|
724
820
|
test("ADR-017 (#5705): in-sync ROADMAP and DB → no roadmap-divergence drift", async (t) => {
|
|
725
821
|
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-clean-"));
|
|
726
822
|
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import test from 'node:test';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
|
|
6
|
-
import { isClosedStatus } from '../status-guards.ts';
|
|
6
|
+
import { isClosedStatus, isFutureMilestoneStatus } from '../status-guards.ts';
|
|
7
7
|
|
|
8
8
|
test('isClosedStatus: "complete" returns true', () => {
|
|
9
9
|
assert.equal(isClosedStatus('complete'), true);
|
|
@@ -32,3 +32,15 @@ test('isClosedStatus: "active" returns false', () => {
|
|
|
32
32
|
test('isClosedStatus: "" (empty string) returns false', () => {
|
|
33
33
|
assert.equal(isClosedStatus(''), false);
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
test('isFutureMilestoneStatus includes future milestone aliases', () => {
|
|
37
|
+
assert.equal(isFutureMilestoneStatus('pending'), true);
|
|
38
|
+
assert.equal(isFutureMilestoneStatus('queued'), true);
|
|
39
|
+
assert.equal(isFutureMilestoneStatus('planned'), true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('isFutureMilestoneStatus excludes active and closed milestones', () => {
|
|
43
|
+
assert.equal(isFutureMilestoneStatus('active'), false);
|
|
44
|
+
assert.equal(isFutureMilestoneStatus('complete'), false);
|
|
45
|
+
assert.equal(isFutureMilestoneStatus('parked'), false);
|
|
46
|
+
});
|
|
@@ -162,7 +162,7 @@ describe("validate-milestone stuck-loop guard (#4094)", () => {
|
|
|
162
162
|
assert.equal(pauseAutoMock.mock.callCount(), 0);
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
test("
|
|
165
|
+
test("retries when no VALIDATION file exists yet", async () => {
|
|
166
166
|
insertMilestone({ id: "M001" });
|
|
167
167
|
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice 1", status: "complete" });
|
|
168
168
|
|
|
@@ -173,7 +173,34 @@ describe("validate-milestone stuck-loop guard (#4094)", () => {
|
|
|
173
173
|
|
|
174
174
|
const result = await runPostUnitVerification({ s, ctx, pi } as VerificationContext, pauseAutoMock);
|
|
175
175
|
|
|
176
|
-
assert.equal(result, "
|
|
176
|
+
assert.equal(result, "retry");
|
|
177
|
+
assert.equal(pauseAutoMock.mock.callCount(), 0);
|
|
178
|
+
assert.ok(s.pendingVerificationRetry);
|
|
179
|
+
assert.equal(s.pendingVerificationRetry!.unitId, "M001");
|
|
180
|
+
assert.match(s.pendingVerificationRetry!.failureContext, /gsd_validate_milestone/);
|
|
181
|
+
assert.equal(s.pendingVerificationRetry!.attempt, 1);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("retries when VALIDATION file exists but is empty", async () => {
|
|
185
|
+
insertMilestone({ id: "M001" });
|
|
186
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice 1", status: "complete" });
|
|
187
|
+
|
|
188
|
+
const path = join(tempDir, ".gsd", "milestones", "M001", "M001-VALIDATION.md");
|
|
189
|
+
writeFileSync(path, "", "utf-8");
|
|
190
|
+
invalidateAllCaches();
|
|
191
|
+
|
|
192
|
+
const ctx = makeMockCtx();
|
|
193
|
+
const pi = makeMockPi();
|
|
194
|
+
const pauseAutoMock = mock.fn(async () => {});
|
|
195
|
+
const s = makeMockSession(tempDir, "validate-milestone", "M001");
|
|
196
|
+
|
|
197
|
+
const result = await runPostUnitVerification({ s, ctx, pi } as VerificationContext, pauseAutoMock);
|
|
198
|
+
|
|
199
|
+
assert.equal(result, "retry");
|
|
177
200
|
assert.equal(pauseAutoMock.mock.callCount(), 0);
|
|
201
|
+
assert.ok(s.pendingVerificationRetry);
|
|
202
|
+
assert.equal(s.pendingVerificationRetry!.unitId, "M001");
|
|
203
|
+
assert.match(s.pendingVerificationRetry!.failureContext, /exists but is empty/);
|
|
204
|
+
assert.equal(s.pendingVerificationRetry!.attempt, 1);
|
|
178
205
|
});
|
|
179
206
|
});
|
|
@@ -746,3 +746,21 @@ test("transport compatibility still blocks units whose MCP tools are not exposed
|
|
|
746
746
|
assert.match(error ?? "", /requires secure_env_collect/);
|
|
747
747
|
assert.match(error ?? "", /currently exposes only/);
|
|
748
748
|
});
|
|
749
|
+
|
|
750
|
+
test("transport compatibility accepts MCP-namespaced runtime tools", () => {
|
|
751
|
+
const error = getWorkflowTransportSupportError(
|
|
752
|
+
"claude-code",
|
|
753
|
+
["gsd_summary_save"],
|
|
754
|
+
{
|
|
755
|
+
projectRoot: "/tmp/project",
|
|
756
|
+
env: { GSD_WORKFLOW_MCP_COMMAND: "node" },
|
|
757
|
+
surface: "auto-mode",
|
|
758
|
+
unitType: "research-slice",
|
|
759
|
+
authMode: "externalCli",
|
|
760
|
+
baseUrl: "local://claude-code",
|
|
761
|
+
activeTools: ["mcp__gsd-workflow__gsd_summary_save"],
|
|
762
|
+
},
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
assert.equal(error, null);
|
|
766
|
+
});
|
|
@@ -18,6 +18,7 @@ export interface WorkflowCapabilityOptions {
|
|
|
18
18
|
unitType?: string;
|
|
19
19
|
authMode?: "apiKey" | "oauth" | "externalCli" | "none";
|
|
20
20
|
baseUrl?: string;
|
|
21
|
+
activeTools?: string[];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const MCP_WORKFLOW_TOOL_SURFACE = new Set([
|
|
@@ -383,6 +384,15 @@ function hasAskUserQuestionsTool(activeTools: string[]): boolean {
|
|
|
383
384
|
});
|
|
384
385
|
}
|
|
385
386
|
|
|
387
|
+
function hasRequiredTool(requiredTool: string, activeTools: string[]): boolean {
|
|
388
|
+
return activeTools.some((toolName) => {
|
|
389
|
+
if (toolName === requiredTool) return true;
|
|
390
|
+
if (!toolName.startsWith("mcp__")) return false;
|
|
391
|
+
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
392
|
+
return toolSeparator >= 0 && toolName.slice(toolSeparator + 2) === requiredTool;
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
386
396
|
function workflowMcpStructuredQuestionsOptIn(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
387
397
|
const value = env.GSD_WORKFLOW_MCP_STRUCTURED_QUESTIONS;
|
|
388
398
|
return value === "1" || value === "true";
|
|
@@ -423,8 +433,15 @@ export function getWorkflowTransportSupportError(
|
|
|
423
433
|
return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: the GSD workflow MCP server is not configured or discoverable. Detected Claude Code model but no workflow MCP. Please run /gsd mcp init . from your project root. You can also configure GSD_WORKFLOW_MCP_COMMAND, build packages/mcp-server/dist/cli.js, or install gsd-mcp-server on PATH.`;
|
|
424
434
|
}
|
|
425
435
|
|
|
426
|
-
const
|
|
436
|
+
const uniqueRequired = [...new Set(requiredTools)];
|
|
437
|
+
const missing = (options.activeTools && options.activeTools.length > 0)
|
|
438
|
+
? uniqueRequired.filter((tool) => !hasRequiredTool(tool, options.activeTools!))
|
|
439
|
+
: uniqueRequired.filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
|
|
427
440
|
if (missing.length === 0) return null;
|
|
428
441
|
|
|
442
|
+
if (options.activeTools && options.activeTools.length > 0) {
|
|
443
|
+
return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: this unit requires ${missing.join(", ")}, but the active runtime toolset currently exposes only ${options.activeTools.slice().sort().join(", ")}.`;
|
|
444
|
+
}
|
|
445
|
+
|
|
429
446
|
return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: this unit requires ${missing.join(", ")}, but the workflow MCP transport currently exposes only ${Array.from(MCP_WORKFLOW_TOOL_SURFACE).sort().join(", ")}.`;
|
|
430
447
|
}
|
|
File without changes
|
|
File without changes
|