@sema-agent/core 7.50.2 → 7.51.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 +263 -0
- package/dist/agents/child-failure.d.ts +5 -16
- package/dist/agents/child-failure.js +4 -24
- package/dist/agents/subagent-steps.js +2 -2
- package/dist/agents/subagent.d.ts +4 -13
- package/dist/agents/subagent.js +94 -204
- package/dist/agents/tool-filter.d.ts +2 -2
- package/dist/brain/anthropic.d.ts +1 -1
- package/dist/brain/anthropic.js +7 -5
- package/dist/brain/open-responses.d.ts +1 -1
- package/dist/brain/open-responses.js +3 -2
- package/dist/brain/openai.d.ts +1 -1
- package/dist/brain/openai.js +3 -2
- package/dist/brain/request-route.d.ts +2 -2
- package/dist/brain/route-adjudicator.d.ts +16 -7
- package/dist/brain/route-adjudicator.js +23 -7
- package/dist/brain/route-conformance.js +23 -5
- package/dist/brain/stream-engine.js +9 -3
- package/dist/core/a2a.js +6 -8
- package/dist/core/allow-entry.d.ts +45 -26
- package/dist/core/allow-entry.js +48 -24
- package/dist/core/arg-summary.d.ts +8 -85
- package/dist/core/arg-summary.js +4 -386
- package/dist/core/ask-origin.d.ts +35 -33
- package/dist/core/ask-origin.js +9 -11
- package/dist/core/checkpoint-requirements.d.ts +6 -0
- package/dist/core/checkpoint-requirements.js +1 -0
- package/dist/core/checkpoint-store.d.ts +15 -34
- package/dist/core/checkpoint-store.js +5 -4
- package/dist/core/classifier-unavailable-arm.d.ts +12 -8
- package/dist/core/classifier-unavailable-arm.js +7 -2
- package/dist/core/credential-vocabulary.d.ts +3 -2
- package/dist/core/credential-vocabulary.js +27 -18
- package/dist/core/delegation-frames.d.ts +40 -15
- package/dist/core/delegation-frames.js +34 -0
- package/dist/core/engine-notice.d.ts +35 -11
- package/dist/core/gate-fold.js +9 -7
- package/dist/core/gate-lanes.js +6 -4
- package/dist/core/gate-outcome.d.ts +81 -15
- package/dist/core/gate-outcome.js +168 -67
- package/dist/core/governance-codes.d.ts +7 -1
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hooks.d.ts +4 -4
- package/dist/core/hooks.js +4 -3
- package/dist/core/mcp-connection-pool.d.ts +2 -0
- package/dist/core/mcp-connection-pool.js +2 -1
- package/dist/core/mcp-failure.js +2 -1
- package/dist/core/mcp-server-spec.d.ts +27 -5
- package/dist/core/mcp.d.ts +13 -38
- package/dist/core/mcp.js +28 -23
- package/dist/core/media-byte-cap.d.ts +25 -0
- package/dist/core/media-byte-cap.js +18 -2
- package/dist/core/memory-engine/consolidation-driver.js +1 -1
- package/dist/core/mode-policy.d.ts +25 -1
- package/dist/core/mode-policy.js +28 -13
- package/dist/core/own-property-receipt.d.ts +18 -0
- package/dist/core/own-property-receipt.js +39 -0
- package/dist/core/permission-rule-model.d.ts +32 -11
- package/dist/core/permission-rule-model.js +12 -7
- package/dist/core/persisted-rule-arms.d.ts +3 -3
- package/dist/core/prompt-section-seat.d.ts +54 -0
- package/dist/core/prompt-section-seat.js +49 -0
- package/dist/core/protocol-http-auth.d.ts +44 -0
- package/dist/core/protocol-http-auth.js +45 -0
- package/dist/core/read-face-seats.d.ts +30 -0
- package/dist/core/read-face-seats.js +38 -0
- package/dist/core/redaction-passes.d.ts +82 -0
- package/dist/core/redaction-passes.js +378 -0
- package/dist/core/remote-env.d.ts +4 -3
- package/dist/core/resume-startup-cause.d.ts +56 -0
- package/dist/core/resume-startup-cause.js +43 -0
- package/dist/core/rule-denial-sentence.d.ts +2 -2
- package/dist/core/runner/announce-once-ledger.js +2 -2
- package/dist/core/runner/classifier-ladder.d.ts +17 -13
- package/dist/core/runner/classifier-ladder.js +12 -10
- package/dist/core/runner/construction-doors.js +9 -20
- package/dist/core/runner/contracts.d.ts +4 -4
- package/dist/core/runner/gate-exit.js +2 -2
- package/dist/core/runner/memory-consolidation-write-judge.d.ts +53 -9
- package/dist/core/runner/memory-consolidation-write-judge.js +39 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +8 -13
- package/dist/core/runner/person-path-rows.d.ts +4 -3
- package/dist/core/runner/policy-throw.js +4 -4
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +8 -6
- package/dist/core/runner/prepare-gate-stations.js +4 -4
- package/dist/core/runner/prepare-hands-readface.js +1 -19
- package/dist/core/runner/prepare-inherited-gate.js +10 -9
- package/dist/core/runner/prepare-policy-chain.d.ts +3 -5
- package/dist/core/runner/prepare-policy-chain.js +10 -13
- package/dist/core/runner/prepare-project-context.d.ts +4 -4
- package/dist/core/runner/prepare-project-context.js +2 -1
- package/dist/core/runner/prepare-prompt-assembly.js +1 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-inputs.js +4 -4
- package/dist/core/runner/prepare-protocol-tools.d.ts +4 -3
- package/dist/core/runner/prepare-protocol-tools.js +3 -2
- package/dist/core/runner/prepare-task.js +6 -4
- package/dist/core/runner/prepare-turn-wiring.d.ts +16 -13
- package/dist/core/runner/prepare-turn-wiring.js +8 -7
- package/dist/core/runner/run-harness-handlers.js +2 -2
- package/dist/core/runner/run-leg.js +10 -9
- package/dist/core/runner/run-settle-and-teardown.js +5 -5
- package/dist/core/runner/run-turn-boundary.js +3 -2
- package/dist/core/runner/runtask.d.ts +1 -2
- package/dist/core/runner/runtask.js +8 -12
- package/dist/core/runner/session-rule-policy.d.ts +15 -11
- package/dist/core/runner/session-rule-policy.js +43 -33
- package/dist/core/runner/stream-lifecycle-verbs.js +2 -2
- package/dist/core/runner/stream-settle-backstop.js +2 -1
- package/dist/core/runner/sub-agent-deny-lists.d.ts +12 -8
- package/dist/core/runner/sub-agent-deny-lists.js +23 -12
- package/dist/core/runner/terminal-account.js +3 -3
- package/dist/core/runner/tool-output-projection.js +3 -8
- package/dist/core/runner/tool-result-media-seat.d.ts +19 -0
- package/dist/core/runner/tool-result-media-seat.js +13 -0
- package/dist/core/runner/turn-attachments.d.ts +13 -12
- package/dist/core/runner/turn-attachments.js +11 -7
- package/dist/core/runner-deps.d.ts +4 -3
- package/dist/core/safety-merge-corpus.js +21 -21
- package/dist/core/secret-env.js +1 -1
- package/dist/core/session-policy-store.d.ts +89 -72
- package/dist/core/session-policy-store.js +100 -93
- package/dist/core/shell-read-silence.d.ts +38 -4
- package/dist/core/shell-read-silence.js +102 -0
- package/dist/core/side-query.d.ts +7 -8
- package/dist/core/skill-grant-binding.d.ts +32 -11
- package/dist/core/skill-grant-binding.js +11 -3
- package/dist/core/skill-grant.d.ts +4 -3
- package/dist/core/skill-grant.js +5 -4
- package/dist/core/skills-directory.d.ts +12 -1
- package/dist/core/skills-directory.js +17 -8
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +2 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +3 -0
- package/dist/core/swappable-deps.d.ts +15 -1
- package/dist/core/swappable-deps.js +25 -1
- package/dist/core/synthetic-read-verdict.d.ts +16 -14
- package/dist/core/synthetic-read-verdict.js +28 -8
- package/dist/core/task-notification.d.ts +13 -3
- package/dist/core/task-notification.js +12 -1
- package/dist/core/task-spec.d.ts +14 -15
- package/dist/core/tool-name-readings.d.ts +0 -4
- package/dist/core/tool-name-readings.js +0 -1
- package/dist/core/tool-policy.d.ts +40 -9
- package/dist/core/tool-policy.js +25 -7
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-egress.d.ts +60 -11
- package/dist/core/untrusted-egress.js +120 -9
- package/dist/core/untrusted-text.js +16 -0
- package/dist/core/wiring-manifest.d.ts +22 -8
- package/dist/core/wiring-manifest.js +12 -4
- package/dist/engine/harness/agent-harness.d.ts +2 -1
- package/dist/engine/harness/agent-harness.js +4 -1
- package/dist/engine/harness/types.d.ts +3 -0
- package/dist/engine/llm/types.d.ts +7 -9
- package/dist/engine/loop/agent-loop.d.ts +8 -3
- package/dist/engine/loop/agent-loop.js +26 -9
- package/dist/engine/loop/types.d.ts +10 -0
- package/dist/index.d.ts +17 -5
- package/dist/index.js +14 -5
- package/dist/orchestration/run-workflow-tool.js +8 -8
- package/dist/orchestration/workflow.js +2 -2
- package/dist/prompt-assembly/assemble.d.ts +3 -1
- package/dist/prompt-assembly/assemble.js +6 -0
- package/dist/prompts/cowork.d.ts +42 -0
- package/dist/prompts/cowork.js +529 -0
- package/dist/prompts/default.d.ts +14 -1
- package/dist/prompts/default.js +3 -0
- package/dist/stores/file/session-policy-store.d.ts +6 -3
- package/dist/stores/file/session-policy-store.js +5 -16
- package/dist/tools/artifact/artifact-tool.js +2 -0
- package/dist/tools/fs/image-admission.d.ts +57 -4
- package/dist/tools/fs/image-admission.js +85 -0
- package/dist/tools/fs/path-containment.d.ts +2 -0
- package/dist/tools/fs/path-containment.js +5 -0
- package/dist/tools/fs/shell-read-check.d.ts +31 -6
- package/dist/tools/fs/shell-read-check.js +2 -4
- package/dist/tools/fs/shell-read-environment.d.ts +10 -25
- package/dist/tools/fs/shell-read-environment.js +6 -18
- package/dist/tools/fs/shell-read-establish.d.ts +3 -2
- package/dist/tools/fs/shell-read-establish.js +5 -5
- package/dist/tools/fs/shell-read-judge.d.ts +38 -8
- package/dist/tools/fs/shell-read-judge.js +12 -10
- package/dist/tools/web.js +2 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +94 -10
- package/wire-changes/core@7.51.0.json +2421 -0
|
@@ -172,31 +172,33 @@ export interface BackgroundChildEvent {
|
|
|
172
172
|
* Lets a parent's orchestration logic decide "continue it" vs "start fresh" without trial-and-error.
|
|
173
173
|
*/
|
|
174
174
|
resumable?: boolean;
|
|
175
|
-
/** terminal: the settled status
|
|
175
|
+
/** terminal: the settled status — like every completion fact on the terminal frame (`seq`,
|
|
176
|
+
* `stoppedBy`, `summary`, `result`, the residuals, `resumable`, `usage`, `completionId`), read from
|
|
177
|
+
* the settle's one completion frame by {@link backgroundChildTerminal}, never re-stated beside it. */
|
|
176
178
|
status?: "completed" | "killed" | "failed";
|
|
177
179
|
/** terminal + spawn/tick (#258 widened the carriers): the stop-cycle number — on a TERMINAL frame
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
+
* the completion frame's `TaskNotificationPayload.seq` (same settle, same X3 snapshot), or the
|
|
181
|
+
* row's generation when that frame states none; on SPAWN and TICK frames the registry row's generation at emit (fresh spawn = 1, a
|
|
180
182
|
* revived cycle's bumped counter), so a fleet consumer can tell a LATE first frame from a revived
|
|
181
183
|
* cycle's frame without waiting for the terminal. One axis with `task_progress`'s `seq` — the tick
|
|
182
184
|
* mirrors the frame's own stamp. Same honest downgrade as ever: present whenever a cycle number is
|
|
183
185
|
* knowable (the registry handle / retain ledger's `cycleSeq`, the durable row's `seq` on a tier-3
|
|
184
186
|
* revival / parked resume), absent when no carrier exists (forging a period would lie). */
|
|
185
187
|
seq?: number;
|
|
186
|
-
/** terminal: the cross-channel completion correlation id —
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* — "同一完成今天从四条通道扇出" — so it gets the same mirror treatment `seq`/`stoppedBy` already
|
|
190
|
-
* have here, not a fifth divergent copy). Absent until the underlying task reaches a terminal
|
|
191
|
-
* settle, or on a pre-P1-3 core build. */
|
|
188
|
+
/** terminal: the cross-channel completion correlation id — the completion frame's
|
|
189
|
+
* `TaskNotificationPayload.completionId` (one minted value for every face of one completion). Absent
|
|
190
|
+
* until the underlying task reaches a terminal settle, or on a pre-P1-3 core build. */
|
|
192
191
|
completionId?: string;
|
|
193
|
-
/** terminal, killed only (design/134 §3.3): who stopped it
|
|
194
|
-
*
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
stoppedBy?: "user" | "parent" | "system" | (string & {});
|
|
198
|
-
/** terminal: bounded human summary (same text the task_notification carries). */
|
|
192
|
+
/** terminal, killed only (design/134 §3.3): who stopped it — the completion frame's own word, so its
|
|
193
|
+
* type is that frame's. OPEN ENUM: consumers must tolerate unknown values (a future "timeout" is not breaking). */
|
|
194
|
+
stoppedBy?: import("./task-notification.js").TaskNotificationPayload["stoppedBy"];
|
|
195
|
+
/** terminal: the completion frame's bounded human summary (the text the parent's model reads). */
|
|
199
196
|
summary?: string;
|
|
197
|
+
/** terminal: the child's report as the completion frame carries it — the same string, cut once at the
|
|
198
|
+
* frame's bound with its disclosure, so a host that wakes an idle conversation reads the report here
|
|
199
|
+
* rather than from a second, differently-cut copy. Absent when the frame carries none (a killed or
|
|
200
|
+
* failed leg with no report, a withheld hand-back). UNTRUSTED (the child's own text). */
|
|
201
|
+
result?: string;
|
|
200
202
|
/** tick: live rollup (`task_progress.usage`) · terminal: the settled
|
|
201
203
|
* `{tokens, turns, costMicroUsd?, toolUses?, durationMs}`. `costMicroUsd` is own+nested and present
|
|
202
204
|
* only when that total is KNOWN (RB-368); `toolUses` is the run's own `stats.toolCalls` and is
|
|
@@ -221,6 +223,29 @@ export interface BackgroundChildEvent {
|
|
|
221
223
|
costMicroUsd?: number;
|
|
222
224
|
};
|
|
223
225
|
}
|
|
226
|
+
/** What a background child's terminal frame states beside its completion: the row's own facts. */
|
|
227
|
+
export interface BackgroundChildRow {
|
|
228
|
+
taskId: string;
|
|
229
|
+
sessionScoped: boolean;
|
|
230
|
+
/** The child run's session id, when known (the row-join anchor). */
|
|
231
|
+
sessionId?: string;
|
|
232
|
+
/** The read handle to the child's transcript — absent when it was released (a stillborn fork branch). */
|
|
233
|
+
transcriptId?: string;
|
|
234
|
+
parentToolCallId?: string;
|
|
235
|
+
/** The row's registry generation: the cycle the terminal names when the completion frame states none. */
|
|
236
|
+
generation?: number;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The ONE constructor of a background child's TERMINAL {@link BackgroundChildEvent}: a projection of the
|
|
240
|
+
* completion frame the same settle routes to the parent's model, so the fleet face reads every completion
|
|
241
|
+
* fact from that one record and cannot state a different one (a second spelling of the summary, a result
|
|
242
|
+
* cut twice, a cycle number read at another instant). The row supplies only what a completion does not
|
|
243
|
+
* state. The frame's spend is re-spelled in this face's vocabulary (`tool_uses` → `toolUses`,
|
|
244
|
+
* `duration_ms` → `durationMs`); a member the frame lacks stays absent.
|
|
245
|
+
*/
|
|
246
|
+
export declare function backgroundChildTerminal(completion: import("./task-notification.js").TaskNotificationPayload & {
|
|
247
|
+
status: "completed" | "killed" | "failed";
|
|
248
|
+
}, row: BackgroundChildRow): BackgroundChildEvent;
|
|
224
249
|
/**
|
|
225
250
|
* #281 件B — one lifecycle phase of a DELEGATED child leg, delivered to the process-level
|
|
226
251
|
* {@link RunnerDeps.onDelegationLifecycle} observer: the public, deps-level home of the delegation
|
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
import { observeThenableRejection } from "./safe-notify.js";
|
|
2
|
+
export function backgroundChildTerminal(completion, row) {
|
|
3
|
+
const seq = completion.seq ?? row.generation;
|
|
4
|
+
const usage = fleetUsageOf(completion.usage);
|
|
5
|
+
return {
|
|
6
|
+
kind: "terminal",
|
|
7
|
+
taskId: row.taskId,
|
|
8
|
+
sessionScoped: row.sessionScoped,
|
|
9
|
+
...(row.sessionId !== undefined ? { sessionId: row.sessionId } : {}),
|
|
10
|
+
...(row.transcriptId !== undefined ? { transcriptId: row.transcriptId } : {}),
|
|
11
|
+
...(row.parentToolCallId !== undefined ? { parentToolCallId: row.parentToolCallId } : {}),
|
|
12
|
+
status: completion.status,
|
|
13
|
+
...(seq !== undefined ? { seq } : {}),
|
|
14
|
+
...(completion.stoppedBy !== undefined ? { stoppedBy: completion.stoppedBy } : {}),
|
|
15
|
+
summary: completion.summary,
|
|
16
|
+
...(completion.result !== undefined ? { result: completion.result } : {}),
|
|
17
|
+
...(completion.recentSteps !== undefined ? { recentSteps: completion.recentSteps } : {}),
|
|
18
|
+
...(completion.editedFiles !== undefined ? { editedFiles: completion.editedFiles } : {}),
|
|
19
|
+
...(completion.resumable !== undefined ? { resumable: completion.resumable } : {}),
|
|
20
|
+
...(usage !== undefined ? { usage } : {}),
|
|
21
|
+
...(completion.completionId !== undefined ? { completionId: completion.completionId } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function fleetUsageOf(usage) {
|
|
25
|
+
if (typeof usage !== "object" || usage === null)
|
|
26
|
+
return undefined;
|
|
27
|
+
const u = usage;
|
|
28
|
+
return {
|
|
29
|
+
...(typeof u.tokens === "number" ? { tokens: u.tokens } : {}),
|
|
30
|
+
...(typeof u.turns === "number" ? { turns: u.turns } : {}),
|
|
31
|
+
...(typeof u.costMicroUsd === "number" ? { costMicroUsd: u.costMicroUsd } : {}),
|
|
32
|
+
...(typeof u.tool_uses === "number" ? { toolUses: u.tool_uses } : {}),
|
|
33
|
+
...(typeof u.duration_ms === "number" ? { durationMs: u.duration_ms } : {}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
2
36
|
export function emitsChildRowFrames(identity) {
|
|
3
37
|
return identity.isDelegatedChild;
|
|
4
38
|
}
|
|
@@ -91,6 +91,13 @@ export interface EngineNotice {
|
|
|
91
91
|
* per-process-deduplicated: each failed write is a distinct fact, and `ref` names the ROW rather
|
|
92
92
|
* than the attempt, so the uuidv7 `occurrenceId` minted at the failure is what tells two genuine
|
|
93
93
|
* losses of one ref apart. Dedup key: (code, occurrenceId).
|
|
94
|
+
* - `"tool_result.media_refused"` — an executed call's result carried media blocks (an image or a document, from
|
|
95
|
+
* an MCP server, a host tool, an engine tool or a `tool_result` hook's replacement) whose bytes the tool-result
|
|
96
|
+
* seat's admission refused: not a base64 payload, a media type outside the closed set, over the cap, or bytes
|
|
97
|
+
* without the claimed type's signature. Each such block already stands in the result as a text placeholder naming
|
|
98
|
+
* the tool and the refusal (never the bytes), so the model, `tool_end.output` and the transcript read that; this is
|
|
99
|
+
* the operator's account. ONCE PER CALL. `detail: { toolName, toolCallId, refused: [{ type, reason, bytes, limit?,
|
|
100
|
+
* mimeType? }], sessionId, runId }` — closed-set words, counts and a media type only when it can be one.
|
|
94
101
|
* - `"workflow.governance_key_stripped"` (#235) — the fields of an LLM-authored workflow `agent(spec)`
|
|
95
102
|
* that did NOT cross the governed default-deny whitelist: an unrecognized/control-plane field, or a
|
|
96
103
|
* `readFace` value that is not the containment-tightening one. The spawn PROCEEDS on the deployment
|
|
@@ -184,6 +191,13 @@ export interface EngineNotice {
|
|
|
184
191
|
* - `"config.write_face_swapped"` — the same line for the WRITE seat (`RunnerDeps.writeFace`),
|
|
185
192
|
* same payload, same laws. A SEPARATE code rather than a face field on the line above: the audience
|
|
186
193
|
* table and every consumer table are keyed by code.
|
|
194
|
+
* - `"config.read_deny_swapped"` — `Runner.swapDeps` replaced the deployment's read-deny declaration
|
|
195
|
+
* (any of `readDenyPatterns` / `readDenyBuiltinTiers` / `readDenyBuiltinExclude`) without a restart;
|
|
196
|
+
* ONE line per swap. `detail: { seats, patterns, tiers, exclude, occurrenceId }` — the seats the swap
|
|
197
|
+
* named, then the declaration in force after it (additions and removals as counts, the tier selection
|
|
198
|
+
* by name; `null` = no declaration). In-flight legs keep the deny face they prepared under; every later
|
|
199
|
+
* prepare compiles against the new declaration. A candidate outside the seats' gates throws atomically
|
|
200
|
+
* and mints nothing. Dedup key: (code, occurrenceId).
|
|
187
201
|
* - `"config.context_settings_swapped"` — `Runner.swapDeps` replaced the deployment's per-model
|
|
188
202
|
* context-window overlay (`RunnerDeps.contextSettings`, the `contextSettings` seat of the swappable
|
|
189
203
|
* set) without a restart. Unlike every other swappable seat this one is read LIVE: a running leg
|
|
@@ -237,10 +251,11 @@ export interface EngineNotice {
|
|
|
237
251
|
* - `"classifier.unavailable"` (`src/core/runner/classifier-ladder.ts`, `classifierUnavailableNotice`; minted by
|
|
238
252
|
* both classifier stations — the leg's gate and an ancestor's frozen classifier in the policy fold) — a
|
|
239
253
|
* classification could NOT RULE (the classifier leg failed, or its per-level budget
|
|
240
|
-
* `RunnerDeps.autoMode.timeoutMs` ran out) and says where the call went
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* way), `"denied"` = refused with the classifier's own
|
|
254
|
+
* `RunnerDeps.autoMode.timeoutMs` ran out) and says where the call went, read off the station's one approval
|
|
255
|
+
* route (`approvalRouteOf`): `disposition: "asked"` = on to the live approver, or on to the durable park — the
|
|
256
|
+
* sentence names which route, never whether the park then commits (the handed-on ask carries `requiresRealApproval`, so no automatic lane answers
|
|
257
|
+
* it; a declared departure from CC, which refuses either way), `"denied"` = refused with the classifier's own
|
|
258
|
+
* sentence (route `none`: no approver and no park facility).
|
|
244
259
|
* `detail: { toolName, toolCallId, cause, disposition, sessionId?, runId? }` — `cause` is the
|
|
245
260
|
* `AutoModeUnavailableCause` word. Once per classification that could not answer (a call judged by an ancestor's
|
|
246
261
|
* classifier and the leg's own can carry two); not minted while the call is being aborted (a halt, or the run's end). Audience
|
|
@@ -370,11 +385,13 @@ export interface EngineNotice {
|
|
|
370
385
|
* `detail: { names }` — every withheld key's name, never a value.
|
|
371
386
|
* - `"config.permission_mode_unavailable"` — the permission mode a task requested is not the mode the leg runs
|
|
372
387
|
* under: the deployment denies it (`by: "operator_deny"` — `RuntimeCaps.bypassPermissions` / `autoMode` is
|
|
373
|
-
* `false`), a requested `auto` has no classifier face (`by: "face_absent"`
|
|
374
|
-
* under its parent's ceiling (`by: "inherited_ceiling"
|
|
375
|
-
*
|
|
376
|
-
* `effective` (always `default` for the first two arms),
|
|
377
|
-
* `detail: { requested, effective, by, sessionId, runId
|
|
388
|
+
* `false`), a requested `auto` has no classifier face (`by: "face_absent"` — neither the leg's deps nor its chain carry
|
|
389
|
+
* one), or a child's declaration was folded under its parent's ceiling (`by: "inherited_ceiling"`). A CHILD's fold, of
|
|
390
|
+
* any of the three, is minted on the PARENT's stream too (`childSessionId` beside the parent's `sessionId` — a child's
|
|
391
|
+
* own manifest is not shown to the person). The leg runs in `effective` (always `default` for the first two arms),
|
|
392
|
+
* announced once per leg and once per steer that folds; `detail: { requested, effective, by, sessionId, runId,
|
|
393
|
+
* childSessionId? }` — `requested` is the word the fold folded (a child that requested nothing folds the word it
|
|
394
|
+
* inherited; the sentence says "(inherited)"). Audience `user`.
|
|
378
395
|
* - `"config.permission_mode_invalid"`, `"config.spec_retired_key"` and `"config.shell_gate_value_retired"`
|
|
379
396
|
* are ERROR codes, not notices (named here only to keep the mode family's spellings
|
|
380
397
|
* in one place): a `permissionMode` word outside the closed set (on the spec or on a checkpoint row), a spec
|
|
@@ -395,7 +412,7 @@ export interface EngineNotice {
|
|
|
395
412
|
* - `"permission.rule_store_unavailable"` — the person's persisted permission rules could not be read (a read
|
|
396
413
|
* failure, a corrupt or unreadable store, a read that did not answer in time), so that read's rows were SKIPPED:
|
|
397
414
|
* none of their allow, ask or deny rows took part in the decisions it served. At `"call"` the call asks a person
|
|
398
|
-
* meanwhile (a deny row among the rows nobody could read may forbid it; the class is `
|
|
415
|
+
* meanwhile (a deny row among the rows nobody could read may forbid it; the class is `rule_unreadable`,
|
|
399
416
|
* which `bypassPermissions` keeps and a headless run refuses); at `"prepare"` the run's path tables lack the rows
|
|
400
417
|
* for the whole run. `detail.at` names the read that found it first: `"prepare"` (the path rows the run's file and
|
|
401
418
|
* shell checks take at run start — the next run reads them again) or `"call"` (one call's own rule check — every
|
|
@@ -855,8 +872,15 @@ export interface EngineNotice {
|
|
|
855
872
|
* throw rendered twice keeps one id, two refusals sharing a code/scope/message get two. Omitted
|
|
856
873
|
* (never fabricated) when the caller composes the line with no error in hand.
|
|
857
874
|
*
|
|
858
|
-
* The
|
|
875
|
+
* The five SERVER-minted rows ({@link NOTICE_MINTER} `"server"`) — catalogued so their audience and detail shape
|
|
859
876
|
* are read here like every other row; this engine never mints them. A server forwards them through the same sink.
|
|
877
|
+
* - `"permission.entry_mode_clamped"` — the permission mode the caller requested was clamped by the deployment's
|
|
878
|
+
* entry floor BEFORE the run reached this engine (the server's own clamp, through this package's
|
|
879
|
+
* `clampPermissionMode`), so the run starts under another mode. The disclosure is minted where the clamp happens:
|
|
880
|
+
* a fold this engine makes itself (a parent's ceiling, the deployment's deny bits, a missing classifier face) is
|
|
881
|
+
* `config.permission_mode_unavailable`, never this row. Audience `"user"`; `detail: { requested, effective,
|
|
882
|
+
* ceiling, sessionId, runId }` — `requested` the caller's word, `effective` the word the run starts under,
|
|
883
|
+
* `ceiling` the floor that clamped it. Once per run.
|
|
860
884
|
* - `"instructions.source_changed"` — the project instruction file this run injects is not the one the same
|
|
861
885
|
* session's previous run injected (a file added, removed or renamed). Audience `"user"`; `detail: { previous,
|
|
862
886
|
* current, sessionId }` — `previous` / `current` are chain-member relative paths, `null` = that run had none.
|
package/dist/core/gate-fold.js
CHANGED
|
@@ -9,7 +9,7 @@ import { shellReadFaceWords } from "../tools/fs/shell-read-face.js";
|
|
|
9
9
|
import { failedJudgmentDeny } from "./runner/policy-throw.js";
|
|
10
10
|
import { thrownText } from "./thrown-value.js";
|
|
11
11
|
import { refuseOutOfContractDecision } from "./tool-policy.js";
|
|
12
|
-
import { applyUnansweredSilence, silencedBy } from "./shell-read-silence.js";
|
|
12
|
+
import { applyUnansweredSilence, readStationAnswer, silencedBy } from "./shell-read-silence.js";
|
|
13
13
|
import { asksUnstated, permissionSeatAt, unstatedAskMessage } from "./mode-policy.js";
|
|
14
14
|
export async function runGateFold(pass) {
|
|
15
15
|
const { input, toolName, toolCallId, callSignal, ledger, notifier, adjudicate } = pass;
|
|
@@ -194,7 +194,9 @@ function shellReadAskMessage(toolName, verdict) {
|
|
|
194
194
|
return `tool "${toolName}" ${verb} where the session's read boundary could not establish what is ${participle} — explicit approval required`;
|
|
195
195
|
return `tool "${toolName}" ${verb} outside the directories allowed for this session — explicit approval required`;
|
|
196
196
|
}
|
|
197
|
-
function applyShellReadVerdict(pass,
|
|
197
|
+
function applyShellReadVerdict(pass, answer, toolName, shellGated) {
|
|
198
|
+
const reading = readStationAnswer(answer, { toolName, toolCallId: pass.toolCallId, report: (e) => traceHookCrash(pass.input, e, pass.notifier) });
|
|
199
|
+
const verdict = reading.verdict;
|
|
198
200
|
const account = verdict.sentence !== undefined && verdict.sentence.trim().length > 0 ? inlineUntrusted(verdict.sentence, PROBE_REASON_MAX) : undefined;
|
|
199
201
|
if (verdict.writesPlaced === true)
|
|
200
202
|
pass.shellWritesPlaced = true;
|
|
@@ -204,20 +206,20 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
204
206
|
pass.targetUnresolved = true;
|
|
205
207
|
if (verdict.unplacedOptions !== undefined)
|
|
206
208
|
pass.shellUnplacedOptions = verdict.unplacedOptions;
|
|
207
|
-
if (
|
|
209
|
+
if (reading.kind === "silence" || verdict.finding === "unestablishable" || verdict.finding === "declined" || verdict.unestablished === true)
|
|
208
210
|
pass.shellReadUnestablished = true;
|
|
209
|
-
if (
|
|
211
|
+
if (reading.kind === "refuse") {
|
|
210
212
|
pass.decision = { action: "deny", message: verdict.sentence ?? `tool "${toolName}" reads what the session's read boundary refuses` };
|
|
211
213
|
pass.deniedBy = "read_boundary";
|
|
212
214
|
if (verdict.details !== undefined)
|
|
213
215
|
pass.denyDetails = verdict.details;
|
|
214
216
|
return;
|
|
215
217
|
}
|
|
216
|
-
if (
|
|
218
|
+
if (reading.kind === "silence") {
|
|
217
219
|
applyUnansweredSilence(pass, verdict, { message: shellReadAskMessage(toolName, verdict), account, tightenedBy: shellGated ? "shell_gate" : "safety" });
|
|
218
220
|
return;
|
|
219
221
|
}
|
|
220
|
-
switch (
|
|
222
|
+
switch (reading.kind) {
|
|
221
223
|
case "vouch":
|
|
222
224
|
return;
|
|
223
225
|
case "mandated": {
|
|
@@ -268,7 +270,7 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
268
270
|
return;
|
|
269
271
|
}
|
|
270
272
|
default: {
|
|
271
|
-
const exhaustive =
|
|
273
|
+
const exhaustive = reading.kind;
|
|
272
274
|
return exhaustive;
|
|
273
275
|
}
|
|
274
276
|
}
|
package/dist/core/gate-lanes.js
CHANGED
|
@@ -21,6 +21,7 @@ import { exitGate, passAskFace } from "./runner/gate-exit.js";
|
|
|
21
21
|
import { readOrgRuleLane, readPersistedRuleLane } from "./rule-lane-reads.js";
|
|
22
22
|
import { traceHookCrash } from "./gate-crash-trace.js";
|
|
23
23
|
import { createGateDeadline, awaitWriteProtectionJudgment, withGateTimeout } from "./gate-bounded-await.js";
|
|
24
|
+
import { readStationAnswer } from "./shell-read-silence.js";
|
|
24
25
|
import { policyThrowLine, reportPolicyThrow } from "./runner/policy-throw.js";
|
|
25
26
|
const QUESTION_TOOL_NAMES = new Set([ASK_USER_QUESTION_TOOL_NAME]);
|
|
26
27
|
function parkWith(suspendAsk, parkArgs, carry) {
|
|
@@ -679,14 +680,15 @@ export async function runGateLanes(pass) {
|
|
|
679
680
|
catch {
|
|
680
681
|
verdict = station.unanswered(pass.req, "the read station could not answer");
|
|
681
682
|
}
|
|
682
|
-
|
|
683
|
+
const reading = readStationAnswer(verdict, { toolName, toolCallId, report: (e) => traceHookCrash(input, e, notifier) });
|
|
684
|
+
if (reading.kind !== "vouch") {
|
|
683
685
|
editDenied = {
|
|
684
686
|
action: "deny",
|
|
685
|
-
message: verdict.sentence ?? `the approved edit for "${toolName}" reads where the read boundary does not vouch — denied fail-closed; re-submit the command as a fresh call and answer its card`,
|
|
687
|
+
message: reading.verdict.sentence ?? `the approved edit for "${toolName}" reads where the read boundary does not vouch — denied fail-closed; re-submit the command as a fresh call and answer its card`,
|
|
686
688
|
};
|
|
687
689
|
pass.deniedBy = "read_boundary";
|
|
688
|
-
if (verdict.details !== undefined)
|
|
689
|
-
pass.denyDetails = verdict.details;
|
|
690
|
+
if (reading.verdict.details !== undefined)
|
|
691
|
+
pass.denyDetails = reading.verdict.details;
|
|
690
692
|
}
|
|
691
693
|
}
|
|
692
694
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* verdict ended.
|
|
9
9
|
*/
|
|
10
10
|
import { type AskClass, type AskOrigin, type AssertAllKeysHandled, type ModeReleaseReason, type PermissionMode, type PersistedRuleMandate } from "./ask-origin.js";
|
|
11
|
-
import { type AutoModeClassifierRound } from "./auto-mode.js";
|
|
11
|
+
import { type AutoModeClassifierRound, type AutoModeFallbackCause } from "./auto-mode.js";
|
|
12
12
|
/**
|
|
13
13
|
* How the wait an ask was in ENDED — the closed set. One word per way a wait can end; the `who` on the
|
|
14
14
|
* record says which party ended it and is fixed BY the word (see {@link Settlement}).
|
|
@@ -403,8 +403,8 @@ export interface ModeRefusal {
|
|
|
403
403
|
* I7 `disposition.released` present ⇒ `kind === "allowed"`, no settlement, `mode` is `bypassPermissions`,
|
|
404
404
|
* `askClass` is an ask class (a member of the closed set — SHAPE; whether the class was releasable is the mint's
|
|
405
405
|
* law at mint time, read by the gate's mode-release arm, never re-judged here against today's table: a persisted
|
|
406
|
-
* record outlives the policy of its day), every member of `classes` is an ask class, `origin` / `reason`,
|
|
407
|
-
* present, are members of their closed sets, and `reason` names a member of `classes` (the mint takes it from
|
|
406
|
+
* record outlives the policy of its day), every member of `classes` is an ask class, `origin` / `mandate` / `reason`,
|
|
407
|
+
* when present, are members of their closed sets, and `reason` names a member of `classes` (the mint takes it from
|
|
408
408
|
* that set) — a mode releases nothing a person answered;
|
|
409
409
|
* I8 `deniedBy === "mode"` ⇔ `mode` present (`bypassPermissions` | `dontAsk`) with `askClass` and `classes`.
|
|
410
410
|
* Nothing here is read out of an ABSENCE: an ordinary allow with no ask is `{ disposition: { kind: "allowed" } }`,
|
|
@@ -416,20 +416,86 @@ export interface GateOutcome {
|
|
|
416
416
|
settlement?: Settlement;
|
|
417
417
|
origin?: AskOrigin;
|
|
418
418
|
}
|
|
419
|
+
/** A release as `major.minor.patch`: the version whose engine stopped minting a retired word. */
|
|
420
|
+
type ReleaseVersion = `${number}.${number}.${number}`;
|
|
419
421
|
/**
|
|
420
|
-
* The
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* the
|
|
424
|
-
*
|
|
425
|
-
*
|
|
422
|
+
* The words that LEFT a closed set a gate record carries, one list per set, each word with the version whose engine stopped
|
|
423
|
+
* minting it. A persisted record outlives the vocabulary of its day as it outlives the policy of its day, so the screen's
|
|
424
|
+
* archive reading ({@link screenGateOutcome}) reads each set as its live members plus these, and its producer reading reads the
|
|
425
|
+
* live members alone. Every set the screen reads has a list (empty when nothing left it); no word is both live and retired
|
|
426
|
+
* ({@link RetiredMembersAreNotLive}). A word-indexed table ({@link DENIED_BY_MAY_VETO}, {@link DENIED_BY_MAY_CARRY_CAUSE},
|
|
427
|
+
* {@link SETTLEMENT_IS_REFUSAL}) keeps rows for live words only: a retired word is read as granted nothing by it.
|
|
426
428
|
*/
|
|
429
|
+
export declare const RETIRED_MEMBERS: Readonly<{
|
|
430
|
+
askClass: readonly (Readonly<{
|
|
431
|
+
word: "write_protection_unresolved";
|
|
432
|
+
retiredIn: ReleaseVersion;
|
|
433
|
+
}> | Readonly<{
|
|
434
|
+
word: "governance_unavailable";
|
|
435
|
+
retiredIn: ReleaseVersion;
|
|
436
|
+
}>)[];
|
|
437
|
+
modeReleaseReason: readonly (Readonly<{
|
|
438
|
+
word: "write_protection_unresolved";
|
|
439
|
+
retiredIn: ReleaseVersion;
|
|
440
|
+
}> | Readonly<{
|
|
441
|
+
word: "rule_unreadable";
|
|
442
|
+
retiredIn: ReleaseVersion;
|
|
443
|
+
}>)[];
|
|
444
|
+
askOrigin: readonly Readonly<{
|
|
445
|
+
word: "unresolvable";
|
|
446
|
+
retiredIn: ReleaseVersion;
|
|
447
|
+
}>[];
|
|
448
|
+
persistedRuleMandate: readonly Readonly<{
|
|
449
|
+
word: "write_protection_unresolved";
|
|
450
|
+
retiredIn: ReleaseVersion;
|
|
451
|
+
}>[];
|
|
452
|
+
deniedBy: readonly Readonly<{
|
|
453
|
+
word: "plan_mode";
|
|
454
|
+
retiredIn: ReleaseVersion;
|
|
455
|
+
}>[];
|
|
456
|
+
settlementKind: readonly [];
|
|
457
|
+
settlementParty: readonly [];
|
|
458
|
+
classifierDenyCause: readonly [];
|
|
459
|
+
permissionMode: readonly [];
|
|
460
|
+
autoModeFallbackCause: readonly [];
|
|
461
|
+
}>;
|
|
462
|
+
type MemberSet = keyof typeof RETIRED_MEMBERS;
|
|
463
|
+
type RetiredWord<S extends MemberSet> = (typeof RETIRED_MEMBERS)[S][number]["word"];
|
|
464
|
+
/** Compile-time fence: `never` while no retired word is also a live member of its set. */
|
|
465
|
+
export type RetiredMembersAreNotLive = AssertAllKeysHandled<Extract<RetiredWord<"askClass">, AskClass> | Extract<RetiredWord<"modeReleaseReason">, ModeReleaseReason> | Extract<RetiredWord<"askOrigin">, AskOrigin> | Extract<RetiredWord<"persistedRuleMandate">, PersistedRuleMandate> | Extract<RetiredWord<"deniedBy">, DeniedBy> | Extract<RetiredWord<"settlementKind">, SettlementKind> | Extract<RetiredWord<"settlementParty">, SettlementParty> | Extract<RetiredWord<"classifierDenyCause">, ClassifierDenyCause> | Extract<RetiredWord<"permissionMode">, PermissionMode> | Extract<RetiredWord<"autoModeFallbackCause">, AutoModeFallbackCause>>;
|
|
466
|
+
/** Compile-time fence: `never` while every reason word, live or retired, is an ask class of its day (I7 reads it in `classes`). */
|
|
467
|
+
export type RetiredReasonsAreClassWords = AssertAllKeysHandled<Exclude<RetiredWord<"modeReleaseReason">, AskClass | RetiredWord<"askClass">>>;
|
|
468
|
+
/** Whether `word` left the closed set `set` ({@link RETIRED_MEMBERS}). A set name outside the registry throws. */
|
|
469
|
+
export declare function isRetiredMember<S extends MemberSet>(set: S, word: unknown): word is RetiredWord<S>;
|
|
427
470
|
/**
|
|
428
|
-
* The
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* records (a replay, an archive) does not read it: a release lawful when minted is not a defect under a later table.
|
|
471
|
+
* The release law of THIS engine (I7's policy half): a mode release names a set of classes that one face of the engine's table
|
|
472
|
+
* releases whole (`releasableAskClassesFor`) — the arbitration releases a set only when no member is immune on the call's face.
|
|
473
|
+
* Policy, not shape — it moves between versions — so only the producer reading of {@link screenGateOutcome} reads it.
|
|
432
474
|
* Module-level only; not part of the package root.
|
|
433
475
|
*/
|
|
434
|
-
export declare function releasePolicyDefects(g:
|
|
435
|
-
|
|
476
|
+
export declare function releasePolicyDefects(g: unknown): string[];
|
|
477
|
+
/** The members only the denied arm of a {@link GateDisposition} carries. */
|
|
478
|
+
declare const DENY_ONLY_MEMBERS: readonly ["deniedBy", "cause", "mode", "askClass", "classes"];
|
|
479
|
+
type DenyOnlyMember = Exclude<keyof Extract<GateDisposition, {
|
|
480
|
+
kind: "denied";
|
|
481
|
+
}>, keyof Extract<GateDisposition, {
|
|
482
|
+
kind: "allowed";
|
|
483
|
+
}>>;
|
|
484
|
+
/** Compile-time fence: `never` while the list is exactly the denied arm's own members. */
|
|
485
|
+
export type DenyOnlyMembersAreListed = AssertAllKeysHandled<Exclude<DenyOnlyMember, (typeof DENY_ONLY_MEMBERS)[number]> | Exclude<(typeof DENY_ONLY_MEMBERS)[number], DenyOnlyMember>>;
|
|
486
|
+
/**
|
|
487
|
+
* The one invariant screen for a {@link GateOutcome} (I1–I8 above, plus the closed-set word each member carries). Two readings:
|
|
488
|
+
* - `"archive"` (the default) — a record read back from where it was kept (a replay, a ledger, a durable row): its shape, with
|
|
489
|
+
* every closed set read as its live members plus {@link RETIRED_MEMBERS}. A record lawful when minted is not a defect later.
|
|
490
|
+
* - `"producer"` — a record THIS engine is composing or publishing now: the live sets alone, and the engine's release law
|
|
491
|
+
* ({@link releasePolicyDefects}). The gate's exit and its station screen read this.
|
|
492
|
+
* The record is read as whatever it holds (`unknown`): a member that is not the shape the type names — `null`, an array, a
|
|
493
|
+
* primitive where a record belongs, an object where a word belongs — is a defect naming its position, never an exception, and
|
|
494
|
+
* every class, reason, origin and mandate word is read wherever the record carries it.
|
|
495
|
+
* Returns the defects as sentences (an empty list is a clean record); the caller decides the fail-loud form (report + withhold,
|
|
496
|
+
* or refuse), never silently repairs the record. An options value that is not an object, or a reading outside the two, throws.
|
|
497
|
+
*/
|
|
498
|
+
export declare function screenGateOutcome(g: unknown, opts?: {
|
|
499
|
+
readonly reading?: "archive" | "producer";
|
|
500
|
+
}): string[];
|
|
501
|
+
export {};
|