@ngockhoale/ukit 3.4.28 → 3.4.30
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 +23 -0
- package/manifests/documentation.yaml +88 -0
- package/package.json +1 -1
- package/src/core/buildPlan.js +11 -1
- package/src/core/permissionPolicy.js +1 -1
- package/src/core/status.js +3 -1
- package/src/index/buildIndex.js +244 -4
- package/src/index/impactContext.js +91 -11
- package/src/index/languageTools.js +126 -0
- package/src/index/paths.js +5 -1
- package/src/index/playbookRegistry.js +108 -9
- package/src/index/queryIndex.js +415 -1
- package/src/index/routeCatalog.js +1 -1
- package/src/index/taskRouting.js +25 -3
- package/template_project/.claude/commands/ukit/handoff-create.md +5 -0
- package/template_project/.claude/commands/ukit/handoff-fullstack.md +43 -4
- package/template_project/.claude/hooks/block-dangerous.mjs +7 -1
- package/template_project/.claude/hooks/handoff-model-guard.sh +235 -21
- package/template_project/.claude/hooks/record-execution.mjs +23 -0
- package/template_project/.claude/hooks/skill-router.sh +105 -7
- package/template_project/.claude/settings.json +21 -1
- package/template_project/.claude/ukit/index/cleanup-task-worktree.mjs +1 -1
- package/template_project/.claude/ukit/index/impact-context.mjs +70 -15
- package/template_project/.claude/ukit/index/land-worktree.mjs +2 -2
- package/template_project/.claude/ukit/index/lib/index-core.mjs +883 -14
- package/template_project/.claude/ukit/index/playbook-registry.mjs +108 -9
- package/template_project/.claude/ukit/index/query-index.mjs +100 -7
- package/template_project/.claude/ukit/index/route-catalog.mjs +1 -1
- package/template_project/.claude/ukit/index/route-task.mjs +208 -31
- package/template_project/.claude/ukit/runtime/execution-ledger.mjs +455 -24
- package/template_project/.claude/ukit/runtime/handoff-intent.mjs +122 -6
- package/template_project/.claude/ukit/runtime/resumable-run.mjs +417 -0
- package/template_project/.claude/ukit/runtime/stop-coordinator.mjs +635 -28
- package/template_project/.omp/hooks/pre/ukit-bridge.js +32 -4
- package/template_user/playbooks/feature-implementation.md +9 -0
- package/template_user/playbooks/migration.md +4 -0
|
@@ -11,6 +11,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
11
11
|
import { spawnSync } from 'node:child_process';
|
|
12
12
|
import {
|
|
13
13
|
evaluateCompletion,
|
|
14
|
+
resolveStopPhase,
|
|
14
15
|
evidencePromptKey,
|
|
15
16
|
incrementContinuation,
|
|
16
17
|
markNotified,
|
|
@@ -47,6 +48,9 @@ export const HOOK_EVENT_MAP = {
|
|
|
47
48
|
'handoff-model-guard.sh',
|
|
48
49
|
'context-hardcap-gate.sh',
|
|
49
50
|
],
|
|
51
|
+
// Delegation + multi-file mutation tools. Only the create-scope guard applies: it denies
|
|
52
|
+
// implementation-capable subagents / source writes while a handoff-create session is live.
|
|
53
|
+
'MultiEdit|NotebookEdit|Agent|Task': ['handoff-model-guard.sh'],
|
|
50
54
|
Bash: [
|
|
51
55
|
'auto-allow-bash.sh',
|
|
52
56
|
'block-dangerous.mjs',
|
|
@@ -60,6 +64,8 @@ export const HOOK_EVENT_MAP = {
|
|
|
60
64
|
'Read|Grep|Glob': ['record-execution.mjs'],
|
|
61
65
|
'Edit|Write': ['post-edit-verify.sh', 'record-execution.mjs', 'task-watchdog.sh'],
|
|
62
66
|
Bash: ['compress-output.sh', 'record-execution.mjs'],
|
|
67
|
+
// Delegation result: releases the per-task execution claim taken by the pre-call guard.
|
|
68
|
+
'MultiEdit|NotebookEdit|Agent|Task': ['record-execution.mjs'],
|
|
63
69
|
},
|
|
64
70
|
before_agent_start: ['sensitive-data-guard.mjs', 'skill-router.sh', 'vision-router.sh', 'context-window-guard.sh'],
|
|
65
71
|
'session.compacting': ['reinject-context.sh'],
|
|
@@ -87,10 +93,26 @@ const TOOL_NAME_MAP = {
|
|
|
87
93
|
eval: 'Bash',
|
|
88
94
|
bash: 'Bash',
|
|
89
95
|
shell: 'Bash',
|
|
96
|
+
multi_edit: 'MultiEdit',
|
|
97
|
+
multiedit: 'MultiEdit',
|
|
98
|
+
notebook_edit: 'NotebookEdit',
|
|
99
|
+
notebookedit: 'NotebookEdit',
|
|
100
|
+
// omp delegation surface (observed in real omp sessions): `task` = subagent fan-out with
|
|
101
|
+
// input {context, tasks:[{agent,name,task}]}; `vibe_spawn` starts a worker; `hub` with
|
|
102
|
+
// op:'start' launches an external process (see mapToolName's input-aware branch).
|
|
103
|
+
task: 'Task',
|
|
104
|
+
vibe_spawn: 'Task',
|
|
105
|
+
agent: 'Task',
|
|
90
106
|
};
|
|
91
107
|
|
|
92
|
-
export function mapToolName(ompToolName) {
|
|
108
|
+
export function mapToolName(ompToolName, input) {
|
|
93
109
|
const normalized = String(ompToolName ?? '').trim().toLowerCase().replaceAll('-', '_');
|
|
110
|
+
// `hub` multiplexes wait/send/list/... (harmless) and start/restart (spawns a process that is
|
|
111
|
+
// outside every other guard): only the spawning ops are delegation.
|
|
112
|
+
if (normalized === 'hub') {
|
|
113
|
+
const op = String(input?.op ?? '').toLowerCase();
|
|
114
|
+
return op === 'start' || op === 'restart' ? 'Task' : null;
|
|
115
|
+
}
|
|
94
116
|
return TOOL_NAME_MAP[normalized] ?? null;
|
|
95
117
|
}
|
|
96
118
|
|
|
@@ -104,6 +126,9 @@ function matcherGroupFor(claudeToolName) {
|
|
|
104
126
|
if (claudeToolName === 'Bash') {
|
|
105
127
|
return 'Bash';
|
|
106
128
|
}
|
|
129
|
+
if (claudeToolName === 'MultiEdit' || claudeToolName === 'NotebookEdit' || claudeToolName === 'Agent' || claudeToolName === 'Task') {
|
|
130
|
+
return 'MultiEdit|NotebookEdit|Agent|Task';
|
|
131
|
+
}
|
|
107
132
|
return null;
|
|
108
133
|
}
|
|
109
134
|
|
|
@@ -828,7 +853,7 @@ export async function runToolCall(pi, event, { projectRoot, context: extensionCo
|
|
|
828
853
|
};
|
|
829
854
|
}
|
|
830
855
|
}
|
|
831
|
-
const mappedToolName = mapToolName(rawToolName);
|
|
856
|
+
const mappedToolName = mapToolName(rawToolName, event.input);
|
|
832
857
|
// An unmapped tool that LOOKS like a file mutation must not sail past the guards — but
|
|
833
858
|
// hard-blocking it froze the run whenever omp renamed or added a tool, because the model
|
|
834
859
|
// cannot add a host adapter mapping mid-run and the block had no recovery path. Run the
|
|
@@ -857,7 +882,7 @@ export async function runToolCall(pi, event, { projectRoot, context: extensionCo
|
|
|
857
882
|
// so a blocked Bash call cannot create a Stop-hook loop.
|
|
858
883
|
const group = matcherGroupFor(toolName);
|
|
859
884
|
const bashFailOpenOverride = process.env.UKIT_OMP_BASH_FAIL_OPEN === '1';
|
|
860
|
-
const failClosedOnTransportError = group === 'Edit|Write' || (group === 'Bash' && !bashFailOpenOverride);
|
|
885
|
+
const failClosedOnTransportError = group === 'Edit|Write' || group === 'MultiEdit|NotebookEdit|Agent|Task' || (group === 'Bash' && !bashFailOpenOverride);
|
|
861
886
|
const result = await runScriptChain(pi, scriptsForToolCall(toolName), payload, {
|
|
862
887
|
projectRoot,
|
|
863
888
|
failClosedOnTransportError,
|
|
@@ -1141,7 +1166,10 @@ export async function runSessionStop(
|
|
|
1141
1166
|
const ledger = suppliedLedger ?? await readExecutionLedger(projectRoot, payload) ?? {};
|
|
1142
1167
|
let evaluation;
|
|
1143
1168
|
try {
|
|
1144
|
-
|
|
1169
|
+
// Command authority (RC-A): same shared phase signal the Claude Stop path uses, so a
|
|
1170
|
+
// handoff-create/review session is never pushed toward Edit/Write on omp either.
|
|
1171
|
+
const phase = await resolveStopPhase(payload.transcript_path);
|
|
1172
|
+
evaluation = evaluateCompletion({ state, ledger, phase });
|
|
1145
1173
|
} catch (error) {
|
|
1146
1174
|
// BUG-C22-05: fail-closed like the shell gate (continue the turn), but only up
|
|
1147
1175
|
// to the configured consecutive-crash cap — a persistently broken evaluator
|
|
@@ -11,6 +11,15 @@ If the user says "new task", re-route — do not treat the message as the next s
|
|
|
11
11
|
4. Implement the smallest change satisfying the predicate.
|
|
12
12
|
5. Verify against the predicate on the real artifact — not "it compiles".
|
|
13
13
|
6. Widen once: check the impact surface the route named, no broader.
|
|
14
|
+
Reference reuse: when the ask points at an existing surface ("like the Customer
|
|
15
|
+
page", "giống trang X", "same as module Y"), read that surface first and mirror
|
|
16
|
+
its structure — the reference defines the done predicate, not just inspiration.
|
|
17
|
+
Reuse-first: when the ask names an existing function, helper, or pattern
|
|
18
|
+
("using validation from Z", "dùng hàm có sẵn"), reuse it — extend or wrap
|
|
19
|
+
before writing new logic, and name the reuse in the report.
|
|
20
|
+
Clone: when the ask duplicates a feature ("clone the Customer page", "nhân bản
|
|
21
|
+
tính năng X"), copy the source feature's structure, rename and adapt each
|
|
22
|
+
surface, and verify the clone against the same predicate class as the original.
|
|
14
23
|
Reply: what changed, the predicate, the evidence it now holds.
|
|
15
24
|
Ask the human only for: irreversible writes, a genuine preference call no experiment
|
|
16
25
|
settles, or a real dead end. Everything else: do it, report it.
|
|
@@ -15,6 +15,10 @@ If the user says "new task", re-route — do not treat the message as the next s
|
|
|
15
15
|
shape; the pin holds.
|
|
16
16
|
5. Demonstrate rollback on a safe surface — run it or dry-run it and capture the
|
|
17
17
|
output; then schedule the legacy path for removal — it does not linger.
|
|
18
|
+
SQL discovery: when the move is a database shape change (column, table, view,
|
|
19
|
+
stored procedure — "sửa cột", ALTER/DROP), pin the current schema and row
|
|
20
|
+
counts before writing DDL, draft the change as a verifiable step, and inspect
|
|
21
|
+
the live schema — never assume it matches the declared migrations.
|
|
18
22
|
Reply: what moved, the verification evidence on the target, the rollback
|
|
19
23
|
demonstration, and the legacy-path removal plan.
|
|
20
24
|
Ask the human only for: irreversible writes, a genuine preference call no experiment
|