@sema-agent/core 7.33.7 → 7.34.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 +357 -0
- package/dist/agents/cross-session-judge.d.ts +16 -7
- package/dist/agents/cross-session-judge.js +18 -15
- package/dist/agents/peer-session-drain.d.ts +4 -0
- package/dist/agents/peer-session-drain.js +5 -2
- package/dist/agents/repair-loop.d.ts +1 -1
- package/dist/agents/subagent.d.ts +3 -0
- package/dist/agents/subagent.js +12 -3
- package/dist/brain/anthropic.js +1 -0
- package/dist/brain/open-responses.js +1 -0
- package/dist/brain/openai.js +1 -0
- package/dist/brain/stream-engine.d.ts +3 -0
- package/dist/brain/stream-engine.js +2 -1
- package/dist/core/a2a.d.ts +3 -1
- package/dist/core/a2a.js +1 -1
- package/dist/core/ask-origin.d.ts +351 -154
- package/dist/core/ask-origin.js +223 -45
- package/dist/core/ask-unresolvable-notice.d.ts +5 -2
- package/dist/core/ask-unresolvable-notice.js +4 -3
- package/dist/core/auto-mode-arming.d.ts +17 -4
- package/dist/core/auto-mode-arming.js +31 -6
- package/dist/core/auto-mode-defaults.d.ts +16 -7
- package/dist/core/auto-mode-defaults.js +2 -1
- package/dist/core/auto-mode-directive.d.ts +18 -30
- package/dist/core/auto-mode-directive.js +9 -18
- package/dist/core/auto-mode-prompt.d.ts +62 -1
- package/dist/core/auto-mode-prompt.js +42 -4
- package/dist/core/auto-mode-rebuild.d.ts +2 -1
- package/dist/core/auto-mode-rebuild.js +1 -0
- package/dist/core/auto-mode.d.ts +32 -3
- package/dist/core/auto-mode.js +80 -41
- package/dist/core/checkpoint-store.d.ts +50 -35
- package/dist/core/checkpoint-store.js +58 -3
- package/dist/core/child-clamp-seats.js +1 -0
- package/dist/core/classifier-unavailable-arm.d.ts +57 -0
- package/dist/core/classifier-unavailable-arm.js +17 -0
- package/dist/core/effective-path-target.d.ts +12 -0
- package/dist/core/effective-path-target.js +18 -7
- package/dist/core/engine-notice.d.ts +53 -2
- package/dist/core/fs-write-gate-policy.d.ts +5 -1
- package/dist/core/fs-write-gate-policy.js +4 -1
- package/dist/core/gate-fold.js +17 -1
- package/dist/core/gate-lanes.js +111 -46
- package/dist/core/gate-outcome.d.ts +40 -7
- package/dist/core/gate-outcome.js +26 -4
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +12 -0
- package/dist/core/hooks.d.ts +50 -29
- package/dist/core/hooks.js +1 -3
- package/dist/core/mcp.js +1 -1
- package/dist/core/mode-policy.d.ts +182 -0
- package/dist/core/mode-policy.js +179 -0
- package/dist/core/oracle-isolation.d.ts +3 -3
- package/dist/core/permission-rule-model.d.ts +16 -3
- package/dist/core/permission-rule-model.js +36 -3
- package/dist/core/permission-rule-provider.d.ts +22 -11
- package/dist/core/permission-rule-provider.js +17 -7
- package/dist/core/permission-rules.d.ts +23 -1
- package/dist/core/permission-rules.js +35 -8
- package/dist/core/persisted-rule-arms.d.ts +10 -9
- package/dist/core/persisted-rule-arms.js +9 -6
- package/dist/core/present-plan-tool.d.ts +1 -1
- package/dist/core/present-plan-tool.js +3 -3
- package/dist/core/read-only-shell.d.ts +19 -19
- package/dist/core/read-only-shell.js +38 -12
- package/dist/core/retired-keys.d.ts +9 -3
- package/dist/core/retired-keys.js +5 -1
- package/dist/core/runner/classifier-ladder.d.ts +43 -1
- package/dist/core/runner/classifier-ladder.js +29 -0
- package/dist/core/runner/contracts.d.ts +37 -35
- package/dist/core/runner/denial-limit-arms.d.ts +30 -7
- package/dist/core/runner/denial-limit-arms.js +15 -9
- package/dist/core/runner/env-capability-census.js +1 -1
- package/dist/core/runner/gate-exit.d.ts +30 -4
- package/dist/core/runner/gate-exit.js +28 -7
- package/dist/core/runner/permission-rule-lanes.d.ts +9 -5
- package/dist/core/runner/permission-rule-lanes.js +44 -40
- package/dist/core/runner/persisted-path-rows.d.ts +64 -0
- package/dist/core/runner/persisted-path-rows.js +89 -0
- package/dist/core/runner/prepare-artifact.d.ts +5 -1
- package/dist/core/runner/prepare-artifact.js +9 -3
- package/dist/core/runner/prepare-ask-lane.d.ts +5 -3
- package/dist/core/runner/prepare-ask-lane.js +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +39 -13
- package/dist/core/runner/prepare-caps-and-workflow.js +58 -29
- package/dist/core/runner/prepare-gate-stations.d.ts +33 -6
- package/dist/core/runner/prepare-gate-stations.js +32 -19
- package/dist/core/runner/prepare-hands-readface.d.ts +40 -17
- package/dist/core/runner/prepare-hands-readface.js +64 -53
- package/dist/core/runner/prepare-inherited-gate.d.ts +22 -22
- package/dist/core/runner/prepare-inherited-gate.js +37 -23
- package/dist/core/runner/prepare-park-ask.d.ts +2 -2
- package/dist/core/runner/prepare-park-ask.js +2 -1
- package/dist/core/runner/prepare-policy-chain.d.ts +22 -2
- package/dist/core/runner/prepare-policy-chain.js +39 -12
- package/dist/core/runner/prepare-protocol-tools.d.ts +28 -0
- package/dist/core/runner/prepare-protocol-tools.js +13 -3
- package/dist/core/runner/prepare-run-refs.d.ts +6 -6
- package/dist/core/runner/prepare-run-refs.js +9 -4
- package/dist/core/runner/prepare-safety-scan.d.ts +5 -0
- package/dist/core/runner/prepare-safety-scan.js +19 -3
- package/dist/core/runner/prepare-suspend-saga.d.ts +5 -5
- package/dist/core/runner/prepare-suspend-saga.js +6 -6
- package/dist/core/runner/prepare-task.js +51 -22
- package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -6
- package/dist/core/runner/prepare-wiring-manifest.js +5 -3
- package/dist/core/runner/read-root-grant.d.ts +9 -0
- package/dist/core/runner/read-root-grant.js +12 -0
- package/dist/core/runner/retired-runner-deps.js +1 -0
- package/dist/core/runner/run-identity-wiring.js +1 -1
- package/dist/core/runner/run-leg.js +24 -15
- package/dist/core/runner/run-notification-lane.js +1 -0
- package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
- package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
- package/dist/core/runner/run-turn-boundary.js +1 -1
- package/dist/core/runner/runtask.js +3 -0
- package/dist/core/runner/stream-mode-verb.d.ts +27 -0
- package/dist/core/runner/stream-mode-verb.js +19 -0
- package/dist/core/runner/turn-attachments.d.ts +3 -3
- package/dist/core/runner/turn-attachments.js +1 -1
- package/dist/core/runner/write-protection-station.d.ts +7 -1
- package/dist/core/runner/write-protection-station.js +6 -3
- package/dist/core/runner-deps.d.ts +31 -34
- package/dist/core/runtime-caps.d.ts +12 -3
- package/dist/core/safety-axis-vocab.d.ts +2 -2
- package/dist/core/safety-axis-vocab.js +1 -1
- package/dist/core/secret-env.d.ts +16 -2
- package/dist/core/secret-env.js +25 -1
- package/dist/core/sensitive-path-policy.d.ts +4 -2
- package/dist/core/sensitive-path-policy.js +39 -30
- package/dist/core/spec-contract.d.ts +15 -0
- package/dist/core/spec-contract.js +19 -10
- package/dist/core/task-event.d.ts +1 -1
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +41 -89
- package/dist/core/task-stream.d.ts +16 -0
- package/dist/core/terminal-cause.js +1 -0
- package/dist/core/tighten-task-spec.d.ts +2 -2
- package/dist/core/tighten-task-spec.js +12 -14
- package/dist/core/tool-catalog-entries.js +4 -3
- package/dist/core/tool-policy.d.ts +54 -25
- package/dist/core/tool-policy.js +43 -2
- package/dist/core/tool-registry.d.ts +2 -0
- package/dist/core/tool-registry.js +3 -0
- package/dist/core/tool-spec.d.ts +8 -9
- package/dist/core/trace.d.ts +7 -6
- package/dist/core/types.d.ts +2 -1
- package/dist/core/wiring-manifest.d.ts +31 -5
- package/dist/core/wiring-manifest.js +28 -1
- package/dist/core/write-protect.d.ts +11 -1
- package/dist/core/write-protect.js +26 -15
- package/dist/engine/execution-env/kill-tree.js +4 -1
- package/dist/engine/execution-env/node-execution-env.d.ts +3 -0
- package/dist/engine/execution-env/node-execution-env.js +34 -35
- package/dist/engine/harness/types.d.ts +6 -7
- package/dist/engine/llm/types.d.ts +2 -4
- package/dist/engine/loop/types.d.ts +7 -0
- package/dist/index.d.ts +15 -5
- package/dist/index.js +12 -3
- package/dist/orchestration/run-spec.d.ts +4 -0
- package/dist/orchestration/run-spec.js +4 -3
- package/dist/orchestration/workflow-governance.js +1 -1
- package/dist/orchestration/workflow-primitives.d.ts +1 -1
- package/dist/orchestration/workflow-size-guideline.js +2 -2
- package/dist/stores/file/fs-atomic.js +2 -1
- package/dist/tools/artifact/artifact-tool.d.ts +17 -0
- package/dist/tools/artifact/artifact-tool.js +16 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +28 -7
- package/dist/tools/fs/bash-readonly-classifier.js +88 -0
- package/dist/tools/fs/containment-face.d.ts +9 -3
- package/dist/tools/fs/containment-face.js +2 -0
- package/dist/tools/fs/file-read-check.d.ts +49 -0
- package/dist/tools/fs/file-read-check.js +71 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-read.d.ts +1 -0
- package/dist/tools/fs/fs-search-tools.d.ts +2 -2
- package/dist/tools/fs/fs-search-tools.js +4 -4
- package/dist/tools/fs/fs-shared.js +20 -6
- package/dist/tools/fs/fs-write.d.ts +4 -3
- package/dist/tools/fs/fs-write.js +9 -9
- package/dist/tools/fs/index.d.ts +39 -3
- package/dist/tools/fs/index.js +38 -15
- package/dist/tools/fs/read-deny-home.d.ts +93 -0
- package/dist/tools/fs/read-deny-home.js +225 -0
- package/dist/tools/fs/read-deny.d.ts +176 -34
- package/dist/tools/fs/read-deny.js +268 -61
- package/dist/tools/fs/safety.d.ts +6 -1
- package/dist/tools/fs/safety.js +18 -5
- package/dist/tools/fs/search.d.ts +3 -0
- package/dist/tools/fs/search.js +47 -9
- package/dist/tools/fs/shell-read-check.d.ts +42 -11
- package/dist/tools/fs/shell-read-check.js +188 -13
- package/dist/tools/fs/shell-read-establish.d.ts +7 -3
- package/dist/tools/fs/shell-read-establish.js +134 -21
- package/dist/tools/fs/shell-read-identity.d.ts +7 -0
- package/dist/tools/fs/shell-read-identity.js +21 -0
- package/dist/tools/fs/shell-read-judge.d.ts +92 -32
- package/dist/tools/fs/shell-read-judge.js +43 -18
- package/dist/tools/fs/shell-read-plan.d.ts +4 -0
- package/dist/tools/fs/shell-read-plan.js +26 -4
- package/dist/tools/fs/shell-read-write-targets.d.ts +73 -0
- package/dist/tools/fs/shell-read-write-targets.js +173 -0
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +103 -11
- package/wire-changes/core@7.33.8.json +165 -0
- package/wire-changes/core@7.34.0.json +2621 -0
|
@@ -397,16 +397,15 @@ export interface FileSystem {
|
|
|
397
397
|
listDir(path: string, abortSignal?: AbortSignal): Promise<Result<FileInfo[], FileError>>;
|
|
398
398
|
/** Return the canonical path for an existing path, resolving symlinks where supported. */
|
|
399
399
|
canonicalPath(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
400
|
-
/**
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* for a DANGLING leaf symlink (a symlink whose target doesn't exist yet, which `canonicalPath`'s
|
|
404
|
-
* `realpath` can't resolve). Needed so a sensitive-path guard / containment check sees the real
|
|
405
|
-
* target of `write_file innocent.txt` where `innocent.txt -> .git/hooks/payload`.
|
|
406
|
-
*/
|
|
400
|
+
/** OPTIONAL: a symlink's raw target, one hop, not followed — so a path guard sees where `innocent.txt -> .git/hooks/payload`
|
|
401
|
+
* writes although the target does not exist yet (`canonicalPath`'s `realpath` cannot resolve a DANGLING leaf link).
|
|
402
|
+
* Omitted ⇒ such a leaf is canonicalized best-effort. */
|
|
407
403
|
readLink?(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
408
404
|
/** OPTIONAL: the LEAF symlink chain of `path` ({@link SymlinkChain}). Omitted, or `ok: false` ⇒ the path judges read the spelling and the canonical terminal only (the reach they had before this seat); a remote adapter answers in one `readlink` round trip and a caller never emulates it through {@link readLink}; bounded (64 hops, a cycle ends it), a network hop kept unprobed. */
|
|
409
405
|
canonicalChain?(path: string, abortSignal?: AbortSignal): Promise<Result<SymlinkChain, FileError>>;
|
|
406
|
+
/** OPTIONAL: the identity of the object `path` names, links followed (`<device>:<inode>` on POSIX, exact): equal answers name one object, where
|
|
407
|
+
* a firmlink or bind mount keeps its own {@link canonicalPath}. Home-anchored deny rows are placed by it; omitted ⇒ by spelling only. */
|
|
408
|
+
fileIdentity?(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
410
409
|
/** Return false for missing paths. Other errors, such as permission failures, return a {@link FileError}. */
|
|
411
410
|
exists(path: string, abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
|
|
412
411
|
/** Create a directory. Defaults: `recursive: true`, no abort signal. */
|
|
@@ -144,10 +144,8 @@ export interface StreamOptions {
|
|
|
144
144
|
* (see BrainTimeoutConfig.firstTokenTimeoutMs, design/17 O5).
|
|
145
145
|
*/
|
|
146
146
|
stallTimeouts?: StallTimeouts;
|
|
147
|
-
/**
|
|
148
|
-
*
|
|
149
|
-
* For example, OpenAI and Anthropic SDK clients default to 2.
|
|
150
|
-
*/
|
|
147
|
+
/** Per-call cap on the brain's transient retry budget: this call retries at most this many times, never more than
|
|
148
|
+
* the brain is configured for. */
|
|
151
149
|
maxRetries?: number;
|
|
152
150
|
/**
|
|
153
151
|
* Maximum delay in milliseconds to wait for a retry when the server requests a long wait.
|
|
@@ -765,6 +765,13 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = unk
|
|
|
765
765
|
* keyed by the folded-away spelling must stay inert rather than land on the other tool. Absent on non-MCP tools.
|
|
766
766
|
*/
|
|
767
767
|
mcpRemoteName?: string;
|
|
768
|
+
/**
|
|
769
|
+
* The MCP server's own read-only declaration (`annotations.readOnlyHint === true` on its tools/list entry), set by
|
|
770
|
+
* the MCP materializer. It answers ONE question: whether the `plan` mode leaves the tool to run (the reference's
|
|
771
|
+
* `isReadOnly` for a server's tool). It is never the tool's effect — a server's self-claim does not lower the
|
|
772
|
+
* repeat-safety effect below its fail-closed `write` default (only the caller's `toolAxes` does). Absent on non-MCP tools.
|
|
773
|
+
*/
|
|
774
|
+
mcpReadOnlyHint?: true;
|
|
768
775
|
/**
|
|
769
776
|
* design/120 P1.5 (CC `isConcurrencySafe(parsedInput)` parity): INPUT-level concurrency refinement
|
|
770
777
|
* for a tool whose safety depends on its arguments — CC's only real consumer is
|
package/dist/index.d.ts
CHANGED
|
@@ -62,6 +62,12 @@ export { probeMcpServers, type McpProbeResult } from "./core/mcp-probe.js";
|
|
|
62
62
|
export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classifyMcpFailure, type McpFailure, type McpFailureKind, type McpDelivered, type McpLivenessState, type McpServerLiveness } from "./core/mcp-failure.js";
|
|
63
63
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice, type McpInjectionDropReason, type McpInjectionDropFacts } from "./core/mcp-injection-drop.js";
|
|
64
64
|
export { askUnresolvableNotice, type AskUnresolvableFacts } from "./core/ask-unresolvable-notice.js";
|
|
65
|
+
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
66
|
+
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
67
|
+
export { TERMINAL_CAUSE_IS_REPLAYABLE } from "./core/terminal-cause.js";
|
|
68
|
+
export { RESERVED_AGENT_NAMES } from "./agents/subagent.js";
|
|
69
|
+
export { WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS } from "./orchestration/workflow-size-guideline.js";
|
|
70
|
+
export { ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./core/untrusted-text.js";
|
|
65
71
|
export { materializeA2aTools, A2aRpcError, type MaterializedA2a, type A2aPeerStatus, type A2aRefreshResult, type A2aToolAxis } from "./core/a2a.js";
|
|
66
72
|
export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf, type ProtocolNamespace, type ProtocolId } from "./core/protocol-table.js";
|
|
67
73
|
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions, } from "./core/session-policy-store.js";
|
|
@@ -104,7 +110,7 @@ export type { InvariantKind, FunctionContract, Invariant, InvariantViolation, Ch
|
|
|
104
110
|
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
105
111
|
export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, type BashReadonlyRootBoundary, type CompoundReadonlyVerdict, } from "./tools/fs/index.js";
|
|
106
112
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
107
|
-
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, type ReadDenyEntry, type ReadDenyMatcher, type NormalizedReadDenyEntry, type ReadDenyBuiltinTier, type ReadDenyBuiltinRow, type ReadDenyBuiltinConfig, } from "./tools/fs/index.js";
|
|
113
|
+
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, READ_DENY_HOME_WORD, readDenyPatternRun, readDenyHomesOf, compileWriteDeny, DENY_FACES, type DenyFace, type PathRuleDenyRow, type WriteDenyMatcher, type ReadDenyEntry, type ReadDenyMatcher, type NormalizedReadDenyEntry, type ReadDenyBuiltinTier, type ReadDenyBuiltinRow, type ReadDenyBuiltinConfig, } from "./tools/fs/index.js";
|
|
108
114
|
export { deploymentFaceClampNotice, resolveContainmentFace, type ContainmentFace, type ContainmentFaceInputs, type ContainmentFaceKind, type ContainmentFaceLayer, } from "./tools/fs/index.js";
|
|
109
115
|
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, type WriteProtectedEntry, type WriteProtectedRow, type WriteProtectedKind, type WriteProtectedHit, type WriteProtectionMatcher, type WriteProtectionVerdict, type WriteProtectionViewAbsence, type WriteProtectionJudgeContext, type WriteProtectionCompileOptions, type WriteProtectionCheck, WRITE_PROTECTION_TARGET_VIEWS, type WriteProtectionTargetView, type WriteProtectionMount, } from "./core/write-protect.js";
|
|
110
116
|
export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, type ToolResultProvenance, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, type ToolResultStore, type ToolResultSlice, type ToolResultDeletionReport, } from "./core/tool-result-store.js";
|
|
@@ -183,14 +189,18 @@ export { createAllowDenyPolicy, createApprovalPolicy,
|
|
|
183
189
|
* members that seat has no lane for (`"unavailable"`, a routing answer; `updatedInput`, an operator edit a
|
|
184
190
|
* policy verdict cannot get re-adjudicated). Exported so a host can NAME it instead of deriving it through
|
|
185
191
|
* `Parameters<typeof createApprovalPolicy>[0]["approve"]`. */
|
|
186
|
-
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
192
|
+
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
187
193
|
export { type ReadRootGrantScreen } from "./core/read-root-grant-screen.js";
|
|
188
|
-
export { type AskOrigin, ASK_ORIGINS, isAskOrigin,
|
|
194
|
+
export { type AskOrigin, ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, type PersistedRuleMandate, isPersistedRuleMandate } from "./core/ask-origin.js";
|
|
195
|
+
export { PERMISSION_MODES, type PermissionMode, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, type AskClass, isAskClass, MODE_ARBITRATION, type ModeArbitrationRow, RELEASABLE_ASK_CLASSES, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, type AskClassification, type AskClassFacts, type ToolMarkSource, arbitrateByMode, type Arbitration, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
196
|
+
export { modePolicyOf, type ModePolicy, PERMISSION_MODE_FOLD_REASONS, type PermissionModeFoldReason, type PermissionModeReceipt, ACCEPT_EDITS_FILE_COMMANDS, modeAcceptsFileCommand } from "./core/mode-policy.js";
|
|
197
|
+
export { readDenyClassifierRules, renderClassifierDenyRules, type DerivedDenyRule } from "./core/auto-mode-prompt.js";
|
|
189
198
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource, type AutoModeDenySource } from "./core/runtime-caps.js";
|
|
190
|
-
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, screenGateOutcome } from "./core/gate-outcome.js";
|
|
199
|
+
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, type ModeRelease, type ModeRefusal, screenGateOutcome } from "./core/gate-outcome.js";
|
|
191
200
|
export { type AskCarry } from "./core/hooks.js";
|
|
192
201
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
|
|
193
202
|
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, classifierParseFailureDenyMessage, AUTO_MODE_PARSE_FAILURES, isAutoModeParseFailure, type AutoModeParseFailure, type AutoModeUnavailableCause, AUTO_MODE_CLASSIFIER_FALLBACKS, isAutoModeClassifierFallback, AUTO_MODE_FALLBACK_CAUSES, isAutoModeFallbackCause, type AutoModeClassifierFallback, type AutoModeFallbackCause, type AutoModeClassifierRound, type AutoModeLadderRung, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
|
|
203
|
+
export type { ClassifierUnavailableSeat, ClassifierUnavailableInfo, ClassifierUnavailableDisposition, ClassifierUnavailableObserver } from "./core/classifier-unavailable-arm.js";
|
|
194
204
|
export { AUTO_MODE_DENIAL_LIMIT_DEFAULTS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "./core/auto-mode-defaults.js";
|
|
195
205
|
export { classifierSeatModel, type ClassifierSeat } from "./core/runner/classifier-ladder.js";
|
|
196
206
|
export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, type AutoModeRules, type BuildAutoModePromptOptions, type AutoModeWindowOptions, } from "./core/auto-mode-prompt.js";
|
|
@@ -352,7 +362,7 @@ export { ROUTE_ADJUDICATION_CONFORMANCE_CORPUS, type RouteAdjudicationVector } f
|
|
|
352
362
|
export { type BrainTimeoutConfig } from "./brain/timeout.js";
|
|
353
363
|
export { createAssistantMessageEventStream } from "./internal/llm.js";
|
|
354
364
|
export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
|
|
355
|
-
export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, TrackFileEditHook, TrackEditRequest, TrackEditResult, FileEditedHook, FileEditedNotice, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, ResumePreflightInfo, ResumePreflightVerdict, EngineNotice, RuntimeCaps, BackgroundChildEvent, DelegationLifecycleEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, TerminalCause, PausedCause, EffectiveMemoryScopes, RemoteEnvFailureNote, TaskSpec, ShellGateDoctrine,
|
|
365
|
+
export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, TrackFileEditHook, TrackEditRequest, TrackEditResult, FileEditedHook, FileEditedNotice, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, ResumePreflightInfo, ResumePreflightVerdict, EngineNotice, RuntimeCaps, BackgroundChildEvent, DelegationLifecycleEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, TerminalCause, PausedCause, EffectiveMemoryScopes, RemoteEnvFailureNote, TaskSpec, ShellGateDoctrine, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolInputVerdict, ToolInputValidationContext, ReversibilityVerdict, ReadRootGrantCandidate, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
|
|
356
366
|
export { Type } from "typebox";
|
|
357
367
|
export type { TSchema, Static } from "typebox";
|
|
358
368
|
export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
|
package/dist/index.js
CHANGED
|
@@ -48,6 +48,12 @@ export { probeMcpServers } from "./core/mcp-probe.js";
|
|
|
48
48
|
export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classifyMcpFailure } from "./core/mcp-failure.js";
|
|
49
49
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice } from "./core/mcp-injection-drop.js";
|
|
50
50
|
export { askUnresolvableNotice } from "./core/ask-unresolvable-notice.js";
|
|
51
|
+
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
52
|
+
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
53
|
+
export { TERMINAL_CAUSE_IS_REPLAYABLE } from "./core/terminal-cause.js";
|
|
54
|
+
export { RESERVED_AGENT_NAMES } from "./agents/subagent.js";
|
|
55
|
+
export { WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS } from "./orchestration/workflow-size-guideline.js";
|
|
56
|
+
export { ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./core/untrusted-text.js";
|
|
51
57
|
export { materializeA2aTools, A2aRpcError } from "./core/a2a.js";
|
|
52
58
|
export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf } from "./core/protocol-table.js";
|
|
53
59
|
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, } from "./core/session-policy-store.js";
|
|
@@ -82,7 +88,7 @@ export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
|
|
|
82
88
|
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
83
89
|
export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, } from "./tools/fs/index.js";
|
|
84
90
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
85
|
-
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, } from "./tools/fs/index.js";
|
|
91
|
+
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, READ_DENY_HOME_WORD, readDenyPatternRun, readDenyHomesOf, compileWriteDeny, DENY_FACES, } from "./tools/fs/index.js";
|
|
86
92
|
export { deploymentFaceClampNotice, resolveContainmentFace, } from "./tools/fs/index.js";
|
|
87
93
|
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, WRITE_PROTECTION_TARGET_VIEWS, } from "./core/write-protect.js";
|
|
88
94
|
export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, } from "./core/tool-result-store.js";
|
|
@@ -148,9 +154,12 @@ export { hasScheduler, isValidCronExpr, SchedulerError } from "./core/scheduler.
|
|
|
148
154
|
export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
|
|
149
155
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
|
|
150
156
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
151
|
-
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
157
|
+
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
152
158
|
export {} from "./core/read-root-grant-screen.js";
|
|
153
|
-
export { ASK_ORIGINS, isAskOrigin,
|
|
159
|
+
export { ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, isPersistedRuleMandate } from "./core/ask-origin.js";
|
|
160
|
+
export { PERMISSION_MODES, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, isAskClass, MODE_ARBITRATION, RELEASABLE_ASK_CLASSES, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, arbitrateByMode, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
161
|
+
export { modePolicyOf, PERMISSION_MODE_FOLD_REASONS, ACCEPT_EDITS_FILE_COMMANDS, modeAcceptsFileCommand } from "./core/mode-policy.js";
|
|
162
|
+
export { readDenyClassifierRules, renderClassifierDenyRules } from "./core/auto-mode-prompt.js";
|
|
154
163
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./core/runtime-caps.js";
|
|
155
164
|
export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, screenGateOutcome } from "./core/gate-outcome.js";
|
|
156
165
|
export {} from "./core/hooks.js";
|
|
@@ -29,6 +29,7 @@ import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
|
29
29
|
import type { TaskResult, TaskSpec } from "../core/types.js";
|
|
30
30
|
import { type ToolPolicy } from "../core/tool-policy.js";
|
|
31
31
|
import type { TaskOutcome } from "../core/task-outcome.js";
|
|
32
|
+
import type { EngineNotice } from "../core/engine-notice.js";
|
|
32
33
|
import { type OracleBaseline, type OracleGateResult, type OracleVerdict, type SpecContract } from "../core/spec-contract.js";
|
|
33
34
|
export interface RunSpecOptions {
|
|
34
35
|
/** Workcopy root — the containment root for frozenPaths, oracle cwd, and `spec.path` resolution. */
|
|
@@ -36,6 +37,9 @@ export interface RunSpecOptions {
|
|
|
36
37
|
/** Per-run base spec (model/tools/toolPolicy/hooks/limits/…). `objective` is owned by runSpec (the
|
|
37
38
|
* spec framing); `toolPolicy` and `hooks` are COMPOSED with runSpec's, never replaced. */
|
|
38
39
|
taskSpec: Omit<TaskSpec, "objective">;
|
|
40
|
+
/** Receives the oracle gates' once-per-process `config.secret_env_scrubbed` notice (`runOracle`'s `onNotice`);
|
|
41
|
+
* absent ⇒ the console line. */
|
|
42
|
+
onNotice?: (notice: EngineNotice) => void;
|
|
39
43
|
}
|
|
40
44
|
export interface RunSpecOracleReport {
|
|
41
45
|
/** Terminal adjudication (the authoritative bit — the stop gate only advises mid-run). */
|
|
@@ -80,7 +80,8 @@ export async function runSpec(runner, contract, opts) {
|
|
|
80
80
|
const startedAt = Date.now();
|
|
81
81
|
const frozenResolved = resolveFrozenPaths(rootDir, contract.frozenPaths);
|
|
82
82
|
const snapshot = snapshotFrozenPaths(frozenResolved);
|
|
83
|
-
const
|
|
83
|
+
const noticeSeat = opts.onNotice !== undefined ? { onNotice: opts.onNotice } : {};
|
|
84
|
+
const preflight = await runOracle(contract.oracle, rootDir, { signal: opts.taskSpec.signal, ...noticeSeat });
|
|
84
85
|
const baseline = captureBaseline(preflight);
|
|
85
86
|
let oracleHadRedRun = preflight.verdict === "red";
|
|
86
87
|
let oracleRuns = 1;
|
|
@@ -137,7 +138,7 @@ export async function runSpec(runner, contract, opts) {
|
|
|
137
138
|
guardRestores += restoreFrozenPaths(snapshot, rootDir);
|
|
138
139
|
if (!gateAbandoned) {
|
|
139
140
|
const gateSignal = ctx.signal !== undefined && opts.taskSpec.signal !== undefined ? AbortSignal.any([ctx.signal, opts.taskSpec.signal]) : (ctx.signal ?? opts.taskSpec.signal);
|
|
140
|
-
const report = await runOracle(contract.oracle, rootDir, { baseline, ...(gateSignal !== undefined ? { signal: gateSignal } : {}) });
|
|
141
|
+
const report = await runOracle(contract.oracle, rootDir, { baseline, ...(gateSignal !== undefined ? { signal: gateSignal } : {}), ...noticeSeat });
|
|
141
142
|
if (ctx.signal?.aborted === true)
|
|
142
143
|
return undefined;
|
|
143
144
|
oracleRuns++;
|
|
@@ -175,7 +176,7 @@ export async function runSpec(runner, contract, opts) {
|
|
|
175
176
|
hooks,
|
|
176
177
|
});
|
|
177
178
|
guardRestores += restoreFrozenPaths(snapshot, rootDir);
|
|
178
|
-
const final = await runOracle(contract.oracle, rootDir, { baseline });
|
|
179
|
+
const final = await runOracle(contract.oracle, rootDir, { baseline, ...noticeSeat });
|
|
179
180
|
oracleRuns++;
|
|
180
181
|
if (final.verdict === "red") {
|
|
181
182
|
oracleHadRedRun = true;
|
|
@@ -298,7 +298,7 @@ function pickWhitelist(scriptSpec) {
|
|
|
298
298
|
if (!Array.isArray(readDenyPatternsRaw)) {
|
|
299
299
|
throw new WorkflowScriptError('agent(spec): `readDenyPatterns` must be an array of deny entries (a "/"-separated segment run such as ".ssh", or { pattern, caseSensitive? })');
|
|
300
300
|
}
|
|
301
|
-
const entries = mapUntrustedArray(readDenyPatternsRaw, "agent(spec): `readDenyPatterns`", MAX_SCRIPT_DENY_ENTRIES, "Every entry is judged against every path the child reads, for the child's whole run; the deployment's own entries, and whichever built-in tiers the deployment
|
|
301
|
+
const entries = mapUntrustedArray(readDenyPatternsRaw, "agent(spec): `readDenyPatterns`", MAX_SCRIPT_DENY_ENTRIES, "Every entry is judged against every path the child reads, for the child's whole run; the deployment's own entries, and whichever built-in tiers the deployment has on (by default the credentials and home agent-config tiers), are in force on top of these.", pickReadDenyEntry);
|
|
302
302
|
try {
|
|
303
303
|
compileReadDeny(entries, "agent(spec).readDenyPatterns");
|
|
304
304
|
}
|
|
@@ -52,7 +52,7 @@ parentReadFace?: () => TaskSpec["readFace"],
|
|
|
52
52
|
* stricter-wins into every spawned child on its own seat (the two seats never read each other). */
|
|
53
53
|
parentWriteFace?: () => TaskSpec["writeFace"],
|
|
54
54
|
/** Twin of the above for the deny-set additions (the extra entries the host's own deployment/task
|
|
55
|
-
* layers stacked on; the built-in rows the DEPLOYMENT
|
|
55
|
+
* layers stacked on; the built-in rows the DEPLOYMENT's tier selection activates apply beside them). */
|
|
56
56
|
parentReadDenyPatterns?: () => TaskSpec["readDenyPatterns"],
|
|
57
57
|
/** #345 ③ — the HOST task's write-hands clamp is ON (`spec.handsReadOnly === true`). Injected
|
|
58
58
|
* tighten-only into every spawned child, like the read-face clamp above; see the injection
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const WORKFLOW_SIZE_GUIDELINES = ["unrestricted", "small", "medium", "large"];
|
|
2
2
|
export const WORKFLOW_SIZE_GUIDELINE_DEFAULT = "medium";
|
|
3
|
-
export const WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS = {
|
|
3
|
+
export const WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS = Object.freeze({
|
|
4
4
|
small: 5,
|
|
5
5
|
medium: 15,
|
|
6
6
|
large: 50,
|
|
7
|
-
};
|
|
7
|
+
});
|
|
8
8
|
export function normalizeWorkflowSizeGuideline(value) {
|
|
9
9
|
return WORKFLOW_SIZE_GUIDELINES.includes(value) ? value : undefined;
|
|
10
10
|
}
|
|
@@ -4,6 +4,7 @@ import { hrtime } from "node:process";
|
|
|
4
4
|
import { basename, dirname, join, resolve as resolvePath } from "node:path";
|
|
5
5
|
import { createHash, randomBytes } from "node:crypto";
|
|
6
6
|
import { execFileSync } from "node:child_process";
|
|
7
|
+
import { scrubSecretEnv } from "../../core/secret-env.js";
|
|
7
8
|
import { physicalPathOf, physicalPathOfExisting } from "../../core/physical-path.js";
|
|
8
9
|
import { thrownText } from "../../core/thrown-value.js";
|
|
9
10
|
const SAFE_COMPONENT = /^[A-Za-z0-9_.-]+$/;
|
|
@@ -637,7 +638,7 @@ function probeStartTimesOnce(pid) {
|
|
|
637
638
|
encoding: "utf8",
|
|
638
639
|
timeout: START_TIME_PROBE_TIMEOUT_MS,
|
|
639
640
|
stdio: ["ignore", "pipe", "ignore"],
|
|
640
|
-
env: { ...process.env, LC_ALL: "C", LANG: "C" },
|
|
641
|
+
env: { ...scrubSecretEnv(process.env), LC_ALL: "C", LANG: "C" },
|
|
641
642
|
});
|
|
642
643
|
}
|
|
643
644
|
catch (err) {
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `Artifact` tool: one tool, `action`-multiplexed, assembled from the host's capability declaration.
|
|
3
|
+
* The action enum, the parameter set and the description are all functions of `capabilities` — the
|
|
4
|
+
* implementation behind the seam is never inspected. Session state (the version tracked per URL and the
|
|
5
|
+
* local-path → URL binding that makes "same file path ⇒ same page" hold) lives in this factory's closure,
|
|
6
|
+
* fresh per run, never checkpointed.
|
|
7
|
+
*/
|
|
8
|
+
import { type PermissionMode } from "../../core/ask-origin.js";
|
|
9
|
+
import { type EngineNotice } from "../../core/engine-notice.js";
|
|
1
10
|
import { type ArtifactHost, type ArtifactHostCapabilities } from "../../core/artifact-host.js";
|
|
2
11
|
import { type OnAsk } from "../../core/tool-policy.js";
|
|
3
12
|
import type { ToolSpec } from "../../core/types.js";
|
|
@@ -42,6 +51,14 @@ export interface ArtifactToolOptions {
|
|
|
42
51
|
* = the run has no ask face, and a shared read is then REFUSED fail-closed (`artifact.refused`, content withheld) —
|
|
43
52
|
* never silently delivered. */
|
|
44
53
|
onAsk?: OnAsk;
|
|
54
|
+
/** The run's effective permission mode, read at each shared-read consent (a steer moves it). The consent ask is
|
|
55
|
+
* arbitrated as the gate's asks are (class `artifact_shared_read`): `bypassPermissions` RELEASES the read — delivered,
|
|
56
|
+
* announced once per run through `onNotice`, and NOT remembered as an approval (a mode release is not a person's
|
|
57
|
+
* nod; a later `default` leg asks) — `dontAsk` refuses it, every other mode asks the approver. Absent ⇒ no arbitration
|
|
58
|
+
* (the approver decides, or the read is withheld with none). */
|
|
59
|
+
permissionMode?: () => PermissionMode;
|
|
60
|
+
/** The notice sink the release account rides (`permission.ask_released_by_mode`, once per run for this class). */
|
|
61
|
+
onNotice?: (notice: EngineNotice) => void;
|
|
45
62
|
}
|
|
46
63
|
/** Supporting files per publish (upstream cap); enforced in the schema AND in the body, for callers that bypass the schema. */
|
|
47
64
|
export declare const MAX_FILES_PER_PUBLISH = 255;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { arbitrateByMode, classifyAsk } from "../../core/ask-origin.js";
|
|
2
|
+
import { deliverEngineNotice } from "../../core/engine-notice.js";
|
|
1
3
|
import { createHash } from "node:crypto";
|
|
2
4
|
import { Type } from "typebox";
|
|
3
5
|
import { ARTIFACT_ACTION_CONCURRENCY_SAFE, ARTIFACT_COMMIT_THROW_OUTCOME, ARTIFACT_FAILURE_RESULT_CODE, ARTIFACT_HOST_ERROR_CODE, ARTIFACT_LIST_SCOPES, ARTIFACT_PLANE_CONTENT_ORIGIN, ARTIFACT_PUBLISH_CONTEXTS, } from "../../core/artifact-host.js";
|
|
@@ -128,7 +130,8 @@ function buildSchema(caps) {
|
|
|
128
130
|
const invalid = (text) => errorResult(`Error (Artifact): ${text}`, { type: "artifact", invalidArguments: true });
|
|
129
131
|
const typed = (code, text, extra = {}) => errorResult(`Error (Artifact): ${text}`, { type: "artifact", code: ARTIFACT_FAILURE_RESULT_CODE[code], ...extra });
|
|
130
132
|
export function createArtifactTool(opts) {
|
|
131
|
-
const { host, capabilities: caps, runId, taskId, sessionId, agentName, readLocalFile, onAsk } = opts;
|
|
133
|
+
const { host, capabilities: caps, runId, taskId, sessionId, agentName, readLocalFile, onAsk, permissionMode, onNotice } = opts;
|
|
134
|
+
let releaseAnnounced = false;
|
|
132
135
|
const versions = new Map();
|
|
133
136
|
const bindings = new Map();
|
|
134
137
|
const occurrences = new Map();
|
|
@@ -316,6 +319,18 @@ export function createArtifactTool(opts) {
|
|
|
316
319
|
const sharedReadConsent = (url, ref, ctx) => {
|
|
317
320
|
if (sharedReadApproved.has(url))
|
|
318
321
|
return Promise.resolve({ ok: true });
|
|
322
|
+
if (permissionMode !== undefined) {
|
|
323
|
+
const verdict = arbitrateByMode(permissionMode(), classifyAsk({ action: "ask", requiresRealApproval: true, guard: "artifact_shared_read" }, { contentQuestion: false, markedUnresolvable: false, org: undefined, tightened: undefined, mandateMarks: {} }));
|
|
324
|
+
if (verdict.kind === "released") {
|
|
325
|
+
if (!releaseAnnounced && onNotice !== undefined) {
|
|
326
|
+
releaseAnnounced = true;
|
|
327
|
+
deliverEngineNotice(onNotice, { code: "permission.ask_released_by_mode", message: `the ${verdict.mode} permission mode released a shared-artifact read (${inlineUntrusted(url, 300)}) without asking anyone; further shared reads of this run under the mode are released the same way`, detail: { mode: verdict.mode, askClass: verdict.askClass, count: 1, firstToolCallId: ctx.toolCallId, ...(sessionId !== undefined ? { sessionId } : {}), runId } });
|
|
328
|
+
}
|
|
329
|
+
return Promise.resolve({ ok: true });
|
|
330
|
+
}
|
|
331
|
+
if (verdict.kind === "denied_by_mode")
|
|
332
|
+
return Promise.resolve({ ok: false, reason: `the ${verdict.mode} permission mode refuses to read another person's artifact without approval` });
|
|
333
|
+
}
|
|
319
334
|
const pending = consentInFlight.get(url);
|
|
320
335
|
if (pending !== undefined)
|
|
321
336
|
return pending;
|
|
@@ -15,7 +15,7 @@ import { type LexedCommand, type LexedSegment, type LexedWord, type ShellLex, ty
|
|
|
15
15
|
* hostname), and `file` (`-C -m` → compiles/writes a magic file) were REMOVED — each is read-only by NAME
|
|
16
16
|
* but state-MUTATING with args, which an argv[0]-only filter cannot tell apart. Leaving them in defeated
|
|
17
17
|
* both the `effect:read` truthfulness here and the classifier's irreversibility promise (a `date -s` would
|
|
18
|
-
* auto-allow an irreversible clock jump
|
|
18
|
+
* auto-allow an irreversible clock jump on the full shell face).
|
|
19
19
|
*
|
|
20
20
|
* Rows 3-4 are the CC-anchored expansion — the members of CC's safe-command
|
|
21
21
|
* set (pretty223.js:420513-420565 `e6s`; identical in the 220 corpus; the 220→245 campaign diff records
|
|
@@ -223,7 +223,7 @@ export declare function splitShellCompoundSegments(source: string, options?: {
|
|
|
223
223
|
reject: string;
|
|
224
224
|
};
|
|
225
225
|
/**
|
|
226
|
-
* Compound read-only classification for the `bash`
|
|
226
|
+
* Compound read-only classification for the `bash` full-shell face (the shape tier).
|
|
227
227
|
* Splits a command on the connector set `;` `&&` `||` `|` and passes every segment through
|
|
228
228
|
* {@link coarseReadonlyCheck} (the single {@link parseLeadingCommandName} parser + bare-name allowlist).
|
|
229
229
|
* All segments green ⇒ read-only. Returns a reason when rejected, else undefined.
|
|
@@ -304,8 +304,11 @@ export interface BashReadonlyRootBoundary {
|
|
|
304
304
|
* EVERY read face wires this one seat, the `bash_readonly` shell included, at BOTH of its judging
|
|
305
305
|
* moments — roots answer WHERE a command may read and the allowlist WHICH verb runs, neither answers
|
|
306
306
|
* WHICH FILES are off the table. What this seat is and is not is stated once, at
|
|
307
|
-
* `shell.read_boundary.friction_floor`.
|
|
308
|
-
|
|
307
|
+
* `shell.read_boundary.friction_floor`. `walked` — the path is a member a traversal enumerated, not a
|
|
308
|
+
* spelling of the command ({@link import("./read-deny.js").ReadDenyMatcher.matchPath}). */
|
|
309
|
+
denyMatch?: (resolvedPath: string, opts?: {
|
|
310
|
+
readonly walked?: boolean;
|
|
311
|
+
}) => string | null;
|
|
309
312
|
/** What the wired {@link denyMatch} judge would apply — the ACTIVE deny patterns. Read for ONE question:
|
|
310
313
|
* is there anything for a traversal to defeat? EMPTY ⇒ the judge refuses nothing, so a walk under it
|
|
311
314
|
* bypasses nothing and {@link CompoundReadonlyVerdict.recursiveReadPaths} is not minted. ABSENT ⇒ the
|
|
@@ -328,7 +331,7 @@ export interface BashReadonlyRootBoundary {
|
|
|
328
331
|
*/
|
|
329
332
|
export interface CompoundReadonlyVerdict {
|
|
330
333
|
/** Demotion reason (the same string {@link classifyCompoundReadonly} returns), or undefined: the
|
|
331
|
-
* command's SHAPE is not one the
|
|
334
|
+
* command's SHAPE is not one the shape tier auto-allows. WHERE the command reads is not this
|
|
332
335
|
* verdict's business — that is the gate's shell read station (`shell-read-check.ts`). */
|
|
333
336
|
reason?: string;
|
|
334
337
|
}
|
|
@@ -350,6 +353,24 @@ export declare function formatOutOfRootReadApprovalOption(directory: string): st
|
|
|
350
353
|
* operand scan below, which is safe for an unknown command because a bare word can only ever name
|
|
351
354
|
* something under the working directory. */
|
|
352
355
|
export declare const NO_PATH_OPERAND_COMMANDS: ReadonlySet<string>;
|
|
356
|
+
/** The no-path-operand programs that EVALUATE a word (`test -v 'a[$(…)]'` runs the substitution in the subscript): a word
|
|
357
|
+
* the shell or that evaluation rewrites is handed over as any program's is; only their settled words name nothing. */
|
|
358
|
+
export declare const NO_PATH_OPERAND_EVALUATORS: ReadonlySet<string>;
|
|
359
|
+
/** The builtins whose `NAME=value` arguments are assignments bash performs (and exports, for `export`), never paths. */
|
|
360
|
+
export declare const DECLARATION_BUILTINS: ReadonlySet<string>;
|
|
361
|
+
/** The shell BUILTINS that open no file, start no program and evaluate nothing: an external program's loader reads its
|
|
362
|
+
* environment (`LD_PRELOAD` for `sleep`), `printf` reads `TZ` for `%(…)T` and assigns through `-v`, `test -v` and an
|
|
363
|
+
* array subscript evaluate arithmetic (which runs a `$(…)` inside it). A declaration builtin counts only bare — no option
|
|
364
|
+
* word (`-i` evaluates the value) — and every inert segment's words carry no `[` `]` `$` or backquote. */
|
|
365
|
+
export declare const INERT_BUILTINS: ReadonlySet<string>;
|
|
366
|
+
/** The indices of the SETTLED words a {@link MESSAGE_SLOTS} row reads as message text under the subcommand's grammar:
|
|
367
|
+
* the value of `-m` (attached, or the next word) or of `--message` (`=`, or the next word; an unambiguous prefix of it
|
|
368
|
+
* counts). A word the shell rewrites is never claimed, and neither is any word another option consumes — those words
|
|
369
|
+
* stay the verb-blind walk's. */
|
|
370
|
+
export declare function messageSlotWords(program: string, words: readonly {
|
|
371
|
+
readonly folded: string;
|
|
372
|
+
readonly expands: unknown;
|
|
373
|
+
}[], programIndex: number): Set<number>;
|
|
353
374
|
/** True for a token that can denote a filesystem location OUTSIDE the working directory. A bare word
|
|
354
375
|
* (`foo`, `a.txt`, a grep pattern, an awk program) cannot: with no separator and no `..` it always
|
|
355
376
|
* resolves under the cwd, which the caller's cwd governance already covers.
|
|
@@ -934,8 +955,8 @@ export declare const POLL_LOOP_MAX_BEATS = 120;
|
|
|
934
955
|
export declare const POLL_LOOP_MAX_SLEEP_SECONDS = 600;
|
|
935
956
|
/**
|
|
936
957
|
* The BOUNDED READ-ONLY POLL LOOP arm of the classify face. The compound classifier above rejects any
|
|
937
|
-
* control structure (`for` is not an allowlisted name), which makes
|
|
938
|
-
* `"always"` for a monitoring consumer whose whole idiom is `for i in $(seq 1 8); do tail -n 5 x.log;
|
|
958
|
+
* control structure (`for` is not an allowlisted name), which makes the shape tier behave like
|
|
959
|
+
* the `"always"` floor for a monitoring consumer whose whole idiom is `for i in $(seq 1 8); do tail -n 5 x.log;
|
|
939
960
|
* sleep 2; done`. This arm accepts EXACTLY that grammar and nothing else. Returns the rejection
|
|
940
961
|
* reason, or undefined when the command matches the grammar (⇒ safe to treat as reversible).
|
|
941
962
|
*
|
|
@@ -162,7 +162,95 @@ export function formatOutOfRootReadApprovalOption(directory) {
|
|
|
162
162
|
export const NO_PATH_OPERAND_COMMANDS = new Set([
|
|
163
163
|
"pwd", "echo", "printf", "whoami", "uname", "which", "tr", "basename", "dirname",
|
|
164
164
|
"cal", "uptime", "id", "groups", "nproc", "locale", "free", "true", "false", "seq", "expr", "type", "sleep",
|
|
165
|
+
"test", "[",
|
|
165
166
|
]);
|
|
167
|
+
export const NO_PATH_OPERAND_EVALUATORS = new Set(["test", "["]);
|
|
168
|
+
export const DECLARATION_BUILTINS = new Set(["export", "declare", "typeset", "local", "readonly"]);
|
|
169
|
+
export const INERT_BUILTINS = new Set(["echo", "true", "false", "pwd", ...DECLARATION_BUILTINS]);
|
|
170
|
+
const MESSAGE_SLOTS = {
|
|
171
|
+
git: {
|
|
172
|
+
globalPlain: ["-p", "--paginate", "-P", "--no-pager", "--bare", "--no-replace-objects", "--literal-pathspecs", "--glob-pathspecs", "--noglob-pathspecs", "--icase-pathspecs", "--no-optional-locks"],
|
|
173
|
+
globalValue: ["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--config-env", "--super-prefix"],
|
|
174
|
+
subcommands: {
|
|
175
|
+
commit: { plain: "apsnvqeioz", optional: "Su", value: "mFCct", longValue: ["message", "file", "template", "pathspec-from-file", "author", "date", "cleanup", "fixup", "squash", "trailer", "reuse-message", "reedit-message"] },
|
|
176
|
+
tag: { plain: "asfdvle", optional: "n", value: "mFu", longValue: ["message", "file", "local-user", "cleanup", "trailer", "sort", "format", "contains", "no-contains", "points-at", "merged", "no-merged"] },
|
|
177
|
+
merge: { plain: "nqve", optional: "S", value: "mFsX", longValue: ["message", "file", "strategy", "strategy-option", "into-name", "cleanup"] },
|
|
178
|
+
stash: { plain: "pkuaqS", optional: "", value: "m", longValue: ["message", "pathspec-from-file"] },
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
export function messageSlotWords(program, words, programIndex) {
|
|
183
|
+
const out = new Set();
|
|
184
|
+
const row = MESSAGE_SLOTS[program];
|
|
185
|
+
if (row === undefined)
|
|
186
|
+
return out;
|
|
187
|
+
let j = programIndex + 1;
|
|
188
|
+
for (; j < words.length; j++) {
|
|
189
|
+
const w = words[j].folded;
|
|
190
|
+
if (!w.startsWith("-"))
|
|
191
|
+
break;
|
|
192
|
+
if (row.globalValue.includes(w))
|
|
193
|
+
j++;
|
|
194
|
+
else if (!row.globalPlain.includes(w) && !row.globalValue.some((o) => o.startsWith("--") && w.startsWith(`${o}=`)))
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
const sub = row.subcommands[words[j]?.folded ?? ""];
|
|
198
|
+
if (sub === undefined)
|
|
199
|
+
return out;
|
|
200
|
+
const settled = (k) => words[k] !== undefined && words[k].expands === false;
|
|
201
|
+
let pending;
|
|
202
|
+
for (let k = j + 1; k < words.length; k++) {
|
|
203
|
+
const w = words[k].folded;
|
|
204
|
+
if (pending !== undefined) {
|
|
205
|
+
if (pending === "message" && settled(k))
|
|
206
|
+
out.add(k);
|
|
207
|
+
pending = undefined;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (w === "--")
|
|
211
|
+
break;
|
|
212
|
+
if (!settled(k)) {
|
|
213
|
+
pending = "other";
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (!w.startsWith("-") || w === "-")
|
|
217
|
+
continue;
|
|
218
|
+
if (w.startsWith("--")) {
|
|
219
|
+
const eq = w.indexOf("=");
|
|
220
|
+
const name = w.slice(2, eq < 0 ? undefined : eq);
|
|
221
|
+
const takers = sub.longValue.filter((n) => n.startsWith(name));
|
|
222
|
+
const message = name.length > 0 && takers.length > 0 && takers.every((n) => n === "message") || name === "message";
|
|
223
|
+
if (eq >= 0) {
|
|
224
|
+
if (message)
|
|
225
|
+
out.add(k);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (takers.length > 0)
|
|
229
|
+
pending = message ? "message" : "other";
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const letters = w.slice(1);
|
|
233
|
+
for (let i = 0; i < letters.length; i++) {
|
|
234
|
+
const c = letters[i];
|
|
235
|
+
if (sub.plain.includes(c))
|
|
236
|
+
continue;
|
|
237
|
+
if (sub.optional.includes(c))
|
|
238
|
+
break;
|
|
239
|
+
if (sub.value.includes(c)) {
|
|
240
|
+
if (i < letters.length - 1) {
|
|
241
|
+
if (c === "m")
|
|
242
|
+
out.add(k);
|
|
243
|
+
}
|
|
244
|
+
else
|
|
245
|
+
pending = c === "m" ? "message" : "other";
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
pending = "other";
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
166
254
|
const XARGS_TARGETS_ACCEPTED_UNJUDGED = NO_PATH_OPERAND_COMMANDS;
|
|
167
255
|
export function isPathShapedToken(tok) {
|
|
168
256
|
return tok.includes("/") || tok.startsWith("~") || tok === "." || tok === "..";
|
|
@@ -18,8 +18,8 @@ export declare function containmentFaceSeatName(kind: ContainmentFaceKind, layer
|
|
|
18
18
|
* screen the seats on runs that never mount hands. The resolver itself also runs on every hands-less
|
|
19
19
|
* leg; this screen still fires first, so a garbage value refuses before any leg-shape branching. */
|
|
20
20
|
export declare function assertContainmentFaceValue(v: unknown, kind: ContainmentFaceKind, layer: ContainmentFaceLayer): ContainmentFace | undefined;
|
|
21
|
-
/** Inputs to {@link resolveContainmentFace} —
|
|
22
|
-
*
|
|
21
|
+
/** Inputs to {@link resolveContainmentFace} — structural/declaration facts; a permission mode enters only as
|
|
22
|
+
* the face its table row states ({@link modeFace}), never as a mode word. */
|
|
23
23
|
export interface ContainmentFaceInputs {
|
|
24
24
|
/** Which face is being resolved. Selects the seat spellings and the mint codes; the ORDER below is
|
|
25
25
|
* one body, identical for both. */
|
|
@@ -41,8 +41,13 @@ export interface ContainmentFaceInputs {
|
|
|
41
41
|
* tool-band assembly from spec-time facts (env kind / handsReadOnly / Bash exclusion — every
|
|
42
42
|
* exclusion source is spec-time-frozen, so this is always computable). When false, the roots fence
|
|
43
43
|
* is the ONLY boundary this face has, so no IMPLICIT default may open it; an EXPLICIT "open" on
|
|
44
|
-
* either seat still wins (row 4 of the order is a default, not a clamp). */
|
|
44
|
+
* either seat or the mode's face still wins (row 4 of the order is a default, not a clamp). */
|
|
45
45
|
fullShellReachable: boolean;
|
|
46
|
+
/** The face the leg's permission MODE states (`ModePolicy.writeFace`: `bypassPermissions` ⇒ "open"; absent ⇒
|
|
47
|
+
* the mode states nothing). Row 3′: read after the explicit seats and before the defaults — a seat's word (the
|
|
48
|
+
* deployment's ceiling, a task's tighten) outranks it, and neither the read-only mount nor org governance
|
|
49
|
+
* consults it. */
|
|
50
|
+
modeFace?: ContainmentFace;
|
|
46
51
|
/** Observation hook for the ONE silent branch of the order: row 1's deployment-seat clamp
|
|
47
52
|
* (readOnly mount + deps "open" + NO task seat). Fired exactly when the deps declaration was the
|
|
48
53
|
* deciding seat and the mount overrode it — not when a task-level "roots" pinned the same value
|
|
@@ -63,6 +68,7 @@ export interface ContainmentFaceInputs {
|
|
|
63
68
|
* 2. org-governed: the task seat's "open" refuses (task layer only tightens); deps "open" wins;
|
|
64
69
|
* otherwise ROOTS.
|
|
65
70
|
* 3. explicit seat: spec ?? deps.
|
|
71
|
+
* 3′. the mode's face ({@link ContainmentFaceInputs.modeFace}).
|
|
66
72
|
* 4. bash-less mount: ROOTS (the fence is the only boundary there — "the fence guards nothing bash
|
|
67
73
|
* reaches anyway" does not hold, so no implicit default may open it).
|
|
68
74
|
* 5. default: ROOTS — the engine never opens implicitly.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The READ station of the file tools (Read / Grep / Glob) — the read face's twin of the shell read station, one gate
|
|
3
|
+
* input shape ({@link ShellReadCheck}) so the gate, the approved-edit re-judge and the resumed leg's belt read both:
|
|
4
|
+
* before approval, where the call's declared path target lands is resolved exactly as the tool will resolve it
|
|
5
|
+
* (`resolveKey` over the same spelling, base, roots, deny table and containment face), and a target OUTSIDE the read
|
|
6
|
+
* roots is an ORDINARY question — a person answers it, a persisted `Read(//dir/**)` row or the auto-mode classifier
|
|
7
|
+
* may, a permission mode arbitrates it — with the directory whose grant clears it on the card. The deny table and
|
|
8
|
+
* every other refusal stay the tool's own: this station judges containment only, after the deny judgment.
|
|
9
|
+
*
|
|
10
|
+
* A call whose out-of-root read the gate put to a question is ADMITTED for that one target when the gate applies the
|
|
11
|
+
* verdict ({@link ShellReadVerdict.admit}): the tool reads it once ({@link FileReadStation.admitted}), on the canonical
|
|
12
|
+
* key the station judged — a target that resolves elsewhere by then is refused by the tool's own fence, and a verdict
|
|
13
|
+
* the gate never received (its wait elapsed, the judgment threw) admits nothing.
|
|
14
|
+
*/
|
|
15
|
+
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
16
|
+
import type { ContainmentFace } from "./containment-face.js";
|
|
17
|
+
import { type ReadDenyMatcher } from "./read-deny.js";
|
|
18
|
+
import type { ShellReadCheck } from "./shell-read-check.js";
|
|
19
|
+
export interface FileReadStation {
|
|
20
|
+
readonly check: ShellReadCheck;
|
|
21
|
+
/** The station's membership: the tool names whose declared read target it judges. */
|
|
22
|
+
readonly tools: ReadonlySet<string>;
|
|
23
|
+
/** Did the gate put THIS call's read of `canonicalKey` outside the roots to a question it then let through? Consumed
|
|
24
|
+
* on a match: the admission covers one read of one target. */
|
|
25
|
+
readonly admitted: (toolCallId: string | undefined, canonicalKey: string) => boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface FileReadStationOptions {
|
|
28
|
+
readonly env: ExecutionEnv;
|
|
29
|
+
readonly rootCanonical: string;
|
|
30
|
+
/** The extra read roots, read per call (a grant widens the live set). */
|
|
31
|
+
readonly roots: () => readonly string[];
|
|
32
|
+
readonly readDeny?: ReadDenyMatcher;
|
|
33
|
+
readonly readFace?: ContainmentFace;
|
|
34
|
+
readonly homeDir?: string;
|
|
35
|
+
/** The file tools this leg mounts (their catalog path target is the one judged). */
|
|
36
|
+
readonly tools: ReadonlySet<string>;
|
|
37
|
+
/** A target no answer may admit (the store-isolation rule's judgment, `rootAdmittingArtifactStore`): it is left to
|
|
38
|
+
* the tool's own refusal, no question is raised for it. */
|
|
39
|
+
readonly excluded?: (canonicalKey: string) => boolean;
|
|
40
|
+
/** A target the tools' own fence admits without the roots (the engine's background output file,
|
|
41
|
+
* `backgroundOutputReadExemption`): no question is put for it. */
|
|
42
|
+
readonly exempt?: (canonicalKey: string) => boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare function createFileReadStation(opts: FileReadStationOptions): FileReadStation;
|
|
45
|
+
/** One gate input over the leg's read stations: each call is judged by the station whose membership holds it. */
|
|
46
|
+
export declare function composeReadChecks(stations: ReadonlyArray<{
|
|
47
|
+
readonly check: ShellReadCheck;
|
|
48
|
+
readonly tools: ReadonlySet<string>;
|
|
49
|
+
}>): ShellReadCheck | undefined;
|