@exaudeus/workrail 3.75.0 → 3.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/console-ui/assets/index-D9pYbwS0.js +28 -0
- package/dist/console-ui/index.html +1 -1
- package/dist/coordinators/adaptive-pipeline.d.ts +8 -0
- package/dist/coordinators/context-assembly.d.ts +4 -0
- package/dist/coordinators/context-assembly.js +156 -0
- package/dist/coordinators/modes/full-pipeline.d.ts +1 -1
- package/dist/coordinators/modes/full-pipeline.js +140 -27
- package/dist/coordinators/modes/implement-shared.d.ts +3 -2
- package/dist/coordinators/modes/implement-shared.js +16 -6
- package/dist/coordinators/modes/implement.js +49 -3
- package/dist/coordinators/pipeline-run-context.d.ts +1811 -0
- package/dist/coordinators/pipeline-run-context.js +114 -0
- package/dist/daemon/context-loader.d.ts +1 -1
- package/dist/daemon/core/agent-client.d.ts +7 -0
- package/dist/daemon/core/agent-client.js +31 -0
- package/dist/daemon/core/index.d.ts +6 -0
- package/dist/daemon/core/index.js +19 -0
- package/dist/daemon/core/session-context.d.ts +14 -0
- package/dist/daemon/core/session-context.js +24 -0
- package/dist/daemon/core/session-result.d.ts +10 -0
- package/dist/daemon/core/session-result.js +92 -0
- package/dist/daemon/core/system-prompt.d.ts +6 -0
- package/dist/daemon/core/system-prompt.js +151 -0
- package/dist/daemon/io/conversation-log.d.ts +2 -0
- package/dist/daemon/io/conversation-log.js +45 -0
- package/dist/daemon/io/execution-stats.d.ts +7 -0
- package/dist/daemon/io/execution-stats.js +86 -0
- package/dist/daemon/io/index.d.ts +5 -0
- package/dist/daemon/io/index.js +24 -0
- package/dist/daemon/io/session-notes-loader.d.ts +4 -0
- package/dist/daemon/io/session-notes-loader.js +45 -0
- package/dist/daemon/io/soul-loader.d.ts +3 -0
- package/dist/daemon/io/soul-loader.js +68 -0
- package/dist/daemon/io/workspace-context-loader.d.ts +17 -0
- package/dist/daemon/io/workspace-context-loader.js +137 -0
- package/dist/daemon/runner/agent-loop-runner.d.ts +28 -0
- package/dist/daemon/runner/agent-loop-runner.js +250 -0
- package/dist/daemon/runner/construct-tools.d.ts +5 -0
- package/dist/daemon/runner/construct-tools.js +30 -0
- package/dist/daemon/runner/finalize-session.d.ts +3 -0
- package/dist/daemon/runner/finalize-session.js +75 -0
- package/dist/daemon/runner/index.d.ts +8 -0
- package/dist/daemon/runner/index.js +18 -0
- package/dist/daemon/runner/pre-agent-session.d.ts +7 -0
- package/dist/daemon/runner/pre-agent-session.js +227 -0
- package/dist/daemon/runner/runner-types.d.ts +73 -0
- package/dist/daemon/runner/runner-types.js +39 -0
- package/dist/daemon/runner/tool-schemas.d.ts +1 -0
- package/dist/daemon/runner/tool-schemas.js +151 -0
- package/dist/daemon/session-scope.d.ts +1 -1
- package/dist/daemon/startup-recovery.d.ts +20 -0
- package/dist/daemon/startup-recovery.js +323 -0
- package/dist/daemon/state/index.d.ts +6 -0
- package/dist/daemon/state/index.js +14 -0
- package/dist/daemon/state/session-state.d.ts +23 -0
- package/dist/daemon/state/session-state.js +44 -0
- package/dist/daemon/state/stuck-detection.d.ts +22 -0
- package/dist/daemon/state/stuck-detection.js +25 -0
- package/dist/daemon/state/terminal-signal.d.ts +9 -0
- package/dist/daemon/state/terminal-signal.js +10 -0
- package/dist/daemon/tools/file-tools.d.ts +1 -1
- package/dist/daemon/turn-end/detect-stuck.d.ts +2 -2
- package/dist/daemon/turn-end/detect-stuck.js +2 -2
- package/dist/daemon/turn-end/step-injector.d.ts +1 -1
- package/dist/daemon/types.d.ts +105 -0
- package/dist/daemon/types.js +11 -0
- package/dist/daemon/workflow-enricher.d.ts +16 -0
- package/dist/daemon/workflow-enricher.js +58 -0
- package/dist/daemon/workflow-runner.d.ts +13 -277
- package/dist/daemon/workflow-runner.js +63 -1421
- package/dist/manifest.json +280 -56
- package/dist/trigger/coordinator-deps.d.ts +1 -1
- package/dist/trigger/coordinator-deps.js +131 -0
- package/dist/trigger/delivery-client.d.ts +1 -1
- package/dist/trigger/delivery-pipeline.d.ts +1 -1
- package/dist/trigger/notification-service.d.ts +1 -1
- package/dist/trigger/trigger-listener.js +6 -2
- package/dist/trigger/trigger-router.d.ts +2 -2
- package/dist/v2/durable-core/domain/artifact-contract-validator.js +99 -0
- package/dist/v2/durable-core/schemas/artifacts/discovery-handoff.d.ts +39 -0
- package/dist/v2/durable-core/schemas/artifacts/discovery-handoff.js +10 -1
- package/dist/v2/durable-core/schemas/artifacts/index.d.ts +2 -1
- package/dist/v2/durable-core/schemas/artifacts/index.js +12 -1
- package/dist/v2/durable-core/schemas/artifacts/phase-handoff.d.ts +89 -0
- package/dist/v2/durable-core/schemas/artifacts/phase-handoff.js +56 -0
- package/docs/authoring-v2.md +12 -0
- package/docs/ideas/backlog.md +639 -25
- package/docs/reference/worktrain-daemon-invariants.md +33 -49
- package/docs/vision.md +5 -15
- package/package.json +2 -2
- package/workflows/coding-task-workflow-agentic.json +9 -6
- package/workflows/mr-review-workflow.agentic.v2.json +2 -2
- package/workflows/wr.discovery.json +2 -1
- package/workflows/wr.shaping.json +7 -4
- package/dist/console-ui/assets/index-BvBihscd.js +0 -28
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>WorkRail Console</title>
|
|
7
|
-
<script type="module" crossorigin src="/console/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/console/assets/index-D9pYbwS0.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/console/assets/index-DHrKiMCf.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { Result } from 'neverthrow';
|
|
1
2
|
import type { CoordinatorDeps } from './pr-review.js';
|
|
3
|
+
import type { PipelineRunContext, PhaseRecord } from './pipeline-run-context.js';
|
|
2
4
|
export declare const DISCOVERY_TIMEOUT_MS: number;
|
|
3
5
|
export declare const SHAPING_TIMEOUT_MS: number;
|
|
4
6
|
export declare const CODING_TIMEOUT_MS: number;
|
|
@@ -33,6 +35,12 @@ export interface AdaptiveCoordinatorDeps extends CoordinatorDeps {
|
|
|
33
35
|
pollForPR(branchPattern: string, timeoutMs: number): Promise<string | null>;
|
|
34
36
|
postToOutbox(message: string, metadata: Readonly<Record<string, unknown>>): Promise<void>;
|
|
35
37
|
pollOutboxAck(requestId: string, timeoutMs: number): Promise<'acked' | 'timeout'>;
|
|
38
|
+
generateRunId(): string;
|
|
39
|
+
readActiveRunId(workspace: string): Promise<Result<string | null, string>>;
|
|
40
|
+
readPipelineContext(workspace: string, runId: string): Promise<Result<PipelineRunContext | null, string>>;
|
|
41
|
+
createPipelineContext(workspace: string, runId: string, goal: string, pipelineMode: PipelineRunContext['pipelineMode']): Promise<Result<void, string>>;
|
|
42
|
+
markPipelineRunComplete(workspace: string, runId: string): Promise<Result<void, string>>;
|
|
43
|
+
writePhaseRecord(workspace: string, runId: string, entry: PhaseRecord): Promise<Result<void, string>>;
|
|
36
44
|
}
|
|
37
45
|
export interface ModeExecutors {
|
|
38
46
|
readonly runQuickReview: (deps: AdaptiveCoordinatorDeps, opts: AdaptivePipelineOpts, prNumbers: readonly number[], coordinatorStartMs: number) => Promise<PipelineOutcome>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ZodType, ZodTypeDef } from 'zod';
|
|
2
|
+
import type { PhaseHandoffArtifact } from '../v2/durable-core/schemas/artifacts/index.js';
|
|
3
|
+
export declare function extractPhaseArtifact<T>(artifacts: readonly unknown[], schema: ZodType<T, ZodTypeDef, unknown>, kindPredicate: (a: unknown) => boolean): T | null;
|
|
4
|
+
export declare function buildContextSummary(priorArtifacts: readonly PhaseHandoffArtifact[], targetPhase: 'shaping' | 'coding' | 'review' | 'fix'): string;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractPhaseArtifact = extractPhaseArtifact;
|
|
4
|
+
exports.buildContextSummary = buildContextSummary;
|
|
5
|
+
const MAX_CONTEXT_BYTES = 8192;
|
|
6
|
+
function extractPhaseArtifact(artifacts, schema, kindPredicate) {
|
|
7
|
+
const candidates = artifacts.filter(kindPredicate);
|
|
8
|
+
if (candidates.length === 0)
|
|
9
|
+
return null;
|
|
10
|
+
const result = schema.safeParse(candidates[0]);
|
|
11
|
+
return result.success ? result.data : null;
|
|
12
|
+
}
|
|
13
|
+
function buildContextSummary(priorArtifacts, targetPhase) {
|
|
14
|
+
const discovery = priorArtifacts.find((a) => a.kind === 'wr.discovery_handoff') ?? null;
|
|
15
|
+
const shaping = priorArtifacts.find((a) => a.kind === 'wr.shaping_handoff') ?? null;
|
|
16
|
+
const coding = priorArtifacts.find((a) => a.kind === 'wr.coding_handoff') ?? null;
|
|
17
|
+
const sections = [];
|
|
18
|
+
switch (targetPhase) {
|
|
19
|
+
case 'shaping': {
|
|
20
|
+
if (discovery) {
|
|
21
|
+
if (discovery.implementationConstraints?.length) {
|
|
22
|
+
sections.push({ priority: 1, content: renderList('Implementation Constraints', discovery.implementationConstraints) });
|
|
23
|
+
}
|
|
24
|
+
sections.push({ priority: 1, content: `**Selected Direction:** ${discovery.selectedDirection}` });
|
|
25
|
+
if (discovery.keyInvariants.length) {
|
|
26
|
+
sections.push({ priority: 2, content: renderList('Key Invariants', discovery.keyInvariants) });
|
|
27
|
+
}
|
|
28
|
+
if (discovery.rejectedDirections?.length) {
|
|
29
|
+
sections.push({ priority: 2, content: renderRejectedDirections(discovery.rejectedDirections) });
|
|
30
|
+
}
|
|
31
|
+
if (discovery.keyCodebaseLocations?.length) {
|
|
32
|
+
sections.push({ priority: 3, content: renderCodebaseLocations(discovery.keyCodebaseLocations) });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case 'coding': {
|
|
38
|
+
if (discovery) {
|
|
39
|
+
if (discovery.implementationConstraints?.length) {
|
|
40
|
+
sections.push({ priority: 1, content: renderList('Implementation Constraints', discovery.implementationConstraints) });
|
|
41
|
+
}
|
|
42
|
+
if (discovery.keyInvariants.length) {
|
|
43
|
+
sections.push({ priority: 2, content: renderList('Key Invariants', discovery.keyInvariants) });
|
|
44
|
+
}
|
|
45
|
+
if (discovery.keyCodebaseLocations?.length) {
|
|
46
|
+
sections.push({ priority: 3, content: renderCodebaseLocations(discovery.keyCodebaseLocations) });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (shaping) {
|
|
50
|
+
sections.push({ priority: 1, content: `**Selected Shape:** ${shaping.selectedShape}\n**Appetite:** ${shaping.appetite}` });
|
|
51
|
+
if (shaping.keyConstraints.length) {
|
|
52
|
+
sections.push({ priority: 1, content: renderList('Key Constraints', shaping.keyConstraints) });
|
|
53
|
+
}
|
|
54
|
+
if (shaping.outOfScope.length) {
|
|
55
|
+
sections.push({ priority: 1, content: renderList('Out of Scope', shaping.outOfScope) });
|
|
56
|
+
}
|
|
57
|
+
if (shaping.rabbitHoles.length) {
|
|
58
|
+
sections.push({ priority: 2, content: renderList('Rabbit Holes', shaping.rabbitHoles) });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'review': {
|
|
64
|
+
if (discovery) {
|
|
65
|
+
if (discovery.implementationConstraints?.length) {
|
|
66
|
+
sections.push({ priority: 1, content: renderList('Implementation Constraints', discovery.implementationConstraints) });
|
|
67
|
+
}
|
|
68
|
+
if (discovery.keyInvariants.length) {
|
|
69
|
+
sections.push({ priority: 2, content: renderList('Key Invariants', discovery.keyInvariants) });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (shaping) {
|
|
73
|
+
if (shaping.validationChecklist.length) {
|
|
74
|
+
sections.push({ priority: 1, content: renderList('Validation Checklist (check each explicitly)', shaping.validationChecklist) });
|
|
75
|
+
}
|
|
76
|
+
if (shaping.keyConstraints.length) {
|
|
77
|
+
sections.push({ priority: 1, content: renderList('Key Constraints', shaping.keyConstraints) });
|
|
78
|
+
}
|
|
79
|
+
if (shaping.outOfScope.length) {
|
|
80
|
+
sections.push({ priority: 1, content: renderList('Out of Scope', shaping.outOfScope) });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (coding) {
|
|
84
|
+
if (coding.keyDecisions.length) {
|
|
85
|
+
sections.push({ priority: 1, content: renderList('Coding Decisions (WHY)', coding.keyDecisions) });
|
|
86
|
+
}
|
|
87
|
+
if (coding.correctedAssumptions?.length) {
|
|
88
|
+
sections.push({ priority: 1, content: renderCorrectedAssumptions(coding.correctedAssumptions) });
|
|
89
|
+
}
|
|
90
|
+
if (coding.knownLimitations.length) {
|
|
91
|
+
sections.push({ priority: 2, content: renderList('Known Limitations', coding.knownLimitations) });
|
|
92
|
+
}
|
|
93
|
+
if (coding.filesChanged.length) {
|
|
94
|
+
sections.push({ priority: 3, content: renderList('Files Changed', coding.filesChanged) });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case 'fix': {
|
|
100
|
+
if (shaping) {
|
|
101
|
+
if (shaping.validationChecklist.length) {
|
|
102
|
+
sections.push({ priority: 1, content: renderList('Validation Checklist', shaping.validationChecklist) });
|
|
103
|
+
}
|
|
104
|
+
if (shaping.keyConstraints.length) {
|
|
105
|
+
sections.push({ priority: 1, content: renderList('Key Constraints', shaping.keyConstraints) });
|
|
106
|
+
}
|
|
107
|
+
if (shaping.outOfScope.length) {
|
|
108
|
+
sections.push({ priority: 1, content: renderList('Out of Scope', shaping.outOfScope) });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (coding) {
|
|
112
|
+
if (coding.keyDecisions.length) {
|
|
113
|
+
sections.push({ priority: 1, content: renderList('Coding Decisions (WHY)', coding.keyDecisions) });
|
|
114
|
+
}
|
|
115
|
+
if (coding.correctedAssumptions?.length) {
|
|
116
|
+
sections.push({ priority: 1, content: renderCorrectedAssumptions(coding.correctedAssumptions) });
|
|
117
|
+
}
|
|
118
|
+
if (coding.knownLimitations.length) {
|
|
119
|
+
sections.push({ priority: 2, content: renderList('Known Limitations', coding.knownLimitations) });
|
|
120
|
+
}
|
|
121
|
+
if (coding.filesChanged.length) {
|
|
122
|
+
sections.push({ priority: 3, content: renderList('Files Changed', coding.filesChanged) });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (sections.length === 0)
|
|
129
|
+
return '';
|
|
130
|
+
return buildBudgetedOutput(sections);
|
|
131
|
+
}
|
|
132
|
+
function renderList(heading, items) {
|
|
133
|
+
return `**${heading}:**\n${items.map((i) => `- ${i}`).join('\n')}`;
|
|
134
|
+
}
|
|
135
|
+
function renderRejectedDirections(directions) {
|
|
136
|
+
return `**Rejected Directions:**\n${directions.map((d) => `- ${d.direction} -- ${d.reason}`).join('\n')}`;
|
|
137
|
+
}
|
|
138
|
+
function renderCodebaseLocations(locations) {
|
|
139
|
+
return `**Key Codebase Locations:**\n${locations.map((l) => `- \`${l.path}\` -- ${l.relevance}`).join('\n')}`;
|
|
140
|
+
}
|
|
141
|
+
function renderCorrectedAssumptions(corrections) {
|
|
142
|
+
return `**Corrected Assumptions (prior phase was wrong about these):**\n${corrections.map((c) => `- Assumed: ${c.assumed}\n Actual: ${c.actual}`).join('\n')}`;
|
|
143
|
+
}
|
|
144
|
+
function buildBudgetedOutput(sections) {
|
|
145
|
+
const ordered = [...sections].sort((a, b) => a.priority - b.priority);
|
|
146
|
+
const included = [];
|
|
147
|
+
let bytesUsed = 0;
|
|
148
|
+
for (const section of ordered) {
|
|
149
|
+
const sectionBytes = Buffer.byteLength(section.content + '\n\n', 'utf8');
|
|
150
|
+
if (bytesUsed + sectionBytes <= MAX_CONTEXT_BYTES) {
|
|
151
|
+
included.push(section.content);
|
|
152
|
+
bytesUsed += sectionBytes;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return included.join('\n\n');
|
|
156
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { AdaptiveCoordinatorDeps, AdaptivePipelineOpts, PipelineOutcome } from '../adaptive-pipeline.js';
|
|
2
|
-
import { type DiscoveryHandoffArtifactV1 } from '../../v2/durable-core/schemas/artifacts/
|
|
2
|
+
import { type DiscoveryHandoffArtifactV1 } from '../../v2/durable-core/schemas/artifacts/index.js';
|
|
3
3
|
export declare function renderHandoff(artifact: DiscoveryHandoffArtifactV1): string;
|
|
4
4
|
export declare function runFullPipeline(deps: AdaptiveCoordinatorDeps, opts: AdaptivePipelineOpts, coordinatorStartMs: number): Promise<PipelineOutcome>;
|
|
@@ -3,12 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.renderHandoff = renderHandoff;
|
|
4
4
|
exports.runFullPipeline = runFullPipeline;
|
|
5
5
|
const adaptive_pipeline_js_1 = require("../adaptive-pipeline.js");
|
|
6
|
-
const
|
|
6
|
+
const index_js_1 = require("../../v2/durable-core/schemas/artifacts/index.js");
|
|
7
|
+
const context_assembly_js_1 = require("../context-assembly.js");
|
|
8
|
+
const pipeline_run_context_js_1 = require("../pipeline-run-context.js");
|
|
7
9
|
const implement_shared_js_1 = require("./implement-shared.js");
|
|
8
10
|
const implement_js_1 = require("./implement.js");
|
|
9
11
|
const PR_POLL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
10
12
|
const UX_GATE_ACK_TIMEOUT_MS = 24 * 60 * 60 * 1000;
|
|
11
13
|
const MIN_NOTES_LENGTH_FOR_FALLBACK = 50;
|
|
14
|
+
function extractPriorArtifactsFromContext(ctx) {
|
|
15
|
+
const artifacts = [];
|
|
16
|
+
if (ctx.phases.discovery?.result.kind === 'full')
|
|
17
|
+
artifacts.push(ctx.phases.discovery.result.artifact);
|
|
18
|
+
if (ctx.phases.shaping?.result.kind === 'full')
|
|
19
|
+
artifacts.push(ctx.phases.shaping.result.artifact);
|
|
20
|
+
if (ctx.phases.coding?.result.kind === 'full')
|
|
21
|
+
artifacts.push(ctx.phases.coding.result.artifact);
|
|
22
|
+
return artifacts;
|
|
23
|
+
}
|
|
12
24
|
function renderHandoff(artifact) {
|
|
13
25
|
const lines = [
|
|
14
26
|
`## Discovery Handoff`,
|
|
@@ -30,9 +42,9 @@ function renderHandoff(artifact) {
|
|
|
30
42
|
function readDiscoveryHandoffArtifact(artifacts, sessionHandle, stderrFn) {
|
|
31
43
|
const handlePrefix = sessionHandle.slice(0, 16);
|
|
32
44
|
for (const raw of artifacts) {
|
|
33
|
-
if (!(0,
|
|
45
|
+
if (!(0, index_js_1.isDiscoveryHandoffArtifact)(raw))
|
|
34
46
|
continue;
|
|
35
|
-
const result =
|
|
47
|
+
const result = index_js_1.DiscoveryHandoffArtifactV1Schema.safeParse(raw);
|
|
36
48
|
if (!result.success) {
|
|
37
49
|
const issues = result.error.issues
|
|
38
50
|
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
@@ -46,13 +58,37 @@ function readDiscoveryHandoffArtifact(artifacts, sessionHandle, stderrFn) {
|
|
|
46
58
|
}
|
|
47
59
|
async function runFullPipeline(deps, opts, coordinatorStartMs) {
|
|
48
60
|
deps.stderr(`[full-pipeline] Starting FULL pipeline for workspace=${opts.workspace}`);
|
|
61
|
+
const activeRunResult = await deps.readActiveRunId(opts.workspace);
|
|
62
|
+
const priorRunId = activeRunResult.isOk() ? activeRunResult.value : null;
|
|
63
|
+
const runId = priorRunId ?? deps.generateRunId();
|
|
64
|
+
let initialPriorArtifacts = [];
|
|
65
|
+
if (priorRunId) {
|
|
66
|
+
const existingCtx = await deps.readPipelineContext(opts.workspace, priorRunId);
|
|
67
|
+
if (existingCtx.isOk() && existingCtx.value !== null) {
|
|
68
|
+
initialPriorArtifacts = extractPriorArtifactsFromContext(existingCtx.value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
deps.stderr(priorRunId
|
|
72
|
+
? `[full-pipeline] Resuming prior run ${priorRunId} with ${initialPriorArtifacts.length} artifact(s)`
|
|
73
|
+
: `[full-pipeline] Starting new run ${runId}`);
|
|
74
|
+
if (!priorRunId) {
|
|
75
|
+
const initResult = await deps.createPipelineContext(opts.workspace, runId, opts.goal, 'FULL');
|
|
76
|
+
if (initResult.isErr()) {
|
|
77
|
+
deps.stderr(`[full-pipeline] FATAL: failed to initialize PipelineRunContext: ${initResult.error}`);
|
|
78
|
+
return { kind: 'escalated', escalationReason: { phase: 'init', reason: `PipelineRunContext initialization failed: ${initResult.error}` } };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
49
81
|
const pitchPath = opts.workspace + '/.workrail/current-pitch.md';
|
|
50
82
|
const archiveDir = opts.workspace + '/.workrail/used-pitches';
|
|
51
83
|
const archiveTimestamp = deps.nowIso().replace(/[:.]/g, '-');
|
|
52
84
|
const archivePath = archiveDir + '/pitch-' + archiveTimestamp + '.md';
|
|
53
85
|
let outcome;
|
|
54
86
|
try {
|
|
55
|
-
outcome = await runFullPipelineCore(deps, opts, coordinatorStartMs);
|
|
87
|
+
outcome = await runFullPipelineCore(deps, opts, coordinatorStartMs, runId, initialPriorArtifacts);
|
|
88
|
+
const markResult = await deps.markPipelineRunComplete(opts.workspace, runId);
|
|
89
|
+
if (markResult.isErr()) {
|
|
90
|
+
deps.stderr(`[WARN full-pipeline] markPipelineRunComplete failed -- next run may resume this one: ${markResult.error}`);
|
|
91
|
+
}
|
|
56
92
|
}
|
|
57
93
|
finally {
|
|
58
94
|
try {
|
|
@@ -66,7 +102,8 @@ async function runFullPipeline(deps, opts, coordinatorStartMs) {
|
|
|
66
102
|
}
|
|
67
103
|
return outcome;
|
|
68
104
|
}
|
|
69
|
-
async function runFullPipelineCore(deps, opts, coordinatorStartMs) {
|
|
105
|
+
async function runFullPipelineCore(deps, opts, coordinatorStartMs, runId, initialPriorArtifacts) {
|
|
106
|
+
let priorArtifacts = initialPriorArtifacts;
|
|
70
107
|
const discoveryCutoff = (0, adaptive_pipeline_js_1.checkSpawnCutoff)(coordinatorStartMs, deps.now(), 'discovery');
|
|
71
108
|
if (discoveryCutoff)
|
|
72
109
|
return discoveryCutoff;
|
|
@@ -107,31 +144,37 @@ async function runFullPipelineCore(deps, opts, coordinatorStartMs) {
|
|
|
107
144
|
deps.stderr(`[coordinator] getAgentResult failed: ${msg}`);
|
|
108
145
|
return {
|
|
109
146
|
kind: 'escalated',
|
|
110
|
-
escalationReason: { phase: '
|
|
147
|
+
escalationReason: { phase: 'discovery', reason: `getAgentResult threw: ${msg}` },
|
|
111
148
|
};
|
|
112
149
|
}
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
};
|
|
150
|
+
const discoveryArtifact = (0, context_assembly_js_1.extractPhaseArtifact)(discoveryAgentResult.artifacts, index_js_1.DiscoveryHandoffArtifactV1Schema, index_js_1.isDiscoveryHandoffArtifact);
|
|
151
|
+
const discoveryPhaseResult = (0, pipeline_run_context_js_1.buildPhaseResult)(discoveryArtifact, discoveryAgentResult.recapMarkdown);
|
|
152
|
+
priorArtifacts = discoveryArtifact !== null ? [...priorArtifacts, discoveryArtifact] : priorArtifacts;
|
|
153
|
+
const discoveryWriteResult = await deps.writePhaseRecord(opts.workspace, runId, {
|
|
154
|
+
phase: 'discovery',
|
|
155
|
+
record: { completedAt: deps.nowIso(), sessionHandle: discoveryHandle, result: discoveryPhaseResult },
|
|
156
|
+
});
|
|
157
|
+
if (discoveryWriteResult.isErr()) {
|
|
158
|
+
deps.stderr(`[full-pipeline] FATAL: failed to persist discovery phase record: ${discoveryWriteResult.error}`);
|
|
159
|
+
return { kind: 'escalated', escalationReason: { phase: 'discovery', reason: `context persistence failed: ${discoveryWriteResult.error}` } };
|
|
122
160
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
shapingContext = {};
|
|
133
|
-
}
|
|
161
|
+
deps.stderr(`[full-pipeline] Discovery phase result: ${discoveryPhaseResult.kind}`);
|
|
162
|
+
if (discoveryPhaseResult.kind === 'fallback') {
|
|
163
|
+
return {
|
|
164
|
+
kind: 'escalated',
|
|
165
|
+
escalationReason: {
|
|
166
|
+
phase: 'discovery',
|
|
167
|
+
reason: 'discovery session produced no usable output (no artifact and no meaningful notes). Starting shaping blind would produce low-quality work. Fix the discovery session and resume.',
|
|
168
|
+
},
|
|
169
|
+
};
|
|
134
170
|
}
|
|
171
|
+
const shapingContextSummary = (0, context_assembly_js_1.buildContextSummary)(priorArtifacts, 'shaping');
|
|
172
|
+
const partialWarning = discoveryPhaseResult.kind === 'partial'
|
|
173
|
+
? '\n\n**Note:** Discovery phase produced partial output only (no structured artifact). Context above is from session notes and may be incomplete.'
|
|
174
|
+
: '';
|
|
175
|
+
const shapingContext = (shapingContextSummary || partialWarning)
|
|
176
|
+
? { assembledContextSummary: (shapingContextSummary + partialWarning).trim() }
|
|
177
|
+
: {};
|
|
135
178
|
const shapingCutoff = (0, adaptive_pipeline_js_1.checkSpawnCutoff)(coordinatorStartMs, deps.now(), 'shaping');
|
|
136
179
|
if (shapingCutoff)
|
|
137
180
|
return shapingCutoff;
|
|
@@ -163,6 +206,36 @@ async function runFullPipelineCore(deps, opts, coordinatorStartMs) {
|
|
|
163
206
|
};
|
|
164
207
|
}
|
|
165
208
|
deps.stderr(`[full-pipeline] Shaping session completed`);
|
|
209
|
+
let shapingAgentResult;
|
|
210
|
+
try {
|
|
211
|
+
shapingAgentResult = await deps.getAgentResult(shapingHandle);
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
215
|
+
deps.stderr(`[coordinator] getAgentResult (shaping) failed: ${msg}`);
|
|
216
|
+
shapingAgentResult = { recapMarkdown: null, artifacts: [] };
|
|
217
|
+
}
|
|
218
|
+
const shapingArtifact = (0, context_assembly_js_1.extractPhaseArtifact)(shapingAgentResult.artifacts, index_js_1.ShapingHandoffArtifactV1Schema, index_js_1.isShapingHandoffArtifact);
|
|
219
|
+
const shapingPhaseResult = (0, pipeline_run_context_js_1.buildPhaseResult)(shapingArtifact, shapingAgentResult.recapMarkdown);
|
|
220
|
+
priorArtifacts = shapingArtifact !== null ? [...priorArtifacts, shapingArtifact] : priorArtifacts;
|
|
221
|
+
const shapingWriteResult = await deps.writePhaseRecord(opts.workspace, runId, {
|
|
222
|
+
phase: 'shaping',
|
|
223
|
+
record: { completedAt: deps.nowIso(), sessionHandle: shapingHandle, result: shapingPhaseResult },
|
|
224
|
+
});
|
|
225
|
+
if (shapingWriteResult.isErr()) {
|
|
226
|
+
deps.stderr(`[full-pipeline] FATAL: failed to persist shaping phase record: ${shapingWriteResult.error}`);
|
|
227
|
+
return { kind: 'escalated', escalationReason: { phase: 'shaping', reason: `context persistence failed: ${shapingWriteResult.error}` } };
|
|
228
|
+
}
|
|
229
|
+
deps.stderr(`[full-pipeline] Shaping phase result: ${shapingPhaseResult.kind}`);
|
|
230
|
+
if (shapingPhaseResult.kind === 'fallback') {
|
|
231
|
+
return {
|
|
232
|
+
kind: 'escalated',
|
|
233
|
+
escalationReason: {
|
|
234
|
+
phase: 'shaping',
|
|
235
|
+
reason: 'shaping session produced no usable output (no artifact and no meaningful notes). Starting coding blind would produce low-quality work. Fix the shaping session and resume.',
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
166
239
|
if ((0, implement_js_1.touchesUI)(opts.goal)) {
|
|
167
240
|
deps.stderr(`[full-pipeline] UX signals detected -- dispatching wr.ui-ux-design`);
|
|
168
241
|
const uxCutoff = (0, adaptive_pipeline_js_1.checkSpawnCutoff)(coordinatorStartMs, deps.now(), 'ux-gate');
|
|
@@ -231,8 +304,18 @@ async function runFullPipelineCore(deps, opts, coordinatorStartMs) {
|
|
|
231
304
|
if (codingCutoff)
|
|
232
305
|
return codingCutoff;
|
|
233
306
|
deps.stderr(`[full-pipeline] Spawning wr.coding-task`);
|
|
307
|
+
const codingContextSummary = (0, context_assembly_js_1.buildContextSummary)(priorArtifacts, 'coding');
|
|
308
|
+
const shapingPartialWarning = shapingPhaseResult.kind === 'partial'
|
|
309
|
+
? '\n\n**Note:** Shaping phase produced partial output only (no structured artifact). Context above is from session notes and may be incomplete.'
|
|
310
|
+
: '';
|
|
311
|
+
const discoveryPartialWarning = discoveryPhaseResult.kind === 'partial'
|
|
312
|
+
? '\n\n**Note:** Discovery phase produced partial output only (no structured artifact). Some upstream context may be missing.'
|
|
313
|
+
: '';
|
|
314
|
+
const codingWarnings = discoveryPartialWarning + shapingPartialWarning;
|
|
315
|
+
const codingFullContext = (codingContextSummary + codingWarnings).trim();
|
|
234
316
|
const codingSpawnResult = await deps.spawnSession('wr.coding-task', opts.goal, opts.workspace, {
|
|
235
317
|
pitchPath: opts.workspace + '/.workrail/current-pitch.md',
|
|
318
|
+
...(codingFullContext ? { assembledContextSummary: codingFullContext } : {}),
|
|
236
319
|
}, { maxSessionMinutes: Math.ceil(adaptive_pipeline_js_1.CODING_TIMEOUT_MS / 60000) });
|
|
237
320
|
if (codingSpawnResult.kind === 'err') {
|
|
238
321
|
return {
|
|
@@ -260,6 +343,36 @@ async function runFullPipelineCore(deps, opts, coordinatorStartMs) {
|
|
|
260
343
|
};
|
|
261
344
|
}
|
|
262
345
|
deps.stderr(`[full-pipeline] Coding session completed`);
|
|
346
|
+
let codingAgentResult;
|
|
347
|
+
try {
|
|
348
|
+
codingAgentResult = await deps.getAgentResult(codingHandle);
|
|
349
|
+
}
|
|
350
|
+
catch (e) {
|
|
351
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
352
|
+
deps.stderr(`[coordinator] getAgentResult (coding) failed: ${msg}`);
|
|
353
|
+
codingAgentResult = { recapMarkdown: null, artifacts: [] };
|
|
354
|
+
}
|
|
355
|
+
const codingArtifact = (0, context_assembly_js_1.extractPhaseArtifact)(codingAgentResult.artifacts, index_js_1.CodingHandoffArtifactV1Schema, index_js_1.isCodingHandoffArtifact);
|
|
356
|
+
const codingPhaseResult = (0, pipeline_run_context_js_1.buildPhaseResult)(codingArtifact, codingAgentResult.recapMarkdown);
|
|
357
|
+
priorArtifacts = codingArtifact !== null ? [...priorArtifacts, codingArtifact] : priorArtifacts;
|
|
358
|
+
const codingWriteResult = await deps.writePhaseRecord(opts.workspace, runId, {
|
|
359
|
+
phase: 'coding',
|
|
360
|
+
record: { completedAt: deps.nowIso(), sessionHandle: codingHandle, result: codingPhaseResult },
|
|
361
|
+
});
|
|
362
|
+
if (codingWriteResult.isErr()) {
|
|
363
|
+
deps.stderr(`[full-pipeline] FATAL: failed to persist coding phase record: ${codingWriteResult.error}`);
|
|
364
|
+
return { kind: 'escalated', escalationReason: { phase: 'coding', reason: `context persistence failed: ${codingWriteResult.error}` } };
|
|
365
|
+
}
|
|
366
|
+
deps.stderr(`[full-pipeline] Coding phase result: ${codingPhaseResult.kind}`);
|
|
367
|
+
if (codingPhaseResult.kind === 'fallback') {
|
|
368
|
+
return {
|
|
369
|
+
kind: 'escalated',
|
|
370
|
+
escalationReason: {
|
|
371
|
+
phase: 'coding',
|
|
372
|
+
reason: 'coding session produced no usable output (no artifact and no meaningful notes). Starting review blind would miss design-level issues. Fix the coding session and resume.',
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
}
|
|
263
376
|
const branchPattern = `worktrain/${codingHandle.slice(0, 16)}`;
|
|
264
377
|
deps.stderr(`[full-pipeline] Polling for PR on branch pattern: ${branchPattern}`);
|
|
265
378
|
let prUrl;
|
|
@@ -284,5 +397,5 @@ async function runFullPipelineCore(deps, opts, coordinatorStartMs) {
|
|
|
284
397
|
};
|
|
285
398
|
}
|
|
286
399
|
deps.stderr(`[full-pipeline] PR detected: ${prUrl}`);
|
|
287
|
-
return (0, implement_shared_js_1.runReviewAndVerdictCycle)(deps, opts, prUrl, coordinatorStartMs, 0);
|
|
400
|
+
return (0, implement_shared_js_1.runReviewAndVerdictCycle)(deps, opts, prUrl, coordinatorStartMs, 0, runId, priorArtifacts);
|
|
288
401
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AdaptiveCoordinatorDeps, AdaptivePipelineOpts, PipelineOutcome } from '../adaptive-pipeline.js';
|
|
2
2
|
import type { ReviewVerdictArtifactV1 } from '../../v2/durable-core/schemas/artifacts/review-verdict.js';
|
|
3
|
+
import type { PhaseHandoffArtifact } from '../../v2/durable-core/schemas/artifacts/index.js';
|
|
3
4
|
export declare const MAX_FIX_ITERATIONS = 2;
|
|
4
|
-
export declare function runReviewAndVerdictCycle(deps: AdaptiveCoordinatorDeps, opts: AdaptivePipelineOpts, prUrl: string, coordinatorStartMs: number, iteration: number): Promise<PipelineOutcome>;
|
|
5
|
-
export declare function runAuditChain(deps: AdaptiveCoordinatorDeps, opts: AdaptivePipelineOpts, prUrl: string, coordinatorStartMs: number, severity: 'blocking' | 'unknown', findings?: ReviewVerdictArtifactV1['findings']): Promise<PipelineOutcome>;
|
|
5
|
+
export declare function runReviewAndVerdictCycle(deps: AdaptiveCoordinatorDeps, opts: AdaptivePipelineOpts, prUrl: string, coordinatorStartMs: number, iteration: number, runId?: string, priorArtifacts?: readonly PhaseHandoffArtifact[]): Promise<PipelineOutcome>;
|
|
6
|
+
export declare function runAuditChain(deps: AdaptiveCoordinatorDeps, opts: AdaptivePipelineOpts, prUrl: string, coordinatorStartMs: number, severity: 'blocking' | 'unknown', findings?: ReviewVerdictArtifactV1['findings'], priorArtifacts?: readonly PhaseHandoffArtifact[]): Promise<PipelineOutcome>;
|
|
@@ -6,8 +6,9 @@ exports.runAuditChain = runAuditChain;
|
|
|
6
6
|
const adaptive_pipeline_js_1 = require("../adaptive-pipeline.js");
|
|
7
7
|
const pr_review_js_1 = require("../pr-review.js");
|
|
8
8
|
const review_verdict_js_1 = require("../../v2/durable-core/schemas/artifacts/review-verdict.js");
|
|
9
|
+
const context_assembly_js_1 = require("../context-assembly.js");
|
|
9
10
|
exports.MAX_FIX_ITERATIONS = 2;
|
|
10
|
-
async function runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, iteration) {
|
|
11
|
+
async function runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, iteration, runId = '', priorArtifacts = []) {
|
|
11
12
|
const cutoffCheck = (0, adaptive_pipeline_js_1.checkSpawnCutoff)(coordinatorStartMs, deps.now(), 'review');
|
|
12
13
|
if (cutoffCheck)
|
|
13
14
|
return cutoffCheck;
|
|
@@ -15,7 +16,11 @@ async function runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, i
|
|
|
15
16
|
? `Review PR for merge: ${prUrl}`
|
|
16
17
|
: `Re-review PR after fixes (iteration ${iteration}): ${prUrl}`;
|
|
17
18
|
deps.stderr(`[review-cycle] Spawning review session (iteration=${iteration}): ${reviewGoal.slice(0, 80)}`);
|
|
18
|
-
const
|
|
19
|
+
const reviewContextSummary = (0, context_assembly_js_1.buildContextSummary)(priorArtifacts, 'review');
|
|
20
|
+
const reviewSpawnResult = await deps.spawnSession('wr.mr-review', reviewGoal, opts.workspace, {
|
|
21
|
+
prUrl,
|
|
22
|
+
...(reviewContextSummary ? { assembledContextSummary: reviewContextSummary } : {}),
|
|
23
|
+
});
|
|
19
24
|
if (reviewSpawnResult.kind === 'err') {
|
|
20
25
|
return {
|
|
21
26
|
kind: 'escalated',
|
|
@@ -86,7 +91,12 @@ async function runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, i
|
|
|
86
91
|
if (fixCutoff)
|
|
87
92
|
return fixCutoff;
|
|
88
93
|
const fixGoal = `Fix review findings: ${findings.findingSummaries.slice(0, 3).join('; ')}`;
|
|
89
|
-
const
|
|
94
|
+
const fixContextSummary = (0, context_assembly_js_1.buildContextSummary)(priorArtifacts, 'fix');
|
|
95
|
+
const fixSpawnResult = await deps.spawnSession('wr.coding-task', fixGoal, opts.workspace, {
|
|
96
|
+
prUrl,
|
|
97
|
+
findings: findings.findingSummaries,
|
|
98
|
+
...(fixContextSummary ? { assembledContextSummary: fixContextSummary } : {}),
|
|
99
|
+
});
|
|
90
100
|
if (fixSpawnResult.kind === 'err') {
|
|
91
101
|
return {
|
|
92
102
|
kind: 'escalated',
|
|
@@ -110,15 +120,15 @@ async function runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, i
|
|
|
110
120
|
};
|
|
111
121
|
}
|
|
112
122
|
deps.stderr(`[review-cycle] Fix iteration ${iteration + 1} complete -- re-reviewing`);
|
|
113
|
-
return runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, iteration + 1);
|
|
123
|
+
return runReviewAndVerdictCycle(deps, opts, prUrl, coordinatorStartMs, iteration + 1, runId, priorArtifacts);
|
|
114
124
|
}
|
|
115
125
|
case 'blocking':
|
|
116
126
|
case 'unknown': {
|
|
117
|
-
return runAuditChain(deps, opts, prUrl, coordinatorStartMs, findings.severity, rawVerdict?.findings);
|
|
127
|
+
return runAuditChain(deps, opts, prUrl, coordinatorStartMs, findings.severity, rawVerdict?.findings, priorArtifacts);
|
|
118
128
|
}
|
|
119
129
|
}
|
|
120
130
|
}
|
|
121
|
-
async function runAuditChain(deps, opts, prUrl, coordinatorStartMs, severity, findings) {
|
|
131
|
+
async function runAuditChain(deps, opts, prUrl, coordinatorStartMs, severity, findings, priorArtifacts = []) {
|
|
122
132
|
deps.stderr(`[audit-chain] ${severity.toUpperCase()} finding -- running audit chain`);
|
|
123
133
|
const auditCutoff = (0, adaptive_pipeline_js_1.checkSpawnCutoff)(coordinatorStartMs, deps.now(), 'audit');
|
|
124
134
|
if (auditCutoff)
|
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.touchesUI = touchesUI;
|
|
4
4
|
exports.runImplementPipeline = runImplementPipeline;
|
|
5
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
6
|
const adaptive_pipeline_js_1 = require("../adaptive-pipeline.js");
|
|
6
7
|
const implement_shared_js_1 = require("./implement-shared.js");
|
|
8
|
+
const context_assembly_js_1 = require("../context-assembly.js");
|
|
9
|
+
const pipeline_run_context_js_1 = require("../pipeline-run-context.js");
|
|
10
|
+
const index_js_1 = require("../../v2/durable-core/schemas/artifacts/index.js");
|
|
7
11
|
const PR_POLL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
8
12
|
const UI_KEYWORDS = [
|
|
9
13
|
'ui', 'screen', 'view', 'layout', 'component', 'design', 'ux', 'frontend',
|
|
@@ -17,9 +21,23 @@ async function runImplementPipeline(deps, opts, pitchPath, coordinatorStartMs) {
|
|
|
17
21
|
const archiveDir = opts.workspace + '/.workrail/used-pitches';
|
|
18
22
|
const archiveTimestamp = deps.nowIso().replace(/[:.]/g, '-');
|
|
19
23
|
const archivePath = archiveDir + '/pitch-' + archiveTimestamp + '.md';
|
|
24
|
+
const activeRunResult = await deps.readActiveRunId(opts.workspace);
|
|
25
|
+
const priorRunId = activeRunResult.isOk() ? activeRunResult.value : null;
|
|
26
|
+
const runId = priorRunId ?? deps.generateRunId();
|
|
27
|
+
const initResult = priorRunId
|
|
28
|
+
? (0, neverthrow_1.ok)(undefined)
|
|
29
|
+
: await deps.createPipelineContext(opts.workspace, runId, opts.goal, 'IMPLEMENT');
|
|
30
|
+
if (initResult.isErr()) {
|
|
31
|
+
deps.stderr(`[implement] FATAL: failed to initialize PipelineRunContext: ${initResult.error}`);
|
|
32
|
+
return { kind: 'escalated', escalationReason: { phase: 'init', reason: `PipelineRunContext initialization failed: ${initResult.error}` } };
|
|
33
|
+
}
|
|
20
34
|
let outcome;
|
|
21
35
|
try {
|
|
22
|
-
outcome = await runImplementCore(deps, opts, pitchPath, coordinatorStartMs);
|
|
36
|
+
outcome = await runImplementCore(deps, opts, pitchPath, coordinatorStartMs, runId);
|
|
37
|
+
const markResult = await deps.markPipelineRunComplete(opts.workspace, runId);
|
|
38
|
+
if (markResult.isErr()) {
|
|
39
|
+
deps.stderr(`[WARN implement] markPipelineRunComplete failed -- next run may resume this one: ${markResult.error}`);
|
|
40
|
+
}
|
|
23
41
|
}
|
|
24
42
|
finally {
|
|
25
43
|
try {
|
|
@@ -33,7 +51,8 @@ async function runImplementPipeline(deps, opts, pitchPath, coordinatorStartMs) {
|
|
|
33
51
|
}
|
|
34
52
|
return outcome;
|
|
35
53
|
}
|
|
36
|
-
async function runImplementCore(deps, opts, pitchPath, coordinatorStartMs) {
|
|
54
|
+
async function runImplementCore(deps, opts, pitchPath, coordinatorStartMs, runId) {
|
|
55
|
+
const priorArtifacts = [];
|
|
37
56
|
if (touchesUI(opts.goal)) {
|
|
38
57
|
deps.stderr(`[implement] UX signals detected in goal, dispatching wr.ui-ux-design`);
|
|
39
58
|
const cutoffCheck = (0, adaptive_pipeline_js_1.checkSpawnCutoff)(coordinatorStartMs, deps.now(), 'ux-gate');
|
|
@@ -97,6 +116,33 @@ async function runImplementCore(deps, opts, pitchPath, coordinatorStartMs) {
|
|
|
97
116
|
};
|
|
98
117
|
}
|
|
99
118
|
deps.stderr(`[implement] Coding session completed (${Math.round((codingResult.durationMs ?? 0) / 1000)}s)`);
|
|
119
|
+
let codingAgentResult;
|
|
120
|
+
try {
|
|
121
|
+
codingAgentResult = await deps.getAgentResult(codingHandle);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
codingAgentResult = { recapMarkdown: null, artifacts: [] };
|
|
125
|
+
}
|
|
126
|
+
const codingArtifact = (0, context_assembly_js_1.extractPhaseArtifact)(codingAgentResult.artifacts, index_js_1.CodingHandoffArtifactV1Schema, index_js_1.isCodingHandoffArtifact);
|
|
127
|
+
const codingPhaseResult = (0, pipeline_run_context_js_1.buildPhaseResult)(codingArtifact, codingAgentResult.recapMarkdown);
|
|
128
|
+
const updatedPriorArtifacts = codingArtifact !== null ? [...priorArtifacts, codingArtifact] : priorArtifacts;
|
|
129
|
+
const codingWriteResult = await deps.writePhaseRecord(opts.workspace, runId, {
|
|
130
|
+
phase: 'coding',
|
|
131
|
+
record: { completedAt: deps.nowIso(), sessionHandle: codingHandle, result: codingPhaseResult },
|
|
132
|
+
});
|
|
133
|
+
if (codingWriteResult.isErr()) {
|
|
134
|
+
deps.stderr(`[implement] FATAL: failed to persist coding phase record: ${codingWriteResult.error}`);
|
|
135
|
+
return { kind: 'escalated', escalationReason: { phase: 'coding', reason: `context persistence failed: ${codingWriteResult.error}` } };
|
|
136
|
+
}
|
|
137
|
+
if (codingPhaseResult.kind === 'fallback') {
|
|
138
|
+
return {
|
|
139
|
+
kind: 'escalated',
|
|
140
|
+
escalationReason: {
|
|
141
|
+
phase: 'coding',
|
|
142
|
+
reason: 'coding session produced no usable output (no artifact and no meaningful notes). Starting review blind would miss design-level issues. Fix the coding session and resume.',
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
100
146
|
const branchPattern = `worktrain/${codingHandle.slice(0, 16)}`;
|
|
101
147
|
deps.stderr(`[implement] Polling for PR on branch pattern: ${branchPattern}`);
|
|
102
148
|
let prUrl;
|
|
@@ -121,5 +167,5 @@ async function runImplementCore(deps, opts, pitchPath, coordinatorStartMs) {
|
|
|
121
167
|
};
|
|
122
168
|
}
|
|
123
169
|
deps.stderr(`[implement] PR detected: ${prUrl}`);
|
|
124
|
-
return (0, implement_shared_js_1.runReviewAndVerdictCycle)(deps, opts, prUrl, coordinatorStartMs, 0);
|
|
170
|
+
return (0, implement_shared_js_1.runReviewAndVerdictCycle)(deps, opts, prUrl, coordinatorStartMs, 0, runId, updatedPriorArtifacts);
|
|
125
171
|
}
|