@ngockhoale/ukit 1.4.1 → 1.4.3
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 +26 -0
- package/package.json +1 -1
- package/src/core/runtimeConfig.js +65 -1
- package/src/index/taskRouting.js +547 -5
- package/templates/.claude/hooks/reinject-context.sh +2 -0
- package/templates/.claude/hooks/session-start.md +2 -0
- package/templates/.claude/hooks/skill-router.sh +938 -15
- package/templates/.claude/ukit/index/route-task.mjs +744 -6
- package/templates/.claude/ukit/runtime/reinject-context.mjs +136 -8
- package/templates/.codex/README.md +8 -1
- package/templates/.codex/settings.json +53 -0
- package/templates/AGENTS.md +3 -0
- package/templates/CLAUDE.md +5 -1
- package/templates/ukit/README.md +1 -1
- package/templates/ukit/storage/config.json +61 -2
|
@@ -49,6 +49,7 @@ async function main() {
|
|
|
49
49
|
const rootDir = getRootDir(args);
|
|
50
50
|
const sharedStatePath = path.join(rootDir, '.claude', 'ukit', 'skill-router-state.json');
|
|
51
51
|
const routeCachePath = path.join(rootDir, '.claude', 'ukit', 'route-cache.json');
|
|
52
|
+
const routeAuditPath = path.join(rootDir, '.ukit', 'storage', 'cache', 'route-audit.json');
|
|
52
53
|
const previousState = await readJson(sharedStatePath, {});
|
|
53
54
|
const targetFile = readFlagValue(args, '--target');
|
|
54
55
|
const taskType = readFlagValue(args, '--type');
|
|
@@ -138,13 +139,30 @@ async function main() {
|
|
|
138
139
|
requestKey,
|
|
139
140
|
});
|
|
140
141
|
if (cachedRouteState) {
|
|
142
|
+
const rescuedRouteSummary = cachedRouteState.routeSummary
|
|
143
|
+
? {
|
|
144
|
+
...cachedRouteState.routeSummary,
|
|
145
|
+
continuationState: advanceContinuationState(
|
|
146
|
+
cachedRouteState.routeSummary.continuationState ?? null,
|
|
147
|
+
cachedRouteState.routeSummary.continuationState ?? null,
|
|
148
|
+
),
|
|
149
|
+
}
|
|
150
|
+
: null;
|
|
151
|
+
if (rescuedRouteSummary) {
|
|
152
|
+
applyRescueBiasToRouteSummary(rescuedRouteSummary);
|
|
153
|
+
}
|
|
141
154
|
const sharedState = {
|
|
142
155
|
...cachedRouteState,
|
|
143
156
|
source: 'task-route',
|
|
144
157
|
ts: Date.now(),
|
|
145
158
|
requestKey,
|
|
159
|
+
routeSummary: rescuedRouteSummary,
|
|
146
160
|
};
|
|
161
|
+
sharedState.fingerprint = buildRouteStateFingerprint(sharedState);
|
|
147
162
|
await writeJson(sharedStatePath, sharedState);
|
|
163
|
+
await appendRouteAuditEntry(routeAuditPath, buildRouteAuditEntry({
|
|
164
|
+
state: sharedState,
|
|
165
|
+
}));
|
|
148
166
|
printRouteState(sharedState);
|
|
149
167
|
return;
|
|
150
168
|
}
|
|
@@ -166,6 +184,7 @@ async function main() {
|
|
|
166
184
|
useIndexedContext,
|
|
167
185
|
previousContextSnapshot,
|
|
168
186
|
recentOutputSnapshot,
|
|
187
|
+
previousRouteSummary: previousState?.routeSummary ?? null,
|
|
169
188
|
});
|
|
170
189
|
await seedHelperCaches({
|
|
171
190
|
rootDir,
|
|
@@ -182,6 +201,10 @@ async function main() {
|
|
|
182
201
|
indexGeneratedAtMs,
|
|
183
202
|
});
|
|
184
203
|
await writeJson(sharedStatePath, sharedState);
|
|
204
|
+
await appendRouteAuditEntry(routeAuditPath, buildRouteAuditEntry({
|
|
205
|
+
route,
|
|
206
|
+
state: sharedState,
|
|
207
|
+
}));
|
|
185
208
|
await writeRecentCacheEntry(routeCachePath, compactRouteCacheState(sharedState), {
|
|
186
209
|
maxEntries: DEFAULT_RECENT_CACHE_MAX_ENTRIES,
|
|
187
210
|
});
|
|
@@ -255,6 +278,28 @@ async function prepareTaskRoute({
|
|
|
255
278
|
selectedIds,
|
|
256
279
|
targetFile: normalizedTarget,
|
|
257
280
|
});
|
|
281
|
+
const executionScores = deriveExecutionScores({
|
|
282
|
+
promptText: normalizedPrompt,
|
|
283
|
+
commandText: normalizedCommand,
|
|
284
|
+
targetFile: normalizedTarget,
|
|
285
|
+
intentMode,
|
|
286
|
+
taskType: inferredTaskType,
|
|
287
|
+
});
|
|
288
|
+
const executionCandidates = buildExecutionModeCandidates({
|
|
289
|
+
promptText: normalizedPrompt,
|
|
290
|
+
commandText: normalizedCommand,
|
|
291
|
+
targetFile: normalizedTarget,
|
|
292
|
+
intentMode,
|
|
293
|
+
executionScores,
|
|
294
|
+
});
|
|
295
|
+
const executionMode = deriveExecutionMode({
|
|
296
|
+
promptText: normalizedPrompt,
|
|
297
|
+
commandText: normalizedCommand,
|
|
298
|
+
targetFile: normalizedTarget,
|
|
299
|
+
intentMode,
|
|
300
|
+
executionScores,
|
|
301
|
+
executionCandidates,
|
|
302
|
+
});
|
|
258
303
|
const preservedPrompt = normalizedPrompt || String(lastExplicitUserPromptText || '').trim();
|
|
259
304
|
|
|
260
305
|
return {
|
|
@@ -269,6 +314,9 @@ async function prepareTaskRoute({
|
|
|
269
314
|
contextIntent,
|
|
270
315
|
taskType: inferredTaskType,
|
|
271
316
|
intentMode,
|
|
317
|
+
executionScores,
|
|
318
|
+
executionCandidates,
|
|
319
|
+
executionMode,
|
|
272
320
|
},
|
|
273
321
|
};
|
|
274
322
|
}
|
|
@@ -283,6 +331,7 @@ async function finalizeTaskRoute({
|
|
|
283
331
|
useIndexedContext = true,
|
|
284
332
|
previousContextSnapshot = null,
|
|
285
333
|
recentOutputSnapshot = null,
|
|
334
|
+
previousRouteSummary = null,
|
|
286
335
|
} = {}) {
|
|
287
336
|
const absoluteRoot = path.resolve(rootDir);
|
|
288
337
|
const activeSkills = preparedRoute?.activeSkills ?? [];
|
|
@@ -347,10 +396,17 @@ async function finalizeTaskRoute({
|
|
|
347
396
|
verificationRecommendation,
|
|
348
397
|
nextAction,
|
|
349
398
|
});
|
|
399
|
+
routeSummary.continuationState = advanceContinuationState(
|
|
400
|
+
routeSummary.continuationState,
|
|
401
|
+
previousRouteSummary?.continuationState ?? null,
|
|
402
|
+
);
|
|
403
|
+
applyRescueBiasToRouteSummary(routeSummary);
|
|
404
|
+
const approachSelector = routeSummary?.approachSelector ?? null;
|
|
350
405
|
|
|
351
406
|
return {
|
|
352
407
|
activeSkills,
|
|
353
408
|
routingContext,
|
|
409
|
+
approachSelector,
|
|
354
410
|
previousContext: previousContextSnapshot,
|
|
355
411
|
recentOutput: recentOutputSnapshot,
|
|
356
412
|
contextRecommendation,
|
|
@@ -445,7 +501,11 @@ function formatDisplayNextAction(routeSummary = null) {
|
|
|
445
501
|
}
|
|
446
502
|
|
|
447
503
|
const nextActionType = String(routeSummary.nextActionType ?? '').trim();
|
|
448
|
-
if (
|
|
504
|
+
if (
|
|
505
|
+
!nextActionType
|
|
506
|
+
|| nextActionType === 'read-skill-instructions'
|
|
507
|
+
|| nextActionType === 'pull-indexed-context'
|
|
508
|
+
) {
|
|
449
509
|
return '';
|
|
450
510
|
}
|
|
451
511
|
|
|
@@ -492,6 +552,10 @@ function formatDisplayHelperHint(routeSummary = null, compactSummary = '') {
|
|
|
492
552
|
return '';
|
|
493
553
|
}
|
|
494
554
|
|
|
555
|
+
if (String(routeSummary.nextActionType ?? '').trim() === 'pull-indexed-context') {
|
|
556
|
+
return '';
|
|
557
|
+
}
|
|
558
|
+
|
|
495
559
|
let helperHint = String(routeSummary.helperHint ?? '').trim().replace(/\s+/g, ' ');
|
|
496
560
|
if (!helperHint) {
|
|
497
561
|
return '';
|
|
@@ -671,6 +735,10 @@ function shouldKeepRouteEntryForIntent(entry, intentMode) {
|
|
|
671
735
|
return false;
|
|
672
736
|
}
|
|
673
737
|
|
|
738
|
+
if (entry.id === 'code-review' && intentMode === 'implement-specific') {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
|
|
674
742
|
return true;
|
|
675
743
|
}
|
|
676
744
|
|
|
@@ -710,6 +778,10 @@ function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
|
710
778
|
routeSignals.commandRawText ?? '',
|
|
711
779
|
routeSignals.commandNormalizedText ?? '',
|
|
712
780
|
].join('\n');
|
|
781
|
+
const rawPromptSignals = [
|
|
782
|
+
routeSignals.promptRawText ?? '',
|
|
783
|
+
routeSignals.commandRawText ?? '',
|
|
784
|
+
].join('\n');
|
|
713
785
|
|
|
714
786
|
if (
|
|
715
787
|
skillId === 'testing-quality'
|
|
@@ -718,6 +790,14 @@ function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
|
718
790
|
return 1;
|
|
719
791
|
}
|
|
720
792
|
|
|
793
|
+
if (
|
|
794
|
+
skillId === 'code-review'
|
|
795
|
+
&& /\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(rawPromptSignals)
|
|
796
|
+
&& !/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(rawPromptSignals)
|
|
797
|
+
) {
|
|
798
|
+
return -4;
|
|
799
|
+
}
|
|
800
|
+
|
|
721
801
|
return 0;
|
|
722
802
|
}
|
|
723
803
|
|
|
@@ -768,13 +848,13 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
|
|
|
768
848
|
}
|
|
769
849
|
|
|
770
850
|
if (concreteTask) {
|
|
771
|
-
if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|
|
|
851
|
+
if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|timeout)\b/.test(lower)) {
|
|
772
852
|
return 'debug-specific';
|
|
773
853
|
}
|
|
774
|
-
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(
|
|
854
|
+
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(raw)) {
|
|
775
855
|
return 'review-specific';
|
|
776
856
|
}
|
|
777
|
-
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature)\b/.test(
|
|
857
|
+
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(raw)) {
|
|
778
858
|
return 'implement-specific';
|
|
779
859
|
}
|
|
780
860
|
}
|
|
@@ -806,7 +886,7 @@ function hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext = false }
|
|
|
806
886
|
return true;
|
|
807
887
|
}
|
|
808
888
|
|
|
809
|
-
return /\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|review|audit|diff|pr feedback|code review|auth|login|api|endpoint|test|spec)\b/.test(lower)
|
|
889
|
+
return /\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply|review|audit|diff|pr feedback|code review|auth|login|api|endpoint|test|spec)\b/.test(lower)
|
|
810
890
|
|| /\b(sửa|fix|lỗi|bug|debug|implement|cài|thêm|review|kiểm tra|soát|đăng nhập)\b/.test(raw);
|
|
811
891
|
}
|
|
812
892
|
|
|
@@ -1225,6 +1305,23 @@ function buildRouteSummary({
|
|
|
1225
1305
|
const compactHelperLane = nextAction?.type === 'pull-indexed-context'
|
|
1226
1306
|
&& typeof contextRecommendation?.command === 'string'
|
|
1227
1307
|
&& contextRecommendation.command.trim();
|
|
1308
|
+
const executionMode = routingContext.executionMode ?? null;
|
|
1309
|
+
const executionScores = routingContext.executionScores ?? null;
|
|
1310
|
+
const executionCandidates = routingContext.executionCandidates ?? null;
|
|
1311
|
+
const approachSelector = buildApproachSelectorResult({
|
|
1312
|
+
executionMode,
|
|
1313
|
+
executionScores,
|
|
1314
|
+
executionCandidates,
|
|
1315
|
+
});
|
|
1316
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
1317
|
+
const completionState = buildCompletionState({
|
|
1318
|
+
executionMode,
|
|
1319
|
+
verificationRecommendation,
|
|
1320
|
+
});
|
|
1321
|
+
const continuationState = buildContinuationState({
|
|
1322
|
+
nextActionType: nextAction?.type ?? null,
|
|
1323
|
+
completionState,
|
|
1324
|
+
});
|
|
1228
1325
|
const helperHint = compactHelperHint(
|
|
1229
1326
|
compactHelperLane
|
|
1230
1327
|
? contextRecommendation?.command
|
|
@@ -1243,7 +1340,6 @@ function buildRouteSummary({
|
|
|
1243
1340
|
editGuardHint ? `editGuard=${editGuardHint}` : null,
|
|
1244
1341
|
delegationRecommendation?.hint ? `delegate=${delegationRecommendation.hint}` : null,
|
|
1245
1342
|
policyMode ? `policy=${policyMode}` : null,
|
|
1246
|
-
contextMode ? `mode=${contextMode}` : null,
|
|
1247
1343
|
].filter(Boolean).join(' | ');
|
|
1248
1344
|
|
|
1249
1345
|
return {
|
|
@@ -1252,6 +1348,13 @@ function buildRouteSummary({
|
|
|
1252
1348
|
preferredOrder,
|
|
1253
1349
|
policyMode,
|
|
1254
1350
|
editGuardHint,
|
|
1351
|
+
executionMode,
|
|
1352
|
+
executionScores,
|
|
1353
|
+
executionCandidates,
|
|
1354
|
+
approachSelector,
|
|
1355
|
+
executionContract,
|
|
1356
|
+
completionState,
|
|
1357
|
+
continuationState,
|
|
1255
1358
|
intentMode: routingContext.intentMode ?? null,
|
|
1256
1359
|
delegateHint: delegationRecommendation?.hint ?? null,
|
|
1257
1360
|
nextActionType: nextAction?.type ?? null,
|
|
@@ -1268,6 +1371,559 @@ function deriveContextMode(taskType) {
|
|
|
1268
1371
|
return null;
|
|
1269
1372
|
}
|
|
1270
1373
|
|
|
1374
|
+
function deriveExecutionScores({
|
|
1375
|
+
promptText = '',
|
|
1376
|
+
commandText = '',
|
|
1377
|
+
targetFile = null,
|
|
1378
|
+
intentMode = null,
|
|
1379
|
+
taskType = null,
|
|
1380
|
+
} = {}) {
|
|
1381
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
1382
|
+
const sharedRisk = isSharedImpactFile(targetFile);
|
|
1383
|
+
const directTransformSignal = /\b(change|replace|set|rename|convert|swap)\b/.test(raw) || /\bchange\s+.+\s+to\s+.+\b/.test(raw);
|
|
1384
|
+
const smallFixSignal = /\b(adjust|tweak|patch|fix|modify|update|apply)\b/.test(raw);
|
|
1385
|
+
const buildSignal = /\b(build|create|add|implement|feature)\b/.test(raw);
|
|
1386
|
+
const debugSignal = intentMode === 'debug-specific' || /\b(root cause|debug|triage|flaky|investigate|why)\b/.test(raw);
|
|
1387
|
+
const reviewSignal = intentMode === 'review-specific' || /\b(review|audit|verify|release readiness)\b/.test(raw);
|
|
1388
|
+
const failureSignal = /\b(failing|failed|broken|error|crash|timeout|undefined|exception|eacces|trace)\b/.test(raw);
|
|
1389
|
+
const impactSignal = /\b(map impact|impact|blast radius|all affected|across (?:runtime|templates|helpers|adapters|mirrors)|affected adapters|affected mirrors|inspect impact)\b/.test(raw);
|
|
1390
|
+
const boundedEditSignal = /\b(one[- ]line|small|tiny|single|local|guard|log line|loading message|label)\b/.test(raw);
|
|
1391
|
+
const implementSignal = /\b(implement|apply|update|modify|add|create|ship|deliver|fix)\b/.test(raw)
|
|
1392
|
+
|| /\bchange\s+.+\s+to\s+.+\b/.test(raw);
|
|
1393
|
+
const explicitTarget = Boolean(targetFile);
|
|
1394
|
+
|
|
1395
|
+
let editCertainty = 0;
|
|
1396
|
+
if (directTransformSignal) {
|
|
1397
|
+
editCertainty = 3;
|
|
1398
|
+
} else if (smallFixSignal) {
|
|
1399
|
+
editCertainty = 2;
|
|
1400
|
+
} else if (buildSignal) {
|
|
1401
|
+
editCertainty = 1;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
let investigationNeed = 0;
|
|
1405
|
+
if (debugSignal) {
|
|
1406
|
+
investigationNeed = 3;
|
|
1407
|
+
} else if (failureSignal) {
|
|
1408
|
+
investigationNeed = 2;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
let blastRadius = 0;
|
|
1412
|
+
if (sharedRisk) {
|
|
1413
|
+
blastRadius = 3;
|
|
1414
|
+
} else if (taskType === 'non-trivial' || taskType === 'shared-simple') {
|
|
1415
|
+
blastRadius = 2;
|
|
1416
|
+
} else if (!targetFile) {
|
|
1417
|
+
blastRadius = 1;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
let verificationBurden = 1;
|
|
1421
|
+
if (reviewSignal || sharedRisk) {
|
|
1422
|
+
verificationBurden = 3;
|
|
1423
|
+
} else if (debugSignal || taskType === 'non-trivial') {
|
|
1424
|
+
verificationBurden = 2;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
let ambiguity = 0;
|
|
1428
|
+
if (!targetFile) {
|
|
1429
|
+
ambiguity = 2;
|
|
1430
|
+
} else if (buildSignal && !directTransformSignal && !smallFixSignal) {
|
|
1431
|
+
ambiguity = 1;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
return {
|
|
1435
|
+
editCertainty,
|
|
1436
|
+
investigationNeed,
|
|
1437
|
+
blastRadius,
|
|
1438
|
+
verificationBurden,
|
|
1439
|
+
ambiguity,
|
|
1440
|
+
sharedRisk,
|
|
1441
|
+
directTransformSignal,
|
|
1442
|
+
smallFixSignal,
|
|
1443
|
+
buildSignal,
|
|
1444
|
+
debugSignal,
|
|
1445
|
+
reviewSignal,
|
|
1446
|
+
failureSignal,
|
|
1447
|
+
impactSignal,
|
|
1448
|
+
boundedEditSignal,
|
|
1449
|
+
implementSignal,
|
|
1450
|
+
explicitTarget,
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
function deriveExecutionMode({
|
|
1455
|
+
promptText = '',
|
|
1456
|
+
commandText = '',
|
|
1457
|
+
targetFile = null,
|
|
1458
|
+
intentMode = null,
|
|
1459
|
+
executionScores = {},
|
|
1460
|
+
executionCandidates = null,
|
|
1461
|
+
} = {}) {
|
|
1462
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
1463
|
+
const scores = executionScores;
|
|
1464
|
+
const candidates = executionCandidates ?? buildExecutionModeCandidates({
|
|
1465
|
+
promptText,
|
|
1466
|
+
commandText,
|
|
1467
|
+
targetFile,
|
|
1468
|
+
intentMode,
|
|
1469
|
+
executionScores,
|
|
1470
|
+
});
|
|
1471
|
+
const explicitReviewLead = /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw);
|
|
1472
|
+
const strongImpactLead = scores.sharedRisk
|
|
1473
|
+
&& (scores.impactSignal || /\b(check all affected|map all affected|across all affected)\b/.test(raw));
|
|
1474
|
+
const boundedLocalBuildCandidate = scores.buildSignal && scores.boundedEditSignal && scores.explicitTarget && !scores.sharedRisk;
|
|
1475
|
+
|
|
1476
|
+
if ((intentMode === 'review-specific' || explicitReviewLead) && !scores.implementSignal) {
|
|
1477
|
+
return 'review-release';
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
if (strongImpactLead || (scores.blastRadius >= 3 && (scores.ambiguity >= 2 || scores.investigationNeed >= 2))) {
|
|
1481
|
+
return 'map-impact';
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
if (scores.sharedRisk && scores.failureSignal && scores.investigationNeed >= 2 && !scores.impactSignal) {
|
|
1485
|
+
return 'shared-edit';
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
if (scores.blastRadius >= 3 || scores.sharedRisk) {
|
|
1489
|
+
return 'shared-edit';
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
if (scores.investigationNeed >= 3 || (scores.failureSignal && scores.investigationNeed >= 2)) {
|
|
1493
|
+
return 'find-cause';
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
if (scores.directTransformSignal && !scores.explicitTarget && scores.investigationNeed === 0 && !scores.sharedRisk) {
|
|
1497
|
+
return 'local-build';
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
if (
|
|
1501
|
+
scores.editCertainty >= 3
|
|
1502
|
+
&& scores.ambiguity <= 1
|
|
1503
|
+
&& scores.blastRadius === 0
|
|
1504
|
+
&& scores.verificationBurden <= 1
|
|
1505
|
+
) {
|
|
1506
|
+
return 'tiny-fix';
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
if (boundedLocalBuildCandidate && scores.investigationNeed === 0) {
|
|
1510
|
+
return 'local-fix';
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
if (
|
|
1514
|
+
/\b(build|create|add|implement|feature|summary card)\b/.test(raw)
|
|
1515
|
+
&& scores.investigationNeed === 0
|
|
1516
|
+
&& scores.blastRadius < 3
|
|
1517
|
+
&& !scores.boundedEditSignal
|
|
1518
|
+
) {
|
|
1519
|
+
return 'local-build';
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
if (scores.editCertainty >= 2 && scores.investigationNeed === 0 && scores.blastRadius === 0) {
|
|
1523
|
+
return 'local-fix';
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
return applySafeUpwardBias(candidates, 'local-build');
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
function buildExecutionModeCandidates({
|
|
1530
|
+
promptText = '',
|
|
1531
|
+
commandText = '',
|
|
1532
|
+
targetFile = null,
|
|
1533
|
+
intentMode = null,
|
|
1534
|
+
executionScores = {},
|
|
1535
|
+
} = {}) {
|
|
1536
|
+
const scores = executionScores;
|
|
1537
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
1538
|
+
const explicitReviewLead = (intentMode === 'review-specific' || /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw))
|
|
1539
|
+
&& !scores.implementSignal;
|
|
1540
|
+
|
|
1541
|
+
const modeScores = {
|
|
1542
|
+
'tiny-fix': (
|
|
1543
|
+
(scores.editCertainty * 4)
|
|
1544
|
+
+ (scores.directTransformSignal ? 4 : 0)
|
|
1545
|
+
+ (scores.explicitTarget ? 1 : 0)
|
|
1546
|
+
- (scores.failureSignal ? 4 : 0)
|
|
1547
|
+
- (scores.blastRadius * 4)
|
|
1548
|
+
- (scores.ambiguity * 2)
|
|
1549
|
+
),
|
|
1550
|
+
'local-fix': (
|
|
1551
|
+
(scores.editCertainty * 3)
|
|
1552
|
+
+ (scores.boundedEditSignal ? 3 : 0)
|
|
1553
|
+
+ (scores.explicitTarget ? 1 : 0)
|
|
1554
|
+
- (scores.failureSignal ? 2 : 0)
|
|
1555
|
+
- (scores.blastRadius * 4)
|
|
1556
|
+
),
|
|
1557
|
+
'local-build': (
|
|
1558
|
+
(scores.buildSignal ? 6 : 0)
|
|
1559
|
+
+ (scores.editCertainty * 1)
|
|
1560
|
+
+ (scores.explicitTarget ? 1 : 0)
|
|
1561
|
+
- (scores.boundedEditSignal ? 3 : 0)
|
|
1562
|
+
- (scores.failureSignal ? 3 : 0)
|
|
1563
|
+
- (scores.blastRadius * 4)
|
|
1564
|
+
),
|
|
1565
|
+
'find-cause': (
|
|
1566
|
+
(scores.investigationNeed * 4)
|
|
1567
|
+
+ (scores.failureSignal ? 3 : 0)
|
|
1568
|
+
+ (scores.debugSignal ? 2 : 0)
|
|
1569
|
+
- (scores.blastRadius >= 3 ? 1 : 0)
|
|
1570
|
+
),
|
|
1571
|
+
'shared-edit': (
|
|
1572
|
+
(scores.sharedRisk ? 8 : 0)
|
|
1573
|
+
+ (scores.editCertainty * 1)
|
|
1574
|
+
+ (scores.buildSignal ? 1 : 0)
|
|
1575
|
+
- (scores.impactSignal ? 2 : 0)
|
|
1576
|
+
),
|
|
1577
|
+
'map-impact': (
|
|
1578
|
+
(scores.sharedRisk ? 7 : 0)
|
|
1579
|
+
+ (scores.impactSignal ? 5 : 0)
|
|
1580
|
+
+ (scores.ambiguity * 2)
|
|
1581
|
+
+ scores.investigationNeed
|
|
1582
|
+
),
|
|
1583
|
+
'review-release': (
|
|
1584
|
+
(explicitReviewLead ? 10 : 0)
|
|
1585
|
+
+ (scores.reviewSignal ? 3 : 0)
|
|
1586
|
+
- (scores.implementSignal ? 5 : 0)
|
|
1587
|
+
),
|
|
1588
|
+
};
|
|
1589
|
+
|
|
1590
|
+
return Object.entries(modeScores)
|
|
1591
|
+
.map(([mode, score]) => ({ mode, score }))
|
|
1592
|
+
.sort((a, b) => b.score - a.score || executionModeRank(a.mode) - executionModeRank(b.mode));
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
function applySafeUpwardBias(candidates = [], fallbackMode = 'local-build') {
|
|
1596
|
+
const [topCandidate, competingCandidate] = candidates;
|
|
1597
|
+
if (!topCandidate) {
|
|
1598
|
+
return fallbackMode;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
if (!competingCandidate) {
|
|
1602
|
+
return topCandidate.mode;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
const scoreGap = Number(topCandidate.score ?? 0) - Number(competingCandidate.score ?? 0);
|
|
1606
|
+
const rankGap = executionModeRank(competingCandidate.mode) - executionModeRank(topCandidate.mode);
|
|
1607
|
+
if (scoreGap <= 1 && rankGap === 1) {
|
|
1608
|
+
return competingCandidate.mode;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
return topCandidate.mode;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
function executionModeRank(mode = '') {
|
|
1615
|
+
const orderedModes = [
|
|
1616
|
+
'tiny-fix',
|
|
1617
|
+
'local-fix',
|
|
1618
|
+
'local-build',
|
|
1619
|
+
'find-cause',
|
|
1620
|
+
'shared-edit',
|
|
1621
|
+
'map-impact',
|
|
1622
|
+
'review-release',
|
|
1623
|
+
];
|
|
1624
|
+
|
|
1625
|
+
const index = orderedModes.indexOf(mode);
|
|
1626
|
+
return index >= 0 ? index : orderedModes.length;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
function buildExecutionContract(executionMode = null) {
|
|
1630
|
+
if (!executionMode) {
|
|
1631
|
+
return null;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
const contracts = {
|
|
1635
|
+
'tiny-fix': {
|
|
1636
|
+
maxReadPasses: 0,
|
|
1637
|
+
maxContextPulls: 0,
|
|
1638
|
+
verificationPolicy: 'minimal-or-targeted',
|
|
1639
|
+
completionRule: 'never-claim-done-without-write',
|
|
1640
|
+
delegationPolicy: 'disallow',
|
|
1641
|
+
completionEvidence: ['write-evidence'],
|
|
1642
|
+
},
|
|
1643
|
+
'local-fix': {
|
|
1644
|
+
maxReadPasses: 1,
|
|
1645
|
+
maxContextPulls: 1,
|
|
1646
|
+
verificationPolicy: 'targeted-if-covered',
|
|
1647
|
+
completionRule: 'require-write',
|
|
1648
|
+
delegationPolicy: 'disallow',
|
|
1649
|
+
completionEvidence: ['write-evidence'],
|
|
1650
|
+
},
|
|
1651
|
+
'local-build': {
|
|
1652
|
+
maxReadPasses: 2,
|
|
1653
|
+
maxContextPulls: 1,
|
|
1654
|
+
verificationPolicy: 'targeted-if-covered',
|
|
1655
|
+
completionRule: 'require-write',
|
|
1656
|
+
delegationPolicy: 'disallow-by-default',
|
|
1657
|
+
completionEvidence: ['write-evidence'],
|
|
1658
|
+
},
|
|
1659
|
+
'find-cause': {
|
|
1660
|
+
maxReadPassesBeforeReassess: 3,
|
|
1661
|
+
verificationPolicy: 'root-cause-then-targeted',
|
|
1662
|
+
completionRule: 'never-claim-fixed-without-write-and-verification',
|
|
1663
|
+
delegationPolicy: 'allow-specialized-debug-lane',
|
|
1664
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
1665
|
+
},
|
|
1666
|
+
'shared-edit': {
|
|
1667
|
+
maxReadPasses: 2,
|
|
1668
|
+
maxContextPulls: 2,
|
|
1669
|
+
verificationPolicy: 'targeted-then-widen-on-risk',
|
|
1670
|
+
completionRule: 'require-write-and-verification',
|
|
1671
|
+
delegationPolicy: 'allow-qualified-sidecar',
|
|
1672
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
1673
|
+
mirrorConsistencyRequired: true,
|
|
1674
|
+
},
|
|
1675
|
+
'map-impact': {
|
|
1676
|
+
maxReadPasses: 3,
|
|
1677
|
+
maxContextPulls: 3,
|
|
1678
|
+
verificationPolicy: 'impact-first-then-targeted-then-widen-on-risk',
|
|
1679
|
+
completionRule: 'require-impact-evidence-before-edit-claim',
|
|
1680
|
+
delegationPolicy: 'allow-impact-sidecar',
|
|
1681
|
+
completionEvidence: ['impact-evidence', 'write-evidence', 'verification-evidence'],
|
|
1682
|
+
mirrorConsistencyRequired: true,
|
|
1683
|
+
},
|
|
1684
|
+
'review-release': {
|
|
1685
|
+
verificationPolicy: 'evidence-first',
|
|
1686
|
+
completionRule: 'report-findings-not-implementation',
|
|
1687
|
+
delegationPolicy: 'allow-review-sidecar',
|
|
1688
|
+
completionEvidence: ['verification-evidence'],
|
|
1689
|
+
},
|
|
1690
|
+
};
|
|
1691
|
+
|
|
1692
|
+
return contracts[executionMode] ? { ...contracts[executionMode] } : null;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
function buildApproachSelectorResult({
|
|
1696
|
+
executionMode = null,
|
|
1697
|
+
executionScores = null,
|
|
1698
|
+
executionCandidates = null,
|
|
1699
|
+
} = {}) {
|
|
1700
|
+
if (!executionMode) {
|
|
1701
|
+
return null;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
1705
|
+
const policyByMode = {
|
|
1706
|
+
'tiny-fix': {
|
|
1707
|
+
riskLevel: 'minimal',
|
|
1708
|
+
contextPolicy: 'confirm-target-only',
|
|
1709
|
+
},
|
|
1710
|
+
'local-fix': {
|
|
1711
|
+
riskLevel: 'local',
|
|
1712
|
+
contextPolicy: 'bounded-local',
|
|
1713
|
+
},
|
|
1714
|
+
'local-build': {
|
|
1715
|
+
riskLevel: 'local',
|
|
1716
|
+
contextPolicy: 'bounded-with-related-files',
|
|
1717
|
+
},
|
|
1718
|
+
'find-cause': {
|
|
1719
|
+
riskLevel: 'investigation',
|
|
1720
|
+
contextPolicy: 'trace-then-bounded-context',
|
|
1721
|
+
},
|
|
1722
|
+
'shared-edit': {
|
|
1723
|
+
riskLevel: 'shared',
|
|
1724
|
+
contextPolicy: 'bounded-with-related-tests',
|
|
1725
|
+
},
|
|
1726
|
+
'map-impact': {
|
|
1727
|
+
riskLevel: 'wide',
|
|
1728
|
+
contextPolicy: 'impact-map-first',
|
|
1729
|
+
},
|
|
1730
|
+
'review-release': {
|
|
1731
|
+
riskLevel: 'release',
|
|
1732
|
+
contextPolicy: 'evidence-review-only',
|
|
1733
|
+
},
|
|
1734
|
+
};
|
|
1735
|
+
const selectedPolicy = policyByMode[executionMode] ?? {
|
|
1736
|
+
riskLevel: 'local',
|
|
1737
|
+
contextPolicy: 'bounded-local',
|
|
1738
|
+
};
|
|
1739
|
+
|
|
1740
|
+
return {
|
|
1741
|
+
executionMode,
|
|
1742
|
+
executionScores: executionScores ? { ...executionScores } : null,
|
|
1743
|
+
riskLevel: selectedPolicy.riskLevel,
|
|
1744
|
+
contextPolicy: selectedPolicy.contextPolicy,
|
|
1745
|
+
verificationPolicy: executionContract?.verificationPolicy ?? null,
|
|
1746
|
+
completionRule: executionContract?.completionRule ?? null,
|
|
1747
|
+
competingMode: executionCandidates?.[1]?.mode ?? null,
|
|
1748
|
+
competingScoreGap: executionCandidates?.length >= 2
|
|
1749
|
+
? Number(executionCandidates[0]?.score ?? 0) - Number(executionCandidates[1]?.score ?? 0)
|
|
1750
|
+
: null,
|
|
1751
|
+
candidateModes: (executionCandidates ?? []).slice(0, 3).map((entry) => ({
|
|
1752
|
+
mode: entry.mode,
|
|
1753
|
+
score: entry.score,
|
|
1754
|
+
})),
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
function buildCompletionState({ executionMode = null, verificationRecommendation = null } = {}) {
|
|
1759
|
+
if (!executionMode) {
|
|
1760
|
+
return null;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
const contract = buildExecutionContract(executionMode);
|
|
1764
|
+
const missingEvidence = [...(contract?.completionEvidence ?? [])];
|
|
1765
|
+
const requiresVerification = missingEvidence.includes('verification-evidence');
|
|
1766
|
+
if (
|
|
1767
|
+
requiresVerification
|
|
1768
|
+
&& verificationRecommendation
|
|
1769
|
+
&& !(verificationRecommendation.commands?.length || verificationRecommendation.fallbackCommands?.length)
|
|
1770
|
+
) {
|
|
1771
|
+
missingEvidence.push('verification-plan');
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
let reason = 'completion evidence is still required';
|
|
1775
|
+
if (['tiny-fix', 'local-fix', 'local-build', 'shared-edit'].includes(executionMode)) {
|
|
1776
|
+
reason = 'implement request has not produced an edit yet';
|
|
1777
|
+
} else if (executionMode === 'review-release') {
|
|
1778
|
+
reason = 'review/release evidence is still required before final claim';
|
|
1779
|
+
} else if (executionMode === 'map-impact') {
|
|
1780
|
+
reason = 'impact evidence is still required before safe completion claim';
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
return {
|
|
1784
|
+
claimAllowed: false,
|
|
1785
|
+
missingEvidence,
|
|
1786
|
+
reason,
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
function buildContinuationState({
|
|
1791
|
+
nextActionType = null,
|
|
1792
|
+
completionState = null,
|
|
1793
|
+
} = {}) {
|
|
1794
|
+
const reasons = [];
|
|
1795
|
+
const missingEvidence = unique(completionState?.missingEvidence ?? []);
|
|
1796
|
+
|
|
1797
|
+
if (nextActionType === 'pull-indexed-context') {
|
|
1798
|
+
reasons.push('pending-bounded-context');
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
if (nextActionType === 'read-skill-instructions') {
|
|
1802
|
+
reasons.push('pending-skill-read');
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
if (missingEvidence.includes('write-evidence')) {
|
|
1806
|
+
reasons.push('missing-write-evidence');
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
if (missingEvidence.includes('verification-evidence') || missingEvidence.includes('verification-plan')) {
|
|
1810
|
+
reasons.push('missing-verification-evidence');
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
if (missingEvidence.includes('impact-evidence')) {
|
|
1814
|
+
reasons.push('missing-impact-evidence');
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
const nextMilestone = reasons.includes('pending-bounded-context')
|
|
1818
|
+
? 'complete-bounded-context-then-continue'
|
|
1819
|
+
: (
|
|
1820
|
+
reasons.includes('missing-write-evidence')
|
|
1821
|
+
? 'produce-write-evidence'
|
|
1822
|
+
: (
|
|
1823
|
+
reasons.includes('missing-verification-evidence')
|
|
1824
|
+
? 'produce-verification-evidence'
|
|
1825
|
+
: (
|
|
1826
|
+
reasons.includes('missing-impact-evidence')
|
|
1827
|
+
? 'produce-impact-evidence'
|
|
1828
|
+
: null
|
|
1829
|
+
)
|
|
1830
|
+
)
|
|
1831
|
+
);
|
|
1832
|
+
|
|
1833
|
+
return {
|
|
1834
|
+
required: reasons.length > 0,
|
|
1835
|
+
reasons,
|
|
1836
|
+
doneLanguageBlocked: reasons.length > 0,
|
|
1837
|
+
stopAllowedOnlyFor: reasons.length > 0 ? ['real-blocker'] : [],
|
|
1838
|
+
nextMilestone,
|
|
1839
|
+
repeatCount: reasons.length > 0 ? 1 : 0,
|
|
1840
|
+
stuckRisk: null,
|
|
1841
|
+
rescueMode: null,
|
|
1842
|
+
wideningBlocked: false,
|
|
1843
|
+
milestonePriority: reasons.length > 0 ? 'normal' : null,
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
function advanceContinuationState(continuationState = null, previousContinuationState = null) {
|
|
1848
|
+
if (!continuationState || typeof continuationState !== 'object') {
|
|
1849
|
+
return continuationState;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
if (!continuationState.required) {
|
|
1853
|
+
return {
|
|
1854
|
+
...continuationState,
|
|
1855
|
+
repeatCount: 0,
|
|
1856
|
+
stuckRisk: null,
|
|
1857
|
+
rescueMode: null,
|
|
1858
|
+
wideningBlocked: false,
|
|
1859
|
+
milestonePriority: null,
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
const currentReasons = unique(continuationState.reasons ?? []);
|
|
1864
|
+
const previousReasons = unique(previousContinuationState?.reasons ?? []);
|
|
1865
|
+
const sameMilestone = Boolean(
|
|
1866
|
+
previousContinuationState?.required
|
|
1867
|
+
&& continuationState.nextMilestone
|
|
1868
|
+
&& previousContinuationState.nextMilestone === continuationState.nextMilestone
|
|
1869
|
+
&& JSON.stringify(previousReasons) === JSON.stringify(currentReasons)
|
|
1870
|
+
);
|
|
1871
|
+
const repeatCount = sameMilestone
|
|
1872
|
+
? Math.max(1, Number(previousContinuationState?.repeatCount ?? 1) + 1)
|
|
1873
|
+
: 1;
|
|
1874
|
+
const rescueMode = repeatCount >= 2
|
|
1875
|
+
? (
|
|
1876
|
+
currentReasons.includes('pending-bounded-context')
|
|
1877
|
+
? 'finish-current-milestone-before-more-reading'
|
|
1878
|
+
: (
|
|
1879
|
+
currentReasons.includes('missing-write-evidence')
|
|
1880
|
+
? 'finish-write-before-more-analysis'
|
|
1881
|
+
: 'finish-required-milestone-before-widening'
|
|
1882
|
+
)
|
|
1883
|
+
)
|
|
1884
|
+
: null;
|
|
1885
|
+
const stuckRisk = repeatCount >= 3
|
|
1886
|
+
? 'high'
|
|
1887
|
+
: (repeatCount === 2 ? 'elevated' : null);
|
|
1888
|
+
const wideningBlocked = repeatCount >= 2 && Boolean(rescueMode);
|
|
1889
|
+
const nextMilestone = repeatCount >= 2 && currentReasons.includes('missing-write-evidence')
|
|
1890
|
+
? 'finish-write-before-more-analysis'
|
|
1891
|
+
: (
|
|
1892
|
+
repeatCount >= 2 && currentReasons.includes('pending-bounded-context')
|
|
1893
|
+
? 'finish-current-milestone-before-more-reading'
|
|
1894
|
+
: continuationState.nextMilestone
|
|
1895
|
+
);
|
|
1896
|
+
|
|
1897
|
+
return {
|
|
1898
|
+
...continuationState,
|
|
1899
|
+
nextMilestone,
|
|
1900
|
+
repeatCount,
|
|
1901
|
+
stuckRisk,
|
|
1902
|
+
rescueMode,
|
|
1903
|
+
wideningBlocked,
|
|
1904
|
+
milestonePriority: wideningBlocked ? 'execute-current-milestone' : 'normal',
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
function applyRescueBiasToRouteSummary(routeSummary = null) {
|
|
1909
|
+
if (!routeSummary || typeof routeSummary !== 'object') {
|
|
1910
|
+
return routeSummary;
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
const continuationState = routeSummary.continuationState;
|
|
1914
|
+
if (
|
|
1915
|
+
continuationState?.repeatCount >= 2
|
|
1916
|
+
&& continuationState?.wideningBlocked
|
|
1917
|
+
&& (continuationState.reasons ?? []).includes('missing-write-evidence')
|
|
1918
|
+
) {
|
|
1919
|
+
routeSummary.nextActionType = 'execute-current-milestone';
|
|
1920
|
+
routeSummary.nextActionCommand = null;
|
|
1921
|
+
routeSummary.helperHint = null;
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
return routeSummary;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1271
1927
|
function deriveExecutionPolicy({
|
|
1272
1928
|
taskType = 'simple',
|
|
1273
1929
|
mode = 'minimal',
|
|
@@ -1687,6 +2343,7 @@ function buildRouteRequestKey({
|
|
|
1687
2343
|
targetFile: routingContext.targetFile ?? '',
|
|
1688
2344
|
contextIntent: routingContext.contextIntent ?? '',
|
|
1689
2345
|
taskType: routingContext.taskType ?? '',
|
|
2346
|
+
executionMode: routingContext.executionMode ?? '',
|
|
1690
2347
|
});
|
|
1691
2348
|
}
|
|
1692
2349
|
|
|
@@ -1704,10 +2361,23 @@ function buildStructuredRouteFingerprintPayload(route = {}) {
|
|
|
1704
2361
|
previousContextIds: unique(route.previousContext?.selectedIds ?? []),
|
|
1705
2362
|
recentOutputLine: route.recentOutput?.line ?? null,
|
|
1706
2363
|
policyMode: routeSummary?.policyMode ?? null,
|
|
2364
|
+
executionMode: routeSummary?.executionMode ?? null,
|
|
2365
|
+
approachRiskLevel: routeSummary?.approachSelector?.riskLevel ?? null,
|
|
2366
|
+
approachContextPolicy: routeSummary?.approachSelector?.contextPolicy ?? null,
|
|
2367
|
+
approachVerificationPolicy: routeSummary?.approachSelector?.verificationPolicy ?? null,
|
|
2368
|
+
approachCompletionRule: routeSummary?.approachSelector?.completionRule ?? null,
|
|
2369
|
+
continuationRequired: routeSummary?.continuationState?.required ?? null,
|
|
2370
|
+
continuationReasons: unique(routeSummary?.continuationState?.reasons ?? []),
|
|
2371
|
+
continuationMilestone: routeSummary?.continuationState?.nextMilestone ?? null,
|
|
2372
|
+
continuationRepeatCount: routeSummary?.continuationState?.repeatCount ?? null,
|
|
2373
|
+
continuationStuckRisk: routeSummary?.continuationState?.stuckRisk ?? null,
|
|
2374
|
+
continuationRescueMode: routeSummary?.continuationState?.rescueMode ?? null,
|
|
1707
2375
|
delegateHint: routeSummary?.delegateHint ?? null,
|
|
1708
2376
|
nextActionType: routeSummary?.nextActionType ?? null,
|
|
1709
2377
|
nextActionCommand: routeSummary?.nextActionCommand ?? null,
|
|
1710
2378
|
helperHint: routeSummary?.helperHint ?? null,
|
|
2379
|
+
completionRule: routeSummary?.executionContract?.completionRule ?? null,
|
|
2380
|
+
completionMissingEvidence: unique(routeSummary?.completionState?.missingEvidence ?? []),
|
|
1711
2381
|
primaryCommands: unique(routeSummary?.primaryCommands ?? []),
|
|
1712
2382
|
fallbackCommands: unique(routeSummary?.fallbackCommands ?? []),
|
|
1713
2383
|
preferredOrder: unique(routeSummary?.preferredOrder ?? []),
|
|
@@ -1784,6 +2454,7 @@ function compactRoutingContext(routingContext = {}) {
|
|
|
1784
2454
|
lastExplicitUserPromptText: routingContext.lastExplicitUserPromptText ?? '',
|
|
1785
2455
|
taskType: routingContext.taskType ?? null,
|
|
1786
2456
|
intentMode: routingContext.intentMode ?? null,
|
|
2457
|
+
executionMode: routingContext.executionMode ?? null,
|
|
1787
2458
|
};
|
|
1788
2459
|
}
|
|
1789
2460
|
|
|
@@ -1846,6 +2517,12 @@ function compactRouteSummary(routeSummary = null) {
|
|
|
1846
2517
|
fallbackCommands: unique(routeSummary.fallbackCommands ?? []).slice(0, 3),
|
|
1847
2518
|
preferredOrder: unique(routeSummary.preferredOrder ?? []).slice(0, 5),
|
|
1848
2519
|
policyMode: routeSummary.policyMode ?? null,
|
|
2520
|
+
executionMode: routeSummary.executionMode ?? null,
|
|
2521
|
+
executionScores: routeSummary.executionScores ?? null,
|
|
2522
|
+
approachSelector: routeSummary.approachSelector ?? null,
|
|
2523
|
+
executionContract: routeSummary.executionContract ?? null,
|
|
2524
|
+
completionState: routeSummary.completionState ?? null,
|
|
2525
|
+
continuationState: routeSummary.continuationState ?? null,
|
|
1849
2526
|
delegateHint: routeSummary.delegateHint ?? null,
|
|
1850
2527
|
nextActionType: routeSummary.nextActionType ?? null,
|
|
1851
2528
|
nextActionCommand: routeSummary.nextActionCommand ?? null,
|
|
@@ -1898,6 +2575,67 @@ function shouldIncludeRecentOutput({
|
|
|
1898
2575
|
return true;
|
|
1899
2576
|
}
|
|
1900
2577
|
|
|
2578
|
+
function buildRouteAuditEntry({ route = null, state = null } = {}) {
|
|
2579
|
+
const routingContext = route?.routingContext ?? state?.routingContext ?? {};
|
|
2580
|
+
const routeSummary = route?.routeSummary ?? state?.routeSummary ?? {};
|
|
2581
|
+
const candidateModes = Array.isArray(routeSummary?.approachSelector?.candidateModes)
|
|
2582
|
+
? routeSummary.approachSelector.candidateModes
|
|
2583
|
+
: [];
|
|
2584
|
+
|
|
2585
|
+
return {
|
|
2586
|
+
ts: Date.now(),
|
|
2587
|
+
source: state?.source ?? 'task-route',
|
|
2588
|
+
requestKey: state?.requestKey ?? null,
|
|
2589
|
+
adapter: routingContext.adapter ?? 'claude',
|
|
2590
|
+
promptFingerprint: stableMachineDigest({
|
|
2591
|
+
prompt: routingContext.lastExplicitUserPromptText ?? '',
|
|
2592
|
+
adapter: routingContext.adapter ?? 'claude',
|
|
2593
|
+
}),
|
|
2594
|
+
targetFile: route?.routingContext?.targetFile ?? null,
|
|
2595
|
+
taskType: routingContext.taskType ?? null,
|
|
2596
|
+
executionMode: routeSummary.executionMode ?? null,
|
|
2597
|
+
competingMode: routeSummary?.approachSelector?.competingMode ?? null,
|
|
2598
|
+
competingScoreGap: routeSummary?.approachSelector?.competingScoreGap ?? null,
|
|
2599
|
+
candidateModes: candidateModes.slice(0, 3),
|
|
2600
|
+
nextActionType: routeSummary.nextActionType ?? null,
|
|
2601
|
+
nextMilestone: routeSummary?.continuationState?.nextMilestone ?? null,
|
|
2602
|
+
repeatCount: routeSummary?.continuationState?.repeatCount ?? null,
|
|
2603
|
+
rescueMode: routeSummary?.continuationState?.rescueMode ?? null,
|
|
2604
|
+
wideningBlocked: routeSummary?.continuationState?.wideningBlocked ?? null,
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
async function appendRouteAuditEntry(filePath, entry) {
|
|
2609
|
+
if (!entry || typeof entry !== 'object') {
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
const existing = await readJson(filePath, { entries: [] });
|
|
2614
|
+
const entries = Array.isArray(existing?.entries) ? existing.entries : [];
|
|
2615
|
+
const dedupeKey = stableMachineDigest({
|
|
2616
|
+
requestKey: entry.requestKey,
|
|
2617
|
+
executionMode: entry.executionMode,
|
|
2618
|
+
nextActionType: entry.nextActionType,
|
|
2619
|
+
nextMilestone: entry.nextMilestone,
|
|
2620
|
+
repeatCount: entry.repeatCount,
|
|
2621
|
+
rescueMode: entry.rescueMode,
|
|
2622
|
+
});
|
|
2623
|
+
const filtered = entries.filter((item) => {
|
|
2624
|
+
const itemKey = stableMachineDigest({
|
|
2625
|
+
requestKey: item?.requestKey ?? null,
|
|
2626
|
+
executionMode: item?.executionMode ?? null,
|
|
2627
|
+
nextActionType: item?.nextActionType ?? null,
|
|
2628
|
+
nextMilestone: item?.nextMilestone ?? null,
|
|
2629
|
+
repeatCount: item?.repeatCount ?? null,
|
|
2630
|
+
rescueMode: item?.rescueMode ?? null,
|
|
2631
|
+
});
|
|
2632
|
+
return itemKey !== dedupeKey;
|
|
2633
|
+
});
|
|
2634
|
+
await writeJson(filePath, {
|
|
2635
|
+
entries: [entry, ...filtered].slice(0, 40),
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
|
|
1901
2639
|
async function readJson(filePath, fallback = null) {
|
|
1902
2640
|
try {
|
|
1903
2641
|
return JSON.parse(await fs.readFile(filePath, 'utf8'));
|