@sema-agent/core 7.53.0 → 7.54.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.
- package/CHANGELOG.md +291 -1
- package/LICENSE +3 -1
- package/dist/agents/peer-session-drain.d.ts +0 -1
- package/dist/agents/peer-session-drain.js +0 -2
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +3 -5
- package/dist/agents/subagent.js +18 -11
- package/dist/agents/tool-filter.d.ts +7 -4
- package/dist/agents/tool-filter.js +7 -3
- package/dist/core/a2a.js +4 -2
- package/dist/core/allow-entry.d.ts +1 -0
- package/dist/core/allow-entry.js +1 -0
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +49 -50
- package/dist/core/auto-compaction.js +41 -51
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +33 -18
- package/dist/core/checkpoint-store.js +5 -4
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +3 -0
- package/dist/core/effective-path-target.js +4 -0
- package/dist/core/engine-notice.d.ts +34 -2
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +10 -2
- package/dist/core/gate-lanes.js +30 -21
- package/dist/core/gate-outcome.d.ts +7 -3
- package/dist/core/governance-codes.d.ts +7 -2
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +14 -14
- package/dist/core/hooks.js +1 -2
- package/dist/core/locked-config.d.ts +28 -1
- package/dist/core/locked-config.js +30 -3
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-server-spec.d.ts +66 -9
- package/dist/core/mcp-server-spec.js +52 -19
- package/dist/core/mcp.js +5 -4
- package/dist/core/memory-engine/engine.js +2 -1
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +13 -8
- package/dist/core/mode-policy.js +3 -2
- package/dist/core/mods/kernel/receive.d.ts +2 -1
- package/dist/core/mods/kernel/receive.js +7 -2
- package/dist/core/parent-spec-seat.d.ts +10 -13
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +29 -6
- package/dist/core/permission-rule-model.js +6 -1
- package/dist/core/permission-rule-org.d.ts +37 -0
- package/dist/core/permission-rule-org.js +34 -42
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +33 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +75 -33
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/person-path-rows.d.ts +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +7 -9
- package/dist/core/runner/prepare-acquire-reconcile.js +8 -6
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +12 -15
- package/dist/core/runner/prepare-config-doors.js +8 -3
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
- package/dist/core/runner/prepare-delegation-surface.js +2 -3
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +2 -2
- package/dist/core/runner/prepare-hands-readface.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.js +2 -7
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +13 -10
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
- package/dist/core/runner/prepare-wiring-manifest.js +2 -2
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.js +9 -9
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/run-leg.js +57 -33
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +15 -4
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +9 -9
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +683 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +6 -4
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +6 -6
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +64 -23
- package/dist/core/tool-policy.js +62 -56
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +7 -0
- package/dist/core/untrusted-text.js +3 -8
- package/dist/core/user-attachment.d.ts +43 -0
- package/dist/core/user-attachment.js +92 -15
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/types.d.ts +7 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/session/parent-chain-guard.d.ts +10 -0
- package/dist/engine/session/parent-chain-guard.js +10 -0
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +5 -2
- package/dist/index.d.ts +23 -9
- package/dist/index.js +19 -8
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/catalog/schema.d.ts +3 -0
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/overlay.js +2 -2
- package/dist/prompt-assembly/select.js +2 -2
- package/dist/prompts/default.d.ts +1 -1
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/tools/artifact/artifact-tool.js +10 -0
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5654 -5520
- package/wire-changes/core@7.53.0.json +30 -8
- package/wire-changes/core@7.54.0.json +2870 -0
- package/wire-changes/core@7.54.1.json +37 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { GateOutcome, HostDecisionFacts } from "./gate-outcome.js";
|
|
2
2
|
import { type ExecutionOutcomeRecordWord } from "./checkpoint-execution-record.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type CheckpointPause } from "./pause-registry.js";
|
|
4
4
|
import type { SystemInjectionPriority } from "./task-notification.js";
|
|
5
5
|
import { type SteerReplayFacet } from "./steer-replay.js";
|
|
6
6
|
import type { QuestionAnswer } from "./ask-question.js";
|
|
@@ -581,6 +581,16 @@ export type ResumeOutcome = {
|
|
|
581
581
|
updatedInput?: unknown;
|
|
582
582
|
/** Model-readable reason attached to a `deny` (else a default is used). */
|
|
583
583
|
reason?: string;
|
|
584
|
+
/**
|
|
585
|
+
* What the approving PERSON wrote in the card's "and tell the agent what to do next" input — the `allow`
|
|
586
|
+
* arm's counterpart of a `deny`'s {@link reason}. The resumed run's continuation user message carries it to
|
|
587
|
+
* the model as the user's own words, after the batch's tool results, once, verbatim apart from the outer
|
|
588
|
+
* whitespace: no fence, no wrapper sentence, no length bound. PRESENT only when the person wrote something
|
|
589
|
+
* (blank — empty or whitespace-only — delivers nothing; a host whose card has no input omits the key).
|
|
590
|
+
* ARM- AND DECIDER-SCOPED like `answer`: a written value on a `deny` or on a decide whose `hostDecision.decidedBy`
|
|
591
|
+
* is not `"person"`, a non-string, or text carrying a `<system-reminder>` tag (opening or closing) is refused pre-CAS.
|
|
592
|
+
*/
|
|
593
|
+
feedback?: string;
|
|
584
594
|
/**
|
|
585
595
|
* The ANSWER to a CONTENT-ASK (the reserved AskUserQuestion tool), carried by the decide itself
|
|
586
596
|
* (ruled 2026-08-04). A content-ask is a question TO the user: `allow` alone says "let the tool
|
|
@@ -854,17 +864,15 @@ export type PendingAction = {
|
|
|
854
864
|
* precedent: an optional group an older reader ignores): the IDENTITY of the row the park minted
|
|
855
865
|
* this action against, read off the leg's tool roster at the suspend station — `capabilityId`
|
|
856
866
|
* (engine-minted over {source, peer, name, contractId}), `contractId`, `shapeDigest`,
|
|
857
|
-
* `implementationRevision
|
|
858
|
-
* same-name row on
|
|
859
|
-
*
|
|
860
|
-
* (`resume.
|
|
861
|
-
* minted before the members existed ⇒ the name-only path, never widened by their absence.
|
|
867
|
+
* `implementationRevision`. With the face below they are the TOOL member of the row's approval object
|
|
868
|
+
* (`judgeApprovalObject`): an identity member that differs from the same-name row on the resuming leg, or is missing
|
|
869
|
+
* while another is present, is a replacement wearing the name (`resume.tool_contract_mismatch`, a reopen); a face
|
|
870
|
+
* that differs vetoes the call (`resume.target_moved`). All four ABSENT ⇒ a pre-identity row: the name alone is bound.
|
|
862
871
|
*/
|
|
863
872
|
capabilityId?: string;
|
|
864
873
|
contractId?: string;
|
|
865
874
|
shapeDigest?: string;
|
|
866
875
|
implementationRevision?: string;
|
|
867
|
-
rosterDigest?: string;
|
|
868
876
|
/**
|
|
869
877
|
* design/388 B6 × B18 (additive; the identity group's precedent): the FACE the parked call was judged under —
|
|
870
878
|
* display `family` + declared `pathTarget` — off the same roster row at the same mint. The pre-CAS resume-edit
|
|
@@ -880,6 +888,9 @@ export type PendingAction = {
|
|
|
880
888
|
* them, as the live gate judged the original, and the resume re-mints its face under the spelling while it still
|
|
881
889
|
* resolves to the row's tool. Absent on a row minted before it ⇒ the row's `toolName` alone. */
|
|
882
890
|
names?: readonly string[];
|
|
891
|
+
/** The approval object's TARGETS (`approvalTargetsOf`): per reading of the path slot, where it resolved when the card
|
|
892
|
+
* was asked; absent ⇒ not judged. A role resolving elsewhere at the execution vetoes the call (`resume.target_moved`). */
|
|
893
|
+
targets?: import("./approval-object.js").ApprovalTargets;
|
|
883
894
|
/**
|
|
884
895
|
* #438 (additive; no checkpoint-version bump — the `reminderMark` precedent: an optional field an
|
|
885
896
|
* older reader ignores. Unlike that precedent seat — which resume DOES read, through its
|
|
@@ -1003,8 +1014,7 @@ export interface CheckpointState {
|
|
|
1003
1014
|
* The WRITE-face containment state at suspend: the RESOLVED write face, written ONLY when it is
|
|
1004
1015
|
* non-default ("open"). An absent section IS "roots" for every reader — which is why it carries NO
|
|
1005
1016
|
* version stamp: losing it can only make a resume STRICTER. Resume folds STRICTER-WINS, the read seat's
|
|
1006
|
-
* law: roots unless the section says open AND the live resolution says open. No deny half and no
|
|
1007
|
-
* governance marker.
|
|
1017
|
+
* law: roots unless the section says open AND the live resolution says open. No deny half and no governance marker.
|
|
1008
1018
|
*/
|
|
1009
1019
|
writeFace?: {
|
|
1010
1020
|
face: "open" | "roots";
|
|
@@ -1326,8 +1336,8 @@ export interface CheckpointState {
|
|
|
1326
1336
|
* **persisted OR live declaration** (a monotonic join, never a downgrade): a run minted under a
|
|
1327
1337
|
* declaring adapter keeps its memory fold and its prompt disclosure when resumed on an
|
|
1328
1338
|
* undeclared/older adapter — the downgrade is closed in the derivation itself, deliberately
|
|
1329
|
-
* WITHOUT a new refusal arm (one fewer failure path, same safety).
|
|
1330
|
-
* prompt disclosure
|
|
1339
|
+
* WITHOUT a new refusal arm (one fewer failure path, same safety). ONE declaration, two readers: the content-class fold (the memory
|
|
1340
|
+
* face, the prompt disclosure — the design/378 red line binds it: no gate/policy/roster reads it) and the tree's cross-boundary taint bit.
|
|
1331
1341
|
* Schema ADDITION (additive, Q5 posture; the version-gate residual is shared with
|
|
1332
1342
|
* {@link placementRootSessionId} above and owned by the same version-lattice ticket).
|
|
1333
1343
|
*/
|
|
@@ -1362,6 +1372,9 @@ export interface CheckpointState {
|
|
|
1362
1372
|
readonly definition?: string;
|
|
1363
1373
|
readonly lists: string;
|
|
1364
1374
|
};
|
|
1375
|
+
/** The row's session holds a cross-boundary record (`CROSS_BOUNDARY_RECORD_TYPE`, written before the row is put): a reader must read
|
|
1376
|
+
* that record to resume the leg under its tree's state. Presence-coded; a capability mark only — the bits live in the session. */
|
|
1377
|
+
crossBoundaryRecorded?: true;
|
|
1365
1378
|
}
|
|
1366
1379
|
/**
|
|
1367
1380
|
* {@link CheckpointState} with **every** field made required-PRESENT, while each value keeps its original
|
|
@@ -1370,8 +1383,7 @@ export interface CheckpointState {
|
|
|
1370
1383
|
* correctness field to {@link CheckpointState} is then a **compile error** at the serialization site until
|
|
1371
1384
|
* it is explicitly handled — it can never be silently omitted and lost on resume. (Keying off
|
|
1372
1385
|
* `keyof Required<…>` makes the mapped type non-homomorphic, so it forces presence of every key yet leaves
|
|
1373
|
-
* each value's `| undefined` intact — `workspaceHandle: undefined` for a process-local suspend still
|
|
1374
|
-
* type-checks.)
|
|
1386
|
+
* each value's `| undefined` intact — `workspaceHandle: undefined` for a process-local suspend still type-checks.)
|
|
1375
1387
|
*/
|
|
1376
1388
|
export type SerializedCheckpointState = {
|
|
1377
1389
|
[K in keyof Required<CheckpointState>]: CheckpointState[K];
|
|
@@ -1603,6 +1615,10 @@ export interface ResolvedOutcome {
|
|
|
1603
1615
|
* the same decision" for no delivery benefit, since a replay is produced by re-presenting the same
|
|
1604
1616
|
* outcome, not by reconstructing an equivalent one. */
|
|
1605
1617
|
reason?: string;
|
|
1618
|
+
/** The approving person's FEEDBACK, if the `allow` carried any — recorded exactly as supplied (a blank value included)
|
|
1619
|
+
* and bound by the replay equality on the same ADDITIVE rule as {@link reason}: absence means "never recorded". No
|
|
1620
|
+
* reader requirement word guards it: `resolvedOutcome` is a store-written state-machine member, never minted with the row. */
|
|
1621
|
+
feedback?: string;
|
|
1606
1622
|
/** The settlement record core minted for this decide ({@link import("./gate-outcome.js").GateOutcome}):
|
|
1607
1623
|
* the row's own copy of what the resolved call's `tool_end` frame carries, written with the winner so
|
|
1608
1624
|
* an audit reading the row reads the same record the stream carried. NOT part of the replay equality
|
|
@@ -1930,8 +1946,7 @@ export interface CheckpointSummary {
|
|
|
1930
1946
|
approvalCard?: import("./tool-face.js").ToolApprovalCard;
|
|
1931
1947
|
/** design S1e: when the checkpoint was created ({@link Checkpoint.createdAt}, epoch ms) —
|
|
1932
1948
|
* projected so a supervisor inbox can sort/age pending entries (oldest-first triage) in ONE `listByScope`
|
|
1933
|
-
* call, no N+1 `getCheckpoint`. ECHO-ONLY display/triage; always present (a Checkpoint always has a
|
|
1934
|
-
* `createdAt`). */
|
|
1949
|
+
* call, no N+1 `getCheckpoint`. ECHO-ONLY display/triage; always present (a Checkpoint always has a `createdAt`). */
|
|
1935
1950
|
createdAt?: number;
|
|
1936
1951
|
/**
|
|
1937
1952
|
* design S1e: a **BOUNDED, UNREDACTED** raw preview of the pending tool call's input
|
|
@@ -2116,7 +2131,7 @@ export type CheckpointErrorReason = "version_newer" | "env_factory_missing" | "g
|
|
|
2116
2131
|
* re-supplied config and the deployment's deps (`configValueDoors`, the rest): the retired deps seats and caller-policy members
|
|
2117
2132
|
* (`config.deps_retired_key`), the peer presence, the restore selector, the microCompact knob, the prompt selectors, `resumeAt` on a resume
|
|
2118
2133
|
* (`resume_at.conflicts_resume`, `resume_at.mode_without_target` — a resume carrying `resumeAt` is refused as a conflict before its mode is
|
|
2119
|
-
* read, so `resume_at.invalid_mode` is a fresh run's word only), the containment faces, the add-only seats and the MCP / A2A `toolAxes` (`config.invalid_argument`), the three memory seats,
|
|
2134
|
+
* read, so `resume_at.invalid_mode` is a fresh run's word only), the containment faces, the add-only seats and the MCP / A2A `toolAxes` (`config.invalid_argument`), an MCP server's `toolFaces` (`config.tool_face_invalid`), the three memory seats,
|
|
2120
2135
|
* the auto-consolidation arming (its role key too, and the role seats and tier bindings it reads: `config.unknown_role`, `detail.reason` naming the arm), the materialize strategy and persistence flag, the lock layer (`config.locked_registry`,
|
|
2121
2136
|
* `config.locked_key`), an MCP server's content class, the skills-listing seats (`config.skill_listing_budget_invalid`), the limits and the
|
|
2122
2137
|
* resource-suspend knobs, the attachment modes, the governance windows, the brain-call guardrail and the retention declaration over the stores the leg
|
|
@@ -2125,7 +2140,7 @@ export type CheckpointErrorReason = "version_newer" | "env_factory_missing" | "g
|
|
|
2125
2140
|
* a skill's `baseDir` by its own reader, `config.skill_base_dir_invalid`). A door not entered here (the leg's model, its rebuilt
|
|
2126
2141
|
* roster, its answer face, the approval seat's value) still refuses after the claim, each for a stated reason (INTEGRATION-CORE, "A resume's two doors").
|
|
2127
2142
|
*/
|
|
2128
|
-
export declare const CHECKPOINT_CONFIG_REFUSAL_CODES: readonly ["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable", "config.user_attachment_invalid", "config.tool_face_control", "config.deps_retired_key", "config.peer_presence_invalid", "config.tool_model_gate_invalid", "config.microcompact_invalid", "config.prompt_selector_invalid", "resume_at.conflicts_resume", "resume_at.mode_without_target", "config.read_face_invalid", "config.write_face_invalid", "config.invalid_argument", "config.memory_delegation_evidence", "config.memory_provenance", "config.memory_capture_policy", "config.auto_consolidation", "config.unknown_role", "config.tool_materialize_invalid", "config.memory_persistence_invalid", "config.tool_materialize_unreachable", "config.locked_registry", "config.locked_key", "config.mcp_content_class", "config.skill_listing_budget_invalid", "config.limit_unknown_key", "config.limit_invalid", "config.attachment_invalid", "config.usage_window_invalid", "config.brain_call_guardrail_invalid", "config.retention_policy", "config.retention_capability", "config.invalid_checkpoint_store", "config.skill_base_dir_invalid"];
|
|
2143
|
+
export declare const CHECKPOINT_CONFIG_REFUSAL_CODES: readonly ["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable", "config.user_attachment_invalid", "config.tool_face_control", "config.deps_retired_key", "config.peer_presence_invalid", "config.tool_model_gate_invalid", "config.microcompact_invalid", "config.prompt_selector_invalid", "resume_at.conflicts_resume", "resume_at.mode_without_target", "config.read_face_invalid", "config.write_face_invalid", "config.invalid_argument", "config.tool_face_invalid", "config.memory_delegation_evidence", "config.memory_provenance", "config.memory_capture_policy", "config.cross_boundary_posture", "config.auto_consolidation", "config.unknown_role", "config.tool_materialize_invalid", "config.memory_persistence_invalid", "config.tool_materialize_unreachable", "config.locked_registry", "config.locked_key", "config.mcp_content_class", "config.skill_listing_budget_invalid", "config.limit_unknown_key", "config.limit_invalid", "config.attachment_invalid", "config.usage_window_invalid", "config.brain_call_guardrail_invalid", "config.retention_policy", "config.retention_capability", "config.invalid_checkpoint_store", "config.skill_base_dir_invalid"];
|
|
2129
2144
|
export type CheckpointConfigRefusalCode = (typeof CHECKPOINT_CONFIG_REFUSAL_CODES)[number];
|
|
2130
2145
|
export declare const isCheckpointConfigRefusalCode: (word: unknown) => word is CheckpointConfigRefusalCode;
|
|
2131
2146
|
/** A typed checkpoint-store error so callers branch on `code` (mirrors `SessionError`). */
|
|
@@ -2946,7 +2961,7 @@ export interface CheckpointStore {
|
|
|
2946
2961
|
* status === 'pending'`), so the list reflects exactly the rows that are still resumable. Order is unspecified
|
|
2947
2962
|
* (the inbox sorts by `severity`/`deadline` itself). An empty scope returns `[]`.
|
|
2948
2963
|
*
|
|
2949
|
-
* **OPTIONAL** for backward-compat with external {@link CheckpointStore} impls (a caller probes
|
|
2964
|
+
* **OPTIONAL** for backward-compat (RL-1336-checkpoint-listbyscope) with external {@link CheckpointStore} impls (a caller probes
|
|
2950
2965
|
* `store.listByScope?.(scope) ?? []`); ALL THREE first-party impls (in-memory, file, Pg) provide it.
|
|
2951
2966
|
*/
|
|
2952
2967
|
listByScope?(scope: string): Promise<CheckpointSummary[]>;
|
|
@@ -6,10 +6,10 @@ import { isAutoModeFallbackCause, readDenialLimitFallback } from "./auto-mode.js
|
|
|
6
6
|
import { isAskOrigin, isPersistedRuleMandate } from "./ask-origin.js";
|
|
7
7
|
import { readBoundBinding } from "./skill-grant-binding.js";
|
|
8
8
|
import { checkpointExecutionRecorded, executionRecordDisposition, ExecutionOutcomeConflictError, } from "./checkpoint-execution-record.js";
|
|
9
|
+
import { parkedApprovalCardOf } from "./pause-registry.js";
|
|
9
10
|
import { renderUntrustedCommandText, stripFormatCharacters } from "./permission-rule-model.js";
|
|
10
11
|
import { egressText } from "./untrusted-egress.js";
|
|
11
12
|
import { steerReplayRefusal } from "./steer-replay.js";
|
|
12
|
-
import { isToolApprovalCard } from "./tool-face.js";
|
|
13
13
|
import { isPermissionMode } from "./ask-origin.js";
|
|
14
14
|
export function mintCheckpointToken() {
|
|
15
15
|
return randomBytes(16).toString("hex");
|
|
@@ -251,7 +251,7 @@ export { REOPEN_REASONS } from "./resume-startup-cause.js";
|
|
|
251
251
|
export function summarizeCheckpoint(cp) {
|
|
252
252
|
const riskDescriptor = cp.gate.kind === "human" || cp.gate.kind === "irreversible_ask" ? cp.gate.riskDescriptor : undefined;
|
|
253
253
|
const severity = riskDescriptor !== undefined ? riskSeverity(riskDescriptor.axes) : undefined;
|
|
254
|
-
const
|
|
254
|
+
const cardReading = parkedApprovalCardOf(cp.gate);
|
|
255
255
|
const tool = cp.pendingAction.kind === "tool_approval" ? cp.pendingAction : undefined;
|
|
256
256
|
let toolInput;
|
|
257
257
|
if (tool !== undefined) {
|
|
@@ -281,7 +281,7 @@ export function summarizeCheckpoint(cp) {
|
|
|
281
281
|
...(cp.sourceTaskId !== undefined ? { sourceTaskId: cp.sourceTaskId } : {}),
|
|
282
282
|
...(cp.principal !== undefined ? { principal: cp.principal } : {}),
|
|
283
283
|
...(tool !== undefined ? { toolCallId: tool.toolCallId, toolName: tool.toolName } : {}),
|
|
284
|
-
...(
|
|
284
|
+
...(cardReading.kind === "card" ? { approvalCard: cardReading.card } : {}),
|
|
285
285
|
...(toolInput !== undefined ? { toolInput } : {}),
|
|
286
286
|
...(cp.state.workspaceHandle !== undefined
|
|
287
287
|
? { restoreMode: cp.state.workspaceHandle.restoreMode === "park_only" ? "park_only" : "snapshot" }
|
|
@@ -305,7 +305,7 @@ export function summarizeCheckpoint(cp) {
|
|
|
305
305
|
...(hasBidi ? { hasBidiControls: true } : {}),
|
|
306
306
|
};
|
|
307
307
|
}
|
|
308
|
-
export const CHECKPOINT_CONFIG_REFUSAL_CODES = Object.freeze(["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable", "config.user_attachment_invalid", "config.tool_face_control", "config.deps_retired_key", "config.peer_presence_invalid", "config.tool_model_gate_invalid", "config.microcompact_invalid", "config.prompt_selector_invalid", "resume_at.conflicts_resume", "resume_at.mode_without_target", "config.read_face_invalid", "config.write_face_invalid", "config.invalid_argument", "config.memory_delegation_evidence", "config.memory_provenance", "config.memory_capture_policy", "config.auto_consolidation", "config.unknown_role", "config.tool_materialize_invalid", "config.memory_persistence_invalid", "config.tool_materialize_unreachable", "config.locked_registry", "config.locked_key", "config.mcp_content_class", "config.skill_listing_budget_invalid", "config.limit_unknown_key", "config.limit_invalid", "config.attachment_invalid", "config.usage_window_invalid", "config.brain_call_guardrail_invalid", "config.retention_policy", "config.retention_capability", "config.invalid_checkpoint_store", "config.skill_base_dir_invalid"]);
|
|
308
|
+
export const CHECKPOINT_CONFIG_REFUSAL_CODES = Object.freeze(["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable", "config.user_attachment_invalid", "config.tool_face_control", "config.deps_retired_key", "config.peer_presence_invalid", "config.tool_model_gate_invalid", "config.microcompact_invalid", "config.prompt_selector_invalid", "resume_at.conflicts_resume", "resume_at.mode_without_target", "config.read_face_invalid", "config.write_face_invalid", "config.invalid_argument", "config.tool_face_invalid", "config.memory_delegation_evidence", "config.memory_provenance", "config.memory_capture_policy", "config.cross_boundary_posture", "config.auto_consolidation", "config.unknown_role", "config.tool_materialize_invalid", "config.memory_persistence_invalid", "config.tool_materialize_unreachable", "config.locked_registry", "config.locked_key", "config.mcp_content_class", "config.skill_listing_budget_invalid", "config.limit_unknown_key", "config.limit_invalid", "config.attachment_invalid", "config.usage_window_invalid", "config.brain_call_guardrail_invalid", "config.retention_policy", "config.retention_capability", "config.invalid_checkpoint_store", "config.skill_base_dir_invalid"]);
|
|
309
309
|
export const isCheckpointConfigRefusalCode = (word) => CHECKPOINT_CONFIG_REFUSAL_CODES.some((w) => w === word);
|
|
310
310
|
export class CheckpointError extends Error {
|
|
311
311
|
code;
|
|
@@ -441,6 +441,7 @@ export function winnerFromOutcome(outcome) {
|
|
|
441
441
|
...(outcome.answer === undefined ? {} : { answer: outcome.answer }),
|
|
442
442
|
...(outcome.gateOutcome === undefined ? {} : { gateOutcome: outcome.gateOutcome }),
|
|
443
443
|
...(outcome.reason === undefined ? {} : { reason: outcome.reason }),
|
|
444
|
+
...(outcome.feedback === undefined ? {} : { feedback: outcome.feedback }),
|
|
444
445
|
};
|
|
445
446
|
}
|
|
446
447
|
const CHECKPOINT_CONTROL_CHARS_RE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* source by hand cannot drop a row;
|
|
12
12
|
* · the SCAN — the gate reads this table literally, requires each registered constructor to go through the carrier,
|
|
13
13
|
* requires the published carriers (`ToolExecuteContext`, `ParentSpecSeat`) to declare exactly the rows they carry,
|
|
14
|
-
* and names any hand-written restricting projection outside the carriers
|
|
14
|
+
* and names any hand-written restricting projection outside the carriers (a field row's: the clamped member at its
|
|
15
|
+
* restricting value on an object, `memory: { enabled: false }`).
|
|
15
16
|
*
|
|
16
17
|
* "Tighten-only" here: the value that travels is the RESTRICTING one and only that one, so a parent that clamped nothing
|
|
17
18
|
* changes nothing about its children, and nothing a child can author lifts a clamp its parent ran under.
|
|
@@ -136,6 +137,13 @@ export declare const CLAMP_SET: Readonly<{
|
|
|
136
137
|
readonly script: false;
|
|
137
138
|
readonly carrier: "specSeat";
|
|
138
139
|
}>;
|
|
140
|
+
memory: Readonly<{
|
|
141
|
+
readonly law: "restricting";
|
|
142
|
+
readonly field: "enabled";
|
|
143
|
+
readonly value: false;
|
|
144
|
+
readonly script: false;
|
|
145
|
+
readonly carrier: "specSeat";
|
|
146
|
+
}>;
|
|
139
147
|
}>;
|
|
140
148
|
/** One row's seat name. */
|
|
141
149
|
export type ClampSeat = keyof typeof CLAMP_SET;
|
|
@@ -155,11 +163,19 @@ export type ClampSource = {
|
|
|
155
163
|
};
|
|
156
164
|
/** The clamp source a construction site hands the carrier: EVERY clamp-carrier row as a PRESENT key. */
|
|
157
165
|
export type ChildClampSource = Pick<ClampSource, ChildClampSeat>;
|
|
166
|
+
/** What one row hands on: its restricting value; an add-only row's list; a field row's restricting MEMBER as a partial
|
|
167
|
+
* declaration of the seat (`{ enabled: false }`) — never the whole declaration, which is the caller's own. */
|
|
168
|
+
type SeatTravels<K extends ClampSeat> = (typeof CLAMP_SET)[K] extends {
|
|
169
|
+
readonly field: infer F extends string;
|
|
170
|
+
readonly value: infer V;
|
|
171
|
+
} ? {
|
|
172
|
+
readonly [P in F]: V;
|
|
173
|
+
} : (typeof CLAMP_SET)[K] extends {
|
|
174
|
+
readonly value: infer V;
|
|
175
|
+
} ? V : NonNullable<TaskSpec[K]>;
|
|
158
176
|
/** Only the restricting values (add-only rows: a non-empty list) — the shape a waker's clamp seat and a projection take. */
|
|
159
177
|
export type ClampValues = {
|
|
160
|
-
readonly [K in ClampSeat]?:
|
|
161
|
-
readonly value: infer V;
|
|
162
|
-
} ? V : NonNullable<TaskSpec[K]>;
|
|
178
|
+
readonly [K in ClampSeat]?: SeatTravels<K>;
|
|
163
179
|
};
|
|
164
180
|
/** Every row's seat name, in table order. */
|
|
165
181
|
export declare const CLAMP_SEATS: readonly ClampSeat[];
|
|
@@ -170,7 +186,9 @@ export type ScriptSeat = {
|
|
|
170
186
|
/** {@link ScriptSeat}, in table order — the script whitelist's tighten-only half. */
|
|
171
187
|
export declare const SCRIPT_SEATS: readonly ScriptSeat[];
|
|
172
188
|
/** Two declarations of one seat under its row's law (`b` is the later one): the restricting value if either carries it,
|
|
173
|
-
* else what was authored (`b` over `a`); an add-only list is the union of both, in order, by the row's identity.
|
|
189
|
+
* else what was authored (`b` over `a`); an add-only list is the union of both, in order, by the row's identity. A field
|
|
190
|
+
* row's seat is a declaration the later author writes whole — what is composed is the one member the row clamps: the
|
|
191
|
+
* restricting value stands on the authored declaration if either side carries it, every other member is the author's. */
|
|
174
192
|
export declare function composeClampSeat(seat: ClampSeat, a: unknown, b: unknown): unknown;
|
|
175
193
|
/**
|
|
176
194
|
* THE union of an add-only seat's lists — the ONE merge every add-only row reads, wherever two of its lists meet: two
|
|
@@ -188,8 +206,13 @@ export declare function unionAddOnly<S extends AddOnlySeat>(seat: S, ...lists: R
|
|
|
188
206
|
* list is folded or compiled, so a task-layer value is judged as the caller wrote it. Absent ⇒ nothing to judge.
|
|
189
207
|
*/
|
|
190
208
|
export declare function assertAddOnlySeats(spec: object): void;
|
|
209
|
+
/** The name a refusal gives a seat's clamped cell: the seat, or (field row) `seat.member`. */
|
|
210
|
+
export declare function clampCellPath(seat: ClampSeat): string;
|
|
211
|
+
/** What a declaration of the seat states for the cell its row clamps (the value itself for a whole-value row). */
|
|
212
|
+
export declare function clampCellOf(seat: ClampSeat, declaration: unknown): unknown;
|
|
191
213
|
/** Would `override` LOOSEN `base` on this seat? Only a restricting row can be loosened: a base carrying the restricting
|
|
192
|
-
* value meeting an override that states a different one
|
|
214
|
+
* value meeting an override that states a different one (a field row reads the one member it clamps, so an override that
|
|
215
|
+
* declares the seat without stating that member loosens nothing). */
|
|
193
216
|
export declare function loosensClampSeat(seat: ClampSeat, base: unknown, override: unknown): boolean;
|
|
194
217
|
/** Read every row (`carrier`: that carrier's rows only) off a record that carries the seats under their own names (a spec, a ctx, a seat). */
|
|
195
218
|
export declare function clampSourceOf(record: object | undefined): ClampSource;
|
|
@@ -201,6 +224,22 @@ export declare function foldClampSources(...records: ReadonlyArray<object | unde
|
|
|
201
224
|
/** The restricting values of every row (`carrier` narrows it to one carrier's rows): a row with nothing restricting adds
|
|
202
225
|
* NO KEY, so the result spreads onto a spec without ever writing a loosening value. */
|
|
203
226
|
export declare function clampSeatsOf(source: Partial<Record<ClampSeat, unknown>>, carrier?: ClampCarrier): ClampValues;
|
|
227
|
+
/** The field rows' seats (object-valued seats, one member of each clamped). */
|
|
228
|
+
export type FieldSeat = {
|
|
229
|
+
[K in ClampSeat]: (typeof CLAMP_SET)[K] extends {
|
|
230
|
+
readonly field: string;
|
|
231
|
+
} ? K : never;
|
|
232
|
+
}[ClampSeat];
|
|
233
|
+
/** {@link clampSeatsOf} for the FIELD rows alone: what a field row hands on is a partial declaration, so it is written onto a
|
|
234
|
+
* spec by {@link applyClampSeats}, never spread over it. */
|
|
235
|
+
export declare function clampFieldSeatsOf(source: Partial<Record<ClampSeat, unknown>>): Pick<ClampValues, FieldSeat>;
|
|
236
|
+
/**
|
|
237
|
+
* Write clamp values onto a spec — the ONE way a projection lands on a record. A whole-value row lands as the value; a field
|
|
238
|
+
* row REWRITES the one member it clamps on the spec's own declaration and keeps every other member (a declaration that was
|
|
239
|
+
* deleted instead would leave the next mint nothing to read, and the clamp would end one level down). Returns a new object;
|
|
240
|
+
* `spec` is not mutated; a seat the values do not carry is left as the spec has it.
|
|
241
|
+
*/
|
|
242
|
+
export declare function applyClampSeats<S extends object>(spec: S, values: ClampValues): S;
|
|
204
243
|
/** The coded refusal of a clamp record a caller handed in (`config.invalid_argument`). */
|
|
205
244
|
export declare function clampRecordError(message: string): Error & {
|
|
206
245
|
code: "config.invalid_argument";
|
|
@@ -102,14 +102,31 @@ export const CLAMP_SET = Object.freeze({
|
|
|
102
102
|
memoryPersistenceCapable: Object.freeze({ law: "restricting", value: false, script: true, carrier: "specSeat" }),
|
|
103
103
|
fileHistory: Object.freeze({ law: "restricting", value: "disabled", script: false, carrier: "specSeat" }),
|
|
104
104
|
promptForm: Object.freeze({ law: "restricting", value: "minimal", script: false, carrier: "specSeat" }),
|
|
105
|
+
memory: Object.freeze({ law: "restricting", field: "enabled", value: false, script: false, carrier: "specSeat" }),
|
|
105
106
|
});
|
|
107
|
+
function fieldOf(row) {
|
|
108
|
+
return "field" in row ? row.field : undefined;
|
|
109
|
+
}
|
|
110
|
+
function cellOf(row, declaration) {
|
|
111
|
+
const field = fieldOf(row);
|
|
112
|
+
if (field === undefined)
|
|
113
|
+
return declaration;
|
|
114
|
+
return typeof declaration === "object" && declaration !== null && !Array.isArray(declaration) ? declaration[field] : undefined;
|
|
115
|
+
}
|
|
116
|
+
function withCell(row, declaration, cell) {
|
|
117
|
+
const field = fieldOf(row);
|
|
118
|
+
if (field === undefined)
|
|
119
|
+
return cell;
|
|
120
|
+
const own = typeof declaration === "object" && declaration !== null && !Array.isArray(declaration) ? declaration : {};
|
|
121
|
+
return { ...own, [field]: cell };
|
|
122
|
+
}
|
|
106
123
|
const ROWS = Object.freeze(Object.entries(CLAMP_SET));
|
|
107
124
|
export const CLAMP_SEATS = Object.freeze(ROWS.map(([seat]) => seat));
|
|
108
125
|
export const SCRIPT_SEATS = Object.freeze(ROWS.filter(([, row]) => row.script !== false).map(([seat]) => seat));
|
|
109
126
|
export function composeClampSeat(seat, a, b) {
|
|
110
127
|
const row = CLAMP_SET[seat];
|
|
111
128
|
if (row.law === "restricting")
|
|
112
|
-
return a === row.value || b === row.value ? row.value : (b ?? a);
|
|
129
|
+
return cellOf(row, a) === row.value || cellOf(row, b) === row.value ? withCell(row, b ?? a, row.value) : (b ?? a);
|
|
113
130
|
const lists = [a, b];
|
|
114
131
|
return unionAddOnly(seat, ...lists);
|
|
115
132
|
}
|
|
@@ -156,14 +173,28 @@ export function assertAddOnlySeats(spec) {
|
|
|
156
173
|
}
|
|
157
174
|
}
|
|
158
175
|
}
|
|
176
|
+
export function clampCellPath(seat) {
|
|
177
|
+
const field = fieldOf(CLAMP_SET[seat]);
|
|
178
|
+
return field === undefined ? seat : `${seat}.${field}`;
|
|
179
|
+
}
|
|
180
|
+
export function clampCellOf(seat, declaration) {
|
|
181
|
+
return cellOf(CLAMP_SET[seat], declaration);
|
|
182
|
+
}
|
|
159
183
|
export function loosensClampSeat(seat, base, override) {
|
|
160
184
|
const row = CLAMP_SET[seat];
|
|
161
|
-
|
|
185
|
+
if (row.law !== "restricting")
|
|
186
|
+
return false;
|
|
187
|
+
const stated = cellOf(row, override);
|
|
188
|
+
return cellOf(row, base) === row.value && stated !== undefined && stated !== row.value;
|
|
162
189
|
}
|
|
163
190
|
function projected(seat, v) {
|
|
164
191
|
const row = CLAMP_SET[seat];
|
|
165
|
-
if (row.law === "restricting")
|
|
166
|
-
|
|
192
|
+
if (row.law === "restricting") {
|
|
193
|
+
if (cellOf(row, v) !== row.value)
|
|
194
|
+
return undefined;
|
|
195
|
+
const travels = withCell(row, undefined, row.value);
|
|
196
|
+
return fieldOf(row) === undefined ? travels : Object.freeze(travels);
|
|
197
|
+
}
|
|
167
198
|
return Array.isArray(v) && v.length > 0 ? Object.freeze(v.map((e) => (typeof e === "object" && e !== null ? { ...e } : e))) : undefined;
|
|
168
199
|
}
|
|
169
200
|
export function clampSourceOf(record, carrier) {
|
|
@@ -184,6 +215,27 @@ export function clampSeatsOf(source, carrier) {
|
|
|
184
215
|
}
|
|
185
216
|
return out;
|
|
186
217
|
}
|
|
218
|
+
export function clampFieldSeatsOf(source) {
|
|
219
|
+
const out = {};
|
|
220
|
+
for (const [seat, row] of ROWS) {
|
|
221
|
+
if (fieldOf(row) === undefined)
|
|
222
|
+
continue;
|
|
223
|
+
const v = projected(seat, source[seat]);
|
|
224
|
+
if (v !== undefined)
|
|
225
|
+
out[seat] = v;
|
|
226
|
+
}
|
|
227
|
+
return out;
|
|
228
|
+
}
|
|
229
|
+
export function applyClampSeats(spec, values) {
|
|
230
|
+
const out = { ...spec };
|
|
231
|
+
for (const [seat, row] of ROWS) {
|
|
232
|
+
const v = values[seat];
|
|
233
|
+
if (v === undefined)
|
|
234
|
+
continue;
|
|
235
|
+
out[seat] = fieldOf(row) === undefined ? v : withCell(row, out[seat], cellOf(row, v));
|
|
236
|
+
}
|
|
237
|
+
return out;
|
|
238
|
+
}
|
|
187
239
|
export function clampRecordError(message) {
|
|
188
240
|
const e = new Error(message);
|
|
189
241
|
e.code = "config.invalid_argument";
|
|
@@ -86,7 +86,7 @@ export declare function consolidateScope(scope: string, deps: ConsolidateScopeDe
|
|
|
86
86
|
* plain max) would lose `id > cursor` and be exiled from consolidation forever. Pass the pass's
|
|
87
87
|
* `stats.consolidatedIds` (processed), `stats.addedIds`, and `stats.failedIds`.
|
|
88
88
|
*
|
|
89
|
-
* No-op when the store lacks the cursor pair (back-compat: an old store keeps the pure-inline behavior).
|
|
89
|
+
* No-op when the store lacks the cursor pair (back-compat, RL-1654-consolidate-scope: an old store keeps the pure-inline behavior).
|
|
90
90
|
* Never throws — a cursor-advance failure routes to `onWarn` (the inline notes are already durable; the
|
|
91
91
|
* worst case is the next periodic pass re-sees them, which `runMemoryConsolidation` handles idempotently).
|
|
92
92
|
*/
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The device lane's CROSS-BOUNDARY vocabulary: the run tree's two taint bits and its posture fact, the legs one call
|
|
3
|
+
* travels, the one table those answer a call's obligation from, and the session record that carries a tree's state from
|
|
4
|
+
* one leg of a session to the next. Pure data and pure functions — no I/O, no clock, no engine state.
|
|
5
|
+
*
|
|
6
|
+
* THE RULE. A call's cross-boundary obligation is decided by three things and nothing else: the legs THIS call travels
|
|
7
|
+
* (declared by the code that dispatches it — a constant on most definitions, given per call by the two that route by
|
|
8
|
+
* their arguments), whether the environment a leg reaches declares itself the target device right now, and the tree's
|
|
9
|
+
* three bits. Two outcomes, independent of each other: `mandate` — a person confirms this call; `record` — once this
|
|
10
|
+
* call is allowed, the tree's off-target-read bit is set. {@link crossBoundaryObligation} is the one function that
|
|
11
|
+
* answers it; every place that asks calls it and none restates a cell.
|
|
12
|
+
*/
|
|
13
|
+
import type { AssertAllKeysHandled } from "./ask-origin.js";
|
|
14
|
+
import type { EngineNotice } from "./engine-notice.js";
|
|
15
|
+
import type { HostDecider } from "./gate-outcome.js";
|
|
16
|
+
/** The run tree's two TAINT bits: the tree executes on a target device (`targetExecutionArmed`), and an off-target read
|
|
17
|
+
* was allowed into it since (`offTargetReadObserved`). Presence-coded on every carrier: `true` or absent, never `false`. */
|
|
18
|
+
export declare const CROSS_BOUNDARY_TAINT_BITS: readonly ["targetExecutionArmed", "offTargetReadObserved"];
|
|
19
|
+
export type CrossBoundaryTaintBit = (typeof CROSS_BOUNDARY_TAINT_BITS)[number];
|
|
20
|
+
/**
|
|
21
|
+
* The tree's state: the two taint bits and `governed` — the tree has run under the `multi_tenant` posture since it was
|
|
22
|
+
* first armed. `governed` is a posture fact, not a taint bit; it rides the same carriers and joins the same way. Each
|
|
23
|
+
* member is `true` or absent. The state only grows ({@link joinCrossBoundaryTree}).
|
|
24
|
+
*/
|
|
25
|
+
export interface CrossBoundaryTree {
|
|
26
|
+
readonly targetExecutionArmed?: true;
|
|
27
|
+
readonly offTargetReadObserved?: true;
|
|
28
|
+
readonly governed?: true;
|
|
29
|
+
}
|
|
30
|
+
/** The deployment's posture words (`RunnerDeps.crossBoundaryPosture`): who is hurt when a tree that executes on a device
|
|
31
|
+
* reaches past it — the device's own user (`single_user`), or an organization's other tenants (`multi_tenant`). */
|
|
32
|
+
export declare const CROSS_BOUNDARY_POSTURES: readonly ["single_user", "multi_tenant"];
|
|
33
|
+
export type CrossBoundaryPosture = (typeof CROSS_BOUNDARY_POSTURES)[number];
|
|
34
|
+
/**
|
|
35
|
+
* The legs one call can travel: `env` — into or out of an execution environment (the call's arguments reach it, or its
|
|
36
|
+
* content comes back from it); `outside_read` — content fetched from beyond the boundary; `outside_write` — an effect
|
|
37
|
+
* produced beyond the boundary. An empty set is a call whose effect stays inside the engine (its process or its session
|
|
38
|
+
* store).
|
|
39
|
+
*/
|
|
40
|
+
export declare const BOUNDARY_LEGS: readonly ["env", "outside_read", "outside_write"];
|
|
41
|
+
export type BoundaryLeg = (typeof BOUNDARY_LEGS)[number];
|
|
42
|
+
/** A definition's declaration of its legs: the legs every call travels, or `"per_call"` — the code that dispatches the call
|
|
43
|
+
* gives them per call (the destination is chosen by the call's own arguments). */
|
|
44
|
+
export type BoundaryLegsDeclaration = BoundaryLegList | "per_call";
|
|
45
|
+
/** A list of legs, in any order, each at most once on a roster row. */
|
|
46
|
+
export type BoundaryLegList = readonly BoundaryLeg[];
|
|
47
|
+
/** What one call owes: a person's confirmation (`mandate`), the off-target-read bit once allowed (`record`), both, or neither. */
|
|
48
|
+
export interface CrossBoundaryObligation {
|
|
49
|
+
readonly mandate: boolean;
|
|
50
|
+
readonly record: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** What a `"per_call"` definition's dispatch gives for one call: the legs it travels and, when its `env` leg reaches an
|
|
53
|
+
* environment other than the calling leg's own (a background shell's), that environment — its declaration is read as the call
|
|
54
|
+
* is judged. */
|
|
55
|
+
export interface BoundaryLegsGiven {
|
|
56
|
+
readonly legs: readonly BoundaryLeg[];
|
|
57
|
+
readonly env?: {
|
|
58
|
+
readonly externalContentTarget?: boolean;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
declare const CROSS_BOUNDARY_TREE_TOKEN: unique symbol;
|
|
62
|
+
/** A run tree's cross-boundary IDENTITY — opaque and frozen, minted by the engine alone: a tool is handed it so a delegation or
|
|
63
|
+
* workflow lane can join its children to the same tree and a registry handle can name the tree that spawned it, compared by
|
|
64
|
+
* identity. Nothing reads or writes the tree's state through it; the state stays the engine's. */
|
|
65
|
+
export interface CrossBoundaryTreeToken {
|
|
66
|
+
readonly [CROSS_BOUNDARY_TREE_TOKEN]: true;
|
|
67
|
+
}
|
|
68
|
+
/** A `"per_call"` definition's resolver, written beside the code that dispatches the call: handed the call's arguments as the
|
|
69
|
+
* tool reads them and the calling tree's {@link CrossBoundaryTreeToken} (a handle that recorded one compares it by identity). No I/O. */
|
|
70
|
+
export type BoundaryLegsFor = (args: unknown, at: {
|
|
71
|
+
readonly tree: CrossBoundaryTreeToken;
|
|
72
|
+
}) => BoundaryLegsGiven;
|
|
73
|
+
/** Why an exit refused a call its decision allowed: the call needs a person's confirmation under the tree's state NOW and the
|
|
74
|
+
* decision was not a person's (`unconfirmed`), or the session record the call owes could not be written before it ran
|
|
75
|
+
* (`unrecorded`). */
|
|
76
|
+
export interface CrossBoundaryExitRefusal {
|
|
77
|
+
readonly kind: "unconfirmed" | "unrecorded";
|
|
78
|
+
readonly message: string;
|
|
79
|
+
}
|
|
80
|
+
/** One call as the cross-boundary seat reads it: its wire name, its arguments as they would run, and its id (the trace names it). */
|
|
81
|
+
export interface CrossBoundaryCall {
|
|
82
|
+
readonly toolName: string;
|
|
83
|
+
readonly args: unknown;
|
|
84
|
+
readonly toolCallId?: string;
|
|
85
|
+
}
|
|
86
|
+
/** The gate's cross-boundary seat — ENGINE-BUILT per leg (`runner/cross-boundary-lane.ts`), never a deployment callback. */
|
|
87
|
+
export interface CrossBoundaryCheck {
|
|
88
|
+
/** This call's obligation under the tree's state at this moment (the station reads it on the final arguments). */
|
|
89
|
+
obligation(call: CrossBoundaryCall): CrossBoundaryObligation;
|
|
90
|
+
/** The allow exit's rule, on the bytes that run and the party that decided: re-reads the obligation; a mandate the decider cannot
|
|
91
|
+
* answer refuses; otherwise the off-target-read bit the call owes is joined and the session record is written before it runs. */
|
|
92
|
+
exit(call: CrossBoundaryCall, decidedBy: HostDecider): Promise<CrossBoundaryExitRefusal | undefined>;
|
|
93
|
+
}
|
|
94
|
+
/** The gate input's seat for {@link CrossBoundaryCheck}: present on a leg whose station is ENGAGED (a posture is declared, the leg runs
|
|
95
|
+
* on a target, or its tree is governed); absent ⇒ the decision path is byte-identical. */
|
|
96
|
+
export interface CrossBoundaryGateSeat {
|
|
97
|
+
crossBoundaryCheck?: CrossBoundaryCheck;
|
|
98
|
+
}
|
|
99
|
+
/** The table's rows. An `env` leg is judged by where it lands: a target environment is its own row, any other environment
|
|
100
|
+
* reads as both outside rows ({@link ENV_LEG_ROWS}). */
|
|
101
|
+
type LegRow = "env_to_target" | "outside_read" | "outside_write";
|
|
102
|
+
/** THE table. The host-lane column is empty, so a tree that never armed decides exactly as it would without this table. */
|
|
103
|
+
declare const OBLIGATION_TABLE: {
|
|
104
|
+
readonly env_to_target: {
|
|
105
|
+
readonly host_lane: "none";
|
|
106
|
+
readonly armed: "none";
|
|
107
|
+
readonly armed_observed: "mandate_if_governed";
|
|
108
|
+
};
|
|
109
|
+
readonly outside_read: {
|
|
110
|
+
readonly host_lane: "none";
|
|
111
|
+
readonly armed: "record";
|
|
112
|
+
readonly armed_observed: "none";
|
|
113
|
+
};
|
|
114
|
+
readonly outside_write: {
|
|
115
|
+
readonly host_lane: "none";
|
|
116
|
+
readonly armed: "mandate_if_governed";
|
|
117
|
+
readonly armed_observed: "mandate_if_governed";
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
export type ObligationTableCoversEveryRow = AssertAllKeysHandled<Exclude<LegRow, keyof typeof OBLIGATION_TABLE>>;
|
|
121
|
+
/** The obligation of one call — the union of its legs' cells under the tree's current state. `legs` are the legs this call
|
|
122
|
+
* travels (a definition's constant, or what its dispatch gave for this call); `reachedEnvIsTarget` — the environment its
|
|
123
|
+
* `env` leg reaches declares itself the target right now (read off that environment, never off the tree's history; unread
|
|
124
|
+
* when the call has no `env` leg). A leg outside {@link BOUNDARY_LEGS}, a non-boolean target fact or a malformed tree throws. */
|
|
125
|
+
export declare function crossBoundaryObligation(legs: readonly BoundaryLeg[], reachedEnvIsTarget: boolean, tree: CrossBoundaryTree): CrossBoundaryObligation;
|
|
126
|
+
/** The tree is GOVERNED — what the table's `mandate_if_governed` cells read, and so what makes the session record a carrier some
|
|
127
|
+
* judgment reads (a record that cannot be written refuses its call on a governed tree only). */
|
|
128
|
+
export declare function crossBoundaryTreeGoverned(tree: CrossBoundaryTree): boolean;
|
|
129
|
+
/** The join of two tree states: every bit either holds. Monotone — it never clears a bit — and returns a fresh frozen
|
|
130
|
+
* state, never one of its operands. */
|
|
131
|
+
export declare function joinCrossBoundaryTree(a: CrossBoundaryTree, b: CrossBoundaryTree): CrossBoundaryTree;
|
|
132
|
+
/** Whether `covering` holds every bit `tree` holds — a record that covers a tree's state need not be written again. */
|
|
133
|
+
export declare function crossBoundaryTreeCovers(covering: CrossBoundaryTree, tree: CrossBoundaryTree): boolean;
|
|
134
|
+
/** The strictest state: what a record that cannot be read stands for. */
|
|
135
|
+
export declare const STRICTEST_CROSS_BOUNDARY_TREE: CrossBoundaryTree;
|
|
136
|
+
/** The `customType` of the session entry that records a tree's state: a custom entry, persisted with the transcript and
|
|
137
|
+
* never replayed into model context — the state lives where the content it describes lives. */
|
|
138
|
+
export declare const CROSS_BOUNDARY_RECORD_TYPE = "engine:cross_boundary";
|
|
139
|
+
/** The record's `data`: written only for an armed tree, so `targetExecutionArmed` is always present. */
|
|
140
|
+
export interface CrossBoundaryRecordData {
|
|
141
|
+
readonly targetExecutionArmed: true;
|
|
142
|
+
readonly offTargetReadObserved?: true;
|
|
143
|
+
readonly governed?: true;
|
|
144
|
+
}
|
|
145
|
+
/** The one spelling of a record's `data` for a tree state. A tree that is not armed has no record: refused. */
|
|
146
|
+
export declare function crossBoundaryRecordData(tree: CrossBoundaryTree): CrossBoundaryRecordData;
|
|
147
|
+
/** What a branch says about its tree: no record on it; the join of its records (`entryId` = the newest one's); or a record — or an
|
|
148
|
+
* entry — that cannot be read, which reads as the strictest state, with the sentence a disclosure names. A record covers the content
|
|
149
|
+
* before it: `uncoveredContent` — conversation content (the session layer's `hasConversationContent`: a message, a custom message, a
|
|
150
|
+
* compaction) follows the newest record, or with no record is on the branch at all — is content produced under a state no record says. */
|
|
151
|
+
export type CrossBoundaryRecordRead = {
|
|
152
|
+
readonly kind: "absent";
|
|
153
|
+
readonly uncoveredContent: boolean;
|
|
154
|
+
} | {
|
|
155
|
+
readonly kind: "recorded";
|
|
156
|
+
readonly entryId?: string;
|
|
157
|
+
readonly tree: CrossBoundaryTree;
|
|
158
|
+
readonly uncoveredContent: boolean;
|
|
159
|
+
} | {
|
|
160
|
+
readonly kind: "malformed";
|
|
161
|
+
readonly entryId?: string;
|
|
162
|
+
readonly tree: CrossBoundaryTree;
|
|
163
|
+
readonly why: string;
|
|
164
|
+
};
|
|
165
|
+
/** The members a session entry is read by. */
|
|
166
|
+
export interface CrossBoundaryRecordEntry {
|
|
167
|
+
readonly type: string;
|
|
168
|
+
readonly id?: string;
|
|
169
|
+
readonly customType?: unknown;
|
|
170
|
+
readonly data?: unknown;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Read a branch's tree state: the JOIN of every cross-boundary record on `branch` (entries in path order) — the state only grows, so
|
|
174
|
+
* a later record holding fewer bits never lowers it. Any record whose shape is not a record's, and any entry that cannot be read
|
|
175
|
+
* (one of its members throws), makes the read {@link STRICTEST_CROSS_BOUNDARY_TREE}, never a looser state. No record reads `absent`.
|
|
176
|
+
*/
|
|
177
|
+
export declare function readCrossBoundaryRecord(branch: readonly CrossBoundaryRecordEntry[]): CrossBoundaryRecordRead;
|
|
178
|
+
/** The one mint of `config.cross_boundary_posture_undeclared`: an armed tree on a deployment that configured no posture, so
|
|
179
|
+
* the permissive `single_user` reading is in force. `detail.taint` lists the tree's taint bits. */
|
|
180
|
+
export declare function crossBoundaryPostureUndeclaredNotice(at: {
|
|
181
|
+
readonly sessionId: string;
|
|
182
|
+
readonly runId: string;
|
|
183
|
+
readonly tree: CrossBoundaryTree;
|
|
184
|
+
}): EngineNotice;
|
|
185
|
+
/** Where a session record's write was owed: a leg's prepare, an exit before its call runs, a suspend before its row, a settle. */
|
|
186
|
+
export type CrossBoundaryRecordPhase = "prepare" | "exit" | "suspend" | "settle"; /** The one mint of `config.cross_boundary_record_unwritten`: a session record that could not be written and refused nothing — on a tree
|
|
187
|
+
* that is not governed (no judgment reads the record), or at a governed leg's prepare / settle (no call to refuse; the next leg then
|
|
188
|
+
* reads the content after the newest record as off-target). A governed exit refuses its call and a governed suspend its row instead. */
|
|
189
|
+
export declare function crossBoundaryRecordUnwrittenNotice(at: {
|
|
190
|
+
readonly sessionId: string;
|
|
191
|
+
readonly runId: string;
|
|
192
|
+
readonly phase: CrossBoundaryRecordPhase;
|
|
193
|
+
readonly governed: boolean;
|
|
194
|
+
readonly cause: string;
|
|
195
|
+
}): EngineNotice;
|
|
196
|
+
/** The face a protocol tool (an MCP tool, an A2A skill) carries for its JUDGED `toolAxes` entry (`readToolAxes`' copy): the empty leg
|
|
197
|
+
* set when the entry declares `boundaryFlow: "engine"`, nothing otherwise (its roster row then states the legs its effect implies).
|
|
198
|
+
* The one translation of that declaration onto a mounted instance; the MCP intake and the A2A peer mint both call it. */
|
|
199
|
+
export declare function boundaryFlowFace(entry: {
|
|
200
|
+
readonly boundaryFlow?: "engine";
|
|
201
|
+
} | undefined): {
|
|
202
|
+
boundaryLegs?: readonly BoundaryLeg[];
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* The legs a ROSTER ROW states, from where the instance came from, what it declares and its resolved effect. The engine's
|
|
206
|
+
* own definitions (`builtin` / `synthetic` rows) and the protocol tools the engine materialized (`mcp` / `a2a`) are read by
|
|
207
|
+
* their declaration; any other row — and a row of those sources that declares nothing — by its effect: `read` reaches beyond
|
|
208
|
+
* the boundary to read, anything else to write. A declaration that is neither `"per_call"` nor a list of legs is refused on EVERY
|
|
209
|
+
* row, whoever declared it (`undefined` back, the caller refuses the row loudly): a row that does not read a declaration still does
|
|
210
|
+
* not let a bad one pass silently. The returned list is a fresh array in {@link BOUNDARY_LEGS} order.
|
|
211
|
+
*/
|
|
212
|
+
export declare function rosterBoundaryLegs(source: string, declared: unknown, effect: "read" | "write" | "idempotent"): BoundaryLegsDeclaration | undefined;
|
|
213
|
+
export {};
|