@sema-agent/core 5.39.0 → 5.41.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 +150 -11
- package/dist/core/auto-mode-prompt.js +1 -1
- package/dist/core/checkpoint-store.d.ts +12 -0
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.js +9 -1
- 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 +648 -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 +99 -1
- package/dist/core/memory-engine/layout.js +143 -7
- 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.js +14 -2
- package/dist/core/runner/prepare-config-doors.js +20 -0
- package/dist/core/runner/prepare-task.js +13 -0
- package/dist/core/runner/runtask.js +14 -1
- package/dist/core/runner/synthetic-tools.js +3 -1
- package/dist/core/runner/tool-disclosure.js +2 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/core/write-protect.d.ts +0 -20
- package/dist/core/write-protect.js +4 -3
- package/dist/engine/harness/agent-harness.d.ts +17 -0
- package/dist/engine/harness/agent-harness.js +19 -1
- package/dist/engine/harness/types.d.ts +5 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tools/fs/safety.d.ts +1 -1
- package/dist/tools/fs/safety.js +1 -1
- 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 +9 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { scopeDirName, type MemoryPartitionIncidentSink } from "./layout.js";
|
|
1
|
+
import { scopeDirName, type ChallengeEvent, type MemoryPartitionIncidentSink } from "./layout.js";
|
|
2
|
+
import type { MemoryBundleImportPlan, MemoryImportReport } from "./export-bundle.js";
|
|
2
3
|
import type { HarvestRejection, MemoryBackend, MemoryEntry, MemoryEntryHeader, NotePatch, PatchReport, ScoredMemoryEntry } from "./types.js";
|
|
3
4
|
/** Files/dirs the entry scan never treats as entries: the derived index, dotfiles (`.hydrate`,
|
|
4
5
|
* transaction staging files), and anything not `.md`. */
|
|
@@ -288,6 +289,55 @@ export interface EntryCustodyReport {
|
|
|
288
289
|
events: TransferEvidence[];
|
|
289
290
|
reason?: string;
|
|
290
291
|
}
|
|
292
|
+
/**
|
|
293
|
+
* design/178 v2-c §3 — what the ONE-LOCK export composite ({@link FileMemoryEngineBackend.exportSnapshotOf})
|
|
294
|
+
* answers: every face of the store the bundle needs, read inside a single txn-mutex hold (see the
|
|
295
|
+
* method doc for the fence law). Entries carry committed content only; a bound row whose committed
|
|
296
|
+
* carrier cannot be served is enumerated under `contentUnavailable` instead (never silently
|
|
297
|
+
* dropped, never dressed as content). `unbound`/`pendingLatch` are STORE-LEVEL residual sets (no
|
|
298
|
+
* tenant to belong to); the bundle assembly decides whether their id lists travel (full-store
|
|
299
|
+
* export) or only their counts (subset export). `challenges`/`lineage`/`pollutedSessions` are the
|
|
300
|
+
* RAW governance faces — the (pure) bundle assembly slices them to the exported entry/session
|
|
301
|
+
* sets; `custody` is already sliced (the slicing consumes row-level scope fields this module owns).
|
|
302
|
+
*/
|
|
303
|
+
export interface MemoryExportSnapshot {
|
|
304
|
+
storeId: string;
|
|
305
|
+
/** True ⇔ the requested scopes cover every registered scope (one trust domain — the residual id
|
|
306
|
+
* lists and unbound-deletion custody rows may travel). */
|
|
307
|
+
fullStore: boolean;
|
|
308
|
+
entries: MemoryEntry[];
|
|
309
|
+
contentUnavailable: Array<{
|
|
310
|
+
id: string;
|
|
311
|
+
scope: string;
|
|
312
|
+
slug: string;
|
|
313
|
+
rev: string;
|
|
314
|
+
reason: string;
|
|
315
|
+
}>;
|
|
316
|
+
unbound: string[];
|
|
317
|
+
pendingLatch: string[];
|
|
318
|
+
custody: TransferEvidence[];
|
|
319
|
+
unsliceableCustody: number;
|
|
320
|
+
challenges: ChallengeEvent[];
|
|
321
|
+
lineage: Array<{
|
|
322
|
+
entryId: string;
|
|
323
|
+
sessionId: string;
|
|
324
|
+
lastRev: string;
|
|
325
|
+
lastAt: number;
|
|
326
|
+
}>;
|
|
327
|
+
pollutedSessions: Array<{
|
|
328
|
+
sessionId: string;
|
|
329
|
+
at: number;
|
|
330
|
+
reason: string;
|
|
331
|
+
}>;
|
|
332
|
+
quarantined: string[];
|
|
333
|
+
quarantineOpaque: number;
|
|
334
|
+
}
|
|
335
|
+
/** Test hook (证伪式复审 L3): small constants so the crash-window leg does not really wait 15-30s. */
|
|
336
|
+
interface TxnLockTimings {
|
|
337
|
+
staleMs?: number;
|
|
338
|
+
waitMs?: number;
|
|
339
|
+
stealGraceMs?: number;
|
|
340
|
+
}
|
|
291
341
|
/** Construction options for {@link FileMemoryEngineBackend}. */
|
|
292
342
|
export interface FileMemoryEngineBackendOptions {
|
|
293
343
|
/** ⚠️ 分家坑(service 报告 2026-07-09):不显式传时,控制平面按无参 `resolveMemoryEngineRoot()`
|
|
@@ -369,6 +419,10 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
|
|
|
369
419
|
private adoptionNoticeKeys;
|
|
370
420
|
/** Test seam (§7.4 r4-④ arm): force a post-commit-point transfer-append failure. */
|
|
371
421
|
private transfersAppendFault?;
|
|
422
|
+
/** Test seam (v2-c §3-2 fence pins): runs INSIDE the export composite's mutex hold, after the
|
|
423
|
+
* data reads and before the second fingerprint — a test injects a governance-face write here to
|
|
424
|
+
* exercise the drift-retry and the three-round refusal. Production leaves it unset. */
|
|
425
|
+
private exportFaceProbe?;
|
|
372
426
|
/** v2-b §3-4 — the resurrection backstop's chain digest, keyed by the evidence log's stat
|
|
373
427
|
* fingerprint (size + mtimeMs — append-only growth and a torn-tail shrink both move `size`).
|
|
374
428
|
* NEVER a mount-lifetime cache: the fingerprint is re-verified under the txn mutex on every
|
|
@@ -972,6 +1026,129 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
|
|
|
972
1026
|
/** The pure open-form evidence read behind {@link custodyOf} (no healing, no writes). `raw` is
|
|
973
1027
|
* the caller's already-fenced read of the log (undefined = absent). */
|
|
974
1028
|
private custodyReadPure;
|
|
1029
|
+
/** design/178 v2-c §4 — the export/import refusal code (engine coded-error family, deliberately
|
|
1030
|
+
* outside the governance registry: a store-state refusal, not a per-principal verdict). */
|
|
1031
|
+
private static readonly EXPORT_INCOMPLETE;
|
|
1032
|
+
/** The durable store identity (§6.2): read it, or mint it (`wx`) on first need — the txn mutex is
|
|
1033
|
+
* held by every caller, so the exclusive create cannot race in-process; a cross-process EEXIST
|
|
1034
|
+
* loser adopts the winner's identity. Corrupt/unreadable identity is fail-closed. */
|
|
1035
|
+
private storeIdentityLocked;
|
|
1036
|
+
/** One consistency fingerprint over the three ENGINE governance faces (challenge ledger, lineage
|
|
1037
|
+
* ledger, pollution markers) — raw bytes, journal included. The two strict sidecars' JOURNAL
|
|
1038
|
+
* reads are wrapped FAIL-CLOSED here (§4-6): the shared strict reader folds a journal read
|
|
1039
|
+
* error into absence, and an export that read a stale main file over an unreadable journal
|
|
1040
|
+
* would seal stale governance under an honest hash. Marker files that exist but cannot be read
|
|
1041
|
+
* fingerprint their error code (a stable fault stays stable; a flapping one drifts the fence). */
|
|
1042
|
+
private exportGovernanceFingerprint;
|
|
1043
|
+
/**
|
|
1044
|
+
* The export chain read: PURE INSPECTION (never heals, never quarantines, never truncates — C-8
|
|
1045
|
+
* pins the file byte-identical across a refused export). A torn tail refuses the export
|
|
1046
|
+
* (`memory.export_incomplete`; the deployment heals it by running any locked mutation entry,
|
|
1047
|
+
* then re-exports); an unknown channel refuses too (T-14: a row whose slicing rules this build
|
|
1048
|
+
* does not know can neither be carried — possible cross-tenant leak — nor silently dropped —
|
|
1049
|
+
* lost mandatory governance); one ev under two different payloads refuses (spliced chain);
|
|
1050
|
+
* non-tail corruption stays the fail-closed {@link ControlPlaneCorruptError}. Byte-equal
|
|
1051
|
+
* duplicates collapse (append-idempotency residue).
|
|
1052
|
+
*/
|
|
1053
|
+
private readExportChainRowsPure;
|
|
1054
|
+
/**
|
|
1055
|
+
* v2-c §2 — the tenant-slicing table over validated chain rows (T-6..T-11; T-9/T-10 refusals,
|
|
1056
|
+
* T-14 already refused by the reader). `storeId` is a thunk so the identity mints only when a
|
|
1057
|
+
* redaction actually needs the provenance stamp.
|
|
1058
|
+
*/
|
|
1059
|
+
private sliceCustodyForScopes;
|
|
1060
|
+
/** T-12 — quarantine residual enumeration for an id set (names for attributable hits, an opaque
|
|
1061
|
+
* count for the rest — same honest bound the erasure attestation uses). */
|
|
1062
|
+
private enumerateQuarantineFor;
|
|
1063
|
+
/**
|
|
1064
|
+
* design/178 v2-c §3 — the ONE-LOCK export composite (capability face; probe with
|
|
1065
|
+
* `typeof backend.exportSnapshotOf === "function"`). All five reads — entries (ledger-driven,
|
|
1066
|
+
* committed content), custody chain, challenge ledger, lineage ledger, pollution markers — happen
|
|
1067
|
+
* inside a single txn-mutex hold: the two backend faces are writer-serialized by the mutex
|
|
1068
|
+
* itself; the three engine faces (written under their own sidecar locks, not the mutex) are
|
|
1069
|
+
* fenced by a byte-level double fingerprint around the reads (≤3 rounds, then a loud refusal —
|
|
1070
|
+
* a store too hot to snapshot answers `memory.export_incomplete`, never a mixed-epoch bundle).
|
|
1071
|
+
* The terminal ownership assertion turns a stolen lock (stale-steal past the 30s line during a
|
|
1072
|
+
* long assembly) into a refusal: an unstolen lock means no writer entered, which IS the
|
|
1073
|
+
* consistency proof — no lease machinery needed. The chain read is pure inspection (a torn tail
|
|
1074
|
+
* refuses with the file byte-untouched); `complete:false`-class scenes all refuse loudly — there
|
|
1075
|
+
* is no degraded bundle shape, by design (§4).
|
|
1076
|
+
*/
|
|
1077
|
+
exportSnapshotOf(scopes: readonly string[], timings?: TxnLockTimings): Promise<MemoryExportSnapshot>;
|
|
1078
|
+
/**
|
|
1079
|
+
* design/178 v2 §4.3 — the single-item governance slice face (parent-design form, kept for
|
|
1080
|
+
* NON-export consumers: erasure resolution, per-id inspection tooling). Answers
|
|
1081
|
+
* `complete: false` + reason instead of a bundle-shaped refusal (its callers fail closed on the
|
|
1082
|
+
* flag); definite corruption still throws. The export path deliberately does NOT use this face —
|
|
1083
|
+
* two independently-locked single faces are exactly the cross-face tear the composite closes.
|
|
1084
|
+
*/
|
|
1085
|
+
governanceExport(scopes: readonly string[], timings?: TxnLockTimings): Promise<{
|
|
1086
|
+
custody: TransferEvidence[];
|
|
1087
|
+
unbound: string[];
|
|
1088
|
+
complete: boolean;
|
|
1089
|
+
unsliceableCustody: number;
|
|
1090
|
+
reason?: string;
|
|
1091
|
+
}>;
|
|
1092
|
+
/**
|
|
1093
|
+
* design/178 v2-c §5.4 — custody carriage onto THIS chain (capability face). Rows land under the
|
|
1094
|
+
* import namespace — `ev = imp:<bundleHash>:<source ev>` (full-hash salt: deterministic per
|
|
1095
|
+
* bundle, chain-deterministic across hops — a re-exported imported row salts its CURRENT ev
|
|
1096
|
+
* next hop), `origin` kept when present (multi-hop provenance) else stamped with the source
|
|
1097
|
+
* store's identity, `srcEv` kept else stamped with the source ev — so an imported row is ALWAYS
|
|
1098
|
+
* origin-bearing and the local replay/anchor judgments structurally never read it. Unknown
|
|
1099
|
+
* channels and rows failing this store's own validation are WITHHELD and reported (never
|
|
1100
|
+
* appended verbatim — an unvalidatable row would poison the fail-closed chain — and never a
|
|
1101
|
+
* whole-package refusal — a newer exporter must not brick an older importer). Appends are
|
|
1102
|
+
* idempotent by ev with canonical-payload comparison (same-bundle re-import converges; a
|
|
1103
|
+
* different payload under an existing ev is fail-closed corruption). Direct chain append, no
|
|
1104
|
+
* journal: custody carriage is not a ledger mutation, and origin-bearing rows are forbidden in
|
|
1105
|
+
* journals by the recovery leg's own validation.
|
|
1106
|
+
*/
|
|
1107
|
+
custodyImport(rows: ReadonlyArray<Record<string, unknown>>, opts: {
|
|
1108
|
+
bundleHash: string;
|
|
1109
|
+
sourceStoreId: string;
|
|
1110
|
+
}, timings?: TxnLockTimings): Promise<{
|
|
1111
|
+
appended: number;
|
|
1112
|
+
withheld: Array<{
|
|
1113
|
+
srcEv: string;
|
|
1114
|
+
channel: string;
|
|
1115
|
+
}>;
|
|
1116
|
+
}>;
|
|
1117
|
+
/** The in-lock custody carriage body ({@link custodyImport}'s and the import composite's shared
|
|
1118
|
+
* leg — the composite already holds the mutex and must not re-enter the acquisition). */
|
|
1119
|
+
private custodyImportLocked;
|
|
1120
|
+
/** Append import-namespace challenge events and VERIFY every key-idempotent replay by reading
|
|
1121
|
+
* the full payload back (§5.2 defense ③): `appendChallengeEvents` is key-idempotent, not
|
|
1122
|
+
* payload-idempotent — a pre-planted same-key event (a resolve, or a same-entry different-
|
|
1123
|
+
* reason challenge) would silently swallow the imported challenge while the return echoes a
|
|
1124
|
+
* plausible assignment. A mismatch ABORTS the import (the latch stays; the account is not
|
|
1125
|
+
* silently short). */
|
|
1126
|
+
private appendImportChallengesVerified;
|
|
1127
|
+
/**
|
|
1128
|
+
* design/178 v2-c §1 — the IMPORT COMPOSITE (capability face; the engine's `importMemoryBundle`
|
|
1129
|
+
* is its validating membrane). One txn-mutex hold end to end:
|
|
1130
|
+
* ①b destination-chain completeness precheck (torn/degraded ⇒ whole package refused with ZERO
|
|
1131
|
+
* side effects — before the latch, "reject before landing" made literal);
|
|
1132
|
+
* ② the synthetic latch (durable pending lineage txn over every bundle entry id — from here
|
|
1133
|
+
* to release, those ids are withheld on every model-visible read face; crash-safe);
|
|
1134
|
+
* ③ authoritative in-lock judgment (the five import rules — a pre-lock classification would
|
|
1135
|
+
* only be advisory, so there is none: the lock-held pass IS the classification);
|
|
1136
|
+
* ④ entry landing through {@link applyPatchesLocked} (same skeleton, same lock, same recovery
|
|
1137
|
+
* leg — never a second transaction protocol; `guard:"absent"` adjudicates the residual
|
|
1138
|
+
* same-id arms);
|
|
1139
|
+
* ⑤ governance legs, custody FIRST unconditionally (chain facts are exempt from the
|
|
1140
|
+
* entry-eligibility rule — an absent-id delete row is exactly the anti-resurrection
|
|
1141
|
+
* payload), then entry-attached lineage/challenges for landed ∪ already-present ids only,
|
|
1142
|
+
* then pollution (retroactive sweep DURABLE BEFORE the marker — the crash between them
|
|
1143
|
+
* leaves contributions challenged and the marker converging on re-import, never the
|
|
1144
|
+
* reverse);
|
|
1145
|
+
* ⑥ the durable completion receipt (`wx`, carrying the report) and the latch release —
|
|
1146
|
+
* receipt-gated, the ONLY release channel.
|
|
1147
|
+
* Any failure past ② leaves the latch standing: re-importing the SAME bundle converges every
|
|
1148
|
+
* crash window (idempotent latch, idempotent judgments, ev/key-idempotent governance legs,
|
|
1149
|
+
* receipt short-circuit).
|
|
1150
|
+
*/
|
|
1151
|
+
importBundleCommit(plan: MemoryBundleImportPlan, timings?: TxnLockTimings): Promise<MemoryImportReport>;
|
|
975
1152
|
getConsolidationCursor(scope: string): Promise<string | undefined>;
|
|
976
1153
|
setConsolidationCursor(scope: string, cursor: string): Promise<void>;
|
|
977
1154
|
private readCursors;
|