@sema-agent/core 7.45.0 → 7.47.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 +298 -1
- package/dist/agents/extra-tool-names.d.ts +65 -0
- package/dist/agents/extra-tool-names.js +124 -0
- package/dist/agents/subagent.d.ts +17 -5
- package/dist/agents/subagent.js +33 -25
- package/dist/agents/tool-filter.d.ts +17 -1
- package/dist/agents/tool-filter.js +7 -0
- package/dist/core/agent-config-dir.d.ts +20 -0
- package/dist/core/agent-config-dir.js +49 -0
- package/dist/core/allow-entry.d.ts +6 -4
- package/dist/core/allow-entry.js +6 -5
- package/dist/core/ask-origin.d.ts +35 -12
- package/dist/core/ask-origin.js +24 -7
- package/dist/core/checkpoint-store.d.ts +39 -2
- package/dist/core/effective-path-target.d.ts +136 -4
- package/dist/core/effective-path-target.js +110 -2
- package/dist/core/engine-notice.d.ts +12 -4
- package/dist/core/gate-fold.js +5 -2
- package/dist/core/gate-lanes.js +11 -4
- package/dist/core/gate-outcome.d.ts +4 -2
- package/dist/core/gate-outcome.js +2 -2
- package/dist/core/governance-codes.d.ts +3 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/hooks.d.ts +3 -0
- package/dist/core/path-rule-binding.d.ts +65 -0
- package/dist/core/path-rule-binding.js +99 -0
- package/dist/core/permission-rule-model.d.ts +59 -24
- package/dist/core/permission-rule-model.js +48 -44
- package/dist/core/permission-rule-provider.d.ts +7 -0
- package/dist/core/permission-rule-provider.js +10 -3
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +6 -2
- package/dist/core/permission-rule-sync.js +2 -2
- package/dist/core/permission-rules.d.ts +26 -45
- package/dist/core/permission-rules.js +77 -57
- package/dist/core/runner/child-tree.d.ts +97 -0
- package/dist/core/runner/child-tree.js +104 -0
- package/dist/core/runner/construction-doors.d.ts +5 -0
- package/dist/core/runner/construction-doors.js +6 -0
- package/dist/core/runner/contracts.d.ts +46 -0
- package/dist/core/runner/gate-exit.d.ts +4 -1
- package/dist/core/runner/gate-exit.js +5 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
- package/dist/core/runner/permission-rule-lanes.js +18 -12
- package/dist/core/runner/persisted-path-rows.d.ts +31 -7
- package/dist/core/runner/persisted-path-rows.js +31 -12
- package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
- package/dist/core/runner/prepare-ask-lane.js +4 -2
- package/dist/core/runner/prepare-execution-env.d.ts +5 -2
- package/dist/core/runner/prepare-execution-env.js +10 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
- package/dist/core/runner/prepare-gate-stations.js +2 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
- package/dist/core/runner/prepare-hands-readface.js +11 -11
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
- package/dist/core/runner/prepare-inherited-gate.js +8 -2
- package/dist/core/runner/prepare-park-ask.d.ts +3 -0
- package/dist/core/runner/prepare-park-ask.js +5 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
- package/dist/core/runner/prepare-policy-chain.js +13 -5
- package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -1
- package/dist/core/runner/prepare-task.js +37 -18
- package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
- package/dist/core/runner/prepare-turn-wiring.js +2 -1
- package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
- package/dist/core/runner/prepare-workspace-restore.js +1 -0
- package/dist/core/runner/resume-apply.js +17 -3
- package/dist/core/runner/resume-checkpoint-screen.js +13 -0
- package/dist/core/runner/run-leg.js +5 -1
- package/dist/core/runner/runtask.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +3 -2
- package/dist/core/runner/write-protection-station.js +1 -0
- package/dist/core/runner-deps.d.ts +14 -0
- package/dist/core/sensitive-path-policy.d.ts +8 -0
- package/dist/core/sensitive-path-policy.js +18 -2
- package/dist/core/shell-wrapper-projection.d.ts +11 -0
- package/dist/core/shell-wrapper-projection.js +56 -0
- package/dist/core/shell-wrapper-table.d.ts +144 -34
- package/dist/core/shell-wrapper-table.js +40 -20
- package/dist/core/synthetic-read-verdict.d.ts +3 -0
- package/dist/core/synthetic-read-verdict.js +3 -1
- package/dist/core/tool-catalog-entries.d.ts +21 -0
- package/dist/core/tool-catalog-entries.js +12 -2
- package/dist/core/tool-face.d.ts +10 -1
- package/dist/core/tool-name-readings.d.ts +8 -0
- package/dist/core/tool-name-readings.js +2 -0
- package/dist/core/tool-policy.d.ts +40 -17
- package/dist/core/tool-policy.js +11 -9
- package/dist/core/tool-registry.d.ts +9 -0
- package/dist/core/tool-registry.js +10 -0
- package/dist/core/tool-spec.d.ts +3 -2
- package/dist/core/write-protect.d.ts +14 -3
- package/dist/core/write-protect.js +41 -10
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/orchestration/run-spec.js +8 -7
- package/dist/orchestration/workflow.js +1 -1
- package/dist/shell/lex.d.ts +22 -0
- package/dist/shell/lex.js +75 -13
- package/dist/tools/fs/bash-program-position.d.ts +14 -90
- package/dist/tools/fs/bash-program-position.js +41 -74
- package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
- package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
- package/dist/tools/fs/index.d.ts +3 -2
- package/dist/tools/fs/program-read-model.d.ts +711 -0
- package/dist/tools/fs/program-read-model.js +1259 -0
- package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
- package/dist/tools/fs/program-read-model.rows.js +624 -0
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +62 -24
- package/dist/tools/fs/read-deny.d.ts +54 -14
- package/dist/tools/fs/read-deny.js +104 -50
- package/dist/tools/fs/removal-targets.d.ts +7 -6
- package/dist/tools/fs/removal-targets.js +34 -24
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +10 -3
- package/dist/tools/fs/shell-read-argv.d.ts +86 -0
- package/dist/tools/fs/shell-read-argv.js +388 -0
- package/dist/tools/fs/shell-read-bindings.d.ts +300 -0
- package/dist/tools/fs/shell-read-bindings.js +755 -0
- package/dist/tools/fs/shell-read-check.js +23 -15
- package/dist/tools/fs/shell-read-establish.js +82 -8
- package/dist/tools/fs/shell-read-judge.d.ts +11 -1
- package/dist/tools/fs/shell-read-judge.js +9 -1
- package/dist/tools/fs/shell-read-plan.d.ts +33 -8
- package/dist/tools/fs/shell-read-plan.js +309 -407
- package/dist/tools/fs/shell-read-word.d.ts +60 -26
- package/dist/tools/fs/shell-read-word.js +47 -37
- package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
- package/dist/tools/fs/shell-read-write-targets.js +85 -137
- package/dist/tools/fs/shell-reentry-text.d.ts +136 -6
- package/dist/tools/fs/shell-reentry-text.js +203 -53
- package/dist/tools/monitor.d.ts +3 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +25 -5
- package/wire-changes/core@7.46.0.json +1522 -0
- package/wire-changes/core@7.47.0.json +412 -0
|
@@ -1,30 +1,31 @@
|
|
|
1
|
+
import { declaresOption, programRows } from "../tools/fs/program-read-model.js";
|
|
1
2
|
export const SHELL_WRAPPER_TABLE = {
|
|
2
3
|
command: { valueFlags: [], flags: ["-p"], commandString: [] },
|
|
3
4
|
builtin: { valueFlags: [], flags: [], commandString: [] },
|
|
4
5
|
noglob: { valueFlags: [], flags: [], commandString: [] },
|
|
5
6
|
nocorrect: { valueFlags: [], flags: [], commandString: [] },
|
|
6
7
|
exec: { valueFlags: ["-a"], flags: ["-c", "-l"], commandString: [] },
|
|
7
|
-
env: { valueFlags: ["
|
|
8
|
-
sudo: { valueFlags: ["-
|
|
9
|
-
doas: { valueFlags: ["-
|
|
10
|
-
pkexec: { valueFlags: ["--user"], flags: ["--disable-internal-agent", "--
|
|
8
|
+
env: { valueFlags: ["--argv0", "--chdir", "--unset", "-C", "-P", "-a", "-u"], flags: ["--debug", "--default-signal", "--help", "--ignore-environment", "--ignore-signal", "--list-signal-handling", "--version", "-i", "-v"], commandString: ["--split-string", "-S"], bareDash: true, assignments: true },
|
|
9
|
+
sudo: { valueFlags: ["--auth-type", "--chdir", "--chroot", "--close-from", "--command-timeout", "--group", "--host", "--other-user", "--prompt", "--role", "--type", "--user", "-C", "-D", "-R", "-T", "-U", "-a", "-g", "-h", "-p", "-r", "-t", "-u"], flags: ["--askpass", "--background", "--bell", "--help", "--list", "--login", "--non-interactive", "--preserve-env", "--preserve-groups", "--remove-timestamp", "--reset-timestamp", "--set-home", "--shell", "--stdin", "--validate", "--version", "-A", "-E", "-H", "-K", "-P", "-S", "-V", "-b", "-i", "-k", "-l", "-n", "-s", "-v"], commandString: [], assignments: true },
|
|
10
|
+
doas: { valueFlags: ["-C", "-a", "-u"], flags: ["-L", "-n", "-s"], commandString: [] },
|
|
11
|
+
pkexec: { valueFlags: ["--user"], flags: ["--disable-internal-agent", "--help", "--keep-cwd", "--version"], commandString: [] },
|
|
11
12
|
nohup: { valueFlags: [], flags: ["--help", "--version"], commandString: [] },
|
|
12
|
-
time: { valueFlags: ["
|
|
13
|
-
nice: { valueFlags: ["
|
|
14
|
-
timeout: { valueFlags: ["-
|
|
15
|
-
stdbuf: { valueFlags: ["
|
|
16
|
-
xargs: { valueFlags: ["-
|
|
13
|
+
time: { valueFlags: ["--format", "--output", "-f", "-o"], flags: ["--append", "--help", "--portability", "--quiet", "--verbose", "--version", "-a", "-p", "-q", "-v"], commandString: [] },
|
|
14
|
+
nice: { valueFlags: ["--adjustment", "-n"], flags: ["--help", "--version"], commandString: [] },
|
|
15
|
+
timeout: { valueFlags: ["--kill-after", "--signal", "-k", "-s"], flags: ["--foreground", "--help", "--preserve-status", "--verbose", "--version", "-v"], commandString: [], duration: true },
|
|
16
|
+
stdbuf: { valueFlags: ["--error", "--input", "--output", "-e", "-i", "-o"], flags: ["--help", "--version"], commandString: [] },
|
|
17
|
+
xargs: { valueFlags: ["--arg-file", "--delimiter", "--max-args", "--max-chars", "--max-procs", "--process-slot-var", "-E", "-I", "-L", "-P", "-a", "-d", "-n", "-s"], flags: ["--eof", "--exit", "--help", "--interactive", "--max-lines", "--no-run-if-empty", "--null", "--open-tty", "--replace", "--show-limits", "--verbose", "--version", "-0", "-o", "-p", "-r", "-t", "-x"], attached: ["-i", "-l"], commandString: [] },
|
|
17
18
|
watch: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
18
|
-
ionice: { valueFlags: ["
|
|
19
|
-
setsid: { valueFlags: [], flags: ["
|
|
20
|
-
taskset: { valueFlags: [], flags: ["-
|
|
21
|
-
chrt: { valueFlags: ["
|
|
22
|
-
strace: { valueFlags: ["
|
|
23
|
-
ltrace: { valueFlags: ["
|
|
24
|
-
flock: { valueFlags: ["-
|
|
25
|
-
script: { valueFlags: [], flags: [], commandString: ["
|
|
26
|
-
unshare: { valueFlags: ["
|
|
27
|
-
nsenter: { valueFlags: ["
|
|
19
|
+
ionice: { valueFlags: ["--class", "--classdata", "--pgid", "--pid", "--uid", "-P", "-c", "-n", "-p", "-u"], flags: ["--help", "--ignore", "--version", "-V", "-h", "-t"], commandString: [] },
|
|
20
|
+
setsid: { valueFlags: [], flags: ["--ctty", "--fork", "--help", "--version", "--wait", "-c", "-f", "-w"], commandString: [] },
|
|
21
|
+
taskset: { valueFlags: [], flags: ["--all-tasks", "--cpu-list", "--help", "--pid", "--version", "-a", "-c", "-p"], commandString: [], positional: /^(?:0x)?[\da-f]+$|^[\d,:-]+$/i },
|
|
22
|
+
chrt: { valueFlags: ["--pid", "--sched-deadline", "--sched-period", "--sched-runtime", "-D", "-P", "-T", "-p"], flags: ["--all-tasks", "--batch", "--deadline", "--fifo", "--help", "--idle", "--max", "--other", "--reset-on-fork", "--rr", "--verbose", "--version", "-R", "-a", "-b", "-d", "-f", "-i", "-m", "-o", "-r", "-v"], commandString: [], positional: /^\d+$/ },
|
|
23
|
+
strace: { valueFlags: ["--attach", "--columns", "--const-print-style", "--detach-on", "--env", "--expr", "--interruptible", "--output", "--string-limit", "--summary-columns", "--summary-sort-by", "--summary-syscall-overhead", "--trace", "--trace-path", "--user", "-E", "-I", "-O", "-P", "-S", "-U", "-X", "-a", "-b", "-e", "-o", "-p", "-s", "-u"], flags: ["--debug", "--follow-forks", "--help", "--summary", "--summary-only", "--version", "-C", "-D", "-F", "-T", "-V", "-Z", "-c", "-d", "-f", "-h", "-i", "-k", "-q", "-r", "-t", "-v", "-w", "-x", "-y", "-z"], commandString: [] },
|
|
24
|
+
ltrace: { valueFlags: ["--align", "--config", "--debug", "--indent", "--library", "--output", "--string-max", "--where", "-A", "-D", "-F", "-a", "-e", "-l", "-n", "-o", "-p", "-s", "-u", "-w", "-x"], flags: ["--demangle", "--help", "--version", "-C", "-L", "-S", "-T", "-V", "-c", "-f", "-i", "-r", "-t"], commandString: [] },
|
|
25
|
+
flock: { valueFlags: ["--conflict-exit-code", "--timeout", "--wait", "-E", "-w"], flags: ["--close", "--exclusive", "--help", "--nb", "--no-fork", "--nonblock", "--shared", "--unlock", "--verbose", "--version", "-F", "-n", "-o", "-s", "-u", "-x"], commandString: ["--command", "-c"], positional: /^/ },
|
|
26
|
+
script: { valueFlags: [], flags: [], commandString: ["--command", "-c"], viaShell: true },
|
|
27
|
+
unshare: { valueFlags: ["--boottime", "--map-group", "--map-user", "--monotonic", "--propagation", "--root", "--setgid", "--setgroups", "--setuid", "--wd", "-G", "-R", "-S", "-w"], flags: ["--cgroup", "--fork", "--help", "--ipc", "--keep-caps", "--kill-child", "--map-current-user", "--map-root-user", "--mount", "--mount-proc", "--net", "--pid", "--time", "--user", "--uts", "--version", "-C", "-T", "-U", "-c", "-f", "-i", "-m", "-n", "-p", "-r", "-u"], commandString: [] },
|
|
28
|
+
nsenter: { valueFlags: ["--setgid", "--setuid", "--target", "-G", "-S", "-t"], flags: ["--all", "--cgroup", "--help", "--ipc", "--mount", "--net", "--no-fork", "--pid", "--preserve-credentials", "--root", "--time", "--user", "--uts", "--version", "--wd", "-C", "-F", "-T", "-U", "-Z", "-a", "-i", "-m", "-n", "-p", "-u"], attached: ["-r", "-w"], commandString: [] },
|
|
28
29
|
eval: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
29
30
|
source: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
30
31
|
".": { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
@@ -41,8 +42,27 @@ export const SHELL_WRAPPER_TABLE = {
|
|
|
41
42
|
find: { valueFlags: [], flags: [], commandString: [], executes: ["-exec", "-execdir", "-ok", "-okdir"] },
|
|
42
43
|
compgen: { valueFlags: [], flags: [], commandString: [], executes: ["-C", "-F"] },
|
|
43
44
|
complete: { valueFlags: [], flags: [], commandString: [], executes: ["-C", "-F"] },
|
|
45
|
+
busybox: { valueFlags: [], flags: [], commandString: [] },
|
|
46
|
+
su: { valueFlags: ["--group", "--shell", "--supp-group", "--whitelist-environment", "-G", "-g", "-s", "-w"], flags: ["--fast", "--help", "--login", "--no-pty", "--preserve-environment", "--pty", "--version", "-P", "-T", "-V", "-f", "-h", "-l", "-m", "-p"], commandString: ["--command", "--session-command", "-c"], viaShell: true },
|
|
47
|
+
runuser: { valueFlags: ["--group", "--shell", "--supp-group", "--user", "--whitelist-environment", "-G", "-g", "-s", "-u", "-w"], flags: ["--fast", "--help", "--login", "--no-pty", "--preserve-environment", "--pty", "--version", "-P", "-T", "-V", "-f", "-h", "-l", "-m", "-p"], commandString: ["--command", "--session-command", "-c"], viaShell: true },
|
|
48
|
+
chroot: { valueFlags: [], flags: [], commandString: [], positional: /^/ },
|
|
49
|
+
setpriv: { valueFlags: [], flags: [], commandString: [] },
|
|
50
|
+
numactl: { valueFlags: [], flags: [], commandString: [] },
|
|
51
|
+
prlimit: { valueFlags: [], flags: [], commandString: [] },
|
|
52
|
+
"systemd-run": { valueFlags: [], flags: [], commandString: [] },
|
|
53
|
+
valgrind: { valueFlags: [], flags: [], commandString: [] },
|
|
54
|
+
firejail: { valueFlags: [], flags: [], commandString: [] },
|
|
55
|
+
bwrap: { valueFlags: [], flags: [], commandString: [] },
|
|
56
|
+
ash: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
57
|
+
mksh: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
58
|
+
yash: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
59
|
+
pdksh: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
60
|
+
parallel: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
61
|
+
alias: { valueFlags: [], flags: [], commandString: [], viaShell: true },
|
|
62
|
+
mapfile: { valueFlags: [], flags: [], commandString: [], executes: ["-C"] },
|
|
63
|
+
readarray: { valueFlags: [], flags: [], commandString: [], executes: ["-C"] },
|
|
44
64
|
};
|
|
45
|
-
export const VARIABLE_OPERAND_BUILTINS = new Set(
|
|
65
|
+
export const VARIABLE_OPERAND_BUILTINS = new Set(programRows().filter((row) => row.operands?.rest?.kind === "binds-name" || declaresOption(row, (spec) => spec.value?.kind === "binds-name")).map((row) => row.key));
|
|
46
66
|
export function evaluatesOperand(run) {
|
|
47
67
|
if (!VARIABLE_OPERAND_BUILTINS.has(run[0]?.text ?? ""))
|
|
48
68
|
return false;
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
* visibility probe from a model's call.
|
|
51
51
|
*/
|
|
52
52
|
import type { ToolCallRequest, ToolCallFace, ToolPolicy } from "./tool-policy.js";
|
|
53
|
+
import type { CallTargetStamp } from "./effective-path-target.js";
|
|
53
54
|
import { type SkillGrantLane } from "./skill-grant.js";
|
|
54
55
|
import type { OrgGateVerdict, PersistedRuleAnswer } from "./hooks.js";
|
|
55
56
|
/** The layers the judge consults, as named in its verdicts. */
|
|
@@ -81,6 +82,8 @@ export interface SyntheticReadLayers {
|
|
|
81
82
|
orgRuleLane?: {
|
|
82
83
|
adjudicate: (req: ToolCallRequest) => Promise<OrgGateVerdict>;
|
|
83
84
|
};
|
|
85
|
+
/** The leg's target-reading stamp: the probe's request carries a reading of its target, as the live gate's does. */
|
|
86
|
+
stampCallTarget?: CallTargetStamp;
|
|
84
87
|
/** The run's signal, for the engine's own layers. */
|
|
85
88
|
signal?: AbortSignal;
|
|
86
89
|
}
|
|
@@ -15,13 +15,15 @@ export function createSyntheticReadJudge(layers) {
|
|
|
15
15
|
return async (call, face, budget) => {
|
|
16
16
|
const deadlineAt = budget?.deadlineAt ?? Date.now() + ORG_ADJUDICATION_TIMEOUT_MS;
|
|
17
17
|
const left = () => Math.max(0, Math.min(ORG_ADJUDICATION_TIMEOUT_MS, deadlineAt - Date.now()));
|
|
18
|
-
const
|
|
18
|
+
const probe = {
|
|
19
19
|
toolName: "Read",
|
|
20
20
|
args: { file_path: call.file_path, ...(call.offset !== undefined ? { offset: call.offset } : {}), ...(call.limit !== undefined ? { limit: call.limit } : {}) },
|
|
21
21
|
toolCallId: syntheticReadProbeId(face),
|
|
22
22
|
...(call.cwd !== undefined ? { cwd: call.cwd } : {}),
|
|
23
23
|
...(call.face !== undefined ? { face: call.face } : {}),
|
|
24
24
|
};
|
|
25
|
+
const stamped = layers.stampCallTarget?.(probe, layers.signal);
|
|
26
|
+
const req = stamped !== undefined ? await stamped : probe;
|
|
25
27
|
let unanswered;
|
|
26
28
|
const cannot = (layer, cause, reason) => {
|
|
27
29
|
unanswered ??= { verdict: "unanswerable", layer, cause, reason };
|
|
@@ -47,3 +47,24 @@ export declare const ENGINE_CARDS: Readonly<Record<string, string>>;
|
|
|
47
47
|
export declare function toolFace(id: string): ToolFaceDeclaration;
|
|
48
48
|
/** Definition-id → face, for the modules that spread one (`...TOOL_FACES.read`). Frozen: a face is data. */
|
|
49
49
|
export declare const TOOL_FACES: Readonly<Record<string, ToolFaceDeclaration>>;
|
|
50
|
+
/**
|
|
51
|
+
* The engine's own tool names, once each: every catalog entry the engine mounts itself (`source: "builtin"` — the hands,
|
|
52
|
+
* the scaffolds, the memory tools, the background-task tools), whatever face or contract it is mounted under. A host that
|
|
53
|
+
* must hand the engine a tool face with NO built-ins (`TaskSpec.excludeTools`, a shell's `--tools ""`) reads this set
|
|
54
|
+
* instead of keeping a list of its own: the catalog is the one source, and a name the engine adds later lands here with it.
|
|
55
|
+
*/
|
|
56
|
+
export declare const ENGINE_BUILTIN_TOOL_NAMES: readonly string[];
|
|
57
|
+
/**
|
|
58
|
+
* The engine's HAND tools, once each, with the other spellings they answer to: the catalog rows mounted by `hands` — what a run
|
|
59
|
+
* mounts for itself over an execution environment (the file and shell band, the worktree pair, the band's background-shell
|
|
60
|
+
* pair). A delegated child's tool-name lists govern these beside the tools the delegation tool hands it, so the spawn reads
|
|
61
|
+
* this set rather than a list of its own.
|
|
62
|
+
*/
|
|
63
|
+
export declare const HAND_TOOLS: ReadonlyArray<{
|
|
64
|
+
readonly name: string;
|
|
65
|
+
readonly aliases?: readonly string[];
|
|
66
|
+
}>;
|
|
67
|
+
/** The wire names of {@link HAND_TOOLS}. */
|
|
68
|
+
export declare const HAND_TOOL_NAMES: readonly string[];
|
|
69
|
+
/** Is this name one the engine mounts itself ({@link ENGINE_BUILTIN_TOOL_NAMES})? A caller tool, an MCP tool or a skill tool is not. */
|
|
70
|
+
export declare function isEngineBuiltinToolName(name: string): boolean;
|
|
@@ -8,7 +8,8 @@ export const TASK_LIST_TOOL_NAME = "TaskList";
|
|
|
8
8
|
export const TODO_WRITE_TOOL_NAME = "TodoWrite";
|
|
9
9
|
export const REFRESH_MCP_TOOLS_TOOL_NAME = "RefreshMcpTools";
|
|
10
10
|
export const ARTIFACT_TOOL_NAME = "Artifact";
|
|
11
|
-
const
|
|
11
|
+
const shellRuleFace = (params) => ({ grammar: "command", primaryParams: ["command"], params });
|
|
12
|
+
const SHELL_RULE_FACE = shellRuleFace(["command", "timeout", "description", "run_in_background"]);
|
|
12
13
|
const c = (contractId, implementationRevision = "1") => ({ contractId, implementationRevision });
|
|
13
14
|
export const TOOL_CATALOG_ENTRIES = [
|
|
14
15
|
{
|
|
@@ -108,7 +109,7 @@ export const TOOL_CATALOG_ENTRIES = [
|
|
|
108
109
|
{ id: "task-stop-hands", name: "TaskStop", source: "builtin", definedIn: "src/tools/fs/fs-bash.ts", mountedBy: ["hands"], cards: [], face: { family: "delegate", effect: "write", contract: TASK_STOP_CONTRACT } },
|
|
109
110
|
{ id: "task-output", name: "TaskOutput", source: "builtin", definedIn: "src/core/task-registry.ts", mountedBy: ["delegation"], cards: ["task-output"], face: { family: "delegate", effect: "read", contract: TASK_OUTPUT_CONTRACT } },
|
|
110
111
|
{ id: "task-stop", name: "TaskStop", source: "builtin", definedIn: "src/core/task-registry.ts", mountedBy: ["delegation"], cards: ["task-stop"], face: { family: "delegate", effect: "write", contract: TASK_STOP_CONTRACT } },
|
|
111
|
-
{ id: "monitor", name: "Monitor", source: "builtin", definedIn: "src/tools/monitor.ts", mountedBy: ["backgroundTasks"], cards: ["monitor-start", "readonly_out_of_root", "read_unestablished"], face: { family: "other", effect: "write", contract: c("core.monitor@1"), offloadThresholdChars: 10_000 } },
|
|
112
|
+
{ id: "monitor", name: "Monitor", source: "builtin", definedIn: "src/tools/monitor.ts", mountedBy: ["backgroundTasks"], cards: ["monitor-start", "readonly_out_of_root", "read_unestablished"], face: { family: "other", effect: "write", contract: c("core.monitor@1"), ruleFace: shellRuleFace(["command", "description", "timeout_ms", "persistent"]), offloadThresholdChars: 10_000 } },
|
|
112
113
|
{ id: "send-message", name: "SendMessage", source: "builtin", definedIn: "src/agents/send-message-tool.ts", mountedBy: ["delegation", "hostInternals", "peerLane"], cards: ["send-message"], face: { family: "protocol", effect: "write", contract: c("core.send_message@1") } },
|
|
113
114
|
{ id: "agent-transcript", name: "AgentTranscript", source: "builtin", definedIn: "src/agents/agent-transcript-tool.ts", mountedBy: ["delegation"], cards: ["agent-transcript"], face: { family: "delegate", effect: "read", contract: c("core.agent_transcript@1") } },
|
|
114
115
|
{ id: "list-agents", name: "ListAgents", source: "builtin", definedIn: "src/agents/list-agents-tool.ts", mountedBy: ["delegation", "peerLane"], cards: ["list-agents"], face: { family: "protocol", effect: "read", aliases: ["ListPeers"], contract: c("core.list_agents@1") } },
|
|
@@ -180,3 +181,12 @@ function deepFreeze(value) {
|
|
|
180
181
|
}
|
|
181
182
|
deepFreeze(TOOL_CATALOG_ENTRIES);
|
|
182
183
|
export const TOOL_FACES = Object.freeze(Object.fromEntries(TOOL_CATALOG_ENTRIES.map((e) => [e.id, e.face])));
|
|
184
|
+
export const ENGINE_BUILTIN_TOOL_NAMES = Object.freeze([...new Set(TOOL_CATALOG_ENTRIES.filter((e) => e.source === "builtin").map((e) => e.name))]);
|
|
185
|
+
export const HAND_TOOLS = Object.freeze([...new Set(TOOL_CATALOG_ENTRIES.filter((e) => e.mountedBy.includes("hands")).map((e) => e.name))].map((name) => {
|
|
186
|
+
const aliases = [...new Set(TOOL_CATALOG_ENTRIES.filter((e) => e.name === name && e.mountedBy.includes("hands")).flatMap((e) => e.face.aliases ?? []))];
|
|
187
|
+
return Object.freeze(aliases.length > 0 ? { name, aliases: Object.freeze(aliases) } : { name });
|
|
188
|
+
}));
|
|
189
|
+
export const HAND_TOOL_NAMES = Object.freeze(HAND_TOOLS.map((t) => t.name));
|
|
190
|
+
export function isEngineBuiltinToolName(name) {
|
|
191
|
+
return ENGINE_BUILTIN_TOOL_NAMES.includes(name);
|
|
192
|
+
}
|
package/dist/core/tool-face.d.ts
CHANGED
|
@@ -201,7 +201,16 @@ export interface ToolFaceDeclaration {
|
|
|
201
201
|
};
|
|
202
202
|
aliases?: string[];
|
|
203
203
|
pathTarget?: ToolPathTarget;
|
|
204
|
-
|
|
204
|
+
/**
|
|
205
|
+
* The rule face ({@link ToolRuleFace}) and, for a definition whose primary parameter is a shell command line, the grammar
|
|
206
|
+
* that judges it — `grammar: "command"`, the SHELL FACE. Every `Bash(<command>)` rule (the command grammar's one spelling,
|
|
207
|
+
* deny / ask / allow, from every source) is judged on a call that answers to the name of such a definition, against that
|
|
208
|
+
* parameter; a bare `Bash` rule stays a rule on the tool of that name. Only a catalog row declares it (a caller's
|
|
209
|
+
* `ToolSpec.ruleFace` is a {@link ToolRuleFace}): the static catalog is the one place the shell face is read from.
|
|
210
|
+
*/
|
|
211
|
+
ruleFace?: ToolRuleFace & {
|
|
212
|
+
readonly grammar?: "command";
|
|
213
|
+
};
|
|
205
214
|
renderHints?: ToolRenderHints;
|
|
206
215
|
offload?: boolean;
|
|
207
216
|
offloadThresholdChars?: number;
|
|
@@ -69,6 +69,10 @@ export declare const NAME_READINGS: {
|
|
|
69
69
|
readonly kind: "wire";
|
|
70
70
|
readonly file: string;
|
|
71
71
|
};
|
|
72
|
+
readonly "gate.askFace": {
|
|
73
|
+
readonly kind: "wire";
|
|
74
|
+
readonly file: string;
|
|
75
|
+
};
|
|
72
76
|
readonly "fold.readStation": {
|
|
73
77
|
readonly kind: "seat";
|
|
74
78
|
readonly rank: "member";
|
|
@@ -251,6 +255,10 @@ export declare const NAME_READINGS: {
|
|
|
251
255
|
readonly kind: "wire";
|
|
252
256
|
readonly file: string;
|
|
253
257
|
};
|
|
258
|
+
readonly "inherited.askFace": {
|
|
259
|
+
readonly kind: "wire";
|
|
260
|
+
readonly file: string;
|
|
261
|
+
};
|
|
254
262
|
readonly "park.contentKindProjection": {
|
|
255
263
|
readonly kind: "wire";
|
|
256
264
|
readonly file: string;
|
|
@@ -19,6 +19,7 @@ export const NAME_READINGS = {
|
|
|
19
19
|
"gate.sandboxBoundary.egress": any(CHAIN),
|
|
20
20
|
"gate.sandboxBoundary.hand": wire(CHAIN),
|
|
21
21
|
"gate.preToolUse": wire("src/core/hooks.ts"),
|
|
22
|
+
"gate.askFace": wire("src/core/runner/gate-exit.ts"),
|
|
22
23
|
"fold.readStation": seat("member", "src/tools/fs/shell-read-check.ts"),
|
|
23
24
|
"lanes.contentQuestionClass": any(LANES),
|
|
24
25
|
"lanes.readOnlyShellAllow": wire(LANES),
|
|
@@ -63,6 +64,7 @@ export const NAME_READINGS = {
|
|
|
63
64
|
"activity.sink": spelling(HANDLERS),
|
|
64
65
|
"reconcile.orphanEffect": spelling("src/core/session-reconcile.ts"),
|
|
65
66
|
"inherited.questionFloat": wire(CHAIN),
|
|
67
|
+
"inherited.askFace": wire(CHAIN),
|
|
66
68
|
"park.contentKindProjection": wire("src/core/checkpoint-store.ts"),
|
|
67
69
|
"resume.contentAskRow": wire("src/core/runner/decide-continuation.ts"),
|
|
68
70
|
"resume.editRecheckQuestionSkip": wire("src/core/runner/resume-apply.ts"),
|
|
@@ -79,6 +79,17 @@ export interface ToolCallRequest {
|
|
|
79
79
|
* Read-only, like `cwd`.
|
|
80
80
|
*/
|
|
81
81
|
root?: string;
|
|
82
|
+
/** The call's target reading (`readCallTarget`: lexical / canonical / hop views per reading of the path slot), stamped by the Runner on a
|
|
83
|
+
* leg whose lanes can hold a path rule; it describes only the `args` object it was taken for (`callTargetReadingOf`). Read-only. */
|
|
84
|
+
targetReading?: import("./effective-path-target.js").CallTargetReading;
|
|
85
|
+
/**
|
|
86
|
+
* An ENGINE-INTERNAL seat, not a fact of the call: the anchors of the policy now judging this request — the leg its
|
|
87
|
+
* path rules were installed on (`installPolicyAnchors`). Present only on the copy an installed policy hands its own
|
|
88
|
+
* inner `check` (where `createPermissionRulePolicy` reads it; an inner installation's anchors win over an outer one's);
|
|
89
|
+
* the request the gate holds, an `AskRequest`, a hook's input and a parked row never carry it. A host neither sets nor
|
|
90
|
+
* reads it.
|
|
91
|
+
*/
|
|
92
|
+
pathRuleAnchors?: import("./permission-rule-model.js").PathRuleBases;
|
|
82
93
|
/**
|
|
83
94
|
* The CANONICAL directories THIS RUN'S PROMPT ADVERTISES AS WRITABLE — the admitted list of the root
|
|
84
95
|
* fence's advertised-writable-directory seat (the memory engine's write home, the deployment's
|
|
@@ -537,11 +548,14 @@ export interface ToolPolicy {
|
|
|
537
548
|
* describes the policy must read that bit, not the field's presence.
|
|
538
549
|
*/
|
|
539
550
|
readonly projection?: ToolPolicyProjection;
|
|
540
|
-
/** The policy's
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
|
|
551
|
+
/** The policy's PATH rules as a function of the ANCHORS of the leg they are installed on (`createPermissionRulePolicy`
|
|
552
|
+
* sets it; present exactly when the policy judges a path target): given the leg's root and home, every path rule
|
|
553
|
+
* bound there — the face-keyed deny rows the prepared leg joins to its read and write tables (so the shell's reads and
|
|
554
|
+
* writes and the traversals meet the rule, not only the tool it names), and the rows its own `check` judges at the
|
|
555
|
+
* gate. A policy the Runner already installed answers with its own installation's rows whatever it is given. Carried
|
|
556
|
+
* through {@link combinePolicies}; read with {@link toolPolicyPathRules}. Its presence also tells the Runner to read
|
|
557
|
+
* each call's target ({@link ToolCallRequest.targetReading}). */
|
|
558
|
+
readonly pathRules?: (anchors: import("./permission-rule-model.js").PathRuleBases) => readonly import("./path-rule-binding.js").BoundPathRule[];
|
|
545
559
|
/** Does this policy guard a write to this ABSOLUTE target — would it refuse the write if a write tool made it? The
|
|
546
560
|
* policy's answer for a writer it cannot see as a call (the shell's file commands), read by the shell station's
|
|
547
561
|
* `writesPlaced` fact alone: a guarded target is not placed, so no permission mode answers the command and its ask
|
|
@@ -558,9 +572,15 @@ export interface ToolPolicy {
|
|
|
558
572
|
* each by name off the wrapped policy, {@link combinePolicies} folds each. The fence makes a new {@link ToolPolicy} member
|
|
559
573
|
* a compile error until the table names it.
|
|
560
574
|
*/
|
|
561
|
-
declare const TOOL_POLICY_CARRIED_MEMBERS: readonly ["projection", "
|
|
575
|
+
declare const TOOL_POLICY_CARRIED_MEMBERS: readonly ["projection", "pathRules", "writeTargetGuard", "nameSets"];
|
|
562
576
|
type ToolPolicyCarriedMember = (typeof TOOL_POLICY_CARRIED_MEMBERS)[number];
|
|
563
577
|
export type ToolPolicyCarriesEveryMember = AssertAllKeysHandled<Exclude<Exclude<keyof ToolPolicy, "check">, ToolPolicyCarriedMember>>;
|
|
578
|
+
/** The carried members that are set on `p`, each read by name — an accessor or a non-enumerable member included. */
|
|
579
|
+
export declare function carriedMembersOf(p: {
|
|
580
|
+
readonly [K in ToolPolicyCarriedMember]?: ToolPolicy[K];
|
|
581
|
+
}): {
|
|
582
|
+
-readonly [K in ToolPolicyCarriedMember]?: ToolPolicy[K];
|
|
583
|
+
};
|
|
564
584
|
/**
|
|
565
585
|
* The ONE way to wrap a policy: the wrapper decides through `check`; every member {@link ToolPolicy} declares beside it
|
|
566
586
|
* (projection, name sets, path deny rows, write-target guard — the carried-member table) rides as `inner` holds it, read
|
|
@@ -570,8 +590,10 @@ export type ToolPolicyCarriesEveryMember = AssertAllKeysHandled<Exclude<Exclude<
|
|
|
570
590
|
* The ask-class brand is not carried: it attests the replaced `check`.
|
|
571
591
|
*/
|
|
572
592
|
export declare function wrapToolPolicy<P extends ToolPolicy>(inner: P, check: ToolPolicy["check"]): Pick<P, ToolPolicyCarriedMember> & ToolPolicy;
|
|
573
|
-
/** Every path
|
|
574
|
-
|
|
593
|
+
/** Every path rule the given policies carry (combined policies included), in order, bound at `anchors` — the anchors of
|
|
594
|
+
* the leg the policies are installed on (a policy already installed answers with its own installation's rows). The deny
|
|
595
|
+
* tables take the rows that guard a face (`faces` non-empty) of a deny rule. */
|
|
596
|
+
export declare function toolPolicyPathRules(policies: readonly (ToolPolicy | undefined)[], anchors: import("./permission-rule-model.js").PathRuleBases): readonly import("./path-rule-binding.js").BoundPathRule[];
|
|
575
597
|
/** The one write-target guard the given policies carry together (combined policies included): `true` when any member
|
|
576
598
|
* guards the target, a member that throws counting as guarding it. `undefined` when none carries one. */
|
|
577
599
|
export declare function toolPolicyWriteTargetGuard(policies: readonly (ToolPolicy | undefined)[]): ToolPolicy["writeTargetGuard"];
|
|
@@ -955,13 +977,14 @@ export declare function createApprovalPolicy(opts: {
|
|
|
955
977
|
*/
|
|
956
978
|
export declare function combinePolicies(...policies: ToolPolicy[]): ToolPolicy;
|
|
957
979
|
/**
|
|
958
|
-
* The shell tools whose `{ command }` arg a coarse command-name policy parses; other tools are out of scope.
|
|
959
|
-
*
|
|
960
|
-
*
|
|
961
|
-
*
|
|
962
|
-
*
|
|
980
|
+
* The shell tools whose `{ command }` arg a coarse command-name policy parses; other tools are out of scope. It is the
|
|
981
|
+
* catalog's shell face ({@link shellFaceToolNames} — every definition whose `command` the command grammar judges, `Monitor`
|
|
982
|
+
* among them: it runs an arbitrary shell `command` through the same env seam as Bash), spelled out for the wire; the
|
|
983
|
+
* catalog's shell face is the truth, and a lockstep pin keeps the two one (a catalog row added or dropped turns it red):
|
|
984
|
+
* the always-on parity gates keyed on it, the `Bash(...)` rules and the shell seat reach the same tools. EXPORTED: a
|
|
985
|
+
* downstream governance layer reads it so its per-command ask-list gates the same tools core does.
|
|
963
986
|
*/
|
|
964
|
-
export declare const COARSE_SHELL_TOOLS:
|
|
987
|
+
export declare const COARSE_SHELL_TOOLS: readonly ["Bash", "Monitor"];
|
|
965
988
|
/**
|
|
966
989
|
* design/center §10 — a COARSE allow/deny gate keyed on the LEADING command NAME (`argv[0]`) of a single
|
|
967
990
|
* simple shell command. It reuses the ONE shared simple-command parser
|
|
@@ -1011,7 +1034,7 @@ export declare function createCoarseCommandNamePolicy(opts: {
|
|
|
1011
1034
|
deny?: string[];
|
|
1012
1035
|
/** What to do for a command not matched by `allow` (or un-parseable): `"ask"` (default) or `"deny"`. */
|
|
1013
1036
|
defaultAction?: "ask" | "deny";
|
|
1014
|
-
/** Override the shell tool names this gate parses (default
|
|
1037
|
+
/** Override the shell tool names this gate parses (default {@link COARSE_SHELL_TOOLS}, the shell face). */
|
|
1015
1038
|
tools?: string[];
|
|
1016
1039
|
}): ToolPolicy;
|
|
1017
1040
|
export declare function findUnverifiableRecursiveDelete(command: string, safeVars?: ReadonlySet<string>): string | undefined;
|
|
@@ -1090,7 +1113,7 @@ export declare function createUnverifiableDeletePolicy(opts?: {
|
|
|
1090
1113
|
* the default was `TMPDIR` alone, reading STRICTER than the gate really is; `HOME`/`PWD` are a
|
|
1091
1114
|
* registered sema divergence from CC's temp-only carve-out, see the RB-340 note there). */
|
|
1092
1115
|
safeVars?: readonly string[];
|
|
1093
|
-
/** Override the shell tool names this gate parses (default
|
|
1116
|
+
/** Override the shell tool names this gate parses (default {@link COARSE_SHELL_TOOLS}, the shell face). */
|
|
1094
1117
|
tools?: string[];
|
|
1095
1118
|
removalSeat?: RemovalGuardSeat;
|
|
1096
1119
|
}): ToolPolicy;
|
|
@@ -1099,7 +1122,7 @@ export declare function createTranscriptIntegrityPolicy(opts?: {
|
|
|
1099
1122
|
sessionsDirs?: readonly string[];
|
|
1100
1123
|
/** argv[0] allowlist for read-only access to the transcript dir (default {@link BASH_READONLY_DEFAULT_ALLOW}). */
|
|
1101
1124
|
readAllow?: readonly string[];
|
|
1102
|
-
/** Override the shell tool names this gate parses (default
|
|
1125
|
+
/** Override the shell tool names this gate parses (default {@link COARSE_SHELL_TOOLS}, the shell face). */
|
|
1103
1126
|
tools?: string[];
|
|
1104
1127
|
}): ToolPolicy;
|
|
1105
1128
|
/**
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
+
import { withArgsReading } from "./effective-path-target.js";
|
|
3
4
|
import { brandPolicyAskClass } from "./ask-class.js";
|
|
4
5
|
import { decisionAskClassesOf, headlessDenialMessage } from "./ask-origin.js";
|
|
5
6
|
import { ownReadRootCandidate, readRootGrantSeat } from "./read-root-grant-screen.js";
|
|
@@ -9,7 +10,7 @@ export { policyCannotAnswer, rowDemandsAPerson } from "./real-approval.js";
|
|
|
9
10
|
import { sanitizeAutoModeArmingRecipe } from "./auto-mode-arming.js";
|
|
10
11
|
import { join, normalize as normalizePath, sep } from "node:path";
|
|
11
12
|
import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
|
|
12
|
-
import { protectivePathTargetOf } from "./tool-registry.js";
|
|
13
|
+
import { protectivePathTargetOf, shellFaceToolNames } from "./tool-registry.js";
|
|
13
14
|
import { heldBy } from "./tool-name-readings.js";
|
|
14
15
|
import { boundInputHashOf } from "./canonical-json.js";
|
|
15
16
|
import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
|
|
@@ -137,8 +138,8 @@ export const ASK_EVIDENCE_ABSENCE_VALUES = ["not_wired", "not_adjudicated", "una
|
|
|
137
138
|
export function decisionText(d) {
|
|
138
139
|
return d.message;
|
|
139
140
|
}
|
|
140
|
-
const TOOL_POLICY_CARRIED_MEMBERS = ["projection", "
|
|
141
|
-
function carriedMembersOf(p) {
|
|
141
|
+
const TOOL_POLICY_CARRIED_MEMBERS = ["projection", "pathRules", "writeTargetGuard", "nameSets"];
|
|
142
|
+
export function carriedMembersOf(p) {
|
|
142
143
|
const out = {};
|
|
143
144
|
const carry = (k) => {
|
|
144
145
|
const v = p[k];
|
|
@@ -152,8 +153,8 @@ function carriedMembersOf(p) {
|
|
|
152
153
|
export function wrapToolPolicy(inner, check) {
|
|
153
154
|
return { ...carriedMembersOf(inner), check };
|
|
154
155
|
}
|
|
155
|
-
export function
|
|
156
|
-
return policies.flatMap((p) => (
|
|
156
|
+
export function toolPolicyPathRules(policies, anchors) {
|
|
157
|
+
return policies.flatMap((p) => (typeof p?.pathRules === "function" ? p.pathRules(anchors) : []));
|
|
157
158
|
}
|
|
158
159
|
export function toolPolicyWriteTargetGuard(policies) {
|
|
159
160
|
const guards = policies.flatMap((p) => (typeof p?.writeTargetGuard === "function" ? [p.writeTargetGuard] : []));
|
|
@@ -514,7 +515,7 @@ export function createApprovalPolicy(opts) {
|
|
|
514
515
|
}
|
|
515
516
|
export function combinePolicies(...policies) {
|
|
516
517
|
const nameSets = policies.flatMap(toolPolicyNameSets);
|
|
517
|
-
const
|
|
518
|
+
const pathRuled = policies.filter((p) => typeof p?.pathRules === "function");
|
|
518
519
|
const writeTargetGuard = toolPolicyWriteTargetGuard(policies);
|
|
519
520
|
const childProjections = policies.map((p) => p.projection);
|
|
520
521
|
const projectedComponents = [];
|
|
@@ -536,7 +537,7 @@ export function combinePolicies(...policies) {
|
|
|
536
537
|
const folded = {
|
|
537
538
|
projection: combinedProjection,
|
|
538
539
|
nameSets: nameSets.length > 0 ? nameSets : undefined,
|
|
539
|
-
|
|
540
|
+
pathRules: pathRuled.length > 0 ? (anchors) => toolPolicyPathRules(pathRuled, anchors) : undefined,
|
|
540
541
|
writeTargetGuard,
|
|
541
542
|
};
|
|
542
543
|
return {
|
|
@@ -576,7 +577,8 @@ export function combinePolicies(...policies) {
|
|
|
576
577
|
continue;
|
|
577
578
|
}
|
|
578
579
|
if (d.updatedInput !== undefined) {
|
|
579
|
-
|
|
580
|
+
const reread = withArgsReading(current, d.updatedInput, signal);
|
|
581
|
+
current = reread !== undefined ? await reread : { ...current, args: d.updatedInput };
|
|
580
582
|
rewrite = d;
|
|
581
583
|
stated = d.action === "allow" ? d.decisionReason : undefined;
|
|
582
584
|
}
|
|
@@ -640,7 +642,7 @@ export function combinePolicies(...policies) {
|
|
|
640
642
|
},
|
|
641
643
|
};
|
|
642
644
|
}
|
|
643
|
-
export const COARSE_SHELL_TOOLS = ["Bash", "Monitor"];
|
|
645
|
+
export const COARSE_SHELL_TOOLS = Object.freeze(["Bash", "Monitor"]);
|
|
644
646
|
function canonicalToolNameSet(tools) {
|
|
645
647
|
return new Set(tools ?? COARSE_SHELL_TOOLS);
|
|
646
648
|
}
|
|
@@ -25,6 +25,15 @@ export declare function catalogToolNames(): ReadonlySet<string>;
|
|
|
25
25
|
export declare function pathConfinableWriteToolNames(): ReadonlySet<string>;
|
|
26
26
|
/** A-8 — every definition that names a path target at all (read or write): the file-tool glob lane. */
|
|
27
27
|
export declare function pathTargetingToolNames(): ReadonlySet<string>;
|
|
28
|
+
/**
|
|
29
|
+
* The SHELL FACE: every definition whose `command` argument is a shell command line the command grammar judges (today the two
|
|
30
|
+
* `Bash` definitions and `Monitor`). A `Bash(<command>)` rule reaches a call that answers to any of these names; the coarse
|
|
31
|
+
* command-name gate's default list, the shell read station and the shell seat are this set. Derived from the rows' rule faces,
|
|
32
|
+
* never a list of its own.
|
|
33
|
+
*/
|
|
34
|
+
export declare function shellFaceToolNames(): ReadonlySet<string>;
|
|
35
|
+
/** {@link shellFaceToolNames}' membership for one name — any definition under the name on the shell face. */
|
|
36
|
+
export declare function isShellFaceToolName(name: string): boolean;
|
|
28
37
|
/** The tools whose declared path target is a READ (a file read, a search root): the file read station's membership. */
|
|
29
38
|
export declare function readTargetToolNames(): ReadonlySet<string>;
|
|
30
39
|
/** A-10 — the micro-compaction whitelist (`compactable: true`). */
|
|
@@ -29,6 +29,16 @@ export function pathConfinableWriteToolNames() {
|
|
|
29
29
|
export function pathTargetingToolNames() {
|
|
30
30
|
return names((e) => e.face.pathTarget !== undefined);
|
|
31
31
|
}
|
|
32
|
+
const onShellFace = (e) => e.face.ruleFace?.grammar === "command";
|
|
33
|
+
export function shellFaceToolNames() {
|
|
34
|
+
return names(onShellFace);
|
|
35
|
+
}
|
|
36
|
+
export function isShellFaceToolName(name) {
|
|
37
|
+
for (const e of TOOL_CATALOG_ENTRIES)
|
|
38
|
+
if (e.name === name && onShellFace(e))
|
|
39
|
+
return true;
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
32
42
|
export function readTargetToolNames() {
|
|
33
43
|
return names((e) => e.face.pathTarget?.access === "read");
|
|
34
44
|
}
|
package/dist/core/tool-spec.d.ts
CHANGED
|
@@ -212,8 +212,9 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
|
|
|
212
212
|
* carries its own tool set, and a parent that mounts nothing but the delegation tool can still hand
|
|
213
213
|
* its children a network tool, so the parent's roster is the wrong thing to look at.
|
|
214
214
|
*
|
|
215
|
-
* ABSENT ⇔ the pool is not statically knowable — a spawn-time tool factory
|
|
216
|
-
* identity does not exist until the call
|
|
215
|
+
* ABSENT ⇔ the pool is not statically knowable — a spawn-time tool factory with no declared roster
|
|
216
|
+
* (`SubagentToolOptions.extraToolNames`) can inject tools whose identity does not exist until the call
|
|
217
|
+
* happens — and the reader fails closed on that. A declared roster's tools are rows of the pool.
|
|
217
218
|
*/
|
|
218
219
|
agentToolPool?: ReadonlyArray<{
|
|
219
220
|
name: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../internal/harness-types.js";
|
|
2
2
|
import type { PermissionResult } from "./tool-policy.js";
|
|
3
|
+
import { type AskFace } from "./ask-origin.js";
|
|
3
4
|
import { type ToolCallLike } from "./tool-registry.js";
|
|
4
5
|
/**
|
|
5
6
|
* How one table row matches the judged path:
|
|
@@ -173,6 +174,10 @@ export interface WriteProtectionCompileOptions {
|
|
|
173
174
|
* path-family source when the call carries no cwd. Omitted ⇒ relative spellings resolve against the
|
|
174
175
|
* cwd, then the environment's own working directory. */
|
|
175
176
|
readonly rootPath?: string;
|
|
177
|
+
/** The host's configuration root when it keeps the agent's configuration directory somewhere other than the home's
|
|
178
|
+
* `.sema` (`RunnerDeps.agentConfigDir`, absolute, already screened): every row that names the `.sema` directory also
|
|
179
|
+
* names the same tail below this root, and a hit there cites the row. Omitted ⇒ the table is judged as it stands. */
|
|
180
|
+
readonly agentConfigDir?: string;
|
|
176
181
|
/**
|
|
177
182
|
* Called at most ONCE per judgment, at the moment the ENVIRONMENT half is found unable to contribute
|
|
178
183
|
* ({@link WriteProtectionViewAbsence}) — before the judgment returns, and on the hit arm as well as the
|
|
@@ -205,11 +210,17 @@ export declare function compileWriteProtection(entries?: readonly WriteProtected
|
|
|
205
210
|
* message (table names are deployment-validated vocabulary); the model-authored target path deliberately
|
|
206
211
|
* does not — `message` is the classifier's `askMessage`, and the approval card already shows the args. The
|
|
207
212
|
* spelling form's sentence is the historical one byte for byte; the target form says the target RESOLVED.
|
|
208
|
-
* · `unresolvable` ⇒
|
|
209
|
-
*
|
|
213
|
+
* · `unresolvable` ⇒ read by the call's FACE (`face`, {@link releasableAskClassesFor}): where no permission mode releases
|
|
214
|
+
* `write_protection_unresolved` (the file face) — `deny` naming the cause: an unjudged target is never vouched (the rule
|
|
215
|
+
* the canonicalizing deny set follows for the same reason), so there a standing allow is refused while a standing ask
|
|
216
|
+
* carrying the record stays a person's question in the modes that ask (dontAsk and bypassPermissions refuse it); where
|
|
217
|
+
* a mode may release the class (the shell face) — `ask` (`safety`)
|
|
218
|
+
* naming the cause, which the mode arbitration answers exactly as it answers that record over a standing ask
|
|
219
|
+
* (bypassPermissions releases it, default puts it to a person, dontAsk refuses): on that face alone a standing allow
|
|
220
|
+
* reads as a standing ask.
|
|
210
221
|
* · `clear` ⇒ `undefined`: the surviving decision stands.
|
|
211
222
|
*/
|
|
212
|
-
export declare function writeProtectionTightenDecision(toolName: string, verdict: WriteProtectionVerdict): PermissionResult | undefined;
|
|
223
|
+
export declare function writeProtectionTightenDecision(toolName: string, verdict: WriteProtectionVerdict, face: AskFace): PermissionResult | undefined;
|
|
213
224
|
/**
|
|
214
225
|
* @contract write_protection.verdict_is_the_mandate — the judge's two non-clear verdicts are the two facts
|
|
215
226
|
* a standing allow rule may not retire, and `clear` is neither: a MATCHED row is the mandate a live decider
|