@sema-agent/core 7.5.0 → 7.5.1

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/core/auto-mode.d.ts +9 -0
  3. package/dist/core/auto-mode.js +11 -0
  4. package/dist/core/checkpoint-store.js +5 -1
  5. package/dist/core/runner/checkpoint-scope.d.ts +32 -0
  6. package/dist/core/runner/checkpoint-scope.js +4 -0
  7. package/dist/core/runner/contracts.d.ts +1878 -0
  8. package/dist/core/runner/contracts.js +1 -0
  9. package/dist/core/runner/denial-limit-arms.d.ts +1 -1
  10. package/dist/core/runner/derived-route-fallback.d.ts +34 -0
  11. package/dist/core/runner/derived-route-fallback.js +16 -0
  12. package/dist/core/runner/prepare-acquire-reconcile.d.ts +1 -1
  13. package/dist/core/runner/prepare-caps-and-workflow.d.ts +170 -0
  14. package/dist/core/runner/prepare-caps-and-workflow.js +255 -0
  15. package/dist/core/runner/prepare-config-doors.d.ts +2 -10
  16. package/dist/core/runner/prepare-defer-classify.d.ts +86 -0
  17. package/dist/core/runner/prepare-defer-classify.js +107 -0
  18. package/dist/core/runner/prepare-delegation-surface.d.ts +104 -0
  19. package/dist/core/runner/prepare-delegation-surface.js +144 -0
  20. package/dist/core/runner/prepare-execution-env.d.ts +54 -0
  21. package/dist/core/runner/prepare-execution-env.js +86 -0
  22. package/dist/core/runner/prepare-file-history.d.ts +95 -0
  23. package/dist/core/runner/prepare-file-history.js +383 -0
  24. package/dist/core/runner/prepare-hands-readface.d.ts +5 -7
  25. package/dist/core/runner/prepare-hands-readface.js +1 -1
  26. package/dist/core/runner/prepare-inherited-gate.d.ts +268 -0
  27. package/dist/core/runner/prepare-inherited-gate.js +266 -0
  28. package/dist/core/runner/prepare-listings.d.ts +77 -0
  29. package/dist/core/runner/prepare-listings.js +76 -0
  30. package/dist/core/runner/prepare-lsp.d.ts +55 -0
  31. package/dist/core/runner/prepare-lsp.js +27 -0
  32. package/dist/core/runner/prepare-memory.d.ts +1 -1
  33. package/dist/core/runner/prepare-offload-wrappers.d.ts +62 -0
  34. package/dist/core/runner/prepare-offload-wrappers.js +45 -0
  35. package/dist/core/runner/prepare-project-context.d.ts +131 -0
  36. package/dist/core/runner/prepare-project-context.js +150 -0
  37. package/dist/core/runner/prepare-prompt-inputs.d.ts +138 -0
  38. package/dist/core/runner/prepare-prompt-inputs.js +141 -0
  39. package/dist/core/runner/prepare-protocol-tools.d.ts +91 -0
  40. package/dist/core/runner/prepare-protocol-tools.js +182 -0
  41. package/dist/core/runner/prepare-question-face.d.ts +119 -0
  42. package/dist/core/runner/prepare-question-face.js +83 -0
  43. package/dist/core/runner/prepare-run-refs.d.ts +89 -0
  44. package/dist/core/runner/prepare-run-refs.js +39 -0
  45. package/dist/core/runner/prepare-safety-scan.d.ts +3 -2
  46. package/dist/core/runner/prepare-task.d.ts +11 -1846
  47. package/dist/core/runner/prepare-task.js +83 -2366
  48. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +111 -0
  49. package/dist/core/runner/prepare-tool-disclosure-mount.js +219 -0
  50. package/dist/core/runner/prepare-wiring-manifest.d.ts +184 -0
  51. package/dist/core/runner/prepare-wiring-manifest.js +240 -0
  52. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -27
  53. package/dist/core/runner/prepare-workspace-restore.js +1 -22
  54. package/dist/core/runner/rollback-stack.d.ts +32 -0
  55. package/dist/core/runner/rollback-stack.js +30 -0
  56. package/dist/core/runner/workspace-path.d.ts +33 -0
  57. package/dist/core/runner/workspace-path.js +22 -0
  58. package/dist/core/tool-policy.d.ts +16 -0
  59. package/dist/core/tool-policy.js +3 -0
  60. package/dist/core/types.d.ts +2 -2
  61. package/dist/core/write-protect.js +3 -2
  62. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.5.1 — 2026-09-06
4
+
5
+ Maintenance release: the design/390 runner decomposition (slices S0–S2), the post-7.5.0 gate repairs, and one summary hardening (#566). **No BREAKING change**: the export surface is byte-identical to 7.5.0 (export snapshot unchanged); the only observable delta is the label text of a wedged dispose on the prepare-throw path (below).
6
+
7
+ ### Changed — design/390 S0–S2: `prepareTask` decomposed into phase modules (14 229 → 7 723 lines), one contract each
8
+ - 24 phase modules under `src/core/runner/prepare-*.ts`, each `prepareX(input: Input): Result` with every Input seat classified (owned / borrowed-readonly / borrowed-mutable + writer table / ownership-ref) and the driver reduced to one destructuring call per phase. Extracted verbatim: offload wrappers, execution-env (`OwnedEnvSeat`), file-history, run-refs, protocol-tools (MCP/A2A), question-face, LSP, project-context, prompt-inputs, defer-classify, listings, inherited-gate, caps-and-workflow, delegation-surface, tool-disclosure-mount, wiring-manifest; helpers `contracts.ts`, `workspace-path.ts`, `derived-route-fallback.ts`, `checkpoint-scope.ts`, `denial-limit-arms.ts`.
9
+ - **RollbackStack** (`rollback-stack.ts`): every resource acquired during prepare registers its disposer the moment it is acquired (env, MCP clients, A2A peers); a prepare throw unwinds them in reverse order, each bounded and reported, replacing the driver's explicit `if (handle) dispose` catch legs. The A2A registration keys on the acquisition decision read ONCE (a caller replacing `spec.a2a` during materialization can no longer unregister an acquired handle).
10
+ - **Disclosed delta**: a dispose that hangs past its budget on the prepare-throw path now reports leg `"<disposer> (rollback leg N of M, prepare-throw)"` (e.g. `mcpDispose (rollback leg 2 of 3, prepare-throw)`) instead of `"mcp.dispose (prepare-throw leg)"` / `"a2a.dispose (prepare-throw leg)"` / `"ownedEnv.destroy (prepare-throw leg)"`. Error class and budget unchanged; no test or consumer referenced the old text.
11
+ - Contract sentence `@contract prepare.deps-read-stable`: the host keeps `deps` / `internals` / `executionEnv` read-stable for the duration of `prepareTask`; an async phase returning a microtask later than the inlined code is within contract.
12
+ - Roster mutation owner table: which phase pushes/splices which tool under which condition is written once on `Prepared.tools` (contracts.ts), not scattered in prose.
13
+ - `isLiveApproverSeat` consumers (3) now read the one predicate in `tool-policy.ts`.
14
+
15
+ ### Fixed
16
+ - #566 `CheckpointSummary.denialLimitFallback` is produced by `readDenialLimitFallback` (the same reader the park row and `AskRequest` use): exactly the four typed members when the row's value is well-formed, no key otherwise — a hand-edited or partial value is dropped, never echoed.
17
+ - Wire-change generator: inherited keys are keys the type HAS — `readTreeModel` folds an interface's `extends` / intersection bases, so moving members onto a base interface no longer reports a false "lost keys" BREAKING item (the two false items in `wire-changes/core@7.5.0.json` are left as published and noted there).
18
+ - `gate:message-branching` (the mcp.ts `transport.kind` fold's five sites are the ONE reader, exemption count corrected) and `gate:domain-lexicon` (UNC anchor test written with `isUncPath`) — two CI-only gates that had been red since the A-089 merge without the local chain running them.
19
+ - Two load-sensitive pins (#583) measure by best-of-three / a generous spawn timeout instead of a single wall-clock reading.
20
+
21
+ ### Tooling / gates
22
+ - `node scripts/gate-all.mjs [--with-dist] [--rc]` runs the whole `gate:*` roster in one command; a `gate:*` script without a roster seat fails `test/gate-all-roster.test.ts` (the release chain's L3 line now points here).
23
+ - New gates: **G1** module line-count ratchet (`test/module-size-ratchet.test.ts`, banked per extraction), **G2** dependency-direction gate (`scripts/verify-layering.mjs` + `docs/LAYERING.json`, four layers: contracts ← prepare-path machinery ← phases ← orchestrator ← runtask; exemptions 13 → 3), **G5** phase-contract gate (`scripts/verify-phase-api.mjs`: every `prepare-*.ts` exports one Input/Result pair, every Input field classified; `KNOWN_INPUT_FIELDS` anti-blindness floor 371), `gate:agent-returns` (every archived car receipt's unresolved line carries a ticket / DEBTS id / DV / slice home).
24
+ - Release criteria: `retiredIn` annotation lets a historic criteria file name a face that a later version removed without rewriting history (`criteria-lint` accepts an absent face carrying the annotation).
25
+ - 16 runtime exports added in 7.5.0 registered in the consumer smoke probe; `test/prepare-lsp-ignore-filter.test.ts` pins the LSP tool's git-ignore wiring (a receiving-side mutation had left every LSP test green).
26
+
3
27
  ## 7.5.0 — 2026-09-05
4
28
 
5
29
  **BREAKING release** (the 7.4.1 bug batch merged into it — one publish, one pickup). 13 exports removed, 5 public types lose keys, one store contract replaced whole; every item is named below with its replacement. Nothing here is a wire FRAME change: `TaskEvent`, `PendingAction`, `CheckpointSummary`, `WiringManifest` only GAIN keys.
@@ -169,6 +169,15 @@ export interface DenialLimitFallback extends DenialLimitCounts {
169
169
  * which is a break with nothing behind it (the routing invariant constrains where a window is WRITTEN,
170
170
  * never who may read one). */
171
171
  export type DenialLimitFallbackFace = UnarmedDenialLimitFallback | DenialLimitFallback;
172
+ /**
173
+ * A stored or foreign value read back AS a fallback member, or `undefined` when it is not one: exactly
174
+ * the four members, each of the right kind (finite non-negative counts, the closed `limit` word, a
175
+ * finite non-negative window), nothing else carried. A deployment-written row (a checkpoint store is a
176
+ * host's) can hold any shape; the faces that echo it (the inbox summary) read through here, so a bad
177
+ * shape reads as ABSENT rather than reaching a consumer as a malformed card. Not a parser of intent —
178
+ * `"3"` is not 3.
179
+ */
180
+ export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
172
181
  /** The window-less route's member, spelled in ONE place: every station that hands a fallback somewhere
173
182
  * nothing can count down (a durable park row, a headless deny, a string `onAsk` seat, a member this
174
183
  * run's tracker did not mint) passes through here rather than writing a `0` of its own. */
@@ -99,6 +99,17 @@ class AutoModeTimeout extends Error {
99
99
  super("auto-mode classify timeout");
100
100
  }
101
101
  }
102
+ export function readDenialLimitFallback(v) {
103
+ if (typeof v !== "object" || v === null)
104
+ return undefined;
105
+ const o = v;
106
+ const count = (x) => typeof x === "number" && Number.isFinite(x) && x >= 0;
107
+ if (!count(o["consecutive"]) || !count(o["total"]) || !count(o["autoDenyAfterMs"]))
108
+ return undefined;
109
+ if (o["limit"] !== "consecutive" && o["limit"] !== "total")
110
+ return undefined;
111
+ return { consecutive: o["consecutive"], total: o["total"], limit: o["limit"], autoDenyAfterMs: o["autoDenyAfterMs"] };
112
+ }
102
113
  export function unarmedWindow(fallback) {
103
114
  return { ...countsOf(fallback), autoDenyAfterMs: 0 };
104
115
  }
@@ -2,6 +2,7 @@ import { randomBytes, randomUUID } from "node:crypto";
2
2
  import { uuidv7 } from "../internal/harness.js";
3
3
  import { PROBE_CAUSE_PATH_MAX, inlineUntrusted, sanitizeUntrustedText } from "./untrusted-text.js";
4
4
  import { carriesBidiControls } from "./tool-policy.js";
5
+ import { readDenialLimitFallback } from "./auto-mode.js";
5
6
  import { isAskOrigin } from "./ask-origin.js";
6
7
  import { renderUntrustedCommandText, stripFormatCharacters } from "./permission-rule-model.js";
7
8
  import { redactSecrets } from "./untrusted-egress.js";
@@ -264,7 +265,10 @@ export function summarizeCheckpoint(cp) {
264
265
  ...(tool?.preview !== undefined ? { preview: tool.preview } : {}),
265
266
  ...(tool?.previewWithheld === "oversize" || tool?.previewWithheld === "unavailable" ? { previewWithheld: tool.previewWithheld } : {}),
266
267
  ...(tool?.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
267
- ...(tool?.denialLimitFallback !== undefined ? { denialLimitFallback: { ...tool.denialLimitFallback } } : {}),
268
+ ...(() => {
269
+ const fb = readDenialLimitFallback(tool?.denialLimitFallback);
270
+ return fb !== undefined ? { denialLimitFallback: fb } : {};
271
+ })(),
268
272
  ...(tool !== undefined && isAskOrigin(tool.origin) ? { origin: tool.origin } : {}),
269
273
  ...(hasBidi ? { hasBidiControls: true } : {}),
270
274
  };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The durable-suspend checkpoint SCOPE vocabulary — the default isolation scope and the ONE derivation of a row's scope —
3
+ * moved whole out of the orchestrator so the wiring-manifest phase (the synthesized durableApproval) and the driver's
4
+ * park-lane mint sites reach DOWN for the same two names. Pure: a constant and a string function over two spec fields.
5
+ */
6
+ /** design/77 §4.4: the multi-tenant scope used when a durable suspend fires for an IRREVERSIBLE tool in an
7
+ * unattended deployment that did NOT opt into `durableApproval` (so there is no caller-supplied scope). The
8
+ * checkpoint carries this scope; resume reads it back from the checkpoint (`cp.scope`), so it is
9
+ * self-consistent without needing the original `TaskSpec`. Kept distinct from any tenant key to make an
10
+ * unattended irreversible suspend auditable as such. */
11
+ export declare const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
12
+ /**
13
+ * design/153 §7.1 — the SINGLE derivation of a durable-suspend checkpoint's scope (both gate mint
14
+ * sites + the bg-watcher park lane's expire compensation/arbitration consume THIS; a re-derived copy
15
+ * that drifted was the exact bug the park tests caught — expire against the wrong scope silently
16
+ * no-ops). `|| DEFAULT` (not `??`): an EMPTY-string principal must not become a shared scope bucket.
17
+ *
18
+ * RB-75 (2026-07-25, red probe): that rule is stated twice in this file and was enforced on ONE of the two
19
+ * inputs — the principal half used `||`, the `durableApproval.scope` half used `??`, so an empty string
20
+ * arriving through the scope field (a config-centre / env lookup that came back blank is the realistic
21
+ * source) sailed through as the literal scope `""`. Two different tenants both landed in that one bucket,
22
+ * where `listByScope("")` reads BOTH their pending approvals — including each summary's `toolInput`
23
+ * preview of the raw arguments — and `reap("")` / `resolve(token, "")` act across both. `durableApproval.
24
+ * scope` is documented as "Multi-tenant isolation key … Required"; a blank string is the absence of an
25
+ * isolation key wearing its clothes, so both halves now fall through to the default isolation scope.
26
+ */
27
+ export declare function checkpointScopeOf(spec: {
28
+ durableApproval?: {
29
+ scope?: string;
30
+ };
31
+ principal?: string;
32
+ }): string;
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
2
+ export function checkpointScopeOf(spec) {
3
+ return spec.durableApproval?.scope || spec.principal || DEFAULT_IRREVERSIBLE_SCOPE;
4
+ }