agentxchain 2.135.0 → 2.136.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/bin/agentxchain.js +10 -1
- package/package.json +4 -2
- package/scripts/release-preflight.sh +2 -0
- package/src/commands/connector.js +136 -0
- package/src/commands/mission.js +250 -103
- package/src/commands/restart.js +3 -0
- package/src/commands/resume.js +15 -0
- package/src/commands/step.js +12 -0
- package/src/lib/connector-validate.js +6 -0
- package/src/lib/context-section-parser.js +52 -0
- package/src/lib/continuous-run.js +60 -5
- package/src/lib/dispatch-bundle.js +14 -0
- package/src/lib/gate-evaluator.js +18 -1
- package/src/lib/governed-state.js +182 -52
- package/src/lib/intake.js +23 -52
- package/src/lib/intent-startup-migration.js +151 -0
- package/src/lib/normalized-config.js +5 -0
- package/src/lib/runtime-capabilities.js +101 -81
- package/src/lib/schemas/agentxchain-config.schema.json +391 -0
- package/src/lib/schemas/connector-capabilities-output.schema.json +104 -0
package/src/commands/resume.js
CHANGED
|
@@ -144,6 +144,9 @@ export async function resumeCommand(opts) {
|
|
|
144
144
|
process.exit(1);
|
|
145
145
|
}
|
|
146
146
|
state = reactivated.state;
|
|
147
|
+
if (reactivated.migration_notice) {
|
|
148
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
149
|
+
}
|
|
147
150
|
|
|
148
151
|
// Write dispatch bundle for the existing turn
|
|
149
152
|
const bundleResult = writeDispatchBundle(root, state, config);
|
|
@@ -204,6 +207,9 @@ export async function resumeCommand(opts) {
|
|
|
204
207
|
process.exit(1);
|
|
205
208
|
}
|
|
206
209
|
state = reactivated.state;
|
|
210
|
+
if (reactivated.migration_notice) {
|
|
211
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
212
|
+
}
|
|
207
213
|
|
|
208
214
|
const bundleResult = writeDispatchBundle(root, state, config, { turnId: retainedTurn.turn_id });
|
|
209
215
|
if (!bundleResult.ok) {
|
|
@@ -233,6 +239,9 @@ export async function resumeCommand(opts) {
|
|
|
233
239
|
}
|
|
234
240
|
state = initResult.state;
|
|
235
241
|
console.log(chalk.green(`Initialized governed run: ${state.run_id}`));
|
|
242
|
+
if (initResult.migration_notice) {
|
|
243
|
+
console.log(chalk.yellow(initResult.migration_notice));
|
|
244
|
+
}
|
|
236
245
|
}
|
|
237
246
|
|
|
238
247
|
// §47: paused + run_id exists → resume same run
|
|
@@ -244,6 +253,9 @@ export async function resumeCommand(opts) {
|
|
|
244
253
|
}
|
|
245
254
|
state = reactivated.state;
|
|
246
255
|
console.log(chalk.green(`Resumed blocked run: ${state.run_id}`));
|
|
256
|
+
if (reactivated.migration_notice) {
|
|
257
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
258
|
+
}
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
// §47: paused + run_id exists → resume same run
|
|
@@ -255,6 +267,9 @@ export async function resumeCommand(opts) {
|
|
|
255
267
|
}
|
|
256
268
|
state = reactivated.state;
|
|
257
269
|
console.log(chalk.green(`Resumed governed run: ${state.run_id}`));
|
|
270
|
+
if (reactivated.migration_notice) {
|
|
271
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
272
|
+
}
|
|
258
273
|
}
|
|
259
274
|
|
|
260
275
|
// Print run-context header before dispatch
|
package/src/commands/step.js
CHANGED
|
@@ -260,6 +260,9 @@ export async function stepCommand(opts) {
|
|
|
260
260
|
process.exit(1);
|
|
261
261
|
}
|
|
262
262
|
state = reactivated.state;
|
|
263
|
+
if (reactivated.migration_notice) {
|
|
264
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
265
|
+
}
|
|
263
266
|
skipAssignment = true;
|
|
264
267
|
|
|
265
268
|
// BUG-1 fix: refresh baseline snapshot to capture files dirtied between assignment and dispatch
|
|
@@ -285,6 +288,9 @@ export async function stepCommand(opts) {
|
|
|
285
288
|
}
|
|
286
289
|
state = initResult.state;
|
|
287
290
|
console.log(chalk.green(`Initialized governed run: ${state.run_id}`));
|
|
291
|
+
if (initResult.migration_notice) {
|
|
292
|
+
console.log(chalk.yellow(initResult.migration_notice));
|
|
293
|
+
}
|
|
288
294
|
}
|
|
289
295
|
|
|
290
296
|
// paused → resume
|
|
@@ -296,6 +302,9 @@ export async function stepCommand(opts) {
|
|
|
296
302
|
}
|
|
297
303
|
state = reactivated.state;
|
|
298
304
|
console.log(chalk.green(`Resumed blocked run: ${state.run_id}`));
|
|
305
|
+
if (reactivated.migration_notice) {
|
|
306
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
307
|
+
}
|
|
299
308
|
}
|
|
300
309
|
|
|
301
310
|
if (!skipAssignment && state.status === 'paused' && state.run_id) {
|
|
@@ -306,6 +315,9 @@ export async function stepCommand(opts) {
|
|
|
306
315
|
}
|
|
307
316
|
state = reactivated.state;
|
|
308
317
|
console.log(chalk.green(`Resumed governed run: ${state.run_id}`));
|
|
318
|
+
if (reactivated.migration_notice) {
|
|
319
|
+
console.log(chalk.yellow(reactivated.migration_notice));
|
|
320
|
+
}
|
|
309
321
|
}
|
|
310
322
|
|
|
311
323
|
// Assign the turn
|
|
@@ -106,6 +106,12 @@ export async function validateConfiguredConnector(sourceRoot, options = {}) {
|
|
|
106
106
|
const tempBase = mkdtempSync(join(tmpdir(), 'axc-connector-validate-'));
|
|
107
107
|
const scratchRoot = join(tempBase, 'workspace');
|
|
108
108
|
const warnings = [...roleSelection.warnings];
|
|
109
|
+
|
|
110
|
+
// Surface capability declaration warnings for self-declared connectors
|
|
111
|
+
const { getCapabilityDeclarationWarnings } = await import('./runtime-capabilities.js');
|
|
112
|
+
const capWarnings = getCapabilityDeclarationWarnings(runtime);
|
|
113
|
+
warnings.push(...capWarnings);
|
|
114
|
+
|
|
109
115
|
let keepArtifacts = options.keepArtifacts === true;
|
|
110
116
|
let dispatch = null;
|
|
111
117
|
let validation = null;
|
|
@@ -10,6 +10,8 @@ const SECTION_DEFINITIONS = [
|
|
|
10
10
|
{ id: 'last_turn_summary', header: null, required: false },
|
|
11
11
|
{ id: 'last_turn_decisions', header: null, required: false },
|
|
12
12
|
{ id: 'last_turn_objections', header: null, required: false },
|
|
13
|
+
{ id: 'last_turn_files_changed', header: null, required: false },
|
|
14
|
+
{ id: 'last_turn_changed_file_previews', header: null, required: false },
|
|
13
15
|
{ id: 'last_turn_verification', header: null, required: false },
|
|
14
16
|
{ id: 'decision_history', header: 'Decision History', required: false },
|
|
15
17
|
{ id: 'blockers', header: 'Blockers', required: true },
|
|
@@ -54,6 +56,8 @@ export function parseContextSections(contextMd) {
|
|
|
54
56
|
summaryLines,
|
|
55
57
|
decisionsLines,
|
|
56
58
|
objectionsLines,
|
|
59
|
+
filesChangedLines,
|
|
60
|
+
changedFilePreviewLines,
|
|
57
61
|
verificationLines,
|
|
58
62
|
} = splitLastAcceptedTurn(lastAcceptedTurnBody);
|
|
59
63
|
|
|
@@ -61,6 +65,8 @@ export function parseContextSections(contextMd) {
|
|
|
61
65
|
pushSection(parsedSections, 'last_turn_summary', summaryLines);
|
|
62
66
|
pushSection(parsedSections, 'last_turn_decisions', decisionsLines);
|
|
63
67
|
pushSection(parsedSections, 'last_turn_objections', objectionsLines);
|
|
68
|
+
pushSection(parsedSections, 'last_turn_files_changed', filesChangedLines);
|
|
69
|
+
pushSection(parsedSections, 'last_turn_changed_file_previews', changedFilePreviewLines);
|
|
64
70
|
pushSection(parsedSections, 'last_turn_verification', verificationLines);
|
|
65
71
|
}
|
|
66
72
|
|
|
@@ -91,6 +97,8 @@ export function renderContextSections(sections) {
|
|
|
91
97
|
sectionMap.get('last_turn_summary')?.content,
|
|
92
98
|
sectionMap.get('last_turn_decisions')?.content,
|
|
93
99
|
sectionMap.get('last_turn_objections')?.content,
|
|
100
|
+
sectionMap.get('last_turn_files_changed')?.content,
|
|
101
|
+
sectionMap.get('last_turn_changed_file_previews')?.content,
|
|
94
102
|
sectionMap.get('last_turn_verification')?.content,
|
|
95
103
|
]);
|
|
96
104
|
|
|
@@ -157,6 +165,8 @@ function splitLastAcceptedTurn(lines) {
|
|
|
157
165
|
let summaryLines = [];
|
|
158
166
|
let decisionsLines = [];
|
|
159
167
|
let objectionsLines = [];
|
|
168
|
+
let filesChangedLines = [];
|
|
169
|
+
let changedFilePreviewLines = [];
|
|
160
170
|
let verificationLines = [];
|
|
161
171
|
|
|
162
172
|
let inVerification = false;
|
|
@@ -200,6 +210,20 @@ function splitLastAcceptedTurn(lines) {
|
|
|
200
210
|
continue;
|
|
201
211
|
}
|
|
202
212
|
|
|
213
|
+
if (line.startsWith('### Files Changed')) {
|
|
214
|
+
const { blockLines, nextIndex } = consumeLevel3Block(lines, index);
|
|
215
|
+
filesChangedLines = blockLines;
|
|
216
|
+
index = nextIndex - 1;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (line.startsWith('### Changed File Previews')) {
|
|
221
|
+
const { blockLines, nextIndex } = consumeLevel3Block(lines, index);
|
|
222
|
+
changedFilePreviewLines = blockLines;
|
|
223
|
+
index = nextIndex - 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
203
227
|
headerLines.push(line);
|
|
204
228
|
}
|
|
205
229
|
|
|
@@ -208,6 +232,8 @@ function splitLastAcceptedTurn(lines) {
|
|
|
208
232
|
summaryLines: trimBlankLines(summaryLines),
|
|
209
233
|
decisionsLines: trimBlankLines(decisionsLines),
|
|
210
234
|
objectionsLines: trimBlankLines(objectionsLines),
|
|
235
|
+
filesChangedLines: trimBlankLines(filesChangedLines),
|
|
236
|
+
changedFilePreviewLines: trimBlankLines(changedFilePreviewLines),
|
|
211
237
|
verificationLines: trimBlankLines(verificationLines),
|
|
212
238
|
};
|
|
213
239
|
}
|
|
@@ -232,6 +258,32 @@ function consumeIndentedBlock(lines, startIndex) {
|
|
|
232
258
|
};
|
|
233
259
|
}
|
|
234
260
|
|
|
261
|
+
function consumeLevel3Block(lines, startIndex) {
|
|
262
|
+
const blockLines = [lines[startIndex]];
|
|
263
|
+
let index = startIndex + 1;
|
|
264
|
+
let inCodeBlock = false;
|
|
265
|
+
|
|
266
|
+
while (index < lines.length) {
|
|
267
|
+
const line = lines[index];
|
|
268
|
+
|
|
269
|
+
if (line.startsWith('```')) {
|
|
270
|
+
inCodeBlock = !inCodeBlock;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (!inCodeBlock && line.startsWith('### ')) {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
blockLines.push(line);
|
|
278
|
+
index += 1;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
blockLines: trimBlankLines(blockLines),
|
|
283
|
+
nextIndex: index,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
235
287
|
function pushSection(target, id, lines) {
|
|
236
288
|
const normalizedLines = trimBlankLines(lines || []);
|
|
237
289
|
if (!normalizedLines.length) return;
|
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
} from './intake.js';
|
|
25
25
|
import { loadProjectState } from './config.js';
|
|
26
26
|
import { safeWriteJson } from './safe-write.js';
|
|
27
|
+
import { emitRunEvent } from './run-events.js';
|
|
28
|
+
import {
|
|
29
|
+
archiveStaleIntentsForRun,
|
|
30
|
+
formatLegacyIntentMigrationNotice,
|
|
31
|
+
} from './intent-startup-migration.js';
|
|
27
32
|
|
|
28
33
|
const CONTINUOUS_SESSION_PATH = '.agentxchain/continuous-session.json';
|
|
29
34
|
|
|
@@ -56,7 +61,7 @@ export function removeContinuousSession(root) {
|
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
function createSession(visionPath, maxRuns, maxIdleCycles, perSessionMaxUsd) {
|
|
64
|
+
function createSession(visionPath, maxRuns, maxIdleCycles, perSessionMaxUsd, currentRunId = null) {
|
|
60
65
|
return {
|
|
61
66
|
session_id: `cont-${randomUUID().slice(0, 8)}`,
|
|
62
67
|
started_at: new Date().toISOString(),
|
|
@@ -65,12 +70,13 @@ function createSession(visionPath, maxRuns, maxIdleCycles, perSessionMaxUsd) {
|
|
|
65
70
|
max_runs: maxRuns,
|
|
66
71
|
idle_cycles: 0,
|
|
67
72
|
max_idle_cycles: maxIdleCycles,
|
|
68
|
-
current_run_id:
|
|
73
|
+
current_run_id: currentRunId,
|
|
69
74
|
current_vision_objective: null,
|
|
70
75
|
status: 'running',
|
|
71
76
|
per_session_max_usd: perSessionMaxUsd || null,
|
|
72
77
|
cumulative_spent_usd: 0,
|
|
73
78
|
budget_exhausted: false,
|
|
79
|
+
startup_reconciled_run_id: null,
|
|
74
80
|
};
|
|
75
81
|
}
|
|
76
82
|
|
|
@@ -133,8 +139,46 @@ function buildContinuousProvenance(intentId, options = {}) {
|
|
|
133
139
|
};
|
|
134
140
|
}
|
|
135
141
|
|
|
136
|
-
export function findNextQueuedIntent(root) {
|
|
137
|
-
return findNextDispatchableIntent(root);
|
|
142
|
+
export function findNextQueuedIntent(root, options = {}) {
|
|
143
|
+
return findNextDispatchableIntent(root, { run_id: options.run_id || null });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function reconcileContinuousStartupState(context, session, contOpts, log) {
|
|
147
|
+
const { root, config } = context;
|
|
148
|
+
const governedState = loadProjectState(root, config);
|
|
149
|
+
const scopedRunId = session.current_run_id || contOpts.continueFrom || governedState?.run_id || null;
|
|
150
|
+
|
|
151
|
+
let sessionChanged = false;
|
|
152
|
+
if (scopedRunId && session.current_run_id !== scopedRunId) {
|
|
153
|
+
session.current_run_id = scopedRunId;
|
|
154
|
+
sessionChanged = true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (scopedRunId && session.startup_reconciled_run_id !== scopedRunId) {
|
|
158
|
+
const startupIntents = archiveStaleIntentsForRun(root, scopedRunId, {
|
|
159
|
+
protocolVersion: governedState?.protocol_version || config?.schema_version || '2.x',
|
|
160
|
+
});
|
|
161
|
+
if (startupIntents.archived_migration_intent_ids?.length > 0) {
|
|
162
|
+
emitRunEvent(root, 'intents_migrated', {
|
|
163
|
+
run_id: scopedRunId,
|
|
164
|
+
phase: governedState?.phase || null,
|
|
165
|
+
status: governedState?.status || 'active',
|
|
166
|
+
payload: {
|
|
167
|
+
archived_count: startupIntents.archived_migration_intent_ids.length,
|
|
168
|
+
archived_intent_ids: startupIntents.archived_migration_intent_ids,
|
|
169
|
+
reason: 'pre-BUG-34 intents with approved_run_id: null archived during continuous startup',
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
const migrationNotice = formatLegacyIntentMigrationNotice(startupIntents.archived_migration_intent_ids);
|
|
173
|
+
if (migrationNotice) log(migrationNotice);
|
|
174
|
+
}
|
|
175
|
+
session.startup_reconciled_run_id = scopedRunId;
|
|
176
|
+
sessionChanged = true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (sessionChanged) {
|
|
180
|
+
writeContinuousSession(root, session);
|
|
181
|
+
}
|
|
138
182
|
}
|
|
139
183
|
|
|
140
184
|
// ---------------------------------------------------------------------------
|
|
@@ -232,6 +276,7 @@ export function resolveContinuousOptions(opts, config) {
|
|
|
232
276
|
|
|
233
277
|
return {
|
|
234
278
|
enabled: opts.continuous ?? configCont.enabled ?? false,
|
|
279
|
+
continueFrom: opts.continueFrom ?? null,
|
|
235
280
|
visionPath: opts.vision ?? configCont.vision_path ?? '.planning/VISION.md',
|
|
236
281
|
maxRuns: opts.maxRuns ?? configCont.max_runs ?? 100,
|
|
237
282
|
pollSeconds: opts.pollSeconds ?? configCont.poll_seconds ?? 30,
|
|
@@ -288,6 +333,8 @@ export async function advanceContinuousRunOnce(context, session, contOpts, execu
|
|
|
288
333
|
return { ok: true, status: 'completed', action: 'session_budget_exhausted', stop_reason: 'session_budget' };
|
|
289
334
|
}
|
|
290
335
|
|
|
336
|
+
reconcileContinuousStartupState(context, session, contOpts, log);
|
|
337
|
+
|
|
291
338
|
// Paused-session guard: if session is paused (blocked run awaiting unblock),
|
|
292
339
|
// check governed state before attempting to advance. Without this guard, the
|
|
293
340
|
// loop would try to startIntent() on a blocked project, hit the blocked-state
|
|
@@ -540,7 +587,15 @@ export async function executeContinuousRun(context, contOpts, executeGovernedRun
|
|
|
540
587
|
return { exitCode: 1, session: null };
|
|
541
588
|
}
|
|
542
589
|
|
|
543
|
-
const
|
|
590
|
+
const startupState = loadProjectState(root, context.config);
|
|
591
|
+
const initialRunId = contOpts.continueFrom || startupState?.run_id || null;
|
|
592
|
+
const session = createSession(
|
|
593
|
+
contOpts.visionPath,
|
|
594
|
+
contOpts.maxRuns,
|
|
595
|
+
contOpts.maxIdleCycles,
|
|
596
|
+
contOpts.perSessionMaxUsd,
|
|
597
|
+
initialRunId,
|
|
598
|
+
);
|
|
544
599
|
writeContinuousSession(root, session);
|
|
545
600
|
|
|
546
601
|
// SIGINT handler
|
|
@@ -389,6 +389,20 @@ function renderPrompt(role, roleId, turn, state, config, root) {
|
|
|
389
389
|
}
|
|
390
390
|
lines.push('');
|
|
391
391
|
}
|
|
392
|
+
if (turn.conflict_context.forward_revision_files?.length) {
|
|
393
|
+
lines.push('Forward-revision files already safe to carry forward:');
|
|
394
|
+
for (const file of turn.conflict_context.forward_revision_files) {
|
|
395
|
+
lines.push(`- \`${file}\``);
|
|
396
|
+
}
|
|
397
|
+
if (turn.conflict_context.forward_revision_turns_since?.length) {
|
|
398
|
+
lines.push('');
|
|
399
|
+
lines.push('Forward-revision turns since assignment:');
|
|
400
|
+
for (const acceptedTurn of turn.conflict_context.forward_revision_turns_since) {
|
|
401
|
+
lines.push(`- \`${acceptedTurn.turn_id}\` (${acceptedTurn.role}) touched: ${acceptedTurn.files_changed.join(', ') || '(none)'}`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
lines.push('');
|
|
405
|
+
}
|
|
392
406
|
if (turn.conflict_context.non_conflicting_files_preserved?.length) {
|
|
393
407
|
lines.push('Non-conflicting files to preserve from your prior attempt:');
|
|
394
408
|
for (const file of turn.conflict_context.non_conflicting_files_preserved) {
|
|
@@ -85,6 +85,15 @@ function addMissingFile(result, filePath) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
function addFailingFile(result, filePath) {
|
|
89
|
+
if (!filePath) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!result.failing_files.includes(filePath)) {
|
|
93
|
+
result.failing_files.push(filePath);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
function prefixSemanticReason(filePath, reason) {
|
|
89
98
|
if (!reason || reason.includes(filePath)) {
|
|
90
99
|
return reason;
|
|
@@ -111,6 +120,7 @@ function evaluateGateArtifacts({ root, config, gateDef, phase, result, state })
|
|
|
111
120
|
if (!existsSync(absPath)) {
|
|
112
121
|
if (artifact.required) {
|
|
113
122
|
addMissingFile(result, artifact.path);
|
|
123
|
+
addFailingFile(result, artifact.path);
|
|
114
124
|
failures.push(`Required file missing: ${artifact.path}`);
|
|
115
125
|
}
|
|
116
126
|
continue;
|
|
@@ -119,6 +129,7 @@ function evaluateGateArtifacts({ root, config, gateDef, phase, result, state })
|
|
|
119
129
|
if (artifact.useLegacySemantics) {
|
|
120
130
|
const semanticCheck = evaluateWorkflowGateSemantics(root, artifact.path);
|
|
121
131
|
if (semanticCheck && !semanticCheck.ok) {
|
|
132
|
+
addFailingFile(result, artifact.path);
|
|
122
133
|
failures.push(semanticCheck.reason);
|
|
123
134
|
}
|
|
124
135
|
}
|
|
@@ -130,12 +141,14 @@ function evaluateGateArtifacts({ root, config, gateDef, phase, result, state })
|
|
|
130
141
|
semantics_config: semantic.semantics_config,
|
|
131
142
|
});
|
|
132
143
|
if (semanticCheck && !semanticCheck.ok) {
|
|
144
|
+
addFailingFile(result, artifact.path);
|
|
133
145
|
failures.push(prefixSemanticReason(artifact.path, semanticCheck.reason));
|
|
134
146
|
}
|
|
135
147
|
}
|
|
136
148
|
|
|
137
149
|
// Charter enforcement: verify owning role participated in this phase
|
|
138
150
|
if (artifact.owned_by && !hasRoleParticipationInPhase(state, phase, artifact.owned_by)) {
|
|
151
|
+
addFailingFile(result, artifact.path);
|
|
139
152
|
failures.push(
|
|
140
153
|
`"${artifact.path}" requires participation from role "${artifact.owned_by}" in phase "${phase}", but no accepted turn from that role was found`,
|
|
141
154
|
);
|
|
@@ -161,11 +174,12 @@ function evaluateGateArtifacts({ root, config, gateDef, phase, result, state })
|
|
|
161
174
|
* @property {boolean} blocked_by_human_approval - gate passed structurally but needs human sign-off
|
|
162
175
|
* @property {string[]} reasons - human-readable failure reasons
|
|
163
176
|
* @property {string[]} missing_files - files required by gate but not found
|
|
177
|
+
* @property {string[]} failing_files - files tied to gate failures
|
|
164
178
|
* @property {boolean} missing_verification - verification required but not passed
|
|
165
179
|
* @property {string|null} next_phase - the target phase if transition was requested and gate passed
|
|
166
180
|
* @property {string|null} transition_request - the raw phase_transition_request value
|
|
167
181
|
* @property {'no_request'|'unknown_phase'|'gate_failed'|'advance'|'awaiting_human_approval'|'no_gate'} action
|
|
168
|
-
|
|
182
|
+
*/
|
|
169
183
|
export function evaluatePhaseExit({ state, config, acceptedTurn, root }) {
|
|
170
184
|
const currentPhase = state.phase;
|
|
171
185
|
const transitionRequest = acceptedTurn.phase_transition_request || null;
|
|
@@ -176,6 +190,7 @@ export function evaluatePhaseExit({ state, config, acceptedTurn, root }) {
|
|
|
176
190
|
blocked_by_human_approval: false,
|
|
177
191
|
reasons: [],
|
|
178
192
|
missing_files: [],
|
|
193
|
+
failing_files: [],
|
|
179
194
|
missing_verification: false,
|
|
180
195
|
next_phase: null,
|
|
181
196
|
transition_request: transitionRequest,
|
|
@@ -303,6 +318,7 @@ export function evaluatePhaseExit({ state, config, acceptedTurn, root }) {
|
|
|
303
318
|
* @property {boolean} blocked_by_human_approval - gate passed structurally but needs human sign-off
|
|
304
319
|
* @property {string[]} reasons - human-readable failure reasons
|
|
305
320
|
* @property {string[]} missing_files - files required by gate but not found
|
|
321
|
+
* @property {string[]} failing_files - files tied to gate failures
|
|
306
322
|
* @property {boolean} missing_verification - verification required but not passed
|
|
307
323
|
* @property {'no_request'|'not_final_phase'|'gate_failed'|'complete'|'awaiting_human_approval'} action
|
|
308
324
|
*/
|
|
@@ -313,6 +329,7 @@ export function evaluateRunCompletion({ state, config, acceptedTurn, root }) {
|
|
|
313
329
|
blocked_by_human_approval: false,
|
|
314
330
|
reasons: [],
|
|
315
331
|
missing_files: [],
|
|
332
|
+
failing_files: [],
|
|
316
333
|
missing_verification: false,
|
|
317
334
|
action: 'no_request',
|
|
318
335
|
};
|