@sema-agent/core 5.38.0 → 5.40.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 +182 -10
- package/dist/agents/send-message-tool.d.ts +8 -0
- package/dist/agents/send-message-tool.js +8 -0
- package/dist/agents/teacher.js +9 -3
- package/dist/agents/verify.js +9 -3
- package/dist/core/checkpoint-store.d.ts +12 -0
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +23 -0
- package/dist/core/hooks.js +53 -4
- package/dist/core/mailbox-store.d.ts +39 -0
- package/dist/core/mailbox-store.js +9 -0
- package/dist/core/memory-engine/engine.d.ts +27 -0
- package/dist/core/memory-engine/engine.js +103 -1
- package/dist/core/memory-engine/export-bundle.d.ts +192 -0
- package/dist/core/memory-engine/export-bundle.js +306 -0
- package/dist/core/memory-engine/file-backend.d.ts +178 -1
- package/dist/core/memory-engine/file-backend.js +637 -6
- package/dist/core/memory-engine/index.d.ts +2 -1
- package/dist/core/memory-engine/index.js +1 -0
- package/dist/core/memory-engine/layout.d.ts +89 -1
- package/dist/core/memory-engine/layout.js +131 -1
- package/dist/core/memory-engine/memory-backend-contract.d.ts +1 -1
- package/dist/core/memory-engine/memory-backend-contract.js +52 -0
- package/dist/core/memory-engine/tools.js +8 -1
- package/dist/core/permission-rule-consent.d.ts +27 -4
- package/dist/core/permission-rule-consent.js +41 -4
- package/dist/core/permission-rule-model.d.ts +7 -1
- package/dist/core/runner/prepare-task.js +24 -3
- package/dist/core/runner/runtask.js +5 -0
- package/dist/core/runner/synthetic-tools.js +3 -1
- package/dist/core/runner/tool-disclosure.js +2 -1
- package/dist/core/sensitive-path-policy.js +3 -3
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +29 -1
- package/dist/core/store-contracts/mailbox-store-contract.js +78 -0
- package/dist/core/types.d.ts +21 -0
- package/dist/core/write-protect.d.ts +73 -0
- package/dist/core/write-protect.js +195 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/orchestration/governance-baseline-validity.d.ts +44 -0
- package/dist/orchestration/governance-baseline-validity.js +55 -0
- package/dist/orchestration/run-workflow-tool.js +33 -8
- package/dist/orchestration/workflow-script-runner.js +9 -4
- package/dist/tools/fs/read-deny.d.ts +15 -5
- package/dist/tools/fs/read-deny.js +33 -12
- package/dist/tools/fs/safety.d.ts +5 -2
- package/dist/tools/fs/safety.js +5 -3
- package/dist/tools/fs/search.d.ts +33 -0
- package/dist/tools/fs/search.js +72 -0
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +21 -1
|
@@ -28,8 +28,9 @@ import { CHANGED_FILES_MTIME_EPS_MS, fenceMcpServerInstructions, renderAgentList
|
|
|
28
28
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
29
29
|
import { policyAskClassOf } from "../ask-class.js";
|
|
30
30
|
import { emitTrace } from "../trace.js";
|
|
31
|
-
import { createSessionRulePolicy } from "./session-rule-policy.js";
|
|
31
|
+
import { createSessionRulePolicy, PATH_CONFINABLE_WRITE_TOOLS } from "./session-rule-policy.js";
|
|
32
32
|
import { cloneObserverInput, createHookEnvCapabilities, createPreToolUseConstraintPolicy, formatHookFeedback, mintHookInvocationIdentity, persistedRuleMandateOf, runToolGate } from "../hooks.js";
|
|
33
|
+
import { createWriteProtectionCheck } from "../write-protect.js";
|
|
33
34
|
import { orgRuleVerdictFor } from "../permission-rule-org.js";
|
|
34
35
|
import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
|
|
35
36
|
import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
|
|
@@ -326,6 +327,13 @@ function orgRevisionEvidenceOf(resolution, onDefect) {
|
|
|
326
327
|
function persistedRuleHitOf(admitting) {
|
|
327
328
|
return admitting === undefined ? undefined : { rule: admitting.rule, dots: admitting.adds.map((a) => ({ actor: a.dot.actor, counter: a.dot.counter })) };
|
|
328
329
|
}
|
|
330
|
+
function cwdConflictsRestoreError(requestedCwd) {
|
|
331
|
+
const e = new Error(`RunInternals.requestedCwd ("${requestedCwd}") cannot be combined with a checkpoint workspace restore — ` +
|
|
332
|
+
`the restored workspace's own mount path is authoritative for the task root, so a requested cwd on this leg ` +
|
|
333
|
+
`would be ignored (or worse, probed against an unrestored environment). Drop requestedCwd on resume legs.`);
|
|
334
|
+
e.code = "config.cwd_conflicts_restore";
|
|
335
|
+
return e;
|
|
336
|
+
}
|
|
329
337
|
export async function prepareTask(spec, deps, sessions, resume, internals, runnerSelf) {
|
|
330
338
|
const doors = prepareConfigDoors({ spec, deps, sessions, resume, internals });
|
|
331
339
|
spec = doors.spec;
|
|
@@ -420,6 +428,10 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
420
428
|
e.code = "config.cwd_unsupported";
|
|
421
429
|
throw e;
|
|
422
430
|
}
|
|
431
|
+
if (internals?.requestedCwd !== undefined && resume?.workspaceHandle !== undefined) {
|
|
432
|
+
await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (cwd-conflicts-restore leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
|
|
433
|
+
throw cwdConflictsRestoreError(internals.requestedCwd);
|
|
434
|
+
}
|
|
423
435
|
try {
|
|
424
436
|
ownedEnv = deps.executionEnvFactory
|
|
425
437
|
? await deps.executionEnvFactory({
|
|
@@ -1247,6 +1259,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1247
1259
|
if (c.ok)
|
|
1248
1260
|
additionalRootsCanonical.push(c.value);
|
|
1249
1261
|
}
|
|
1262
|
+
for (const a of [additionalRootsCanonical, additionalReadRootsCanonical])
|
|
1263
|
+
a.splice(0, a.length, ...new Set(a));
|
|
1250
1264
|
const readFileState = new Map((resume?.seed.readFileState ?? []).map(([k, v]) => [rebaseRestoredPath(k), v]));
|
|
1251
1265
|
readFileStateForCheckpoint = readFileState;
|
|
1252
1266
|
seedContextFiles = async (files) => {
|
|
@@ -1413,6 +1427,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1413
1427
|
toolEffects.set("TaskStop", "write");
|
|
1414
1428
|
tools.push(firstPartyOffload(createTaskOutputTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore, notificationWired: internals?.onTaskNotification !== undefined, oneShot: spec.oneShot, toolResultStore: offloadStore })), firstPartyOffload(createTaskStopTool({ registry: defaultTaskRegistry, owner: hostTaskId, scope: taskScope, sessionId, workflowStore: deps.workflowRunStore, agentStore: deps.backgroundAgentStore })));
|
|
1415
1429
|
if (runnerSelf && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME)) {
|
|
1430
|
+
toolEffects.set(SEND_MESSAGE_TOOL_NAME, "write");
|
|
1431
|
+
axisExplicitNegatives.set(SEND_MESSAGE_TOOL_NAME, { ...axisExplicitNegatives.get(SEND_MESSAGE_TOOL_NAME), egress: false });
|
|
1416
1432
|
const delegationForRevive = (spec.tools ?? []).find((t) => t.agentListing !== undefined);
|
|
1417
1433
|
const reviveSpawn = delegationForRevive !== undefined && deps.backgroundAgentStore !== undefined && deps.mailboxStore !== undefined
|
|
1418
1434
|
? async (req) => {
|
|
@@ -2813,7 +2829,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2813
2829
|
list.push({ cls, layer });
|
|
2814
2830
|
foldAskClasses.set(toolCallId, list);
|
|
2815
2831
|
};
|
|
2816
|
-
const sandboxBoundaryCapable = (toolName) => egressTools.has(toolName) || toolName.includes("__") || ownToolNames.has(toolName);
|
|
2832
|
+
const sandboxBoundaryCapable = (toolName) => egressTools.has(toolName) || toolName.includes("__") || ownToolNames.has(toolName) || toolName === SEND_MESSAGE_TOOL_NAME;
|
|
2817
2833
|
const emitSandboxAdmitted = (info) => {
|
|
2818
2834
|
emitTrace(deps.tracer, () => ({
|
|
2819
2835
|
kind: "permission.sandbox_admitted",
|
|
@@ -4220,13 +4236,16 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4220
4236
|
if (eff !== undefined && !toolEffects.has(t.name))
|
|
4221
4237
|
toolEffects.set(t.name, eff);
|
|
4222
4238
|
}
|
|
4239
|
+
const writeProtectionCheck = createWriteProtectionCheck(deps.writeProtectedPaths);
|
|
4240
|
+
const writeProtectionArmed = writeProtectionCheck !== undefined && tools.some((t) => PATH_CONFINABLE_WRITE_TOOLS.has(t.name));
|
|
4223
4241
|
toolCallGateArmedRef.armed =
|
|
4224
4242
|
effectivePolicy !== undefined ||
|
|
4225
4243
|
hooks?.preToolUse !== undefined ||
|
|
4226
4244
|
egressTools.size > 0 ||
|
|
4227
4245
|
irreversibleTools.size > 0 ||
|
|
4228
4246
|
spec.enablePlanMode === true ||
|
|
4229
|
-
complianceDenies.has("web_fetch")
|
|
4247
|
+
complianceDenies.has("web_fetch") ||
|
|
4248
|
+
writeProtectionArmed;
|
|
4230
4249
|
if (toolCallGateArmedRef.armed) {
|
|
4231
4250
|
harness.on("tool_call", async (e) => {
|
|
4232
4251
|
blockedToolCalls.delete(e.toolCallId);
|
|
@@ -4269,6 +4288,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4269
4288
|
suspendAsk,
|
|
4270
4289
|
resolveContentAsk,
|
|
4271
4290
|
egress: egressTools.has(e.toolName),
|
|
4291
|
+
peerMessage: e.toolName === SEND_MESSAGE_TOOL_NAME,
|
|
4292
|
+
...(writeProtectionCheck !== undefined ? { writeProtectionCheck } : {}),
|
|
4272
4293
|
irreversibility: irreversibilityTier.get(e.toolName),
|
|
4273
4294
|
reversibilityProbe: reversibilityProbes.get(e.toolName),
|
|
4274
4295
|
abortSignal: abortController.signal,
|
|
@@ -4126,6 +4126,11 @@ export class Runner {
|
|
|
4126
4126
|
if (cp.state.workspaceHandle !== undefined && this.deps.executionEnvFactory === undefined) {
|
|
4127
4127
|
throw new CheckpointError("checkpoint.unsupported_version", "checkpoint has a remote workspaceHandle but no RunnerDeps.executionEnvFactory is wired to rebuild the env", { reason: "env_factory_missing" });
|
|
4128
4128
|
}
|
|
4129
|
+
if (cp.state.workspaceHandle !== undefined && internals?.requestedCwd !== undefined) {
|
|
4130
|
+
throw new CheckpointError("checkpoint.cwd_conflicts_restore", `internals.requestedCwd ("${internals.requestedCwd}") cannot be combined with a checkpoint workspace restore — ` +
|
|
4131
|
+
"the restored workspace's own mount path is authoritative for the task root. Drop requestedCwd on resume legs " +
|
|
4132
|
+
"(the checkpoint stays pending and is resumable without it).");
|
|
4133
|
+
}
|
|
4129
4134
|
if (cp.state.inheritedGate?.requiresParentConstraint === true) {
|
|
4130
4135
|
const supplied = internals?.inheritedGate?.parentConstraints?.length ?? 0;
|
|
4131
4136
|
if (supplied === 0) {
|
|
@@ -196,7 +196,9 @@ export function createSkillTool(skills, scope) {
|
|
|
196
196
|
const name = String(a.skill ?? "");
|
|
197
197
|
const skill = byName.get(name);
|
|
198
198
|
if (!skill) {
|
|
199
|
-
throw new Error(`Unknown skill "${name}". Available skills: ${names}
|
|
199
|
+
throw new Error(`Unknown skill "${name}". Available skills: ${names}. ` +
|
|
200
|
+
`(Only skills registered with this deployment are loadable — other products' skills directories are not read. ` +
|
|
201
|
+
`If the user wants one of those here, read its source file and recreate its content for this deployment instead.)`);
|
|
200
202
|
}
|
|
201
203
|
if (scope && skill.manifest) {
|
|
202
204
|
scope.push({ kind: "manifest", manifest: skill.manifest });
|
|
@@ -45,7 +45,8 @@ export function classifyDeferred(opts) {
|
|
|
45
45
|
if (!pinned.has(name))
|
|
46
46
|
deferred.add(name);
|
|
47
47
|
if (opts.deferMode === "auto") {
|
|
48
|
-
const
|
|
48
|
+
const callerNames = new Set(opts.specs.map((s) => s.name));
|
|
49
|
+
const candidates = opts.fullTools.filter((t) => !deferred.has(t.name) && !pinned.has(t.name) && callerNames.has(t.name));
|
|
49
50
|
const inlineFace = opts.fullTools.filter((t) => !deferred.has(t.name));
|
|
50
51
|
const total = inlineFace.reduce((n, t) => n + inlinedChars(t), 0);
|
|
51
52
|
const window = (opts.model.contextTokens ?? opts.model.contextWindow ?? 0) * CHARS_PER_TOKEN;
|
|
@@ -39,8 +39,8 @@ function compilePatterns(patterns) {
|
|
|
39
39
|
}
|
|
40
40
|
return out;
|
|
41
41
|
}
|
|
42
|
-
function matchSensitive(canonicalKey, compiled) {
|
|
43
|
-
return matchSegmentPatterns(canonicalKey, compiled);
|
|
42
|
+
function matchSensitive(canonicalKey, compiled, aliasResolved) {
|
|
43
|
+
return matchSegmentPatterns(canonicalKey, compiled, { aliasResolved });
|
|
44
44
|
}
|
|
45
45
|
export function createSensitivePathPolicy(opts) {
|
|
46
46
|
const compiled = compilePatterns(opts.patterns);
|
|
@@ -64,7 +64,7 @@ export function createSensitivePathPolicy(opts) {
|
|
|
64
64
|
}
|
|
65
65
|
return { action: "allow" };
|
|
66
66
|
}
|
|
67
|
-
const hit = matchSensitive(canon.key, compiled);
|
|
67
|
+
const hit = matchSensitive(canon.key, compiled, canon.aliasResolved === true);
|
|
68
68
|
if (hit) {
|
|
69
69
|
return {
|
|
70
70
|
action: "deny",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type MailboxStore } from "../mailbox-store.js";
|
|
2
2
|
import { type ContractAssertionRunner } from "./contract-harness.js";
|
|
3
3
|
/**
|
|
4
4
|
* design/159 S1 — the cross-backend {@link MailboxStore} contract, extracted VERBATIM from
|
|
@@ -46,3 +46,31 @@ export declare function mailboxAckOwnershipContract(mk: () => MailboxStore, runA
|
|
|
46
46
|
* 放宽」:核心层没有一条为了任何后端而弱化。第三方后端若有租户轴,应当也挂这一层。
|
|
47
47
|
*/
|
|
48
48
|
export declare function mailboxBundledOnlyContract(mk: () => MailboxStore, runAssertion?: ContractAssertionRunner): Promise<void>;
|
|
49
|
+
export interface MailboxTombstonedRecipientContractHooks {
|
|
50
|
+
/** Put `(scope, handle)` into the deployment's PRE-DELETE state — whatever that is for this
|
|
51
|
+
* backend (a cascade marking the session row, a `deleting` column, a tombstone table). Core does
|
|
52
|
+
* not name the mechanism, only what `append` must then do. */
|
|
53
|
+
tombstone: (store: MailboxStore, scope: string, handle: string) => Promise<void>;
|
|
54
|
+
runAssertion?: ContractAssertionRunner;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* T2 可选能力层(pre-delete 分册)—— 只挂**看得见收件人生命周期**的后端:它的 mailbox 行与某个
|
|
58
|
+
* 删除级联要清掉的 session 行同生共死(server 的留存删除级联是首个此形消费方)。三个捆绑后端都
|
|
59
|
+
* 没有这个视角,因此都不挂——**这不是「做不到所以放宽」**:没有预删除态的后端根本没有可拒的对象,
|
|
60
|
+
* 而有这个态却静默接受的后端,拿到的 seq 是一张级联马上就要撕掉的回执(`append` 是 durable-first,
|
|
61
|
+
* 回执即承诺),且没有任何其它面会说出这件事。
|
|
62
|
+
*
|
|
63
|
+
* 契约不规定态怎么置(那是部署自己的删除协议),只钉「拒」这件事的三条轴 —— **三条一起列在这里,
|
|
64
|
+
* 是因为逐条补的过程本身证明了单看一条会假绿**(每加一条,都有一个能过掉前面全部用例的错误实现被
|
|
65
|
+
* 抓出来):
|
|
66
|
+
* 1. **拒因轴**:必须拒,且每条路径上都带同一个码(空箱与非空箱都算路径);
|
|
67
|
+
* 2. **副作用轴**:被拒的 append 对箱零改动 —— 不入箱(幽灵投递)、不清箱(删除窗口内静默丢)、
|
|
68
|
+
* 也不动活租约(动了就撬开 X-1 的单消费者围栏,同一批消息会被二次投递);
|
|
69
|
+
* 3. **收件人边界轴**:态属于一个 `(scope, handle)` 整体,且这个整体是**单射**的 —— 兄弟 handle
|
|
70
|
+
* 不受牵连、跨租户同名不受牵连、拼键歧义不得把两个收件人折成一个。
|
|
71
|
+
* 新增用例请按这三条轴归位;要加第四条轴,先说清它是哪一类假绿。
|
|
72
|
+
*
|
|
73
|
+
* 受众前提与 {@link mailboxBundledOnlyContract} 同线:后端有自己的租户轴(生命周期可见的后端就是
|
|
74
|
+
* 服务端形态的 store),边界轴的两条用例要用两个 scope 构造。
|
|
75
|
+
*/
|
|
76
|
+
export declare function mailboxTombstonedRecipientContract(mk: () => MailboxStore, hooks: MailboxTombstonedRecipientContractHooks): Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { strict as assert } from "node:assert";
|
|
2
|
+
import { MAILBOX_TOMBSTONED_RECIPIENT_CODE } from "../mailbox-store.js";
|
|
2
3
|
import { beginContract } from "./contract-harness.js";
|
|
3
4
|
export const MAILBOX_CONTRACT_SCOPE = "default";
|
|
4
5
|
const msg = (content, sentAt = 1000) => ({ content, sentAt });
|
|
@@ -191,3 +192,80 @@ export async function mailboxBundledOnlyContract(mk, runAssertion) {
|
|
|
191
192
|
});
|
|
192
193
|
await settle();
|
|
193
194
|
}
|
|
195
|
+
export async function mailboxTombstonedRecipientContract(mk, hooks) {
|
|
196
|
+
const { run: runRaw, settle } = beginContract(hooks.runAssertion);
|
|
197
|
+
const run = (name, fn) => runRaw(name, () => withStores(mk, fn));
|
|
198
|
+
const S = MAILBOX_CONTRACT_SCOPE;
|
|
199
|
+
const codeOf = (e) => e?.code;
|
|
200
|
+
run("预删除态的收件人:append 响亮拒且带码(既不静默收下级联即将删掉的消息,也不裸抛)", async (make) => {
|
|
201
|
+
const s = make();
|
|
202
|
+
await hooks.tombstone(s, S, "a1");
|
|
203
|
+
let thrown;
|
|
204
|
+
try {
|
|
205
|
+
await s.append(S, "a1", msg("m1"));
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
thrown = e;
|
|
209
|
+
}
|
|
210
|
+
assert.notEqual(thrown, undefined, "静默收下 = 给发件人一张级联马上撕掉的回执");
|
|
211
|
+
assert.equal(codeOf(thrown), MAILBOX_TOMBSTONED_RECIPIENT_CODE, "裸抛与拒同形:消费方要能按码分诊");
|
|
212
|
+
let again;
|
|
213
|
+
try {
|
|
214
|
+
await s.append(S, "a1", msg("m2"));
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
again = e;
|
|
218
|
+
}
|
|
219
|
+
assert.equal(codeOf(again), MAILBOX_TOMBSTONED_RECIPIENT_CODE);
|
|
220
|
+
});
|
|
221
|
+
run("拒的粒度是收件人,不是开关:同 scope 下另一个活收件人照常收信", async (make) => {
|
|
222
|
+
const s = make();
|
|
223
|
+
await hooks.tombstone(s, S, "a1");
|
|
224
|
+
assert.equal(await s.append(S, "a2", msg("still-live")), 1, "活收件人不受邻居的删除级联牵连");
|
|
225
|
+
assert.equal(await s.peekCount(S, "a2"), 1);
|
|
226
|
+
});
|
|
227
|
+
run("收件人身份是 (scope, handle) 整体:A 租户的删除级联不得拒掉 B 租户的同名收件人", async (make) => {
|
|
228
|
+
const s = make();
|
|
229
|
+
await hooks.tombstone(s, "tenant-a", "a1");
|
|
230
|
+
assert.equal(await s.append("tenant-b", "a1", msg("other-tenant")), 1, "同名 handle 在另一个租户下是另一个收件人");
|
|
231
|
+
assert.equal(await s.peekCount("tenant-b", "a1"), 1);
|
|
232
|
+
});
|
|
233
|
+
run("两件套还得是单射的:把 (scope, handle) 拼成一个字符串记态,不得让两个不同收件人撞成一个", async (make) => {
|
|
234
|
+
const s = make();
|
|
235
|
+
await hooks.tombstone(s, "tenant a", "b");
|
|
236
|
+
assert.equal(await s.append("tenant", "a b", msg("distinct-recipient")), 1, "拼键歧义不得把另一个收件人一起拒掉");
|
|
237
|
+
assert.equal(await s.peekCount("tenant", "a b"), 1);
|
|
238
|
+
});
|
|
239
|
+
run("副作用轴 · 活租约:被拒的 append 不得动别人手上的租约(单消费者围栏不因删除窗口松开)", async (make) => {
|
|
240
|
+
const s = make();
|
|
241
|
+
await s.append(S, "a1", msg("in-flight"));
|
|
242
|
+
const held = await s.claimLease(S, "a1", "consumer-A", 60_000, 10_000);
|
|
243
|
+
assert.equal(held?.messages.length, 1);
|
|
244
|
+
await hooks.tombstone(s, S, "a1");
|
|
245
|
+
await assert.rejects(s.append(S, "a1", msg("after-tombstone", 2_000)), "预删除态下的 append 必须拒");
|
|
246
|
+
assert.equal(await s.claimLease(S, "a1", "rival", 60_000, 11_000), null, "A 的活租约必须仍然 fence 住别人");
|
|
247
|
+
await s.ack(S, "a1", "consumer-A", held.maxSeq);
|
|
248
|
+
assert.equal(await s.peekCount(S, "a1"), 0);
|
|
249
|
+
});
|
|
250
|
+
run("拒的是入口,不是清仓:被拒的 append 零副作用,已入箱的消息按原 seq/内容原封不动", async (make) => {
|
|
251
|
+
const s = make();
|
|
252
|
+
const seq = await s.append(S, "a1", msg("parked-before"));
|
|
253
|
+
await hooks.tombstone(s, S, "a1");
|
|
254
|
+
let thrown;
|
|
255
|
+
let refused = false;
|
|
256
|
+
try {
|
|
257
|
+
await s.append(S, "a1", msg("after-tombstone", 2_000));
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
refused = true;
|
|
261
|
+
thrown = e;
|
|
262
|
+
}
|
|
263
|
+
assert.equal(refused, true, "预删除态下的 append 必须拒");
|
|
264
|
+
assert.equal(codeOf(thrown), MAILBOX_TOMBSTONED_RECIPIENT_CODE, "箱非空时的拒同样要带码");
|
|
265
|
+
assert.equal(await s.peekCount(S, "a1"), 1, "被拒的 append 不得入箱(幽灵投递),也不得清箱");
|
|
266
|
+
const lease = await s.claimLease(S, "a1", "w1", 60_000, 10_000);
|
|
267
|
+
assert.deepEqual(lease?.messages.map((m) => m.seq), [seq]);
|
|
268
|
+
assert.deepEqual(lease?.messages.map((m) => m.content), ["parked-before"], "取到的仍是拒之前那一条");
|
|
269
|
+
});
|
|
270
|
+
await settle();
|
|
271
|
+
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -4785,6 +4785,27 @@ export interface RunnerDeps {
|
|
|
4785
4785
|
* ignored). Same deployment-only seat, clamp argument and checkpoint posture as the tiers key.
|
|
4786
4786
|
*/
|
|
4787
4787
|
readDenyBuiltinExclude?: readonly string[];
|
|
4788
|
+
/**
|
|
4789
|
+
* backlog #286 (#279 — CC 2.1.233 `DANGEROUS_FILES`/`DANGEROUS_DIRECTORIES`/
|
|
4790
|
+
* `DANGEROUS_DIRECTORY_PATHS` parity): the WRITE-protection table. DEFAULT-ON: a path-confinable
|
|
4791
|
+
* write (Write/Edit/NotebookEdit) whose target lands on a table row has a surviving `allow`
|
|
4792
|
+
* demoted to `ask` at the tool gate (`decisionReason: "safety"`; a deny/ask verdict is untouched;
|
|
4793
|
+
* approval flows the ordinary ask-resolution chain — classifier, blanket `onAsk`, durable park —
|
|
4794
|
+
* with no `requiresRealApproval` mandate). Absent =
|
|
4795
|
+
* {@link import("./write-protect.js").WRITE_PROTECTED_DEFAULT_TABLE} (the CC triple verbatim +
|
|
4796
|
+
* the two argued sema rows). This key IS the whole-table escape hatch, deployment seat ONLY (no
|
|
4797
|
+
* TaskSpec twin, no governed-workflow channel): `[]` = no table (explicit and legal); a non-empty
|
|
4798
|
+
* list REPLACES the built-in table whole (compose additions as
|
|
4799
|
+
* `[...WRITE_PROTECTED_DEFAULT_TABLE, …]`; drop rows by filtering the exported table — the
|
|
4800
|
+
* visible/deletable admin face). Bad values refuse loudly at prepare (#123): garbage shapes,
|
|
4801
|
+
* glob metacharacters (the table speaks LITERAL names — glob semantics live in
|
|
4802
|
+
* `createSensitivePathPolicy`), unknown kinds, impossible kind/name combinations. Matching is
|
|
4803
|
+
* lexical over the spelled target with one case fold (ı/ſ included) — a symlink alias evades it
|
|
4804
|
+
* by construction; the canonicalizing opt-in deny policy remains the hard layer. Not frozen into
|
|
4805
|
+
* checkpoints: a resumed task follows the CURRENT deployment table (an approved parked call
|
|
4806
|
+
* bypasses the gate as always — the human already adjudicated it).
|
|
4807
|
+
*/
|
|
4808
|
+
writeProtectedPaths?: readonly import("./write-protect.js").WriteProtectedEntry[];
|
|
4788
4809
|
/**
|
|
4789
4810
|
* design/199 件A — the DEPLOYMENT's read-face declaration
|
|
4790
4811
|
* ({@link import("../tools/fs/read-face.js").ReadFace}; see {@link TaskSpec.readFace} for the
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How one table row matches the judged path:
|
|
3
|
+
* · `"basename"` — the target's last segment equals the row name (CC `DANGEROUS_FILES` form);
|
|
4
|
+
* · `"segment"` — ANY path segment equals the row name (CC `DANGEROUS_DIRECTORIES` form);
|
|
5
|
+
* · `"segment-run"` — a CONSECUTIVE run of segments equals the row's `/`-separated segments
|
|
6
|
+
* (CC `DANGEROUS_DIRECTORY_PATHS` form, e.g. `.config/git`).
|
|
7
|
+
*/
|
|
8
|
+
export type WriteProtectedKind = "basename" | "segment" | "segment-run";
|
|
9
|
+
/** One row of the write-protection table: a LITERAL name and how it matches. The `name` is also the
|
|
10
|
+
* row's stable identity — the string a refusal/ask message cites. */
|
|
11
|
+
export interface WriteProtectedRow {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly kind: WriteProtectedKind;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One deployment-authored entry for the replacement seat (`RunnerDeps.writeProtectedPaths`).
|
|
17
|
+
* String shorthand: a bare name ≡ `{ name, kind: "segment" }` (the WIDER single-segment kind —
|
|
18
|
+
* over-matching is the fail-safe direction for a tighten); a name containing `/` ≡
|
|
19
|
+
* `{ name, kind: "segment-run" }`. Spell `kind: "basename"` explicitly when last-segment-only
|
|
20
|
+
* matching is the intent.
|
|
21
|
+
*/
|
|
22
|
+
export type WriteProtectedEntry = string | WriteProtectedRow;
|
|
23
|
+
/** A table hit: which row matched (the row's canonical name + kind). */
|
|
24
|
+
export interface WriteProtectedHit {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly kind: WriteProtectedKind;
|
|
27
|
+
}
|
|
28
|
+
export declare const WRITE_PROTECTED_DEFAULT_TABLE: readonly WriteProtectedRow[];
|
|
29
|
+
/**
|
|
30
|
+
* The ONE case fold of this module, applied to BOTH sides of every comparison (table names at
|
|
31
|
+
* compile, path segments at match) — `toLowerCase` plus the two confusable letters CC's fold maps
|
|
32
|
+
* (U+0131 dotless ı → i, U+017F long ſ → s). Deliberately NOT full Unicode confusable folding:
|
|
33
|
+
* that would be a different, wider claim than the one made (the read deny set's ASCII-contract doc
|
|
34
|
+
* states the same boundary for its own fold).
|
|
35
|
+
*/
|
|
36
|
+
export declare function foldWriteProtectCase(s: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the ACTIVE table under the deployment seat (validated, loud — #123's bad-value states all
|
|
39
|
+
* throw and name the knob). `undefined` = the default table; `[]` = NO table (an explicit, legal
|
|
40
|
+
* posture — the whole-table escape hatch's empty end); a non-empty list REPLACES the default table
|
|
41
|
+
* whole (compose additions as `[...WRITE_PROTECTED_DEFAULT_TABLE, …]`, drop rows by filtering the
|
|
42
|
+
* exported table — the visible/deletable admin face). Exact duplicates fold (idempotent, not one of
|
|
43
|
+
* #123's bad-value states). Exported so an admin face can preview the effective table under a
|
|
44
|
+
* candidate configuration with the engine's own rules.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveWriteProtectedTable(entries?: readonly WriteProtectedEntry[]): readonly WriteProtectedRow[];
|
|
47
|
+
/** The compiled judge over one resolved table. Pure and synchronous — literal folded comparisons,
|
|
48
|
+
* no filesystem access (see the module header for the declared lexical scope). */
|
|
49
|
+
export interface WriteProtectionMatcher {
|
|
50
|
+
/** The resolved rows this judge was compiled from (canonical names — the disclosure face). */
|
|
51
|
+
readonly rows: readonly WriteProtectedRow[];
|
|
52
|
+
/** Judge ONE path spelling. Returns the first matching row (basename rows first, then segment,
|
|
53
|
+
* then segment-run — deterministic), or null. */
|
|
54
|
+
matchPath(path: string): WriteProtectedHit | null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Compile the write-protection judge for a deployment configuration. Returns `undefined` when the
|
|
58
|
+
* resolved table is EMPTY (`[]` replacement) — the caller then mounts no tighten at all, keeping an
|
|
59
|
+
* opted-out deployment's decision path byte-identical to a build without this layer.
|
|
60
|
+
*/
|
|
61
|
+
export declare function compileWriteProtection(entries?: readonly WriteProtectedEntry[]): WriteProtectionMatcher | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Build the ENGINE-FILLED gate input (`ToolGateInput.writeProtectionCheck`): covered tools are the
|
|
64
|
+
* path-confinable write set (Write/Edit/NotebookEdit — the shared spelling), the judged target is
|
|
65
|
+
* the SAME string the tool itself will resolve (`writeTargetPath`, the shared single source with
|
|
66
|
+
* the sensitive-path guard and the fs-write gate), and the verdict is the table judge's. A covered
|
|
67
|
+
* write with NO resolvable target returns null here — this layer is ADDITIVE friction on a named
|
|
68
|
+
* set of targets, not a containment boundary (a target-less call cannot land on a named row, and
|
|
69
|
+
* the tool's own schema validation refuses it before any write); the fail-closed treatment of the
|
|
70
|
+
* unresolvable case belongs to the containment gates (fs-write-gate-policy documents that split).
|
|
71
|
+
* Returns `undefined` when the resolved table is empty — nothing to judge, mount nothing.
|
|
72
|
+
*/
|
|
73
|
+
export declare function createWriteProtectionCheck(entries?: readonly WriteProtectedEntry[]): ((toolName: string, args: unknown) => WriteProtectedHit | null) | undefined;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { writeTargetPath } from "../tools/fs/safety.js";
|
|
2
|
+
import { PATH_CONFINABLE_WRITE_TOOLS } from "./runner/session-rule-policy.js";
|
|
3
|
+
const freezeTable = (rows) => Object.freeze(rows.map((r) => Object.freeze(r)));
|
|
4
|
+
export const WRITE_PROTECTED_DEFAULT_TABLE = freezeTable([
|
|
5
|
+
{ name: ".gitconfig", kind: "basename" },
|
|
6
|
+
{ name: ".gitmodules", kind: "basename" },
|
|
7
|
+
{ name: ".bashrc", kind: "basename" },
|
|
8
|
+
{ name: ".bash_profile", kind: "basename" },
|
|
9
|
+
{ name: ".zshrc", kind: "basename" },
|
|
10
|
+
{ name: ".zprofile", kind: "basename" },
|
|
11
|
+
{ name: ".profile", kind: "basename" },
|
|
12
|
+
{ name: ".zshenv", kind: "basename" },
|
|
13
|
+
{ name: ".zlogin", kind: "basename" },
|
|
14
|
+
{ name: ".zlogout", kind: "basename" },
|
|
15
|
+
{ name: ".bash_login", kind: "basename" },
|
|
16
|
+
{ name: ".bash_aliases", kind: "basename" },
|
|
17
|
+
{ name: ".bash_logout", kind: "basename" },
|
|
18
|
+
{ name: ".envrc", kind: "basename" },
|
|
19
|
+
{ name: ".ripgreprc", kind: "basename" },
|
|
20
|
+
{ name: ".mcp.json", kind: "basename" },
|
|
21
|
+
{ name: ".claude.json", kind: "basename" },
|
|
22
|
+
{ name: ".npmrc", kind: "basename" },
|
|
23
|
+
{ name: ".yarnrc", kind: "basename" },
|
|
24
|
+
{ name: ".yarnrc.yml", kind: "basename" },
|
|
25
|
+
{ name: ".pnp.cjs", kind: "basename" },
|
|
26
|
+
{ name: ".pnp.loader.mjs", kind: "basename" },
|
|
27
|
+
{ name: ".pnpmfile.cjs", kind: "basename" },
|
|
28
|
+
{ name: "bunfig.toml", kind: "basename" },
|
|
29
|
+
{ name: ".bunfig.toml", kind: "basename" },
|
|
30
|
+
{ name: ".bazelrc", kind: "basename" },
|
|
31
|
+
{ name: ".bazelversion", kind: "basename" },
|
|
32
|
+
{ name: ".bazeliskrc", kind: "basename" },
|
|
33
|
+
{ name: ".pre-commit-config.yaml", kind: "basename" },
|
|
34
|
+
{ name: "lefthook.yml", kind: "basename" },
|
|
35
|
+
{ name: ".lefthook.yml", kind: "basename" },
|
|
36
|
+
{ name: "lefthook.yaml", kind: "basename" },
|
|
37
|
+
{ name: ".lefthook.yaml", kind: "basename" },
|
|
38
|
+
{ name: "gradle-wrapper.properties", kind: "basename" },
|
|
39
|
+
{ name: "maven-wrapper.properties", kind: "basename" },
|
|
40
|
+
{ name: ".devcontainer.json", kind: "basename" },
|
|
41
|
+
{ name: "pyrightconfig.json", kind: "basename" },
|
|
42
|
+
{ name: ".git", kind: "segment" },
|
|
43
|
+
{ name: ".vscode", kind: "segment" },
|
|
44
|
+
{ name: ".idea", kind: "segment" },
|
|
45
|
+
{ name: ".claude", kind: "segment" },
|
|
46
|
+
{ name: ".husky", kind: "segment" },
|
|
47
|
+
{ name: ".cargo", kind: "segment" },
|
|
48
|
+
{ name: ".devcontainer", kind: "segment" },
|
|
49
|
+
{ name: ".yarn", kind: "segment" },
|
|
50
|
+
{ name: ".mvn", kind: "segment" },
|
|
51
|
+
{ name: ".config/git", kind: "segment-run" },
|
|
52
|
+
{ name: ".ssh", kind: "segment" },
|
|
53
|
+
{ name: ".gnupg", kind: "segment" },
|
|
54
|
+
]);
|
|
55
|
+
export function foldWriteProtectCase(s) {
|
|
56
|
+
return s.toLowerCase().replace(/ı/g, "i").replace(/ſ/g, "s");
|
|
57
|
+
}
|
|
58
|
+
const KINDS = ["basename", "segment", "segment-run"];
|
|
59
|
+
function describeEntryValue(v) {
|
|
60
|
+
try {
|
|
61
|
+
return JSON.stringify(v) ?? String(v);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return String(v);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function normalizeWriteProtectedEntry(entry) {
|
|
68
|
+
const shape = typeof entry === "string" ? { name: entry, kind: entry.includes("/") ? "segment-run" : "segment" } : entry;
|
|
69
|
+
if (typeof shape !== "object" || shape === null || typeof shape.name !== "string") {
|
|
70
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(entry)} is not a name string or { name, kind } row.`);
|
|
71
|
+
}
|
|
72
|
+
const name = shape.name;
|
|
73
|
+
if (!KINDS.includes(shape.kind)) {
|
|
74
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(entry)} has kind ${describeEntryValue(shape.kind)} — known kinds: ${KINDS.join(", ")}.`);
|
|
75
|
+
}
|
|
76
|
+
const kind = shape.kind;
|
|
77
|
+
if (name.includes("*") || name.includes("?")) {
|
|
78
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a wildcard metacharacter — this table speaks LITERAL names only (a silently-literal "*" would guard less than it reads); pattern semantics live in createSensitivePathPolicy.`);
|
|
79
|
+
}
|
|
80
|
+
if (name.includes("\\")) {
|
|
81
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a backslash — names are "/"-separated (both path families are matched); spell the segments with "/".`);
|
|
82
|
+
}
|
|
83
|
+
const segments = name.split("/").filter((s) => s.length > 0);
|
|
84
|
+
if (segments.length === 0) {
|
|
85
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains no path segments and would protect nothing — remove the entry or spell the name.`);
|
|
86
|
+
}
|
|
87
|
+
if (segments.some((s) => s === "." || s === "..")) {
|
|
88
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a "." or ".." segment — the judge folds dot segments lexically before matching, so such a row could never match anything; spell the real name.`);
|
|
89
|
+
}
|
|
90
|
+
if (segments.length > 1 && kind !== "segment-run") {
|
|
91
|
+
throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} spans ${segments.length} segments but declares kind "${kind}" — multi-segment names match as kind "segment-run".`);
|
|
92
|
+
}
|
|
93
|
+
return { name: segments.join("/"), kind };
|
|
94
|
+
}
|
|
95
|
+
export function resolveWriteProtectedTable(entries) {
|
|
96
|
+
if (entries === undefined)
|
|
97
|
+
return WRITE_PROTECTED_DEFAULT_TABLE;
|
|
98
|
+
if (!Array.isArray(entries)) {
|
|
99
|
+
throw new Error(`writeProtectedPaths: expected an array of entries (whole-table replacement; [] = no write-protection table), got ${describeEntryValue(entries)}.`);
|
|
100
|
+
}
|
|
101
|
+
const out = [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
const row = normalizeWriteProtectedEntry(entry);
|
|
105
|
+
const key = `${row.kind}:${foldWriteProtectCase(row.name)}`;
|
|
106
|
+
if (seen.has(key))
|
|
107
|
+
continue;
|
|
108
|
+
seen.add(key);
|
|
109
|
+
out.push(row);
|
|
110
|
+
}
|
|
111
|
+
return freezeTable(out);
|
|
112
|
+
}
|
|
113
|
+
export function compileWriteProtection(entries) {
|
|
114
|
+
const rows = resolveWriteProtectedTable(entries);
|
|
115
|
+
if (rows.length === 0)
|
|
116
|
+
return undefined;
|
|
117
|
+
const basenames = new Map();
|
|
118
|
+
const segments = new Map();
|
|
119
|
+
const runs = [];
|
|
120
|
+
for (const row of rows) {
|
|
121
|
+
const folded = foldWriteProtectCase(row.name);
|
|
122
|
+
if (row.kind === "basename") {
|
|
123
|
+
if (!basenames.has(folded))
|
|
124
|
+
basenames.set(folded, row.name);
|
|
125
|
+
}
|
|
126
|
+
else if (row.kind === "segment") {
|
|
127
|
+
if (!segments.has(folded))
|
|
128
|
+
segments.set(folded, row.name);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
runs.push({ name: row.name, parts: folded.split("/").filter((s) => s.length > 0) });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
rows,
|
|
136
|
+
matchPath(path) {
|
|
137
|
+
const viewOf = (win32) => {
|
|
138
|
+
const segs = [];
|
|
139
|
+
for (const raw of path.split(/[\\/]/)) {
|
|
140
|
+
if (raw.length === 0)
|
|
141
|
+
continue;
|
|
142
|
+
const dot = !win32 || /^\.{1,2}$/.test(raw) ? raw : raw.replace(/ +$/, "");
|
|
143
|
+
if (dot === ".")
|
|
144
|
+
continue;
|
|
145
|
+
if (dot === "..") {
|
|
146
|
+
const last = segs[segs.length - 1];
|
|
147
|
+
if (segs.length > 0 && last !== "..")
|
|
148
|
+
segs.pop();
|
|
149
|
+
else
|
|
150
|
+
segs.push("..");
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const stripped = win32 ? raw.replace(/[. ]+$/, "") : raw;
|
|
154
|
+
segs.push(foldWriteProtectCase(stripped.length > 0 ? stripped : raw));
|
|
155
|
+
}
|
|
156
|
+
return segs;
|
|
157
|
+
};
|
|
158
|
+
const judge = (segs) => {
|
|
159
|
+
if (segs.length === 0)
|
|
160
|
+
return null;
|
|
161
|
+
const base = basenames.get(segs[segs.length - 1] ?? "");
|
|
162
|
+
if (base !== undefined)
|
|
163
|
+
return { name: base, kind: "basename" };
|
|
164
|
+
for (const s of segs) {
|
|
165
|
+
const hit = segments.get(s);
|
|
166
|
+
if (hit !== undefined)
|
|
167
|
+
return { name: hit, kind: "segment" };
|
|
168
|
+
}
|
|
169
|
+
for (const run of runs) {
|
|
170
|
+
const n = run.parts.length;
|
|
171
|
+
for (let i = 0; i + n <= segs.length; i++) {
|
|
172
|
+
if (run.parts.every((p, j) => segs[i + j] === p))
|
|
173
|
+
return { name: run.name, kind: "segment-run" };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
};
|
|
178
|
+
const posix = viewOf(false);
|
|
179
|
+
return judge(posix) ?? judge(viewOf(true));
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
export function createWriteProtectionCheck(entries) {
|
|
184
|
+
const matcher = compileWriteProtection(entries);
|
|
185
|
+
if (matcher === undefined)
|
|
186
|
+
return undefined;
|
|
187
|
+
return (toolName, args) => {
|
|
188
|
+
if (!PATH_CONFINABLE_WRITE_TOOLS.has(toolName))
|
|
189
|
+
return null;
|
|
190
|
+
const path = writeTargetPath(toolName, args);
|
|
191
|
+
if (typeof path !== "string" || path.length === 0)
|
|
192
|
+
return null;
|
|
193
|
+
return matcher.matchPath(path);
|
|
194
|
+
};
|
|
195
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -91,6 +91,7 @@ export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, ty
|
|
|
91
91
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
92
92
|
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, type ReadDenyEntry, type ReadDenyMatcher, type NormalizedReadDenyEntry, type ReadDenyBuiltinTier, type ReadDenyBuiltinRow, type ReadDenyBuiltinConfig, } from "./tools/fs/index.js";
|
|
93
93
|
export { deploymentReadFaceClampNotice, resolveReadFace, type ReadFace, type ReadFaceInputs } from "./tools/fs/index.js";
|
|
94
|
+
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, type WriteProtectedEntry, type WriteProtectedRow, type WriteProtectedKind, type WriteProtectedHit, type WriteProtectionMatcher, } from "./core/write-protect.js";
|
|
94
95
|
export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, type ToolResultProvenance, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, type ToolResultStore, type ToolResultSlice, type ToolResultDeletionReport, } from "./core/tool-result-store.js";
|
|
95
96
|
export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, type ActorAssertion, type PendingSteerEntry, type PendingSteerInput, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type ProbeCause, type ProbeCauseOperands, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type RealApprovalGateBit, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
|
|
96
97
|
export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, type UsageWindow, type UsageWindowStore, type UsageWindowReading, type UsageWindowRecord, type UsageSlot, type UsageBucketRow, } from "./core/usage-window-store.js";
|
|
@@ -114,7 +115,7 @@ export { type StoreDurability } from "./core/checkpoint-store.js";
|
|
|
114
115
|
export { type StoreFidelity } from "./core/checkpoint-store.js";
|
|
115
116
|
export { projectHumanInput, buildHumanInputEvent, type HumanInputSource, type HumanInputFrame, type HumanInputEvent, type HumanInputDelivery, } from "./core/human-input-projection.js";
|
|
116
117
|
export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, type SemaTaskType, type SemaTaskStatus, type SemaTaskHandle, type ParkedClaimTicket, type TaskAccess, type UnifiedTaskOutput, type TaskRetrievalStatus, type StopSource, type RegisterMonitorInput, type MonitorTimers, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
|
|
117
|
-
export { InMemoryMailboxStore, type MailboxStore, type MailboxMessage, type MailboxLease } from "./core/mailbox-store.js";
|
|
118
|
+
export { InMemoryMailboxStore, type MailboxStore, type MailboxMessage, type MailboxLease, MailboxStoreError, MAILBOX_TOMBSTONED_RECIPIENT_CODE, } from "./core/mailbox-store.js";
|
|
118
119
|
export { FileMailboxStore, type FileMailboxStoreOptions } from "./stores/file/mailbox-store.js";
|
|
119
120
|
export { createFileTaskListStore } from "./stores/file/task-list-store.js";
|
|
120
121
|
export { createCcFileTaskListStore } from "./stores/cc/task-list-store.js";
|
|
@@ -165,7 +166,7 @@ export { AdoptionError, assertAdoptionBootGate, readRootAdoptionFile, writeRootA
|
|
|
165
166
|
export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdoptionQuarantine, readAdoptionStatus, type AdoptionStatus, type AdoptLocalDataRootOptions, type AdoptLocalDataRootResult, type AdoptionCarriageLeg, type AdoptionCarriageLegContext, type AdoptionConfigWitnessReceipt, } from "./stores/file/adoption/adopt.js";
|
|
166
167
|
export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, type PersistedRuleHit, type PersistedRuleUnreadable, type PersistedRuleAnswer, normalizePersistedRuleHit, type Hooks, type HookToolContext, type HookInvocationIdentity, type UserPromptSubmitContext, type PostToolBatchContext, type HookEnvCapabilities, 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";
|
|
167
168
|
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";
|
|
168
|
-
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_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, readV2HeaderHints, type V2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type MemoryGetDetails, 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 EntryProvenanceAccount, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, 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";
|
|
169
|
+
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_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, readV2HeaderHints, type V2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type MemoryGetDetails, 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 EntryProvenanceAccount, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, computeMemoryBundleHash, type MemoryExportBundle, type MemoryImportReport, type MemoryExportSnapshot, type MemoryBundleImportPlan, type BundleChallengeRow, type BundleLineageRow, type BundlePollutedSession, 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";
|
|
169
170
|
export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, type SharedMemoryStoreProvider, type SharedMemoryStoreReader, type SharedMemoryPagedList, type SharedMemoryStoreInfo, type SharedMemoryDocumentEntry, type SharedMemorySnapshot, type SharedMemoryRequestContext, type MemoryListDetails, type MemoryReadDetails, } from "./core/shared-memory/types.js";
|
|
170
171
|
export { sharedMemoryStoreContract, type SharedMemoryFixture, type SharedMemoryStoreContractHooks, } from "./core/shared-memory/contract.js";
|
|
171
172
|
export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
|
|
@@ -217,7 +218,7 @@ export { sessionRepoContract } from "./core/store-contracts/session-repo-contrac
|
|
|
217
218
|
export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
|
|
218
219
|
export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
|
|
219
220
|
export { permissionRuleSyncContract, type PermissionRuleSyncContractHooks } from "./core/store-contracts/permission-rule-sync-contract.js";
|
|
220
|
-
export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
|
|
221
|
+
export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, type MailboxTombstonedRecipientContractHooks, } from "./core/store-contracts/mailbox-store-contract.js";
|
|
221
222
|
export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
|
|
222
223
|
export { type BackgroundAgentStore, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentUsage, canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, type BackgroundAgentQuery, } from "./core/background-agent-store.js";
|
|
223
224
|
export { serveDurableAgentRowLane, buildAgentPollDetails, type AgentPollDetailsInput, } from "./core/task-registry-agent.js";
|