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/lsp/capabilities.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// treated as fail-closed: NO_LSP_SUPPORT (gate skips rather than pretending
|
|
12
12
|
// it ran).
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { z } from "zod/v4";
|
|
15
15
|
import {
|
|
16
16
|
parseStructuredOutput,
|
|
17
17
|
runWithOutputValidation,
|
|
@@ -20,18 +20,15 @@ import {
|
|
|
20
20
|
import { renderSchemaText } from "../ai/schema-text.js";
|
|
21
21
|
import type { GateExecutionContext } from "../types.js";
|
|
22
22
|
|
|
23
|
-
export const LspCapabilitiesSchema =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
},
|
|
31
|
-
{ additionalProperties: false },
|
|
32
|
-
);
|
|
23
|
+
export const LspCapabilitiesSchema = z.object({
|
|
24
|
+
diagnostics: z.boolean(),
|
|
25
|
+
references: z.boolean(),
|
|
26
|
+
definition: z.boolean(),
|
|
27
|
+
hover: z.boolean(),
|
|
28
|
+
rename: z.boolean(),
|
|
29
|
+
}).strict();
|
|
33
30
|
|
|
34
|
-
export type LspCapabilities =
|
|
31
|
+
export type LspCapabilities = z.infer<typeof LspCapabilitiesSchema>;
|
|
35
32
|
|
|
36
33
|
const SCHEMA_TEXT = renderSchemaText(LspCapabilitiesSchema);
|
|
37
34
|
|
package/src/lsp/contracts.ts
CHANGED
|
@@ -4,32 +4,24 @@
|
|
|
4
4
|
// ai/structured-output.ts to schema-check model output and by
|
|
5
5
|
// ai/schema-text.ts to render the shape into the prompt.
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { z } from "zod/v4";
|
|
8
8
|
|
|
9
9
|
const DIAGNOSTIC_SEVERITIES = ["error", "warning", "info", "hint"] as const;
|
|
10
10
|
|
|
11
|
-
export const LspDiagnosticSchema =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
line: Type.Number(),
|
|
18
|
-
column: Type.Number(),
|
|
19
|
-
},
|
|
20
|
-
{ additionalProperties: false },
|
|
21
|
-
);
|
|
11
|
+
export const LspDiagnosticSchema = z.object({
|
|
12
|
+
severity: z.enum(DIAGNOSTIC_SEVERITIES),
|
|
13
|
+
message: z.string(),
|
|
14
|
+
line: z.number(),
|
|
15
|
+
column: z.number(),
|
|
16
|
+
}).strict();
|
|
22
17
|
|
|
23
|
-
export const LspDiagnosticsResultSchema =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
{ additionalProperties: false },
|
|
29
|
-
);
|
|
18
|
+
export const LspDiagnosticsResultSchema = z.object({
|
|
19
|
+
file: z.string(),
|
|
20
|
+
diagnostics: z.array(LspDiagnosticSchema),
|
|
21
|
+
}).strict();
|
|
30
22
|
|
|
31
|
-
export const LspDiagnosticsResultsSchema =
|
|
23
|
+
export const LspDiagnosticsResultsSchema = z.array(LspDiagnosticsResultSchema);
|
|
32
24
|
|
|
33
|
-
export type LspDiagnostic =
|
|
34
|
-
export type LspDiagnosticsResult =
|
|
35
|
-
export type LspDiagnosticsResults =
|
|
25
|
+
export type LspDiagnostic = z.infer<typeof LspDiagnosticSchema>;
|
|
26
|
+
export type LspDiagnosticsResult = z.infer<typeof LspDiagnosticsResultSchema>;
|
|
27
|
+
export type LspDiagnosticsResults = z.infer<typeof LspDiagnosticsResultsSchema>;
|
|
@@ -129,11 +129,11 @@ function getAskRedirectReason(): string | null {
|
|
|
129
129
|
*/
|
|
130
130
|
export function registerPlanningAskToolGuard(platform: Platform): void {
|
|
131
131
|
platform.on("tool_call", (event) => {
|
|
132
|
-
if (event.toolName === "
|
|
132
|
+
if (event.toolName === "resolve" && isPlanApprovalResolveInput(event.input) && isPlanningActive()) {
|
|
133
133
|
return {
|
|
134
134
|
block: true,
|
|
135
135
|
reason:
|
|
136
|
-
"Planning mode: /supi:plan uses a file-based approval hook. Do not call
|
|
136
|
+
"Planning mode: /supi:plan uses a file-based approval hook. Do not call `resolve` with `extra.title` because it is OMP's native approval path and bypasses supipowers plan tracking.",
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -148,3 +148,14 @@ export function registerPlanningAskToolGuard(platform: Platform): void {
|
|
|
148
148
|
};
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
|
+
|
|
152
|
+
function isPlanApprovalResolveInput(input: unknown): boolean {
|
|
153
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) return false;
|
|
154
|
+
const candidate = input as { action?: unknown; extra?: unknown };
|
|
155
|
+
if (candidate.action !== "apply") return false;
|
|
156
|
+
const extra = candidate.extra;
|
|
157
|
+
return extra !== null
|
|
158
|
+
&& typeof extra === "object"
|
|
159
|
+
&& !Array.isArray(extra)
|
|
160
|
+
&& typeof (extra as { title?: unknown }).title === "string";
|
|
161
|
+
}
|
package/src/planning/spec.ts
CHANGED
|
@@ -8,35 +8,29 @@
|
|
|
8
8
|
// Phase 3 exit gate: PlanSpec is the canonical planning artifact; markdown
|
|
9
9
|
// is rendered from it via render-markdown.ts, not the other way around.
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { z } from "zod/v4";
|
|
12
12
|
|
|
13
13
|
export const TASK_COMPLEXITY_VALUES = ["small", "medium", "large"] as const;
|
|
14
14
|
|
|
15
|
-
export const PlanSpecTaskSchema =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
{ additionalProperties: false },
|
|
26
|
-
);
|
|
15
|
+
export const PlanSpecTaskSchema = z.object({
|
|
16
|
+
id: z.number().int().min(1),
|
|
17
|
+
name: z.string().min(1),
|
|
18
|
+
description: z.string(),
|
|
19
|
+
files: z.array(z.string().min(1)),
|
|
20
|
+
criteria: z.string(),
|
|
21
|
+
complexity: z.enum(TASK_COMPLEXITY_VALUES),
|
|
22
|
+
model: z.string().min(1).optional(),
|
|
23
|
+
}).strict();
|
|
27
24
|
|
|
28
|
-
export const PlanSpecSchema =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
{ additionalProperties: false },
|
|
39
|
-
);
|
|
25
|
+
export const PlanSpecSchema = z.object({
|
|
26
|
+
name: z.string().min(1),
|
|
27
|
+
/** ISO date string, e.g. "2026-04-17". Empty string is tolerated for
|
|
28
|
+
* legacy plans produced before the field was required. */
|
|
29
|
+
created: z.string(),
|
|
30
|
+
tags: z.array(z.string()),
|
|
31
|
+
context: z.string(),
|
|
32
|
+
tasks: z.array(PlanSpecTaskSchema),
|
|
33
|
+
}).strict();
|
|
40
34
|
|
|
41
|
-
export type PlanSpec =
|
|
42
|
-
export type PlanSpecTask =
|
|
35
|
+
export type PlanSpec = z.infer<typeof PlanSpecSchema>;
|
|
36
|
+
export type PlanSpecTask = z.infer<typeof PlanSpecTaskSchema>;
|
|
@@ -233,7 +233,7 @@ function buildPlanningCriticalBlock(options: PlanningSystemPromptOptions): strin
|
|
|
233
233
|
"## Plan submission",
|
|
234
234
|
"",
|
|
235
235
|
"This is NOT native OMP plan mode.",
|
|
236
|
-
"You **MUST NOT** call `
|
|
236
|
+
"You **MUST NOT** call `resolve` with `extra.title` — that is OMP's native approval path and bypasses supipowers' file-based approval hook.",
|
|
237
237
|
`You **MUST NOT** write plans to \`local://PLAN.md\` — that is OMP's native plan location and will not trigger the approval flow.`,
|
|
238
238
|
`You **MUST** save the plan to \`${options.plansDir}/YYYY-MM-DD-<feature-name>.md\` using the Write tool.`,
|
|
239
239
|
"After saving, tell the user the plan path, then **stop and yield your turn**.",
|
package/src/planning/validate.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// Everyone converges on the same path so validation errors surface in one
|
|
6
6
|
// consistent shape with field-level paths.
|
|
7
7
|
|
|
8
|
-
import { Value } from "@sinclair/typebox/value";
|
|
9
8
|
import { collectValidationErrors, formatValidationErrors } from "../ai/structured-output.js";
|
|
10
9
|
import type { ValidationError } from "../types.js";
|
|
11
10
|
import { PlanSpecSchema, type PlanSpec } from "./spec.js";
|
|
@@ -22,14 +21,12 @@ export interface PlanSpecValidationResult {
|
|
|
22
21
|
* human-readable summary and `errors` lists every field-level issue.
|
|
23
22
|
*/
|
|
24
23
|
export function validatePlanSpec(data: unknown): PlanSpecValidationResult {
|
|
25
|
-
|
|
24
|
+
const errors = collectValidationErrors(PlanSpecSchema, data);
|
|
25
|
+
if (errors.length === 0) {
|
|
26
26
|
return { output: data as PlanSpec, error: null, errors: [] };
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
const error = errors.length > 0
|
|
31
|
-
? formatValidationErrors(errors).join("; ")
|
|
32
|
-
: "Plan does not match the PlanSpec schema.";
|
|
29
|
+
const error = formatValidationErrors(errors).join("; ") || "Plan does not match the PlanSpec schema.";
|
|
33
30
|
return { output: null, error, errors };
|
|
34
31
|
}
|
|
35
32
|
|
|
@@ -37,7 +34,7 @@ export function validatePlanSpec(data: unknown): PlanSpecValidationResult {
|
|
|
37
34
|
* Narrowing predicate for PlanSpec. Use when you do not need error detail.
|
|
38
35
|
*/
|
|
39
36
|
export function isPlanSpec(value: unknown): value is PlanSpec {
|
|
40
|
-
return
|
|
37
|
+
return collectValidationErrors(PlanSpecSchema, value).length === 0;
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
|
package/src/platform/progress.ts
CHANGED
|
@@ -58,6 +58,7 @@ export function createWorkflowProgress(ui: PlatformUI, options: WorkflowProgress
|
|
|
58
58
|
let frame = 0;
|
|
59
59
|
let statusActive = false;
|
|
60
60
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
61
|
+
let disposed = false;
|
|
61
62
|
|
|
62
63
|
function visibleSteps(): WorkflowStepState[] {
|
|
63
64
|
return steps.filter((step) => !step.hidden);
|
|
@@ -92,6 +93,9 @@ export function createWorkflowProgress(ui: PlatformUI, options: WorkflowProgress
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
function refresh() {
|
|
96
|
+
if (disposed) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
95
99
|
frame++;
|
|
96
100
|
ui.setWidget?.(widgetKey, () => new Text(renderWidgetText(), 0, 0));
|
|
97
101
|
if (statusActive) {
|
|
@@ -100,6 +104,9 @@ export function createWorkflowProgress(ui: PlatformUI, options: WorkflowProgress
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
function startTimer() {
|
|
107
|
+
if (disposed) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
103
110
|
if (!timer) {
|
|
104
111
|
timer = setInterval(refresh, 80);
|
|
105
112
|
}
|
|
@@ -117,6 +124,9 @@ export function createWorkflowProgress(ui: PlatformUI, options: WorkflowProgress
|
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
function setStatus(stepKey: string, status: WorkflowStepStatus, detail?: string) {
|
|
127
|
+
if (disposed) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
120
130
|
const step = getStep(stepKey);
|
|
121
131
|
if (!step) {
|
|
122
132
|
return;
|
|
@@ -170,6 +180,7 @@ export function createWorkflowProgress(ui: PlatformUI, options: WorkflowProgress
|
|
|
170
180
|
refresh();
|
|
171
181
|
},
|
|
172
182
|
dispose() {
|
|
183
|
+
disposed = true;
|
|
173
184
|
stopTimer();
|
|
174
185
|
ui.setStatus?.(options.statusKey, undefined);
|
|
175
186
|
for (const key of options.clearStatusKeys ?? []) {
|
package/src/quality/contracts.ts
CHANGED
|
@@ -1,34 +1,26 @@
|
|
|
1
1
|
// src/quality/contracts.ts
|
|
2
2
|
//
|
|
3
|
-
//
|
|
3
|
+
// Zod contracts for AI-driven quality-gate workflows. Embedded into
|
|
4
4
|
// prompts via ai/schema-text.ts and used by ai/structured-output.ts to
|
|
5
5
|
// validate model output with retry-on-invalid feedback.
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { z } from "zod/v4";
|
|
8
8
|
|
|
9
9
|
const ISSUE_SEVERITIES = ["error", "warning", "info"] as const;
|
|
10
10
|
const RECOMMENDED_STATUSES = ["passed", "failed", "blocked"] as const;
|
|
11
11
|
|
|
12
|
-
export const AiReviewIssueSchema =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
{ additionalProperties: false },
|
|
21
|
-
);
|
|
12
|
+
export const AiReviewIssueSchema = z.object({
|
|
13
|
+
severity: z.enum(ISSUE_SEVERITIES),
|
|
14
|
+
message: z.string().min(1),
|
|
15
|
+
file: z.string().optional(),
|
|
16
|
+
line: z.number().optional(),
|
|
17
|
+
detail: z.string().optional(),
|
|
18
|
+
}).strict();
|
|
22
19
|
|
|
23
|
-
export const AiReviewOutputSchema =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
RECOMMENDED_STATUSES.map((value) => Type.Literal(value)),
|
|
29
|
-
),
|
|
30
|
-
},
|
|
31
|
-
{ additionalProperties: false },
|
|
32
|
-
);
|
|
20
|
+
export const AiReviewOutputSchema = z.object({
|
|
21
|
+
summary: z.string(),
|
|
22
|
+
issues: z.array(AiReviewIssueSchema),
|
|
23
|
+
recommendedStatus: z.enum(RECOMMENDED_STATUSES),
|
|
24
|
+
}).strict();
|
|
33
25
|
|
|
34
|
-
export type AiReviewOutput =
|
|
26
|
+
export type AiReviewOutput = z.infer<typeof AiReviewOutputSchema>;
|
package/src/quality/schemas.ts
CHANGED
|
@@ -1,79 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { ZodType } from "zod/v4";
|
|
3
3
|
import type { GateId } from "../types.js";
|
|
4
4
|
|
|
5
|
-
export const LspDiagnosticsGateConfigSchema =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
},
|
|
9
|
-
{ additionalProperties: false },
|
|
10
|
-
);
|
|
5
|
+
export const LspDiagnosticsGateConfigSchema = z.object({
|
|
6
|
+
enabled: z.boolean(),
|
|
7
|
+
}).strict();
|
|
11
8
|
|
|
12
|
-
export const CommandGateRunTargetSchema =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
),
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{
|
|
27
|
-
scope: Type.Literal("all-workspaces"),
|
|
28
|
-
},
|
|
29
|
-
{ additionalProperties: false },
|
|
30
|
-
),
|
|
31
|
-
Type.Object(
|
|
32
|
-
{
|
|
33
|
-
scope: Type.Literal("workspace"),
|
|
34
|
-
relativeDir: Type.String({ minLength: 1 }),
|
|
35
|
-
},
|
|
36
|
-
{ additionalProperties: false },
|
|
37
|
-
),
|
|
9
|
+
export const CommandGateRunTargetSchema = z.union([
|
|
10
|
+
z.object({
|
|
11
|
+
scope: z.literal("all-targets"),
|
|
12
|
+
}).strict(),
|
|
13
|
+
z.object({
|
|
14
|
+
scope: z.literal("root"),
|
|
15
|
+
}).strict(),
|
|
16
|
+
z.object({
|
|
17
|
+
scope: z.literal("all-workspaces"),
|
|
18
|
+
}).strict(),
|
|
19
|
+
z.object({
|
|
20
|
+
scope: z.literal("workspace"),
|
|
21
|
+
relativeDir: z.string().min(1),
|
|
22
|
+
}).strict(),
|
|
38
23
|
]);
|
|
39
24
|
|
|
40
|
-
export const CommandGateRunSchema =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
{ additionalProperties: false },
|
|
46
|
-
);
|
|
25
|
+
export const CommandGateRunSchema = z.object({
|
|
26
|
+
command: z.string().min(1),
|
|
27
|
+
target: CommandGateRunTargetSchema,
|
|
28
|
+
}).strict();
|
|
47
29
|
|
|
48
|
-
export const CommandGateConfigSchema =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
enabled: Type.Literal(true),
|
|
58
|
-
runs: Type.Array(CommandGateRunSchema, { minItems: 1 }),
|
|
59
|
-
},
|
|
60
|
-
{ additionalProperties: false },
|
|
61
|
-
),
|
|
30
|
+
export const CommandGateConfigSchema = z.union([
|
|
31
|
+
z.object({
|
|
32
|
+
enabled: z.literal(false),
|
|
33
|
+
}).strict(),
|
|
34
|
+
z.object({
|
|
35
|
+
enabled: z.literal(true),
|
|
36
|
+
runs: z.array(CommandGateRunSchema).min(1),
|
|
37
|
+
}).strict(),
|
|
62
38
|
]);
|
|
63
39
|
|
|
64
|
-
export const QualityGatesSchema =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
},
|
|
73
|
-
{ additionalProperties: false },
|
|
74
|
-
);
|
|
40
|
+
export const QualityGatesSchema = z.object({
|
|
41
|
+
"lsp-diagnostics": LspDiagnosticsGateConfigSchema.optional(),
|
|
42
|
+
lint: CommandGateConfigSchema.optional(),
|
|
43
|
+
typecheck: CommandGateConfigSchema.optional(),
|
|
44
|
+
format: CommandGateConfigSchema.optional(),
|
|
45
|
+
"test-suite": CommandGateConfigSchema.optional(),
|
|
46
|
+
build: CommandGateConfigSchema.optional(),
|
|
47
|
+
}).strict();
|
|
75
48
|
|
|
76
|
-
export const GATE_CONFIG_SCHEMAS: Record<GateId,
|
|
49
|
+
export const GATE_CONFIG_SCHEMAS: Record<GateId, ZodType> = {
|
|
77
50
|
"lsp-diagnostics": LspDiagnosticsGateConfigSchema,
|
|
78
51
|
lint: CommandGateConfigSchema,
|
|
79
52
|
typecheck: CommandGateConfigSchema,
|
package/src/release/contracts.ts
CHANGED
|
@@ -15,49 +15,40 @@
|
|
|
15
15
|
// hands validation errors back to the model rather than letting the
|
|
16
16
|
// release command publish on malformed output.
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { z } from "zod/v4";
|
|
19
19
|
|
|
20
20
|
// ── Release-note polish ───────────────────────────────────────
|
|
21
21
|
|
|
22
22
|
export const RELEASE_NOTE_STATUSES = ["ok", "empty"] as const;
|
|
23
23
|
export type ReleaseNoteStatus = (typeof RELEASE_NOTE_STATUSES)[number];
|
|
24
24
|
|
|
25
|
-
export const ReleaseNotePolishOutputSchema =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
{ additionalProperties: false },
|
|
33
|
-
);
|
|
25
|
+
export const ReleaseNotePolishOutputSchema = z.object({
|
|
26
|
+
title: z.string().min(1),
|
|
27
|
+
body: z.string(),
|
|
28
|
+
highlights: z.array(z.string().min(1)),
|
|
29
|
+
status: z.enum(RELEASE_NOTE_STATUSES),
|
|
30
|
+
}).strict();
|
|
34
31
|
|
|
35
|
-
export type ReleaseNotePolishOutput =
|
|
32
|
+
export type ReleaseNotePolishOutput = z.infer<typeof ReleaseNotePolishOutputSchema>;
|
|
36
33
|
|
|
37
34
|
// ── Release doc-fix ───────────────────────────────────────────
|
|
38
35
|
|
|
39
36
|
export const RELEASE_DOC_FIX_STATUSES = ["ok", "blocked"] as const;
|
|
40
37
|
export type ReleaseDocFixStatus = (typeof RELEASE_DOC_FIX_STATUSES)[number];
|
|
41
38
|
|
|
42
|
-
export const ReleaseDocFixEditSchema =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
{ additionalProperties: false },
|
|
48
|
-
);
|
|
39
|
+
export const ReleaseDocFixEditSchema = z.object({
|
|
40
|
+
file: z.string().min(1),
|
|
41
|
+
instructions: z.string().min(1),
|
|
42
|
+
}).strict();
|
|
49
43
|
|
|
50
|
-
export const ReleaseDocFixOutputSchema =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
},
|
|
56
|
-
{ additionalProperties: false },
|
|
57
|
-
);
|
|
44
|
+
export const ReleaseDocFixOutputSchema = z.object({
|
|
45
|
+
edits: z.array(ReleaseDocFixEditSchema),
|
|
46
|
+
summary: z.string().min(1),
|
|
47
|
+
status: z.enum(RELEASE_DOC_FIX_STATUSES),
|
|
48
|
+
}).strict();
|
|
58
49
|
|
|
59
|
-
export type ReleaseDocFixEdit =
|
|
60
|
-
export type ReleaseDocFixOutput =
|
|
50
|
+
export type ReleaseDocFixEdit = z.infer<typeof ReleaseDocFixEditSchema>;
|
|
51
|
+
export type ReleaseDocFixOutput = z.infer<typeof ReleaseDocFixOutputSchema>;
|
|
61
52
|
|
|
62
53
|
/**
|
|
63
54
|
* Render a polished release-note artifact as markdown suitable for
|