@sema-agent/core 7.29.0 → 7.30.1

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 (158) hide show
  1. package/CHANGELOG.md +393 -0
  2. package/dist/agents/child-model-seat.d.ts +59 -7
  3. package/dist/agents/child-model-seat.js +33 -7
  4. package/dist/agents/cross-session-judge.d.ts +27 -5
  5. package/dist/agents/cross-session-judge.js +23 -12
  6. package/dist/agents/list-agents-tool.d.ts +31 -6
  7. package/dist/agents/list-agents-tool.js +66 -14
  8. package/dist/agents/peer-admission.d.ts +20 -8
  9. package/dist/agents/peer-admission.js +21 -12
  10. package/dist/agents/peer-directory.d.ts +29 -0
  11. package/dist/agents/peer-directory.js +20 -0
  12. package/dist/agents/peer-held-queue.d.ts +31 -4
  13. package/dist/agents/peer-held-queue.js +32 -1
  14. package/dist/agents/peer-session-drain.d.ts +91 -13
  15. package/dist/agents/peer-session-drain.js +409 -102
  16. package/dist/agents/read-inbox-tool.d.ts +22 -0
  17. package/dist/agents/read-inbox-tool.js +39 -0
  18. package/dist/agents/roster-store.d.ts +2 -4
  19. package/dist/agents/roster-store.js +1 -1
  20. package/dist/agents/send-message-tool.d.ts +4 -4
  21. package/dist/agents/send-message-tool.js +22 -2
  22. package/dist/agents/subagent.js +62 -44
  23. package/dist/agents/team-role.d.ts +34 -0
  24. package/dist/agents/team-role.js +17 -0
  25. package/dist/agents/verify.js +2 -2
  26. package/dist/core/auto-compaction.d.ts +42 -0
  27. package/dist/core/auto-compaction.js +35 -2
  28. package/dist/core/child-clamp-seats.d.ts +11 -0
  29. package/dist/core/child-clamp-seats.js +3 -0
  30. package/dist/core/context-edit.d.ts +3 -2
  31. package/dist/core/context-edit.js +6 -5
  32. package/dist/core/context-guard.d.ts +2 -1
  33. package/dist/core/context-guard.js +3 -2
  34. package/dist/core/context-settings.d.ts +103 -0
  35. package/dist/core/context-settings.js +60 -0
  36. package/dist/core/engine-notice.d.ts +11 -1
  37. package/dist/core/frame-settlement.d.ts +97 -0
  38. package/dist/core/frame-settlement.js +36 -0
  39. package/dist/core/governance-codes.d.ts +1 -1
  40. package/dist/core/governance-codes.js +2 -0
  41. package/dist/core/hooks.d.ts +10 -10
  42. package/dist/core/mailbox-store.d.ts +41 -7
  43. package/dist/core/mailbox-store.js +9 -3
  44. package/dist/core/parent-spec-seat.d.ts +14 -1
  45. package/dist/core/parent-spec-seat.js +6 -0
  46. package/dist/core/permission-rule-model.js +1 -1
  47. package/dist/core/roles.d.ts +20 -0
  48. package/dist/core/roles.js +35 -16
  49. package/dist/core/runner/assemble-result.d.ts +2 -0
  50. package/dist/core/runner/assemble-result.js +1 -1
  51. package/dist/core/runner/compaction-call-options.d.ts +26 -2
  52. package/dist/core/runner/compaction-call-options.js +9 -0
  53. package/dist/core/runner/compaction-seams.d.ts +4 -3
  54. package/dist/core/runner/compaction-seams.js +13 -6
  55. package/dist/core/runner/contracts.d.ts +56 -7
  56. package/dist/core/runner/decide-continuation.d.ts +2 -1
  57. package/dist/core/runner/decide-continuation.js +11 -10
  58. package/dist/core/runner/initial-run-state.js +1 -1
  59. package/dist/core/runner/prepare-caps-and-workflow.js +9 -1
  60. package/dist/core/runner/prepare-config-doors.js +4 -1
  61. package/dist/core/runner/prepare-context-lane.d.ts +9 -2
  62. package/dist/core/runner/prepare-context-lane.js +15 -10
  63. package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
  64. package/dist/core/runner/prepare-delegation-surface.js +9 -3
  65. package/dist/core/runner/prepare-file-history.js +10 -8
  66. package/dist/core/runner/prepare-gate-stations.d.ts +4 -0
  67. package/dist/core/runner/prepare-gate-stations.js +3 -1
  68. package/dist/core/runner/prepare-inherited-gate.js +1 -0
  69. package/dist/core/runner/prepare-prompt-inputs.d.ts +6 -0
  70. package/dist/core/runner/prepare-prompt-inputs.js +2 -1
  71. package/dist/core/runner/prepare-task.js +22 -9
  72. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -1
  73. package/dist/core/runner/prepare-wiring-manifest.js +6 -1
  74. package/dist/core/runner/retired-runner-deps.d.ts +3 -1
  75. package/dist/core/runner/retired-runner-deps.js +1 -0
  76. package/dist/core/runner/run-compaction-machinery.d.ts +4 -2
  77. package/dist/core/runner/run-compaction-machinery.js +5 -3
  78. package/dist/core/runner/run-harness-handlers.js +1 -1
  79. package/dist/core/runner/run-identity-wiring.js +19 -1
  80. package/dist/core/runner/run-leg.js +1 -1
  81. package/dist/core/runner/run-notification-lane.js +8 -2
  82. package/dist/core/runner/run-recovery-lanes.js +9 -5
  83. package/dist/core/runner/run-settle-and-teardown.d.ts +4 -22
  84. package/dist/core/runner/run-settle-and-teardown.js +6 -10
  85. package/dist/core/runner/run-stop-and-final-verify.js +1 -0
  86. package/dist/core/runner/run-terminal-adoption.js +5 -5
  87. package/dist/core/runner/run-turn-boundary.js +32 -5
  88. package/dist/core/runner/runtask.d.ts +8 -1
  89. package/dist/core/runner/runtask.js +32 -1
  90. package/dist/core/runner-deps.d.ts +44 -13
  91. package/dist/core/secret-env.js +2 -1
  92. package/dist/core/swappable-deps.d.ts +20 -4
  93. package/dist/core/swappable-deps.js +6 -1
  94. package/dist/core/task-event.d.ts +5 -0
  95. package/dist/core/task-notification.d.ts +144 -2
  96. package/dist/core/task-notification.js +154 -5
  97. package/dist/core/task-result.d.ts +14 -0
  98. package/dist/core/task-spec.d.ts +7 -0
  99. package/dist/core/tool-catalog-entries.js +2 -1
  100. package/dist/core/tool-conformance.js +1 -0
  101. package/dist/core/tool-policy.d.ts +9 -4
  102. package/dist/core/tool-spec.d.ts +14 -0
  103. package/dist/core/wiring-manifest.d.ts +12 -0
  104. package/dist/core/wiring-manifest.js +5 -1
  105. package/dist/engine/harness/agent-harness.d.ts +14 -1
  106. package/dist/engine/harness/agent-harness.js +28 -3
  107. package/dist/engine/harness/types.d.ts +3 -1
  108. package/dist/engine/llm/types.d.ts +8 -7
  109. package/dist/engine/llm/types.js +1 -1
  110. package/dist/engine/lsp/node-lsp-manager.d.ts +3 -0
  111. package/dist/engine/lsp/node-lsp-manager.js +5 -3
  112. package/dist/engine/session/import-validate.js +4 -0
  113. package/dist/index.d.ts +10 -7
  114. package/dist/index.js +7 -5
  115. package/dist/orchestration/run-workflow-tool.d.ts +4 -4
  116. package/dist/orchestration/workflow.d.ts +1 -1
  117. package/dist/orchestration/workflow.js +8 -5
  118. package/dist/shell/lex.d.ts +38 -54
  119. package/dist/shell/lex.js +239 -286
  120. package/dist/stores/cc/mailbox-store.js +3 -2
  121. package/dist/stores/file/corrupt-read-sink.d.ts +28 -2
  122. package/dist/stores/file/file-history-store.d.ts +2 -4
  123. package/dist/stores/file/file-history-store.js +1 -1
  124. package/dist/stores/file/fs-atomic.d.ts +16 -11
  125. package/dist/stores/file/fs-atomic.js +17 -6
  126. package/dist/stores/file/index.d.ts +5 -6
  127. package/dist/stores/file/index.js +1 -1
  128. package/dist/stores/file/mailbox-store.d.ts +4 -9
  129. package/dist/stores/file/mailbox-store.js +29 -30
  130. package/dist/stores/file/session-policy-store.d.ts +2 -0
  131. package/dist/stores/file/session-policy-store.js +1 -1
  132. package/dist/stores/file/session-store.d.ts +11 -7
  133. package/dist/stores/file/session-store.js +23 -16
  134. package/dist/stores/file/shared-ledger.js +3 -14
  135. package/dist/stores/file/tool-result-store.d.ts +2 -0
  136. package/dist/stores/file/tool-result-store.js +5 -2
  137. package/dist/stores/file/workflow-journal-store.js +14 -9
  138. package/dist/tools/fs/bash-program-position.d.ts +15 -24
  139. package/dist/tools/fs/bash-program-position.js +11 -29
  140. package/dist/tools/fs/bash-readonly-classifier.d.ts +131 -117
  141. package/dist/tools/fs/bash-readonly-classifier.js +404 -272
  142. package/dist/tools/fs/shell-read-check.js +3 -3
  143. package/dist/tools/fs/shell-read-establish.d.ts +1 -1
  144. package/dist/tools/fs/shell-read-establish.js +5 -33
  145. package/dist/tools/fs/shell-read-identity.d.ts +13 -0
  146. package/dist/tools/fs/shell-read-identity.js +39 -0
  147. package/dist/tools/fs/shell-read-judge.d.ts +8 -0
  148. package/dist/tools/fs/shell-read-judge.js +7 -0
  149. package/dist/tools/fs/shell-read-plan.d.ts +15 -6
  150. package/dist/tools/fs/shell-read-plan.js +171 -195
  151. package/dist/tools/fs/shell-read-word.d.ts +64 -0
  152. package/dist/tools/fs/shell-read-word.js +94 -0
  153. package/dist/tools/fs/shell-reentry-text.d.ts +10 -0
  154. package/dist/tools/fs/shell-reentry-text.js +73 -0
  155. package/package.json +1 -1
  156. package/test/export-surface.snapshot.json +58 -8
  157. package/wire-changes/core@7.30.0.json +1821 -0
  158. package/wire-changes/core@7.30.1.json +154 -0
@@ -8,7 +8,7 @@ import { planShellReads } from "./shell-read-plan.js";
8
8
  import { createShellReadEstablisher, establishShellReadsLexically } from "./shell-read-establish.js";
9
9
  import { allFindings, decideShellRead, foldShellReadFindings, judgeEstablishedPlan, readRootGrantCandidateOf, } from "./shell-read-judge.js";
10
10
  import { normalizeReadRootCandidate } from "../../core/read-root-candidate.js";
11
- import { wordsOf, lexShellText } from "../../shell/lex.js";
11
+ import { argvOf, lexShellText } from "../../shell/lex.js";
12
12
  function containmentDetails(paths) {
13
13
  return { type: "readonly_out_of_root", code: "readonly_out_of_root", paths };
14
14
  }
@@ -18,9 +18,9 @@ function shellCommandOf(args) {
18
18
  return typeof command === "string" ? command : undefined;
19
19
  }
20
20
  function declineSentence(segment) {
21
- const lexed = lexShellText(segment.text, { mode: "lenient" });
21
+ const lexed = lexShellText(segment.text);
22
22
  if (!("reject" in lexed) && lexed.segments[0] !== undefined) {
23
- const pos = readProgramPosition(wordsOf(lexed.segments[0]));
23
+ const pos = readProgramPosition(argvOf(lexed.segments[0]));
24
24
  if (pos.refusal !== undefined)
25
25
  return programPositionRefusalSentence(pos.refusal);
26
26
  if (pos.argvFromStdin) {
@@ -35,7 +35,7 @@
35
35
  */
36
36
  import type { ExecutionEnv } from "../../internal/harness-types.js";
37
37
  import type { ShellReadPlan, ShellReadSegment } from "./shell-read-plan.js";
38
- import type { EstablishedRead, ShellReadBoundary } from "./shell-read-judge.js";
38
+ import { type EstablishedRead, type ShellReadBoundary } from "./shell-read-judge.js";
39
39
  /**
40
40
  * How many directories one glob operand (or one traversal root) may enumerate, and how many names it may
41
41
  * match, before the leg gives up and answers `unestablishable`.
@@ -1,6 +1,8 @@
1
1
  import { normalizeAbsPathLexically, pathFamilyOf } from "./safety.js";
2
2
  import { boundaryIsTheSandbox, canonicalPathIsAuthoritative } from "../../core/remote-env.js";
3
3
  import { resolveOperandSpellings } from "./bash-readonly-classifier.js";
4
+ import { denyFloorShadowsOf } from "./shell-read-judge.js";
5
+ import { movedReads } from "./shell-read-identity.js";
4
6
  const GLOB_METACHAR_RE = /[*?[]/;
5
7
  export const MAX_GLOB_DIRS = 256;
6
8
  export const MAX_GLOB_MATCHES = 8192;
@@ -130,7 +132,8 @@ function lexicalReadsOf(candidate, boundary) {
130
132
  return out;
131
133
  }
132
134
  function judgedCandidatesOf(segment) {
133
- return segment.reads.filter((c) => c.provenance !== "write_redirect_target");
135
+ const reads = segment.reads.filter((c) => c.provenance !== "write_redirect_target");
136
+ return [...reads, ...denyFloorShadowsOf(reads)];
134
137
  }
135
138
  export function establishShellReadsLexically(plan, boundary) {
136
139
  const reads = new Map();
@@ -424,38 +427,7 @@ export function createShellReadEstablisher(env, readRoots) {
424
427
  if (lexicalOnly)
425
428
  return { changed: [] };
426
429
  const again = await establishPlan(previous.plan, { ...boundary, roots: previous.roots }, previous.roots, signal);
427
- const settled = (e) => {
428
- const out = [];
429
- const walk = (p) => {
430
- for (const reads of p.reads.values())
431
- for (const r of reads)
432
- if ((r.established === "canonical" || r.established === "expansion") && r.target !== undefined)
433
- out.push(r.target);
434
- for (const n of p.nested.values())
435
- walk(n);
436
- };
437
- walk(e);
438
- return out.sort();
439
- };
440
- const before = settled(previous);
441
- const after = new Set(settled(again));
442
- const beforeSet = new Set(before);
443
- const moved = before.filter((t) => !after.has(t));
444
- const appeared = [...after].filter((t) => !beforeSet.has(t));
445
- if (moved.length === 0 && appeared.length === 0)
446
- return { changed: [] };
447
- const changed = [];
448
- const collect = (p) => {
449
- for (const reads of p.reads.values())
450
- for (const r of reads)
451
- if (r.target !== undefined && (moved.includes(r.target) || appeared.includes(r.target)))
452
- changed.push(r);
453
- for (const n of p.nested.values())
454
- collect(n);
455
- };
456
- collect(previous);
457
- collect(again);
458
- return { changed };
430
+ return { changed: movedReads(previous, again) };
459
431
  },
460
432
  };
461
433
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The pre-spawn identity comparison: which established reads of one plan resolve somewhere else now.
3
+ *
4
+ * Compared PER CANDIDATE, never as one pooled set of targets: a candidate is keyed by where it stands in the plan
5
+ * (segment, nested plan) and by what it is (deny-only or a read, provenance, spelling, expansion, raw word), and its
6
+ * set of established targets is compared with the same candidate's set from the re-establishment. A pooled set let
7
+ * one candidate's targets hide another's move — `head linkx` retargeted onto a path some other word's pattern already
8
+ * matched, or onto a home shadow's target, left the pool unchanged and the call was admitted unjudged.
9
+ */
10
+ import type { EstablishedPlan } from "./shell-read-establish.js";
11
+ import type { EstablishedRead } from "./shell-read-judge.js";
12
+ /** Every read of either establishment whose candidate's settled target set differs between the two. */
13
+ export declare function movedReads(previous: EstablishedPlan, again: EstablishedPlan): EstablishedRead[];
@@ -0,0 +1,39 @@
1
+ export function movedReads(previous, again) {
2
+ const before = targetsByCandidate(previous);
3
+ const after = targetsByCandidate(again);
4
+ const changed = [];
5
+ for (const key of new Set([...before.keys(), ...after.keys()])) {
6
+ const b = before.get(key);
7
+ const a = after.get(key);
8
+ if (b !== undefined && a !== undefined && sameTargets(b.targets, a.targets))
9
+ continue;
10
+ changed.push(...(b?.reads ?? []), ...(a?.reads ?? []));
11
+ }
12
+ return changed.filter((r) => r.target !== undefined);
13
+ }
14
+ function targetsByCandidate(e) {
15
+ const out = new Map();
16
+ const walk = (p, at) => {
17
+ p.plan.segments.forEach((segment, si) => {
18
+ for (const r of p.reads.get(segment) ?? []) {
19
+ const c = r.candidate;
20
+ const key = [at, si, c.denyOnly === true ? "floor" : "read", c.provenance, c.spelled, String(c.expands), c.raw].join("\0");
21
+ const landing = out.get(key) ?? { targets: new Set(), reads: [] };
22
+ out.set(key, landing);
23
+ landing.reads.push(r);
24
+ if ((r.established === "canonical" || r.established === "expansion") && r.target !== undefined)
25
+ landing.targets.add(r.target);
26
+ }
27
+ segment.nested.forEach((n, ni) => {
28
+ const nested = p.nested.get(n);
29
+ if (nested !== undefined)
30
+ walk(nested, `${at}/${si}.${ni}`);
31
+ });
32
+ });
33
+ };
34
+ walk(e, "");
35
+ return out;
36
+ }
37
+ function sameTargets(a, b) {
38
+ return a.size === b.size && [...a].every((t) => b.has(t));
39
+ }
@@ -173,6 +173,14 @@ export interface ReadFinding {
173
173
  * neither is a containment candidate — both still meet the deny judge, on every spelling.
174
174
  */
175
175
  export declare function judgeRead(read: EstablishedRead, boundary: ShellReadBoundary): ReadFinding;
176
+ /**
177
+ * The deny floor of every home word the plan does not place: each candidate carrying a `floorSpelled` (the word
178
+ * spelled with the DECLARED home) gets a SHADOW candidate at that spelling, established exactly as a read is — the
179
+ * canonical target, a pattern's matches (a glob the word carries unquoted), a traversal root's tree — and judged for
180
+ * deny rows only (`denyOnly`). A deny row is a floor the text's rebinding may never reach past; the shadow adds no
181
+ * other finding, so a read that is not a deny row still asks through its own unplaced candidate.
182
+ */
183
+ export declare function denyFloorShadowsOf(candidates: readonly ReadCandidate[]): ReadCandidate[];
176
184
  /** One segment's judged reads and declines, with its nested plans judged the same way. */
177
185
  export interface JudgedSegment {
178
186
  readonly segment: ShellReadSegment;
@@ -1,4 +1,6 @@
1
1
  import { hasWin32AliasedComponent, normalizeAbsPathLexically, withinAnyRoot } from "./safety.js";
2
+ import { globInWord } from "./bash-readonly-classifier.js";
3
+ import { readOfText } from "./shell-read-word.js";
2
4
  export const SHELL_READ_FINDINGS = ["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "none"];
3
5
  export const SHELL_READ_SEATS = ["bash_off", "bash_classify", "readonly", "rejudge"];
4
6
  export const SHELL_READ_FINDING_RANK = {
@@ -32,6 +34,8 @@ export function judgeRead(read, boundary) {
32
34
  }
33
35
  }
34
36
  const containment = containmentOf(read, boundary);
37
+ if (read.candidate.denyOnly === true)
38
+ return { read, kind: "none", containment };
35
39
  const provenance = read.candidate.provenance;
36
40
  if (provenance === "env_assignment" || (provenance === "program_path" && read.candidate.expands !== "unresolvable"))
37
41
  return { read, kind: "none", containment };
@@ -39,6 +43,9 @@ export function judgeRead(read, boundary) {
39
43
  return { read, kind: "unestablishable", containment };
40
44
  return { read, kind: containment === "outside" ? "outside_roots" : "none", containment };
41
45
  }
46
+ export function denyFloorShadowsOf(candidates) {
47
+ return candidates.flatMap((c) => (c.floorSpelled === undefined ? [] : [{ spelled: c.floorSpelled, raw: c.raw, provenance: c.provenance, expands: globInWord(readOfText(c.raw).word) ? "glob" : false, bases: [], denyOnly: true }]));
48
+ }
42
49
  function containmentOf(read, boundary) {
43
50
  if (boundary.face === "open")
44
51
  return "open";
@@ -4,8 +4,8 @@
4
4
  * The read boundary today re-derives "which words may be read" at several sites (the compound walk, the
5
5
  * containment-only gate, the refused-command whitelist, the execute-time recheck), each with its own idea
6
6
  * of launchers, option slots, redirections and re-entry. This module is the single extraction those sites
7
- * are to consume: a pure, zero-I/O function over the lenient lexer (`src/shell/lex.ts`) and the program-position
8
- * reader (`bash-program-position.ts`), returning every path word a command MAY read, each tagged with its
7
+ * are to consume: a pure, zero-I/O function over the one lexer's word FACTS (`src/shell/lex.ts`) and the
8
+ * program-position reader (`bash-program-position.ts`), returning every path word a command MAY read, each tagged with its
9
9
  * PROVENANCE (why it is a candidate) and the working-directory candidates it is relative to. Establishment
10
10
  * (`shell-read-establish.ts`) and judgment are downstream; nothing here decides allow/ask/deny.
11
11
  *
@@ -15,8 +15,9 @@
15
15
  * · an UNLISTED program hands every word of its argv (a program declared to open no path operand hands none);
16
16
  * · a LAUNCHER chain is peeled to its program and the chain's own words are never candidates; a launcher
17
17
  * option the row cannot read is recorded as a decline and every word after it is handed over;
18
- * · a SHELL re-entry (`sh -c S`, `eval S`, a launcher handing text to a shell, `env -S S`) carries its text as a
19
- * NESTED plan; an argv re-entry (`xargs`) is a decline unless the target opens nothing it is handed;
18
+ * · a SHELL re-entry (`sh -c S`, `eval S`, a launcher handing text to a shell, `env -S S`, a builtin's code-body
19
+ * operand the shell runs later — `trap S SIG`, `alias N=S`, `mapfile -C S`) carries its text as a NESTED plan;
20
+ * an argv re-entry (`xargs`) is a decline unless the target opens nothing it is handed;
20
21
  * · an INTERPRETER's inline program is a shape fact (`reentry:"interpreter"`), never parsed, never a finding;
21
22
  * · `<` targets are read candidates, `>`-family targets are write targets (tagged, not read), here-documents
22
23
  * and here-strings are data (an UNQUOTED here-document body's substitutions are nested plans);
@@ -35,7 +36,8 @@ export type ReadCandidateProvenance = (typeof READ_CANDIDATE_PROVENANCES)[number
35
36
  export interface ShellReadDeclarations {
36
37
  /** The listed read verbs. They decide whether a segment is read by verb slots or word by word, never whether it hands candidates. */
37
38
  readonly readers: ReadonlySet<string>;
38
- /** Substituted for `$HOME` / `${HOME}` word spellings before lexing; `~` itself is left to establishment. */
39
+ /** The declared home: a word that spells it (`$HOME` / `${HOME}` — {@link homeExpansionOf}) is named by it,
40
+ * unless the command may rebind `HOME` (then `~` is unresolvable too); `~` itself is left to establishment. */
39
41
  readonly homeDir?: string;
40
42
  /** The working directory the first segment's relative words resolve against. */
41
43
  readonly cwd: string;
@@ -60,6 +62,11 @@ export interface ReadCandidate {
60
62
  * A deny row is a floor, so the judge resolves the spelling against these for deny rows ONLY — never to
61
63
  * establish a read. `cd sub && cd $'\x2e' && cat <deny row under sub>` (bash: `cd .`) is refused through it. */
62
64
  readonly floorBases?: readonly string[];
65
+ /** A home word the plan does not place (the text may rebind `HOME`, or it sits in a value): spelled with the DECLARED
66
+ * home. A deny row is a floor: the judge reads it for deny rows ONLY, never to establish a read. */
67
+ readonly floorSpelled?: string;
68
+ /** A deny-floor shadow of a `floorSpelled` spelling, established as a read and judged for deny rows only. */
69
+ readonly denyOnly?: true;
63
70
  }
64
71
  /** How the shell reached one segment — what the base-candidate walk needs from the connectors. */
65
72
  export interface SegmentReach {
@@ -118,4 +125,6 @@ export interface ShellReadPlan {
118
125
  readonly strayRedirection: boolean;
119
126
  };
120
127
  }
121
- export declare function planShellReads(command: string, decl: ShellReadDeclarations, depth?: number): ShellReadPlan;
128
+ /** Plan every read candidate of one command (the contract is this module's header). `arithmetic` = the text is an
129
+ * `$((…))` body, which bash evaluates and never globs (no extended-glob floor). */
130
+ export declare function planShellReads(command: string, decl: ShellReadDeclarations, depth?: number, homeRebound?: boolean, arithmetic?: boolean): ShellReadPlan;