@ngockhoale/ukit 1.4.1 → 1.4.2
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 +20 -0
- package/package.json +1 -1
- package/src/core/runtimeConfig.js +65 -1
- package/src/index/taskRouting.js +382 -4
- 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 +657 -15
- package/templates/.claude/ukit/index/route-task.mjs +475 -5
- package/templates/.claude/ukit/runtime/reinject-context.mjs +120 -3
- 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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to UKit are documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 1.4.2 - 2026-05-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added a quality-first internal orchestration ladder with seven execution layers: `tiny-fix`, `local-fix`, `local-build`, `find-cause`, `shared-edit`, `map-impact`, and `review-release`.
|
|
12
|
+
- Added structured route continuity state so installed helpers and hooks can carry `completionState`, `continuationState`, and stuck-lane rescue signals across turns instead of forgetting unfinished execution debt.
|
|
13
|
+
- Added orchestration/runtime config defaults and Codex adapter metadata for the internal advisor/orchestrator contract while keeping the teammate workflow centered on `ukit install`.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Kept context routing and context-mode hints internal so UKit no longer surfaces `pull-indexed-context`, `resolve-context`, or `mode=LITE/FULL` in the main route prose for ordinary work.
|
|
18
|
+
- Preserved the structured route state (`nextActionType`, `helperHint`, `contextMode`) for internal orchestration, while removing the user/model-facing leakage that was nudging sessions into micro-step stop-and-wait behavior.
|
|
19
|
+
- Hardened implementation routing and installed agent guidance so explicit implement/apply/fix requests keep moving through bounded read → edit → verify flow instead of stopping after read-only inspection.
|
|
20
|
+
- Escalated repeated unfinished returns with `repeatCount`, `stuckRisk`, and `rescueMode` so UKit can rescue a stuck lane instead of quietly looping the same partial milestone.
|
|
21
|
+
- Fixed the installed `route-task` continuation handoff so previous route summaries are carried through correctly during rescue escalation.
|
|
22
|
+
|
|
23
|
+
### Tests
|
|
24
|
+
|
|
25
|
+
- Added/updated route, hook, reinject, install-pipeline, and package-artifact coverage for internal helper hiding, continuation rescue escalation, and the expanded orchestration contract.
|
|
26
|
+
|
|
7
27
|
## 1.4.1 - 2026-05-09
|
|
8
28
|
|
|
9
29
|
- Completed cleanup and 1.4.1 template alignment.
|
package/package.json
CHANGED
|
@@ -49,7 +49,7 @@ export function buildDefaultRuntimeConfig(overrides = {}) {
|
|
|
49
49
|
const safeOverrides = isPlainObject(overrides) ? overrides : {};
|
|
50
50
|
|
|
51
51
|
return mergeObjects({
|
|
52
|
-
version: '1.4.
|
|
52
|
+
version: '1.4.2',
|
|
53
53
|
agent: 'claude-code',
|
|
54
54
|
autonomy: {
|
|
55
55
|
level: 'balanced',
|
|
@@ -112,6 +112,59 @@ export function buildDefaultRuntimeConfig(overrides = {}) {
|
|
|
112
112
|
advisorEnabled: true,
|
|
113
113
|
maxAdvisorCalls: 3,
|
|
114
114
|
},
|
|
115
|
+
orchestration: {
|
|
116
|
+
enabled: true,
|
|
117
|
+
orchestratorModel: 'claude-sonnet-4-6',
|
|
118
|
+
advisorEnabled: true,
|
|
119
|
+
contracts: {
|
|
120
|
+
'tiny-fix': {
|
|
121
|
+
maxReadPasses: 0,
|
|
122
|
+
maxContextPulls: 0,
|
|
123
|
+
verificationPolicy: 'minimal-or-targeted',
|
|
124
|
+
completionRule: 'never-claim-done-without-write',
|
|
125
|
+
delegationPolicy: 'disallow',
|
|
126
|
+
},
|
|
127
|
+
'local-fix': {
|
|
128
|
+
maxReadPasses: 1,
|
|
129
|
+
maxContextPulls: 1,
|
|
130
|
+
verificationPolicy: 'targeted-if-covered',
|
|
131
|
+
completionRule: 'require-write',
|
|
132
|
+
delegationPolicy: 'disallow',
|
|
133
|
+
},
|
|
134
|
+
'local-build': {
|
|
135
|
+
maxReadPasses: 2,
|
|
136
|
+
maxContextPulls: 1,
|
|
137
|
+
verificationPolicy: 'targeted-if-covered',
|
|
138
|
+
completionRule: 'require-write',
|
|
139
|
+
delegationPolicy: 'disallow-by-default',
|
|
140
|
+
},
|
|
141
|
+
'find-cause': {
|
|
142
|
+
maxReadPassesBeforeReassess: 3,
|
|
143
|
+
verificationPolicy: 'root-cause-then-targeted',
|
|
144
|
+
completionRule: 'never-claim-fixed-without-write-and-verification',
|
|
145
|
+
delegationPolicy: 'allow-specialized-debug-lane',
|
|
146
|
+
},
|
|
147
|
+
'shared-edit': {
|
|
148
|
+
maxReadPasses: 2,
|
|
149
|
+
maxContextPulls: 2,
|
|
150
|
+
verificationPolicy: 'targeted-then-widen-on-risk',
|
|
151
|
+
completionRule: 'require-write-and-verification',
|
|
152
|
+
delegationPolicy: 'allow-qualified-sidecar',
|
|
153
|
+
},
|
|
154
|
+
'map-impact': {
|
|
155
|
+
maxReadPasses: 3,
|
|
156
|
+
maxContextPulls: 3,
|
|
157
|
+
verificationPolicy: 'impact-first-then-targeted-then-widen-on-risk',
|
|
158
|
+
completionRule: 'require-impact-evidence-before-edit-claim',
|
|
159
|
+
delegationPolicy: 'allow-impact-sidecar',
|
|
160
|
+
},
|
|
161
|
+
'review-release': {
|
|
162
|
+
verificationPolicy: 'evidence-first',
|
|
163
|
+
completionRule: 'report-findings-not-implementation',
|
|
164
|
+
delegationPolicy: 'allow-review-sidecar',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
115
168
|
memory: {
|
|
116
169
|
enabled: true,
|
|
117
170
|
autoCapture: true,
|
|
@@ -278,6 +331,17 @@ export function validateRuntimeConfig(config) {
|
|
|
278
331
|
pushPositiveNumberError(errors, config.router.maxAdvisorCalls, 'router.maxAdvisorCalls');
|
|
279
332
|
}
|
|
280
333
|
|
|
334
|
+
if (!isPlainObject(config.orchestration)) {
|
|
335
|
+
errors.push('orchestration must be an object.');
|
|
336
|
+
} else {
|
|
337
|
+
pushBooleanError(errors, config.orchestration.enabled, 'orchestration.enabled');
|
|
338
|
+
pushNonEmptyStringError(errors, config.orchestration.orchestratorModel, 'orchestration.orchestratorModel');
|
|
339
|
+
pushBooleanError(errors, config.orchestration.advisorEnabled, 'orchestration.advisorEnabled');
|
|
340
|
+
if (!isPlainObject(config.orchestration.contracts)) {
|
|
341
|
+
errors.push('orchestration.contracts must be an object.');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
281
345
|
if (!isPlainObject(config.memory)) {
|
|
282
346
|
errors.push('memory must be an object.');
|
|
283
347
|
} else {
|
package/src/index/taskRouting.js
CHANGED
|
@@ -52,6 +52,21 @@ 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 executionMode = deriveExecutionMode({
|
|
63
|
+
promptText: normalizedPrompt,
|
|
64
|
+
commandText: normalizedCommand,
|
|
65
|
+
targetFile: normalizedTarget,
|
|
66
|
+
intentMode,
|
|
67
|
+
taskType: inferredTaskType,
|
|
68
|
+
executionScores,
|
|
69
|
+
});
|
|
55
70
|
const preservedPrompt = normalizedPrompt || String(lastExplicitUserPromptText || '').trim();
|
|
56
71
|
const degradedWarnings = [];
|
|
57
72
|
let contextResult = null;
|
|
@@ -128,11 +143,14 @@ export async function deriveTaskRoute({
|
|
|
128
143
|
taskType: inferredTaskType,
|
|
129
144
|
intentMode,
|
|
130
145
|
autonomyLevel,
|
|
146
|
+
executionScores,
|
|
147
|
+
executionMode,
|
|
131
148
|
},
|
|
132
149
|
contextRecommendation,
|
|
133
150
|
verificationRecommendation,
|
|
134
151
|
nextAction,
|
|
135
152
|
});
|
|
153
|
+
const approachSelector = routeSummary?.approachSelector ?? null;
|
|
136
154
|
|
|
137
155
|
return {
|
|
138
156
|
activeSkills,
|
|
@@ -145,7 +163,10 @@ export async function deriveTaskRoute({
|
|
|
145
163
|
taskType: inferredTaskType,
|
|
146
164
|
intentMode,
|
|
147
165
|
autonomyLevel,
|
|
166
|
+
executionScores,
|
|
167
|
+
executionMode,
|
|
148
168
|
},
|
|
169
|
+
approachSelector,
|
|
149
170
|
contextRecommendation,
|
|
150
171
|
verificationRecommendation,
|
|
151
172
|
nextAction,
|
|
@@ -186,6 +207,21 @@ export function buildRouteSummary({
|
|
|
186
207
|
const compactHelperLane = nextAction?.type === 'pull-indexed-context'
|
|
187
208
|
&& typeof contextRecommendation?.command === 'string'
|
|
188
209
|
&& contextRecommendation.command.trim();
|
|
210
|
+
const executionMode = routingContext.executionMode ?? null;
|
|
211
|
+
const executionScores = routingContext.executionScores ?? null;
|
|
212
|
+
const approachSelector = buildApproachSelectorResult({
|
|
213
|
+
executionMode,
|
|
214
|
+
executionScores,
|
|
215
|
+
});
|
|
216
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
217
|
+
const completionState = buildCompletionState({
|
|
218
|
+
executionMode,
|
|
219
|
+
verificationRecommendation,
|
|
220
|
+
});
|
|
221
|
+
const continuationState = buildContinuationState({
|
|
222
|
+
nextActionType: nextAction?.type ?? null,
|
|
223
|
+
completionState,
|
|
224
|
+
});
|
|
189
225
|
const helperHint = compactHelperHint(
|
|
190
226
|
compactHelperLane
|
|
191
227
|
? contextRecommendation?.command
|
|
@@ -204,7 +240,6 @@ export function buildRouteSummary({
|
|
|
204
240
|
editGuardHint ? `editGuard=${editGuardHint}` : null,
|
|
205
241
|
delegationRecommendation?.hint ? `delegate=${delegationRecommendation.hint}` : null,
|
|
206
242
|
policyMode ? `policy=${policyMode}` : null,
|
|
207
|
-
contextMode ? `mode=${contextMode}` : null,
|
|
208
243
|
].filter(Boolean).join(' | ');
|
|
209
244
|
|
|
210
245
|
return {
|
|
@@ -213,6 +248,12 @@ export function buildRouteSummary({
|
|
|
213
248
|
preferredOrder,
|
|
214
249
|
policyMode,
|
|
215
250
|
editGuardHint,
|
|
251
|
+
executionMode,
|
|
252
|
+
executionScores,
|
|
253
|
+
approachSelector,
|
|
254
|
+
executionContract,
|
|
255
|
+
completionState,
|
|
256
|
+
continuationState,
|
|
216
257
|
intentMode: routingContext.intentMode ?? null,
|
|
217
258
|
delegateHint: delegationRecommendation?.hint ?? null,
|
|
218
259
|
nextActionType: nextAction?.type ?? null,
|
|
@@ -229,6 +270,327 @@ function deriveContextMode(taskType) {
|
|
|
229
270
|
return null;
|
|
230
271
|
}
|
|
231
272
|
|
|
273
|
+
function deriveExecutionScores({
|
|
274
|
+
promptText = '',
|
|
275
|
+
commandText = '',
|
|
276
|
+
targetFile = null,
|
|
277
|
+
intentMode = null,
|
|
278
|
+
taskType = null,
|
|
279
|
+
} = {}) {
|
|
280
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
281
|
+
const sharedRisk = isSharedImpactFile(targetFile);
|
|
282
|
+
const directTransformSignal = /\b(change|replace|set|rename|convert|swap)\b/.test(raw) || /\bchange\s+.+\s+to\s+.+\b/.test(raw);
|
|
283
|
+
const smallFixSignal = /\b(adjust|tweak|patch|fix|modify|update|apply)\b/.test(raw);
|
|
284
|
+
const buildSignal = /\b(build|create|add|implement|feature)\b/.test(raw);
|
|
285
|
+
const debugSignal = intentMode === 'debug-specific' || /\b(root cause|debug|triage|flaky|investigate|why)\b/.test(raw);
|
|
286
|
+
const reviewSignal = intentMode === 'review-specific' || /\b(review|audit|verify|release readiness)\b/.test(raw);
|
|
287
|
+
|
|
288
|
+
let editCertainty = 0;
|
|
289
|
+
if (directTransformSignal) {
|
|
290
|
+
editCertainty = 3;
|
|
291
|
+
} else if (smallFixSignal) {
|
|
292
|
+
editCertainty = 2;
|
|
293
|
+
} else if (buildSignal) {
|
|
294
|
+
editCertainty = 1;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let investigationNeed = 0;
|
|
298
|
+
if (debugSignal) {
|
|
299
|
+
investigationNeed = 3;
|
|
300
|
+
} else if (/\b(failing|broken|error|crash|timeout)\b/.test(raw)) {
|
|
301
|
+
investigationNeed = 2;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
let blastRadius = 0;
|
|
305
|
+
if (sharedRisk) {
|
|
306
|
+
blastRadius = 3;
|
|
307
|
+
} else if (taskType === 'non-trivial' || taskType === 'shared-simple') {
|
|
308
|
+
blastRadius = 2;
|
|
309
|
+
} else if (!targetFile) {
|
|
310
|
+
blastRadius = 1;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
let verificationBurden = 1;
|
|
314
|
+
if (reviewSignal || sharedRisk) {
|
|
315
|
+
verificationBurden = 3;
|
|
316
|
+
} else if (debugSignal || taskType === 'non-trivial') {
|
|
317
|
+
verificationBurden = 2;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
let ambiguity = 0;
|
|
321
|
+
if (!targetFile) {
|
|
322
|
+
ambiguity = 2;
|
|
323
|
+
} else if (buildSignal && !directTransformSignal && !smallFixSignal) {
|
|
324
|
+
ambiguity = 1;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
editCertainty,
|
|
329
|
+
investigationNeed,
|
|
330
|
+
blastRadius,
|
|
331
|
+
verificationBurden,
|
|
332
|
+
ambiguity,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function deriveExecutionMode({
|
|
337
|
+
promptText = '',
|
|
338
|
+
commandText = '',
|
|
339
|
+
targetFile = null,
|
|
340
|
+
intentMode = null,
|
|
341
|
+
executionScores = {},
|
|
342
|
+
} = {}) {
|
|
343
|
+
const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
|
|
344
|
+
const scores = executionScores;
|
|
345
|
+
const explicitReviewLead = /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw);
|
|
346
|
+
|
|
347
|
+
if (intentMode === 'review-specific' || explicitReviewLead) {
|
|
348
|
+
return 'review-release';
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (scores.blastRadius >= 3 && (scores.ambiguity >= 2 || scores.investigationNeed >= 2)) {
|
|
352
|
+
return 'map-impact';
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (scores.blastRadius >= 3 || isSharedImpactFile(targetFile)) {
|
|
356
|
+
return 'shared-edit';
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (scores.investigationNeed >= 3) {
|
|
360
|
+
return 'find-cause';
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (
|
|
364
|
+
scores.editCertainty >= 3
|
|
365
|
+
&& scores.ambiguity === 0
|
|
366
|
+
&& scores.blastRadius === 0
|
|
367
|
+
&& scores.verificationBurden <= 1
|
|
368
|
+
) {
|
|
369
|
+
return 'tiny-fix';
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (
|
|
373
|
+
/\b(build|create|add|implement|feature|summary card)\b/.test(raw)
|
|
374
|
+
&& scores.investigationNeed === 0
|
|
375
|
+
&& scores.blastRadius < 3
|
|
376
|
+
) {
|
|
377
|
+
return 'local-build';
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (scores.editCertainty >= 2 && scores.investigationNeed === 0 && scores.blastRadius === 0) {
|
|
381
|
+
return 'local-fix';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return 'local-build';
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function buildExecutionContract(executionMode = null) {
|
|
388
|
+
if (!executionMode) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const contracts = {
|
|
393
|
+
'tiny-fix': {
|
|
394
|
+
maxReadPasses: 0,
|
|
395
|
+
maxContextPulls: 0,
|
|
396
|
+
verificationPolicy: 'minimal-or-targeted',
|
|
397
|
+
completionRule: 'never-claim-done-without-write',
|
|
398
|
+
delegationPolicy: 'disallow',
|
|
399
|
+
completionEvidence: ['write-evidence'],
|
|
400
|
+
},
|
|
401
|
+
'local-fix': {
|
|
402
|
+
maxReadPasses: 1,
|
|
403
|
+
maxContextPulls: 1,
|
|
404
|
+
verificationPolicy: 'targeted-if-covered',
|
|
405
|
+
completionRule: 'require-write',
|
|
406
|
+
delegationPolicy: 'disallow',
|
|
407
|
+
completionEvidence: ['write-evidence'],
|
|
408
|
+
},
|
|
409
|
+
'local-build': {
|
|
410
|
+
maxReadPasses: 2,
|
|
411
|
+
maxContextPulls: 1,
|
|
412
|
+
verificationPolicy: 'targeted-if-covered',
|
|
413
|
+
completionRule: 'require-write',
|
|
414
|
+
delegationPolicy: 'disallow-by-default',
|
|
415
|
+
completionEvidence: ['write-evidence'],
|
|
416
|
+
},
|
|
417
|
+
'find-cause': {
|
|
418
|
+
maxReadPassesBeforeReassess: 3,
|
|
419
|
+
verificationPolicy: 'root-cause-then-targeted',
|
|
420
|
+
completionRule: 'never-claim-fixed-without-write-and-verification',
|
|
421
|
+
delegationPolicy: 'allow-specialized-debug-lane',
|
|
422
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
423
|
+
},
|
|
424
|
+
'shared-edit': {
|
|
425
|
+
maxReadPasses: 2,
|
|
426
|
+
maxContextPulls: 2,
|
|
427
|
+
verificationPolicy: 'targeted-then-widen-on-risk',
|
|
428
|
+
completionRule: 'require-write-and-verification',
|
|
429
|
+
delegationPolicy: 'allow-qualified-sidecar',
|
|
430
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
431
|
+
mirrorConsistencyRequired: true,
|
|
432
|
+
},
|
|
433
|
+
'map-impact': {
|
|
434
|
+
maxReadPasses: 3,
|
|
435
|
+
maxContextPulls: 3,
|
|
436
|
+
verificationPolicy: 'impact-first-then-targeted-then-widen-on-risk',
|
|
437
|
+
completionRule: 'require-impact-evidence-before-edit-claim',
|
|
438
|
+
delegationPolicy: 'allow-impact-sidecar',
|
|
439
|
+
completionEvidence: ['impact-evidence', 'write-evidence', 'verification-evidence'],
|
|
440
|
+
mirrorConsistencyRequired: true,
|
|
441
|
+
},
|
|
442
|
+
'review-release': {
|
|
443
|
+
verificationPolicy: 'evidence-first',
|
|
444
|
+
completionRule: 'report-findings-not-implementation',
|
|
445
|
+
delegationPolicy: 'allow-review-sidecar',
|
|
446
|
+
completionEvidence: ['verification-evidence'],
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
return contracts[executionMode] ? { ...contracts[executionMode] } : null;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function buildApproachSelectorResult({
|
|
454
|
+
executionMode = null,
|
|
455
|
+
executionScores = null,
|
|
456
|
+
} = {}) {
|
|
457
|
+
if (!executionMode) {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
462
|
+
const policyByMode = {
|
|
463
|
+
'tiny-fix': {
|
|
464
|
+
riskLevel: 'minimal',
|
|
465
|
+
contextPolicy: 'confirm-target-only',
|
|
466
|
+
},
|
|
467
|
+
'local-fix': {
|
|
468
|
+
riskLevel: 'local',
|
|
469
|
+
contextPolicy: 'bounded-local',
|
|
470
|
+
},
|
|
471
|
+
'local-build': {
|
|
472
|
+
riskLevel: 'local',
|
|
473
|
+
contextPolicy: 'bounded-with-related-files',
|
|
474
|
+
},
|
|
475
|
+
'find-cause': {
|
|
476
|
+
riskLevel: 'investigation',
|
|
477
|
+
contextPolicy: 'trace-then-bounded-context',
|
|
478
|
+
},
|
|
479
|
+
'shared-edit': {
|
|
480
|
+
riskLevel: 'shared',
|
|
481
|
+
contextPolicy: 'bounded-with-related-tests',
|
|
482
|
+
},
|
|
483
|
+
'map-impact': {
|
|
484
|
+
riskLevel: 'wide',
|
|
485
|
+
contextPolicy: 'impact-map-first',
|
|
486
|
+
},
|
|
487
|
+
'review-release': {
|
|
488
|
+
riskLevel: 'release',
|
|
489
|
+
contextPolicy: 'evidence-review-only',
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
const selectedPolicy = policyByMode[executionMode] ?? {
|
|
493
|
+
riskLevel: 'local',
|
|
494
|
+
contextPolicy: 'bounded-local',
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
return {
|
|
498
|
+
executionMode,
|
|
499
|
+
executionScores: executionScores ? { ...executionScores } : null,
|
|
500
|
+
riskLevel: selectedPolicy.riskLevel,
|
|
501
|
+
contextPolicy: selectedPolicy.contextPolicy,
|
|
502
|
+
verificationPolicy: executionContract?.verificationPolicy ?? null,
|
|
503
|
+
completionRule: executionContract?.completionRule ?? null,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function buildCompletionState({ executionMode = null, verificationRecommendation = null } = {}) {
|
|
508
|
+
if (!executionMode) {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const contract = buildExecutionContract(executionMode);
|
|
513
|
+
const missingEvidence = [...(contract?.completionEvidence ?? [])];
|
|
514
|
+
const requiresVerification = missingEvidence.includes('verification-evidence');
|
|
515
|
+
if (
|
|
516
|
+
requiresVerification
|
|
517
|
+
&& verificationRecommendation
|
|
518
|
+
&& !(verificationRecommendation.commands?.length || verificationRecommendation.fallbackCommands?.length)
|
|
519
|
+
) {
|
|
520
|
+
missingEvidence.push('verification-plan');
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
let reason = 'completion evidence is still required';
|
|
524
|
+
if (['tiny-fix', 'local-fix', 'local-build', 'shared-edit'].includes(executionMode)) {
|
|
525
|
+
reason = 'implement request has not produced an edit yet';
|
|
526
|
+
} else if (executionMode === 'review-release') {
|
|
527
|
+
reason = 'review/release evidence is still required before final claim';
|
|
528
|
+
} else if (executionMode === 'map-impact') {
|
|
529
|
+
reason = 'impact evidence is still required before safe completion claim';
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return {
|
|
533
|
+
claimAllowed: false,
|
|
534
|
+
missingEvidence,
|
|
535
|
+
reason,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function buildContinuationState({
|
|
540
|
+
nextActionType = null,
|
|
541
|
+
completionState = null,
|
|
542
|
+
} = {}) {
|
|
543
|
+
const reasons = [];
|
|
544
|
+
const missingEvidence = unique(completionState?.missingEvidence ?? []);
|
|
545
|
+
|
|
546
|
+
if (nextActionType === 'pull-indexed-context') {
|
|
547
|
+
reasons.push('pending-bounded-context');
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (nextActionType === 'read-skill-instructions') {
|
|
551
|
+
reasons.push('pending-skill-read');
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (missingEvidence.includes('write-evidence')) {
|
|
555
|
+
reasons.push('missing-write-evidence');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (missingEvidence.includes('verification-evidence') || missingEvidence.includes('verification-plan')) {
|
|
559
|
+
reasons.push('missing-verification-evidence');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (missingEvidence.includes('impact-evidence')) {
|
|
563
|
+
reasons.push('missing-impact-evidence');
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const nextMilestone = reasons.includes('pending-bounded-context')
|
|
567
|
+
? 'complete-bounded-context-then-continue'
|
|
568
|
+
: (
|
|
569
|
+
reasons.includes('missing-write-evidence')
|
|
570
|
+
? 'produce-write-evidence'
|
|
571
|
+
: (
|
|
572
|
+
reasons.includes('missing-verification-evidence')
|
|
573
|
+
? 'produce-verification-evidence'
|
|
574
|
+
: (
|
|
575
|
+
reasons.includes('missing-impact-evidence')
|
|
576
|
+
? 'produce-impact-evidence'
|
|
577
|
+
: null
|
|
578
|
+
)
|
|
579
|
+
)
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
return {
|
|
583
|
+
required: reasons.length > 0,
|
|
584
|
+
reasons,
|
|
585
|
+
doneLanguageBlocked: reasons.length > 0,
|
|
586
|
+
stopAllowedOnlyFor: reasons.length > 0 ? ['real-blocker'] : [],
|
|
587
|
+
nextMilestone,
|
|
588
|
+
repeatCount: reasons.length > 0 ? 1 : 0,
|
|
589
|
+
stuckRisk: null,
|
|
590
|
+
rescueMode: null,
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
232
594
|
async function selectActiveSkills({ rootDir, promptText, commandText, targetFile, intentMode = null }) {
|
|
233
595
|
const routeSignals = {
|
|
234
596
|
promptRawText: String(promptText || '').toLowerCase(),
|
|
@@ -269,6 +631,10 @@ function shouldKeepRouteEntryForIntent(entry, intentMode) {
|
|
|
269
631
|
return false;
|
|
270
632
|
}
|
|
271
633
|
|
|
634
|
+
if (entry.id === 'code-review' && intentMode === 'implement-specific') {
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
|
|
272
638
|
return true;
|
|
273
639
|
}
|
|
274
640
|
|
|
@@ -313,6 +679,10 @@ function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
|
313
679
|
routeSignals.commandRawText ?? '',
|
|
314
680
|
routeSignals.commandNormalizedText ?? '',
|
|
315
681
|
].join('\n');
|
|
682
|
+
const rawPromptSignals = [
|
|
683
|
+
routeSignals.promptRawText ?? '',
|
|
684
|
+
routeSignals.commandRawText ?? '',
|
|
685
|
+
].join('\n');
|
|
316
686
|
|
|
317
687
|
if (
|
|
318
688
|
skillId === 'testing-quality'
|
|
@@ -321,6 +691,14 @@ function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
|
321
691
|
return 1;
|
|
322
692
|
}
|
|
323
693
|
|
|
694
|
+
if (
|
|
695
|
+
skillId === 'code-review'
|
|
696
|
+
&& /\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(rawPromptSignals)
|
|
697
|
+
&& !/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(rawPromptSignals)
|
|
698
|
+
) {
|
|
699
|
+
return -4;
|
|
700
|
+
}
|
|
701
|
+
|
|
324
702
|
return 0;
|
|
325
703
|
}
|
|
326
704
|
|
|
@@ -374,10 +752,10 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
|
|
|
374
752
|
if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|login|timeout)\b/.test(lower)) {
|
|
375
753
|
return 'debug-specific';
|
|
376
754
|
}
|
|
377
|
-
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(
|
|
755
|
+
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(raw)) {
|
|
378
756
|
return 'review-specific';
|
|
379
757
|
}
|
|
380
|
-
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature)\b/.test(
|
|
758
|
+
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(raw)) {
|
|
381
759
|
return 'implement-specific';
|
|
382
760
|
}
|
|
383
761
|
}
|
|
@@ -409,7 +787,7 @@ function hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext = false }
|
|
|
409
787
|
return true;
|
|
410
788
|
}
|
|
411
789
|
|
|
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)
|
|
790
|
+
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
791
|
|| /\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
792
|
}
|
|
415
793
|
|
|
@@ -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.
|