@opengsd/gsd-pi 1.1.1-dev.9bb7453 → 1.1.1-dev.a5a2de8
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/gsd/auto-dispatch.js +11 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +4 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
- package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +16 -10
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +19 -8
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
- package/dist/resources/extensions/gsd/guided-flow.js +89 -107
- package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
- package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +3 -17
- package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
- package/dist/resources/extensions/gsd/tool-contract.js +5 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +17 -7
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -4
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -75
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- 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/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 +10 -10
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- 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/cloud-mcp-gateway/package.json +2 -2
- 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/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +3 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +6 -6
- package/packages/pi-ai/dist/models.generated.js +6 -6
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +4 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
- package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +16 -10
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +23 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
- package/src/resources/extensions/gsd/guided-flow.ts +124 -134
- package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
- package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
- package/src/resources/extensions/gsd/prompts/run-uat.md +3 -17
- package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +23 -5
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +221 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
- package/src/resources/extensions/gsd/tool-contract.ts +6 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +38 -8
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +100 -5
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -75
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
- /package/dist/web/standalone/.next/static/{jBtwT9v1u2lUA3UEOy_ZH → 9y3LeeR2uGr2yRj9RjY3D}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{jBtwT9v1u2lUA3UEOy_ZH → 9y3LeeR2uGr2yRj9RjY3D}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Resolve phase-aware tool surfaces for GSD model presentations.
|
|
3
3
|
|
|
4
|
+
import {
|
|
5
|
+
RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
6
|
+
RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
7
|
+
RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
8
|
+
} from "./unit-tool-contracts.js";
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
12
|
+
RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
13
|
+
RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
14
|
+
} from "./unit-tool-contracts.js";
|
|
15
|
+
|
|
4
16
|
export type ToolPresentationSurface = "provider-tools" | "claude-code-sdk" | "mcp" | "hybrid";
|
|
5
17
|
|
|
6
18
|
export interface ToolPresentationModel {
|
|
@@ -20,14 +32,6 @@ export interface ToolPresentationPlan {
|
|
|
20
32
|
diagnostics: string[];
|
|
21
33
|
}
|
|
22
34
|
|
|
23
|
-
export const RUN_UAT_WORKFLOW_TOOL_NAMES = [
|
|
24
|
-
"gsd_uat_exec",
|
|
25
|
-
"gsd_uat_result_save",
|
|
26
|
-
"gsd_resume",
|
|
27
|
-
"gsd_milestone_status",
|
|
28
|
-
"gsd_journal_query",
|
|
29
|
-
] as const;
|
|
30
|
-
|
|
31
35
|
export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
|
|
32
36
|
"edit",
|
|
33
37
|
"write",
|
|
@@ -105,10 +109,36 @@ function addBlockedTool(
|
|
|
105
109
|
export function buildRunUatCanonicalToolNames(options: { includeBrowserTools?: readonly string[] } = {}): string[] {
|
|
106
110
|
return dedupe([
|
|
107
111
|
...RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
112
|
+
...RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
108
113
|
...(options.includeBrowserTools ?? []),
|
|
109
114
|
]);
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
export function buildRunUatResultPresentation(options: {
|
|
118
|
+
surface?: ToolPresentationSurface;
|
|
119
|
+
includeBrowserTools?: readonly string[];
|
|
120
|
+
presentedTools?: readonly string[];
|
|
121
|
+
} = {}): {
|
|
122
|
+
surface: ToolPresentationSurface;
|
|
123
|
+
presentedTools: string[];
|
|
124
|
+
blockedTools: Array<{ name: string; reason: string }>;
|
|
125
|
+
toolPresentationPlanId: string;
|
|
126
|
+
} {
|
|
127
|
+
const presentedTools = options.presentedTools
|
|
128
|
+
? dedupe(options.presentedTools)
|
|
129
|
+
: buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools });
|
|
130
|
+
const blockedTools = RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
131
|
+
.filter((toolName) => !toolName.includes("*"))
|
|
132
|
+
.map((name) => ({ name, reason: "forbidden during run-uat" }));
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
surface: options.surface ?? "mcp",
|
|
136
|
+
presentedTools,
|
|
137
|
+
blockedTools,
|
|
138
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
112
142
|
export function resolveToolPresentationPlan(options: {
|
|
113
143
|
phase: string;
|
|
114
144
|
surface: ToolPresentationSurface;
|
|
@@ -48,9 +48,11 @@ import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
|
48
48
|
import { parseProject } from "../schemas/parsers.js";
|
|
49
49
|
import { getAutoRuntimeSnapshot } from "../auto-runtime-state.js";
|
|
50
50
|
import {
|
|
51
|
+
buildRunUatResultPresentation,
|
|
51
52
|
canonicalWorkflowToolName,
|
|
52
53
|
parseMcpToolName,
|
|
53
54
|
RUN_UAT_FORBIDDEN_TOOL_NAMES,
|
|
55
|
+
RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
54
56
|
RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
55
57
|
} from "../tool-presentation-plan.js";
|
|
56
58
|
|
|
@@ -90,7 +92,7 @@ function blockIfWrongAutoUnit(requiredUnitType: string, operation: string): Tool
|
|
|
90
92
|
if (!snapshot.active || !snapshot.currentUnit) return null;
|
|
91
93
|
if (snapshot.currentUnit.type === requiredUnitType) return null;
|
|
92
94
|
|
|
93
|
-
const error = `HARD BLOCK: ${operation} may only run from ${requiredUnitType}; active unit is ${snapshot.currentUnit.type}. The orchestrator owns phase transitions.`;
|
|
95
|
+
const error = `HARD BLOCK: Tool Contract failure: ${operation} may only run from ${requiredUnitType}; active unit is ${snapshot.currentUnit.type}. Fix unit-tool-contracts.ts or the active Unit prompt. The orchestrator owns phase transitions.`;
|
|
94
96
|
return {
|
|
95
97
|
content: [{ type: "text", text: error }],
|
|
96
98
|
details: { operation, error },
|
|
@@ -178,7 +180,11 @@ export async function executeSummarySave(
|
|
|
178
180
|
if (rootArtifactGuard.block) {
|
|
179
181
|
return {
|
|
180
182
|
content: [{ type: "text", text: `Error saving artifact: ${rootArtifactGuard.reason ?? "root artifact write blocked"}` }],
|
|
181
|
-
details: {
|
|
183
|
+
details: {
|
|
184
|
+
operation: "save_summary",
|
|
185
|
+
error: "root_artifact_write_blocked",
|
|
186
|
+
displayReason: "Approval confirmation required before saving final project setup artifacts.",
|
|
187
|
+
},
|
|
182
188
|
isError: true,
|
|
183
189
|
};
|
|
184
190
|
}
|
|
@@ -191,9 +197,13 @@ export async function executeSummarySave(
|
|
|
191
197
|
if (contextGuard.block) {
|
|
192
198
|
return {
|
|
193
199
|
content: [{ type: "text", text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
|
|
194
|
-
details: {
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
details: {
|
|
201
|
+
operation: "save_summary",
|
|
202
|
+
error: "context_write_blocked",
|
|
203
|
+
displayReason: "Depth check required before writing milestone context.",
|
|
204
|
+
},
|
|
205
|
+
isError: true,
|
|
206
|
+
};
|
|
197
207
|
}
|
|
198
208
|
try {
|
|
199
209
|
let relativePath: string;
|
|
@@ -441,6 +451,9 @@ export interface UatEvidenceRef {
|
|
|
441
451
|
kind: "gsd_uat_exec" | "gsd_exec" | "screenshot" | "log" | "url" | "browser";
|
|
442
452
|
ref: string;
|
|
443
453
|
note?: string;
|
|
454
|
+
unitType?: string;
|
|
455
|
+
tool?: string;
|
|
456
|
+
executionId?: string;
|
|
444
457
|
}
|
|
445
458
|
|
|
446
459
|
export interface UatCheckResultInput {
|
|
@@ -1008,10 +1021,68 @@ function isNonEmptyString(value: unknown): value is string {
|
|
|
1008
1021
|
return typeof value === "string" && value.trim().length > 0;
|
|
1009
1022
|
}
|
|
1010
1023
|
|
|
1024
|
+
function mergeBlockedTools(
|
|
1025
|
+
current: UatPresentationInput["blockedTools"] | undefined,
|
|
1026
|
+
canonical: UatPresentationInput["blockedTools"],
|
|
1027
|
+
): UatPresentationInput["blockedTools"] {
|
|
1028
|
+
const merged = new Map<string, { name: string; reason: string }>();
|
|
1029
|
+
for (const entry of [...(current ?? []), ...canonical]) {
|
|
1030
|
+
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name), entry);
|
|
1031
|
+
}
|
|
1032
|
+
return [...merged.values()];
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function mergePresentedTools(current: readonly string[] | undefined, canonical: readonly string[]): string[] {
|
|
1036
|
+
return [...new Set([...(current ?? []), ...canonical])];
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
function normalizeUatVerdict(params: UatResultSaveParams): UatResultSaveParams {
|
|
1040
|
+
const raw = params as Partial<UatResultSaveParams> & Record<string, unknown>;
|
|
1041
|
+
if (typeof raw.verdict === "string") {
|
|
1042
|
+
return { ...params, verdict: raw.verdict.toUpperCase() as UatVerdict };
|
|
1043
|
+
}
|
|
1044
|
+
return params;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function supplyDefaultPresentation(params: UatResultSaveParams): UatResultSaveParams {
|
|
1048
|
+
const raw = params as Partial<UatResultSaveParams> & Record<string, unknown>;
|
|
1049
|
+
if (!raw.presentation) {
|
|
1050
|
+
return { ...params, presentation: buildRunUatResultPresentation() };
|
|
1051
|
+
}
|
|
1052
|
+
return params;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
function mergeCanonicalPresentation(params: UatResultSaveParams): UatResultSaveParams {
|
|
1056
|
+
const canonicalPresentation = buildRunUatResultPresentation();
|
|
1057
|
+
const providedPresentation = params.presentation as Partial<UatPresentationInput>;
|
|
1058
|
+
return {
|
|
1059
|
+
...params,
|
|
1060
|
+
presentation: {
|
|
1061
|
+
...providedPresentation,
|
|
1062
|
+
surface: providedPresentation.surface ?? canonicalPresentation.surface,
|
|
1063
|
+
presentedTools: mergePresentedTools(providedPresentation.presentedTools, canonicalPresentation.presentedTools),
|
|
1064
|
+
blockedTools: mergeBlockedTools(providedPresentation.blockedTools, canonicalPresentation.blockedTools),
|
|
1065
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
1066
|
+
} as UatPresentationInput,
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const VALID_UAT_TYPES: readonly UatType[] = [
|
|
1071
|
+
"artifact-driven",
|
|
1072
|
+
"browser-executable",
|
|
1073
|
+
"runtime-executable",
|
|
1074
|
+
"live-runtime",
|
|
1075
|
+
"mixed",
|
|
1076
|
+
"human-experience",
|
|
1077
|
+
];
|
|
1078
|
+
|
|
1011
1079
|
function ensureUatRequiredFields(params: UatResultSaveParams): string | null {
|
|
1012
1080
|
if (!isNonEmptyString(params.milestoneId)) return "milestoneId is required";
|
|
1013
1081
|
if (!isNonEmptyString(params.sliceId)) return "sliceId is required";
|
|
1014
1082
|
if (!isNonEmptyString(params.uatType)) return "uatType is required";
|
|
1083
|
+
if (!(VALID_UAT_TYPES as readonly string[]).includes(params.uatType)) {
|
|
1084
|
+
return `uatType must be one of: ${VALID_UAT_TYPES.join(", ")}`;
|
|
1085
|
+
}
|
|
1015
1086
|
if (!["PASS", "FAIL", "PARTIAL"].includes(params.verdict)) return "verdict must be PASS, FAIL, or PARTIAL";
|
|
1016
1087
|
if (!Array.isArray(params.checks) || params.checks.length === 0) return "checks must contain at least one UAT check";
|
|
1017
1088
|
if (!params.presentation || !Array.isArray(params.presentation.presentedTools)) return "presentation.presentedTools is required";
|
|
@@ -1147,6 +1218,15 @@ function validateUatChecks(basePath: string, params: UatResultSaveParams): strin
|
|
|
1147
1218
|
return null;
|
|
1148
1219
|
}
|
|
1149
1220
|
|
|
1221
|
+
function validateFreshUatOwnedEvidence(params: UatResultSaveParams): string | null {
|
|
1222
|
+
const hasFreshUatEvidence = params.checks.some((check) =>
|
|
1223
|
+
(check.evidence ?? []).some((evidence) => evidence.kind === "gsd_uat_exec")
|
|
1224
|
+
);
|
|
1225
|
+
return hasFreshUatEvidence
|
|
1226
|
+
? null
|
|
1227
|
+
: "UAT Assessment requires at least one fresh gsd_uat_exec evidence reference from run-uat";
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1150
1230
|
function validateUatMode(params: UatResultSaveParams): string | null {
|
|
1151
1231
|
const modes = new Set(params.checks.map((check) => check.mode));
|
|
1152
1232
|
const hasHuman = params.checks.some((check) => check.result === "NEEDS-HUMAN");
|
|
@@ -1306,15 +1386,30 @@ export async function executeUatResultSave(
|
|
|
1306
1386
|
params: UatResultSaveParams,
|
|
1307
1387
|
basePath: string = process.cwd(),
|
|
1308
1388
|
): Promise<ToolExecutionResult> {
|
|
1389
|
+
const unitGuard = blockIfWrongAutoUnit("run-uat", "save_uat_result");
|
|
1390
|
+
if (unitGuard) return unitGuard;
|
|
1391
|
+
|
|
1392
|
+
// Phase 1: normalize verdict and supply the canonical presentation when none was provided.
|
|
1393
|
+
params = normalizeUatVerdict(params);
|
|
1394
|
+
params = supplyDefaultPresentation(params);
|
|
1395
|
+
|
|
1309
1396
|
const dbAvailable = await ensureDbOpen(basePath);
|
|
1310
1397
|
if (!dbAvailable) return errorResult("save_uat_result", "GSD database is not available.", "db_unavailable");
|
|
1311
1398
|
|
|
1399
|
+
// Phase 2: validate the submitted presentation before the canonical merge so that
|
|
1400
|
+
// presentations missing required workflow tools are rejected rather than silently patched.
|
|
1312
1401
|
const requiredError = ensureUatRequiredFields(params);
|
|
1313
1402
|
if (requiredError) return errorResult("save_uat_result", requiredError, "invalid_params");
|
|
1314
1403
|
const presentationError = validateCanonicalPresentation(params);
|
|
1315
1404
|
if (presentationError) return errorResult("save_uat_result", presentationError, "alias_tool_name");
|
|
1405
|
+
|
|
1406
|
+
// Phase 3: merge in the canonical plan ID and read-only audit tools so the persisted
|
|
1407
|
+
// artifact always carries the full audit surface even when the provider omitted them.
|
|
1408
|
+
params = mergeCanonicalPresentation(params);
|
|
1316
1409
|
const checkError = validateUatChecks(basePath, params);
|
|
1317
1410
|
if (checkError) return errorResult("save_uat_result", checkError, "invalid_evidence");
|
|
1411
|
+
const freshEvidenceError = validateFreshUatOwnedEvidence(params);
|
|
1412
|
+
if (freshEvidenceError) return errorResult("save_uat_result", freshEvidenceError, "missing_fresh_uat_evidence");
|
|
1318
1413
|
const modeError = validateUatMode(params);
|
|
1319
1414
|
if (modeError) return errorResult("save_uat_result", modeError, "uat_mode_mismatch");
|
|
1320
1415
|
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Central Unit-to-tool contracts for phase-aware GSD tool surfaces.
|
|
3
|
+
|
|
4
|
+
export interface UnitToolSurfaceContract {
|
|
5
|
+
allowedGsdTools: readonly string[];
|
|
6
|
+
requiredWorkflowTools: readonly string[];
|
|
7
|
+
forbiddenGsdTools?: Readonly<Record<string, string>>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const RUN_UAT_WORKFLOW_TOOL_NAMES = [
|
|
11
|
+
"gsd_uat_exec",
|
|
12
|
+
"gsd_uat_result_save",
|
|
13
|
+
"gsd_resume",
|
|
14
|
+
"gsd_milestone_status",
|
|
15
|
+
"gsd_journal_query",
|
|
16
|
+
] as const;
|
|
17
|
+
|
|
18
|
+
export const RUN_UAT_READ_ONLY_TOOL_NAMES = [
|
|
19
|
+
"find",
|
|
20
|
+
"glob",
|
|
21
|
+
"grep",
|
|
22
|
+
"ls",
|
|
23
|
+
"read",
|
|
24
|
+
] as const;
|
|
25
|
+
|
|
26
|
+
export const RUN_UAT_BROWSER_TOOL_NAMES = [
|
|
27
|
+
"browser_navigate",
|
|
28
|
+
"browser_click",
|
|
29
|
+
"browser_type",
|
|
30
|
+
"browser_fill_form",
|
|
31
|
+
"browser_click_ref",
|
|
32
|
+
"browser_fill_ref",
|
|
33
|
+
"browser_wait_for",
|
|
34
|
+
"browser_assert",
|
|
35
|
+
"browser_verify",
|
|
36
|
+
"browser_screenshot",
|
|
37
|
+
"browser_snapshot_refs",
|
|
38
|
+
"browser_find",
|
|
39
|
+
"browser_get_console_logs",
|
|
40
|
+
"browser_get_network_logs",
|
|
41
|
+
"browser_evaluate",
|
|
42
|
+
"browser_reload",
|
|
43
|
+
"browser_batch",
|
|
44
|
+
"browser_act",
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
47
|
+
export const RUN_UAT_TOOL_PRESENTATION_PLAN_ID = "run-uat/default-v1";
|
|
48
|
+
|
|
49
|
+
export const UNIT_TOOL_CONTRACTS: Record<string, UnitToolSurfaceContract> = {
|
|
50
|
+
"research-milestone": {
|
|
51
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
52
|
+
requiredWorkflowTools: ["gsd_summary_save"],
|
|
53
|
+
},
|
|
54
|
+
"plan-milestone": {
|
|
55
|
+
allowedGsdTools: ["gsd_plan_milestone", "gsd_decision_save", "gsd_requirement_update"],
|
|
56
|
+
requiredWorkflowTools: ["gsd_plan_milestone"],
|
|
57
|
+
},
|
|
58
|
+
"discuss-milestone": {
|
|
59
|
+
allowedGsdTools: [
|
|
60
|
+
"gsd_summary_save",
|
|
61
|
+
"gsd_decision_save",
|
|
62
|
+
"gsd_requirement_save",
|
|
63
|
+
"gsd_requirement_update",
|
|
64
|
+
"gsd_plan_milestone",
|
|
65
|
+
"gsd_milestone_generate_id",
|
|
66
|
+
],
|
|
67
|
+
requiredWorkflowTools: [
|
|
68
|
+
"gsd_summary_save",
|
|
69
|
+
"gsd_requirement_save",
|
|
70
|
+
"gsd_requirement_update",
|
|
71
|
+
"gsd_plan_milestone",
|
|
72
|
+
"gsd_milestone_generate_id",
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
"discuss-slice": {
|
|
76
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
77
|
+
requiredWorkflowTools: ["gsd_summary_save"],
|
|
78
|
+
},
|
|
79
|
+
"validate-milestone": {
|
|
80
|
+
allowedGsdTools: ["gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
|
|
81
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"],
|
|
82
|
+
},
|
|
83
|
+
"complete-milestone": {
|
|
84
|
+
allowedGsdTools: ["gsd_complete_milestone", "subagent"],
|
|
85
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_complete_milestone"],
|
|
86
|
+
},
|
|
87
|
+
"research-slice": {
|
|
88
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
89
|
+
requiredWorkflowTools: ["gsd_summary_save"],
|
|
90
|
+
},
|
|
91
|
+
"plan-slice": {
|
|
92
|
+
allowedGsdTools: ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
93
|
+
requiredWorkflowTools: ["gsd_plan_slice"],
|
|
94
|
+
},
|
|
95
|
+
"refine-slice": {
|
|
96
|
+
allowedGsdTools: ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
97
|
+
requiredWorkflowTools: [],
|
|
98
|
+
},
|
|
99
|
+
"replan-slice": {
|
|
100
|
+
allowedGsdTools: ["gsd_replan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
101
|
+
requiredWorkflowTools: ["gsd_replan_slice"],
|
|
102
|
+
},
|
|
103
|
+
"complete-slice": {
|
|
104
|
+
allowedGsdTools: [
|
|
105
|
+
"gsd_slice_complete",
|
|
106
|
+
"gsd_task_reopen",
|
|
107
|
+
"gsd_replan_slice",
|
|
108
|
+
"gsd_decision_save",
|
|
109
|
+
"gsd_requirement_update",
|
|
110
|
+
"subagent",
|
|
111
|
+
],
|
|
112
|
+
requiredWorkflowTools: ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"],
|
|
113
|
+
forbiddenGsdTools: {
|
|
114
|
+
gsd_uat_result_save: "Run UAT owns persisted UAT Assessment.",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
"reassess-roadmap": {
|
|
118
|
+
allowedGsdTools: ["gsd_reassess_roadmap"],
|
|
119
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_reassess_roadmap"],
|
|
120
|
+
},
|
|
121
|
+
"execute-task": {
|
|
122
|
+
allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
|
|
123
|
+
requiredWorkflowTools: ["gsd_task_complete"],
|
|
124
|
+
},
|
|
125
|
+
"execute-task-simple": {
|
|
126
|
+
allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
|
|
127
|
+
requiredWorkflowTools: ["gsd_task_complete"],
|
|
128
|
+
},
|
|
129
|
+
"reactive-execute": {
|
|
130
|
+
allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
|
|
131
|
+
requiredWorkflowTools: ["gsd_task_complete"],
|
|
132
|
+
},
|
|
133
|
+
"run-uat": {
|
|
134
|
+
allowedGsdTools: [...RUN_UAT_WORKFLOW_TOOL_NAMES, "subagent"],
|
|
135
|
+
requiredWorkflowTools: [...RUN_UAT_WORKFLOW_TOOL_NAMES],
|
|
136
|
+
forbiddenGsdTools: {
|
|
137
|
+
gsd_exec: "Use gsd_uat_exec so acceptance evidence is typed as UAT-owned.",
|
|
138
|
+
gsd_save_gate_result: "gsd_uat_result_save owns the aggregate UAT gate.",
|
|
139
|
+
gsd_summary_save: "gsd_uat_result_save owns persisted UAT Assessment writes.",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
"gate-evaluate": {
|
|
143
|
+
allowedGsdTools: ["gsd_save_gate_result"],
|
|
144
|
+
requiredWorkflowTools: ["gsd_save_gate_result"],
|
|
145
|
+
},
|
|
146
|
+
"rewrite-docs": {
|
|
147
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
148
|
+
requiredWorkflowTools: [],
|
|
149
|
+
},
|
|
150
|
+
"workflow-preferences": {
|
|
151
|
+
allowedGsdTools: ["gsd_summary_save"],
|
|
152
|
+
requiredWorkflowTools: [],
|
|
153
|
+
},
|
|
154
|
+
"discuss-project": {
|
|
155
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
|
|
156
|
+
requiredWorkflowTools: ["ask_user_questions", "gsd_summary_save"],
|
|
157
|
+
},
|
|
158
|
+
"discuss-requirements": {
|
|
159
|
+
allowedGsdTools: ["gsd_requirement_save", "gsd_summary_save"],
|
|
160
|
+
requiredWorkflowTools: ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"],
|
|
161
|
+
},
|
|
162
|
+
"research-decision": {
|
|
163
|
+
allowedGsdTools: ["gsd_summary_save"],
|
|
164
|
+
requiredWorkflowTools: ["ask_user_questions"],
|
|
165
|
+
},
|
|
166
|
+
"research-project": {
|
|
167
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
168
|
+
requiredWorkflowTools: [],
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export const AUTO_UNIT_SCOPED_TOOLS: Record<string, readonly string[]> = Object.fromEntries(
|
|
173
|
+
Object.entries(UNIT_TOOL_CONTRACTS).map(([unitType, contract]) => [unitType, contract.allowedGsdTools]),
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
export function getUnitToolSurfaceContract(unitType: string): UnitToolSurfaceContract | undefined {
|
|
177
|
+
return UNIT_TOOL_CONTRACTS[unitType];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function getRequiredWorkflowToolsForUnit(unitType: string): string[] {
|
|
181
|
+
return [...(UNIT_TOOL_CONTRACTS[unitType]?.requiredWorkflowTools ?? [])];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function getForbiddenGsdToolReason(unitType: string, toolName: string): string | undefined {
|
|
185
|
+
return UNIT_TOOL_CONTRACTS[unitType]?.forbiddenGsdTools?.[toolName];
|
|
186
|
+
}
|
|
@@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
|
|
|
2
2
|
import { existsSync, realpathSync } from "node:fs";
|
|
3
3
|
import { dirname, resolve, sep } from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
-
import {
|
|
5
|
+
import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
|
|
6
6
|
|
|
7
7
|
type WorkflowExecutorsModule = typeof import("./tools/workflow-tool-executors.js");
|
|
8
8
|
|
|
@@ -414,83 +414,11 @@ export function buildWorkflowMcpServers(
|
|
|
414
414
|
}
|
|
415
415
|
|
|
416
416
|
export function getRequiredWorkflowToolsForGuidedUnit(unitType: string): string[] {
|
|
417
|
-
|
|
418
|
-
case "discuss-project":
|
|
419
|
-
return ["ask_user_questions", "gsd_summary_save"];
|
|
420
|
-
case "discuss-requirements":
|
|
421
|
-
return ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"];
|
|
422
|
-
case "research-decision":
|
|
423
|
-
return ["ask_user_questions"];
|
|
424
|
-
case "discuss-milestone":
|
|
425
|
-
return [
|
|
426
|
-
"gsd_summary_save",
|
|
427
|
-
"gsd_requirement_save",
|
|
428
|
-
"gsd_requirement_update",
|
|
429
|
-
"gsd_plan_milestone",
|
|
430
|
-
"gsd_milestone_generate_id",
|
|
431
|
-
];
|
|
432
|
-
case "discuss-slice":
|
|
433
|
-
return ["gsd_summary_save"];
|
|
434
|
-
case "research-milestone":
|
|
435
|
-
case "research-slice":
|
|
436
|
-
return ["gsd_summary_save"];
|
|
437
|
-
case "plan-milestone":
|
|
438
|
-
return ["gsd_plan_milestone"];
|
|
439
|
-
case "plan-slice":
|
|
440
|
-
return ["gsd_plan_slice"];
|
|
441
|
-
case "execute-task":
|
|
442
|
-
return ["gsd_task_complete"];
|
|
443
|
-
case "complete-slice":
|
|
444
|
-
return ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"];
|
|
445
|
-
default:
|
|
446
|
-
return [];
|
|
447
|
-
}
|
|
417
|
+
return getRequiredWorkflowToolsForUnit(unitType);
|
|
448
418
|
}
|
|
449
419
|
|
|
450
420
|
export function getRequiredWorkflowToolsForAutoUnit(unitType: string): string[] {
|
|
451
|
-
|
|
452
|
-
case "discuss-project":
|
|
453
|
-
return ["ask_user_questions", "gsd_summary_save"];
|
|
454
|
-
case "discuss-requirements":
|
|
455
|
-
return ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"];
|
|
456
|
-
case "research-decision":
|
|
457
|
-
return ["ask_user_questions"];
|
|
458
|
-
case "discuss-milestone":
|
|
459
|
-
return [
|
|
460
|
-
"gsd_summary_save",
|
|
461
|
-
"gsd_requirement_save",
|
|
462
|
-
"gsd_requirement_update",
|
|
463
|
-
"gsd_plan_milestone",
|
|
464
|
-
"gsd_milestone_generate_id",
|
|
465
|
-
];
|
|
466
|
-
case "research-milestone":
|
|
467
|
-
case "research-slice":
|
|
468
|
-
return ["gsd_summary_save"];
|
|
469
|
-
case "run-uat":
|
|
470
|
-
return [...RUN_UAT_WORKFLOW_TOOL_NAMES];
|
|
471
|
-
case "plan-milestone":
|
|
472
|
-
return ["gsd_plan_milestone"];
|
|
473
|
-
case "plan-slice":
|
|
474
|
-
return ["gsd_plan_slice"];
|
|
475
|
-
case "execute-task":
|
|
476
|
-
case "execute-task-simple":
|
|
477
|
-
case "reactive-execute":
|
|
478
|
-
return ["gsd_task_complete"];
|
|
479
|
-
case "complete-slice":
|
|
480
|
-
return ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"];
|
|
481
|
-
case "replan-slice":
|
|
482
|
-
return ["gsd_replan_slice"];
|
|
483
|
-
case "reassess-roadmap":
|
|
484
|
-
return ["gsd_milestone_status", "gsd_reassess_roadmap"];
|
|
485
|
-
case "gate-evaluate":
|
|
486
|
-
return ["gsd_save_gate_result"];
|
|
487
|
-
case "validate-milestone":
|
|
488
|
-
return ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"];
|
|
489
|
-
case "complete-milestone":
|
|
490
|
-
return ["gsd_milestone_status", "gsd_complete_milestone"];
|
|
491
|
-
default:
|
|
492
|
-
return [];
|
|
493
|
-
}
|
|
421
|
+
return getRequiredWorkflowToolsForUnit(unitType);
|
|
494
422
|
}
|
|
495
423
|
|
|
496
424
|
export function usesWorkflowMcpTransport(
|