@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
package/src/index/taskRouting.js
CHANGED
|
@@ -52,6 +52,28 @@ export async function deriveTaskRoute({
|
|
|
52
52
|
selectedIds,
|
|
53
53
|
targetFile: normalizedTarget,
|
|
54
54
|
});
|
|
55
|
+
const executionScores = deriveExecutionScores({
|
|
56
|
+
promptText: normalizedPrompt,
|
|
57
|
+
commandText: normalizedCommand,
|
|
58
|
+
targetFile: normalizedTarget,
|
|
59
|
+
intentMode,
|
|
60
|
+
taskType: inferredTaskType,
|
|
61
|
+
});
|
|
62
|
+
const executionCandidates = buildExecutionModeCandidates({
|
|
63
|
+
promptText: normalizedPrompt,
|
|
64
|
+
commandText: normalizedCommand,
|
|
65
|
+
targetFile: normalizedTarget,
|
|
66
|
+
intentMode,
|
|
67
|
+
executionScores,
|
|
68
|
+
});
|
|
69
|
+
const executionMode = deriveExecutionMode({
|
|
70
|
+
promptText: normalizedPrompt,
|
|
71
|
+
commandText: normalizedCommand,
|
|
72
|
+
targetFile: normalizedTarget,
|
|
73
|
+
intentMode,
|
|
74
|
+
executionScores,
|
|
75
|
+
executionCandidates,
|
|
76
|
+
});
|
|
55
77
|
const preservedPrompt = normalizedPrompt || String(lastExplicitUserPromptText || '').trim();
|
|
56
78
|
const degradedWarnings = [];
|
|
57
79
|
let contextResult = null;
|
|
@@ -128,11 +150,15 @@ export async function deriveTaskRoute({
|
|
|
128
150
|
taskType: inferredTaskType,
|
|
129
151
|
intentMode,
|
|
130
152
|
autonomyLevel,
|
|
153
|
+
executionScores,
|
|
154
|
+
executionCandidates,
|
|
155
|
+
executionMode,
|
|
131
156
|
},
|
|
132
157
|
contextRecommendation,
|
|
133
158
|
verificationRecommendation,
|
|
134
159
|
nextAction,
|
|
135
160
|
});
|
|
161
|
+
const approachSelector = routeSummary?.approachSelector ?? null;
|
|
136
162
|
|
|
137
163
|
return {
|
|
138
164
|
activeSkills,
|
|
@@ -145,7 +171,11 @@ export async function deriveTaskRoute({
|
|
|
145
171
|
taskType: inferredTaskType,
|
|
146
172
|
intentMode,
|
|
147
173
|
autonomyLevel,
|
|
174
|
+
executionScores,
|
|
175
|
+
executionCandidates,
|
|
176
|
+
executionMode,
|
|
148
177
|
},
|
|
178
|
+
approachSelector,
|
|
149
179
|
contextRecommendation,
|
|
150
180
|
verificationRecommendation,
|
|
151
181
|
nextAction,
|
|
@@ -186,6 +216,23 @@ export function buildRouteSummary({
|
|
|
186
216
|
const compactHelperLane = nextAction?.type === 'pull-indexed-context'
|
|
187
217
|
&& typeof contextRecommendation?.command === 'string'
|
|
188
218
|
&& contextRecommendation.command.trim();
|
|
219
|
+
const executionMode = routingContext.executionMode ?? null;
|
|
220
|
+
const executionScores = routingContext.executionScores ?? null;
|
|
221
|
+
const executionCandidates = routingContext.executionCandidates ?? null;
|
|
222
|
+
const approachSelector = buildApproachSelectorResult({
|
|
223
|
+
executionMode,
|
|
224
|
+
executionScores,
|
|
225
|
+
executionCandidates,
|
|
226
|
+
});
|
|
227
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
228
|
+
const completionState = buildCompletionState({
|
|
229
|
+
executionMode,
|
|
230
|
+
verificationRecommendation,
|
|
231
|
+
});
|
|
232
|
+
const continuationState = buildContinuationState({
|
|
233
|
+
nextActionType: nextAction?.type ?? null,
|
|
234
|
+
completionState,
|
|
235
|
+
});
|
|
189
236
|
const helperHint = compactHelperHint(
|
|
190
237
|
compactHelperLane
|
|
191
238
|
? contextRecommendation?.command
|
|
@@ -204,7 +251,6 @@ export function buildRouteSummary({
|
|
|
204
251
|
editGuardHint ? `editGuard=${editGuardHint}` : null,
|
|
205
252
|
delegationRecommendation?.hint ? `delegate=${delegationRecommendation.hint}` : null,
|
|
206
253
|
policyMode ? `policy=${policyMode}` : null,
|
|
207
|
-
contextMode ? `mode=${contextMode}` : null,
|
|
208
254
|
].filter(Boolean).join(' | ');
|
|
209
255
|
|
|
210
256
|
return {
|
|
@@ -213,6 +259,13 @@ export function buildRouteSummary({
|
|
|
213
259
|
preferredOrder,
|
|
214
260
|
policyMode,
|
|
215
261
|
editGuardHint,
|
|
262
|
+
executionMode,
|
|
263
|
+
executionScores,
|
|
264
|
+
executionCandidates,
|
|
265
|
+
approachSelector,
|
|
266
|
+
executionContract,
|
|
267
|
+
completionState,
|
|
268
|
+
continuationState,
|
|
216
269
|
intentMode: routingContext.intentMode ?? null,
|
|
217
270
|
delegateHint: delegationRecommendation?.hint ?? null,
|
|
218
271
|
nextActionType: nextAction?.type ?? null,
|
|
@@ -229,6 +282,479 @@ function deriveContextMode(taskType) {
|
|
|
229
282
|
return null;
|
|
230
283
|
}
|
|
231
284
|
|
|
285
|
+
function deriveExecutionScores({
|
|
286
|
+
promptText = '',
|
|
287
|
+
commandText = '',
|
|
288
|
+
targetFile = null,
|
|
289
|
+
intentMode = null,
|
|
290
|
+
taskType = null,
|
|
291
|
+
} = {}) {
|
|
292
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
293
|
+
const sharedRisk = isSharedImpactFile(targetFile);
|
|
294
|
+
const directTransformSignal = /\b(change|replace|set|rename|convert|swap)\b/.test(raw) || /\bchange\s+.+\s+to\s+.+\b/.test(raw);
|
|
295
|
+
const smallFixSignal = /\b(adjust|tweak|patch|fix|modify|update|apply)\b/.test(raw);
|
|
296
|
+
const buildSignal = /\b(build|create|add|implement|feature)\b/.test(raw);
|
|
297
|
+
const debugSignal = intentMode === 'debug-specific' || /\b(root cause|debug|triage|flaky|investigate|why)\b/.test(raw);
|
|
298
|
+
const reviewSignal = intentMode === 'review-specific' || /\b(review|audit|verify|release readiness)\b/.test(raw);
|
|
299
|
+
const failureSignal = /\b(failing|failed|broken|error|crash|timeout|undefined|exception|eacces|trace)\b/.test(raw);
|
|
300
|
+
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);
|
|
301
|
+
const boundedEditSignal = /\b(one[- ]line|small|tiny|single|local|guard|log line|loading message|label)\b/.test(raw);
|
|
302
|
+
const implementSignal = /\b(implement|apply|update|modify|add|create|ship|deliver|fix)\b/.test(raw)
|
|
303
|
+
|| /\bchange\s+.+\s+to\s+.+\b/.test(raw);
|
|
304
|
+
const explicitTarget = Boolean(targetFile);
|
|
305
|
+
|
|
306
|
+
let editCertainty = 0;
|
|
307
|
+
if (directTransformSignal) {
|
|
308
|
+
editCertainty = 3;
|
|
309
|
+
} else if (smallFixSignal) {
|
|
310
|
+
editCertainty = 2;
|
|
311
|
+
} else if (buildSignal) {
|
|
312
|
+
editCertainty = 1;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let investigationNeed = 0;
|
|
316
|
+
if (debugSignal) {
|
|
317
|
+
investigationNeed = 3;
|
|
318
|
+
} else if (failureSignal) {
|
|
319
|
+
investigationNeed = 2;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let blastRadius = 0;
|
|
323
|
+
if (sharedRisk) {
|
|
324
|
+
blastRadius = 3;
|
|
325
|
+
} else if (taskType === 'non-trivial' || taskType === 'shared-simple') {
|
|
326
|
+
blastRadius = 2;
|
|
327
|
+
} else if (!targetFile) {
|
|
328
|
+
blastRadius = 1;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
let verificationBurden = 1;
|
|
332
|
+
if (reviewSignal || sharedRisk) {
|
|
333
|
+
verificationBurden = 3;
|
|
334
|
+
} else if (debugSignal || taskType === 'non-trivial') {
|
|
335
|
+
verificationBurden = 2;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
let ambiguity = 0;
|
|
339
|
+
if (!targetFile) {
|
|
340
|
+
ambiguity = 2;
|
|
341
|
+
} else if (buildSignal && !directTransformSignal && !smallFixSignal) {
|
|
342
|
+
ambiguity = 1;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
editCertainty,
|
|
347
|
+
investigationNeed,
|
|
348
|
+
blastRadius,
|
|
349
|
+
verificationBurden,
|
|
350
|
+
ambiguity,
|
|
351
|
+
sharedRisk,
|
|
352
|
+
directTransformSignal,
|
|
353
|
+
smallFixSignal,
|
|
354
|
+
buildSignal,
|
|
355
|
+
debugSignal,
|
|
356
|
+
reviewSignal,
|
|
357
|
+
failureSignal,
|
|
358
|
+
impactSignal,
|
|
359
|
+
boundedEditSignal,
|
|
360
|
+
implementSignal,
|
|
361
|
+
explicitTarget,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function deriveExecutionMode({
|
|
366
|
+
promptText = '',
|
|
367
|
+
commandText = '',
|
|
368
|
+
targetFile = null,
|
|
369
|
+
intentMode = null,
|
|
370
|
+
executionScores = {},
|
|
371
|
+
executionCandidates = null,
|
|
372
|
+
} = {}) {
|
|
373
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
374
|
+
const scores = executionScores;
|
|
375
|
+
const candidates = executionCandidates ?? buildExecutionModeCandidates({
|
|
376
|
+
promptText,
|
|
377
|
+
commandText,
|
|
378
|
+
targetFile,
|
|
379
|
+
intentMode,
|
|
380
|
+
executionScores,
|
|
381
|
+
});
|
|
382
|
+
const explicitReviewLead = /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw);
|
|
383
|
+
const strongImpactLead = scores.sharedRisk
|
|
384
|
+
&& (scores.impactSignal || /\b(check all affected|map all affected|across all affected)\b/.test(raw));
|
|
385
|
+
const boundedLocalBuildCandidate = scores.buildSignal && scores.boundedEditSignal && scores.explicitTarget && !scores.sharedRisk;
|
|
386
|
+
|
|
387
|
+
if ((intentMode === 'review-specific' || explicitReviewLead) && !scores.implementSignal) {
|
|
388
|
+
return 'review-release';
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (strongImpactLead || (scores.blastRadius >= 3 && (scores.ambiguity >= 2 || scores.investigationNeed >= 2))) {
|
|
392
|
+
return 'map-impact';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (scores.sharedRisk && scores.failureSignal && scores.investigationNeed >= 2 && !scores.impactSignal) {
|
|
396
|
+
return 'shared-edit';
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (scores.blastRadius >= 3 || scores.sharedRisk) {
|
|
400
|
+
return 'shared-edit';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (scores.investigationNeed >= 3 || (scores.failureSignal && scores.investigationNeed >= 2)) {
|
|
404
|
+
return 'find-cause';
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (scores.directTransformSignal && !scores.explicitTarget && scores.investigationNeed === 0 && !scores.sharedRisk) {
|
|
408
|
+
return 'local-build';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (
|
|
412
|
+
scores.editCertainty >= 3
|
|
413
|
+
&& scores.ambiguity <= 1
|
|
414
|
+
&& scores.blastRadius === 0
|
|
415
|
+
&& scores.verificationBurden <= 1
|
|
416
|
+
) {
|
|
417
|
+
return 'tiny-fix';
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (boundedLocalBuildCandidate && scores.investigationNeed === 0) {
|
|
421
|
+
return 'local-fix';
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (
|
|
425
|
+
/\b(build|create|add|implement|feature|summary card)\b/.test(raw)
|
|
426
|
+
&& scores.investigationNeed === 0
|
|
427
|
+
&& scores.blastRadius < 3
|
|
428
|
+
&& !scores.boundedEditSignal
|
|
429
|
+
) {
|
|
430
|
+
return 'local-build';
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (scores.editCertainty >= 2 && scores.investigationNeed === 0 && scores.blastRadius === 0) {
|
|
434
|
+
return 'local-fix';
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return applySafeUpwardBias(candidates, 'local-build');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function buildExecutionModeCandidates({
|
|
441
|
+
promptText = '',
|
|
442
|
+
commandText = '',
|
|
443
|
+
targetFile = null,
|
|
444
|
+
intentMode = null,
|
|
445
|
+
executionScores = {},
|
|
446
|
+
} = {}) {
|
|
447
|
+
const scores = executionScores;
|
|
448
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
449
|
+
const explicitReviewLead = (intentMode === 'review-specific' || /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw))
|
|
450
|
+
&& !scores.implementSignal;
|
|
451
|
+
|
|
452
|
+
const modeScores = {
|
|
453
|
+
'tiny-fix': (
|
|
454
|
+
(scores.editCertainty * 4)
|
|
455
|
+
+ (scores.directTransformSignal ? 4 : 0)
|
|
456
|
+
+ (scores.explicitTarget ? 1 : 0)
|
|
457
|
+
- (scores.failureSignal ? 4 : 0)
|
|
458
|
+
- (scores.blastRadius * 4)
|
|
459
|
+
- (scores.ambiguity * 2)
|
|
460
|
+
),
|
|
461
|
+
'local-fix': (
|
|
462
|
+
(scores.editCertainty * 3)
|
|
463
|
+
+ (scores.boundedEditSignal ? 3 : 0)
|
|
464
|
+
+ (scores.explicitTarget ? 1 : 0)
|
|
465
|
+
- (scores.failureSignal ? 2 : 0)
|
|
466
|
+
- (scores.blastRadius * 4)
|
|
467
|
+
),
|
|
468
|
+
'local-build': (
|
|
469
|
+
(scores.buildSignal ? 6 : 0)
|
|
470
|
+
+ (scores.editCertainty * 1)
|
|
471
|
+
+ (scores.explicitTarget ? 1 : 0)
|
|
472
|
+
- (scores.boundedEditSignal ? 3 : 0)
|
|
473
|
+
- (scores.failureSignal ? 3 : 0)
|
|
474
|
+
- (scores.blastRadius * 4)
|
|
475
|
+
),
|
|
476
|
+
'find-cause': (
|
|
477
|
+
(scores.investigationNeed * 4)
|
|
478
|
+
+ (scores.failureSignal ? 3 : 0)
|
|
479
|
+
+ (scores.debugSignal ? 2 : 0)
|
|
480
|
+
- (scores.blastRadius >= 3 ? 1 : 0)
|
|
481
|
+
),
|
|
482
|
+
'shared-edit': (
|
|
483
|
+
(scores.sharedRisk ? 8 : 0)
|
|
484
|
+
+ (scores.editCertainty * 1)
|
|
485
|
+
+ (scores.buildSignal ? 1 : 0)
|
|
486
|
+
- (scores.impactSignal ? 2 : 0)
|
|
487
|
+
),
|
|
488
|
+
'map-impact': (
|
|
489
|
+
(scores.sharedRisk ? 7 : 0)
|
|
490
|
+
+ (scores.impactSignal ? 5 : 0)
|
|
491
|
+
+ (scores.ambiguity * 2)
|
|
492
|
+
+ scores.investigationNeed
|
|
493
|
+
),
|
|
494
|
+
'review-release': (
|
|
495
|
+
(explicitReviewLead ? 10 : 0)
|
|
496
|
+
+ (scores.reviewSignal ? 3 : 0)
|
|
497
|
+
- (scores.implementSignal ? 5 : 0)
|
|
498
|
+
),
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
return Object.entries(modeScores)
|
|
502
|
+
.map(([mode, score]) => ({ mode, score }))
|
|
503
|
+
.sort((a, b) => b.score - a.score || executionModeRank(a.mode) - executionModeRank(b.mode));
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function applySafeUpwardBias(candidates = [], fallbackMode = 'local-build') {
|
|
507
|
+
const [topCandidate, competingCandidate] = candidates;
|
|
508
|
+
if (!topCandidate) {
|
|
509
|
+
return fallbackMode;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (!competingCandidate) {
|
|
513
|
+
return topCandidate.mode;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const scoreGap = Number(topCandidate.score ?? 0) - Number(competingCandidate.score ?? 0);
|
|
517
|
+
const rankGap = executionModeRank(competingCandidate.mode) - executionModeRank(topCandidate.mode);
|
|
518
|
+
if (scoreGap <= 1 && rankGap === 1) {
|
|
519
|
+
return competingCandidate.mode;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return topCandidate.mode;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function executionModeRank(mode = '') {
|
|
526
|
+
const orderedModes = [
|
|
527
|
+
'tiny-fix',
|
|
528
|
+
'local-fix',
|
|
529
|
+
'local-build',
|
|
530
|
+
'find-cause',
|
|
531
|
+
'shared-edit',
|
|
532
|
+
'map-impact',
|
|
533
|
+
'review-release',
|
|
534
|
+
];
|
|
535
|
+
|
|
536
|
+
const index = orderedModes.indexOf(mode);
|
|
537
|
+
return index >= 0 ? index : orderedModes.length;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function buildExecutionContract(executionMode = null) {
|
|
541
|
+
if (!executionMode) {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const contracts = {
|
|
546
|
+
'tiny-fix': {
|
|
547
|
+
maxReadPasses: 0,
|
|
548
|
+
maxContextPulls: 0,
|
|
549
|
+
verificationPolicy: 'minimal-or-targeted',
|
|
550
|
+
completionRule: 'never-claim-done-without-write',
|
|
551
|
+
delegationPolicy: 'disallow',
|
|
552
|
+
completionEvidence: ['write-evidence'],
|
|
553
|
+
},
|
|
554
|
+
'local-fix': {
|
|
555
|
+
maxReadPasses: 1,
|
|
556
|
+
maxContextPulls: 1,
|
|
557
|
+
verificationPolicy: 'targeted-if-covered',
|
|
558
|
+
completionRule: 'require-write',
|
|
559
|
+
delegationPolicy: 'disallow',
|
|
560
|
+
completionEvidence: ['write-evidence'],
|
|
561
|
+
},
|
|
562
|
+
'local-build': {
|
|
563
|
+
maxReadPasses: 2,
|
|
564
|
+
maxContextPulls: 1,
|
|
565
|
+
verificationPolicy: 'targeted-if-covered',
|
|
566
|
+
completionRule: 'require-write',
|
|
567
|
+
delegationPolicy: 'disallow-by-default',
|
|
568
|
+
completionEvidence: ['write-evidence'],
|
|
569
|
+
},
|
|
570
|
+
'find-cause': {
|
|
571
|
+
maxReadPassesBeforeReassess: 3,
|
|
572
|
+
verificationPolicy: 'root-cause-then-targeted',
|
|
573
|
+
completionRule: 'never-claim-fixed-without-write-and-verification',
|
|
574
|
+
delegationPolicy: 'allow-specialized-debug-lane',
|
|
575
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
576
|
+
},
|
|
577
|
+
'shared-edit': {
|
|
578
|
+
maxReadPasses: 2,
|
|
579
|
+
maxContextPulls: 2,
|
|
580
|
+
verificationPolicy: 'targeted-then-widen-on-risk',
|
|
581
|
+
completionRule: 'require-write-and-verification',
|
|
582
|
+
delegationPolicy: 'allow-qualified-sidecar',
|
|
583
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
584
|
+
mirrorConsistencyRequired: true,
|
|
585
|
+
},
|
|
586
|
+
'map-impact': {
|
|
587
|
+
maxReadPasses: 3,
|
|
588
|
+
maxContextPulls: 3,
|
|
589
|
+
verificationPolicy: 'impact-first-then-targeted-then-widen-on-risk',
|
|
590
|
+
completionRule: 'require-impact-evidence-before-edit-claim',
|
|
591
|
+
delegationPolicy: 'allow-impact-sidecar',
|
|
592
|
+
completionEvidence: ['impact-evidence', 'write-evidence', 'verification-evidence'],
|
|
593
|
+
mirrorConsistencyRequired: true,
|
|
594
|
+
},
|
|
595
|
+
'review-release': {
|
|
596
|
+
verificationPolicy: 'evidence-first',
|
|
597
|
+
completionRule: 'report-findings-not-implementation',
|
|
598
|
+
delegationPolicy: 'allow-review-sidecar',
|
|
599
|
+
completionEvidence: ['verification-evidence'],
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
return contracts[executionMode] ? { ...contracts[executionMode] } : null;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function buildApproachSelectorResult({
|
|
607
|
+
executionMode = null,
|
|
608
|
+
executionScores = null,
|
|
609
|
+
executionCandidates = null,
|
|
610
|
+
} = {}) {
|
|
611
|
+
if (!executionMode) {
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
616
|
+
const policyByMode = {
|
|
617
|
+
'tiny-fix': {
|
|
618
|
+
riskLevel: 'minimal',
|
|
619
|
+
contextPolicy: 'confirm-target-only',
|
|
620
|
+
},
|
|
621
|
+
'local-fix': {
|
|
622
|
+
riskLevel: 'local',
|
|
623
|
+
contextPolicy: 'bounded-local',
|
|
624
|
+
},
|
|
625
|
+
'local-build': {
|
|
626
|
+
riskLevel: 'local',
|
|
627
|
+
contextPolicy: 'bounded-with-related-files',
|
|
628
|
+
},
|
|
629
|
+
'find-cause': {
|
|
630
|
+
riskLevel: 'investigation',
|
|
631
|
+
contextPolicy: 'trace-then-bounded-context',
|
|
632
|
+
},
|
|
633
|
+
'shared-edit': {
|
|
634
|
+
riskLevel: 'shared',
|
|
635
|
+
contextPolicy: 'bounded-with-related-tests',
|
|
636
|
+
},
|
|
637
|
+
'map-impact': {
|
|
638
|
+
riskLevel: 'wide',
|
|
639
|
+
contextPolicy: 'impact-map-first',
|
|
640
|
+
},
|
|
641
|
+
'review-release': {
|
|
642
|
+
riskLevel: 'release',
|
|
643
|
+
contextPolicy: 'evidence-review-only',
|
|
644
|
+
},
|
|
645
|
+
};
|
|
646
|
+
const selectedPolicy = policyByMode[executionMode] ?? {
|
|
647
|
+
riskLevel: 'local',
|
|
648
|
+
contextPolicy: 'bounded-local',
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
return {
|
|
652
|
+
executionMode,
|
|
653
|
+
executionScores: executionScores ? { ...executionScores } : null,
|
|
654
|
+
riskLevel: selectedPolicy.riskLevel,
|
|
655
|
+
contextPolicy: selectedPolicy.contextPolicy,
|
|
656
|
+
verificationPolicy: executionContract?.verificationPolicy ?? null,
|
|
657
|
+
completionRule: executionContract?.completionRule ?? null,
|
|
658
|
+
competingMode: executionCandidates?.[1]?.mode ?? null,
|
|
659
|
+
competingScoreGap: executionCandidates?.length >= 2
|
|
660
|
+
? Number(executionCandidates[0]?.score ?? 0) - Number(executionCandidates[1]?.score ?? 0)
|
|
661
|
+
: null,
|
|
662
|
+
candidateModes: (executionCandidates ?? []).slice(0, 3).map((entry) => ({
|
|
663
|
+
mode: entry.mode,
|
|
664
|
+
score: entry.score,
|
|
665
|
+
})),
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function buildCompletionState({ executionMode = null, verificationRecommendation = null } = {}) {
|
|
670
|
+
if (!executionMode) {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const contract = buildExecutionContract(executionMode);
|
|
675
|
+
const missingEvidence = [...(contract?.completionEvidence ?? [])];
|
|
676
|
+
const requiresVerification = missingEvidence.includes('verification-evidence');
|
|
677
|
+
if (
|
|
678
|
+
requiresVerification
|
|
679
|
+
&& verificationRecommendation
|
|
680
|
+
&& !(verificationRecommendation.commands?.length || verificationRecommendation.fallbackCommands?.length)
|
|
681
|
+
) {
|
|
682
|
+
missingEvidence.push('verification-plan');
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
let reason = 'completion evidence is still required';
|
|
686
|
+
if (['tiny-fix', 'local-fix', 'local-build', 'shared-edit'].includes(executionMode)) {
|
|
687
|
+
reason = 'implement request has not produced an edit yet';
|
|
688
|
+
} else if (executionMode === 'review-release') {
|
|
689
|
+
reason = 'review/release evidence is still required before final claim';
|
|
690
|
+
} else if (executionMode === 'map-impact') {
|
|
691
|
+
reason = 'impact evidence is still required before safe completion claim';
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return {
|
|
695
|
+
claimAllowed: false,
|
|
696
|
+
missingEvidence,
|
|
697
|
+
reason,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function buildContinuationState({
|
|
702
|
+
nextActionType = null,
|
|
703
|
+
completionState = null,
|
|
704
|
+
} = {}) {
|
|
705
|
+
const reasons = [];
|
|
706
|
+
const missingEvidence = unique(completionState?.missingEvidence ?? []);
|
|
707
|
+
|
|
708
|
+
if (nextActionType === 'pull-indexed-context') {
|
|
709
|
+
reasons.push('pending-bounded-context');
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if (nextActionType === 'read-skill-instructions') {
|
|
713
|
+
reasons.push('pending-skill-read');
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (missingEvidence.includes('write-evidence')) {
|
|
717
|
+
reasons.push('missing-write-evidence');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (missingEvidence.includes('verification-evidence') || missingEvidence.includes('verification-plan')) {
|
|
721
|
+
reasons.push('missing-verification-evidence');
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (missingEvidence.includes('impact-evidence')) {
|
|
725
|
+
reasons.push('missing-impact-evidence');
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const nextMilestone = reasons.includes('pending-bounded-context')
|
|
729
|
+
? 'complete-bounded-context-then-continue'
|
|
730
|
+
: (
|
|
731
|
+
reasons.includes('missing-write-evidence')
|
|
732
|
+
? 'produce-write-evidence'
|
|
733
|
+
: (
|
|
734
|
+
reasons.includes('missing-verification-evidence')
|
|
735
|
+
? 'produce-verification-evidence'
|
|
736
|
+
: (
|
|
737
|
+
reasons.includes('missing-impact-evidence')
|
|
738
|
+
? 'produce-impact-evidence'
|
|
739
|
+
: null
|
|
740
|
+
)
|
|
741
|
+
)
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
return {
|
|
745
|
+
required: reasons.length > 0,
|
|
746
|
+
reasons,
|
|
747
|
+
doneLanguageBlocked: reasons.length > 0,
|
|
748
|
+
stopAllowedOnlyFor: reasons.length > 0 ? ['real-blocker'] : [],
|
|
749
|
+
nextMilestone,
|
|
750
|
+
repeatCount: reasons.length > 0 ? 1 : 0,
|
|
751
|
+
stuckRisk: null,
|
|
752
|
+
rescueMode: null,
|
|
753
|
+
wideningBlocked: false,
|
|
754
|
+
milestonePriority: reasons.length > 0 ? 'normal' : null,
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
232
758
|
async function selectActiveSkills({ rootDir, promptText, commandText, targetFile, intentMode = null }) {
|
|
233
759
|
const routeSignals = {
|
|
234
760
|
promptRawText: String(promptText || '').toLowerCase(),
|
|
@@ -269,6 +795,10 @@ function shouldKeepRouteEntryForIntent(entry, intentMode) {
|
|
|
269
795
|
return false;
|
|
270
796
|
}
|
|
271
797
|
|
|
798
|
+
if (entry.id === 'code-review' && intentMode === 'implement-specific') {
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
|
|
272
802
|
return true;
|
|
273
803
|
}
|
|
274
804
|
|
|
@@ -313,6 +843,10 @@ function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
|
313
843
|
routeSignals.commandRawText ?? '',
|
|
314
844
|
routeSignals.commandNormalizedText ?? '',
|
|
315
845
|
].join('\n');
|
|
846
|
+
const rawPromptSignals = [
|
|
847
|
+
routeSignals.promptRawText ?? '',
|
|
848
|
+
routeSignals.commandRawText ?? '',
|
|
849
|
+
].join('\n');
|
|
316
850
|
|
|
317
851
|
if (
|
|
318
852
|
skillId === 'testing-quality'
|
|
@@ -321,6 +855,14 @@ function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
|
321
855
|
return 1;
|
|
322
856
|
}
|
|
323
857
|
|
|
858
|
+
if (
|
|
859
|
+
skillId === 'code-review'
|
|
860
|
+
&& /\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(rawPromptSignals)
|
|
861
|
+
&& !/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(rawPromptSignals)
|
|
862
|
+
) {
|
|
863
|
+
return -4;
|
|
864
|
+
}
|
|
865
|
+
|
|
324
866
|
return 0;
|
|
325
867
|
}
|
|
326
868
|
|
|
@@ -371,13 +913,13 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
|
|
|
371
913
|
}
|
|
372
914
|
|
|
373
915
|
if (concreteTask) {
|
|
374
|
-
if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|
|
|
916
|
+
if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|timeout)\b/.test(lower)) {
|
|
375
917
|
return 'debug-specific';
|
|
376
918
|
}
|
|
377
|
-
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(
|
|
919
|
+
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(raw)) {
|
|
378
920
|
return 'review-specific';
|
|
379
921
|
}
|
|
380
|
-
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature)\b/.test(
|
|
922
|
+
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(raw)) {
|
|
381
923
|
return 'implement-specific';
|
|
382
924
|
}
|
|
383
925
|
}
|
|
@@ -409,7 +951,7 @@ function hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext = false }
|
|
|
409
951
|
return true;
|
|
410
952
|
}
|
|
411
953
|
|
|
412
|
-
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)
|
|
954
|
+
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)
|
|
413
955
|
|| /\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);
|
|
414
956
|
}
|
|
415
957
|
|
|
@@ -23,6 +23,8 @@ cat <<'FALLBACK'
|
|
|
23
23
|
- Auto-activate matching project-local skills from prompt + tool/file signals.
|
|
24
24
|
- Reuse existing code. Use yarn. Run tests after code changes.
|
|
25
25
|
- Scope-based verification: match verify effort to change scope.
|
|
26
|
+
- If a routed lane still needs `pull-indexed-context` or still has completion debt, treat that as internal continuation work, not a stopping point.
|
|
27
|
+
- Do not end with “done/applied/fixed” language while write/verification evidence is still missing unless a real blocker is found.
|
|
26
28
|
- If broad verification gets blocked by a Claude hook, follow the routed targeted order or ask for explicit full-suite confirmation.
|
|
27
29
|
=== END ===
|
|
28
30
|
FALLBACK
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
- Auto-activate matching project-local skills from prompt + tool/file signals; end users should not need to know skill names.
|
|
9
9
|
- After routing skill + context, prefer verification derived from related tests/context bundle before broad test runs.
|
|
10
10
|
- Follow routed verification policy: auto-run targeted checks when localized, widen in order for shared/risky scope, and ask before blanket broad runs when no related test evidence exists.
|
|
11
|
+
- Nếu route còn `pull-indexed-context`, coi đó là bước nội bộ để tiếp tục chứ không phải điểm dừng; đọc xong context thì tiếp tục edit/verify ngay khi an toàn.
|
|
12
|
+
- Không được kết thúc bằng “done/applied/fixed” khi còn thiếu write-evidence hoặc verification-evidence, trừ khi có blocker thật.
|
|
11
13
|
- If Claude blocks a broad verification command, do not fight the hook blindly — use the targeted indexed lane first or get explicit confirmation for a full-suite run.
|
|
12
14
|
- Nếu mơ hồ hoặc risk cao (security/migration/auth/data-loss/uninstall-core), escalate đọc sâu hơn hoặc hỏi 1 câu clarify ngắn.
|
|
13
15
|
- Docs là navigation aid, source code là ground truth. Nếu mâu thuẫn → source thắng, update docs trước khi tiếp tục.
|