@sema-agent/core 5.0.1 → 5.2.0
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 +67 -0
- package/dist/agents/roster-store.d.ts +9 -2
- package/dist/agents/roster-store.js +32 -6
- package/dist/agents/subagent.js +8 -3
- package/dist/bin/sema-tb.d.ts +1 -2
- package/dist/bin/sema-tb.js +14 -27
- package/dist/brain/anthropic.js +2 -3
- package/dist/brain/degrading.d.ts +2 -8
- package/dist/brain/degrading.js +3 -3
- package/dist/brain/openai.js +3 -5
- package/dist/brain/terminal-cause.d.ts +1 -1
- package/dist/brain/terminal-cause.js +2 -8
- package/dist/core/hooks.js +12 -7
- package/dist/core/lsp.js +2 -3
- package/dist/core/mcp.d.ts +1 -1
- package/dist/core/mcp.js +2 -1
- package/dist/core/memory-engine/dual-root.js +2 -1
- package/dist/core/memory-engine/engine.d.ts +4 -0
- package/dist/core/memory-engine/engine.js +25 -6
- package/dist/core/memory-engine/file-backend.d.ts +7 -5
- package/dist/core/memory-engine/file-backend.js +3 -1
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +7 -0
- package/dist/core/memory-engine/layout.js +98 -5
- package/dist/core/memory.d.ts +0 -1
- package/dist/core/memory.js +7 -1
- package/dist/core/permission-rules.js +8 -7
- package/dist/core/protocol-table.d.ts +17 -0
- package/dist/core/protocol-table.js +37 -0
- package/dist/core/runner/active-skill-scope.js +7 -7
- package/dist/core/runner/prepare-memory.js +7 -4
- package/dist/core/runner/prepare-task.js +43 -26
- package/dist/core/runner/runtask.js +18 -6
- package/dist/core/runner/session-rule-policy.js +1 -1
- package/dist/core/runner/synthetic-tools.js +2 -2
- package/dist/core/runner/tool-disclosure.d.ts +0 -1
- package/dist/core/runner/tool-disclosure.js +6 -3
- package/dist/core/runner/turn-attachments.js +2 -1
- package/dist/core/sensitive-path-policy.js +2 -2
- package/dist/core/tool-policy.d.ts +1 -3
- package/dist/core/tool-policy.js +40 -16
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/orchestration/run-spec.js +1 -1
- package/dist/orchestration/run-workflow-tool.js +7 -3
- package/dist/orchestration/workflow-script-store.d.ts +1 -1
- package/dist/orchestration/workflow-script-store.js +1 -1
- package/dist/prompt-assembly/assemble.js +0 -2
- package/dist/prompt-assembly/tool-catalog.d.ts +2 -1
- package/dist/prompts/default.d.ts +0 -2
- package/dist/prompts/default.js +1 -5
- package/dist/stores/cc/mailbox-store.d.ts +4 -0
- package/dist/stores/cc/mailbox-store.js +67 -9
- package/dist/stores/file/file-snapshot-store.d.ts +9 -1
- package/dist/stores/file/file-snapshot-store.js +28 -5
- package/dist/stores/file/fs-atomic.d.ts +4 -1
- package/dist/stores/file/fs-atomic.js +2 -1
- package/dist/stores/file/index.d.ts +10 -3
- package/dist/stores/file/index.js +4 -3
- package/dist/stores/file/mailbox-store.d.ts +5 -0
- package/dist/stores/file/mailbox-store.js +15 -3
- package/dist/stores/file/session-policy-store.d.ts +13 -1
- package/dist/stores/file/session-policy-store.js +39 -6
- package/dist/stores/file/session-store.d.ts +9 -1
- package/dist/stores/file/session-store.js +19 -4
- package/dist/tools/fs/fs-search-tools.js +10 -2
- package/dist/tools/fs/fs-shared.d.ts +1 -2
- package/dist/tools/fs/fs-shared.js +1 -2
- package/dist/tools/todo.js +14 -7
- package/package.json +1 -1
|
@@ -16,7 +16,7 @@ import { createSubagentWorktreeHelper, forkGovernanceDenial } from "../../agents
|
|
|
16
16
|
import { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME } from "../../agents/agent-transcript-tool.js";
|
|
17
17
|
import { createSendMessageTool, SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
|
|
18
18
|
import { SubagentRetainLedger } from "../../agents/retain-ledger.js";
|
|
19
|
-
import { combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, resolveAsk, toolPolicyNameSets } from "../tool-policy.js";
|
|
19
|
+
import { combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, refuseOutOfContractDecision, resolveAsk, toolPolicyNameSets } from "../tool-policy.js";
|
|
20
20
|
import { ActiveSkillScope, createActiveSkillScopePolicy } from "./active-skill-scope.js";
|
|
21
21
|
import { computeCallCap, createCallCapRef, softExecDeadlineMs, toolCutDeadlineMs, WALLTIME_STALL_CONNECT_MS, WALLTIME_STALL_FIRST_TOKEN_MS, WALLTIME_STALL_IDLE_MS } from "./call-cap.js";
|
|
22
22
|
import { createCutKillRegistry } from "./cut-kill.js";
|
|
@@ -30,6 +30,7 @@ import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-det
|
|
|
30
30
|
import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
|
|
31
31
|
import { defineTool, isDefineToolProduct } from "../tools.js";
|
|
32
32
|
import { RETIRED_TOOL_NAMES } from "../tool-name-aliases.js";
|
|
33
|
+
import { protocolOf } from "../protocol-table.js";
|
|
33
34
|
import { pathToUri } from "../lsp-protocol.js";
|
|
34
35
|
import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, createOffloadPersist, firstPartyOffloadPolicy, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, isVolatileOffloadStore, OFFLOAD_TOOL_NAME, createReadToolResultTool, withToolResultOffload, } from "../tool-result-store.js";
|
|
35
36
|
import { OUTPUT_TOOL_NAME, REPORT_FINDINGS_TOOL_NAME, SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createOutputTool, createReportBlockedTool, createReportFindingsTool, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
|
|
@@ -1835,7 +1836,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1835
1836
|
...(assembled.sections
|
|
1836
1837
|
? { sections: assembled.sections.map((s) => ({ id: s.id, slot: s.slot, carrier: s.carrier, cadence: s.cadence, cacheClass: s.cacheClass, chars: s.text.length, hash: saltedHash(s.text), ...(s.declaredContentHash !== undefined ? { contentHash: s.declaredContentHash } : {}) })) }
|
|
1837
1838
|
: {}),
|
|
1838
|
-
tools: projectToolManifest(tools, (t) => (t.name
|
|
1839
|
+
tools: projectToolManifest(tools, (t) => protocolOf(t.name)?.id ?? "caller"),
|
|
1839
1840
|
};
|
|
1840
1841
|
const epochDeclaredSections = (assembled.sections ?? [])
|
|
1841
1842
|
.filter((s) => s.origin === "provider")
|
|
@@ -2209,7 +2210,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2209
2210
|
err.code = "config.legacy_tool_name";
|
|
2210
2211
|
throw err;
|
|
2211
2212
|
}
|
|
2212
|
-
if (n.includes("__") &&
|
|
2213
|
+
if (n.includes("__") && protocolOf(n) === undefined) {
|
|
2213
2214
|
const err = new Error(`tool policy ${kind}-list entry "${n}" is a pre-prefix MCP tool name and matches nothing in this run's roster — MCP tools are named "mcp__<server>__<tool>" and legacy-name normalization was removed (RB-476-A), so this entry would silently guard nothing. Prefix the entry with "mcp__".`);
|
|
2214
2215
|
err.code = "config.legacy_tool_name";
|
|
2215
2216
|
throw err;
|
|
@@ -2339,7 +2340,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2339
2340
|
if (round >= 3) {
|
|
2340
2341
|
return {
|
|
2341
2342
|
action: "deny",
|
|
2342
|
-
|
|
2343
|
+
message: `the approval-edit chain for "${creq.toolName}" exceeded the re-approval cap (inherited parent policy) — denied fail-closed; re-submit the edited action directly`,
|
|
2343
2344
|
};
|
|
2344
2345
|
}
|
|
2345
2346
|
let re;
|
|
@@ -2349,7 +2350,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2349
2350
|
catch (err) {
|
|
2350
2351
|
return {
|
|
2351
2352
|
action: "deny",
|
|
2352
|
-
|
|
2353
|
+
message: `inherited parent policy re-check of the approved edit errored for "${creq.toolName}": ${err instanceof Error ? err.message : String(err)}`,
|
|
2353
2354
|
};
|
|
2354
2355
|
}
|
|
2355
2356
|
if (re.action === "deny")
|
|
@@ -2363,7 +2364,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2363
2364
|
toolName: creq.toolName,
|
|
2364
2365
|
toolCallId: creq.toolCallId,
|
|
2365
2366
|
args: editArgs,
|
|
2366
|
-
message: re.message ??
|
|
2367
|
+
message: re.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
2367
2368
|
...askSourceIdentity(),
|
|
2368
2369
|
...(re.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
2369
2370
|
}, onAskOf, csignal ?? abortController.signal);
|
|
@@ -2381,7 +2382,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2381
2382
|
if (first === undefined) {
|
|
2382
2383
|
return {
|
|
2383
2384
|
action: "deny",
|
|
2384
|
-
|
|
2385
|
+
message: `inherited parent policy could not be arbitrated for "${creq.toolName}" ` +
|
|
2385
2386
|
`(shared-instance first decision unavailable); denied fail-closed`,
|
|
2386
2387
|
};
|
|
2387
2388
|
}
|
|
@@ -2399,7 +2400,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2399
2400
|
}
|
|
2400
2401
|
return {
|
|
2401
2402
|
action: "deny",
|
|
2402
|
-
|
|
2403
|
+
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
2403
2404
|
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
2404
2405
|
};
|
|
2405
2406
|
}
|
|
@@ -2409,7 +2410,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2409
2410
|
toolName: creq.toolName,
|
|
2410
2411
|
toolCallId: creq.toolCallId,
|
|
2411
2412
|
args: presentedArgs,
|
|
2412
|
-
message: first.message ??
|
|
2413
|
+
message: first.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
2413
2414
|
...askSourceIdentity(),
|
|
2414
2415
|
...(first.action === "ask" && first.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
2415
2416
|
}, pc.onAsk, csignal ?? abortController.signal);
|
|
@@ -2419,7 +2420,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2419
2420
|
return first;
|
|
2420
2421
|
return {
|
|
2421
2422
|
action: "deny",
|
|
2422
|
-
|
|
2423
|
+
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
2423
2424
|
};
|
|
2424
2425
|
}
|
|
2425
2426
|
if (resolved.action !== "allow")
|
|
@@ -2440,7 +2441,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2440
2441
|
catch (err) {
|
|
2441
2442
|
return {
|
|
2442
2443
|
action: "deny",
|
|
2443
|
-
|
|
2444
|
+
message: `inherited parent policy errored for "${creq.toolName}": ${err instanceof Error ? err.message : String(err)}`,
|
|
2444
2445
|
};
|
|
2445
2446
|
}
|
|
2446
2447
|
if (decision.action !== "ask")
|
|
@@ -2455,7 +2456,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2455
2456
|
}
|
|
2456
2457
|
return {
|
|
2457
2458
|
action: "deny",
|
|
2458
|
-
|
|
2459
|
+
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
2459
2460
|
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
2460
2461
|
};
|
|
2461
2462
|
}
|
|
@@ -2465,7 +2466,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2465
2466
|
toolName: creq.toolName,
|
|
2466
2467
|
toolCallId: creq.toolCallId,
|
|
2467
2468
|
args: presentedArgs,
|
|
2468
|
-
message: decision.message ??
|
|
2469
|
+
message: decision.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
2469
2470
|
...askSourceIdentity(),
|
|
2470
2471
|
...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
2471
2472
|
}, pc.onAsk, csignal ?? abortController.signal);
|
|
@@ -2475,7 +2476,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2475
2476
|
return decision;
|
|
2476
2477
|
return {
|
|
2477
2478
|
action: "deny",
|
|
2478
|
-
|
|
2479
|
+
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
2479
2480
|
};
|
|
2480
2481
|
}
|
|
2481
2482
|
if (resolved.action !== "allow")
|
|
@@ -2630,7 +2631,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2630
2631
|
const adjudicate = effectivePolicy
|
|
2631
2632
|
? (req) => raceAbort(Promise.resolve(effectivePolicy.check({ ...req, budget: budgetSnapshot }, abortController.signal)), abortController.signal, () => ({
|
|
2632
2633
|
action: "deny",
|
|
2633
|
-
|
|
2634
|
+
message: "policy check aborted (task timed out or cancelled)",
|
|
2634
2635
|
}))
|
|
2635
2636
|
: undefined;
|
|
2636
2637
|
const sanitizePreview = (node, depth = 0) => {
|
|
@@ -2672,7 +2673,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2672
2673
|
if (inheritedUnavailableAsks.delete(req.toolCallId)) {
|
|
2673
2674
|
return {
|
|
2674
2675
|
action: "deny",
|
|
2675
|
-
|
|
2676
|
+
message: `approval for "${req.toolName}" requires an ancestor task's approval that cannot be resolved here ` +
|
|
2676
2677
|
`(no live approver reachable, or a durable-park mandate applies), and no durable approval park is ` +
|
|
2677
2678
|
`available — denied fail-closed (the inherited constraint stands).`,
|
|
2678
2679
|
decisionReason: "mode",
|
|
@@ -2705,7 +2706,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2705
2706
|
const preview = approvalPreviewOf(req.toolName, req.args);
|
|
2706
2707
|
return preview !== undefined ? { preview } : {};
|
|
2707
2708
|
})(),
|
|
2708
|
-
message: decision.message ??
|
|
2709
|
+
message: decision.message ?? `approval required for "${req.toolName}"`,
|
|
2709
2710
|
...askSourceIdentity(),
|
|
2710
2711
|
...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
2711
2712
|
}, onAsk, abortController.signal);
|
|
@@ -2749,17 +2750,33 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2749
2750
|
const checkpointStore = spec.checkpointStore ?? deps.checkpointStore;
|
|
2750
2751
|
const durableApproval = spec.durableApproval ??
|
|
2751
2752
|
(runtimeCaps?.forceDurableGate ? { scope: spec.principal || DEFAULT_IRREVERSIBLE_SCOPE } : undefined);
|
|
2752
|
-
const
|
|
2753
|
+
const inFlightSpendMicroUsd = () => {
|
|
2754
|
+
const own = liveSpendRef.get?.().costMicroUsd ?? 0;
|
|
2755
|
+
const seededNested = resume?.seed.nestedStats.costMicroUsd;
|
|
2756
|
+
const nestedDelta = nestedStats.costMicroUsd - (typeof seededNested === "number" && Number.isFinite(seededNested) ? seededNested : 0);
|
|
2757
|
+
return (Number.isFinite(own) ? own : 0) + Math.max(0, Number.isFinite(nestedDelta) ? nestedDelta : 0);
|
|
2758
|
+
};
|
|
2759
|
+
const repairBundleForCheckpoint = (parkedSpendMicroUsd) => {
|
|
2760
|
+
const carried = internals?.repairBundle !== undefined
|
|
2761
|
+
? structuredClone(internals.repairBundle)
|
|
2762
|
+
: resume?.seed.repairBundle !== undefined
|
|
2763
|
+
? structuredClone(resume.seed.repairBundle)
|
|
2764
|
+
: undefined;
|
|
2765
|
+
if (carried === undefined)
|
|
2766
|
+
return undefined;
|
|
2767
|
+
if (parkedSpendMicroUsd === undefined || !Number.isFinite(parkedSpendMicroUsd) || parkedSpendMicroUsd <= 0)
|
|
2768
|
+
return carried;
|
|
2769
|
+
const prior = typeof carried.spentMicroUsd === "number" && Number.isFinite(carried.spentMicroUsd) ? Math.max(0, carried.spentMicroUsd) : 0;
|
|
2770
|
+
carried.spentMicroUsd = prior + parkedSpendMicroUsd;
|
|
2771
|
+
return carried;
|
|
2772
|
+
};
|
|
2773
|
+
const serializeCheckpointState = (workspaceHandle, parkedSpendMicroUsd) => ({
|
|
2753
2774
|
activeTools: [...activeTools],
|
|
2754
2775
|
outputRef: { value: outputRef.value, set: outputRef.set },
|
|
2755
2776
|
nestedStats: { ...nestedStats },
|
|
2756
2777
|
consolidationNotes: undefined,
|
|
2757
2778
|
readFileState: readFileStateForCheckpoint ? [...readFileStateForCheckpoint.entries()] : undefined,
|
|
2758
|
-
repairBundle:
|
|
2759
|
-
? structuredClone(internals.repairBundle)
|
|
2760
|
-
: resume?.seed.repairBundle !== undefined
|
|
2761
|
-
? structuredClone(resume.seed.repairBundle)
|
|
2762
|
-
: undefined,
|
|
2779
|
+
repairBundle: repairBundleForCheckpoint(parkedSpendMicroUsd),
|
|
2763
2780
|
workspaceHandle,
|
|
2764
2781
|
handsCwd: handsCwdRef?.current,
|
|
2765
2782
|
activeWorktree: worktreeSessionRef?.current ? { ...worktreeSessionRef.current } : undefined,
|
|
@@ -2977,7 +2994,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2977
2994
|
leafId,
|
|
2978
2995
|
gate,
|
|
2979
2996
|
pendingAction: { kind: "plan_review" },
|
|
2980
|
-
state: serializeCheckpointState(remoteHandle),
|
|
2997
|
+
state: serializeCheckpointState(remoteHandle, inFlightSpendMicroUsd()),
|
|
2981
2998
|
status: "pending",
|
|
2982
2999
|
createdAt: mintedAt,
|
|
2983
3000
|
suspendedAt: now(),
|
|
@@ -3091,7 +3108,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3091
3108
|
};
|
|
3092
3109
|
const scope = durableApproval?.scope || checkpointScopeOf({ principal: spec.principal });
|
|
3093
3110
|
const ttlMs = sanitizedTtlMs(durableApproval?.ttlMs);
|
|
3094
|
-
const checkpointState = serializeCheckpointState(remoteHandle);
|
|
3111
|
+
const checkpointState = serializeCheckpointState(remoteHandle, inFlightSpendMicroUsd());
|
|
3095
3112
|
const approvalLedger = debitLedger(priorLedger, liveSpendRef.get?.() ?? { costMicroUsd: 0, tokens: 0, turns: 0, walltimeMs: 0 }, resourceTotal, { countSlice: false });
|
|
3096
3113
|
const mintedAt = Date.now();
|
|
3097
3114
|
cp = {
|
|
@@ -3395,7 +3412,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3395
3412
|
? undefined
|
|
3396
3413
|
: async (path) => {
|
|
3397
3414
|
try {
|
|
3398
|
-
const d = await denyNarrowingPolicy.check({ toolName: "Read", args: { file_path: path }, toolCallId: "changed-files-visibility-probe" }, abortController.signal);
|
|
3415
|
+
const d = refuseOutOfContractDecision(await denyNarrowingPolicy.check({ toolName: "Read", args: { file_path: path }, toolCallId: "changed-files-visibility-probe" }, abortController.signal));
|
|
3399
3416
|
return d.action === "deny";
|
|
3400
3417
|
}
|
|
3401
3418
|
catch {
|
|
@@ -36,7 +36,7 @@ import { delimitUntrusted, inlineUntrusted, sanitizeUntrustedText } from "../unt
|
|
|
36
36
|
import { reconcileInterruptedSession } from "../session-reconcile.js";
|
|
37
37
|
import { RunnerSharedToolResultStore } from "../tool-result-store.js";
|
|
38
38
|
import { formatDiagnosticsBlock } from "../lsp-diagnostics.js";
|
|
39
|
-
import { toolPolicyNameSets } from "../tool-policy.js";
|
|
39
|
+
import { refuseOutOfContractDecision, toolPolicyNameSets } from "../tool-policy.js";
|
|
40
40
|
import { defaultTaskRegistry } from "../task-registry.js";
|
|
41
41
|
import { discloseDroppedPending, PendingSessionNotifications, renderTaskNotificationXml, SystemInjectionQueue, taskNotificationDedupKey } from "../task-notification.js";
|
|
42
42
|
import { ToolDetachHub } from "../tool-detach.js";
|
|
@@ -1674,7 +1674,19 @@ export class Runner {
|
|
|
1674
1674
|
}
|
|
1675
1675
|
rs.telemetry.taskStart = Date.now();
|
|
1676
1676
|
rs.telemetry.taskStartMonotonic = performance.now();
|
|
1677
|
-
|
|
1677
|
+
const discloseNoteTaskRunFailure = (err) => {
|
|
1678
|
+
try {
|
|
1679
|
+
this.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId: prepared.sessionId });
|
|
1680
|
+
}
|
|
1681
|
+
catch {
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
try {
|
|
1685
|
+
void Promise.resolve(this.sessions.noteTaskRun?.(prepared.sessionId, rs.telemetry.taskId)).catch(discloseNoteTaskRunFailure);
|
|
1686
|
+
}
|
|
1687
|
+
catch (err) {
|
|
1688
|
+
discloseNoteTaskRunFailure(err);
|
|
1689
|
+
}
|
|
1678
1690
|
rs.degrade.recordDegraded = (info, toModel) => {
|
|
1679
1691
|
if (rs.degrade.degraded !== undefined)
|
|
1680
1692
|
return;
|
|
@@ -3341,19 +3353,19 @@ export class Runner {
|
|
|
3341
3353
|
return;
|
|
3342
3354
|
}
|
|
3343
3355
|
if (outcome.decision === "allow" && outcome.updatedInput !== undefined && prepared.basePolicyForResumeEdit) {
|
|
3344
|
-
const rechecked = await prepared.basePolicyForResumeEdit.check({ toolName: pendingAction.toolName, args: resolvedArgs, toolCallId: pendingAction.toolCallId }, prepared.abortController.signal);
|
|
3356
|
+
const rechecked = refuseOutOfContractDecision(await prepared.basePolicyForResumeEdit.check({ toolName: pendingAction.toolName, args: resolvedArgs, toolCallId: pendingAction.toolCallId }, prepared.abortController.signal));
|
|
3345
3357
|
if (rechecked.action === "deny") {
|
|
3346
3358
|
emitEnd(true);
|
|
3347
|
-
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, formatHookFeedback(`The approver EDITED this call's input; the edited call is denied by the deployment's tool policy and was not executed${rechecked.
|
|
3359
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, formatHookFeedback(`The approver EDITED this call's input; the edited call is denied by the deployment's tool policy and was not executed${rechecked.message ? `: ${rechecked.message}` : ""}.`), true));
|
|
3348
3360
|
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
3349
3361
|
return;
|
|
3350
3362
|
}
|
|
3351
3363
|
}
|
|
3352
3364
|
if (prepared.denyNarrowingPolicy) {
|
|
3353
|
-
const narrowed = await prepared.denyNarrowingPolicy.check({ toolName: pendingAction.toolName, args: resolvedArgs, toolCallId: pendingAction.toolCallId }, prepared.abortController.signal);
|
|
3365
|
+
const narrowed = refuseOutOfContractDecision(await prepared.denyNarrowingPolicy.check({ toolName: pendingAction.toolName, args: resolvedArgs, toolCallId: pendingAction.toolCallId }, prepared.abortController.signal));
|
|
3354
3366
|
if (narrowed.action === "deny") {
|
|
3355
3367
|
emitEnd(true);
|
|
3356
|
-
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, formatHookFeedback(`The approved tool call "${pendingAction.toolName}" is now denied by a session rule and was not executed${narrowed.
|
|
3368
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, formatHookFeedback(`The approved tool call "${pendingAction.toolName}" is now denied by a session rule and was not executed${narrowed.message ? `: ${narrowed.message}` : ""}.`), true));
|
|
3357
3369
|
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
3358
3370
|
return;
|
|
3359
3371
|
}
|
|
@@ -18,7 +18,7 @@ export function isWithin(root, p) {
|
|
|
18
18
|
const base = r.endsWith("/") ? r : r + "/";
|
|
19
19
|
return c.startsWith(base);
|
|
20
20
|
}
|
|
21
|
-
const deny = (
|
|
21
|
+
const deny = (message) => ({ action: "deny", message, decisionReason: "rule" });
|
|
22
22
|
export function createSessionRulePolicy(rules, opts) {
|
|
23
23
|
const { env, rootPath, toolEffects } = opts;
|
|
24
24
|
const toolDeny = new Set(rules.toolDeny ?? []);
|
|
@@ -187,13 +187,13 @@ export function createSkillTool(skills, scope) {
|
|
|
187
187
|
`Do not invoke a skill that is already running. ` +
|
|
188
188
|
`If a \`<command-name>\` block is already present this turn, the skill is loaded — follow it directly rather than calling again.`,
|
|
189
189
|
parameters: Type.Object({
|
|
190
|
-
skill: Type.
|
|
190
|
+
skill: Type.String({ description: 'The skill name. E.g., "commit", "review-pr", or "pdf"' }),
|
|
191
191
|
args: Type.Optional(Type.String({ description: "Optional arguments for the skill" })),
|
|
192
192
|
}),
|
|
193
193
|
effect: "read",
|
|
194
194
|
execute: (rawArgs) => {
|
|
195
195
|
const a = (rawArgs ?? {});
|
|
196
|
-
const name = String(a.skill ??
|
|
196
|
+
const name = String(a.skill ?? "");
|
|
197
197
|
const skill = byName.get(name);
|
|
198
198
|
if (!skill) {
|
|
199
199
|
throw new Error(`Unknown skill "${name}". Available skills: ${names}.`);
|
|
@@ -39,7 +39,6 @@ export declare function scoreToolMatch(query: string, info: DeferredToolInfo): n
|
|
|
39
39
|
export interface ToolSearchArgs {
|
|
40
40
|
query?: string;
|
|
41
41
|
max_results?: number;
|
|
42
|
-
select?: string[];
|
|
43
42
|
}
|
|
44
43
|
export declare function resolveToolSearchDetailed(args: ToolSearchArgs, registry: ReadonlyMap<string, DeferredToolInfo>): {
|
|
45
44
|
matched: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { Value } from "typebox/value";
|
|
3
|
-
import { defineTool } from "../tools.js";
|
|
3
|
+
import { defineTool, errorResult } from "../tools.js";
|
|
4
4
|
export const TOOL_SEARCH_NAME = "ToolSearch";
|
|
5
5
|
const DEFER_AUTO_FRACTION = 0.1;
|
|
6
6
|
const CHARS_PER_TOKEN = 4;
|
|
@@ -130,8 +130,6 @@ export function resolveToolSearchDetailed(args, registry) {
|
|
|
130
130
|
out.push(name);
|
|
131
131
|
}
|
|
132
132
|
};
|
|
133
|
-
for (const name of args.select ?? [])
|
|
134
|
-
add(name);
|
|
135
133
|
const q = typeof args.query === "string" ? args.query.trim() : "";
|
|
136
134
|
if (q !== "") {
|
|
137
135
|
const selectMatch = /^select:(.+)$/i.exec(q);
|
|
@@ -249,6 +247,11 @@ export function createToolSearchTool(opts) {
|
|
|
249
247
|
}),
|
|
250
248
|
effect: "read",
|
|
251
249
|
execute: async (raw) => {
|
|
250
|
+
const staleSelect = (raw ?? {});
|
|
251
|
+
if (staleSelect.select !== undefined) {
|
|
252
|
+
return errorResult(`Error (${TOOL_SEARCH_NAME}): \`select\` is not a parameter (the array form is retired) — put the ` +
|
|
253
|
+
`selection in \`query\` instead: {"query":"select:ToolA,ToolB"}. Nothing was activated.`);
|
|
254
|
+
}
|
|
252
255
|
const args = (raw ?? {});
|
|
253
256
|
const { matched, missing } = resolveToolSearchDetailed(args, registry);
|
|
254
257
|
const mounted = mountedNames?.() ?? new Set();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PRESENT_PLAN_TOOL_NAME } from "../present-plan-tool.js";
|
|
2
2
|
import { defuseFenceMarkers, delimitUntrusted, sanitizeUntrustedText } from "../untrusted-text.js";
|
|
3
|
+
import { protocolOf } from "../protocol-table.js";
|
|
3
4
|
import { buildSkillsBlock, skillListingLine } from "./synthetic-tools.js";
|
|
4
5
|
import { TOOL_SEARCH_NAME as TOOL_SEARCH_TOOL_NAME } from "./tool-disclosure.js";
|
|
5
6
|
export const TODO_REMINDER_CONFIG = {
|
|
@@ -384,7 +385,7 @@ export const TOOLS_DELTA_LIST_MAX = 30;
|
|
|
384
385
|
function groupByMcpServer(names) {
|
|
385
386
|
const counts = new Map();
|
|
386
387
|
for (const n of names) {
|
|
387
|
-
const key =
|
|
388
|
+
const key = protocolOf(n)?.displayGroupKey(n) ?? n;
|
|
388
389
|
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
389
390
|
}
|
|
390
391
|
return [...counts.entries()]
|
|
@@ -69,7 +69,7 @@ export function createSensitivePathPolicy(opts) {
|
|
|
69
69
|
if (canon.unresolvedSymlink) {
|
|
70
70
|
return {
|
|
71
71
|
action: "deny",
|
|
72
|
-
|
|
72
|
+
message: `write to "${path}" is blocked: it is a symlink whose real target could not be resolved (it could point onto a guarded sensitive path)`,
|
|
73
73
|
decisionReason: "safety",
|
|
74
74
|
};
|
|
75
75
|
}
|
|
@@ -79,7 +79,7 @@ export function createSensitivePathPolicy(opts) {
|
|
|
79
79
|
if (hit) {
|
|
80
80
|
return {
|
|
81
81
|
action: "deny",
|
|
82
|
-
|
|
82
|
+
message: `write to "${path}" is blocked: its real target resolves onto the guarded sensitive path "${hit}"`,
|
|
83
83
|
decisionReason: "safety",
|
|
84
84
|
};
|
|
85
85
|
}
|
|
@@ -13,26 +13,24 @@ export type PermissionResult = {
|
|
|
13
13
|
action: "allow";
|
|
14
14
|
updatedInput?: unknown;
|
|
15
15
|
message?: string;
|
|
16
|
-
reason?: string;
|
|
17
16
|
decisionReason?: DecisionReason;
|
|
18
17
|
} | {
|
|
19
18
|
action: "ask";
|
|
20
19
|
updatedInput?: unknown;
|
|
21
20
|
message?: string;
|
|
22
|
-
reason?: string;
|
|
23
21
|
decisionReason?: DecisionReason;
|
|
24
22
|
requiresRealApproval?: boolean;
|
|
25
23
|
} | {
|
|
26
24
|
action: "deny";
|
|
27
25
|
updatedInput?: unknown;
|
|
28
26
|
message?: string;
|
|
29
|
-
reason?: string;
|
|
30
27
|
decisionReason?: DecisionReason;
|
|
31
28
|
};
|
|
32
29
|
export declare function decisionText(d: PermissionResult): string | undefined;
|
|
33
30
|
export interface ToolPolicy {
|
|
34
31
|
check(req: ToolCallRequest, signal?: AbortSignal): PermissionResult | Promise<PermissionResult>;
|
|
35
32
|
}
|
|
33
|
+
export declare function refuseOutOfContractDecision(d: PermissionResult): PermissionResult;
|
|
36
34
|
export interface ToolPolicyNameSets {
|
|
37
35
|
readonly allow?: readonly string[];
|
|
38
36
|
readonly deny?: readonly string[];
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -3,9 +3,19 @@ import { isAbsolute, join, normalize as normalizePath, sep } from "node:path";
|
|
|
3
3
|
import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
|
|
4
4
|
import { writeTargetPath } from "../tools/fs/safety.js";
|
|
5
5
|
export function decisionText(d) {
|
|
6
|
-
return d.message
|
|
6
|
+
return d.message;
|
|
7
7
|
}
|
|
8
8
|
const ALLOW = { action: "allow" };
|
|
9
|
+
const RETIRED_TEXT_FIELD = "reason";
|
|
10
|
+
const RETIRED_TEXT_FIELD_DENY_MESSAGE = `a permission decision carries the retired "${RETIRED_TEXT_FIELD}" field — rename it to "message" (the one text field ` +
|
|
11
|
+
`a decision carries); denied fail-closed rather than executing a decision whose text this layer cannot read`;
|
|
12
|
+
export function refuseOutOfContractDecision(d) {
|
|
13
|
+
if (typeof d !== "object" || d === null)
|
|
14
|
+
return d;
|
|
15
|
+
if (!Object.prototype.hasOwnProperty.call(d, RETIRED_TEXT_FIELD))
|
|
16
|
+
return d;
|
|
17
|
+
return { action: "deny", message: RETIRED_TEXT_FIELD_DENY_MESSAGE, decisionReason: "rule" };
|
|
18
|
+
}
|
|
9
19
|
function withTimeout(p, ms, onTimeout) {
|
|
10
20
|
if (ms === undefined) {
|
|
11
21
|
return p;
|
|
@@ -39,10 +49,10 @@ export function createAllowDenyPolicy(opts) {
|
|
|
39
49
|
check(req) {
|
|
40
50
|
const toolName = req.toolName;
|
|
41
51
|
if (deny.has(toolName)) {
|
|
42
|
-
return { action: "deny",
|
|
52
|
+
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
43
53
|
}
|
|
44
54
|
if (allow && !allow.has(toolName)) {
|
|
45
|
-
return { action: "deny",
|
|
55
|
+
return { action: "deny", message: `tool "${req.toolName}" is not in the allowlist` };
|
|
46
56
|
}
|
|
47
57
|
return ALLOW;
|
|
48
58
|
},
|
|
@@ -66,11 +76,11 @@ export function createApprovalPolicy(opts) {
|
|
|
66
76
|
async check(req, signal) {
|
|
67
77
|
const toolName = req.toolName;
|
|
68
78
|
if (deny.has(toolName)) {
|
|
69
|
-
return { action: "deny",
|
|
79
|
+
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
70
80
|
}
|
|
71
81
|
if (need.has(toolName)) {
|
|
72
82
|
if (signal?.aborted) {
|
|
73
|
-
return { action: "deny",
|
|
83
|
+
return { action: "deny", message: `approval aborted for "${req.toolName}" (task ended)` };
|
|
74
84
|
}
|
|
75
85
|
let ok;
|
|
76
86
|
try {
|
|
@@ -79,13 +89,19 @@ export function createApprovalPolicy(opts) {
|
|
|
79
89
|
catch (err) {
|
|
80
90
|
return {
|
|
81
91
|
action: "deny",
|
|
82
|
-
|
|
92
|
+
message: `approval errored for "${req.toolName}": ${err instanceof Error ? err.message : String(err)}`,
|
|
83
93
|
};
|
|
84
94
|
}
|
|
85
|
-
|
|
95
|
+
const okRaw = ok;
|
|
96
|
+
if (okRaw === true)
|
|
97
|
+
return ALLOW;
|
|
98
|
+
if (okRaw !== false) {
|
|
99
|
+
return { action: "deny", message: `approval callback for "${req.toolName}" returned an out-of-contract value (${typeof ok}) — denied fail-closed (this policy's \`approve\` returns a boolean: return true or false)` };
|
|
100
|
+
}
|
|
101
|
+
return { action: "deny", message: `approval denied for "${req.toolName}"` };
|
|
86
102
|
}
|
|
87
103
|
if (opts.denyByDefault && !auto.has(toolName)) {
|
|
88
|
-
return { action: "deny",
|
|
104
|
+
return { action: "deny", message: `tool "${req.toolName}" requires explicit allow` };
|
|
89
105
|
}
|
|
90
106
|
return ALLOW;
|
|
91
107
|
},
|
|
@@ -100,7 +116,7 @@ export function combinePolicies(...policies) {
|
|
|
100
116
|
let current = req;
|
|
101
117
|
let rewrite;
|
|
102
118
|
for (const p of policies) {
|
|
103
|
-
const d = await p.check(current, signal);
|
|
119
|
+
const d = refuseOutOfContractDecision(await p.check(current, signal));
|
|
104
120
|
if (d.action === "deny") {
|
|
105
121
|
return rewrite?.updatedInput !== undefined ? { ...d, updatedInput: rewrite.updatedInput } : d;
|
|
106
122
|
}
|
|
@@ -130,7 +146,7 @@ export function createCoarseCommandNamePolicy(opts) {
|
|
|
130
146
|
const shellTools = canonicalToolNameSet(opts.tools);
|
|
131
147
|
const defaultAction = opts.defaultAction ?? "ask";
|
|
132
148
|
const fallback = (reason) => defaultAction === "deny"
|
|
133
|
-
? { action: "deny", reason, decisionReason: "rule" }
|
|
149
|
+
? { action: "deny", message: reason, decisionReason: "rule" }
|
|
134
150
|
: { action: "ask", message: reason, decisionReason: "rule" };
|
|
135
151
|
return {
|
|
136
152
|
check(req) {
|
|
@@ -145,7 +161,7 @@ export function createCoarseCommandNamePolicy(opts) {
|
|
|
145
161
|
return fallback(`command is not a single simple command (${parsed.reject})`);
|
|
146
162
|
}
|
|
147
163
|
if (deny.has(parsed.name)) {
|
|
148
|
-
return { action: "deny",
|
|
164
|
+
return { action: "deny", message: `command "${parsed.name}" is denied by policy`, decisionReason: "rule" };
|
|
149
165
|
}
|
|
150
166
|
if (allow && !allow.has(parsed.name)) {
|
|
151
167
|
return fallback(`command "${parsed.name}" is not in the allowlist`);
|
|
@@ -394,7 +410,7 @@ export function createUnverifiableDeletePolicy(opts) {
|
|
|
394
410
|
action: "ask",
|
|
395
411
|
decisionReason: "safety",
|
|
396
412
|
requiresRealApproval: true,
|
|
397
|
-
|
|
413
|
+
message: `Unverifiable recursive delete (fail-closed unless cleared): ${finding}. ` +
|
|
398
414
|
`Re-run the delete with the resolved literal path written into the command itself ` +
|
|
399
415
|
`(or assign the variable in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`,
|
|
400
416
|
};
|
|
@@ -468,7 +484,7 @@ export function createTranscriptIntegrityPolicy(opts) {
|
|
|
468
484
|
action: "ask",
|
|
469
485
|
decisionReason: "safety",
|
|
470
486
|
requiresRealApproval: true,
|
|
471
|
-
|
|
487
|
+
message: `Session-transcript write (fail-closed unless cleared): ${what}. Session transcripts (the .jsonl files ` +
|
|
472
488
|
`under the agent data dir's sessions/ directory) are harness-written session state, not agent working ` +
|
|
473
489
|
`files — modifying or deleting them tampers with the run's own audit trail. Reading them (ls/cat/grep ` +
|
|
474
490
|
`as a single simple command) is fine.`,
|
|
@@ -613,7 +629,15 @@ export async function resolveAsk(req, onAsk, signal) {
|
|
|
613
629
|
}
|
|
614
630
|
return { action: "allow", updatedInput: edit.value, decisionReason: "mode" };
|
|
615
631
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
632
|
+
const okRaw = ok;
|
|
633
|
+
if (okRaw === true)
|
|
634
|
+
return { action: "allow", decisionReason: "mode", presentedInput: presented.value };
|
|
635
|
+
if (okRaw !== false) {
|
|
636
|
+
return {
|
|
637
|
+
action: "deny",
|
|
638
|
+
message: `the approver for "${req.toolName}" returned an out-of-contract value (${typeof ok}) — denied fail-closed (return true, false, "unavailable", or the {allow} object)`,
|
|
639
|
+
decisionReason: "mode",
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
return { action: "deny", message: `approval denied for "${req.toolName}": ${req.message}`, decisionReason: "mode" };
|
|
619
643
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export { decideAutoPromote, deriveTripwire, FROZEN_DENYLIST_FLOOR, type AutoProm
|
|
|
40
40
|
export { runCascade, type CascadeRung, type CascadeConfig, type CascadeAttempt, type CascadeRunResult, type GateVerdict, } from "./agents/cascade.js";
|
|
41
41
|
export { pgQuery, mysqlQuery, sqliteQuery } from "./tools/sql-adapters.js";
|
|
42
42
|
export { materializeMcpTools, MCP_PREFIX, type MaterializedMcp, type McpServerStatus, type McpRefreshResult } from "./core/mcp.js";
|
|
43
|
+
export { PROTOCOL_TABLE, MCP_NAMESPACE, protocolOf, type ProtocolNamespace, type ProtocolId } from "./core/protocol-table.js";
|
|
43
44
|
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions, } from "./core/session-policy-store.js";
|
|
44
45
|
export { SAFETY_MERGE_CONFORMANCE_CORPUS, type SafetyMergeVector } from "./core/safety-merge-corpus.js";
|
|
45
46
|
export { SAFETY_AXIS_VOCABULARY } from "./core/safety-axis-vocab.js";
|
|
@@ -76,7 +77,7 @@ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpoi
|
|
|
76
77
|
export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
|
|
77
78
|
export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
|
|
78
79
|
export type { FileSnapshotStore, FileSnapshotResult, FileSnapshotError, FileSnapshotBounds } from "./core/file-snapshot-store.js";
|
|
79
|
-
export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, type FileStorageBackendOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
|
|
80
|
+
export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileSessionRepoOptions, type FileFileSnapshotStoreOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
|
|
80
81
|
export { CacheBreakDetector, type CacheBreakFinding, type ToolFingerprintInput } from "./core/cache-break-detector.js";
|
|
81
82
|
export { maybeCompact, type MaybeCompactOptions, type CompactionWindowSafetyInfo } from "./core/auto-compaction.js";
|
|
82
83
|
export { brainToRuntime } from "./core/runtime.js";
|
|
@@ -112,7 +113,7 @@ export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/au
|
|
|
112
113
|
export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, type PermissionRule, type ParsedPermissionRule, type PermissionRuleIssue, type PermissionRuleCaps, type PermissionRulePolicyOptions, } from "./core/permission-rules.js";
|
|
113
114
|
export { formatHookFeedback, runToolGate, type Hooks, type HookToolContext, type HookToolOutput, type PreToolUseResult, type PostToolUseResult, type UserPromptSubmitResult, type HookToolFailure, type PostToolUseFailureResult, type PostToolBatchCall, type PostToolBatchResult, type PreCompactContext, type PreCompactResult, type PostCompactContext, type StopFailureContext, type PermissionDeniedPayload, type PermissionDeniedSource, } from "./core/hooks.js";
|
|
114
115
|
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, type NormalizedMemorySpec, type MemorySpecInput, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, type Embedder, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, type UtilityGate, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryNoteType, type StructuredNoteInput, } from "./core/memory.js";
|
|
115
|
-
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
|
|
116
|
+
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
|
|
116
117
|
export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
|
|
117
118
|
export { encodeSurfacedKey, buildManifestText, validateSelectedIds, composeSelectiveBody, formatMemoryAge, resolveLinkedIds, RECALL_CAVEAT, DEFAULT_MAX_SELECTED, DEFAULT_MAX_LINKED, type MemorySelector, type MemorySelectRequest, type SelectiveRecallOptions, type SelectiveRecallResult, type LayeredRecallOptions, type LayeredRecallResult, type ScopedNoteHeader, type ScopedNoteRecord, } from "./core/memory-recall.js";
|
|
118
119
|
export { runMemoryConsolidation, CONSOLIDATION_SYSTEM_PROMPT, DEFAULT_CONSOLIDATION_BAND, DEFAULT_CONSOLIDATION_SEARCH_LIMIT, DEFAULT_CONSOLIDATION_MAX_NOTES, DEFAULT_CONSOLIDATION_TIMEOUT_SEC, normalizeForExactMatch, type ConsolidationParams, type ConsolidationStats, type ConsolidationNote, type ConsolidationLLM, } from "./core/runner/memory-consolidation.js";
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ export { decideAutoPromote, deriveTripwire, FROZEN_DENYLIST_FLOOR, } from "./cor
|
|
|
37
37
|
export { runCascade, } from "./agents/cascade.js";
|
|
38
38
|
export { pgQuery, mysqlQuery, sqliteQuery } from "./tools/sql-adapters.js";
|
|
39
39
|
export { materializeMcpTools, MCP_PREFIX } from "./core/mcp.js";
|
|
40
|
+
export { PROTOCOL_TABLE, MCP_NAMESPACE, protocolOf } from "./core/protocol-table.js";
|
|
40
41
|
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, } from "./core/session-policy-store.js";
|
|
41
42
|
export { SAFETY_MERGE_CONFORMANCE_CORPUS } from "./core/safety-merge-corpus.js";
|
|
42
43
|
export { SAFETY_AXIS_VOCABULARY } from "./core/safety-axis-vocab.js";
|
|
@@ -99,7 +100,7 @@ export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/au
|
|
|
99
100
|
export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, } from "./core/permission-rules.js";
|
|
100
101
|
export { formatHookFeedback, runToolGate, } from "./core/hooks.js";
|
|
101
102
|
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, } from "./core/memory.js";
|
|
102
|
-
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
|
|
103
|
+
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
|
|
103
104
|
export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
|
|
104
105
|
export { encodeSurfacedKey, buildManifestText, validateSelectedIds, composeSelectiveBody, formatMemoryAge, resolveLinkedIds, RECALL_CAVEAT, DEFAULT_MAX_SELECTED, DEFAULT_MAX_LINKED, } from "./core/memory-recall.js";
|
|
105
106
|
export { runMemoryConsolidation, CONSOLIDATION_SYSTEM_PROMPT, DEFAULT_CONSOLIDATION_BAND, DEFAULT_CONSOLIDATION_SEARCH_LIMIT, DEFAULT_CONSOLIDATION_MAX_NOTES, DEFAULT_CONSOLIDATION_TIMEOUT_SEC, normalizeForExactMatch, } from "./core/runner/memory-consolidation.js";
|
|
@@ -28,7 +28,7 @@ function frozenDenyPolicy(rootDir, frozenResolved) {
|
|
|
28
28
|
const absForm = isAbsolutePathForm(raw);
|
|
29
29
|
const abs = pathKey(absForm ? raw : resolve(rootDir, raw));
|
|
30
30
|
if (frozen.has(abs)) {
|
|
31
|
-
return { action: "deny",
|
|
31
|
+
return { action: "deny", message: `${raw} is part of the frozen specification surface (read-only).` };
|
|
32
32
|
}
|
|
33
33
|
return { action: "allow" };
|
|
34
34
|
},
|