@ngockhoale/ukit 1.4.0 → 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 +24 -0
- package/package.json +1 -1
- package/src/bug/triageBug.js +1 -33
- package/src/cli/commands/install.js +5 -10
- package/src/context/detectProjectContext.js +3 -24
- package/src/core/compact/index.js +19 -27
- package/src/core/ensureGitignore.js +1 -1
- package/src/core/fileOps.js +41 -2
- package/src/core/memory/hygiene.js +17 -1
- package/src/core/memory/store.js +14 -36
- package/src/core/metadata.js +5 -5
- package/src/core/output/index.js +20 -20
- package/src/core/packageManager.js +51 -0
- package/src/core/router/router.js +22 -6
- package/src/core/runInstallPipeline.js +1 -36
- package/src/core/runtimeConfig.js +71 -3
- package/src/core/token/index.js +21 -1
- package/src/core/uninstall.js +15 -38
- package/src/index/buildIndex.js +217 -49
- package/src/index/gitHooks.js +32 -7
- package/src/index/impactContext.js +16 -6
- package/src/index/importResolution.js +105 -28
- package/src/index/paths.js +29 -0
- package/src/index/queryIndex.js +20 -35
- package/src/index/relatedTests.js +15 -2
- package/src/index/routeCatalog.js +1 -1
- package/src/index/taskRouting.js +438 -18
- package/src/index/verificationPlan.js +2 -36
- 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-catalog.mjs +1 -1
- 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
|
@@ -176,6 +176,26 @@ const { pathToFileURL } = require('url');
|
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
function shouldKeepRouteEntryForIntent(entry, intentMode) {
|
|
180
|
+
if (entry.id === 'next-step' && ['scoped-advice', 'docs-specific'].includes(intentMode)) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (entry.id === 'update-status' && intentMode === 'docs-specific') {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (entry.id === 'docs-quality' && ['open-ended-status', 'status-update'].includes(intentMode)) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (entry.id === 'code-review' && intentMode === 'implement-specific') {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
179
199
|
function deriveSkillPriorityBoost(skillId, routeSignals = {}) {
|
|
180
200
|
const combinedPromptSignals = [
|
|
181
201
|
routeSignals.promptRawText || '',
|
|
@@ -183,6 +203,10 @@ const { pathToFileURL } = require('url');
|
|
|
183
203
|
routeSignals.commandRawText || '',
|
|
184
204
|
routeSignals.commandNormalizedText || '',
|
|
185
205
|
].join('\n');
|
|
206
|
+
const rawPromptSignals = [
|
|
207
|
+
routeSignals.promptRawText || '',
|
|
208
|
+
routeSignals.commandRawText || '',
|
|
209
|
+
].join('\n');
|
|
186
210
|
|
|
187
211
|
if (
|
|
188
212
|
skillId === 'testing-quality'
|
|
@@ -191,6 +215,14 @@ const { pathToFileURL } = require('url');
|
|
|
191
215
|
return 1;
|
|
192
216
|
}
|
|
193
217
|
|
|
218
|
+
if (
|
|
219
|
+
skillId === 'code-review'
|
|
220
|
+
&& /\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(rawPromptSignals)
|
|
221
|
+
&& !/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(rawPromptSignals)
|
|
222
|
+
) {
|
|
223
|
+
return -4;
|
|
224
|
+
}
|
|
225
|
+
|
|
194
226
|
return 0;
|
|
195
227
|
}
|
|
196
228
|
|
|
@@ -215,6 +247,131 @@ const { pathToFileURL } = require('url');
|
|
|
215
247
|
};
|
|
216
248
|
}
|
|
217
249
|
|
|
250
|
+
function deriveIntentMode({ promptText = '', commandText = '', targetFile = null } = {}) {
|
|
251
|
+
const lower = buildRouteSignalText(promptText, commandText);
|
|
252
|
+
const raw = `${promptText || ''}\n${commandText || ''}`.toLowerCase();
|
|
253
|
+
const taskQueueNext = hasTaskQueueNextSignal(lower, raw);
|
|
254
|
+
const docsSpecific = hasDocsSpecificTaskSignal(lower, raw, targetFile, { taskQueueNext });
|
|
255
|
+
const statusUpdate = hasStatusUpdateSignal(lower, raw);
|
|
256
|
+
const openEndedStatus = hasOpenEndedStatusSignal(lower, raw) || taskQueueNext;
|
|
257
|
+
const concreteTask = hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext });
|
|
258
|
+
|
|
259
|
+
if (docsSpecific) {
|
|
260
|
+
return 'docs-specific';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (statusUpdate) {
|
|
264
|
+
return 'status-update';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (concreteTask && openEndedStatus) {
|
|
268
|
+
return 'scoped-advice';
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (openEndedStatus) {
|
|
272
|
+
return 'open-ended-status';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (concreteTask) {
|
|
276
|
+
if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|login|timeout)\b/.test(lower)) {
|
|
277
|
+
return 'debug-specific';
|
|
278
|
+
}
|
|
279
|
+
if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(raw)) {
|
|
280
|
+
return 'review-specific';
|
|
281
|
+
}
|
|
282
|
+
if (/\b(implement|build|create|add|ship|deliver|refactor|integrate|integration|scaffold|feature|update|change|modify|inject|apply)\b/.test(raw)) {
|
|
283
|
+
return 'implement-specific';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function hasStatusUpdateSignal(lower, raw) {
|
|
291
|
+
return /\b(update|refresh|write|sync|record|capture|summarize|summarise).{0,64}\b(status\.md|project status|current state|next candidates|session state)\b/.test(lower)
|
|
292
|
+
|| /\b(status\.md|project status).{0,64}\b(update|refresh|write|sync|record|capture|summarize|summarise)\b/.test(lower)
|
|
293
|
+
|| /\b(wrap up|handoff|end this session|ending this session|session summary|before final)\b/.test(lower)
|
|
294
|
+
|| /\b(cap nhat|ghi lai|tong ket|chot session|ban giao).{0,64}\b(status|trang thai|viec tiep theo)\b/.test(lower)
|
|
295
|
+
|| /\b(cập nhật|ghi lại|tổng kết|chốt session|bàn giao).{0,64}\b(status|trạng thái|việc tiếp theo)\b/.test(raw);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function hasOpenEndedStatusSignal(lower, raw) {
|
|
299
|
+
return /\b(what next|what is next|what's next|next step|next steps|project status|current status|where are we|continue|continue from last session|roadmap|status\.md|task queue|tasks\.md|next queued task|pick next task|work from tasks)\b/.test(lower)
|
|
300
|
+
|| /\b(lam gi tiep|buoc tiep theo|tiep theo lam gi|lam tiep|dang o dau|trang thai project|tinh trang project|task tiep theo|viec tiep theo trong tasks)\b/.test(lower)
|
|
301
|
+
|| /\b(làm gì tiếp|bước tiếp theo|tiếp theo làm gì|làm tiếp|đang ở đâu|trạng thái project|tình trạng project|task tiếp theo|việc tiếp theo trong tasks)\b/.test(raw);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function hasTaskQueueNextSignal(lower, raw) {
|
|
305
|
+
return /\b(task queue|tasks\.md|next queued task|pick next task|work from tasks|next task from tasks|ready for ai)\b/.test(lower)
|
|
306
|
+
|| /\b(task tiếp theo|việc tiếp theo trong tasks|làm task trong tasks|lấy task tiếp theo)\b/.test(raw);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext = false } = {}) {
|
|
310
|
+
if (targetFile && !isStatusFileTarget(targetFile) && !(taskQueueNext && isTasksFileTarget(targetFile))) {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
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)
|
|
315
|
+
|| /\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);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function hasDocsSpecificTaskSignal(lower, raw, targetFile, { taskQueueNext = false } = {}) {
|
|
319
|
+
if (!targetFile || !isDocsTarget(targetFile)) {
|
|
320
|
+
return /\b(clean tasks|cleanup tasks|prune tasks|dedupe tasks|clear completed tasks|dọn tasks|dọn task)\b/.test(lower)
|
|
321
|
+
|| /\b(dọn tasks|dọn task|dọn danh sách task|xóa task đã xong)\b/.test(raw);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (taskQueueNext && isTasksFileTarget(targetFile) && !/\b(clean|cleanup|prune|dedupe|edit|template|wording|format|structure)\b/.test(lower)) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const targetName = path.posix.basename(String(targetFile || '').replaceAll('\\', '/')).toLowerCase();
|
|
329
|
+
const explicitStatusUpdate = hasExplicitStatusUpdateSignal(lower, raw);
|
|
330
|
+
|
|
331
|
+
if (!isStatusFileTarget(targetFile)) {
|
|
332
|
+
if (explicitStatusUpdate && !mentionsTargetDoc(lower, targetName)) {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return mentionsTargetDoc(lower, targetName)
|
|
337
|
+
|| /\b(edit|write|improve|document|docs?|readme|changelog|worklog|memory|code map|template|wording|copy|grammar|format|structure|heading|section|handoff notes?)\b/.test(lower)
|
|
338
|
+
|| /\b(câu chữ|chỉnh|sửa chữ|ngữ pháp|định dạng|cấu trúc|tài liệu|ghi chú bàn giao)\b/.test(raw);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return /\b(template|wording|edit|copy|grammar|format|structure|heading|section|docs?)\b/.test(lower)
|
|
342
|
+
|| /\b(mẫu|câu chữ|chỉnh|sửa chữ|ngữ pháp|định dạng|cấu trúc|tài liệu)\b/.test(raw);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function hasExplicitStatusUpdateSignal(lower, raw) {
|
|
346
|
+
return /\b(update|refresh|write|sync|record|capture|summarize|summarise).{0,64}\b(status\.md|project status|current state|next candidates|session state)\b/.test(lower)
|
|
347
|
+
|| /\b(status\.md|project status).{0,64}\b(update|refresh|write|sync|record|capture|summarize|summarise)\b/.test(lower)
|
|
348
|
+
|| /\b(cap nhat|ghi lai|tong ket|chot session|ban giao).{0,64}\b(status|trang thai|viec tiep theo)\b/.test(lower)
|
|
349
|
+
|| /\b(cập nhật|ghi lại|tổng kết|chốt session|bàn giao).{0,64}\b(status|trạng thái|việc tiếp theo)\b/.test(raw);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function mentionsTargetDoc(lower, targetName) {
|
|
353
|
+
if (!targetName) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const escaped = targetName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
358
|
+
const withoutExt = escaped.replace(/\\\.md$/i, '');
|
|
359
|
+
return new RegExp(`\\b(?:${escaped}|${withoutExt})\\b`, 'i').test(lower);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function isStatusFileTarget(targetFile) {
|
|
363
|
+
return /(?:^|\/)docs\/STATUS\.md$|(?:^|\/)STATUS\.md$/i.test(String(targetFile || ''));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function isTasksFileTarget(targetFile) {
|
|
367
|
+
return /(?:^|\/)docs\/TASKS\.md$|(?:^|\/)TASKS\.md$/i.test(String(targetFile || ''));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function isDocsTarget(targetFile) {
|
|
371
|
+
const normalized = String(targetFile || '').replaceAll('\\', '/');
|
|
372
|
+
return /(?:^|\/)docs\/.+\.md$|(?:^|\/)(?:README|CHANGELOG|AGENTS|CLAUDE|STATUS)\.md$/i.test(normalized);
|
|
373
|
+
}
|
|
374
|
+
|
|
218
375
|
function shouldUseIndexedContext({ activeSkills = [], targetFile = null } = {}) {
|
|
219
376
|
if (activeSkills.length === 0) {
|
|
220
377
|
return Boolean(targetFile);
|
|
@@ -312,6 +469,7 @@ const { pathToFileURL } = require('url');
|
|
|
312
469
|
targetFile: routingContext.targetFile || '',
|
|
313
470
|
contextIntent: routingContext.contextIntent || '',
|
|
314
471
|
taskType: routingContext.taskType || '',
|
|
472
|
+
executionMode: routingContext.executionMode || '',
|
|
315
473
|
previousContextFingerprint: previousContextFingerprint || null,
|
|
316
474
|
});
|
|
317
475
|
}
|
|
@@ -325,6 +483,17 @@ const { pathToFileURL } = require('url');
|
|
|
325
483
|
return buildCompactMachineKey('routefp-v3', {
|
|
326
484
|
skills: activeSkills.map((item) => item.id),
|
|
327
485
|
taskType: routingContext?.taskType || null,
|
|
486
|
+
executionMode: routeSummary?.executionMode || null,
|
|
487
|
+
approachRiskLevel: routeSummary?.approachSelector?.riskLevel || null,
|
|
488
|
+
approachContextPolicy: routeSummary?.approachSelector?.contextPolicy || null,
|
|
489
|
+
approachVerificationPolicy: routeSummary?.approachSelector?.verificationPolicy || null,
|
|
490
|
+
approachCompletionRule: routeSummary?.approachSelector?.completionRule || null,
|
|
491
|
+
continuationRequired: routeSummary?.continuationState?.required || null,
|
|
492
|
+
continuationReasons: unique(routeSummary?.continuationState?.reasons ?? []),
|
|
493
|
+
continuationMilestone: routeSummary?.continuationState?.nextMilestone || null,
|
|
494
|
+
continuationRepeatCount: routeSummary?.continuationState?.repeatCount || null,
|
|
495
|
+
continuationStuckRisk: routeSummary?.continuationState?.stuckRisk || null,
|
|
496
|
+
continuationRescueMode: routeSummary?.continuationState?.rescueMode || null,
|
|
328
497
|
previousContextLine: previousContext?.line || null,
|
|
329
498
|
previousContextIds: unique(previousContext?.selectedIds ?? []),
|
|
330
499
|
policyMode: routeSummary?.policyMode || null,
|
|
@@ -332,6 +501,8 @@ const { pathToFileURL } = require('url');
|
|
|
332
501
|
nextActionType: routeSummary?.nextActionType || null,
|
|
333
502
|
nextActionCommand: routeSummary?.nextActionCommand || null,
|
|
334
503
|
helperHint: routeSummary?.helperHint || null,
|
|
504
|
+
completionRule: routeSummary?.executionContract?.completionRule || null,
|
|
505
|
+
completionMissingEvidence: unique(routeSummary?.completionState?.missingEvidence ?? []),
|
|
335
506
|
primaryCommands: [...new Set((routeSummary?.primaryCommands || []).filter(Boolean))],
|
|
336
507
|
fallbackCommands: [...new Set((routeSummary?.fallbackCommands || []).filter(Boolean))],
|
|
337
508
|
preferredOrder: [...new Set((routeSummary?.preferredOrder || []).filter(Boolean))],
|
|
@@ -397,11 +568,16 @@ const { pathToFileURL } = require('url');
|
|
|
397
568
|
return 'non-trivial';
|
|
398
569
|
}
|
|
399
570
|
|
|
571
|
+
let inferred = 'simple';
|
|
400
572
|
if (/\b(typo|label|text|rename|color|spacing|toggle|comment)\b/.test(lower)) {
|
|
401
|
-
|
|
573
|
+
inferred = 'trivial';
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if ((inferred === 'simple' || inferred === 'trivial') && isSharedImpactFile(targetFile)) {
|
|
577
|
+
return 'shared-simple';
|
|
402
578
|
}
|
|
403
579
|
|
|
404
|
-
return
|
|
580
|
+
return inferred;
|
|
405
581
|
}
|
|
406
582
|
|
|
407
583
|
function shellEscape(value) {
|
|
@@ -1129,6 +1305,21 @@ const { pathToFileURL } = require('url');
|
|
|
1129
1305
|
const compactHelperLane = nextAction?.type === 'pull-indexed-context'
|
|
1130
1306
|
&& typeof contextRecommendation?.command === 'string'
|
|
1131
1307
|
&& contextRecommendation.command.trim();
|
|
1308
|
+
const executionMode = routingContext.executionMode || null;
|
|
1309
|
+
const executionScores = routingContext.executionScores || null;
|
|
1310
|
+
const approachSelector = buildApproachSelectorResult({
|
|
1311
|
+
executionMode,
|
|
1312
|
+
executionScores,
|
|
1313
|
+
});
|
|
1314
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
1315
|
+
const completionState = buildCompletionState({
|
|
1316
|
+
executionMode,
|
|
1317
|
+
verificationRecommendation,
|
|
1318
|
+
});
|
|
1319
|
+
const continuationState = buildContinuationState({
|
|
1320
|
+
nextActionType: nextAction?.type || null,
|
|
1321
|
+
completionState,
|
|
1322
|
+
});
|
|
1132
1323
|
const helperHint = compactHelperHint(
|
|
1133
1324
|
compactHelperLane
|
|
1134
1325
|
? contextRecommendation?.command
|
|
@@ -1152,6 +1343,12 @@ const { pathToFileURL } = require('url');
|
|
|
1152
1343
|
fallbackCommands,
|
|
1153
1344
|
preferredOrder,
|
|
1154
1345
|
policyMode,
|
|
1346
|
+
executionMode,
|
|
1347
|
+
executionScores,
|
|
1348
|
+
approachSelector,
|
|
1349
|
+
executionContract,
|
|
1350
|
+
completionState,
|
|
1351
|
+
continuationState,
|
|
1155
1352
|
delegateHint: delegationRecommendation?.hint || null,
|
|
1156
1353
|
nextActionType: nextAction?.type || null,
|
|
1157
1354
|
nextActionCommand,
|
|
@@ -1160,6 +1357,396 @@ const { pathToFileURL } = require('url');
|
|
|
1160
1357
|
};
|
|
1161
1358
|
}
|
|
1162
1359
|
|
|
1360
|
+
function deriveExecutionScores({
|
|
1361
|
+
promptText = '',
|
|
1362
|
+
commandText = '',
|
|
1363
|
+
targetFile = null,
|
|
1364
|
+
intentMode = null,
|
|
1365
|
+
taskType = null,
|
|
1366
|
+
} = {}) {
|
|
1367
|
+
const raw = `${promptText || ''}\n${commandText || ''}`.toLowerCase();
|
|
1368
|
+
const sharedRisk = isSharedImpactFile(targetFile);
|
|
1369
|
+
const directTransformSignal = /\b(change|replace|set|rename|convert|swap)\b/.test(raw) || /\bchange\s+.+\s+to\s+.+\b/.test(raw);
|
|
1370
|
+
const smallFixSignal = /\b(adjust|tweak|patch|fix|modify|update|apply)\b/.test(raw);
|
|
1371
|
+
const buildSignal = /\b(build|create|add|implement|feature)\b/.test(raw);
|
|
1372
|
+
const debugSignal = intentMode === 'debug-specific' || /\b(root cause|debug|triage|flaky|investigate|why)\b/.test(raw);
|
|
1373
|
+
const reviewSignal = intentMode === 'review-specific' || /\b(review|audit|verify|release readiness)\b/.test(raw);
|
|
1374
|
+
|
|
1375
|
+
let editCertainty = 0;
|
|
1376
|
+
if (directTransformSignal) {
|
|
1377
|
+
editCertainty = 3;
|
|
1378
|
+
} else if (smallFixSignal) {
|
|
1379
|
+
editCertainty = 2;
|
|
1380
|
+
} else if (buildSignal) {
|
|
1381
|
+
editCertainty = 1;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
let investigationNeed = 0;
|
|
1385
|
+
if (debugSignal) {
|
|
1386
|
+
investigationNeed = 3;
|
|
1387
|
+
} else if (/\b(failing|broken|error|crash|timeout)\b/.test(raw)) {
|
|
1388
|
+
investigationNeed = 2;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
let blastRadius = 0;
|
|
1392
|
+
if (sharedRisk) {
|
|
1393
|
+
blastRadius = 3;
|
|
1394
|
+
} else if (taskType === 'non-trivial' || taskType === 'shared-simple') {
|
|
1395
|
+
blastRadius = 2;
|
|
1396
|
+
} else if (!targetFile) {
|
|
1397
|
+
blastRadius = 1;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
let verificationBurden = 1;
|
|
1401
|
+
if (reviewSignal || sharedRisk) {
|
|
1402
|
+
verificationBurden = 3;
|
|
1403
|
+
} else if (debugSignal || taskType === 'non-trivial') {
|
|
1404
|
+
verificationBurden = 2;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
let ambiguity = 0;
|
|
1408
|
+
if (!targetFile) {
|
|
1409
|
+
ambiguity = 2;
|
|
1410
|
+
} else if (buildSignal && !directTransformSignal && !smallFixSignal) {
|
|
1411
|
+
ambiguity = 1;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
return {
|
|
1415
|
+
editCertainty,
|
|
1416
|
+
investigationNeed,
|
|
1417
|
+
blastRadius,
|
|
1418
|
+
verificationBurden,
|
|
1419
|
+
ambiguity,
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
function deriveExecutionMode({
|
|
1424
|
+
promptText = '',
|
|
1425
|
+
commandText = '',
|
|
1426
|
+
targetFile = null,
|
|
1427
|
+
intentMode = null,
|
|
1428
|
+
executionScores = {},
|
|
1429
|
+
} = {}) {
|
|
1430
|
+
const raw = `${promptText || ''}\n${commandText || ''}`.toLowerCase();
|
|
1431
|
+
const scores = executionScores;
|
|
1432
|
+
const explicitReviewLead = /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw);
|
|
1433
|
+
|
|
1434
|
+
if (intentMode === 'review-specific' || explicitReviewLead) {
|
|
1435
|
+
return 'review-release';
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
if (scores.blastRadius >= 3 && (scores.ambiguity >= 2 || scores.investigationNeed >= 2)) {
|
|
1439
|
+
return 'map-impact';
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
if (scores.blastRadius >= 3 || isSharedImpactFile(targetFile)) {
|
|
1443
|
+
return 'shared-edit';
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
if (scores.investigationNeed >= 3) {
|
|
1447
|
+
return 'find-cause';
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
if (
|
|
1451
|
+
scores.editCertainty >= 3
|
|
1452
|
+
&& scores.ambiguity === 0
|
|
1453
|
+
&& scores.blastRadius === 0
|
|
1454
|
+
&& scores.verificationBurden <= 1
|
|
1455
|
+
) {
|
|
1456
|
+
return 'tiny-fix';
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if (
|
|
1460
|
+
/\b(build|create|add|implement|feature|summary card)\b/.test(raw)
|
|
1461
|
+
&& scores.investigationNeed === 0
|
|
1462
|
+
&& scores.blastRadius < 3
|
|
1463
|
+
) {
|
|
1464
|
+
return 'local-build';
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
if (scores.editCertainty >= 2 && scores.investigationNeed === 0 && scores.blastRadius === 0) {
|
|
1468
|
+
return 'local-fix';
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
return 'local-build';
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
function buildExecutionContract(executionMode = null) {
|
|
1475
|
+
if (!executionMode) {
|
|
1476
|
+
return null;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
const contracts = {
|
|
1480
|
+
'tiny-fix': {
|
|
1481
|
+
maxReadPasses: 0,
|
|
1482
|
+
maxContextPulls: 0,
|
|
1483
|
+
verificationPolicy: 'minimal-or-targeted',
|
|
1484
|
+
completionRule: 'never-claim-done-without-write',
|
|
1485
|
+
delegationPolicy: 'disallow',
|
|
1486
|
+
completionEvidence: ['write-evidence'],
|
|
1487
|
+
},
|
|
1488
|
+
'local-fix': {
|
|
1489
|
+
maxReadPasses: 1,
|
|
1490
|
+
maxContextPulls: 1,
|
|
1491
|
+
verificationPolicy: 'targeted-if-covered',
|
|
1492
|
+
completionRule: 'require-write',
|
|
1493
|
+
delegationPolicy: 'disallow',
|
|
1494
|
+
completionEvidence: ['write-evidence'],
|
|
1495
|
+
},
|
|
1496
|
+
'local-build': {
|
|
1497
|
+
maxReadPasses: 2,
|
|
1498
|
+
maxContextPulls: 1,
|
|
1499
|
+
verificationPolicy: 'targeted-if-covered',
|
|
1500
|
+
completionRule: 'require-write',
|
|
1501
|
+
delegationPolicy: 'disallow-by-default',
|
|
1502
|
+
completionEvidence: ['write-evidence'],
|
|
1503
|
+
},
|
|
1504
|
+
'find-cause': {
|
|
1505
|
+
maxReadPassesBeforeReassess: 3,
|
|
1506
|
+
verificationPolicy: 'root-cause-then-targeted',
|
|
1507
|
+
completionRule: 'never-claim-fixed-without-write-and-verification',
|
|
1508
|
+
delegationPolicy: 'allow-specialized-debug-lane',
|
|
1509
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
1510
|
+
},
|
|
1511
|
+
'shared-edit': {
|
|
1512
|
+
maxReadPasses: 2,
|
|
1513
|
+
maxContextPulls: 2,
|
|
1514
|
+
verificationPolicy: 'targeted-then-widen-on-risk',
|
|
1515
|
+
completionRule: 'require-write-and-verification',
|
|
1516
|
+
delegationPolicy: 'allow-qualified-sidecar',
|
|
1517
|
+
completionEvidence: ['write-evidence', 'verification-evidence'],
|
|
1518
|
+
mirrorConsistencyRequired: true,
|
|
1519
|
+
},
|
|
1520
|
+
'map-impact': {
|
|
1521
|
+
maxReadPasses: 3,
|
|
1522
|
+
maxContextPulls: 3,
|
|
1523
|
+
verificationPolicy: 'impact-first-then-targeted-then-widen-on-risk',
|
|
1524
|
+
completionRule: 'require-impact-evidence-before-edit-claim',
|
|
1525
|
+
delegationPolicy: 'allow-impact-sidecar',
|
|
1526
|
+
completionEvidence: ['impact-evidence', 'write-evidence', 'verification-evidence'],
|
|
1527
|
+
mirrorConsistencyRequired: true,
|
|
1528
|
+
},
|
|
1529
|
+
'review-release': {
|
|
1530
|
+
verificationPolicy: 'evidence-first',
|
|
1531
|
+
completionRule: 'report-findings-not-implementation',
|
|
1532
|
+
delegationPolicy: 'allow-review-sidecar',
|
|
1533
|
+
completionEvidence: ['verification-evidence'],
|
|
1534
|
+
},
|
|
1535
|
+
};
|
|
1536
|
+
|
|
1537
|
+
return contracts[executionMode] ? { ...contracts[executionMode] } : null;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function buildApproachSelectorResult({
|
|
1541
|
+
executionMode = null,
|
|
1542
|
+
executionScores = null,
|
|
1543
|
+
} = {}) {
|
|
1544
|
+
if (!executionMode) {
|
|
1545
|
+
return null;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
const executionContract = buildExecutionContract(executionMode);
|
|
1549
|
+
const policyByMode = {
|
|
1550
|
+
'tiny-fix': {
|
|
1551
|
+
riskLevel: 'minimal',
|
|
1552
|
+
contextPolicy: 'confirm-target-only',
|
|
1553
|
+
},
|
|
1554
|
+
'local-fix': {
|
|
1555
|
+
riskLevel: 'local',
|
|
1556
|
+
contextPolicy: 'bounded-local',
|
|
1557
|
+
},
|
|
1558
|
+
'local-build': {
|
|
1559
|
+
riskLevel: 'local',
|
|
1560
|
+
contextPolicy: 'bounded-with-related-files',
|
|
1561
|
+
},
|
|
1562
|
+
'find-cause': {
|
|
1563
|
+
riskLevel: 'investigation',
|
|
1564
|
+
contextPolicy: 'trace-then-bounded-context',
|
|
1565
|
+
},
|
|
1566
|
+
'shared-edit': {
|
|
1567
|
+
riskLevel: 'shared',
|
|
1568
|
+
contextPolicy: 'bounded-with-related-tests',
|
|
1569
|
+
},
|
|
1570
|
+
'map-impact': {
|
|
1571
|
+
riskLevel: 'wide',
|
|
1572
|
+
contextPolicy: 'impact-map-first',
|
|
1573
|
+
},
|
|
1574
|
+
'review-release': {
|
|
1575
|
+
riskLevel: 'release',
|
|
1576
|
+
contextPolicy: 'evidence-review-only',
|
|
1577
|
+
},
|
|
1578
|
+
};
|
|
1579
|
+
const selectedPolicy = policyByMode[executionMode] ?? {
|
|
1580
|
+
riskLevel: 'local',
|
|
1581
|
+
contextPolicy: 'bounded-local',
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
return {
|
|
1585
|
+
executionMode,
|
|
1586
|
+
executionScores: executionScores ? { ...executionScores } : null,
|
|
1587
|
+
riskLevel: selectedPolicy.riskLevel,
|
|
1588
|
+
contextPolicy: selectedPolicy.contextPolicy,
|
|
1589
|
+
verificationPolicy: executionContract?.verificationPolicy ?? null,
|
|
1590
|
+
completionRule: executionContract?.completionRule ?? null,
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
function buildCompletionState({ executionMode = null, verificationRecommendation = null } = {}) {
|
|
1595
|
+
if (!executionMode) {
|
|
1596
|
+
return null;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
const contract = buildExecutionContract(executionMode);
|
|
1600
|
+
const missingEvidence = [...(contract?.completionEvidence ?? [])];
|
|
1601
|
+
const requiresVerification = missingEvidence.includes('verification-evidence');
|
|
1602
|
+
if (
|
|
1603
|
+
requiresVerification
|
|
1604
|
+
&& verificationRecommendation
|
|
1605
|
+
&& !(verificationRecommendation.commands?.length || verificationRecommendation.fallbackCommands?.length)
|
|
1606
|
+
) {
|
|
1607
|
+
missingEvidence.push('verification-plan');
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
let reason = 'completion evidence is still required';
|
|
1611
|
+
if (['tiny-fix', 'local-fix', 'local-build', 'shared-edit'].includes(executionMode)) {
|
|
1612
|
+
reason = 'implement request has not produced an edit yet';
|
|
1613
|
+
} else if (executionMode === 'review-release') {
|
|
1614
|
+
reason = 'review/release evidence is still required before final claim';
|
|
1615
|
+
} else if (executionMode === 'map-impact') {
|
|
1616
|
+
reason = 'impact evidence is still required before safe completion claim';
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
return {
|
|
1620
|
+
claimAllowed: false,
|
|
1621
|
+
missingEvidence,
|
|
1622
|
+
reason,
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
function buildContinuationState({
|
|
1627
|
+
nextActionType = null,
|
|
1628
|
+
completionState = null,
|
|
1629
|
+
} = {}) {
|
|
1630
|
+
const reasons = [];
|
|
1631
|
+
const missingEvidence = unique(completionState?.missingEvidence ?? []);
|
|
1632
|
+
|
|
1633
|
+
if (nextActionType === 'pull-indexed-context') {
|
|
1634
|
+
reasons.push('pending-bounded-context');
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
if (nextActionType === 'read-skill-instructions') {
|
|
1638
|
+
reasons.push('pending-skill-read');
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
if (missingEvidence.includes('write-evidence')) {
|
|
1642
|
+
reasons.push('missing-write-evidence');
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
if (missingEvidence.includes('verification-evidence') || missingEvidence.includes('verification-plan')) {
|
|
1646
|
+
reasons.push('missing-verification-evidence');
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
if (missingEvidence.includes('impact-evidence')) {
|
|
1650
|
+
reasons.push('missing-impact-evidence');
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
const nextMilestone = reasons.includes('pending-bounded-context')
|
|
1654
|
+
? 'complete-bounded-context-then-continue'
|
|
1655
|
+
: (
|
|
1656
|
+
reasons.includes('missing-write-evidence')
|
|
1657
|
+
? 'produce-write-evidence'
|
|
1658
|
+
: (
|
|
1659
|
+
reasons.includes('missing-verification-evidence')
|
|
1660
|
+
? 'produce-verification-evidence'
|
|
1661
|
+
: (
|
|
1662
|
+
reasons.includes('missing-impact-evidence')
|
|
1663
|
+
? 'produce-impact-evidence'
|
|
1664
|
+
: null
|
|
1665
|
+
)
|
|
1666
|
+
)
|
|
1667
|
+
);
|
|
1668
|
+
|
|
1669
|
+
return {
|
|
1670
|
+
required: reasons.length > 0,
|
|
1671
|
+
reasons,
|
|
1672
|
+
doneLanguageBlocked: reasons.length > 0,
|
|
1673
|
+
stopAllowedOnlyFor: reasons.length > 0 ? ['real-blocker'] : [],
|
|
1674
|
+
nextMilestone,
|
|
1675
|
+
repeatCount: reasons.length > 0 ? 1 : 0,
|
|
1676
|
+
stuckRisk: null,
|
|
1677
|
+
rescueMode: null,
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
function advanceContinuationState(continuationState = null, previousContinuationState = null) {
|
|
1682
|
+
if (!continuationState || typeof continuationState !== 'object') {
|
|
1683
|
+
return continuationState;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
if (!continuationState.required) {
|
|
1687
|
+
return {
|
|
1688
|
+
...continuationState,
|
|
1689
|
+
repeatCount: 0,
|
|
1690
|
+
stuckRisk: null,
|
|
1691
|
+
rescueMode: null,
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
const currentReasons = unique(continuationState.reasons ?? []);
|
|
1696
|
+
const previousReasons = unique(previousContinuationState?.reasons ?? []);
|
|
1697
|
+
const sameMilestone = Boolean(
|
|
1698
|
+
previousContinuationState?.required
|
|
1699
|
+
&& continuationState.nextMilestone
|
|
1700
|
+
&& previousContinuationState.nextMilestone === continuationState.nextMilestone
|
|
1701
|
+
&& JSON.stringify(previousReasons) === JSON.stringify(currentReasons)
|
|
1702
|
+
);
|
|
1703
|
+
const repeatCount = sameMilestone
|
|
1704
|
+
? Math.max(1, Number(previousContinuationState?.repeatCount ?? 1) + 1)
|
|
1705
|
+
: 1;
|
|
1706
|
+
const rescueMode = repeatCount >= 2
|
|
1707
|
+
? (
|
|
1708
|
+
currentReasons.includes('pending-bounded-context')
|
|
1709
|
+
? 'finish-current-milestone-before-more-reading'
|
|
1710
|
+
: (
|
|
1711
|
+
currentReasons.includes('missing-write-evidence')
|
|
1712
|
+
? 'finish-write-before-more-analysis'
|
|
1713
|
+
: 'finish-required-milestone-before-widening'
|
|
1714
|
+
)
|
|
1715
|
+
)
|
|
1716
|
+
: null;
|
|
1717
|
+
const stuckRisk = repeatCount >= 3
|
|
1718
|
+
? 'high'
|
|
1719
|
+
: (repeatCount === 2 ? 'elevated' : null);
|
|
1720
|
+
|
|
1721
|
+
return {
|
|
1722
|
+
...continuationState,
|
|
1723
|
+
repeatCount,
|
|
1724
|
+
stuckRisk,
|
|
1725
|
+
rescueMode,
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
const SHARED_IMPACT_PATTERNS = [
|
|
1730
|
+
/^\.claude\/hooks\//,
|
|
1731
|
+
/^\.claude\/ukit\//,
|
|
1732
|
+
/^\.codex\//,
|
|
1733
|
+
/^src\/index\//,
|
|
1734
|
+
/^src\/core\/(runInstallPipeline|applyPlan|buildPlan|diffPlan|metadata|migrateLegacy|uninstall|runtimeConfig|runtimePaths)\.js$/,
|
|
1735
|
+
/^src\/core\/(output|token|compact)\//,
|
|
1736
|
+
/^templates\/\.claude\/hooks\//,
|
|
1737
|
+
/^templates\/\.claude\/ukit\//,
|
|
1738
|
+
/^manifests\/platform\.full\.yaml$/,
|
|
1739
|
+
/^templates\//,
|
|
1740
|
+
];
|
|
1741
|
+
|
|
1742
|
+
function isSharedImpactFile(filePath) {
|
|
1743
|
+
const normalized = String(filePath ?? '').trim().replace(/\\/g, '/').replace(/^\.\//, '');
|
|
1744
|
+
if (!normalized) {
|
|
1745
|
+
return false;
|
|
1746
|
+
}
|
|
1747
|
+
return SHARED_IMPACT_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1163
1750
|
function summarizeCompactList(values, limit = 2) {
|
|
1164
1751
|
const normalized = [...new Set((values || []).filter(Boolean))];
|
|
1165
1752
|
return {
|
|
@@ -1268,6 +1855,8 @@ const { pathToFileURL } = require('url');
|
|
|
1268
1855
|
return {
|
|
1269
1856
|
lastExplicitUserPromptText: routingContext.lastExplicitUserPromptText || '',
|
|
1270
1857
|
taskType: routingContext.taskType || null,
|
|
1858
|
+
intentMode: routingContext.intentMode || null,
|
|
1859
|
+
executionMode: routingContext.executionMode || null,
|
|
1271
1860
|
};
|
|
1272
1861
|
}
|
|
1273
1862
|
|
|
@@ -1299,6 +1888,12 @@ const { pathToFileURL } = require('url');
|
|
|
1299
1888
|
fallbackCommands: [...new Set((routeSummary.fallbackCommands || []).filter(Boolean))].slice(0, 3),
|
|
1300
1889
|
preferredOrder: [...new Set((routeSummary.preferredOrder || []).filter(Boolean))].slice(0, 5),
|
|
1301
1890
|
policyMode: routeSummary.policyMode || null,
|
|
1891
|
+
executionMode: routeSummary.executionMode || null,
|
|
1892
|
+
executionScores: routeSummary.executionScores || null,
|
|
1893
|
+
approachSelector: routeSummary.approachSelector || null,
|
|
1894
|
+
executionContract: routeSummary.executionContract || null,
|
|
1895
|
+
completionState: routeSummary.completionState || null,
|
|
1896
|
+
continuationState: routeSummary.continuationState || null,
|
|
1302
1897
|
delegateHint: routeSummary.delegateHint || null,
|
|
1303
1898
|
nextActionType: routeSummary.nextActionType || null,
|
|
1304
1899
|
nextActionCommand: routeSummary.nextActionCommand || null,
|
|
@@ -1373,7 +1968,7 @@ const { pathToFileURL } = require('url');
|
|
|
1373
1968
|
}
|
|
1374
1969
|
|
|
1375
1970
|
const nextActionType = String(routeSummary.nextActionType ?? '').trim();
|
|
1376
|
-
if (!nextActionType || nextActionType === 'read-skill-instructions') {
|
|
1971
|
+
if (!nextActionType || nextActionType === 'read-skill-instructions' || nextActionType === 'pull-indexed-context') {
|
|
1377
1972
|
return '';
|
|
1378
1973
|
}
|
|
1379
1974
|
|
|
@@ -1426,12 +2021,18 @@ const { pathToFileURL } = require('url');
|
|
|
1426
2021
|
commandNormalizedText: buildRouteSignalText(commandText),
|
|
1427
2022
|
fileText: String(filePath || '').toLowerCase(),
|
|
1428
2023
|
};
|
|
2024
|
+
const intentMode = deriveIntentMode({
|
|
2025
|
+
promptText,
|
|
2026
|
+
commandText,
|
|
2027
|
+
targetFile: filePath,
|
|
2028
|
+
});
|
|
1429
2029
|
|
|
1430
2030
|
const catalog = await loadRouteCatalog(projectRoot);
|
|
1431
2031
|
|
|
1432
2032
|
const active = catalog
|
|
1433
2033
|
.map((entry) => scoreSkillRouteEntry(entry, routeSignals))
|
|
1434
|
-
.filter((entry) => entry.score > 0 && existsSkill(projectRoot, entry.path))
|
|
2034
|
+
.filter((entry) => entry.score > 0 && existsSkill(projectRoot, entry.path))
|
|
2035
|
+
.filter((entry) => shouldKeepRouteEntryForIntent(entry, intentMode));
|
|
1435
2036
|
|
|
1436
2037
|
const now = Date.now();
|
|
1437
2038
|
const debounceMs = 10 * 60 * 1000;
|
|
@@ -1498,6 +2099,21 @@ const { pathToFileURL } = require('url');
|
|
|
1498
2099
|
selectedIds,
|
|
1499
2100
|
buildRouteSignalText,
|
|
1500
2101
|
});
|
|
2102
|
+
const executionScores = deriveExecutionScores({
|
|
2103
|
+
promptText,
|
|
2104
|
+
commandText,
|
|
2105
|
+
targetFile: filePath,
|
|
2106
|
+
intentMode,
|
|
2107
|
+
taskType,
|
|
2108
|
+
});
|
|
2109
|
+
const executionMode = deriveExecutionMode({
|
|
2110
|
+
promptText,
|
|
2111
|
+
commandText,
|
|
2112
|
+
targetFile: filePath,
|
|
2113
|
+
intentMode,
|
|
2114
|
+
taskType,
|
|
2115
|
+
executionScores,
|
|
2116
|
+
});
|
|
1501
2117
|
const lastExplicitUserPromptText = promptText.trim()
|
|
1502
2118
|
|| previous?.routingContext?.lastExplicitUserPromptText
|
|
1503
2119
|
|| '';
|
|
@@ -1508,6 +2124,9 @@ const { pathToFileURL } = require('url');
|
|
|
1508
2124
|
targetFile: filePath,
|
|
1509
2125
|
contextIntent,
|
|
1510
2126
|
taskType,
|
|
2127
|
+
intentMode,
|
|
2128
|
+
executionScores,
|
|
2129
|
+
executionMode,
|
|
1511
2130
|
};
|
|
1512
2131
|
const useIndexedContext = shouldUseIndexedContext({
|
|
1513
2132
|
activeSkills: selected,
|
|
@@ -1565,12 +2184,23 @@ const { pathToFileURL } = require('url');
|
|
|
1565
2184
|
&& cachedRouteState?.routeSummary
|
|
1566
2185
|
&& Array.isArray(cachedRouteState?.activeSkills)
|
|
1567
2186
|
) {
|
|
2187
|
+
const rescuedRouteSummary = cachedRouteState.routeSummary
|
|
2188
|
+
? {
|
|
2189
|
+
...cachedRouteState.routeSummary,
|
|
2190
|
+
continuationState: advanceContinuationState(
|
|
2191
|
+
cachedRouteState.routeSummary.continuationState || null,
|
|
2192
|
+
cachedRouteState.routeSummary.continuationState || null,
|
|
2193
|
+
),
|
|
2194
|
+
}
|
|
2195
|
+
: null;
|
|
1568
2196
|
const reusedState = {
|
|
1569
2197
|
...cachedRouteState,
|
|
1570
2198
|
source: 'skill-router',
|
|
1571
2199
|
ts: now,
|
|
1572
2200
|
requestKey,
|
|
2201
|
+
routeSummary: rescuedRouteSummary,
|
|
1573
2202
|
};
|
|
2203
|
+
reusedState.fingerprint = buildRouteStateFingerprint(reusedState);
|
|
1574
2204
|
|
|
1575
2205
|
if (previous?.fingerprint === reusedState.fingerprint && now - previousTs < debounceMs) {
|
|
1576
2206
|
process.exit(0);
|
|
@@ -1588,7 +2218,11 @@ const { pathToFileURL } = require('url');
|
|
|
1588
2218
|
if (reusedState.routeSummary?.delegateHint) {
|
|
1589
2219
|
process.stdout.write(`[ukit-skill-router] Delegate: ${reusedState.routeSummary.delegateHint}\n`);
|
|
1590
2220
|
}
|
|
1591
|
-
if (
|
|
2221
|
+
if (
|
|
2222
|
+
reusedState.routeSummary?.helperHint
|
|
2223
|
+
&& !reusedState.routeSummary?.nextActionCommand
|
|
2224
|
+
&& reusedState.routeSummary?.nextActionType !== 'pull-indexed-context'
|
|
2225
|
+
) {
|
|
1592
2226
|
process.stdout.write(`[ukit-skill-router] Helper: ${reusedState.routeSummary.helperHint}\n`);
|
|
1593
2227
|
}
|
|
1594
2228
|
process.exit(0);
|
|
@@ -1618,13 +2252,17 @@ const { pathToFileURL } = require('url');
|
|
|
1618
2252
|
contextRecommendation,
|
|
1619
2253
|
verificationRecommendation,
|
|
1620
2254
|
});
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
2255
|
+
const routeSummary = buildRouteSummary({
|
|
2256
|
+
activeSkills: selected,
|
|
2257
|
+
routingContext,
|
|
2258
|
+
contextRecommendation,
|
|
2259
|
+
verificationRecommendation,
|
|
2260
|
+
nextAction,
|
|
2261
|
+
});
|
|
2262
|
+
routeSummary.continuationState = advanceContinuationState(
|
|
2263
|
+
routeSummary.continuationState,
|
|
2264
|
+
previous?.routeSummary?.continuationState || null,
|
|
2265
|
+
);
|
|
1628
2266
|
|
|
1629
2267
|
const fingerprint = buildRouteStateFingerprint({
|
|
1630
2268
|
activeSkills: selected,
|
|
@@ -1669,9 +2307,13 @@ const { pathToFileURL } = require('url');
|
|
|
1669
2307
|
if (routeSummary.delegateHint) {
|
|
1670
2308
|
process.stdout.write(`[ukit-skill-router] Delegate: ${routeSummary.delegateHint}\n`);
|
|
1671
2309
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
2310
|
+
if (
|
|
2311
|
+
routeSummary.helperHint
|
|
2312
|
+
&& !routeSummary.nextActionCommand
|
|
2313
|
+
&& routeSummary.nextActionType !== 'pull-indexed-context'
|
|
2314
|
+
) {
|
|
2315
|
+
process.stdout.write(`[ukit-skill-router] Helper: ${routeSummary.helperHint}\n`);
|
|
2316
|
+
}
|
|
1675
2317
|
})().catch(() => {
|
|
1676
2318
|
process.exit(0);
|
|
1677
2319
|
});
|