@ngockhoale/ukit 3.4.26 → 3.4.28
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 +30 -0
- package/manifests/documentation.yaml +61 -0
- package/manifests/platform.full.yaml +24 -0
- package/package.json +7 -1
- package/scripts/audit/subagent-cost/metrics.mjs +14 -2
- package/scripts/audit/subagent-cost/reader.mjs +15 -3
- package/scripts/audit/subagent-cost/usage-fields.mjs +82 -0
- package/scripts/dev/worktree-preflight.mjs +147 -0
- package/src/cli/commands/update.js +59 -2
- package/src/core/agentRuntime/context.js +78 -0
- package/src/core/diffPlan.js +100 -102
- package/src/core/docContracts.js +3 -0
- package/src/core/observability/emit/sessionBoot.js +14 -0
- package/src/core/runtimeConfigMerge.js +125 -0
- package/src/core/updateSafety.js +174 -0
- package/src/index/contextPack.js +285 -0
- package/src/index/sensitivePath.js +21 -0
- package/src/index/taskRouting.js +3 -0
- package/template_project/.claude/commands/ukit/ci-check.md +53 -0
- package/template_project/.claude/hooks/auto-allow-bash.sh +20 -2
- package/template_project/.claude/hooks/handoff-model-guard.sh +9 -2
- package/template_project/.claude/hooks/handoff-resume.sh +25 -1
- package/template_project/.claude/hooks/record-execution.mjs +9 -0
- package/template_project/.claude/hooks/skill-router.sh +3 -0
- package/template_project/.claude/ukit/index/ci-check.mjs +665 -0
- package/template_project/.claude/ukit/index/post-edit-verify.mjs +4 -4
- package/template_project/.claude/ukit/index/pre-edit-backup.mjs +3 -3
- package/template_project/.claude/ukit/index/route-task.mjs +3 -0
- package/template_project/.claude/ukit/runtime/execution-ledger.mjs +154 -12
- package/template_project/.claude/ukit/runtime/handoff-intent.mjs +61 -0
- package/template_project/.claude/ukit/runtime/hook-chain-runner.mjs +70 -4
- package/template_project/.claude/ukit/runtime/loop-state.mjs +131 -0
- package/template_project/.claude/ukit/runtime/observability-emit.mjs +14 -0
- package/template_project/.claude/ukit/runtime/read-advisory.mjs +92 -0
- package/template_project/.claude/ukit/runtime/safe-patch-core.mjs +71 -0
- package/template_project/.claude/ukit/runtime/stop-coordinator.mjs +53 -6
- package/template_project/.claude/ukit/runtime/usage-capture.mjs +338 -0
- package/template_project/.omp/hooks/pre/ukit-bridge.js +48 -4
|
@@ -751,6 +751,12 @@ function normalizeToolInput(toolName, input) {
|
|
|
751
751
|
const paths = Array.isArray(normalized.paths) ? normalized.paths.filter(Boolean) : [];
|
|
752
752
|
normalized.file_path = normalized.path || paths[0] || undefined;
|
|
753
753
|
}
|
|
754
|
+
// omp's eval tool carries `{language, code}` (no `command`), but block-dangerous and the
|
|
755
|
+
// secret guard only read tool_input.command. Surface the code as the command so the same
|
|
756
|
+
// Bash chain scans it; otherwise an eval payload would reach the gate as an empty command.
|
|
757
|
+
if (toolName === 'Bash' && typeof normalized.command !== 'string' && typeof normalized.code === 'string') {
|
|
758
|
+
normalized.command = normalized.code;
|
|
759
|
+
}
|
|
754
760
|
return normalized;
|
|
755
761
|
}
|
|
756
762
|
|
|
@@ -789,8 +795,39 @@ function sendContext(pi, context, deliverAs, { display = false } = {}) {
|
|
|
789
795
|
pi.sendMessage(hookContextMessage(content, { display }), { deliverAs });
|
|
790
796
|
}
|
|
791
797
|
|
|
792
|
-
|
|
798
|
+
// eval threat model (F2): the Bash chain is a text matcher over a command string. It cannot
|
|
799
|
+
// prove that arbitrary Python/JS is safe (shutil.rmtree, fs.rmSync, pathlib loops, dynamic
|
|
800
|
+
// strings all pass it — verified in a sentinel sandbox). So eval is DENIED by the bridge unless
|
|
801
|
+
// the user opted in with orchestration.allowUnsafeEval=true in .ukit/storage/config.json,
|
|
802
|
+
// independent of .omp/config.yml tools.approval.eval. When opted in, the Bash chain still runs
|
|
803
|
+
// as best-effort defence in depth; it is NOT a safety guarantee for eval code.
|
|
804
|
+
async function readAllowUnsafeEval(projectRoot) {
|
|
805
|
+
try {
|
|
806
|
+
const parsed = JSON.parse(
|
|
807
|
+
await fs.promises.readFile(path.join(projectRoot, '.ukit', 'storage', 'config.json'), 'utf8'),
|
|
808
|
+
);
|
|
809
|
+
return parsed?.orchestration?.allowUnsafeEval === true;
|
|
810
|
+
} catch {
|
|
811
|
+
return false; // missing/corrupt config → fail closed
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
export async function runToolCall(pi, event, { projectRoot, context: extensionContext = {}, allowUnsafeEval } = {}) {
|
|
793
816
|
const rawToolName = event.toolName ?? event.tool;
|
|
817
|
+
if (String(rawToolName ?? '').trim().toLowerCase() === 'eval') {
|
|
818
|
+
const allowed = allowUnsafeEval ?? await readAllowUnsafeEval(projectRoot);
|
|
819
|
+
if (!allowed) {
|
|
820
|
+
return {
|
|
821
|
+
block: true,
|
|
822
|
+
toolName: 'Bash',
|
|
823
|
+
invoked: [],
|
|
824
|
+
context: [],
|
|
825
|
+
reason: 'UKit denies the omp eval tool: arbitrary Python/JS cannot be verified by the shell guard. '
|
|
826
|
+
+ 'Use the bash tool for commands (guarded), or opt in explicitly with orchestration.allowUnsafeEval=true '
|
|
827
|
+
+ 'in .ukit/storage/config.json (unsafe; the guard is best-effort for eval).',
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
}
|
|
794
831
|
const mappedToolName = mapToolName(rawToolName);
|
|
795
832
|
// An unmapped tool that LOOKS like a file mutation must not sail past the guards — but
|
|
796
833
|
// hard-blocking it froze the run whenever omp renamed or added a tool, because the model
|
|
@@ -811,9 +848,16 @@ export async function runToolCall(pi, event, { projectRoot, context: extensionCo
|
|
|
811
848
|
toolUseId: event.toolCallId,
|
|
812
849
|
...metadata,
|
|
813
850
|
});
|
|
814
|
-
//
|
|
815
|
-
//
|
|
816
|
-
|
|
851
|
+
// F4: Edit|Write and Bash (which also carries omp's `eval`) are security-critical and fail
|
|
852
|
+
// CLOSED on a bridge/runner transport failure — an unverifiable shell/eval call is not
|
|
853
|
+
// allowed to proceed. Read|Grep|Glob stay fail-open (documented limit: the secret-read guard
|
|
854
|
+
// is advisory on a runner outage) so diagnosis tools are not bricked. Recovery for a Bash
|
|
855
|
+
// outage is a user action, not a model one: the user exports UKIT_OMP_BASH_FAIL_OPEN=1 (or
|
|
856
|
+
// fixes Node/PATH) and restarts omp. This only affects PreToolUse; the Stop gate is separate,
|
|
857
|
+
// so a blocked Bash call cannot create a Stop-hook loop.
|
|
858
|
+
const group = matcherGroupFor(toolName);
|
|
859
|
+
const bashFailOpenOverride = process.env.UKIT_OMP_BASH_FAIL_OPEN === '1';
|
|
860
|
+
const failClosedOnTransportError = group === 'Edit|Write' || (group === 'Bash' && !bashFailOpenOverride);
|
|
817
861
|
const result = await runScriptChain(pi, scriptsForToolCall(toolName), payload, {
|
|
818
862
|
projectRoot,
|
|
819
863
|
failClosedOnTransportError,
|