@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.
Files changed (139) hide show
  1. package/CHANGELOG.md +298 -1
  2. package/dist/agents/extra-tool-names.d.ts +65 -0
  3. package/dist/agents/extra-tool-names.js +124 -0
  4. package/dist/agents/subagent.d.ts +17 -5
  5. package/dist/agents/subagent.js +33 -25
  6. package/dist/agents/tool-filter.d.ts +17 -1
  7. package/dist/agents/tool-filter.js +7 -0
  8. package/dist/core/agent-config-dir.d.ts +20 -0
  9. package/dist/core/agent-config-dir.js +49 -0
  10. package/dist/core/allow-entry.d.ts +6 -4
  11. package/dist/core/allow-entry.js +6 -5
  12. package/dist/core/ask-origin.d.ts +35 -12
  13. package/dist/core/ask-origin.js +24 -7
  14. package/dist/core/checkpoint-store.d.ts +39 -2
  15. package/dist/core/effective-path-target.d.ts +136 -4
  16. package/dist/core/effective-path-target.js +110 -2
  17. package/dist/core/engine-notice.d.ts +12 -4
  18. package/dist/core/gate-fold.js +5 -2
  19. package/dist/core/gate-lanes.js +11 -4
  20. package/dist/core/gate-outcome.d.ts +4 -2
  21. package/dist/core/gate-outcome.js +2 -2
  22. package/dist/core/governance-codes.d.ts +3 -1
  23. package/dist/core/governance-codes.js +3 -0
  24. package/dist/core/hooks.d.ts +3 -0
  25. package/dist/core/path-rule-binding.d.ts +65 -0
  26. package/dist/core/path-rule-binding.js +99 -0
  27. package/dist/core/permission-rule-model.d.ts +59 -24
  28. package/dist/core/permission-rule-model.js +48 -44
  29. package/dist/core/permission-rule-provider.d.ts +7 -0
  30. package/dist/core/permission-rule-provider.js +10 -3
  31. package/dist/core/permission-rule-store.d.ts +8 -0
  32. package/dist/core/permission-rule-store.js +6 -2
  33. package/dist/core/permission-rule-sync.js +2 -2
  34. package/dist/core/permission-rules.d.ts +26 -45
  35. package/dist/core/permission-rules.js +77 -57
  36. package/dist/core/runner/child-tree.d.ts +97 -0
  37. package/dist/core/runner/child-tree.js +104 -0
  38. package/dist/core/runner/construction-doors.d.ts +5 -0
  39. package/dist/core/runner/construction-doors.js +6 -0
  40. package/dist/core/runner/contracts.d.ts +46 -0
  41. package/dist/core/runner/gate-exit.d.ts +4 -1
  42. package/dist/core/runner/gate-exit.js +5 -1
  43. package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
  44. package/dist/core/runner/permission-rule-lanes.js +18 -12
  45. package/dist/core/runner/persisted-path-rows.d.ts +31 -7
  46. package/dist/core/runner/persisted-path-rows.js +31 -12
  47. package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
  48. package/dist/core/runner/prepare-ask-lane.js +4 -2
  49. package/dist/core/runner/prepare-execution-env.d.ts +5 -2
  50. package/dist/core/runner/prepare-execution-env.js +10 -3
  51. package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
  52. package/dist/core/runner/prepare-gate-stations.js +2 -1
  53. package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
  54. package/dist/core/runner/prepare-hands-readface.js +11 -11
  55. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
  56. package/dist/core/runner/prepare-inherited-gate.js +8 -2
  57. package/dist/core/runner/prepare-park-ask.d.ts +3 -0
  58. package/dist/core/runner/prepare-park-ask.js +5 -3
  59. package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
  60. package/dist/core/runner/prepare-policy-chain.js +13 -5
  61. package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
  62. package/dist/core/runner/prepare-suspend-saga.js +7 -1
  63. package/dist/core/runner/prepare-task.js +37 -18
  64. package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
  65. package/dist/core/runner/prepare-turn-wiring.js +2 -1
  66. package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
  67. package/dist/core/runner/prepare-workspace-restore.js +1 -0
  68. package/dist/core/runner/resume-apply.js +17 -3
  69. package/dist/core/runner/resume-checkpoint-screen.js +13 -0
  70. package/dist/core/runner/run-leg.js +5 -1
  71. package/dist/core/runner/runtask.js +2 -2
  72. package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
  73. package/dist/core/runner/write-protection-station.d.ts +3 -2
  74. package/dist/core/runner/write-protection-station.js +1 -0
  75. package/dist/core/runner-deps.d.ts +14 -0
  76. package/dist/core/sensitive-path-policy.d.ts +8 -0
  77. package/dist/core/sensitive-path-policy.js +18 -2
  78. package/dist/core/shell-wrapper-projection.d.ts +11 -0
  79. package/dist/core/shell-wrapper-projection.js +56 -0
  80. package/dist/core/shell-wrapper-table.d.ts +144 -34
  81. package/dist/core/shell-wrapper-table.js +40 -20
  82. package/dist/core/synthetic-read-verdict.d.ts +3 -0
  83. package/dist/core/synthetic-read-verdict.js +3 -1
  84. package/dist/core/tool-catalog-entries.d.ts +21 -0
  85. package/dist/core/tool-catalog-entries.js +12 -2
  86. package/dist/core/tool-face.d.ts +10 -1
  87. package/dist/core/tool-name-readings.d.ts +8 -0
  88. package/dist/core/tool-name-readings.js +2 -0
  89. package/dist/core/tool-policy.d.ts +40 -17
  90. package/dist/core/tool-policy.js +11 -9
  91. package/dist/core/tool-registry.d.ts +9 -0
  92. package/dist/core/tool-registry.js +10 -0
  93. package/dist/core/tool-spec.d.ts +3 -2
  94. package/dist/core/write-protect.d.ts +14 -3
  95. package/dist/core/write-protect.js +41 -10
  96. package/dist/index.d.ts +6 -4
  97. package/dist/index.js +5 -3
  98. package/dist/orchestration/run-spec.js +8 -7
  99. package/dist/orchestration/workflow.js +1 -1
  100. package/dist/shell/lex.d.ts +22 -0
  101. package/dist/shell/lex.js +75 -13
  102. package/dist/tools/fs/bash-program-position.d.ts +14 -90
  103. package/dist/tools/fs/bash-program-position.js +41 -74
  104. package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
  105. package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
  106. package/dist/tools/fs/index.d.ts +3 -2
  107. package/dist/tools/fs/program-read-model.d.ts +711 -0
  108. package/dist/tools/fs/program-read-model.js +1259 -0
  109. package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
  110. package/dist/tools/fs/program-read-model.rows.js +624 -0
  111. package/dist/tools/fs/read-deny-home.d.ts +19 -1
  112. package/dist/tools/fs/read-deny-home.js +62 -24
  113. package/dist/tools/fs/read-deny.d.ts +54 -14
  114. package/dist/tools/fs/read-deny.js +104 -50
  115. package/dist/tools/fs/removal-targets.d.ts +7 -6
  116. package/dist/tools/fs/removal-targets.js +34 -24
  117. package/dist/tools/fs/safety.d.ts +3 -0
  118. package/dist/tools/fs/safety.js +10 -3
  119. package/dist/tools/fs/shell-read-argv.d.ts +86 -0
  120. package/dist/tools/fs/shell-read-argv.js +388 -0
  121. package/dist/tools/fs/shell-read-bindings.d.ts +300 -0
  122. package/dist/tools/fs/shell-read-bindings.js +755 -0
  123. package/dist/tools/fs/shell-read-check.js +23 -15
  124. package/dist/tools/fs/shell-read-establish.js +82 -8
  125. package/dist/tools/fs/shell-read-judge.d.ts +11 -1
  126. package/dist/tools/fs/shell-read-judge.js +9 -1
  127. package/dist/tools/fs/shell-read-plan.d.ts +33 -8
  128. package/dist/tools/fs/shell-read-plan.js +309 -407
  129. package/dist/tools/fs/shell-read-word.d.ts +60 -26
  130. package/dist/tools/fs/shell-read-word.js +47 -37
  131. package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
  132. package/dist/tools/fs/shell-read-write-targets.js +85 -137
  133. package/dist/tools/fs/shell-reentry-text.d.ts +136 -6
  134. package/dist/tools/fs/shell-reentry-text.js +203 -53
  135. package/dist/tools/monitor.d.ts +3 -3
  136. package/package.json +1 -1
  137. package/test/export-surface.snapshot.json +25 -5
  138. package/wire-changes/core@7.46.0.json +1522 -0
  139. 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: ["-u", "-C", "-a", "-P", "--unset", "--chdir", "--argv0"], flags: ["-i", "-0", "-v", "--ignore-environment", "--null", "--debug", "--list-signal-handling", "--default-signal", "--ignore-signal", "--block-signal", "--help", "--version"], commandString: ["-S", "--split-string"], bareDash: true, assignments: true },
8
- sudo: { valueFlags: ["-u", "-g", "-U", "-C", "-D", "-h", "-p", "-r", "-R", "-t", "-T", "--user", "--group", "--other-user", "--close-from", "--chdir", "--host", "--prompt", "--role", "--chroot", "--type", "--command-timeout", "-a", "--auth-type"], flags: ["-A", "-b", "-E", "-H", "-i", "-K", "-k", "-l", "-n", "-P", "-S", "-s", "-V", "-v", "--askpass", "--background", "--preserve-env", "--set-home", "--login", "--remove-timestamp", "--reset-timestamp", "--list", "--non-interactive", "--preserve-groups", "--stdin", "--shell", "--version", "--validate", "--bell", "--help"], commandString: [], assignments: true },
9
- doas: { valueFlags: ["-a", "-u", "-C"], flags: ["-L", "-n", "-s"], commandString: [] },
10
- pkexec: { valueFlags: ["--user"], flags: ["--disable-internal-agent", "--keep-cwd", "--version", "--help"], commandString: [] },
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: ["-o", "--output", "-f", "--format"], flags: ["-p", "-a", "-v", "-q", "--append", "--portability", "--verbose", "--quiet", "--help", "--version"], commandString: [] },
13
- nice: { valueFlags: ["-n", "--adjustment"], flags: ["--help", "--version"], commandString: [] },
14
- timeout: { valueFlags: ["-k", "-s", "--kill-after", "--signal"], flags: ["-v", "--foreground", "--preserve-status", "--verbose", "--help", "--version"], commandString: [], duration: true },
15
- stdbuf: { valueFlags: ["-i", "-o", "-e", "--input", "--output", "--error"], flags: ["--help", "--version"], commandString: [] },
16
- xargs: { valueFlags: ["-n", "-L", "-P", "-I", "-d", "-s", "-a", "-E", "--max-args", "--max-procs", "--delimiter", "--max-chars", "--arg-file", "--process-slot-var"], flags: ["-0", "-r", "-t", "-x", "-p", "-o", "--null", "--no-run-if-empty", "--verbose", "--exit", "--interactive", "--open-tty", "--show-limits", "--help", "--version", "--replace", "--eof", "--max-lines"], attached: ["-i", "-l"], commandString: [] },
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: ["-c", "-n", "-p", "-P", "-u", "--class", "--classdata", "--pid", "--pgid", "--uid"], flags: ["-t", "--ignore", "-h", "--help", "-V", "--version"], commandString: [] },
19
- setsid: { valueFlags: [], flags: ["-c", "-f", "-w", "--ctty", "--fork", "--wait", "--help", "--version"], commandString: [] },
20
- taskset: { valueFlags: [], flags: ["-a", "-p", "-c", "--all-tasks", "--pid", "--cpu-list", "--help", "--version"], commandString: [], positional: /^(?:0x)?[\da-f]+$|^[\d,:-]+$/i },
21
- chrt: { valueFlags: ["-p", "--pid", "-T", "-P", "-D", "--sched-runtime", "--sched-period", "--sched-deadline"], flags: ["-b", "-f", "-i", "-o", "-r", "-d", "-m", "-a", "-R", "-v", "--batch", "--fifo", "--idle", "--other", "--rr", "--deadline", "--max", "--all-tasks", "--reset-on-fork", "--verbose", "--help", "--version"], commandString: [], positional: /^\d+$/ },
22
- strace: { valueFlags: ["-e", "-o", "-p", "-s", "-E", "-P", "-S", "-a", "-b", "-I", "-u", "-X", "-O", "-U", "--output", "--trace", "--expr", "--attach", "--string-limit", "--env", "--trace-path", "--columns", "--user", "--interruptible", "--detach-on", "--const-print-style", "--summary-sort-by", "--summary-syscall-overhead", "--summary-columns"], flags: ["-f", "-ff", "-c", "-C", "-d", "-D", "-h", "-i", "-k", "-q", "-qq", "-r", "-t", "-tt", "-ttt", "-T", "-v", "-V", "-w", "-x", "-xx", "-y", "-yy", "-z", "-Z", "-F", "--follow-forks", "--summary-only", "--summary", "--debug", "--help", "--version"], commandString: [] },
23
- ltrace: { valueFlags: ["-a", "-A", "-e", "-l", "-n", "-o", "-p", "-s", "-u", "-x", "-D", "-F", "--align", "--config", "--debug", "--indent", "--library", "--output", "--string-max", "-w", "--where"], flags: ["-c", "-C", "-f", "-i", "-L", "-r", "-S", "-t", "-tt", "-ttt", "-T", "-V", "--demangle", "--help", "--version"], commandString: [] },
24
- flock: { valueFlags: ["-w", "-E", "--timeout", "--wait", "--conflict-exit-code"], flags: ["-s", "-x", "-u", "-n", "-o", "-F", "--shared", "--exclusive", "--unlock", "--nonblock", "--nb", "--close", "--no-fork", "--verbose", "--help", "--version"], commandString: ["-c", "--command"], positional: /^/ },
25
- script: { valueFlags: [], flags: [], commandString: ["-c", "--command"], viaShell: true },
26
- unshare: { valueFlags: ["-R", "-w", "-S", "-G", "--setuid", "--setgid", "--root", "--wd", "--propagation", "--setgroups", "--monotonic", "--boottime", "--map-user", "--map-group"], flags: ["-m", "-u", "-i", "-n", "-p", "-U", "-C", "-T", "-f", "-r", "-c", "--mount", "--uts", "--ipc", "--net", "--pid", "--user", "--cgroup", "--time", "--fork", "--map-root-user", "--map-current-user", "--kill-child", "--mount-proc", "--keep-caps", "--help", "--version"], commandString: [] },
27
- nsenter: { valueFlags: ["-t", "-S", "-G", "--target", "--setuid", "--setgid"], flags: ["-a", "-m", "-u", "-i", "-n", "-p", "-U", "-C", "-T", "-r", "-w", "-F", "-Z", "--all", "--mount", "--uts", "--ipc", "--net", "--pid", "--user", "--cgroup", "--time", "--root", "--wd", "--no-fork", "--preserve-credentials", "--help", "--version"], commandString: [] },
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(["printf", "unset", "read", "mapfile", "readarray", "declare", "typeset", "local", "export", "readonly", "test", "[", "[["]);
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 req = {
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 SHELL_RULE_FACE = { primaryParams: ["command"], params: ["command", "timeout", "description", "run_in_background"] };
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
+ }
@@ -201,7 +201,16 @@ export interface ToolFaceDeclaration {
201
201
  };
202
202
  aliases?: string[];
203
203
  pathTarget?: ToolPathTarget;
204
- ruleFace?: ToolRuleFace;
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 path DENY rules that speak for a face of the engine's deny table (a `Read(<pattern>)` / `Edit(<pattern>)`
541
- * deny compiled by `createPermissionRulePolicy`), as rows the prepared leg joins to its read and write tables — so the
542
- * shell's reads and writes and the traversals meet the rule, not only the tool it names. Carried through
543
- * {@link combinePolicies}; read with {@link toolPolicyPathDenyRules}. Deny-only: a row can only refuse more. */
544
- readonly pathDenyRules?: readonly import("../tools/fs/read-deny.js").PathRuleDenyRow[];
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", "pathDenyRules", "writeTargetGuard", "nameSets"];
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 deny row the given policies carry (combined policies included), in order — the deny tables' rule rows. */
574
- export declare function toolPolicyPathDenyRules(policies: readonly (ToolPolicy | undefined)[]): readonly import("../tools/fs/read-deny.js").PathRuleDenyRow[];
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. `Monitor`
959
- * belongs here: it runs an arbitrary shell `command` through the same env seam as Bash, so the always-on parity gates
960
- * keyed on this list reach it too (a list of `Bash` alone let the identical command run ungated as `Monitor`). EXPORTED:
961
- * a downstream governance layer keeps its own copy of this list so its per-command ask-list gates the same tools core
962
- * does — the list itself is the fact, and publishing it removes the guess.
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: string[];
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 `Bash` — bash + bash_readonly share the CC name). */
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 `Bash`). */
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 `Bash`). */
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
  /**
@@ -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", "pathDenyRules", "writeTargetGuard", "nameSets"];
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 toolPolicyPathDenyRules(policies) {
156
- return policies.flatMap((p) => (Array.isArray(p?.pathDenyRules) ? p.pathDenyRules : []));
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 pathDenyRules = toolPolicyPathDenyRules(policies);
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
- pathDenyRules: pathDenyRules.length > 0 ? pathDenyRules : undefined,
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
- current = { ...current, args: d.updatedInput };
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
  }
@@ -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 can inject tools whose
216
- * identity does not exist until the call happens — and the reader fails closed on that.
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` ⇒ `deny` naming the cause: an unjudged target is never vouched, and an ask would be a
209
- * question about a file nobody can name — the rule the canonicalizing deny set follows for the same reason.
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