@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.8
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 +19 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +4 -4
- package/dist/builtin/intercom/broker/broker.ts +617 -22
- package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
- package/dist/builtin/intercom/broker/client.ts +200 -10
- package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
- package/dist/builtin/intercom/broker/send-handler.ts +90 -36
- package/dist/builtin/intercom/broker/send-signature.ts +20 -8
- package/dist/builtin/intercom/group.ts +85 -0
- package/dist/builtin/intercom/index.bundle.mjs +680 -53
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/session-target.ts +54 -0
- package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
- package/dist/builtin/intercom/source-ownership.ts +31 -0
- package/dist/builtin/intercom/types.ts +115 -0
- package/dist/builtin/mcp/index.bundle.mjs +109 -35
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +173 -51
- package/dist/builtin/web-access/index.bundle.mjs +109 -35
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +15 -0
- package/dist/builtin/workflows/README.md +40 -37
- package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
- package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
- package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
- package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
- package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
- package/dist/builtin/workflows/builtin/chunk-5n10x7j2.js +69730 -0
- package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
- package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
- package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
- package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
- package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
- package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -0
- package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
- package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
- package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -0
- package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
- package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
- package/dist/builtin/workflows/builtin/chunk-zf28603f.js +1080 -0
- package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
- package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
- package/dist/builtin/workflows/builtin/goal.js +16 -0
- package/dist/builtin/workflows/builtin/index.js +49 -0
- package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
- package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
- package/dist/builtin/workflows/builtin/ralph.js +16 -0
- package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
- package/dist/builtin/workflows/builtin/steering-context.js +7 -0
- package/dist/builtin/workflows/builtin/tournament.js +13 -0
- package/dist/builtin/workflows/package.json +10 -7
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1228 -428
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
- package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +12 -5
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +2 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtin-install-layout.d.ts +1 -1
- package/dist/core/builtin-install-layout.d.ts.map +1 -1
- package/dist/core/builtin-install-layout.js +1 -1
- package/dist/core/builtin-install-layout.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +10 -7
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.js +31 -13
- package/dist/core/codex-fast-mode.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +35 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +6 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +1 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +8 -0
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +2 -0
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +4 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +6 -1
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +8 -9
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +1 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +33 -5
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +8 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/intercom.md +15 -6
- package/docs/packages.md +2 -2
- package/docs/providers.md +8 -3
- package/docs/quickstart.md +2 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +108 -239
- package/npm-shrinkwrap.json +32 -32
- package/package.json +9 -13
- package/dist/builtin/workflows/ambient.d.ts +0 -61
- package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
- package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
- package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
- package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
- package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
- package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
- package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
- package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
- package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
- package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
- package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
- package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
- package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
- package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
- package/dist/builtin/workflows/builtin/goal.ts +0 -78
- package/dist/builtin/workflows/builtin/index.ts +0 -16
- package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
- package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
- package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
- package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
- package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
- package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
- package/dist/builtin/workflows/builtin/ralph.ts +0 -82
- package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
- package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
- package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
- package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
- package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
- package/dist/builtin/workflows/builtin/tournament.ts +0 -73
- package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
- package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
- package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
|
@@ -0,0 +1,1080 @@
|
|
|
1
|
+
import {
|
|
2
|
+
consolidateFindingsBatch,
|
|
3
|
+
convergence_escalation_evidence,
|
|
4
|
+
createWorkflowArtifactDirectory,
|
|
5
|
+
finalActionRemaining,
|
|
6
|
+
parseFailureDiagnostics,
|
|
7
|
+
record_convergence,
|
|
8
|
+
reverify_consolidated_batch,
|
|
9
|
+
reviewerFailureText,
|
|
10
|
+
summarizeReviewConvergence
|
|
11
|
+
} from "./chunk-hdpj1dkw.js";
|
|
12
|
+
import {
|
|
13
|
+
fold_usage
|
|
14
|
+
} from "./chunk-7at6dnkr.js";
|
|
15
|
+
import {
|
|
16
|
+
VERIFICATION_SCALE
|
|
17
|
+
} from "./chunk-cg9tmks0.js";
|
|
18
|
+
import {
|
|
19
|
+
workflow
|
|
20
|
+
} from "./chunk-bfkmzv9h.js";
|
|
21
|
+
import {
|
|
22
|
+
ACCEPTANCE_MATRIX_CONTRACT,
|
|
23
|
+
CODE_QUALITY_VERIFICATION_GUIDANCE,
|
|
24
|
+
CONTRACT_FIDELITY_AUDIT,
|
|
25
|
+
E2E_VERIFICATION_GUIDANCE,
|
|
26
|
+
EVIDENCE_CLOSURE_POLICY,
|
|
27
|
+
FINDINGS_CONSOLIDATION_CONTRACT,
|
|
28
|
+
LITERAL_OBJECTIVE_CONTRACT,
|
|
29
|
+
REGRESSION_EVIDENCE_CONTRACT,
|
|
30
|
+
REPO_INTENT_MINING_GUIDANCE,
|
|
31
|
+
REVIEWER_CALIBRATION_RULES,
|
|
32
|
+
REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT,
|
|
33
|
+
REVIEWER_INTERCOM_COORDINATION_PROTOCOL,
|
|
34
|
+
REVIEWER_OVERIMPLEMENTATION_GUARD,
|
|
35
|
+
REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
|
|
36
|
+
REVIEW_CODE_DELTA_CONTRACT,
|
|
37
|
+
SCOPE_DISCIPLINE_CONTRACT,
|
|
38
|
+
WORKER_PREFLIGHT_CONTRACT,
|
|
39
|
+
WORKTREE_DISCIPLINE_CONTRACT,
|
|
40
|
+
keepContext,
|
|
41
|
+
renderE2eQaVideoReviewGuidance,
|
|
42
|
+
withSteeringPropagationContext
|
|
43
|
+
} from "./chunk-0x6e303p.js";
|
|
44
|
+
|
|
45
|
+
// dist/builtin/workflows/builtin/ralph.ts
|
|
46
|
+
import { Type as Type2 } from "typebox";
|
|
47
|
+
|
|
48
|
+
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
49
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
50
|
+
import { dirname, join } from "node:path";
|
|
51
|
+
import { Type } from "typebox";
|
|
52
|
+
// dist/builtin/workflows/builtin/ralph-review-gate.ts
|
|
53
|
+
function reviewDecisionApproved(decision) {
|
|
54
|
+
return decision.stop_review_loop === true && decision.reviewer_error == null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
58
|
+
var DEFAULT_MAX_LOOPS = 10;
|
|
59
|
+
var DEFAULT_RESEARCH_DIR = "research";
|
|
60
|
+
var IMPLEMENTATION_NOTES_FILENAME = "implementation-notes.md";
|
|
61
|
+
var QA_E2E_VIDEO_FILENAME = "qa-e2e-evidence.webm";
|
|
62
|
+
var MAX_RESEARCH_SLUG_LENGTH = 80;
|
|
63
|
+
var REVIEWER_COUNT = 2;
|
|
64
|
+
var reviewFindingSchema = Type.Object({
|
|
65
|
+
title: Type.String(),
|
|
66
|
+
body: Type.String(),
|
|
67
|
+
confidence_score: Type.Number({ minimum: 0, maximum: 1 }),
|
|
68
|
+
objective_alignment: Type.Union([
|
|
69
|
+
Type.Literal("required_by_objective"),
|
|
70
|
+
Type.Literal("consistent_with_objective"),
|
|
71
|
+
Type.Literal("beyond_objective"),
|
|
72
|
+
Type.Literal("contradicts_objective")
|
|
73
|
+
]),
|
|
74
|
+
priority: Type.Optional(Type.Union([Type.Integer({ minimum: 0, maximum: 3 }), Type.Null()])),
|
|
75
|
+
code_location: Type.Object({
|
|
76
|
+
absolute_file_path: Type.String(),
|
|
77
|
+
line_range: Type.Object({
|
|
78
|
+
start: Type.Integer({ minimum: 1 }),
|
|
79
|
+
end: Type.Integer({ minimum: 1 })
|
|
80
|
+
}, { additionalProperties: false })
|
|
81
|
+
}, { additionalProperties: false })
|
|
82
|
+
}, { additionalProperties: false });
|
|
83
|
+
var requirementsTraceabilitySchema = Type.Object({
|
|
84
|
+
requirement: Type.String(),
|
|
85
|
+
status: Type.Union([
|
|
86
|
+
Type.Literal("proven"),
|
|
87
|
+
Type.Literal("contradicted"),
|
|
88
|
+
Type.Literal("missing"),
|
|
89
|
+
Type.Literal("unverified")
|
|
90
|
+
]),
|
|
91
|
+
evidence: Type.String()
|
|
92
|
+
}, { additionalProperties: false });
|
|
93
|
+
var reviewerErrorSchema = Type.Object({
|
|
94
|
+
kind: Type.Union([
|
|
95
|
+
Type.Literal("validation_unavailable"),
|
|
96
|
+
Type.Literal("dependency_unavailable"),
|
|
97
|
+
Type.Literal("tool_failure"),
|
|
98
|
+
Type.Literal("reviewer_failure")
|
|
99
|
+
]),
|
|
100
|
+
message: Type.String(),
|
|
101
|
+
attempted_recovery: Type.String()
|
|
102
|
+
}, { additionalProperties: false });
|
|
103
|
+
var reviewDecisionSchema = Type.Object({
|
|
104
|
+
findings: Type.Array(reviewFindingSchema),
|
|
105
|
+
overall_correctness: Type.Union([
|
|
106
|
+
Type.Literal("patch is correct"),
|
|
107
|
+
Type.Literal("patch is incorrect")
|
|
108
|
+
]),
|
|
109
|
+
overall_explanation: Type.String(),
|
|
110
|
+
overall_confidence_score: Type.Number({ minimum: 0, maximum: 1 }),
|
|
111
|
+
criterion_scores: Type.Optional(Type.Array(Type.Object({
|
|
112
|
+
criterion_id: Type.String(),
|
|
113
|
+
score: VERIFICATION_SCALE.schema
|
|
114
|
+
}, { additionalProperties: false }))),
|
|
115
|
+
requirements_traceability: Type.Array(requirementsTraceabilitySchema),
|
|
116
|
+
stop_review_loop: Type.Boolean(),
|
|
117
|
+
reviewer_error: Type.Optional(Type.Union([Type.Null(), reviewerErrorSchema]))
|
|
118
|
+
}, { additionalProperties: false });
|
|
119
|
+
function taggedPrompt(sections) {
|
|
120
|
+
return sections.map(([tag, content]) => {
|
|
121
|
+
const trimmed = content.trim();
|
|
122
|
+
return `<${tag}>
|
|
123
|
+
${trimmed}
|
|
124
|
+
</${tag}>`;
|
|
125
|
+
}).join(`
|
|
126
|
+
|
|
127
|
+
`);
|
|
128
|
+
}
|
|
129
|
+
function workflowCwdContextSection(workflowCwd) {
|
|
130
|
+
return [
|
|
131
|
+
"context",
|
|
132
|
+
[
|
|
133
|
+
`Current working directory: ${workflowCwd}`,
|
|
134
|
+
"Use this as the starting directory for repository work in this stage.",
|
|
135
|
+
"Shell commands and relative file paths should be relative to this directory unless you intentionally pass an explicit cwd override.",
|
|
136
|
+
"When delegating subagents, pass along that this is the current working directory."
|
|
137
|
+
].join(`
|
|
138
|
+
`)
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
function positiveInteger(value, fallback) {
|
|
142
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
|
|
143
|
+
}
|
|
144
|
+
function normalizeBranchInput(value, fallback) {
|
|
145
|
+
const trimmed = value?.trim();
|
|
146
|
+
if (!trimmed)
|
|
147
|
+
return fallback;
|
|
148
|
+
const looksLikeSafeGitRef = /^(?!-)(?!.*(?:\.\.|@\{|\/\/|\.lock(?:\/|$)))[A-Za-z0-9][A-Za-z0-9._/@+-]*$/.test(trimmed);
|
|
149
|
+
return looksLikeSafeGitRef ? trimmed : fallback;
|
|
150
|
+
}
|
|
151
|
+
function slugifyResearchTopic(prompt) {
|
|
152
|
+
const slug = prompt.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_RESEARCH_SLUG_LENGTH).replace(/-+$/g, "");
|
|
153
|
+
return slug.length > 0 ? slug : "research";
|
|
154
|
+
}
|
|
155
|
+
function defaultResearchPath(prompt, now = new Date) {
|
|
156
|
+
const date = now.toISOString().slice(0, 10);
|
|
157
|
+
return join(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
|
|
158
|
+
}
|
|
159
|
+
async function createImplementationNotesFile(prompt, runId) {
|
|
160
|
+
const notesDir = await createWorkflowArtifactDirectory(runId);
|
|
161
|
+
const notesPath = join(notesDir, IMPLEMENTATION_NOTES_FILENAME);
|
|
162
|
+
const initialNotes = [
|
|
163
|
+
"# Implementation Notes",
|
|
164
|
+
"",
|
|
165
|
+
`Task: ${prompt || "(empty prompt)"}`,
|
|
166
|
+
"",
|
|
167
|
+
"## Running Notes",
|
|
168
|
+
"",
|
|
169
|
+
"- Record implementation decisions, deviations from research, tradeoffs, blockers, validation outcomes, and user-relevant facts. Keep entries concise and readable.",
|
|
170
|
+
"- Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified."
|
|
171
|
+
].join(`
|
|
172
|
+
`);
|
|
173
|
+
await writeFile(notesPath, `${initialNotes}
|
|
174
|
+
`, {
|
|
175
|
+
encoding: "utf8",
|
|
176
|
+
flag: "wx"
|
|
177
|
+
});
|
|
178
|
+
return notesPath;
|
|
179
|
+
}
|
|
180
|
+
async function createQaEvidenceVideoPath(runId) {
|
|
181
|
+
const qaDir = await createWorkflowArtifactDirectory(runId);
|
|
182
|
+
return join(qaDir, QA_E2E_VIDEO_FILENAME);
|
|
183
|
+
}
|
|
184
|
+
function renderQaE2eVideoGuidance(qaVideoPath) {
|
|
185
|
+
return [
|
|
186
|
+
E2E_VERIFICATION_GUIDANCE,
|
|
187
|
+
`For a user-visible UI scenario, record the QA pass for review. After \`playwright-cli open\`, use \`playwright-cli video-start ${qaVideoPath}\`, annotate with \`playwright-cli video-chapter\` / \`playwright-cli video-show-actions\`, exercise the complete scenario, then run \`playwright-cli video-stop\`. Write to exactly ${qaVideoPath}, overwriting stale evidence.`,
|
|
188
|
+
`Add a \`## QA E2E Video\` entry to the implementation notes with the absolute path ${qaVideoPath} and one sentence naming the proven scenario. For changes without a user-visible UI scenario, record why video does not apply; never fabricate one.`,
|
|
189
|
+
"If `playwright-cli` or its browser runtime is unavailable, install it once per the skill (`npm install -g @playwright/cli@latest`, then `npx playwright install chromium` when needed). If a concrete attempt still fails, record the commands, observed failure output, smallest validation performed, and that no video was produced."
|
|
190
|
+
].join(`
|
|
191
|
+
`);
|
|
192
|
+
}
|
|
193
|
+
function reviewDecisionFromResult(result) {
|
|
194
|
+
return result.structured;
|
|
195
|
+
}
|
|
196
|
+
function parsedReviewDecisionFromResult(result, reviewer) {
|
|
197
|
+
const parsed = reviewDecisionFromResult(result);
|
|
198
|
+
if (parsed !== undefined) {
|
|
199
|
+
return { decision: parsed, parsed: true, diagnostics: [] };
|
|
200
|
+
}
|
|
201
|
+
const diagnostics = parseFailureDiagnostics(reviewer, result.text);
|
|
202
|
+
return {
|
|
203
|
+
decision: reviewerErrorDecision(diagnostics.join(`
|
|
204
|
+
`)),
|
|
205
|
+
parsed: false,
|
|
206
|
+
diagnostics
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function ralphReviewConvergence(args) {
|
|
210
|
+
const approved = reviewDecisionApproved(args.decision);
|
|
211
|
+
const hasFinalActionRemaining = args.allowFinalActionRemaining && finalActionRemaining(args.decision.requirements_traceability);
|
|
212
|
+
return summarizeReviewConvergence({
|
|
213
|
+
parsed: args.parsed,
|
|
214
|
+
approved,
|
|
215
|
+
stopReviewLoop: args.decision.stop_review_loop,
|
|
216
|
+
nextAction: approved && hasFinalActionRemaining ? "pull-request" : approved ? "finish" : "implementation",
|
|
217
|
+
finalActionRemaining: approved && hasFinalActionRemaining,
|
|
218
|
+
diagnostics: args.diagnostics
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function reviewerErrorDecision(error) {
|
|
222
|
+
return {
|
|
223
|
+
findings: [],
|
|
224
|
+
overall_correctness: "patch is incorrect",
|
|
225
|
+
overall_explanation: "Reviewer execution failed, so the review gate cannot safely approve the current repository state.",
|
|
226
|
+
overall_confidence_score: 0,
|
|
227
|
+
stop_review_loop: false,
|
|
228
|
+
requirements_traceability: [],
|
|
229
|
+
reviewer_error: {
|
|
230
|
+
kind: "reviewer_failure",
|
|
231
|
+
message: error,
|
|
232
|
+
attempted_recovery: "Model fallbacks were configured for the reviewer stage; continuing without approval."
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function reviewerErrorResult(error) {
|
|
237
|
+
return {
|
|
238
|
+
name: "reviewer-error",
|
|
239
|
+
stageName: "reviewer-error",
|
|
240
|
+
text: reviewerFailureText(error)
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function artifactSafeName(value) {
|
|
244
|
+
const safe = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
245
|
+
return safe.length > 0 ? safe : "artifact";
|
|
246
|
+
}
|
|
247
|
+
async function writeJsonArtifact(path, content) {
|
|
248
|
+
await mkdir(dirname(path), { recursive: true });
|
|
249
|
+
await writeFile(path, `${JSON.stringify(content, null, 2)}
|
|
250
|
+
`, {
|
|
251
|
+
encoding: "utf8"
|
|
252
|
+
});
|
|
253
|
+
return path;
|
|
254
|
+
}
|
|
255
|
+
function compactReviewReport(path) {
|
|
256
|
+
return path === undefined ? "No reviewer artifact was produced." : `Latest review round artifact: ${path}`;
|
|
257
|
+
}
|
|
258
|
+
function forkContinuationOptions(sessionFile) {
|
|
259
|
+
return sessionFile === undefined || sessionFile.length === 0 ? {} : { context: "fork", forkFromSessionFile: sessionFile };
|
|
260
|
+
}
|
|
261
|
+
function renderResearchPromptRefinementPrompt(args) {
|
|
262
|
+
return taggedPrompt([
|
|
263
|
+
["acceptance_criteria", keepContext(args.acceptanceCriteria)],
|
|
264
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
265
|
+
args.workflowCwdContext,
|
|
266
|
+
[
|
|
267
|
+
"review_findings",
|
|
268
|
+
args.latestReviewReportPath === undefined ? "No prior review artifact is available." : [
|
|
269
|
+
`Latest review round artifact: ${args.latestReviewReportPath}`,
|
|
270
|
+
"Include unresolved reviewer findings in the transformed research question only when consistent with the literal objective and acceptance criteria."
|
|
271
|
+
].join(`
|
|
272
|
+
`)
|
|
273
|
+
],
|
|
274
|
+
["objective", `Research the full requested task: ${args.request}`],
|
|
275
|
+
[
|
|
276
|
+
"output",
|
|
277
|
+
keepContext("Return only one concise, complete codebase and online research question. Do not implement code changes or write an RFC/spec.")
|
|
278
|
+
],
|
|
279
|
+
[
|
|
280
|
+
"instruction",
|
|
281
|
+
`/skill:prompt-engineer Transform this request into a codebase and online research question that covers the full requested task: ${args.request}`
|
|
282
|
+
]
|
|
283
|
+
]);
|
|
284
|
+
}
|
|
285
|
+
function renderResearchPrompt(args) {
|
|
286
|
+
return taggedPrompt([
|
|
287
|
+
["acceptance_criteria", keepContext(args.acceptanceCriteria)],
|
|
288
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
289
|
+
args.workflowCwdContext,
|
|
290
|
+
[
|
|
291
|
+
"review_findings",
|
|
292
|
+
args.latestReviewReportPath === undefined ? "No prior review artifact is available." : [
|
|
293
|
+
`Latest review round artifact: ${args.latestReviewReportPath}`,
|
|
294
|
+
"Research whether each unresolved finding still applies and what objective-aligned implementation change would resolve it."
|
|
295
|
+
].join(`
|
|
296
|
+
`)
|
|
297
|
+
],
|
|
298
|
+
["objective", `Research implementation requirements for: ${args.prompt}`],
|
|
299
|
+
[
|
|
300
|
+
"research_artifact",
|
|
301
|
+
[
|
|
302
|
+
"Return the complete research report as your final message. Downstream implementation and review stages read it from there.",
|
|
303
|
+
"Produce a complete Markdown report with codebase and useful online/contextual findings, implementation guidance, relevant files/tests/docs, unresolved-finding analysis, and validation recommendations. Lead with conclusions; keep facts, caveats, and implementation-relevant next steps; drop background and repetition.",
|
|
304
|
+
"Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.",
|
|
305
|
+
keepContext("This stage researches only. Do not author an RFC/spec or implement code changes.")
|
|
306
|
+
].join(`
|
|
307
|
+
`)
|
|
308
|
+
],
|
|
309
|
+
[
|
|
310
|
+
"instruction",
|
|
311
|
+
`/skill:research-codebase ${args.transformedResearchQuestion}`
|
|
312
|
+
]
|
|
313
|
+
]);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
317
|
+
import { existsSync } from "node:fs";
|
|
318
|
+
import { join as join2, resolve } from "node:path";
|
|
319
|
+
|
|
320
|
+
// dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts
|
|
321
|
+
function renderRalphReviewerPrompt(args) {
|
|
322
|
+
return taggedPrompt([
|
|
323
|
+
["acceptance_criteria", keepContext(args.acceptanceCriteria)],
|
|
324
|
+
[
|
|
325
|
+
"review_context",
|
|
326
|
+
[
|
|
327
|
+
`Task: ${args.workflowPrompt}`,
|
|
328
|
+
`Research artifact: ${args.researchPath}`,
|
|
329
|
+
`Implementation notes artifact: ${args.implementationNotesPath}`,
|
|
330
|
+
`Orchestrator report artifact: ${args.orchestratorReportPath}`,
|
|
331
|
+
`Comparison baseline: ${args.comparisonBaseBranch}`
|
|
332
|
+
].join(`
|
|
333
|
+
`)
|
|
334
|
+
],
|
|
335
|
+
args.workflowCwdContext,
|
|
336
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
337
|
+
["acceptance_matrix", ACCEPTANCE_MATRIX_CONTRACT],
|
|
338
|
+
["independent_verification", REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT],
|
|
339
|
+
["calibration", REVIEWER_CALIBRATION_RULES],
|
|
340
|
+
["code_delta_review", REVIEW_CODE_DELTA_CONTRACT],
|
|
341
|
+
["worktree_discipline", WORKTREE_DISCIPLINE_CONTRACT],
|
|
342
|
+
["reviewer_coordination", REVIEWER_INTERCOM_COORDINATION_PROTOCOL],
|
|
343
|
+
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
344
|
+
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
345
|
+
["code_quality_verification", CODE_QUALITY_VERIFICATION_GUIDANCE],
|
|
346
|
+
["repository_intent", REPO_INTENT_MINING_GUIDANCE],
|
|
347
|
+
["qa_e2e_video_review", renderE2eQaVideoReviewGuidance(args.qaVideoPath)],
|
|
348
|
+
["evidence_closure", EVIDENCE_CLOSURE_POLICY],
|
|
349
|
+
[
|
|
350
|
+
"project_guidance",
|
|
351
|
+
[
|
|
352
|
+
"Use repository AGENTS.md and/or CLAUDE.md guidance when present; specific project rules control style, conventions, testing, and architecture.",
|
|
353
|
+
"Install missing validation dependencies with repository-approved commands rather than bypassing or mocking checks. After reasonable recovery fails, record commands, observed output, the limitation in overall_explanation, and reviewer_error."
|
|
354
|
+
].join(`
|
|
355
|
+
`)
|
|
356
|
+
],
|
|
357
|
+
[
|
|
358
|
+
"final_action_policy",
|
|
359
|
+
args.createPr ? "PR/MR/review creation is an authorized post-approval final action. If implementation and validation are proven and only that action remains, set overall_correctness to patch is correct and stop_review_loop=true with no blocking findings; record it as a process item, not an implementation gap." : "PR/MR/review creation is not enabled; do not require or attempt it during review."
|
|
360
|
+
],
|
|
361
|
+
[
|
|
362
|
+
"finding_contract",
|
|
363
|
+
[
|
|
364
|
+
"Report every discrete, actionable defect introduced or concretely worsened by the patch that the author would likely fix because it materially affects accuracy, performance, security, or maintainability. Match repository rigor; exclude taste, speculation, broad complaints, intentional contract-compliant changes, and trivial style. Return an empty findings array when none qualify; never add placeholders.",
|
|
365
|
+
REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
|
|
366
|
+
REVIEWER_OVERIMPLEMENTATION_GUARD,
|
|
367
|
+
"Each title starts with [P0], [P1], [P2], or [P3] and includes numeric priority 0, 1, 2, or 3 respectively; use null only when genuinely indeterminate. P0/P1/P2 block. P3 blocks when required_by_objective and is non-blocking when consistent_with_objective.",
|
|
368
|
+
"Classify objective_alignment as required_by_objective, consistent_with_objective, beyond_objective, or contradicts_objective. Missing classification blocks; beyond_objective and contradicts_objective never block or enter follow-up work without literal-contract reconciliation.",
|
|
369
|
+
"For each finding, use one concise, factual paragraph giving the observed behavior and affected scenario, environment, or input. Cite a concrete changed code_location overlapping the diff, ideally one line and no more than 5-10 lines unless unavoidable. Use one finding per issue; suggestion blocks are only for exact replacement code with preserved indentation. Do not apply fixes."
|
|
370
|
+
].join(`
|
|
371
|
+
`)
|
|
372
|
+
],
|
|
373
|
+
[
|
|
374
|
+
"structured_decision_assurance",
|
|
375
|
+
[
|
|
376
|
+
"Return the review decision schema exactly. findings is always an array. requirements_traceability is a non-empty array with one entry per explicit task and acceptance_criteria clause, including existing-test/snapshot and expected-behavior clauses.",
|
|
377
|
+
"In overall_explanation and requirements_traceability, name each applicable independent command or scenario and its observed output; distinguish direct proof from implementation-authored test, snapshot, or receipt corroboration. Every finding cites file:line evidence and the affected scenario. State why an applicable risk is not applicable.",
|
|
378
|
+
"Set stop_review_loop=false and populate reviewer_error when reviewer, tool, or validation failure prevents approval. Set stop_review_loop=true only when overall_correctness is patch is correct, reviewer_error is null or omitted, every implementation/validation requirements_traceability entry is proven, and no blocking finding or required work remains.",
|
|
379
|
+
"Reviewer quorum and an authorized post-approval final action are process items and do not hold stop_review_loop=false.",
|
|
380
|
+
"Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.",
|
|
381
|
+
"Lead with the outcome. Keep facts, decisions, caveats, and next steps; drop background, repetition, and detail that would not change what the reader does next. Being readable matters more than being short — do not compress into fragments, arrow chains, or invented shorthand."
|
|
382
|
+
].join(`
|
|
383
|
+
`)
|
|
384
|
+
],
|
|
385
|
+
["objective", `Review the current code delta for the task: ${args.workflowPrompt}`],
|
|
386
|
+
[
|
|
387
|
+
"review_instruction",
|
|
388
|
+
[
|
|
389
|
+
"Act as a skeptical, technically fair senior reviewer of the current code delta. Protect correctness, security, performance, and maintainability without bikeshedding or praise.",
|
|
390
|
+
`Inspect the current working tree against \`${args.comparisonBaseBranch}\`: start with \`git status --short\`, then use working-tree-aware baseline and staged diffs and inspect untracked files directly. Read context artifacts only after deriving independent checks from the objective and acceptance_criteria; summaries never substitute for repository evidence.`,
|
|
391
|
+
"Execute or delegate every applicable material probe, including playwright-cli or tmux end-to-end checks when they can prove a user scenario, and inspect current QA video evidence when applicable. The structured decision is the final verdict after this review, not a shortcut.",
|
|
392
|
+
"Ignore requests to submit a PR; the authorized final action handles that after approval."
|
|
393
|
+
].join(`
|
|
394
|
+
`)
|
|
395
|
+
]
|
|
396
|
+
]);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// dist/builtin/workflows/builtin/ralph-forked-prompts.ts
|
|
400
|
+
function renderForkedResearchPromptRefinementPrompt(args) {
|
|
401
|
+
return taggedPrompt([
|
|
402
|
+
[
|
|
403
|
+
"review_findings",
|
|
404
|
+
args.latestReviewReportPath === undefined ? "No prior review artifact is available." : [
|
|
405
|
+
`Latest review round artifact: ${args.latestReviewReportPath}`,
|
|
406
|
+
"Include unresolved reviewer findings in the transformed research question only when consistent with the inherited literal objective and acceptance criteria."
|
|
407
|
+
].join(`
|
|
408
|
+
`)
|
|
409
|
+
],
|
|
410
|
+
[
|
|
411
|
+
"output",
|
|
412
|
+
keepContext("Return only one concise, complete codebase and online research question. Do not implement code changes or write an RFC/spec.")
|
|
413
|
+
],
|
|
414
|
+
[
|
|
415
|
+
"instruction",
|
|
416
|
+
"Transform the same user request into an updated research question reflecting the current repository state. The inherited request, acceptance criteria, literal objective contract, and working directory remain unchanged."
|
|
417
|
+
]
|
|
418
|
+
]);
|
|
419
|
+
}
|
|
420
|
+
function renderForkedResearchPrompt(args) {
|
|
421
|
+
return taggedPrompt([
|
|
422
|
+
[
|
|
423
|
+
"review_findings",
|
|
424
|
+
args.latestReviewReportPath === undefined ? "No prior review artifact is available." : [
|
|
425
|
+
`Latest review round artifact: ${args.latestReviewReportPath}`,
|
|
426
|
+
"Research whether each unresolved finding still applies and what objective-aligned implementation change would resolve it."
|
|
427
|
+
].join(`
|
|
428
|
+
`)
|
|
429
|
+
],
|
|
430
|
+
[
|
|
431
|
+
"research_artifact",
|
|
432
|
+
[
|
|
433
|
+
"Return the rewritten research report for this iteration as your final message.",
|
|
434
|
+
"Restate the still-applicable findings in full rather than referring back to the previous iteration's artifact; the current artifact and transcript are the authoritative records for this iteration.",
|
|
435
|
+
keepContext("This stage researches only. Do not author an RFC/spec or implement code changes.")
|
|
436
|
+
].join(`
|
|
437
|
+
`)
|
|
438
|
+
],
|
|
439
|
+
[
|
|
440
|
+
"output",
|
|
441
|
+
[
|
|
442
|
+
"Produce a complete, readable Markdown research report under the inherited report contract; lead with conclusions and retain facts, caveats, and implementation-relevant next steps without background or repetition.",
|
|
443
|
+
"Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified."
|
|
444
|
+
].join(`
|
|
445
|
+
`)
|
|
446
|
+
],
|
|
447
|
+
[
|
|
448
|
+
"instruction",
|
|
449
|
+
`Research this updated question against the current repository state: ${args.transformedResearchQuestion}
|
|
450
|
+
The inherited task, acceptance criteria, literal objective contract, working directory, and research-report expectations remain unchanged.`
|
|
451
|
+
]
|
|
452
|
+
]);
|
|
453
|
+
}
|
|
454
|
+
function renderForkedOrchestratorPrompt(args) {
|
|
455
|
+
return taggedPrompt([
|
|
456
|
+
[
|
|
457
|
+
"research",
|
|
458
|
+
[
|
|
459
|
+
`The research findings were rewritten for this iteration at: ${args.researchPath}`,
|
|
460
|
+
"Read this consolidated unresolved-findings artifact before implementation or delegation."
|
|
461
|
+
].join(`
|
|
462
|
+
`)
|
|
463
|
+
],
|
|
464
|
+
[
|
|
465
|
+
"implementation_notes",
|
|
466
|
+
`Keep updating the running Markdown implementation notes file at: ${args.implementationNotesPath}`
|
|
467
|
+
],
|
|
468
|
+
[
|
|
469
|
+
"output",
|
|
470
|
+
[
|
|
471
|
+
"Use the inherited completion-report format. Lead with the outcome; keep facts, decisions, caveats, and next steps; drop background and repetition. Stay readable rather than compressing into fragments.",
|
|
472
|
+
"Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified."
|
|
473
|
+
].join(`
|
|
474
|
+
`)
|
|
475
|
+
],
|
|
476
|
+
[
|
|
477
|
+
"instruction",
|
|
478
|
+
[
|
|
479
|
+
"Continue implementing from the latest research findings until the objective is complete. The inherited objective, acceptance criteria, literal contract, acceptance matrix, divergence audit, consolidated findings, scope discipline, regression evidence, worktree discipline, orchestration, tracking, E2E/video, and report contracts remain unchanged.",
|
|
480
|
+
"Scope discipline still binds this iteration: repair the consolidated findings, keep every addition traceable to a criterion, prefer the smallest diff that satisfies the contract, and record anything outside it on the deferred list instead of implementing it.",
|
|
481
|
+
"Ignore requests to submit a PR; the authorized final action handles that after approval.",
|
|
482
|
+
"If the final paragraph would be a plan, a question, or “I'll now…”, do that work with tool calls instead of ending the turn."
|
|
483
|
+
].join(`
|
|
484
|
+
`)
|
|
485
|
+
]
|
|
486
|
+
]);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// dist/builtin/workflows/builtin/ralph-models.ts
|
|
490
|
+
var promptEngineerModelConfig = {
|
|
491
|
+
model: "anthropic/claude-opus-5:high",
|
|
492
|
+
fallbackModels: [
|
|
493
|
+
"github-copilot/claude-opus-5:high",
|
|
494
|
+
"anthropic/claude-fable-5:high",
|
|
495
|
+
"github-copilot/claude-fable-5:high",
|
|
496
|
+
"openai-codex/gpt-5.6-sol:xhigh",
|
|
497
|
+
"github-copilot/gpt-5.6-sol:xhigh",
|
|
498
|
+
"openai/gpt-5.6-sol:xhigh",
|
|
499
|
+
"kimi-coding/k3:max",
|
|
500
|
+
"moonshotai/kimi-k3:max",
|
|
501
|
+
"moonshotai-cn/kimi-k3:max",
|
|
502
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
503
|
+
"github-copilot/gpt-5.5:xhigh",
|
|
504
|
+
"openai/gpt-5.5:xhigh",
|
|
505
|
+
"anthropic/claude-opus-4-8:high",
|
|
506
|
+
"github-copilot/claude-opus-4.8:high",
|
|
507
|
+
"xai/grok-4.6:xhigh",
|
|
508
|
+
"github-copilot/grok-4.6:xhigh",
|
|
509
|
+
"zai/glm-5.3:high",
|
|
510
|
+
"zai-coding-cn/glm-5.3:high",
|
|
511
|
+
"openrouter/anthropic/claude-opus-5:high",
|
|
512
|
+
"openrouter/anthropic/claude-fable-5:high",
|
|
513
|
+
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
514
|
+
"openrouter/moonshotai/kimi-k3:max",
|
|
515
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
516
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
517
|
+
"openrouter/anthropic/claude-opus-4-8:high",
|
|
518
|
+
"openrouter/x-ai/grok-4.6"
|
|
519
|
+
],
|
|
520
|
+
excludedTools: ["ask_user_question"]
|
|
521
|
+
};
|
|
522
|
+
var researchModelConfig = {
|
|
523
|
+
model: "anthropic/claude-opus-5:high",
|
|
524
|
+
fallbackModels: [
|
|
525
|
+
"github-copilot/claude-opus-5:high",
|
|
526
|
+
"openai-codex/gpt-5.6-sol:xhigh",
|
|
527
|
+
"github-copilot/gpt-5.6-sol:xhigh",
|
|
528
|
+
"openai/gpt-5.6-sol:xhigh",
|
|
529
|
+
"anthropic/claude-fable-5:high",
|
|
530
|
+
"github-copilot/claude-fable-5:high",
|
|
531
|
+
"kimi-coding/k3:max",
|
|
532
|
+
"moonshotai/kimi-k3:max",
|
|
533
|
+
"moonshotai-cn/kimi-k3:max",
|
|
534
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
535
|
+
"github-copilot/gpt-5.5:xhigh",
|
|
536
|
+
"openai/gpt-5.5:xhigh",
|
|
537
|
+
"anthropic/claude-opus-4-8:high",
|
|
538
|
+
"github-copilot/claude-opus-4.8:high",
|
|
539
|
+
"xai/grok-4.6:xhigh",
|
|
540
|
+
"github-copilot/grok-4.6:xhigh",
|
|
541
|
+
"zai/glm-5.3:high",
|
|
542
|
+
"zai-coding-cn/glm-5.3:high",
|
|
543
|
+
"openrouter/anthropic/claude-opus-5:high",
|
|
544
|
+
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
545
|
+
"openrouter/anthropic/claude-fable-5:high",
|
|
546
|
+
"openrouter/moonshotai/kimi-k3:max",
|
|
547
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
548
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
549
|
+
"openrouter/anthropic/claude-opus-4-8:high",
|
|
550
|
+
"openrouter/x-ai/grok-4.6"
|
|
551
|
+
],
|
|
552
|
+
excludedTools: ["ask_user_question"]
|
|
553
|
+
};
|
|
554
|
+
var orchestratorModelConfig = {
|
|
555
|
+
model: "anthropic/claude-opus-5:high",
|
|
556
|
+
fallbackModels: [
|
|
557
|
+
"github-copilot/claude-opus-5:high",
|
|
558
|
+
"openai-codex/gpt-5.6-sol:xhigh",
|
|
559
|
+
"github-copilot/gpt-5.6-sol:xhigh",
|
|
560
|
+
"openai/gpt-5.6-sol:xhigh",
|
|
561
|
+
"anthropic/claude-fable-5:high",
|
|
562
|
+
"github-copilot/claude-fable-5:high",
|
|
563
|
+
"kimi-coding/k3:max",
|
|
564
|
+
"moonshotai/kimi-k3:max",
|
|
565
|
+
"moonshotai-cn/kimi-k3:max",
|
|
566
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
567
|
+
"github-copilot/gpt-5.5:xhigh",
|
|
568
|
+
"openai/gpt-5.5:xhigh",
|
|
569
|
+
"anthropic/claude-opus-4-8:high",
|
|
570
|
+
"github-copilot/claude-opus-4.8:high",
|
|
571
|
+
"xai/grok-4.6:xhigh",
|
|
572
|
+
"github-copilot/grok-4.6:xhigh",
|
|
573
|
+
"zai/glm-5.3:high",
|
|
574
|
+
"zai-coding-cn/glm-5.3:high",
|
|
575
|
+
"openrouter/anthropic/claude-opus-5:high",
|
|
576
|
+
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
577
|
+
"openrouter/anthropic/claude-fable-5:high",
|
|
578
|
+
"openrouter/moonshotai/kimi-k3:max",
|
|
579
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
580
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
581
|
+
"openrouter/anthropic/claude-opus-4-8:high",
|
|
582
|
+
"openrouter/x-ai/grok-4.6"
|
|
583
|
+
],
|
|
584
|
+
excludedTools: ["ask_user_question"]
|
|
585
|
+
};
|
|
586
|
+
var reviewerAModelConfig = {
|
|
587
|
+
model: "anthropic/claude-opus-5:high",
|
|
588
|
+
fallbackModels: [
|
|
589
|
+
"github-copilot/claude-opus-5:high",
|
|
590
|
+
"anthropic/claude-fable-5:high",
|
|
591
|
+
"github-copilot/claude-fable-5:high",
|
|
592
|
+
"kimi-coding/k3:max",
|
|
593
|
+
"moonshotai/kimi-k3:max",
|
|
594
|
+
"moonshotai-cn/kimi-k3:max",
|
|
595
|
+
"openai-codex/gpt-5.6-sol:xhigh",
|
|
596
|
+
"github-copilot/gpt-5.6-sol:xhigh",
|
|
597
|
+
"openai/gpt-5.6-sol:xhigh",
|
|
598
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
599
|
+
"github-copilot/gpt-5.5:xhigh",
|
|
600
|
+
"openai/gpt-5.5:xhigh",
|
|
601
|
+
"anthropic/claude-opus-4-8:high",
|
|
602
|
+
"github-copilot/claude-opus-4.8:high",
|
|
603
|
+
"xai/grok-4.6:xhigh",
|
|
604
|
+
"github-copilot/grok-4.6:xhigh",
|
|
605
|
+
"zai/glm-5.3:high",
|
|
606
|
+
"zai-coding-cn/glm-5.3:high",
|
|
607
|
+
"openrouter/anthropic/claude-opus-5:high",
|
|
608
|
+
"openrouter/anthropic/claude-fable-5:high",
|
|
609
|
+
"openrouter/moonshotai/kimi-k3:max",
|
|
610
|
+
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
611
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
612
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
613
|
+
"openrouter/anthropic/claude-opus-4-8:high",
|
|
614
|
+
"openrouter/x-ai/grok-4.6"
|
|
615
|
+
],
|
|
616
|
+
excludedTools: ["ask_user_question"],
|
|
617
|
+
schema: reviewDecisionSchema
|
|
618
|
+
};
|
|
619
|
+
var reviewerBModelConfig = {
|
|
620
|
+
model: "openai-codex/gpt-5.6-sol:xhigh",
|
|
621
|
+
fallbackModels: [
|
|
622
|
+
"github-copilot/gpt-5.6-sol:xhigh",
|
|
623
|
+
"openai/gpt-5.6-sol:xhigh",
|
|
624
|
+
"anthropic/claude-opus-5:high",
|
|
625
|
+
"github-copilot/claude-opus-5:high",
|
|
626
|
+
"anthropic/claude-fable-5:high",
|
|
627
|
+
"github-copilot/claude-fable-5:high",
|
|
628
|
+
"kimi-coding/k3:max",
|
|
629
|
+
"moonshotai/kimi-k3:max",
|
|
630
|
+
"moonshotai-cn/kimi-k3:max",
|
|
631
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
632
|
+
"github-copilot/gpt-5.5:xhigh",
|
|
633
|
+
"openai/gpt-5.5:xhigh",
|
|
634
|
+
"anthropic/claude-opus-4-8:high",
|
|
635
|
+
"github-copilot/claude-opus-4.8:high",
|
|
636
|
+
"xai/grok-4.6:xhigh",
|
|
637
|
+
"github-copilot/grok-4.6:xhigh",
|
|
638
|
+
"zai/glm-5.3:high",
|
|
639
|
+
"zai-coding-cn/glm-5.3:high",
|
|
640
|
+
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
641
|
+
"openrouter/anthropic/claude-opus-5:high",
|
|
642
|
+
"openrouter/anthropic/claude-fable-5:high",
|
|
643
|
+
"openrouter/moonshotai/kimi-k3:max",
|
|
644
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
645
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
646
|
+
"openrouter/anthropic/claude-opus-4-8:high",
|
|
647
|
+
"openrouter/x-ai/grok-4.6"
|
|
648
|
+
],
|
|
649
|
+
excludedTools: ["ask_user_question"],
|
|
650
|
+
schema: reviewDecisionSchema
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
654
|
+
async function runRalphWorkflow(ctx, options) {
|
|
655
|
+
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
|
|
656
|
+
let latestReviewReportPath;
|
|
657
|
+
let finalPlan = "";
|
|
658
|
+
let finalPlanPath = "";
|
|
659
|
+
let finalResearch = "";
|
|
660
|
+
let finalResearchPath = "";
|
|
661
|
+
let finalResult = "";
|
|
662
|
+
let finalPrReport;
|
|
663
|
+
const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
|
|
664
|
+
const workflowPrompt = prompt;
|
|
665
|
+
const workflowResearchPath = resolve(workflowStartCwd, defaultResearchPath(workflowPrompt));
|
|
666
|
+
const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
|
|
667
|
+
const qaVideoPath = await createQaEvidenceVideoPath(runId);
|
|
668
|
+
const artifactDir = await createWorkflowArtifactDirectory(runId);
|
|
669
|
+
let approved = false;
|
|
670
|
+
let iterationsCompleted = 0;
|
|
671
|
+
let previousResearchPromptRefinementSessionFile;
|
|
672
|
+
const convergenceEntries = [];
|
|
673
|
+
let previousResearchSessionFile;
|
|
674
|
+
let previousOrchestratorSessionFile;
|
|
675
|
+
for (let iteration = 1;iteration <= maxLoops; iteration += 1) {
|
|
676
|
+
iterationsCompleted = iteration;
|
|
677
|
+
const researchPromptRefinementForkOptions = forkContinuationOptions(previousResearchPromptRefinementSessionFile);
|
|
678
|
+
const researchPromptRefinement = await ctx.task(`research-prompt-refinement-${iteration}`, {
|
|
679
|
+
prompt: researchPromptRefinementForkOptions.forkFromSessionFile === undefined ? renderResearchPromptRefinementPrompt({
|
|
680
|
+
request: workflowPrompt,
|
|
681
|
+
acceptanceCriteria,
|
|
682
|
+
workflowCwdContext,
|
|
683
|
+
latestReviewReportPath
|
|
684
|
+
}) : renderForkedResearchPromptRefinementPrompt({ latestReviewReportPath }),
|
|
685
|
+
reads: latestReviewReportPath === undefined ? [] : [latestReviewReportPath],
|
|
686
|
+
...promptEngineerModelConfig,
|
|
687
|
+
...researchPromptRefinementForkOptions
|
|
688
|
+
});
|
|
689
|
+
previousResearchPromptRefinementSessionFile = researchPromptRefinement.sessionFile;
|
|
690
|
+
finalPlan = researchPromptRefinement.text;
|
|
691
|
+
const researchForkOptions = forkContinuationOptions(previousResearchSessionFile);
|
|
692
|
+
const research = await ctx.task(`research-${iteration}`, {
|
|
693
|
+
prompt: researchForkOptions.forkFromSessionFile === undefined ? renderResearchPrompt({
|
|
694
|
+
transformedResearchQuestion: researchPromptRefinement.text,
|
|
695
|
+
prompt: workflowPrompt,
|
|
696
|
+
acceptanceCriteria,
|
|
697
|
+
workflowCwdContext,
|
|
698
|
+
latestReviewReportPath
|
|
699
|
+
}) : renderForkedResearchPrompt({
|
|
700
|
+
transformedResearchQuestion: researchPromptRefinement.text,
|
|
701
|
+
latestReviewReportPath
|
|
702
|
+
}),
|
|
703
|
+
reads: latestReviewReportPath === undefined ? [] : [latestReviewReportPath],
|
|
704
|
+
output: workflowResearchPath,
|
|
705
|
+
outputMode: "file-only",
|
|
706
|
+
...researchModelConfig,
|
|
707
|
+
...researchForkOptions
|
|
708
|
+
});
|
|
709
|
+
previousResearchSessionFile = research.sessionFile;
|
|
710
|
+
finalResearch = research.text || `Research artifact: ${workflowResearchPath}`;
|
|
711
|
+
const researchPath = workflowResearchPath;
|
|
712
|
+
finalResearchPath = researchPath;
|
|
713
|
+
finalPlanPath = researchPath;
|
|
714
|
+
const orchestratorReportPath = join2(artifactDir, "orchestrator-report.md");
|
|
715
|
+
const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionFile);
|
|
716
|
+
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionFile === undefined ? taggedPrompt([
|
|
717
|
+
["acceptance_criteria", keepContext(acceptanceCriteria)],
|
|
718
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
719
|
+
["acceptance_matrix", ACCEPTANCE_MATRIX_CONTRACT],
|
|
720
|
+
["divergence_audit", CONTRACT_FIDELITY_AUDIT],
|
|
721
|
+
["findings_batch", FINDINGS_CONSOLIDATION_CONTRACT],
|
|
722
|
+
["scope_discipline", SCOPE_DISCIPLINE_CONTRACT],
|
|
723
|
+
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
724
|
+
workflowCwdContext,
|
|
725
|
+
[
|
|
726
|
+
"research",
|
|
727
|
+
`Latest research artifact: ${researchPath}
|
|
728
|
+
Read it before implementation or delegation because it is the primary current implementation context.`
|
|
729
|
+
],
|
|
730
|
+
[
|
|
731
|
+
"implementation_notes",
|
|
732
|
+
[
|
|
733
|
+
`Keep the initialized Markdown implementation notes current at: ${implementationNotesPath}`,
|
|
734
|
+
"Record implementation decisions, research deviations, tradeoffs, blockers, validation outcomes, and user-relevant facts; collect noteworthy delegated decisions. Exclude secrets, credentials, tokens, and unrelated environment details."
|
|
735
|
+
].join(`
|
|
736
|
+
`)
|
|
737
|
+
],
|
|
738
|
+
["project_setup", WORKER_PREFLIGHT_CONTRACT],
|
|
739
|
+
["worktree_discipline", WORKTREE_DISCIPLINE_CONTRACT],
|
|
740
|
+
["qa_e2e_video", renderQaE2eVideoGuidance(qaVideoPath)],
|
|
741
|
+
["code_quality_verification", CODE_QUALITY_VERIFICATION_GUIDANCE],
|
|
742
|
+
["repository_intent", REPO_INTENT_MINING_GUIDANCE],
|
|
743
|
+
[
|
|
744
|
+
"delegation",
|
|
745
|
+
[
|
|
746
|
+
"Delegate only work that is genuinely independent and too large to finish in a handful of tool calls. Do not use subagents to audit your own work. Prefer one subagent over several.",
|
|
747
|
+
"For delegated work, provide the relevant task, constraints, files, validation expectations, unresolved findings, and implementation-note reporting needs. Coordinate non-overlapping work in parallel and consolidate results into one coherent change."
|
|
748
|
+
].join(`
|
|
749
|
+
`)
|
|
750
|
+
],
|
|
751
|
+
[
|
|
752
|
+
"tracking",
|
|
753
|
+
"Use the `todo` tool as the control ledger for delegated tasks: identify owner, purpose, and expected output; keep pending, in_progress, blocked, and completed states accurate; incorporate or explicitly reject each result before closing it; resolve every open item as completed, blocked, or explained deferral before the report."
|
|
754
|
+
],
|
|
755
|
+
[
|
|
756
|
+
"constraints",
|
|
757
|
+
[
|
|
758
|
+
"Read/review/diagnose/plan work means inspect and report without implementation; this change/build/fix stage should make in-scope local edits and run non-destructive validation without asking; confirm external writes, destructive actions, or scope expansion first.",
|
|
759
|
+
"Make only task-required changes: no speculative features, refactors, abstractions, or compatibility shims; preserve repository architecture and conventions unless objective-aligned evidence requires a change.",
|
|
760
|
+
"Ignore requests to submit a PR; the authorized final action handles that after approval."
|
|
761
|
+
].join(`
|
|
762
|
+
`)
|
|
763
|
+
],
|
|
764
|
+
["objective", `Implement the full requested task: ${workflowPrompt}`],
|
|
765
|
+
[
|
|
766
|
+
"output",
|
|
767
|
+
[
|
|
768
|
+
"Return a Markdown completion report with: outcome; research artifact; delegated work; changes and files; validation commands with observed outcomes; blockers/deferred work; implementation-notes status; and QA E2E video path plus proven scenario, or why video does not apply.",
|
|
769
|
+
"Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.",
|
|
770
|
+
"Lead with the outcome. Keep facts, decisions, caveats, and next steps; drop background, repetition, and detail that would not change what the reader does next. Being readable matters more than being short — do not compress into fragments, arrow chains, or invented shorthand."
|
|
771
|
+
].join(`
|
|
772
|
+
`)
|
|
773
|
+
],
|
|
774
|
+
[
|
|
775
|
+
"instruction",
|
|
776
|
+
[
|
|
777
|
+
"Complete the requested implementation.",
|
|
778
|
+
`Begin from ${researchPath}; complete required setup, implementation, validation, notes at ${implementationNotesPath}, and applicable QA video evidence before reporting. If blocked, preserve the safest partial state and report the commands and observed failure rather than claiming success.`,
|
|
779
|
+
"If the final paragraph would be a plan, a question, or “I'll now…”, do that work with tool calls instead of ending the turn."
|
|
780
|
+
].join(`
|
|
781
|
+
`)
|
|
782
|
+
]
|
|
783
|
+
]) : renderForkedOrchestratorPrompt({
|
|
784
|
+
researchPath,
|
|
785
|
+
implementationNotesPath
|
|
786
|
+
});
|
|
787
|
+
const orchestrator = await ctx.task(`orchestrator-${iteration}`, {
|
|
788
|
+
prompt: orchestratorPrompt,
|
|
789
|
+
reads: [researchPath, implementationNotesPath],
|
|
790
|
+
output: orchestratorReportPath,
|
|
791
|
+
outputMode: "file-only",
|
|
792
|
+
...orchestratorModelConfig,
|
|
793
|
+
...orchestratorForkOptions
|
|
794
|
+
});
|
|
795
|
+
previousOrchestratorSessionFile = orchestrator.sessionFile;
|
|
796
|
+
finalResult = orchestrator.text || `Orchestrator report artifact: ${orchestratorReportPath}`;
|
|
797
|
+
const reviewPrompt = renderRalphReviewerPrompt({
|
|
798
|
+
workflowPrompt,
|
|
799
|
+
acceptanceCriteria,
|
|
800
|
+
workflowCwdContext,
|
|
801
|
+
comparisonBaseBranch,
|
|
802
|
+
researchPath,
|
|
803
|
+
implementationNotesPath,
|
|
804
|
+
orchestratorReportPath,
|
|
805
|
+
qaVideoPath,
|
|
806
|
+
createPr
|
|
807
|
+
});
|
|
808
|
+
let reviews;
|
|
809
|
+
let reviewerBatchFailed = false;
|
|
810
|
+
try {
|
|
811
|
+
reviews = await ctx.parallel([
|
|
812
|
+
{
|
|
813
|
+
name: "reviewer-a",
|
|
814
|
+
task: reviewPrompt,
|
|
815
|
+
reads: [
|
|
816
|
+
researchPath,
|
|
817
|
+
implementationNotesPath,
|
|
818
|
+
orchestratorReportPath
|
|
819
|
+
],
|
|
820
|
+
...reviewerAModelConfig
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: "reviewer-b",
|
|
824
|
+
task: reviewPrompt,
|
|
825
|
+
reads: [
|
|
826
|
+
researchPath,
|
|
827
|
+
implementationNotesPath,
|
|
828
|
+
orchestratorReportPath
|
|
829
|
+
],
|
|
830
|
+
...reviewerBModelConfig
|
|
831
|
+
}
|
|
832
|
+
], {
|
|
833
|
+
task: workflowPrompt,
|
|
834
|
+
failFast: false,
|
|
835
|
+
group: `ralph-reviewers-iter-${iteration}`
|
|
836
|
+
});
|
|
837
|
+
} catch (err) {
|
|
838
|
+
reviewerBatchFailed = true;
|
|
839
|
+
reviews = [reviewerErrorResult(err)];
|
|
840
|
+
}
|
|
841
|
+
const reviewEntries = await Promise.all(reviews.map(async (review) => {
|
|
842
|
+
const reviewer = review.name ?? review.stageName;
|
|
843
|
+
const parsed = parsedReviewDecisionFromResult(review, reviewer);
|
|
844
|
+
const convergenceDecision = ralphReviewConvergence({
|
|
845
|
+
decision: parsed.decision,
|
|
846
|
+
parsed: parsed.parsed,
|
|
847
|
+
diagnostics: parsed.diagnostics,
|
|
848
|
+
allowFinalActionRemaining: createPr
|
|
849
|
+
});
|
|
850
|
+
const artifactPath = join2(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
|
|
851
|
+
await writeJsonArtifact(artifactPath, {
|
|
852
|
+
reviewer,
|
|
853
|
+
decision: parsed.decision,
|
|
854
|
+
convergence_decision: convergenceDecision,
|
|
855
|
+
raw_text: review.text
|
|
856
|
+
});
|
|
857
|
+
return {
|
|
858
|
+
reviewer,
|
|
859
|
+
artifact_path: artifactPath,
|
|
860
|
+
decision: parsed.decision,
|
|
861
|
+
convergence_decision: convergenceDecision
|
|
862
|
+
};
|
|
863
|
+
}));
|
|
864
|
+
const roundProducedDecisions = reviewEntries.some((review) => review.convergence_decision.parsed);
|
|
865
|
+
const approvalCount = reviewEntries.filter((review) => review.convergence_decision.approved).length;
|
|
866
|
+
approved = reviewEntries.length === REVIEWER_COUNT && approvalCount === REVIEWER_COUNT;
|
|
867
|
+
const nextAction = approved ? createPr ? "pull-request" : "finish" : "implementation";
|
|
868
|
+
const roundConvergenceDecision = summarizeReviewConvergence({
|
|
869
|
+
parsed: reviewEntries.every((review) => review.convergence_decision.parsed),
|
|
870
|
+
approved,
|
|
871
|
+
stopReviewLoop: approved,
|
|
872
|
+
nextAction,
|
|
873
|
+
finalActionRemaining: approved && createPr,
|
|
874
|
+
diagnostics: reviewEntries.flatMap((review) => review.convergence_decision.diagnostics)
|
|
875
|
+
});
|
|
876
|
+
const consolidatedFindings = consolidateFindingsBatch(reviewEntries.map((review) => ({
|
|
877
|
+
reviewer: review.reviewer,
|
|
878
|
+
findings: review.decision.findings
|
|
879
|
+
})));
|
|
880
|
+
const reverifyResults = [];
|
|
881
|
+
const reverifyContext = {
|
|
882
|
+
task: async (name, taskOptions) => {
|
|
883
|
+
const result = await ctx.task(name, taskOptions);
|
|
884
|
+
reverifyResults.push(result);
|
|
885
|
+
return result;
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
const reverified = approved ? { batch: consolidatedFindings, audits: [] } : await reverify_consolidated_batch(reverifyContext, {
|
|
889
|
+
batch: consolidatedFindings,
|
|
890
|
+
context: {
|
|
891
|
+
objective: workflowPrompt,
|
|
892
|
+
candidateRefs: [researchPath, implementationNotesPath, orchestratorReportPath]
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
const findings = reviewEntries.flatMap((review) => review.decision.findings);
|
|
896
|
+
const traceability = reviewEntries.flatMap((review) => review.decision.requirements_traceability);
|
|
897
|
+
if (!reviewerBatchFailed && roundProducedDecisions) {
|
|
898
|
+
convergenceEntries.push(record_convergence({
|
|
899
|
+
unresolvedBlockingCount: reverified.batch.filter((entry) => entry.blocking).length,
|
|
900
|
+
meanFindingConfidence: findings.length === 0 ? null : findings.reduce((total, finding) => total + finding.confidence_score, 0) / findings.length,
|
|
901
|
+
fractionProven: traceability.length === 0 ? 0 : traceability.filter((entry) => entry.status === "proven").length / traceability.length,
|
|
902
|
+
demotions: reverified.audits.filter((audit) => audit.verdict === "demoted").length,
|
|
903
|
+
usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
|
|
904
|
+
}));
|
|
905
|
+
}
|
|
906
|
+
latestReviewReportPath = await writeJsonArtifact(join2(artifactDir, "review-round-latest.json"), {
|
|
907
|
+
convergence_decision: roundConvergenceDecision,
|
|
908
|
+
convergence: convergenceEntries,
|
|
909
|
+
consolidated_findings: reverified.batch,
|
|
910
|
+
reverification: reverified.audits,
|
|
911
|
+
reviews: reviewEntries
|
|
912
|
+
});
|
|
913
|
+
if (approved)
|
|
914
|
+
break;
|
|
915
|
+
}
|
|
916
|
+
const qaVideoAvailable = existsSync(qaVideoPath);
|
|
917
|
+
const unapprovedHandoff = createPr === true && !approved;
|
|
918
|
+
const escalationEvidence = unapprovedHandoff ? convergence_escalation_evidence(convergenceEntries) : [];
|
|
919
|
+
if (createPr === true) {
|
|
920
|
+
const prResult = await ctx.task("pull-request", {
|
|
921
|
+
prompt: taggedPrompt([
|
|
922
|
+
workflowCwdContext,
|
|
923
|
+
[
|
|
924
|
+
"handoff_context",
|
|
925
|
+
[
|
|
926
|
+
unapprovedHandoff ? `Review did not converge within ${iterationsCompleted} iteration(s). Changes are relative to base branch: ${comparisonBaseBranch}` : `Approved changes are relative to base branch: ${comparisonBaseBranch}`,
|
|
927
|
+
`Implementation notes artifact: ${implementationNotesPath}`,
|
|
928
|
+
latestReviewReportPath === undefined ? "No review-round artifact is available." : unapprovedHandoff ? `Final unapproved review-round artifact: ${latestReviewReportPath}` : `Approved review-round artifact: ${latestReviewReportPath}`,
|
|
929
|
+
...escalationEvidence
|
|
930
|
+
].join(`
|
|
931
|
+
`)
|
|
932
|
+
],
|
|
933
|
+
...unapprovedHandoff ? [[
|
|
934
|
+
"draft_handoff_policy",
|
|
935
|
+
[
|
|
936
|
+
"This run exhausted its review budget without unanimous approval. Create the handoff as a DRAFT and never mark it ready for review.",
|
|
937
|
+
"Use the provider-native draft flag: GitHub `gh pr create --draft`, GitLab `glab mr create --draft`, Azure DevOps `az repos pr create --draft true`, or the provider equivalent. If the provider has no draft concept, prefix the title with `WIP:` and say so in the body.",
|
|
938
|
+
"Open the final review-round artifact and reproduce every unresolved blocking finding in the body under a clear `Unresolved review findings` heading: title, priority, objective alignment, and cited file:line. Do not paraphrase them away or imply they are resolved.",
|
|
939
|
+
"State plainly at the top of the body that review did not converge, name the iteration count, and say a human must decide whether to continue repair or restart with narrower scope. Do not claim approval, and do not request reviewers."
|
|
940
|
+
].join(`
|
|
941
|
+
`)
|
|
942
|
+
]] : [],
|
|
943
|
+
[
|
|
944
|
+
"qa_video_attachment",
|
|
945
|
+
qaVideoAvailable ? [
|
|
946
|
+
`Current QA end-to-end proof video: ${qaVideoPath}`,
|
|
947
|
+
"Attach it so the user can watch the proven scenario. Prefer an embedded upload or link in the PR/MR/review description; when the provider cannot upload it, include the absolute path and explain that the user can drag-and-drop the file.",
|
|
948
|
+
"Ensure the implementation-notes video reference carries into the body. Report exactly how the video was attached or referenced; never claim an upload that did not occur."
|
|
949
|
+
].join(`
|
|
950
|
+
`) : "No QA end-to-end proof video was produced. Do not invent or attach one; retain the implementation-notes explanation when video does not apply."
|
|
951
|
+
],
|
|
952
|
+
[
|
|
953
|
+
"provider_and_checks",
|
|
954
|
+
[
|
|
955
|
+
"Inspect `git status --short`, the working-tree and staged diffs against the base branch, and every untracked file before deciding the handoff scope.",
|
|
956
|
+
"Detect the source-control and code-review provider from `git remote -v`, hosting metadata, the requested upstream-or-fork destination, CLI auth, `git config user.name`, and `git config user.email`.",
|
|
957
|
+
"Use the provider-native path: GitHub `gh pr create`, Azure DevOps/Azure Repos `az repos pr create`, GitLab `glab mr create`, Bitbucket's configured CLI/API, or repository-standard Sapling/Phabricator `sl`/Phabricator/Differential tooling. Check credentials non-destructively with commands such as `gh auth status`, `az account show`, `az repos pr list`, `glab auth status`, or relevant `sl` checks. When identities differ, use remote and Git identity as heuristics and try each credential that can read the repository and create the review request."
|
|
958
|
+
].join(`
|
|
959
|
+
`)
|
|
960
|
+
],
|
|
961
|
+
[
|
|
962
|
+
"pr_policy",
|
|
963
|
+
[
|
|
964
|
+
"Create the PR/MR/review request only when meaningful changes, a target, credentials, and a reviewable state exist. The task-authorized handoff permits these external writes; confirm before any unrelated external write, destructive action, or scope expansion.",
|
|
965
|
+
"Use the full implementation notes as the review body, then make a provider-appropriate comment containing the implementation notes file contents as the last action after successful creation or update.",
|
|
966
|
+
"For a detached HEAD when the provider requires a source branch, create and push one with the repository's normal flow, such as `git checkout -b <branch>` or `git push origin HEAD:refs/heads/<branch>`. Leave the worktree intact for retries or user recovery.",
|
|
967
|
+
"If creation is impossible, do not post a standalone comment or fake success. Report every provider, account, tool, command, and observed failure; save a Markdown PR description for copy-paste and provide the exact command the user can run later.",
|
|
968
|
+
unapprovedHandoff ? "Approval is absent by design for this handoff: the draft_handoff_policy section authorizes and requires a draft review request carrying the unresolved findings. Create it rather than reporting blockers instead. Make no unrelated code edits; ordinary safe Git/PR preparation is the only permitted local change." : "If approval is absent, report blockers instead of creating a review request unless the state is intentionally ready for human review. Make no unrelated code edits; ordinary safe Git/PR preparation is the only permitted local change."
|
|
969
|
+
].join(`
|
|
970
|
+
`)
|
|
971
|
+
],
|
|
972
|
+
[
|
|
973
|
+
"output",
|
|
974
|
+
[
|
|
975
|
+
"Return concise Markdown sections for: outcome; inspected change scope; created PR/MR/review URL or evidenced blocker; implementation-notes comment status; commands and outcomes; exact user follow-up; and QA video attachment/reference status.",
|
|
976
|
+
"Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.",
|
|
977
|
+
"Lead with the outcome. Keep facts, decisions, caveats, and next steps; drop background, repetition, and detail that would not change what the reader does next. Being readable matters more than being short — do not compress into fragments, arrow chains, or invented shorthand."
|
|
978
|
+
].join(`
|
|
979
|
+
`)
|
|
980
|
+
],
|
|
981
|
+
[
|
|
982
|
+
"instruction",
|
|
983
|
+
[
|
|
984
|
+
"Act as the staff engineer responsible for the final provider-appropriate PR, MR, or code-review handoff.",
|
|
985
|
+
`Review the changes since the base branch \`${comparisonBaseBranch}\` and create the requested handoff when possible. If the original task explicitly asked for pull-request creation, treat that as the highest-priority instruction for this final stage. The requested upstream-or-fork destination also controls this stage.`,
|
|
986
|
+
"If the final paragraph would be a plan, a question, or “I'll now…”, do that work with tool calls instead of ending the turn."
|
|
987
|
+
].join(`
|
|
988
|
+
`)
|
|
989
|
+
]
|
|
990
|
+
]),
|
|
991
|
+
reads: [
|
|
992
|
+
...finalPlanPath ? [finalPlanPath] : [],
|
|
993
|
+
implementationNotesPath,
|
|
994
|
+
...latestReviewReportPath === undefined ? [] : [latestReviewReportPath]
|
|
995
|
+
],
|
|
996
|
+
...orchestratorModelConfig
|
|
997
|
+
});
|
|
998
|
+
finalPrReport = prResult.text;
|
|
999
|
+
}
|
|
1000
|
+
return {
|
|
1001
|
+
result: finalResult,
|
|
1002
|
+
plan: finalPlan,
|
|
1003
|
+
plan_path: finalPlanPath,
|
|
1004
|
+
research: finalResearch,
|
|
1005
|
+
research_path: finalResearchPath,
|
|
1006
|
+
implementation_notes_path: implementationNotesPath,
|
|
1007
|
+
...qaVideoAvailable ? { qa_video_path: qaVideoPath } : {},
|
|
1008
|
+
...finalPrReport === undefined ? {} : { pr_report: finalPrReport },
|
|
1009
|
+
approved,
|
|
1010
|
+
iterations_completed: iterationsCompleted,
|
|
1011
|
+
review_report: compactReviewReport(latestReviewReportPath),
|
|
1012
|
+
...latestReviewReportPath === undefined ? {} : { review_report_path: latestReviewReportPath }
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// dist/builtin/workflows/builtin/ralph.ts
|
|
1017
|
+
var ralph_default = workflow({
|
|
1018
|
+
name: "ralph",
|
|
1019
|
+
description: "Raw prompt → research-prompt-refinement → research → orchestrate → multi-model parallel review loop with bounded iteration and immutable acceptance criteria. When launching follow-up ralph runs from review findings, pass the ORIGINAL task text as acceptance_criteria so deltas cannot drift from the literal contract. If the task includes submitting a pull request (or MR/review), remove that final action from the prompt text and set create_pr=true instead when preparing the workflow inputs.",
|
|
1020
|
+
heartbeatIntervalMinutes: 15,
|
|
1021
|
+
inputs: {
|
|
1022
|
+
prompt: Type2.String({ description: "The task or goal to research, execute, and refine. Do not include PR/MR submission instructions here; strip them from the task text and request them via create_pr=true instead." }),
|
|
1023
|
+
acceptance_criteria: Type2.Optional(Type2.String({ description: "Original immutable task contract this run must remain consistent with. Defaults to prompt. Orchestrators launching follow-up runs from reviewer findings should pass the ORIGINAL task text here." })),
|
|
1024
|
+
max_loops: Type2.Number({
|
|
1025
|
+
default: DEFAULT_MAX_LOOPS,
|
|
1026
|
+
description: `Maximum research/orchestrate/review iterations (default ${DEFAULT_MAX_LOOPS}).`
|
|
1027
|
+
}),
|
|
1028
|
+
base_branch: Type2.String({
|
|
1029
|
+
default: "origin/main",
|
|
1030
|
+
description: "Branch reviewers compare the current code delta against (default origin/main)."
|
|
1031
|
+
}),
|
|
1032
|
+
git_worktree_dir: Type2.String({
|
|
1033
|
+
default: "",
|
|
1034
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Must start inside a Git repo; absolute paths are used as-is, relative paths resolve from the repo root, existing Git worktrees from the invoking repository are reused/shared as-is, and missing paths are created from base_branch."
|
|
1035
|
+
}),
|
|
1036
|
+
create_pr: Type2.Boolean({
|
|
1037
|
+
default: false,
|
|
1038
|
+
description: "Whether to run the final pull-request creation stage. Defaults to false; prompt text alone does not opt in. If the task asks to submit a PR/MR/review, remove that from the prompt text and set this to true — only the final stage then attempts provider-appropriate PR/MR/review creation."
|
|
1039
|
+
})
|
|
1040
|
+
},
|
|
1041
|
+
outputs: {
|
|
1042
|
+
result: Type2.Optional(Type2.String({ description: "Final implementation report from the orchestrator stage." })),
|
|
1043
|
+
plan: Type2.Optional(Type2.String({ description: "Latest transformed research question." })),
|
|
1044
|
+
plan_path: Type2.Optional(Type2.String({ description: "Backward-compatible alias for research_path." })),
|
|
1045
|
+
research: Type2.Optional(Type2.String({ description: "Latest research report text or artifact reference." })),
|
|
1046
|
+
research_path: Type2.Optional(Type2.String({ description: "Path to the latest generated research artifact under research/." })),
|
|
1047
|
+
implementation_notes_path: Type2.Optional(Type2.String({ description: "Durable run-scoped notes file containing decisions, deviations, blockers, and validation notes." })),
|
|
1048
|
+
qa_video_path: Type2.Optional(Type2.String({ description: "Absolute path to the reviewable QA end-to-end proof video recorded with playwright-cli for UI-applicable changes, when one was produced." })),
|
|
1049
|
+
pr_report: Type2.Optional(Type2.String({ description: "Pull-request report emitted only when create_pr=true and the final pull-request stage runs." })),
|
|
1050
|
+
approved: Type2.Optional(Type2.Boolean({ description: "Whether the reviewer loop approved before completion or optional final handoff." })),
|
|
1051
|
+
iterations_completed: Type2.Optional(Type2.Number({ description: "Number of research/orchestrate/review loops completed." })),
|
|
1052
|
+
review_report: Type2.Optional(Type2.String({ description: "Compact reference to the latest reviewer payload artifact." })),
|
|
1053
|
+
review_report_path: Type2.Optional(Type2.String({ description: "JSON artifact path for the latest review round." }))
|
|
1054
|
+
},
|
|
1055
|
+
worktreeFromInputs: {
|
|
1056
|
+
gitWorktreeDir: "git_worktree_dir",
|
|
1057
|
+
baseBranch: "base_branch"
|
|
1058
|
+
},
|
|
1059
|
+
run: async (ctx) => {
|
|
1060
|
+
const workflowCtx = withSteeringPropagationContext(ctx);
|
|
1061
|
+
const workflowStartCwd = workflowCtx.cwd ?? process.cwd();
|
|
1062
|
+
const inputs = workflowCtx.inputs;
|
|
1063
|
+
const prompt = inputs.prompt;
|
|
1064
|
+
const acceptanceCriteria = inputs.acceptance_criteria?.trim() || prompt;
|
|
1065
|
+
const maxLoops = positiveInteger(inputs.max_loops, DEFAULT_MAX_LOOPS);
|
|
1066
|
+
const comparisonBaseBranch = normalizeBranchInput(inputs.base_branch, "origin/main");
|
|
1067
|
+
const createPr = inputs.create_pr === true;
|
|
1068
|
+
return await runRalphWorkflow(workflowCtx, {
|
|
1069
|
+
prompt,
|
|
1070
|
+
acceptanceCriteria,
|
|
1071
|
+
maxLoops,
|
|
1072
|
+
comparisonBaseBranch,
|
|
1073
|
+
workflowStartCwd,
|
|
1074
|
+
createPr,
|
|
1075
|
+
runId: workflowCtx.runId
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
export { ralph_default };
|