supipowers 2.1.0 → 2.2.1
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 +71 -12
- package/package.json +4 -8
- package/skills/ui-design/SKILL.md +2 -2
- package/src/ai/final-message.ts +15 -1
- package/src/ai/schema-text.ts +60 -40
- package/src/ai/schema-validation.ts +88 -0
- package/src/ai/structured-output.ts +19 -19
- package/src/bootstrap.ts +3 -0
- package/src/commands/fix-pr.ts +166 -26
- package/src/commands/optimize-context.ts +153 -16
- package/src/commands/runbook.ts +511 -0
- package/src/config/schema.ts +102 -139
- package/src/context/rule-renderer.ts +274 -2
- package/src/context/runbook-extension-template.ts +193 -0
- package/src/context/startup-check.ts +197 -2
- package/src/context/startup-optimizer.ts +133 -10
- package/src/docs/contracts.ts +13 -23
- package/src/fix-pr/assessment.ts +63 -24
- package/src/fix-pr/contracts.ts +15 -23
- package/src/fix-pr/fetch-comments.ts +119 -0
- package/src/fix-pr/prompt-builder.ts +19 -8
- package/src/git/commit-contract.ts +13 -19
- package/src/git/commit.ts +168 -6
- package/src/harness/command.ts +98 -6
- package/src/harness/git-verification.ts +515 -0
- package/src/harness/git-verify-qa.ts +406 -0
- package/src/harness/pipeline.ts +17 -8
- package/src/harness/stages/implement-apply.ts +61 -4
- package/src/harness/stages/validate.ts +108 -0
- package/src/lsp/capabilities.ts +9 -12
- package/src/lsp/contracts.ts +15 -23
- package/src/planning/planning-ask-tool.ts +13 -2
- package/src/planning/spec.ts +21 -27
- package/src/planning/system-prompt.ts +1 -1
- package/src/planning/validate.ts +4 -7
- package/src/platform/progress.ts +11 -0
- package/src/quality/contracts.ts +15 -23
- package/src/quality/schemas.ts +40 -67
- package/src/release/contracts.ts +19 -28
- package/src/review/types.ts +142 -186
- package/src/types.ts +45 -2
- package/src/ui-design/session.ts +13 -2
- package/src/ui-design/system-prompt.ts +2 -2
- package/src/ultraplan/contracts.ts +458 -524
package/src/review/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { ZodType } from "zod/v4";
|
|
3
3
|
import type {
|
|
4
4
|
ConfiguredReviewAgent,
|
|
5
5
|
ReviewAgentConfig,
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
ReviewSessionArtifacts,
|
|
19
19
|
ThinkingLevel,
|
|
20
20
|
} from "../types.js";
|
|
21
|
+
import { checkSchema } from "../ai/schema-validation.js";
|
|
21
22
|
export type {
|
|
22
23
|
ConfiguredReviewAgent,
|
|
23
24
|
ReviewAgentConfig,
|
|
@@ -45,226 +46,181 @@ export const REVIEW_SESSION_STATUSES = ["running", "completed", "blocked", "canc
|
|
|
45
46
|
export const REVIEW_POST_CONSOLIDATION_ACTIONS = ["fix-now", "document-only", "discuss-before-fixing"] as const;
|
|
46
47
|
export const REVIEW_FIX_STATUSES = ["applied", "skipped", "failed"] as const;
|
|
47
48
|
|
|
48
|
-
export const ReviewScopeFileSchema =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
},
|
|
143
|
-
{ additionalProperties: false },
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
export const ReviewAgentFrontmatterSchema = Type.Object(
|
|
147
|
-
{
|
|
148
|
-
name: Type.String({ minLength: 1 }),
|
|
149
|
-
description: Type.String({ minLength: 1 }),
|
|
150
|
-
focus: Type.Optional(Type.String({ minLength: 1 })),
|
|
151
|
-
},
|
|
152
|
-
{ additionalProperties: false },
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
export const ReviewIterationSummarySchema = Type.Object(
|
|
156
|
-
{
|
|
157
|
-
iteration: Type.Number({ minimum: 1 }),
|
|
158
|
-
findings: Type.Number({ minimum: 0 }),
|
|
159
|
-
status: Type.Union(REVIEW_OUTPUT_STATUSES.map((value) => Type.Literal(value))),
|
|
160
|
-
file: Type.String({ minLength: 1 }),
|
|
161
|
-
createdAt: Type.String({ minLength: 1 }),
|
|
162
|
-
},
|
|
163
|
-
{ additionalProperties: false },
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
export const ReviewFixRecordSchema = Type.Object(
|
|
167
|
-
{
|
|
168
|
-
findingIds: Type.Array(Type.String({ minLength: 1 })),
|
|
169
|
-
file: Type.Union([Type.String({ minLength: 1 }), Type.Null()]),
|
|
170
|
-
status: Type.Union(REVIEW_FIX_STATUSES.map((value) => Type.Literal(value))),
|
|
171
|
-
summary: Type.String({ minLength: 1 }),
|
|
172
|
-
},
|
|
173
|
-
{ additionalProperties: false },
|
|
174
|
-
);
|
|
49
|
+
export const ReviewScopeFileSchema = z.object({
|
|
50
|
+
path: z.string().min(1),
|
|
51
|
+
additions: z.number().min(0),
|
|
52
|
+
deletions: z.number().min(0),
|
|
53
|
+
diff: z.string(),
|
|
54
|
+
}).strict();
|
|
55
|
+
|
|
56
|
+
export const ReviewScopeStatsSchema = z.object({
|
|
57
|
+
filesChanged: z.number().min(0),
|
|
58
|
+
excludedFiles: z.number().min(0),
|
|
59
|
+
additions: z.number().min(0),
|
|
60
|
+
deletions: z.number().min(0),
|
|
61
|
+
}).strict();
|
|
62
|
+
|
|
63
|
+
export const ReviewScopeSchema = z.object({
|
|
64
|
+
mode: z.enum(REVIEW_SCOPE_MODES),
|
|
65
|
+
description: z.string().min(1),
|
|
66
|
+
diff: z.string(),
|
|
67
|
+
files: z.array(ReviewScopeFileSchema),
|
|
68
|
+
stats: ReviewScopeStatsSchema,
|
|
69
|
+
baseBranch: z.string().min(1).optional(),
|
|
70
|
+
commit: z.string().min(1).optional(),
|
|
71
|
+
customInstructions: z.string().min(1).optional(),
|
|
72
|
+
}).strict();
|
|
73
|
+
|
|
74
|
+
export const ReviewFindingValidationSchema = z.object({
|
|
75
|
+
verdict: z.enum(REVIEW_VALIDATION_VERDICTS),
|
|
76
|
+
reasoning: z.string().min(1),
|
|
77
|
+
validatedBy: z.string().min(1),
|
|
78
|
+
validatedAt: z.string().min(1),
|
|
79
|
+
}).strict();
|
|
80
|
+
|
|
81
|
+
export const ReviewFindingSchema = z.object({
|
|
82
|
+
id: z.string().min(1),
|
|
83
|
+
title: z.string().min(1),
|
|
84
|
+
severity: z.enum(REVIEW_FINDING_SEVERITIES),
|
|
85
|
+
priority: z.enum(REVIEW_FINDING_PRIORITIES),
|
|
86
|
+
confidence: z.number().min(0).max(1),
|
|
87
|
+
file: z.string().min(1).nullable(),
|
|
88
|
+
lineStart: z.number().min(1).nullable(),
|
|
89
|
+
lineEnd: z.number().min(1).nullable(),
|
|
90
|
+
body: z.string().min(1),
|
|
91
|
+
suggestion: z.string().min(1).nullable(),
|
|
92
|
+
agent: z.string().min(1).optional(),
|
|
93
|
+
validation: ReviewFindingValidationSchema.optional(),
|
|
94
|
+
}).strict();
|
|
95
|
+
|
|
96
|
+
export const ReviewOutputSchema = z.object({
|
|
97
|
+
findings: z.array(ReviewFindingSchema),
|
|
98
|
+
summary: z.string().min(1),
|
|
99
|
+
status: z.enum(REVIEW_OUTPUT_STATUSES),
|
|
100
|
+
}).strict();
|
|
101
|
+
|
|
102
|
+
export const ReviewAgentConfigSchema = z.object({
|
|
103
|
+
name: z.string().min(1),
|
|
104
|
+
enabled: z.boolean(),
|
|
105
|
+
data: z.string().min(1),
|
|
106
|
+
model: z.string().min(1).nullable(),
|
|
107
|
+
thinkingLevel: z.union([
|
|
108
|
+
z.literal("off"),
|
|
109
|
+
z.literal("minimal"),
|
|
110
|
+
z.literal("low"),
|
|
111
|
+
z.literal("medium"),
|
|
112
|
+
z.literal("high"),
|
|
113
|
+
z.literal("xhigh"),
|
|
114
|
+
z.null(),
|
|
115
|
+
]).optional(),
|
|
116
|
+
peerCoordination: z.boolean().optional(),
|
|
117
|
+
}).strict();
|
|
118
|
+
|
|
119
|
+
export const ReviewAgentsConfigSchema = z.object({
|
|
120
|
+
agents: z.array(ReviewAgentConfigSchema),
|
|
121
|
+
}).strict();
|
|
122
|
+
|
|
123
|
+
export const ReviewAgentFrontmatterSchema = z.object({
|
|
124
|
+
name: z.string().min(1),
|
|
125
|
+
description: z.string().min(1),
|
|
126
|
+
focus: z.string().min(1).optional(),
|
|
127
|
+
}).strict();
|
|
128
|
+
|
|
129
|
+
export const ReviewIterationSummarySchema = z.object({
|
|
130
|
+
iteration: z.number().min(1),
|
|
131
|
+
findings: z.number().min(0),
|
|
132
|
+
status: z.enum(REVIEW_OUTPUT_STATUSES),
|
|
133
|
+
file: z.string().min(1),
|
|
134
|
+
createdAt: z.string().min(1),
|
|
135
|
+
}).strict();
|
|
136
|
+
|
|
137
|
+
export const ReviewFixRecordSchema = z.object({
|
|
138
|
+
findingIds: z.array(z.string().min(1)),
|
|
139
|
+
file: z.string().min(1).nullable(),
|
|
140
|
+
status: z.enum(REVIEW_FIX_STATUSES),
|
|
141
|
+
summary: z.string().min(1),
|
|
142
|
+
}).strict();
|
|
175
143
|
|
|
176
144
|
export const REVIEW_FIX_OUTPUT_STATUSES = ["applied", "partial", "skipped", "blocked"] as const;
|
|
177
145
|
|
|
178
|
-
export const ReviewFixOutputSchema =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
Type.Union(REVIEW_POST_CONSOLIDATION_ACTIONS.map((value) => Type.Literal(value))),
|
|
213
|
-
Type.Null(),
|
|
214
|
-
]),
|
|
215
|
-
maxIterations: Type.Number({ minimum: 0 }),
|
|
216
|
-
currentIteration: Type.Number({ minimum: 0 }),
|
|
217
|
-
iterations: Type.Array(ReviewIterationSummarySchema),
|
|
218
|
-
fixes: Type.Array(ReviewFixRecordSchema),
|
|
219
|
-
artifacts: ReviewSessionArtifactsSchema,
|
|
220
|
-
agents: Type.Array(Type.String({ minLength: 1 })),
|
|
221
|
-
},
|
|
222
|
-
{ additionalProperties: false },
|
|
223
|
-
);
|
|
146
|
+
export const ReviewFixOutputSchema = z.object({
|
|
147
|
+
fixes: z.array(ReviewFixRecordSchema),
|
|
148
|
+
summary: z.string().min(1),
|
|
149
|
+
status: z.enum(REVIEW_FIX_OUTPUT_STATUSES),
|
|
150
|
+
}).strict();
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
export const ReviewSessionArtifactsSchema = z.object({
|
|
154
|
+
scope: z.string().min(1),
|
|
155
|
+
iterationsDir: z.string().min(1),
|
|
156
|
+
agentsDir: z.string().min(1),
|
|
157
|
+
rawFindings: z.string().min(1).optional(),
|
|
158
|
+
validatedFindings: z.string().min(1).optional(),
|
|
159
|
+
consolidatedFindings: z.string().min(1).optional(),
|
|
160
|
+
findingsReport: z.string().min(1).optional(),
|
|
161
|
+
}).strict();
|
|
162
|
+
|
|
163
|
+
export const ReviewSessionSchema = z.object({
|
|
164
|
+
id: z.string().min(1),
|
|
165
|
+
createdAt: z.string().min(1),
|
|
166
|
+
updatedAt: z.string().min(1),
|
|
167
|
+
level: z.enum(REVIEW_LEVELS),
|
|
168
|
+
status: z.enum(REVIEW_SESSION_STATUSES),
|
|
169
|
+
scope: ReviewScopeSchema,
|
|
170
|
+
validateFindings: z.boolean(),
|
|
171
|
+
consolidate: z.boolean(),
|
|
172
|
+
postConsolidationAction: z.enum(REVIEW_POST_CONSOLIDATION_ACTIONS).nullable(),
|
|
173
|
+
maxIterations: z.number().min(0),
|
|
174
|
+
currentIteration: z.number().min(0),
|
|
175
|
+
iterations: z.array(ReviewIterationSummarySchema),
|
|
176
|
+
fixes: z.array(ReviewFixRecordSchema),
|
|
177
|
+
artifacts: ReviewSessionArtifactsSchema,
|
|
178
|
+
agents: z.array(z.string().min(1)),
|
|
179
|
+
}).strict();
|
|
224
180
|
|
|
225
181
|
|
|
226
182
|
export function isReviewScopeFile(value: unknown): value is ReviewScopeFile {
|
|
227
|
-
return
|
|
183
|
+
return checkSchema(ReviewScopeFileSchema, value);
|
|
228
184
|
}
|
|
229
185
|
|
|
230
186
|
export function isReviewScopeStats(value: unknown): value is ReviewScopeStats {
|
|
231
|
-
return
|
|
187
|
+
return checkSchema(ReviewScopeStatsSchema, value);
|
|
232
188
|
}
|
|
233
189
|
|
|
234
190
|
export function isReviewScope(value: unknown): value is ReviewScope {
|
|
235
|
-
return
|
|
191
|
+
return checkSchema(ReviewScopeSchema, value);
|
|
236
192
|
}
|
|
237
193
|
|
|
238
194
|
export function isReviewFinding(value: unknown): value is ReviewFinding {
|
|
239
|
-
return
|
|
195
|
+
return checkSchema(ReviewFindingSchema, value);
|
|
240
196
|
}
|
|
241
197
|
|
|
242
198
|
export function isReviewOutput(value: unknown): value is ReviewOutput {
|
|
243
|
-
return
|
|
199
|
+
return checkSchema(ReviewOutputSchema, value);
|
|
244
200
|
}
|
|
245
201
|
|
|
246
202
|
export function isReviewAgentConfig(value: unknown): value is ReviewAgentConfig {
|
|
247
|
-
return
|
|
203
|
+
return checkSchema(ReviewAgentConfigSchema, value);
|
|
248
204
|
}
|
|
249
205
|
|
|
250
206
|
export function isReviewAgentsConfig(value: unknown): value is ReviewAgentsConfig {
|
|
251
|
-
return
|
|
207
|
+
return checkSchema(ReviewAgentsConfigSchema, value);
|
|
252
208
|
}
|
|
253
209
|
|
|
254
210
|
export function isReviewSessionArtifacts(value: unknown): value is ReviewSessionArtifacts {
|
|
255
|
-
return
|
|
211
|
+
return checkSchema(ReviewSessionArtifactsSchema, value);
|
|
256
212
|
}
|
|
257
213
|
|
|
258
214
|
export function isReviewIterationSummary(value: unknown): value is ReviewIterationSummary {
|
|
259
|
-
return
|
|
215
|
+
return checkSchema(ReviewIterationSummarySchema, value);
|
|
260
216
|
}
|
|
261
217
|
|
|
262
218
|
export function isReviewFixRecord(value: unknown): value is ReviewFixRecord {
|
|
263
|
-
return
|
|
219
|
+
return checkSchema(ReviewFixRecordSchema, value);
|
|
264
220
|
}
|
|
265
221
|
|
|
266
222
|
export function isReviewSession(value: unknown): value is ReviewSession {
|
|
267
|
-
return
|
|
223
|
+
return checkSchema(ReviewSessionSchema, value);
|
|
268
224
|
}
|
|
269
225
|
|
|
270
226
|
export function isReviewAgentDefinition(value: unknown): value is ReviewAgentDefinition {
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ZodType } from "zod/v4";
|
|
2
2
|
import type { AgentSession, AgentSessionOptions, ExecOptions, ExecResult } from "./platform/types.js";
|
|
3
3
|
|
|
4
4
|
|
|
@@ -6,6 +6,9 @@ import type { AgentSession, AgentSessionOptions, ExecOptions, ExecResult } from
|
|
|
6
6
|
export interface ValidationError {
|
|
7
7
|
path: string;
|
|
8
8
|
message: string;
|
|
9
|
+
code?: string;
|
|
10
|
+
expected?: unknown;
|
|
11
|
+
received?: unknown;
|
|
9
12
|
}
|
|
10
13
|
// src/types.ts — Shared type definitions for supipowers
|
|
11
14
|
|
|
@@ -365,7 +368,7 @@ export interface GateExecutionContext {
|
|
|
365
368
|
export interface GateDefinition<TConfig> {
|
|
366
369
|
id: GateId;
|
|
367
370
|
description: string;
|
|
368
|
-
configSchema:
|
|
371
|
+
configSchema: ZodType;
|
|
369
372
|
detect(projectFacts: ProjectFacts): GateDetectionResult<TConfig> | null;
|
|
370
373
|
run(context: GateExecutionContext, config: TConfig): Promise<GateResult>;
|
|
371
374
|
}
|
|
@@ -1826,6 +1829,46 @@ export interface HarnessCiConfig {
|
|
|
1826
1829
|
* an explicit truthy `enabled`, so legacy specs do not trip it.
|
|
1827
1830
|
*/
|
|
1828
1831
|
prComment?: HarnessPrCommentConfig;
|
|
1832
|
+
/**
|
|
1833
|
+
* Optional Git topology + branch-protection wiring captured by the interactive
|
|
1834
|
+
* `git-verify` sub-step run between Design and Plan. Absent on legacy specs.
|
|
1835
|
+
*
|
|
1836
|
+
* - `mainBranch` is the canonical protected branch (typically `main` or `master`).
|
|
1837
|
+
* - `devBranch` is the development branch dev work flows through; `null` when the user
|
|
1838
|
+
* opts out of the convention.
|
|
1839
|
+
* - `enforceMainFromDevOnly` controls both the CI-side guardrail (a `verify-pr-source`
|
|
1840
|
+
* job appended to the rendered workflow) and the opportunistic server-side ruleset
|
|
1841
|
+
* applied via `gh api`. The CI guardrail is deterministic; the ruleset is best-effort.
|
|
1842
|
+
* - `verification` records what the interactive helper actually did. `appliedProtections`
|
|
1843
|
+
* is the set of enforcement layers that landed (e.g. `"ci-guardrail"`, `"ruleset"`).
|
|
1844
|
+
* `findings` carries non-fatal issues surfaced during the run; the validate stage
|
|
1845
|
+
* folds them into its report. `manualInstructionsPath` points at the rendered
|
|
1846
|
+
* fallback doc when `gh` is unavailable or lacks scope.
|
|
1847
|
+
*/
|
|
1848
|
+
git?: HarnessCiGitConfig;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
/** Git/branch-protection block recorded by the interactive verification helper. */
|
|
1852
|
+
export interface HarnessCiGitConfig {
|
|
1853
|
+
mainBranch: string;
|
|
1854
|
+
devBranch: string | null;
|
|
1855
|
+
enforceMainFromDevOnly: boolean;
|
|
1856
|
+
verification: HarnessCiGitVerification | null;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
/** Result block recorded by `runGitVerificationQa` for downstream stages to consume. */
|
|
1860
|
+
export interface HarnessCiGitVerification {
|
|
1861
|
+
checkedAt: string;
|
|
1862
|
+
appliedProtections: string[];
|
|
1863
|
+
findings: HarnessCiGitFinding[];
|
|
1864
|
+
/** Relative path (under the session dir) to the rendered manual-instructions doc, or null. */
|
|
1865
|
+
manualInstructionsPath: string | null;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
export interface HarnessCiGitFinding {
|
|
1869
|
+
severity: "info" | "warning" | "error";
|
|
1870
|
+
message: string;
|
|
1871
|
+
remediation?: string;
|
|
1829
1872
|
}
|
|
1830
1873
|
|
|
1831
1874
|
|
package/src/ui-design/session.ts
CHANGED
|
@@ -898,10 +898,10 @@ export function registerUiDesignToolGuard(platform: Platform): void {
|
|
|
898
898
|
const session = activeSession;
|
|
899
899
|
if (!session) return;
|
|
900
900
|
|
|
901
|
-
if (event.toolName === "
|
|
901
|
+
if (event.toolName === "resolve" && isUiDesignPlanApprovalResolveInput(event.input)) {
|
|
902
902
|
return {
|
|
903
903
|
block: true,
|
|
904
|
-
reason: "UI-design mode: completion is driven by the agent_end approval hook; do not call
|
|
904
|
+
reason: "UI-design mode: completion is driven by the agent_end approval hook; do not call `resolve` with `extra.title`.",
|
|
905
905
|
};
|
|
906
906
|
}
|
|
907
907
|
|
|
@@ -943,6 +943,17 @@ export function registerUiDesignToolGuard(platform: Platform): void {
|
|
|
943
943
|
});
|
|
944
944
|
}
|
|
945
945
|
|
|
946
|
+
function isUiDesignPlanApprovalResolveInput(input: unknown): boolean {
|
|
947
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) return false;
|
|
948
|
+
const candidate = input as { action?: unknown; extra?: unknown };
|
|
949
|
+
if (candidate.action !== "apply") return false;
|
|
950
|
+
const extra = candidate.extra;
|
|
951
|
+
return extra !== null
|
|
952
|
+
&& typeof extra === "object"
|
|
953
|
+
&& !Array.isArray(extra)
|
|
954
|
+
&& typeof (extra as { title?: unknown }).title === "string";
|
|
955
|
+
}
|
|
956
|
+
|
|
946
957
|
/**
|
|
947
958
|
* Register the `agent_end` hook that drives the ui-design approval UI.
|
|
948
959
|
*
|
|
@@ -129,7 +129,7 @@ function buildHardGate(options: UiDesignSystemPromptOptions): string[] {
|
|
|
129
129
|
"",
|
|
130
130
|
`- All file writes MUST happen inside \`${options.sessionDir}\`. Writing anywhere else is forbidden.`,
|
|
131
131
|
"- You **MUST NOT** generate production code (`.ts`, `.tsx`, `.vue`, `.svelte`, `.py`) into the user's codebase.",
|
|
132
|
-
"- You **MUST NOT** call `
|
|
132
|
+
"- You **MUST NOT** call `resolve` with `extra.title` — completion is driven by the agent_end approval hook.",
|
|
133
133
|
"- You **MUST NOT** use the `ask` tool. Use `planning_ask` for every user question.",
|
|
134
134
|
"- You **MUST NOT** skip a phase. Each phase's precondition file MUST exist on disk before you advance.",
|
|
135
135
|
"- You **MUST NOT** declare completion without updating `manifest.json`.",
|
|
@@ -256,7 +256,7 @@ function buildCriticalBlock(options: UiDesignSystemPromptOptions): string {
|
|
|
256
256
|
"## Completion",
|
|
257
257
|
"",
|
|
258
258
|
"Completion is driven by `manifest.json`. Set `status: \"complete\"` + `approvedAt` only after the user approves via Phase 9's review gate.",
|
|
259
|
-
"You **MUST NOT** call `
|
|
259
|
+
"You **MUST NOT** call `resolve` with `extra.title`, or write to `local://PLAN.md`.",
|
|
260
260
|
"After updating the manifest to a terminal state, stop and yield your turn — the approval UI handles teardown.",
|
|
261
261
|
"</critical>",
|
|
262
262
|
].join("\n");
|