@bastani/atomic 0.8.29-alpha.2 → 0.8.29-alpha.4
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/CHANGELOG.md +14 -6
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +1 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +4 -4
- package/dist/builtin/subagents/README.md +4 -4
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.ts +14 -0
- package/dist/builtin/subagents/src/extension/schemas.ts +1 -1
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +1 -6
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +1 -6
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +0 -1
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -1
- package/dist/builtin/subagents/src/runs/shared/structured-output.ts +16 -285
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
- package/dist/builtin/subagents/src/shared/types.ts +4 -4
- package/dist/builtin/subagents/src/slash/saved-chain-mapping.ts +3 -18
- package/dist/builtin/web-access/CHANGELOG.md +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +12 -5
- package/dist/builtin/workflows/README.md +10 -8
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +9 -49
- package/dist/builtin/workflows/builtin/goal.ts +68 -155
- package/dist/builtin/workflows/builtin/index.d.ts +2 -0
- package/dist/builtin/workflows/builtin/open-claude-design.ts +42 -110
- package/dist/builtin/workflows/builtin/ralph.d.ts +2 -0
- package/dist/builtin/workflows/builtin/ralph.ts +235 -565
- package/dist/builtin/workflows/builtin/shared-prompts.ts +7 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.ts +17 -0
- package/dist/builtin/workflows/src/extension/wiring.ts +55 -8
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +2 -29
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +1 -5
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +1 -1
- package/dist/builtin/workflows/src/shared/types.ts +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +7 -7
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -36
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/structured-output.d.ts +7 -18
- package/dist/core/tools/structured-output.d.ts.map +1 -1
- package/dist/core/tools/structured-output.js +9 -89
- package/dist/core/tools/structured-output.js.map +1 -1
- package/dist/core/tools/todos.d.ts +1 -0
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/todos.js +4 -0
- package/dist/core/tools/todos.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/docs/extensions.md +1 -1
- package/docs/quickstart.md +3 -3
- package/docs/sdk.md +1 -1
- package/docs/subagents.md +4 -6
- package/docs/usage.md +1 -1
- package/docs/workflows.md +23 -19
- package/package.json +2 -2
|
@@ -13,7 +13,7 @@ import { join } from "node:path";
|
|
|
13
13
|
import { defineWorkflow } from "../src/workflows/define-workflow.js";
|
|
14
14
|
import { Type } from "typebox";
|
|
15
15
|
import type { WorkflowTaskResult } from "../src/shared/types.js";
|
|
16
|
-
import { WORKER_PREFLIGHT_CONTRACT } from "./shared-prompts.js";
|
|
16
|
+
import { E2E_VERIFICATION_GUIDANCE, WORKER_PREFLIGHT_CONTRACT } from "./shared-prompts.js";
|
|
17
17
|
|
|
18
18
|
const DEFAULT_MAX_TURNS = 10;
|
|
19
19
|
// Goal Runner runs three independent reviewer personas; two approvals form a majority.
|
|
@@ -135,108 +135,64 @@ function positiveInteger(value: number | undefined, fallback: number): number {
|
|
|
135
135
|
return floored >= 1 ? floored : fallback;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
type: "array",
|
|
154
|
-
items: {
|
|
155
|
-
type: "object",
|
|
156
|
-
additionalProperties: false,
|
|
157
|
-
required: ["title", "body", "confidence_score", "code_location"],
|
|
158
|
-
properties: {
|
|
159
|
-
title: { type: "string" },
|
|
160
|
-
body: { type: "string" },
|
|
161
|
-
confidence_score: { type: "number", minimum: 0, maximum: 1 },
|
|
162
|
-
priority: { type: ["integer", "null"], minimum: 0, maximum: 3 },
|
|
163
|
-
code_location: {
|
|
164
|
-
type: "object",
|
|
165
|
-
additionalProperties: false,
|
|
166
|
-
required: ["absolute_file_path", "line_range"],
|
|
167
|
-
properties: {
|
|
168
|
-
absolute_file_path: { type: "string" },
|
|
169
|
-
line_range: {
|
|
170
|
-
type: "object",
|
|
171
|
-
additionalProperties: false,
|
|
172
|
-
required: ["start", "end"],
|
|
173
|
-
properties: {
|
|
174
|
-
start: { type: "integer", minimum: 1 },
|
|
175
|
-
end: { type: "integer", minimum: 1 },
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
138
|
+
const reviewFindingSchema = Type.Object(
|
|
139
|
+
{
|
|
140
|
+
title: Type.String(),
|
|
141
|
+
body: Type.String(),
|
|
142
|
+
confidence_score: Type.Number({ minimum: 0, maximum: 1 }),
|
|
143
|
+
priority: Type.Optional(
|
|
144
|
+
Type.Union([Type.Integer({ minimum: 0, maximum: 3 }), Type.Null()]),
|
|
145
|
+
),
|
|
146
|
+
code_location: Type.Object(
|
|
147
|
+
{
|
|
148
|
+
absolute_file_path: Type.String(),
|
|
149
|
+
line_range: Type.Object(
|
|
150
|
+
{
|
|
151
|
+
start: Type.Integer({ minimum: 1 }),
|
|
152
|
+
end: Type.Integer({ minimum: 1 }),
|
|
179
153
|
},
|
|
180
|
-
|
|
154
|
+
{ additionalProperties: false },
|
|
155
|
+
),
|
|
181
156
|
},
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
type: "string",
|
|
185
|
-
enum: ["patch is correct", "patch is incorrect"],
|
|
186
|
-
},
|
|
187
|
-
overall_explanation: { type: "string" },
|
|
188
|
-
overall_confidence_score: { type: "number", minimum: 0, maximum: 1 },
|
|
189
|
-
goal_oracle_satisfied: { type: "boolean" },
|
|
190
|
-
receipt_assessment: { type: "string" },
|
|
191
|
-
verification_remaining: { type: "string" },
|
|
192
|
-
stop_review_loop: { type: "boolean" },
|
|
193
|
-
reviewer_error: {
|
|
194
|
-
anyOf: [
|
|
195
|
-
{ type: "null" },
|
|
196
|
-
{
|
|
197
|
-
type: "object",
|
|
198
|
-
additionalProperties: false,
|
|
199
|
-
required: ["kind", "message", "attempted_recovery"],
|
|
200
|
-
properties: {
|
|
201
|
-
kind: {
|
|
202
|
-
type: "string",
|
|
203
|
-
enum: [
|
|
204
|
-
"validation_unavailable",
|
|
205
|
-
"dependency_unavailable",
|
|
206
|
-
"tool_failure",
|
|
207
|
-
"reviewer_failure",
|
|
208
|
-
],
|
|
209
|
-
},
|
|
210
|
-
message: { type: "string" },
|
|
211
|
-
attempted_recovery: { type: "string" },
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
],
|
|
215
|
-
},
|
|
157
|
+
{ additionalProperties: false },
|
|
158
|
+
),
|
|
216
159
|
},
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
async execute(_toolCallId: string, params: ReviewDecision) {
|
|
231
|
-
return {
|
|
232
|
-
content: [
|
|
233
|
-
{ type: "text" as const, text: JSON.stringify(params, null, 2) },
|
|
234
|
-
],
|
|
235
|
-
details: params,
|
|
236
|
-
terminate: true,
|
|
237
|
-
};
|
|
160
|
+
{ additionalProperties: false },
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const reviewerErrorSchema = Type.Object(
|
|
164
|
+
{
|
|
165
|
+
kind: Type.Union([
|
|
166
|
+
Type.Literal("validation_unavailable"),
|
|
167
|
+
Type.Literal("dependency_unavailable"),
|
|
168
|
+
Type.Literal("tool_failure"),
|
|
169
|
+
Type.Literal("reviewer_failure"),
|
|
170
|
+
]),
|
|
171
|
+
message: Type.String(),
|
|
172
|
+
attempted_recovery: Type.String(),
|
|
238
173
|
},
|
|
239
|
-
}
|
|
174
|
+
{ additionalProperties: false },
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const reviewDecisionSchema = Type.Object(
|
|
178
|
+
{
|
|
179
|
+
findings: Type.Array(reviewFindingSchema),
|
|
180
|
+
overall_correctness: Type.Union([
|
|
181
|
+
Type.Literal("patch is correct"),
|
|
182
|
+
Type.Literal("patch is incorrect"),
|
|
183
|
+
]),
|
|
184
|
+
overall_explanation: Type.String(),
|
|
185
|
+
overall_confidence_score: Type.Number({ minimum: 0, maximum: 1 }),
|
|
186
|
+
goal_oracle_satisfied: Type.Boolean(),
|
|
187
|
+
receipt_assessment: Type.String(),
|
|
188
|
+
verification_remaining: Type.String(),
|
|
189
|
+
stop_review_loop: Type.Boolean(),
|
|
190
|
+
reviewer_error: Type.Optional(
|
|
191
|
+
Type.Union([Type.Null(), reviewerErrorSchema]),
|
|
192
|
+
),
|
|
193
|
+
},
|
|
194
|
+
{ additionalProperties: false },
|
|
195
|
+
);
|
|
240
196
|
|
|
241
197
|
const GOAL_CONTINUATION_REFERENCE = [
|
|
242
198
|
"Continuation behavior:",
|
|
@@ -358,26 +314,8 @@ function normalizeBranchInput(
|
|
|
358
314
|
return looksLikeSafeGitRef ? trimmed : fallback;
|
|
359
315
|
}
|
|
360
316
|
|
|
361
|
-
function
|
|
362
|
-
|
|
363
|
-
const parsed = JSON.parse(text) as Partial<ReviewDecision>;
|
|
364
|
-
if (
|
|
365
|
-
parsed.overall_correctness !== "patch is correct" &&
|
|
366
|
-
parsed.overall_correctness !== "patch is incorrect"
|
|
367
|
-
) {
|
|
368
|
-
return undefined;
|
|
369
|
-
}
|
|
370
|
-
if (!Array.isArray(parsed.findings)) return undefined;
|
|
371
|
-
if (typeof parsed.stop_review_loop !== "boolean") return undefined;
|
|
372
|
-
if (typeof parsed.overall_explanation !== "string") return undefined;
|
|
373
|
-
if (typeof parsed.overall_confidence_score !== "number") return undefined;
|
|
374
|
-
if (typeof parsed.goal_oracle_satisfied !== "boolean") return undefined;
|
|
375
|
-
if (typeof parsed.receipt_assessment !== "string") return undefined;
|
|
376
|
-
if (typeof parsed.verification_remaining !== "string") return undefined;
|
|
377
|
-
return parsed as ReviewDecision;
|
|
378
|
-
} catch {
|
|
379
|
-
return undefined;
|
|
380
|
-
}
|
|
317
|
+
function reviewDecisionFromResult(result: WorkflowTaskResult): ReviewDecision | undefined {
|
|
318
|
+
return result.structured as ReviewDecision | undefined;
|
|
381
319
|
}
|
|
382
320
|
|
|
383
321
|
function reviewApproved(decision: ReviewDecision): boolean {
|
|
@@ -589,6 +527,7 @@ function renderGoalContinuationPrompt(
|
|
|
589
527
|
].join("\n"),
|
|
590
528
|
],
|
|
591
529
|
["goal_guidelines", GOAL_CONTINUATION_REFERENCE],
|
|
530
|
+
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
592
531
|
]);
|
|
593
532
|
}
|
|
594
533
|
|
|
@@ -619,6 +558,7 @@ function renderForkedGoalWorkerPrompt(
|
|
|
619
558
|
renderLatestReviewArtifacts(latestReviewArtifactPaths),
|
|
620
559
|
].join("\n"),
|
|
621
560
|
],
|
|
561
|
+
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
622
562
|
]);
|
|
623
563
|
}
|
|
624
564
|
|
|
@@ -795,6 +735,7 @@ function renderReviewerPrompt(args: {
|
|
|
795
735
|
["goal_framework", GOAL_METHOD_REFERENCE],
|
|
796
736
|
["goal_guidelines", GOAL_CONTINUATION_REFERENCE],
|
|
797
737
|
["auditability", RECEIPT_EXPECTATIONS],
|
|
738
|
+
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
798
739
|
[
|
|
799
740
|
"goal_context",
|
|
800
741
|
[
|
|
@@ -829,8 +770,6 @@ function renderReviewerPrompt(args: {
|
|
|
829
770
|
[
|
|
830
771
|
"Inspect the actual diff/repository state rather than trusting stage summaries.",
|
|
831
772
|
"Identify the smallest relevant validation set from repository evidence: targeted tests, lint, typecheck, build, generated-artifact checks, CI-equivalent scripts, or user-flow proof.",
|
|
832
|
-
"When practical, include an end-to-end QA check that exercises the app the way a user would: use the tmux skill for terminal app environments and browser for web app environments.",
|
|
833
|
-
"For web app environments, capture a screenshot as a certificate of correct completion when the UI state proves the objective; for terminal app environments, capture the terminal window/output that shows proof of correctness.",
|
|
834
773
|
"Run or delegate focused validation when it is necessary to distinguish a real bug from a hunch.",
|
|
835
774
|
"If tests or typechecks fail because dependencies are missing, install/download the missing dependencies with the repo's documented package manager instead of bypassing the check.",
|
|
836
775
|
"If validation cannot be completed after reasonable recovery, record the limitation in overall_explanation and reviewer_error; do not use missing dependencies as a reason to approve.",
|
|
@@ -915,37 +854,9 @@ function renderReviewerPrompt(args: {
|
|
|
915
854
|
[
|
|
916
855
|
"output_format",
|
|
917
856
|
[
|
|
918
|
-
"You have a structured-output tool named review_decision. Use it after your investigation and validation attempts.",
|
|
919
|
-
"The tool terminates the turn and provides the structured data; do not emit a separate final assistant response after calling it.",
|
|
920
|
-
"The review gate decides completion only by parsing the JSON object returned by this tool; invalid JSON, missing fields, reviewer_error, or stop_review_loop=false are treated as not approved for safety.",
|
|
921
857
|
"Set stop_review_loop=true only when there are no P0/P1/P2 findings, overall_correctness is patch is correct, goal_oracle_satisfied is true, no objective-relevant verification remains, and reviewer_error is null/omitted.",
|
|
922
858
|
"P3 nice-to-have findings are non-blocking when the rest of the approval contract is satisfied; do not use P3 for work required by the objective or verification oracle.",
|
|
923
|
-
"If you hit a reviewer/tool/validation error,
|
|
924
|
-
[
|
|
925
|
-
"The review_decision tool schema is authoritative; do not copy a hand-written JSON blob into the final response. Here is an example output:",
|
|
926
|
-
"{",
|
|
927
|
-
' "findings": [',
|
|
928
|
-
" {",
|
|
929
|
-
' "title": "<≤ 80 chars, imperative, starts with [P0]/[P1]/[P2]/[P3]>",',
|
|
930
|
-
' "body": "<one paragraph of valid Markdown explaining why this is a problem; cite files/lines/functions>",',
|
|
931
|
-
' "confidence_score": <float 0.0-1.0>,',
|
|
932
|
-
' "priority": <int 0-3 or null>,',
|
|
933
|
-
' "code_location": {',
|
|
934
|
-
' "absolute_file_path": "<absolute file path>",',
|
|
935
|
-
' "line_range": {"start": <int>, "end": <int>}',
|
|
936
|
-
" }",
|
|
937
|
-
" }",
|
|
938
|
-
" ],",
|
|
939
|
-
' "overall_correctness": "patch is correct" | "patch is incorrect",',
|
|
940
|
-
' "overall_explanation": "<1-3 sentence explanation justifying the verdict>",',
|
|
941
|
-
' "overall_confidence_score": <float 0.0-1.0>,',
|
|
942
|
-
' "goal_oracle_satisfied": <boolean>,',
|
|
943
|
-
' "receipt_assessment": "<how receipts/current evidence map to the verification oracle>",',
|
|
944
|
-
' "verification_remaining": "<oracle-relevant verification still missing, or none>",',
|
|
945
|
-
' "stop_review_loop": <boolean>,',
|
|
946
|
-
' "reviewer_error": null | {"kind": "validation_unavailable" | "dependency_unavailable" | "tool_failure" | "reviewer_failure", "message": "<what failed>", "attempted_recovery": "<what you tried>"}',
|
|
947
|
-
"}",
|
|
948
|
-
].join("\n"),
|
|
859
|
+
"If you hit a reviewer/tool/validation error, set stop_review_loop=false and populate reviewer_error instead of pretending the patch is approved.",
|
|
949
860
|
].join("\n"),
|
|
950
861
|
],
|
|
951
862
|
]);
|
|
@@ -1080,8 +991,8 @@ export default defineWorkflow("goal")
|
|
|
1080
991
|
"github-copilot/claude-opus-4.8:xhigh",
|
|
1081
992
|
"anthropic/claude-opus-4-8:xhigh"
|
|
1082
993
|
],
|
|
1083
|
-
tools:
|
|
1084
|
-
|
|
994
|
+
tools: goalRunnerTools,
|
|
995
|
+
schema: reviewDecisionSchema,
|
|
1085
996
|
};
|
|
1086
997
|
|
|
1087
998
|
let latestReviews: ReviewRecord[] = [];
|
|
@@ -1212,20 +1123,22 @@ export default defineWorkflow("goal")
|
|
|
1212
1123
|
});
|
|
1213
1124
|
} catch (err) {
|
|
1214
1125
|
const message = err instanceof Error ? err.message : String(err);
|
|
1126
|
+
const structured = reviewerErrorDecision(message);
|
|
1215
1127
|
reviewResults = [
|
|
1216
1128
|
{
|
|
1217
1129
|
name: `reviewer-error-${turn}`,
|
|
1218
1130
|
stageName: `reviewer-error-${turn}`,
|
|
1219
|
-
text: JSON.stringify(
|
|
1131
|
+
text: JSON.stringify(structured, null, 2),
|
|
1132
|
+
structured,
|
|
1220
1133
|
},
|
|
1221
1134
|
];
|
|
1222
1135
|
}
|
|
1223
1136
|
|
|
1224
1137
|
latestReviews = await Promise.all(reviewResults.map(async (result) => {
|
|
1225
1138
|
const reviewerName = result.name ?? result.stageName;
|
|
1226
|
-
const parsed =
|
|
1139
|
+
const parsed = reviewDecisionFromResult(result) ??
|
|
1227
1140
|
reviewerErrorDecision(
|
|
1228
|
-
`Reviewer ${reviewerName} returned
|
|
1141
|
+
`Reviewer ${reviewerName} returned no structured decision.`,
|
|
1229
1142
|
);
|
|
1230
1143
|
const reviewArtifactPath = await writeReviewArtifact(
|
|
1231
1144
|
artifactDir,
|
|
@@ -83,6 +83,8 @@ export type RalphWorkflowOutputs = WorkflowOutputValues & {
|
|
|
83
83
|
readonly result?: string;
|
|
84
84
|
readonly plan?: string;
|
|
85
85
|
readonly plan_path?: string;
|
|
86
|
+
readonly research?: string;
|
|
87
|
+
readonly research_path?: string;
|
|
86
88
|
readonly implementation_notes_path?: string;
|
|
87
89
|
readonly pr_report?: string;
|
|
88
90
|
readonly approved?: boolean;
|
|
@@ -115,115 +115,49 @@ type ExportGateDecision = {
|
|
|
115
115
|
readonly blocking_findings: readonly ExportGateFinding[];
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
const refinementDecisionSchema =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
ready_for_export: { type: "boolean" },
|
|
124
|
-
rationale: { type: "string" },
|
|
125
|
-
required_changes: { type: "array", items: { type: "string" } },
|
|
118
|
+
const refinementDecisionSchema = Type.Object(
|
|
119
|
+
{
|
|
120
|
+
ready_for_export: Type.Boolean(),
|
|
121
|
+
rationale: Type.String(),
|
|
122
|
+
required_changes: Type.Array(Type.String()),
|
|
126
123
|
},
|
|
127
|
-
|
|
124
|
+
{ additionalProperties: false },
|
|
125
|
+
);
|
|
128
126
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"This is a terminating structured-output tool; do not emit another assistant response after calling it.",
|
|
137
|
-
],
|
|
138
|
-
parameters: refinementDecisionSchema,
|
|
139
|
-
async execute(_toolCallId: string, params: RefinementDecision) {
|
|
140
|
-
return {
|
|
141
|
-
content: [{ type: "text" as const, text: JSON.stringify(params, null, 2) }],
|
|
142
|
-
details: params,
|
|
143
|
-
terminate: true,
|
|
144
|
-
};
|
|
127
|
+
const exportGateFindingSchema = Type.Object(
|
|
128
|
+
{
|
|
129
|
+
finding: Type.String(),
|
|
130
|
+
evidence: Type.String(),
|
|
131
|
+
why_blocking: Type.String(),
|
|
132
|
+
must_fix_action: Type.String(),
|
|
133
|
+
severity: Type.Literal("P0"),
|
|
145
134
|
},
|
|
146
|
-
}
|
|
135
|
+
{ additionalProperties: false },
|
|
136
|
+
);
|
|
147
137
|
|
|
148
|
-
const exportGateDecisionSchema =
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
has_blocking_findings: { type: "boolean" },
|
|
154
|
-
rationale: { type: "string" },
|
|
155
|
-
blocking_findings: {
|
|
156
|
-
type: "array",
|
|
157
|
-
items: {
|
|
158
|
-
type: "object",
|
|
159
|
-
additionalProperties: false,
|
|
160
|
-
required: ["finding", "evidence", "why_blocking", "must_fix_action", "severity"],
|
|
161
|
-
properties: {
|
|
162
|
-
finding: { type: "string" },
|
|
163
|
-
evidence: { type: "string" },
|
|
164
|
-
why_blocking: { type: "string" },
|
|
165
|
-
must_fix_action: { type: "string" },
|
|
166
|
-
severity: { type: "string", enum: ["P0"] },
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
},
|
|
138
|
+
const exportGateDecisionSchema = Type.Object(
|
|
139
|
+
{
|
|
140
|
+
has_blocking_findings: Type.Boolean(),
|
|
141
|
+
rationale: Type.String(),
|
|
142
|
+
blocking_findings: Type.Array(exportGateFindingSchema),
|
|
170
143
|
},
|
|
171
|
-
|
|
144
|
+
{ additionalProperties: false },
|
|
145
|
+
);
|
|
172
146
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
promptSnippet: "Emit the final export gate decision as structured data",
|
|
178
|
-
promptGuidelines: [
|
|
179
|
-
"Call export_gate_decision after auditing the preview for blocking findings.",
|
|
180
|
-
"This is a terminating structured-output tool; do not emit another assistant response after calling it.",
|
|
181
|
-
],
|
|
182
|
-
parameters: exportGateDecisionSchema,
|
|
183
|
-
async execute(_toolCallId: string, params: ExportGateDecision) {
|
|
184
|
-
return {
|
|
185
|
-
content: [{ type: "text" as const, text: JSON.stringify(params, null, 2) }],
|
|
186
|
-
details: params,
|
|
187
|
-
terminate: true,
|
|
188
|
-
};
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
function parseRefinementDecision(text: string): RefinementDecision {
|
|
193
|
-
const parsed = JSON.parse(text) as Partial<RefinementDecision>;
|
|
194
|
-
if (typeof parsed.ready_for_export !== "boolean") {
|
|
195
|
-
throw new Error("open-claude-design refinement decision missing ready_for_export.");
|
|
147
|
+
function refinementDecisionFromResult(result: WorkflowTaskResult): RefinementDecision {
|
|
148
|
+
const decision = result.structured as RefinementDecision | undefined;
|
|
149
|
+
if (!decision) {
|
|
150
|
+
throw new Error("open-claude-design refinement decision missing structured result.");
|
|
196
151
|
}
|
|
197
|
-
return
|
|
198
|
-
ready_for_export: parsed.ready_for_export,
|
|
199
|
-
rationale: typeof parsed.rationale === "string" ? parsed.rationale : "",
|
|
200
|
-
required_changes: Array.isArray(parsed.required_changes)
|
|
201
|
-
? parsed.required_changes.filter((item): item is string => typeof item === "string")
|
|
202
|
-
: [],
|
|
203
|
-
};
|
|
152
|
+
return decision;
|
|
204
153
|
}
|
|
205
154
|
|
|
206
|
-
function
|
|
207
|
-
const
|
|
208
|
-
if (
|
|
209
|
-
throw new Error("open-claude-design export gate decision missing
|
|
155
|
+
function exportGateDecisionFromResult(result: WorkflowTaskResult): ExportGateDecision {
|
|
156
|
+
const decision = result.structured as ExportGateDecision | undefined;
|
|
157
|
+
if (!decision) {
|
|
158
|
+
throw new Error("open-claude-design export gate decision missing structured result.");
|
|
210
159
|
}
|
|
211
|
-
return
|
|
212
|
-
has_blocking_findings: parsed.has_blocking_findings,
|
|
213
|
-
rationale: typeof parsed.rationale === "string" ? parsed.rationale : "",
|
|
214
|
-
blocking_findings: Array.isArray(parsed.blocking_findings)
|
|
215
|
-
? parsed.blocking_findings.filter(
|
|
216
|
-
(item): item is ExportGateFinding =>
|
|
217
|
-
typeof item === "object" &&
|
|
218
|
-
item !== null &&
|
|
219
|
-
"finding" in item &&
|
|
220
|
-
"evidence" in item &&
|
|
221
|
-
"why_blocking" in item &&
|
|
222
|
-
"must_fix_action" in item &&
|
|
223
|
-
"severity" in item,
|
|
224
|
-
)
|
|
225
|
-
: [],
|
|
226
|
-
};
|
|
160
|
+
return decision;
|
|
227
161
|
}
|
|
228
162
|
|
|
229
163
|
function joinResults(results: readonly WorkflowTaskResult[]): string {
|
|
@@ -481,13 +415,13 @@ export default defineWorkflow("open-claude-design")
|
|
|
481
415
|
};
|
|
482
416
|
const refinementDecisionConfig = {
|
|
483
417
|
...designModelConfig,
|
|
484
|
-
tools: [...READ_ONLY_TOOLS
|
|
485
|
-
|
|
418
|
+
tools: [...READ_ONLY_TOOLS],
|
|
419
|
+
schema: refinementDecisionSchema,
|
|
486
420
|
};
|
|
487
421
|
const exportGateDecisionConfig = {
|
|
488
422
|
...designModelConfig,
|
|
489
|
-
tools: [...READ_ONLY_TOOLS
|
|
490
|
-
|
|
423
|
+
tools: [...READ_ONLY_TOOLS],
|
|
424
|
+
schema: exportGateDecisionSchema,
|
|
491
425
|
};
|
|
492
426
|
|
|
493
427
|
let designSystem: string;
|
|
@@ -850,7 +784,7 @@ export default defineWorkflow("open-claude-design")
|
|
|
850
784
|
[
|
|
851
785
|
"1. If a previous `preview-display-*` step captured annotated user feedback or notes, honor them as the primary signal.",
|
|
852
786
|
"2. Otherwise, you may inspect the HTML file at preview_path directly (read it from disk) and run an impeccable `critique` against it.",
|
|
853
|
-
"3. Decide whether the current design is ready for export
|
|
787
|
+
"3. Decide whether the current design is ready for export.",
|
|
854
788
|
"4. If refinement is still needed, put specific changes in required_changes ordered by user value and implementation risk.",
|
|
855
789
|
"5. Never request changes that contradict DESIGN.md unless you explicitly identify and explain the conflict.",
|
|
856
790
|
].join("\n"),
|
|
@@ -858,7 +792,6 @@ export default defineWorkflow("open-claude-design")
|
|
|
858
792
|
[
|
|
859
793
|
"output_format",
|
|
860
794
|
[
|
|
861
|
-
"Call the refinement_decision tool after your inspection.",
|
|
862
795
|
"Set ready_for_export=true only when the current preview needs no further refinement before export.",
|
|
863
796
|
"Set ready_for_export=false and populate required_changes when another polish iteration is needed.",
|
|
864
797
|
].join("\n"),
|
|
@@ -868,7 +801,7 @@ export default defineWorkflow("open-claude-design")
|
|
|
868
801
|
...refinementDecisionConfig,
|
|
869
802
|
});
|
|
870
803
|
|
|
871
|
-
const feedbackDecision =
|
|
804
|
+
const feedbackDecision = refinementDecisionFromResult(feedback);
|
|
872
805
|
if (feedbackDecision.ready_for_export) {
|
|
873
806
|
approvedForExport = true;
|
|
874
807
|
break;
|
|
@@ -1058,14 +991,13 @@ export default defineWorkflow("open-claude-design")
|
|
|
1058
991
|
"1. Read the HTML at preview_path and score it across all five audit dimensions.",
|
|
1059
992
|
"2. Scan for banned anti-patterns, accessibility blockers, severe visual regressions, missing critical states, and handoff gaps.",
|
|
1060
993
|
"3. Only mark findings as blocking when they would materially harm implementation or user experience (impeccable P0 severity).",
|
|
1061
|
-
"4. Decide whether export is blocked
|
|
994
|
+
"4. Decide whether export is blocked.",
|
|
1062
995
|
"5. Every blocking finding must include selector-level evidence and a must-fix action.",
|
|
1063
996
|
].join("\n"),
|
|
1064
997
|
],
|
|
1065
998
|
[
|
|
1066
|
-
"
|
|
999
|
+
"decision_rules",
|
|
1067
1000
|
[
|
|
1068
|
-
"Call the export_gate_decision tool after the audit.",
|
|
1069
1001
|
"Set has_blocking_findings=true only when one or more P0 findings block export.",
|
|
1070
1002
|
"Populate blocking_findings with every blocking P0 issue; leave it empty when export is safe.",
|
|
1071
1003
|
].join("\n"),
|
|
@@ -1075,7 +1007,7 @@ export default defineWorkflow("open-claude-design")
|
|
|
1075
1007
|
...exportGateDecisionConfig,
|
|
1076
1008
|
});
|
|
1077
1009
|
|
|
1078
|
-
const exportGateDecision =
|
|
1010
|
+
const exportGateDecision = exportGateDecisionFromResult(preExport);
|
|
1079
1011
|
if (exportGateDecision.has_blocking_findings) {
|
|
1080
1012
|
const forcedFix = await ctx.task("forced-fix", {
|
|
1081
1013
|
prompt: taggedPrompt([
|
|
@@ -20,6 +20,8 @@ export type RalphWorkflowOutputs = WorkflowOutputValues & {
|
|
|
20
20
|
readonly result?: string;
|
|
21
21
|
readonly plan?: string;
|
|
22
22
|
readonly plan_path?: string;
|
|
23
|
+
readonly research?: string;
|
|
24
|
+
readonly research_path?: string;
|
|
23
25
|
readonly implementation_notes_path?: string;
|
|
24
26
|
readonly pr_report?: string;
|
|
25
27
|
readonly approved?: boolean;
|