@sema-agent/core 7.14.0 → 7.16.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 +59 -0
- package/dist/core/ask-origin.d.ts +2 -2
- package/dist/core/checkpoint-store.d.ts +14 -15
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +4 -3
- package/dist/core/memory-engine/delegation-settlement.d.ts +37 -12
- package/dist/core/memory-engine/delegation-settlement.js +128 -39
- package/dist/core/memory-engine/engine.d.ts +9 -8
- package/dist/core/memory-engine/engine.js +115 -120
- package/dist/core/memory-engine/file-backend.d.ts +17 -5
- package/dist/core/memory-engine/file-backend.js +78 -34
- package/dist/core/memory-engine/index.d.ts +2 -2
- package/dist/core/memory-engine/index.js +2 -2
- package/dist/core/memory-engine/layout.d.ts +152 -54
- package/dist/core/memory-engine/layout.js +441 -104
- package/dist/core/memory-engine/types.d.ts +8 -3
- package/dist/core/memory-engine/types.js +5 -0
- package/dist/core/runner/abort-race.d.ts +3 -3
- package/dist/core/runner/active-skill-scope.d.ts +2 -2
- package/dist/core/runner/assemble-result.d.ts +29 -29
- package/dist/core/runner/checkpoint-scope.d.ts +4 -4
- package/dist/core/runner/clock-and-limits.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.d.ts +11 -11
- package/dist/core/runner/compaction-knobs.d.ts +4 -4
- package/dist/core/runner/compaction-seams.d.ts +5 -5
- package/dist/core/runner/contracts.d.ts +224 -226
- package/dist/core/runner/decide-continuation.d.ts +6 -6
- package/dist/core/runner/denial-limit-arms.d.ts +8 -8
- package/dist/core/runner/derived-route-fallback.d.ts +2 -2
- package/dist/core/runner/gate-exit.d.ts +6 -6
- package/dist/core/runner/git-status-frame.d.ts +7 -7
- package/dist/core/runner/inherited-ask-grants.d.ts +6 -6
- package/dist/core/runner/memory-capture-optout.d.ts +1 -1
- package/dist/core/runner/memory-consolidation-driver.d.ts +4 -4
- package/dist/core/runner/memory-consolidation.d.ts +6 -6
- package/dist/core/runner/park-commit.d.ts +6 -6
- package/dist/core/runner/permission-rule-lanes.d.ts +22 -20
- package/dist/core/runner/permission-rule-lanes.js +1 -1
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -4
- package/dist/core/runner/prepare-ask-lane.d.ts +3 -3
- package/dist/core/runner/prepare-boundary-parks.d.ts +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -5
- package/dist/core/runner/prepare-config-doors.d.ts +21 -21
- package/dist/core/runner/prepare-context-lane.d.ts +6 -6
- package/dist/core/runner/prepare-defer-classify.d.ts +3 -3
- package/dist/core/runner/prepare-defer-classify.js +12 -10
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
- package/dist/core/runner/prepare-file-history.d.ts +2 -2
- package/dist/core/runner/prepare-gate-stations.d.ts +8 -9
- package/dist/core/runner/prepare-gate-stations.js +2 -2
- package/dist/core/runner/prepare-hands-readface.d.ts +41 -41
- package/dist/core/runner/prepare-hands-readface.js +27 -29
- package/dist/core/runner/prepare-inherited-gate.d.ts +6 -6
- package/dist/core/runner/prepare-listings.d.ts +3 -3
- package/dist/core/runner/prepare-lsp.d.ts +3 -3
- package/dist/core/runner/prepare-memory-engine-session.d.ts +5 -5
- package/dist/core/runner/prepare-memory.js +6 -7
- package/dist/core/runner/prepare-offload-wrappers.d.ts +2 -2
- package/dist/core/runner/prepare-park-ask.d.ts +11 -12
- package/dist/core/runner/prepare-park-ask.js +3 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +6 -6
- package/dist/core/runner/prepare-policy-chain.js +2 -2
- package/dist/core/runner/prepare-prompt-inputs.d.ts +5 -5
- package/dist/core/runner/prepare-protocol-tools.d.ts +1 -1
- package/dist/core/runner/prepare-question-face.d.ts +4 -4
- package/dist/core/runner/prepare-run-refs.d.ts +11 -11
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-suspend-saga.d.ts +4 -4
- package/dist/core/runner/prepare-task.d.ts +12 -12
- package/dist/core/runner/prepare-task.js +5 -7
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +2 -3
- package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -4
- package/dist/core/runner/prepare-workspace-restore.d.ts +1 -1
- package/dist/core/runner/remote-env-retry.d.ts +3 -3
- package/dist/core/runner/resume-admission.d.ts +1 -1
- package/dist/core/runner/resume-claim.d.ts +1 -1
- package/dist/core/runner/resume-internals-and-config.d.ts +1 -1
- package/dist/core/runner/resume-policy-outcome.d.ts +1 -1
- package/dist/core/runner/resume-preflight.d.ts +1 -1
- package/dist/core/runner/resume-review-outcome.d.ts +1 -1
- package/dist/core/runner/run-brain-sinks.d.ts +1 -1
- package/dist/core/runner/run-clock-and-content.d.ts +4 -4
- package/dist/core/runner/run-compaction-machinery.d.ts +3 -3
- package/dist/core/runner/run-git-lane.d.ts +1 -1
- package/dist/core/runner/run-harness-handlers.d.ts +2 -2
- package/dist/core/runner/run-identity-wiring.d.ts +4 -4
- package/dist/core/runner/run-leg.d.ts +3 -3
- package/dist/core/runner/run-notification-lane.d.ts +2 -2
- package/dist/core/runner/run-reasoning-seat.d.ts +2 -2
- package/dist/core/runner/run-settle-and-teardown.d.ts +4 -4
- package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
- package/dist/core/runner/run-terminal-adoption.d.ts +5 -5
- package/dist/core/runner/runtask.d.ts +14 -14
- package/dist/core/runner/session-file-state-replay.d.ts +3 -3
- package/dist/core/runner/session-rule-policy.d.ts +2 -2
- package/dist/core/runner/steer-admission.d.ts +2 -2
- package/dist/core/runner/stream-halt-verbs.d.ts +1 -1
- package/dist/core/runner/stream-reap.d.ts +1 -1
- package/dist/core/runner/synthetic-tools.d.ts +8 -8
- package/dist/core/runner/teardown-bounded.d.ts +2 -2
- package/dist/core/runner/tool-defer-gate.d.ts +86 -0
- package/dist/core/runner/tool-defer-gate.js +57 -0
- package/dist/core/runner/tool-disclosure.d.ts +33 -69
- package/dist/core/runner/tool-disclosure.js +0 -43
- package/dist/core/runner/tool-end-body.d.ts +3 -3
- package/dist/core/runner/tool-face-overlay.d.ts +2 -2
- package/dist/core/runner/tool-output-projection.d.ts +2 -2
- package/dist/core/runner/turn-attachments.d.ts +53 -53
- package/dist/core/runner/usage-accounting.d.ts +4 -4
- package/dist/core/runner/workspace-path.d.ts +1 -1
- package/dist/core/runner-deps.d.ts +16 -9
- package/dist/core/task-spec.d.ts +8 -2
- package/dist/core/tool-spec.d.ts +7 -4
- package/dist/core/types.d.ts +1 -1
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/tools/fs/bash-readonly-classifier.d.ts +40 -40
- package/dist/tools/fs/encoding.d.ts +31 -40
- package/dist/tools/fs/fs-bash.d.ts +76 -35
- package/dist/tools/fs/fs-bash.js +86 -29
- package/dist/tools/fs/fs-pdf.d.ts +8 -8
- package/dist/tools/fs/fs-search-tools.d.ts +4 -4
- package/dist/tools/fs/fs-shared.d.ts +144 -158
- package/dist/tools/fs/fs-write.d.ts +8 -8
- package/dist/tools/fs/gh-rate-limit.d.ts +13 -14
- package/dist/tools/fs/index.d.ts +74 -78
- package/dist/tools/fs/notebook.d.ts +24 -25
- package/dist/tools/fs/pdf.d.ts +3 -3
- package/dist/tools/fs/read-deny.d.ts +22 -22
- package/dist/tools/fs/read-face.d.ts +21 -24
- package/dist/tools/fs/repo-map.d.ts +8 -8
- package/dist/tools/fs/safety.d.ts +116 -129
- package/dist/tools/fs/search.d.ts +63 -71
- package/package.json +5 -2
- package/test/export-surface.snapshot.json +9 -1
|
@@ -4,11 +4,11 @@ import { type CwdRef } from "./fs-shared.js";
|
|
|
4
4
|
import type { ReversibilityVerdict } from "../../core/types.js";
|
|
5
5
|
import { type BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* A parsed-command classifier for the `bash` tool, exposed as a
|
|
8
8
|
* `ToolSpec.reversibilityProbe`. A full shell is treated as egress+irreversible by DEFAULT; this probe is the
|
|
9
|
-
* "real parsed classifier" that lets a deployment safely auto-allow the provably-benign subset (the
|
|
10
|
-
* doctrine: shell⇒always-gate UNLESS a parsed classifier is wired).
|
|
11
|
-
*
|
|
9
|
+
* "real parsed classifier" that lets a deployment safely auto-allow the provably-benign subset (the
|
|
10
|
+
* doctrine: shell⇒always-gate UNLESS a parsed classifier is wired). It is COMPOUND-aware
|
|
11
|
+
* ({@link classifyCompoundReadonly}): a command is reversible ONLY if every `;`/`&&`/`||`/`|`
|
|
12
12
|
* connected segment is a bare command (no redirects/substitution/subshells/escapes/`&` anywhere — those
|
|
13
13
|
* whole-string reject, so it can't chain to `curl`/`git push`/`rm` or background past TaskStop) whose
|
|
14
14
|
* `argv[0]` is in the reversible allowlist (default
|
|
@@ -23,7 +23,7 @@ import { type BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
|
|
|
23
23
|
* Wire it on the `bash` tool with `irreversibility: "maybe"` (or via `TaskSpec.shellGate: "classify"`); without
|
|
24
24
|
* a classifier a deployment should mark `bash` `irreversibility: "always"` (`shellGate: "always"`) — fail-closed.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
26
|
+
* The DATA-side residual named above is closed for the read direction: pass `boundary` and a listed
|
|
27
27
|
* reader whose path arguments leave the allowed directories stops being reversible, so the gate asks
|
|
28
28
|
* instead of auto-allowing. Pass it as a FUNCTION wherever the working directory is observable (an
|
|
29
29
|
* in-task `cd` moves the base a relative operand resolves against, and the probe is called per command).
|
|
@@ -38,7 +38,7 @@ import { type BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
|
|
|
38
38
|
* safety argument lives on that function). Additive by construction: the plain verdict is tried
|
|
39
39
|
* first and is never overridden.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
41
|
+
* The RECURSIVE-READ demotion returns a STRUCTURED cause alongside the verdict. That
|
|
42
42
|
* demotion is the one arm whose reason is genuinely unrecoverable downstream: a recursive read is
|
|
43
43
|
* refused for what the traversal REACHES, and the reached set is by definition not in the command text
|
|
44
44
|
* an approval card shows. The cause is minted from the SAME classification pass that produced the
|
|
@@ -57,7 +57,48 @@ import { type BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
|
|
|
57
57
|
*/
|
|
58
58
|
export declare function bashReversibilityProbe(allow?: readonly string[], boundary?: BashReadonlyRootBoundary | (() => BashReadonlyRootBoundary | undefined)): (args: unknown) => ReversibilityVerdict;
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* The READ-BOUNDARY seat of the full shell: a `ToolSpec.reversibilityProbe` that answers exactly ONE
|
|
61
|
+
* question — does the deployment's read boundary object to where this command reads? — and nothing about
|
|
62
|
+
* the command's shape. It is the shell face of the rule every read face obeys: the structured readers
|
|
63
|
+
* (Read/Grep/Glob) refuse a deny-listed or out-of-root target; the shell reader gets a MANDATED ask for the
|
|
64
|
+
* same target. The engine installs it on Bash and Monitor whenever a real writable shell is mounted and the
|
|
65
|
+
* shellGate doctrine adds no residual-risk classifier of its own (`shellGate:"off"`, the default); under
|
|
66
|
+
* `"classify"` the doctrine installs {@link bashReversibilityProbe} instead, which composes THIS judgment
|
|
67
|
+
* with the read-only shape classifier, and under `"always"` the tier itself is the mandate and no probe runs.
|
|
68
|
+
* The boundary is therefore judged under every doctrine; the doctrine decides only what happens to the
|
|
69
|
+
* residual shell risk.
|
|
70
|
+
*
|
|
71
|
+
* The verdict, in the probe vocabulary the gate reads (`reversible` here means "the boundary raised no
|
|
72
|
+
* question — the seat vouches the call may run"):
|
|
73
|
+
* · the boundary DECLARED an objection — a deny-listed operand, a recursive walk under the deny judge, an
|
|
74
|
+
* operand outside the roots — ⇒ `{ reversible: false, mandated: true }` (+ the recursive-reach `cause`);
|
|
75
|
+
* · the boundary could NOT READ where the command reads — an unexpanded glob operand (the compound face
|
|
76
|
+
* reports it as undecided), a `~`-rooted operand with no home declared, a working-directory move the walk
|
|
77
|
+
* cannot model — ⇒ `{ reversible: false }` (fail-closed; a plain ask, which a stored allow rule may retire —
|
|
78
|
+
* the seat did not declare anything, it declined to guess);
|
|
79
|
+
* · otherwise ⇒ `{ reversible: true }`. This includes every command whose SHAPE the read faces refuse whole
|
|
80
|
+
* (an unlisted program, a redirection, a substitution, a segment that is not a reader): those shapes carry
|
|
81
|
+
* no read-face verdict, so this seat has no question to ask — the residual is the doctrine's, and under
|
|
82
|
+
* `"off"` the doctrine asks nothing. `run_in_background` is likewise not this seat's question (it changes
|
|
83
|
+
* WHEN the command runs, never WHERE it reads).
|
|
84
|
+
*
|
|
85
|
+
* Reach = the read faces' reach, and nothing wider: the compound face walks the operands of a command whose
|
|
86
|
+
* every segment is a listed reader, and the bounded poll-loop face walks a loop body of listed readers. A
|
|
87
|
+
* read hidden in a shape the faces refuse whole (`cat x | <unlisted>`, `$(cat x)`, `cat $DIR/x`, a launcher
|
|
88
|
+
* `env cat x`, a path-prefixed `/bin/cat x`) is not seen here — deny-listed or out-of-root alike — exactly
|
|
89
|
+
* the shapes the `"classify"` doctrine exists to ask about. The text-level containment gate the classify
|
|
90
|
+
* seat consults on its demotion arms is deliberately not consulted here ({@link boundaryDeclared}: it may
|
|
91
|
+
* add a mandate to an ask, never originate one). The poll-loop face reports its refusal as one sentence,
|
|
92
|
+
* so the boundary's share of it is read by removing the boundary's judging seats
|
|
93
|
+
* ({@link pollLoopBoundaryVerdict}).
|
|
94
|
+
*
|
|
95
|
+
* The reader set is the engine's classify set ({@link BASH_CLASSIFY_DEFAULT_ALLOW}) — here it is NOT an
|
|
96
|
+
* auto-allow list but the set of programs whose operands the faces read; a wider set means more reads are
|
|
97
|
+
* judged, never that more runs are vouched.
|
|
98
|
+
*/
|
|
99
|
+
export declare function bashReadBoundaryProbe(boundary: BashReadonlyRootBoundary | (() => BashReadonlyRootBoundary | undefined)): (args: unknown) => ReversibilityVerdict;
|
|
100
|
+
/**
|
|
101
|
+
* The FULL shell's contract id, single-sourced: both shell faces share the wire
|
|
61
102
|
* name "Bash", so this id is the ONE structural discriminator between the write-capable shell and
|
|
62
103
|
* the read-only allowlist face (`core.bash_readonly@1`). Consumed by prepare-task's
|
|
63
104
|
* fullShellReachable roster assertion (its first load-bearing consumer).
|
|
@@ -66,36 +107,36 @@ export { FULL_SHELL_CONTRACT_ID } from "../../core/tool-catalog-entries.js";
|
|
|
66
107
|
/** The CC-verbatim exit-1 interpretation for `command`, or undefined when exit 1 means a real error.
|
|
67
108
|
* Conservative parse: last `;`/`&&`/`||`/newline statement → last `|` pipeline segment → leading
|
|
68
109
|
* command name (env-assignments skipped, path prefix stripped); `git grep`/`git diff` special-cased
|
|
69
|
-
* (CC cLp). Exported for
|
|
110
|
+
* (CC `cLp`). Exported for its unit tests. */
|
|
70
111
|
export declare function bashExitOneInterpretation(command: string): string | undefined;
|
|
71
112
|
export declare function canAutoBackground(command: string, depth?: number): boolean;
|
|
72
113
|
/**
|
|
73
114
|
* `bash` (effect:write) — a full shell. ⚠️ It runs with `rootCanonical` as the initial cwd but is NOT
|
|
74
115
|
* sandboxed: a command can `cd` out, read/write/delete any path the process can reach, and use the
|
|
75
|
-
* network. `rootPath` is a file-tool guard rail, NOT a bash sandbox
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* persists across calls
|
|
116
|
+
* network. `rootPath` is a file-tool guard rail, NOT a bash sandbox — real isolation is the
|
|
117
|
+
* deployment's job (inject a chroot/container `ExecutionEnv`). Every call still goes through the
|
|
118
|
+
* tool-policy gate, which a multi-tenant deployment MUST wire to constrain it. The cwd
|
|
119
|
+
* persists across calls: a per-task `cwdRef` starts at `rootCanonical` and is updated
|
|
79
120
|
* from the shell's final pwd after each command.
|
|
80
121
|
*/
|
|
81
122
|
export declare function createBashTool(env: ExecutionEnv, rootCanonical: string, coAuthor?: string | false, cwdRef?: CwdRef, taskOpts?: {
|
|
82
123
|
taskRegistry?: TaskRegistry;
|
|
83
124
|
taskOwner?: string;
|
|
84
125
|
taskScope?: string;
|
|
85
|
-
/** (
|
|
126
|
+
/** (mirrors MonitorToolOptions.sessionId): when the task runs INSIDE a session,
|
|
86
127
|
* a background command registers session-resident (owner = sessionId, sessionScoped flag) — it
|
|
87
128
|
* survives the run teardown like CC's bg shells and is reaped at the session terminal. Absent ⇒
|
|
88
129
|
* run-scoped registration exactly as before (killed-with-receipt at teardown). */
|
|
89
130
|
sessionId?: string;
|
|
90
|
-
/**
|
|
131
|
+
/** Completion-notification sink — a finished background command fires ONE
|
|
91
132
|
* task-notification (priority "next": boundary interrupt, CC LocalShellTask posture). */
|
|
92
133
|
onTaskNotification?: (n: import("../../core/task-notification.js").TaskNotificationPayload, opts?: {
|
|
93
134
|
priority?: "now" | "next" | "later";
|
|
94
135
|
}) => void;
|
|
95
|
-
/**
|
|
136
|
+
/** Per-tool-call detach hub — a fired signal adopts the running command as background. */
|
|
96
137
|
detachHub?: import("../../core/tool-detach.js").ToolDetachHub;
|
|
97
138
|
/**
|
|
98
|
-
*
|
|
139
|
+
* EXPLICIT deployment opt-in: on this command's own
|
|
99
140
|
* timeout, an eligible foreground command (see `canAutoBackground`'s own docstring — a
|
|
100
141
|
* DELIBERATELY simplified, narrower-than-CC classifier) is adopted as a background task instead
|
|
101
142
|
* of being killed. Defaults to `false` (the pre-existing, unconditional kill-on-timeout behavior)
|
|
@@ -110,7 +151,7 @@ export declare function createBashTool(env: ExecutionEnv, rootCanonical: string,
|
|
|
110
151
|
*/
|
|
111
152
|
autoBackgroundOnTimeout?: boolean;
|
|
112
153
|
/**
|
|
113
|
-
*
|
|
154
|
+
* Mirrors {@link import("../../core/types.js").TaskSpec.oneShot}: this run has no later
|
|
114
155
|
* turn for an async background notification to land in (a headless `-p` process exits once the
|
|
115
156
|
* turn ends). Branches the background-launch receipt's guidance toward an active block-wait
|
|
116
157
|
* instruction instead of "you will be notified — do not poll", the same failure form
|
|
@@ -119,18 +160,18 @@ export declare function createBashTool(env: ExecutionEnv, rootCanonical: string,
|
|
|
119
160
|
*/
|
|
120
161
|
oneShot?: boolean;
|
|
121
162
|
/**
|
|
122
|
-
*
|
|
163
|
+
* The EXTRA containment roots of the structured file tools (additionalDirectories,
|
|
123
164
|
* canonical) — combined with `rootCanonical` and consulted ONLY for the post-`cd` disclosure
|
|
124
165
|
* note (a committed cwd outside every root gets one trailer line saying the structured tools'
|
|
125
166
|
* relative paths now resolve there and may be refused). Bash itself stays deliberately
|
|
126
167
|
* unconfined; passing this never gates anything.
|
|
127
168
|
*/
|
|
128
169
|
additionalRoots?: readonly string[];
|
|
129
|
-
/**
|
|
170
|
+
/** Override of the `timeout` parameter's DEFAULT budget, in ms — see
|
|
130
171
|
* {@link import("./index.js").HandsToolkitOptions.bashDefaultTimeoutMs} for the resolution
|
|
131
172
|
* contract (options over env over constant; invalid values discarded). */
|
|
132
173
|
bashDefaultTimeoutMs?: number;
|
|
133
|
-
/**
|
|
174
|
+
/** Override of the `timeout` parameter's engine CEILING, in ms — only-widen
|
|
134
175
|
* vs the resolved default; see {@link import("./index.js").HandsToolkitOptions.bashMaxTimeoutMs}. */
|
|
135
176
|
bashMaxTimeoutMs?: number;
|
|
136
177
|
/** Structured sink for this leg's timeout-cap discard announcements — consumed by
|
|
@@ -138,36 +179,36 @@ export declare function createBashTool(env: ExecutionEnv, rootCanonical: string,
|
|
|
138
179
|
* {@link import("./index.js").HandsToolkitOptions.onNotice} for the replace-vs-warn contract). */
|
|
139
180
|
onNotice?: (n: import("../../core/types.js").EngineNotice) => void;
|
|
140
181
|
/**
|
|
141
|
-
*
|
|
182
|
+
* Whether the Monitor tool is on THIS run's roster (the Runner's own mount predicate is
|
|
142
183
|
* `backgroundTaskToolsActive`; it, not this tool, mounts Monitor). Read by the SR-2 gh rate-limit
|
|
143
184
|
* hint, whose closing clause teaches the Monitor tool: `false` ⇒ the clause is dropped (the sleep
|
|
144
185
|
* advice stays), absent/`true` ⇒ historic full wording (a standalone toolkit consumer may well have
|
|
145
186
|
* mounted Monitor itself — the omitted default must not silently rewrite its hint).
|
|
146
187
|
*/
|
|
147
188
|
monitorToolActive?: boolean;
|
|
148
|
-
/**
|
|
189
|
+
/** The session's reminder provenance mark: stamped on the gh rate-limit
|
|
149
190
|
* hint's open tag by the mint home (see {@link import("./index.js").HandsToolkitOptions.reminderMark}).
|
|
150
191
|
* Absent ⇒ historic bare tag. */
|
|
151
192
|
reminderMark?: string;
|
|
152
193
|
}): AgentTool;
|
|
153
194
|
/**
|
|
154
|
-
* `bash_readonly` (effect:read) — a restricted shell for the verifier read-only boundary
|
|
155
|
-
*
|
|
156
|
-
* read-only filter, but it is NOT a policy circumvention — it still goes through the
|
|
157
|
-
* a read can still be a side channel
|
|
195
|
+
* `bash_readonly` (effect:read) — a restricted shell for the verifier read-only boundary: a single
|
|
196
|
+
* allowlisted, bare command with no shell operators. effect:read lets it survive the verifier's
|
|
197
|
+
* read-only filter, but it is NOT a policy circumvention — it still goes through the tool-policy gate,
|
|
198
|
+
* because a read can still be a side channel (dumping a secret file). The allowlist is a coarse pre-filter;
|
|
158
199
|
* the policy gate is the authoritative control.
|
|
159
200
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
201
|
+
* Hard refusal, not a demotion: the allowlist vets argv[0] and nothing else, so without a path
|
|
202
|
+
* boundary an allowlisted reader could name ANY file on the host and get it (`cat /etc/passwd` would go
|
|
203
|
+
* straight through). The full `bash` leg carries the same boundary as a DEMOTION — that leg's verdict
|
|
204
|
+
* feeds an approval gate, so "outside the roots" can become a prompt. This face has no
|
|
164
205
|
* such channel: `effect:"read"` is precisely what lets it run where the write shell may not (the verifier's
|
|
165
206
|
* read-only band), so an out-of-root read here is not something to escalate, it is outside what the tool
|
|
166
207
|
* is. It is refused, fail-closed, before anything executes — including the conservative direction, where
|
|
167
208
|
* the operand cannot be resolved statically (there is nothing to degrade to).
|
|
168
209
|
*/
|
|
169
210
|
export declare function createBashReadonlyTool(env: ExecutionEnv, rootCanonical: string, allow: ReadonlySet<string>, opts?: {
|
|
170
|
-
/**
|
|
211
|
+
/** Same timeout-cap overrides the full `bash` leg takes — see
|
|
171
212
|
* {@link import("./index.js").HandsToolkitOptions.bashDefaultTimeoutMs} /
|
|
172
213
|
* {@link import("./index.js").HandsToolkitOptions.bashMaxTimeoutMs} (类修完整域: both foreground
|
|
173
214
|
* legs share runShell's clamp, so both must share the configurable resolution). */
|
|
@@ -176,21 +217,21 @@ export declare function createBashReadonlyTool(env: ExecutionEnv, rootCanonical:
|
|
|
176
217
|
/** Structured sink for the timeout-cap discard announcements — same seat the full `bash` leg
|
|
177
218
|
* takes (both foreground legs share the resolver, so both must share the sink). */
|
|
178
219
|
onNotice?: (n: import("../../core/types.js").EngineNotice) => void;
|
|
179
|
-
/**
|
|
220
|
+
/** The extra containment roots the structured file tools got (the CC `--add-dir` family,
|
|
180
221
|
* canonical). A read this deployment already sanctions for Read/Grep/Glob is equally sanctioned
|
|
181
222
|
* here — the two faces must not disagree about which directories exist for this session. */
|
|
182
223
|
additionalRoots?: readonly string[];
|
|
183
224
|
}): AgentTool;
|
|
184
225
|
/**
|
|
185
|
-
*
|
|
226
|
+
* `TaskOutput` — read a background shell's NEW output
|
|
186
227
|
* since the last call (cursor), by task_id. Optional legacy `filter` regex is applied BEFORE the per-poll truncation so a watched line survives even when it
|
|
187
228
|
* falls in a high-throughput middle window. Untrusted process output is fenced (delimitUntrusted) — observe-only,
|
|
188
229
|
* never re-fed as instructions.
|
|
189
230
|
*/
|
|
190
231
|
export declare function createEnvTaskOutputTool(env: ExecutionEnv): AgentTool;
|
|
191
|
-
/**
|
|
232
|
+
/** `TaskStop` — terminate a background shell by task_id.
|
|
192
233
|
*
|
|
193
|
-
*
|
|
234
|
+
* This band kills ENV-DIRECT (it mounts precisely when the toolkit has
|
|
194
235
|
* no registry — the createHandsToolkit ternary routes registry deployments to createTaskStopTool), so a
|
|
195
236
|
* row for the SAME shell in the process-local {@link defaultTaskRegistry} (a Runner-mounted run sharing
|
|
196
237
|
* this env) used to settle via the watcher's no-claimant floor as stoppedBy:"system". The tool now marks
|
package/dist/tools/fs/fs-bash.js
CHANGED
|
@@ -25,40 +25,100 @@ function operandFamily(paths) {
|
|
|
25
25
|
export function bashReversibilityProbe(allow, boundary) {
|
|
26
26
|
const allowSet = new Set(allow ?? BASH_CLASSIFY_DEFAULT_ALLOW);
|
|
27
27
|
return (args) => {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
if (typeof command !== "string")
|
|
28
|
+
const command = shellCommandOf(args);
|
|
29
|
+
if (command === undefined)
|
|
31
30
|
return { reversible: false };
|
|
32
31
|
const resolved = typeof boundary === "function" ? boundary() : boundary;
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const backgrounded =
|
|
32
|
+
const boundaryGate = (verdict) => readBoundaryMandate(command, allowSet, resolved, verdict);
|
|
33
|
+
const outOfRootGate = () => readBoundaryMandate(command, allowSet, resolved, {});
|
|
34
|
+
const backgrounded = isBackgroundShellCall(args);
|
|
36
35
|
const detailed = classifyCompoundReadonlyDetailed(command, allowSet, resolved);
|
|
37
36
|
if (backgrounded)
|
|
38
37
|
return { reversible: false, ...boundaryGate(detailed) };
|
|
39
38
|
if (detailed.reason === undefined) {
|
|
40
39
|
if (detailed.undecidedPaths !== undefined && detailed.undecidedPaths.length > 0) {
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
const others = detailed.undecidedPaths.filter((p) => !recursiveSet.has(p));
|
|
45
|
-
return {
|
|
46
|
-
reversible: false,
|
|
47
|
-
...boundaryGate(detailed),
|
|
48
|
-
cause: {
|
|
49
|
-
code: RECURSIVE_READ_CAUSE_CODE,
|
|
50
|
-
roots: operandFamily(recursive),
|
|
51
|
-
...(others.length > 0 ? { further: operandFamily(others) } : {}),
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
}
|
|
40
|
+
const cause = recursiveReadCause(detailed);
|
|
41
|
+
if (cause !== undefined)
|
|
42
|
+
return { reversible: false, ...boundaryGate(detailed), cause };
|
|
55
43
|
return { reversible: false, ...outOfRootGate() };
|
|
56
44
|
}
|
|
57
45
|
return { reversible: true };
|
|
58
46
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
const loopRefusal = classifyBoundedReadonlyPollLoop(command, allowSet, resolved);
|
|
48
|
+
if (loopRefusal === undefined)
|
|
49
|
+
return { reversible: true };
|
|
50
|
+
return { reversible: false, ...(pollLoopBoundaryVerdict(command, allowSet, resolved, loopRefusal) === "declared" ? { mandated: true } : boundaryGate(detailed)) };
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function attributeRefusal(face, resolved, fullRefusal) {
|
|
54
|
+
if (resolved === undefined)
|
|
55
|
+
return "shape";
|
|
56
|
+
const { denyMatch: _deny, ...withoutDenyJudge } = resolved;
|
|
57
|
+
const opened = face({ ...withoutDenyJudge, face: "open" });
|
|
58
|
+
if (opened === undefined || opened !== fullRefusal)
|
|
59
|
+
return "declared";
|
|
60
|
+
return face(undefined) === opened ? "shape" : "unread";
|
|
61
|
+
}
|
|
62
|
+
function pollLoopBoundaryVerdict(command, allowSet, resolved, fullRefusal) {
|
|
63
|
+
return attributeRefusal((b) => classifyBoundedReadonlyPollLoop(command, allowSet, b), resolved, fullRefusal);
|
|
64
|
+
}
|
|
65
|
+
function boundaryDeclared(verdict) {
|
|
66
|
+
return denyJudgeSpoke(verdict) || verdict.outOfRootRead === true;
|
|
67
|
+
}
|
|
68
|
+
function denyJudgeSpoke(verdict) {
|
|
69
|
+
return verdict.readDenied === true || (verdict.recursiveReadPaths !== undefined && verdict.recursiveReadPaths.length > 0);
|
|
70
|
+
}
|
|
71
|
+
function shellCommandOf(args) {
|
|
72
|
+
const command = args?.command;
|
|
73
|
+
return typeof command === "string" ? command : undefined;
|
|
74
|
+
}
|
|
75
|
+
function isBackgroundShellCall(args) {
|
|
76
|
+
return args?.run_in_background === true;
|
|
77
|
+
}
|
|
78
|
+
function readBoundaryMandate(command, allowSet, resolved, verdict) {
|
|
79
|
+
if (denyJudgeSpoke(verdict))
|
|
80
|
+
return { mandated: true };
|
|
81
|
+
return resolved !== undefined && classifyOutOfRootReadGate(command, allowSet, resolved).gated ? { mandated: true } : {};
|
|
82
|
+
}
|
|
83
|
+
function recursiveReadCause(detailed) {
|
|
84
|
+
const recursive = detailed.recursiveReadPaths;
|
|
85
|
+
if (recursive === undefined || recursive.length === 0)
|
|
86
|
+
return undefined;
|
|
87
|
+
const recursiveSet = new Set(recursive);
|
|
88
|
+
const others = (detailed.undecidedPaths ?? []).filter((p) => !recursiveSet.has(p));
|
|
89
|
+
return {
|
|
90
|
+
code: RECURSIVE_READ_CAUSE_CODE,
|
|
91
|
+
roots: operandFamily(recursive),
|
|
92
|
+
...(others.length > 0 ? { further: operandFamily(others) } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function bashReadBoundaryProbe(boundary) {
|
|
96
|
+
const allowSet = new Set(BASH_CLASSIFY_DEFAULT_ALLOW);
|
|
97
|
+
return (args) => {
|
|
98
|
+
const command = shellCommandOf(args);
|
|
99
|
+
if (command === undefined)
|
|
100
|
+
return { reversible: false };
|
|
101
|
+
const resolved = typeof boundary === "function" ? boundary() : boundary;
|
|
102
|
+
if (resolved === undefined)
|
|
103
|
+
return { reversible: true };
|
|
104
|
+
const detailed = classifyCompoundReadonlyDetailed(command, allowSet, resolved);
|
|
105
|
+
if (boundaryDeclared(detailed)) {
|
|
106
|
+
const cause = recursiveReadCause(detailed);
|
|
107
|
+
return { reversible: false, mandated: true, ...(cause !== undefined ? { cause } : {}) };
|
|
108
|
+
}
|
|
109
|
+
if (detailed.reason === undefined) {
|
|
110
|
+
return detailed.undecidedPaths !== undefined && detailed.undecidedPaths.length > 0 ? { reversible: false } : { reversible: true };
|
|
111
|
+
}
|
|
112
|
+
const compound = attributeRefusal((b) => classifyCompoundReadonlyDetailed(command, allowSet, b).reason, resolved, detailed.reason);
|
|
113
|
+
if (compound === "declared")
|
|
114
|
+
return { reversible: false, mandated: true };
|
|
115
|
+
if (compound === "unread")
|
|
116
|
+
return { reversible: false };
|
|
117
|
+
const loopRefusal = classifyBoundedReadonlyPollLoop(command, allowSet, resolved);
|
|
118
|
+
if (loopRefusal === undefined)
|
|
119
|
+
return { reversible: true };
|
|
120
|
+
const loop = pollLoopBoundaryVerdict(command, allowSet, resolved, loopRefusal);
|
|
121
|
+
return loop === "shape" ? { reversible: true } : loop === "declared" ? { reversible: false, mandated: true } : { reversible: false };
|
|
62
122
|
};
|
|
63
123
|
}
|
|
64
124
|
export { FULL_SHELL_CONTRACT_ID } from "../../core/tool-catalog-entries.js";
|
|
@@ -563,13 +623,10 @@ export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = {
|
|
|
563
623
|
})),
|
|
564
624
|
}),
|
|
565
625
|
isConcurrencySafe: (args) => {
|
|
566
|
-
const
|
|
567
|
-
if (
|
|
568
|
-
return false;
|
|
569
|
-
const bg = args.run_in_background;
|
|
570
|
-
if (bg === true)
|
|
626
|
+
const command = shellCommandOf(args);
|
|
627
|
+
if (command === undefined || isBackgroundShellCall(args))
|
|
571
628
|
return false;
|
|
572
|
-
return coarseReadonlyCheck(
|
|
629
|
+
return coarseReadonlyCheck(command, new Set(BASH_READONLY_DEFAULT_ALLOW)) === undefined;
|
|
573
630
|
},
|
|
574
631
|
execute: async (args, ctx) => {
|
|
575
632
|
const { command, timeout, run_in_background, description } = args;
|
|
@@ -4,7 +4,7 @@ import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
|
4
4
|
import { type PdfModelCapabilities } from "./pdf.js";
|
|
5
5
|
import { type ReadImageDownsamplerOption } from "./fs-shared.js";
|
|
6
6
|
import { type ReminderDisclosureCounts } from "../../core/reminder-disclosure.js";
|
|
7
|
-
/**
|
|
7
|
+
/** The Read tool's disclosure state, threaded into the PDF TEXT legs (the
|
|
8
8
|
* two `pdftotext` extraction arms — the only PDF returns with a model-facing text projection of
|
|
9
9
|
* the document; the native document block and rendered page images have no text to scan). Shares
|
|
10
10
|
* the Read closure's throttle windows so a PDF and its text read dedup on the same file key. */
|
|
@@ -21,7 +21,7 @@ type ReadPdfReturn = string | {
|
|
|
21
21
|
details: unknown;
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
|
-
* PDF read pipeline (CC FileReadTool parity — mechanism
|
|
24
|
+
* PDF read pipeline (CC FileReadTool parity — mechanism + limits in fs/pdf.ts):
|
|
25
25
|
* - no `pages` → whole file as a native `document` block, gated at ≤{@link PDF_TARGET_RAW_SIZE} raw and
|
|
26
26
|
* ≤{@link PDF_INLINE_PAGE_THRESHOLD} pages (page count via `pdfinfo`, byte-scan fallback; unknown = fail-open,
|
|
27
27
|
* CC-identical — the size gate still bounds the request);
|
|
@@ -30,11 +30,11 @@ type ReadPdfReturn = string | {
|
|
|
30
30
|
* degradation with the working alternative, never a fake success.
|
|
31
31
|
* Wire discipline: the base64 payload rides `details.file` only while ≤48K chars (same OMIT rule as the
|
|
32
32
|
* image variant — a bigger card would be dropped whole by the card projector's 4×cap and blind the shell).
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* code and the pages/fallback-level disclosure invisible to a host.
|
|
33
|
+
* The budget rule only means anything while `"document"` is registered on `CC_DETAIL_TYPES`: without
|
|
34
|
+
* that word every `document` card, sized or not, is dropped at the gate, which makes the 48K rule dead
|
|
35
|
+
* code and the pages/fallback-level disclosure invisible to a host.
|
|
36
36
|
*
|
|
37
|
-
* Degradation chain
|
|
37
|
+
* Degradation chain (the brain-level placeholder is NOT the end state): when the SERVING model
|
|
38
38
|
* cannot take a native document block (`caps.document === false` — e.g. any openai-compatible API), the
|
|
39
39
|
* whole-PDF path degrades IN THE TOOL (the only layer holding env.exec), best first:
|
|
40
40
|
* 1. `pdftotext -layout` text extraction → the content arrives as TEXT (Read byte-cap discipline applies);
|
|
@@ -42,10 +42,10 @@ type ReadPdfReturn = string | {
|
|
|
42
42
|
* pages via the existing `pdftoppm` pipeline (note directs `pages` for more);
|
|
43
43
|
* 3. honest placeholder explaining WHY levels 1–2 did not run + the Bash self-help.
|
|
44
44
|
* Every degraded return carries `details.fallback = { level, reason }` (telemetry on the structured frame).
|
|
45
|
-
* `caps` absent ⇒ fully capable (
|
|
45
|
+
* `caps` absent ⇒ fully capable (native document block; the brain placeholder still guards).
|
|
46
46
|
*/
|
|
47
47
|
export declare function readPdfFile(env: ExecutionEnv, path: string, key: string, pages: string | undefined, signal: AbortSignal | undefined, downsamplerOpt: ReadImageDownsamplerOption, cwd: string, preRead?: Uint8Array, caps?: PdfModelCapabilities, readDeny?: import("./read-deny.js").ReadDenyMatcher, disclosure?: PdfReminderDisclosure): Promise<ReadPdfReturn>;
|
|
48
|
-
/**
|
|
48
|
+
/** readPdfFile's own return type stays `ReadPdfReturn` (its INTERNAL string-means-error dispatch
|
|
49
49
|
* contract, shared with pdfPagesToImageBlocks) — the isError flag is applied once, here, at the tool's
|
|
50
50
|
* actual execute() boundary, not inside the helper. */
|
|
51
51
|
export declare function pdfResultToToolReturn(r: ReadPdfReturn): ReturnType<typeof errorResult> | Exclude<ReadPdfReturn, string>;
|
|
@@ -5,10 +5,10 @@ import type { CwdRef } from "./fs-shared.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* The Grep card's details assembly, PURE over the engine text ({mode, offset} from the request) —
|
|
7
7
|
* exported so the text→structured mapping is pinnable with synthetic texts (the byte-truncation and
|
|
8
|
-
* fenced-partial shapes are impractical to construct through a live tool call).
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* fenced-partial shapes are impractical to construct through a live tool call). PATH IDENTITY comes
|
|
9
|
+
* off the engines' served rows, not the text (both legs supply them); the counts and totals below
|
|
10
|
+
* still read the engine's own honesty markers out of the text, which is what keeps this seam the
|
|
11
|
+
* honesty boundary.
|
|
12
12
|
*/
|
|
13
13
|
export declare function grepDetailFields(text: string, mode: "files_with_matches" | "content" | "count", offset?: number, structuredRows?: readonly import("./search.js").GrepRow[]): Record<string, unknown>;
|
|
14
14
|
export declare function createGrepTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: readonly string[], readDeny?: ReadDenyMatcher, readFace?: ReadFace, cwdRef?: CwdRef): AgentTool;
|