@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,4 +1,5 @@
1
1
  import { type LexedCommand, type LexedSegment, type LexedWord, type ShellLex, type ShellSegmentConnector, type WordPiece } from "../../shell/lex.js";
2
+ import { type ProgramRow } from "./program-read-model.js";
2
3
  /**
3
4
  * Bare command names `bash_readonly` permits out of the box, ALSO the default reversible set for the
4
5
  * The {@link import("./fs-bash.js").bashReversibilityProbe} classifier. **Coarse first filter, NOT a security
@@ -22,8 +23,8 @@ import { type LexedCommand, type LexedSegment, type LexedWord, type ShellLex, ty
22
23
  * no change on this face) that satisfy THIS list's curation bar (no write/mutation mode under any args)
23
24
  * without new stdin-floor/option-value modeling: pure status/computation printers (`cal`…`sleep` — none
24
25
  * reads stdin when bare, none takes a path it READS except realpath/readlink, which stay boundary-judged)
25
- * plus the floor-2 content comparers `diff`/`cmp`/`comm` (STDIN_FILE_FLOOR rows added alongside; diff's
26
- * recursive form was already modeled in RECURSIVE_READ_FORMS). Still deliberately excluded, each for a
26
+ * plus the floor-2 content comparers `diff`/`cmp`/`comm` (their rows state the floor of 2 operands; diff's
27
+ * recursive form was already a traversal row of the program read model). Still deliberately excluded, each for a
27
28
  * stated reason: `env` (an executor: `env FOO=1 cmd` runs cmd — CC excludes it too), `sort` (`-o` writes),
28
29
  * `uniq` (second positional is an OUTPUT file; CC allows a flags-only regex form this filter cannot
29
30
  * express), `printf` (builtin `-v var` assigns), `find` (CC allows only a regex excluding
@@ -156,7 +157,7 @@ export interface StrictResidualOptions {
156
157
  /** Only the two data-free spellings pass ({@link isDataFreeRedirection}); every other redirection refuses. */
157
158
  readonly dataFreeRedirections?: boolean;
158
159
  /** The declared home: a word that spells it ({@link homeExpansionOf}) is not an expansion to refuse — unless the
159
- * command may rebind `HOME` ({@link homeMayBeRebound}), which makes the declared home a guess. */
160
+ * command may rebind `HOME` ({@link textBindsHome}), which makes the declared home a guess. */
160
161
  readonly homeDir?: string;
161
162
  }
162
163
  /**
@@ -294,8 +295,8 @@ export interface BashReadonlyRootBoundary {
294
295
  * only, no ancestor intersection: the judge sees the operand's own resolved spelling, never its subtree.
295
296
  * The RECURSIVE-reach half of ① is narrowed — a listed recursive verb's path operand under this wired
296
297
  * seat rides {@link CompoundReadonlyVerdict.recursiveReadPaths} (⊂ undecidedPaths), so `grep -r x ~/` no
297
- * longer auto-allows; what REMAINS is the form table's stated open set (the KNOWN OPEN SET note at
298
- * {@link RECURSIVE_READ_FORMS}: a traversal verb absent there that a deployment allowlists classifies by
298
+ * longer auto-allows; what REMAINS is the traversal rows' stated open set (the KNOWN OPEN SET note at
299
+ * the program read model's traversal rows: a traversal verb absent there that a deployment allowlists classifies by
299
300
  * its ordinary form and can auto-run a traversal unjudged). ② LEXICAL only HERE — an in-root symlink
300
301
  * whose target is guarded reads as its innocent spelling at this seat, as it does for the containment
301
302
  * half, because the classify auto-allow lane has no I/O seat by contract; the CANONICAL view is judged by
@@ -346,31 +347,6 @@ export interface CompoundReadonlyVerdict {
346
347
  * uses the host's native separator.
347
348
  */
348
349
  export declare function formatOutOfRootReadApprovalOption(directory: string): string;
349
- /** Programs whose operands are NEVER filesystem paths, so no operand of theirs is checked:
350
- * `echo`'s words are literal text, `which`'s are PATH lookups, `tr`'s are character sets, and
351
- * `basename`/`dirname` do pure string surgery on a path without ever opening it. Everything else —
352
- * including a deployment-widened name this file does not know — goes through the path-shaped
353
- * operand scan below, which is safe for an unknown command because a bare word can only ever name
354
- * something under the working directory. */
355
- export declare const NO_PATH_OPERAND_COMMANDS: ReadonlySet<string>;
356
- /** The no-path-operand programs that EVALUATE a word (`test -v 'a[$(…)]'` runs the substitution in the subscript): a word
357
- * the shell or that evaluation rewrites is handed over as any program's is; only their settled words name nothing. */
358
- export declare const NO_PATH_OPERAND_EVALUATORS: ReadonlySet<string>;
359
- /** The builtins whose `NAME=value` arguments are assignments bash performs (and exports, for `export`), never paths. */
360
- export declare const DECLARATION_BUILTINS: ReadonlySet<string>;
361
- /** The shell BUILTINS that open no file, start no program and evaluate nothing: an external program's loader reads its
362
- * environment (`LD_PRELOAD` for `sleep`), `printf` reads `TZ` for `%(…)T` and assigns through `-v`, `test -v` and an
363
- * array subscript evaluate arithmetic (which runs a `$(…)` inside it). A declaration builtin counts only bare — no option
364
- * word (`-i` evaluates the value) — and every inert segment's words carry no `[` `]` `$` or backquote. */
365
- export declare const INERT_BUILTINS: ReadonlySet<string>;
366
- /** The indices of the SETTLED words a {@link MESSAGE_SLOTS} row reads as message text under the subcommand's grammar:
367
- * the value of `-m` (attached, or the next word) or of `--message` (`=`, or the next word; an unambiguous prefix of it
368
- * counts). A word the shell rewrites is never claimed, and neither is any word another option consumes — those words
369
- * stay the verb-blind walk's. */
370
- export declare function messageSlotWords(program: string, words: readonly {
371
- readonly folded: string;
372
- readonly expands: unknown;
373
- }[], programIndex: number): Set<number>;
374
350
  /** True for a token that can denote a filesystem location OUTSIDE the working directory. A bare word
375
351
  * (`foo`, `a.txt`, a grep pattern, an awk program) cannot: with no separator and no `..` it always
376
352
  * resolves under the cwd, which the caller's cwd governance already covers.
@@ -427,13 +403,6 @@ export interface OperandSpellings {
427
403
  /** Resolve one operand into {@link OperandSpellings}, or `undefined` on the same unresolvable operands
428
404
  * {@link resolveOperandLexically} reports (it is this function's folded half). */
429
405
  export declare function resolveOperandSpellings(base: string | undefined, operand: string, homeDir: string | undefined): OperandSpellings | undefined;
430
- /** Programs that run their argument AS SHELL TEXT (the sh family, `eval`, `source`, `.`): what they read is decided
431
- * by text nobody here parsed. Spelled as a pattern, not a name list — these are program names, never tool names.
432
- * The prefix alternation is the SPELLINGS of the shell, not a curated subset of them: the Almquist shell and
433
- * its descendants (`ash`, `mksh`, `yash`, `pdksh`) and the C shell family (`csh`, `tcsh`) all run `-c` text
434
- * exactly as `sh` does, and a deployment that meets one of them meets the whole member. GNU `parallel` is a member
435
- * for the reason it is not a launcher: it hands a BUILT command line to a shell. */
436
- export declare const SHELL_REENTRY_PROGRAM_RE: RegExp;
437
406
  /**
438
407
  * Does the shell REWRITE this word before the program sees it — a brace list, a parameter, command, process or
439
408
  * arithmetic expansion, or a `$` / backtick / brace character where bash reads it (unquoted; `$` and a backtick
@@ -444,7 +413,8 @@ export declare const SHELL_REENTRY_PROGRAM_RE: RegExp;
444
413
  * has no filesystem), such a word is declared unresolvable — the direction the whole file errs in.
445
414
  *
446
415
  * Deliberately NOT here: the GLOB characters ({@link globInWord}) — a glob only ever names entries of a
447
- * directory that is already on the command line — and a tilde, which the resolver reads.
416
+ * directory that is already on the command line — and a tilde, which the resolver reads. A bracket expression whose
417
+ * body carries an expansion (`[$x]`, `[$(…)]`: bash expands the members before it matches) IS here.
448
418
  */
449
419
  export declare function expansionInWord(w: {
450
420
  readonly pieces: readonly WordPiece[];
@@ -458,250 +428,6 @@ export declare function expansionInWord(w: {
458
428
  export declare function globInWord(w: {
459
429
  readonly pieces: readonly WordPiece[];
460
430
  }): boolean;
461
- /**
462
- * Does this token supply the verb's FIRST-OPERAND slot, so that the first operand is a FILE rather than the
463
- * slot ({@link VerbOptionSlots.firstOperand})? One reader, every verb with such a row.
464
- *
465
- * Read over the whole leading letter RUN, not a prefix: GNU clusters short options (`-if` is `-i -f`) and a
466
- * prefix reading left the slot to swallow — and therefore skip — a real file operand. Digits belong to the run
467
- * (grep's obsolete numeric context spec: `-2ebeta` is `-C2 -e beta`), and a long option is matched as an
468
- * ABBREVIATION of the declared name (`grep --reg=X <outside>` is `--regexp`). Over-triggering is harmless in
469
- * the direction that matters: a token wrongly counted here makes the first operand a CHECKED path candidate.
470
- */
471
- export declare function suppliesFirstOperandSlot(slot: NonNullable<VerbOptionSlots["firstOperand"]>, tok: string): boolean;
472
- /**
473
- * WHAT ONE OPTION'S VALUE IS, per verb — the one declaration every reader of an option token shares.
474
- *
475
- * The question asked of a value is always "can this name a file?", and the answer is a property of the
476
- * OPTION and its own grammar, never of the value's shape: `sed -e 's/a/b/'` and `sed -f s.sed` differ in
477
- * nothing a shape test can see. The kinds spell that answer out per slot so a row is auditable letter by
478
- * letter, and {@link slotValueCandidates} is where every consumer gets it — a kind that cannot name a
479
- * file yields nothing there, which is the same answer as "this value named none".
480
- */
481
- export type OptionValueKind = "path" | "indirect" | "pattern" | "script" | "count" | "delimiter" | "name-pattern" | "form" | "header" | "url" | "label";
482
- /**
483
- * One verb's option grammar: which short letters and long names take a VALUE, and what that value is.
484
- *
485
- * FAIL-SAFE BY CONSTRUCTION, which is what makes a PARTIAL row sound: the reader must account for every
486
- * option character it walks, so the first character a row does not declare ends the reading as
487
- * `unexplained` and hands the token back to the verb-blind payload scan ({@link attachedOptionPayloads})
488
- * — today's over-approximation, unchanged. A row therefore only ever makes an answer MORE precise where
489
- * it recognizes the option; omitting one costs precision, never a judgement.
490
- *
491
- * THREE ARITIES, because `getopt_long` has three. An option that takes no value, one that requires a
492
- * value (attached or the next token), and one whose value is OPTIONAL — and the third is not the second
493
- * with a caveat: `getopt_long` gives an optional value NO separated spelling, so `diff --unified a b`
494
- * hands diff two FILES while `diff --unified=3 a b` hands it a width. A row that files an optional-value
495
- * option under {@link VerbOptionSlots.longValue} therefore eats `a`, and the file operand it swallowed
496
- * is judged by nobody — the one direction this table may never move. They go in
497
- * {@link VerbOptionSlots.longOptionalValue}, which reads the attached spelling and consumes nothing in
498
- * the separated one. A short letter whose value is optional (`sed -i[SUFFIX]`) is left out of BOTH short
499
- * maps for the same reason: an optional value can only ever be attached, and the blind scan is the safe
500
- * reading of a token this row will not explain.
501
- *
502
- * WHAT A ROW MAY NOT GET WRONG, stated as the rule for adding one: declaring a FILE-valued option
503
- * as something else hides a read, and so does declaring an OPTIONAL-value option as a required one —
504
- * the value it eats in the separated spelling is a file operand. Declaring a value-taking option as
505
- * plain is safe (the reading ends unexplained at its value), and declaring the non-file slots is what
506
- * removes the phantom candidates a blind split invents — admitting one more option character moves the
507
- * split right, and a split that lands on a `/` manufactures an absolute path the command never names.
508
- *
509
- * AND A ROW IS ABOUT A NAME, WHICH TWO IMPLEMENTATIONS MAY NOT SPELL ALIKE. `sed -l` takes a required
510
- * line length in one widely deployed sed and NO value in another; `grep --context` is optional in one
511
- * and required in another; and the engine runs whichever the host ships. A disputed arity is resolved
512
- * towards the reading that CONSUMES NOTHING, because only consuming can swallow a file operand: a
513
- * disputed LONG name is filed as optional-value (right under one reading, merely imprecise under the
514
- * other), and a disputed SHORT letter is left out of both short maps, since the short maps have no way
515
- * to say "attached only". Where implementations disagree about a value's KIND rather than its arity,
516
- * the file-naming reading is the one to declare — over-approximating a value costs an ask and
517
- * under-approximating one costs the read. Every row here is checked against the binaries this
518
- * repository's own tools run on; a row added from a manual page alone is a guess.
519
- *
520
- * AND A ROW APPLIES WHILE THE COMMAND IS STILL IN ITS OPTION SECTION. POSIX ends option parsing at the
521
- * first operand, GNU permutes, and a transfer program parses its own options anywhere — so once the
522
- * operands have begun, whether a dash-leading token is an option at all is implementation-dependent and
523
- * BOTH readings are taken: the token is not consumed (it is judged as the operand it may be) and the
524
- * slot's candidates are judged too (it may name a file). Adding a candidate is always safe; consuming
525
- * is what hides one.
526
- *
527
- * @contract shell.read_boundary.option_value_slots — where this table declares a verb's option, the
528
- * read boundary reads that option's value from the DECLARED slot and nowhere else: a slot that can name
529
- * a file yields exactly its value as a path candidate (an `indirect` slot also yields what the value
530
- * names past its `@`, a `header` slot only for a whole-value `@<file>`, and a `url` slot the local path
531
- * a `file:` URL names), and a slot that cannot yields none — the attached and separated spellings of one
532
- * option read the same row and can never disagree, except where the row declares the value OPTIONAL,
533
- * which has no separated spelling at all. Past the command's first operand the separated spelling
534
- * consumes nothing and its value is judged BOTH as that value and as an operand, because which of the
535
- * two it is, is implementation-dependent. Where it declares nothing — no row for the verb, an
536
- * option character the row does not account for, a long-option prefix whose reachable names leave this
537
- * spelling's value unsettled —
538
- * the verb-blind payload scan judges the token exactly as it did before, so an absent or partial row
539
- * costs precision and never a judgement. A row is DATA about a PROGRAM and not about the read-only
540
- * allowlist: it says what that program does with its own argument, never that the program may be read
541
- * from, and it grants no per-verb arm to a program a deployment has not listed.
542
- */
543
- export interface VerbOptionSlots {
544
- /** Short letters whose value is the rest of the token, or the NEXT token when the letter ends it. */
545
- readonly shortValue: Readonly<Record<string, OptionValueKind>>;
546
- /** Short letters taking no value. */
547
- readonly shortPlain: string;
548
- /** Long option FULL names whose value is `=<value>` or the next token. */
549
- readonly longValue: Readonly<Record<string, OptionValueKind>>;
550
- /** Long option FULL names whose value exists ONLY as `=<value>`: `getopt_long`'s `optional_argument`,
551
- * which never reaches for the next token. Reading one of these as {@link longValue} would consume the
552
- * operand that follows the bare spelling, so the operand goes unjudged — see the THREE ARITIES note. */
553
- readonly longOptionalValue: Readonly<Record<string, OptionValueKind>>;
554
- /** Long option FULL names taking no value — declared so that an abbreviation reaching one is seen to be
555
- * ambiguous rather than read as its value-taking neighbour. */
556
- readonly longPlain: readonly string[];
557
- /** SINGLE-dash WORD options — a grammar getopt does not have and a cluster walk cannot read: `-name` is not
558
- * `-n -a -m -e`, and splitting it that way manufactures a path candidate per suffix. Asked before the cluster
559
- * walk, only for a dash plus MORE THAN ONE character; a name in neither map falls to the verb-blind scan. */
560
- readonly dashWordValue?: Readonly<Record<string, OptionValueKind>>;
561
- /** The value-less half of {@link dashWordValue}. */
562
- readonly dashWordPlain?: readonly string[];
563
- /** The FIRST positional operand, where this verb's grammar gives it a meaning that is NOT a file: grep's
564
- * PATTERN, sed's SCRIPT. Read with the same {@link OptionValueKind} vocabulary the option slots use, so
565
- * {@link slotValueCandidates} answers "can this word name a file" once for both spellings — `sed -e '/x/p' f`
566
- * and `sed '/x/p' f` are one invocation and were two readings. `suppliedBy*` name the options that deliver
567
- * the slot instead, leaving the first operand a file after all. No row ⇒ an ordinary first operand. */
568
- readonly firstOperand?: {
569
- readonly kind: OptionValueKind;
570
- /** Short letters, matched inside a cluster and with digits allowed in front (grep's obsolete numeric
571
- * context spec: `-2ebeta` is `-C2 -e beta`). */
572
- readonly suppliedByLetters: string;
573
- /** Long option FULL names; an abbreviation reaching one counts ({@link isLongOptionAbbrevOf}). */
574
- readonly suppliedByLongNames: readonly string[];
575
- };
576
- /** This program parses its options WHEREVER they appear, so the permute ambiguity the both-readings rule
577
- * below answers (POSIX/GNU/BSD disagree whether a dash-token past the first operand is still an option) does
578
- * not exist for it. Declared only where the program's manual states the grammar, and never to rescue a
579
- * spelling into auto-allow: a token the row does not explain still goes to the verb-blind scan. */
580
- readonly optionsArePositionIndependent?: true;
581
- }
582
- /** What one row makes of ONE option token. `unexplained` = the row cannot account for the token, and the
583
- * caller reads it the verb-blind way it always did. */
584
- export type VerbOptionSlotReading = {
585
- readonly form: "unexplained";
586
- } | {
587
- readonly form: "no-value";
588
- } | {
589
- readonly form: "attached";
590
- readonly value: string;
591
- readonly kind: OptionValueKind;
592
- } | {
593
- readonly form: "separated";
594
- readonly kind: OptionValueKind;
595
- };
596
- /**
597
- * Read one option token of `name` through its row. `undefined` ⇒ this verb has no row.
598
- *
599
- * Short form is getopt: scanning the cluster left to right, the FIRST value-taking letter owns the
600
- * remainder of the token, or the next token when it ends there. Long form is `getopt_long`'s
601
- * unambiguous-prefix rule with an EXACT name resolved first; a prefix reaching several names is settled
602
- * only where they agree about what THIS spelling does with its value, which is one question for an
603
- * attached `=value` (can it name a file?) and two for a separated one (does the option take the next
604
- * token at all?) — see the branch below.
605
- *
606
- * An unsettled prefix falls back rather than guessing, because skipping a value that is really a FILE
607
- * hides a read: the verb-blind scan that judges every suffix is the safe answer to "this row does not
608
- * know". That direction is why this reading is NOT the stdin floor's ({@link SEPARATED_VALUE_OPTIONS}),
609
- * which asks a different question — does this value fill one of the SLOTS the floor counts — and answers
610
- * it in the other direction. Measured rather than argued: reading the floor off this table moved twelve
611
- * of its verdicts, eight of them wrongly (`grep -e pat file` blocks on nothing, and its pattern value is
612
- * exactly what makes grep's floor of two `<pattern> <file>`).
613
- */
614
- export declare function readVerbOptionSlot(name: string, tok: string): VerbOptionSlotReading | undefined;
615
- /** Does this verb's row declare that its options are parsed WHEREVER they appear — i.e. that the permute
616
- * ambiguity the both-readings rule answers does not exist for it? See
617
- * {@link VerbOptionSlots.optionsArePositionIndependent}. */
618
- export declare function verbOptionsArePositionIndependent(name: string): boolean;
619
- /** The verb's first-operand slot row, for a reader outside this module that walks operands with the same tables. */
620
- export declare function verbFirstOperandSlot(name: string): VerbOptionSlots["firstOperand"];
621
- /**
622
- * The path candidates one DECLARED value offers, which is also the answer to "did this value name a
623
- * file?" — an empty list IS the no.
624
- *
625
- * Three readings, one per grammar the declared slots have: a value that always names a file offers
626
- * itself; an `indirect` one may name a file either way, so it offers itself AND what it names past an
627
- * `@`; and a `header` names a file ONLY as a whole-value `@<file>` — `curl -H 'X: /etc/x'` sends that
628
- * text and opens nothing, while `curl -H @<file>` adds a header per line of the file (measured against
629
- * the binary, both directions). Reading `header` the `indirect` way would refuse a header whose text
630
- * merely looks like a path; reading it as a non-file kind hides the `@` spelling, which is the direction
631
- * that may not be taken.
632
- */
633
- export declare function slotValueCandidates(value: string, kind: OptionValueKind): string[];
634
- /**
635
- * The per-command model of RECURSIVE/EXPANDING read forms: invocations that read the
636
- * SUBTREE of a path operand, not the operand itself. Consumed by {@link collectSegmentBoundaryFindings}
637
- * only when a {@link BashReadonlyRootBoundary.denyMatch} seat is wired and has entries to apply (see
638
- * {@link CompoundReadonlyVerdict.recursiveReadPaths} for the contract and why the deny seat is the
639
- * trigger), and then only for the rows whose {@link RecursiveReadFormModel.discloses} column reads
640
- * "contents". The reference implementation draws the same line as a verb set: its recursive-reach breaker
641
- * fires for `grep`/`egrep`/`fgrep`/`rg`/`diff` (plus two copy verbs a WRITE face answers for here) and for no
642
- * name that merely lists a tree; `tar` is a contents row here and absent there, because that implementation
643
- * ships no built-in deny table and this one does.
644
- *
645
- * Membership covers every {@link BASH_READONLY_DEFAULT_ALLOW} verb with a recursive form, PLUS the
646
- * common tree-reading verbs a deployment plausibly widens its allowlist with (`find`, `rg`, …): the
647
- * allow set is a caller parameter, and a table pinned to the default list would silently go blind the
648
- * day a deployment adds `rg` — whose recursion needs no flag at all. A widened verb this table does
649
- * not know stays name-only classified (recorded residual: the deployment owns that widening, same
650
- * posture as the allowlist's own header note).
651
- *
652
- * DIRECTION. Detection over-approximates deliberately: a flag mis-read as recursive costs one ask on
653
- * a command that is usually a real-getopt error anyway (`grep -dr …` — ambiguous enum value), while an
654
- * under-read auto-allows a traversal the deny judge never saw — the leaking direction. The cluster
655
- * walk therefore honours getopt value-owner semantics ONLY where skipping prevents a false fire on a
656
- * value AND the ownership holds on every supported implementation (`grep -eRfoo` is a pattern under
657
- * GNU and BSD alike), never to rescue a spelling into auto-allow — a letter whose ownership DIVERGES
658
- * across implementations is not modeled at all (see the `ls` row), because a scan stopped on the
659
- * wrong platform's table is an auto-allowed real traversal.
660
- */
661
- export interface RecursiveReadFormModel {
662
- /** What the traversal puts in front of the CALLER: the file CONTENTS it walked over, or only their
663
- * NAMES and sizes. The demotion arm reads "contents" rows only — the deny judge cannot pre-check a
664
- * subtree, and handing back the bytes it guards is the hazard; handing back names is a different
665
- * disclosure with a different answer. WHERE THE BYTES GO is part of the question and not always a
666
- * property of the verb (`tar -cf -` writes the archive to stdout), and reading that per invocation is a
667
- * per-program option model this zero-IO pass does not carry — so an ambiguous row resolves demote-ward,
668
- * as every ambiguity here does. A "names" row's other fields have no behavioural consumer today; the
669
- * row stays because it is a DECISION, and a verb deleted from this table reads as one nobody made. */
670
- readonly discloses: "contents" | "names";
671
- /** The verb's ordinary operation IS a tree walk — every invocation with a path operand recurses,
672
- * no flag required (`du`, `find`, `rg`, `tree`, `ag`, `ack`). */
673
- readonly always?: true;
674
- /** Short option letters selecting recursion, judged over the getopt option-letter run. */
675
- readonly shortLetters?: string;
676
- /** Value-taking short letters: the FIRST one hit owns the token remainder (or, when it ends the
677
- * token, the next token) — letters inside that value are not options and must not fire. List a
678
- * letter ONLY when it takes a value on EVERY supported implementation (GNU and BSD): stopping the
679
- * scan on one platform's table is an under-read on the other, the leaking direction. */
680
- readonly valueOwners?: string;
681
- /** Long option names selecting recursion, abbreviation-aware ({@link isLongOptionAbbrevOf} — an
682
- * abbreviation real getopt_long would call ambiguous over-fires into an ask, the safe side). */
683
- readonly longNames?: readonly string[];
684
- /** Enum-valued options where one VALUE selects recursion (grep's `-d recurse` /
685
- * `--directories=recurse`). The value is matched as a CASE-FOLDED unambiguous-prefix
686
- * over-approximation: GNU argmatch accepts prefixes, and BSD grep accepts the value
687
- * case-insensitively (`-d RECURSE` recurses — verified on the real binary), so
688
- * both laxities fold in. A spelling only one implementation accepts over-fires on the other
689
- * into an ask on an erroring command — the required side. */
690
- readonly enumOptions?: readonly {
691
- shortLetter?: string;
692
- longName?: string;
693
- recursiveValue: string;
694
- }[];
695
- /** tar's traditional dash-less FIRST-operand key word (`tar cf out.tar dir`, the "old option
696
- * style" in tar's own manual): mode letters found there select recursion exactly as their dashed
697
- * spellings do. */
698
- readonly bundledModeLetters?: string;
699
- /** `true` when a bare `-` operand denotes STDIN for this command (content readers: grep's file
700
- * slot, diff, tar's `-f -`). Absent ⇒ `-` is an ordinary filename (ls/du/find/tree have no stdin
701
- * sense) and stays a positional operand for the recursion demotion. */
702
- readonly dashIsStdin?: boolean;
703
- }
704
- export declare const RECURSIVE_READ_FORMS: Readonly<Record<string, RecursiveReadFormModel>>;
705
431
  /**
706
432
  * Read ONE sed script and answer whether it can name a file or run a command.
707
433
  *
@@ -723,133 +449,11 @@ export interface SedScriptNames {
723
449
  * in the command (one reading), or no reading could parse it to its end. Absent when every name is listed. */
724
450
  readonly unread?: string;
725
451
  }
726
- /**
727
- * Does this verb's SCRIPT SLOT put a file name or a command line somewhere the walk's operand reading
728
- * cannot see? Table-driven by verb so a second such verb is a row rather than a second branch.
729
- *
730
- * EVERY implementation reading is asked, and the answers combined: an affirmative `names` under any one
731
- * refuses; a script no reading could SEE refuses, because file-supplied program text may carry anything;
732
- * and a script no reading could finish refuses. A reading that lands on a clean script is what clears the
733
- * invocation — which is what keeps the everyday spellings, whose other reading lands on a plain file name,
734
- * at their old verdict.
735
- */
736
- /** Every file and command line a sed invocation's script slot names, under BOTH option dialects (the union,
737
- * deduplicated): what a candidate extraction hands the read judge (`reads`), the write face (`writes`) and a
738
- * nested plan (`commands`). A reading that saw no text names nothing here — that fact rides the verdict face. */
739
- export declare function sedScriptSlotFiles(args: readonly string[]): SedScriptNames;
740
- /**
741
- * How an INTERPRETER receives the program it runs, declared per interpreter rather than guessed.
742
- *
743
- * The member that completes the ARGUMENT-AS-PROGRAM family. An interpreter's program can arrive three
744
- * ways: as an OPTION's value (`perl -e '...'`, `python3 -c '...'`, `node --eval '...'`), as the first
745
- * OPERAND (the awk family, whose program is mandatory and is not a file unless `-f` named one), or on
746
- * STANDARD INPUT when the command line names none at all. Only the third and the first are this arm's
747
- * business together with the second; a program named as a FILE operand (`perl x.pl`, `python3 app.py`)
748
- * is a path the ordinary operand walk already judges, and stays exactly where it was.
749
- *
750
- * WHAT IS JUDGED IS THE PRESENCE OF PROGRAM TEXT, NEVER ITS CONTENT. A quoted program is ONE word to
751
- * this file's lexer and its contents are never parsed — so the answer cannot be "does this program read
752
- * a file", only "is there a program this walk did not read". That is why the everyday harmless
753
- * spellings (`node -e 'console.log(1)'`) refuse along with the rest: telling them apart needs a parser
754
- * per language, which is exactly the thing a lexical floor must not grow.
755
- *
756
- * A row is DATA, so a further interpreter is a row rather than a branch, and a versioned spelling
757
- * (`python3.11`, `perl5.36`, `tclsh8.6`) is the same row via {@link interpreterKey}.
758
- */
759
- export interface InlineProgramModel {
760
- /** Options whose value is program TEXT, separated (`--eval prog`) or fused (`--eval=prog`). Matched on
761
- * the whole token, so a single-dash long option (`-cmd`) is one of these rather than a letter bundle. */
762
- readonly longText: ReadonlySet<string>;
763
- /** Options whose value NAMES the program (a script file, or a module the interpreter resolves). */
764
- readonly longFile: ReadonlySet<string>;
765
- /** Options that NAME the program while taking NO value of their own — a mode that selects what runs
766
- * (`node --test` runs the test files it discovers, and reads no program from its input). */
767
- readonly longNamesProgram: ReadonlySet<string>;
768
- /** Options whose value is a file the interpreter reads BESIDE the program it is given — an
769
- * initialization script, a library to preload. Their value is consumed so it is not counted as an
770
- * operand, and they do NOT name the program: what follows still has to. */
771
- readonly longSupplemental: ReadonlySet<string>;
772
- /** Options whose value is the NEXT token and means none of the above. */
773
- readonly longValue: ReadonlySet<string>;
774
- /** Long options this row declares to take NO value. Declaring them is what keeps an invocation
775
- * EXPLAINED past them, so a later script operand still ends the interpreter's own option scanning. */
776
- readonly longPlain: ReadonlySet<string>;
777
- /** Whether an option that NAMES the program also ends this interpreter's option processing, because
778
- * what follows is the named program's own argument list (`python3 -m <module> -c` passes `-c` to the
779
- * module). False where a named source is PRELIMINARY and further sources still follow (`dc -f <file>
780
- * -e '<program>'` runs both). */
781
- readonly fileOptionEndsOptions: boolean;
782
- /** Short-option letters that introduce program text — alone (`-e prog`), fused (`-eprog`) or inside a
783
- * bundle (`-pe`, `-lne`, `-uc`, `-0777e`). */
784
- readonly textLetters: string;
785
- /** Short-option letters whose value names the program (`-f prog.awk`, `-fprog.awk`, `-m <module>`). */
786
- readonly fileLetters: string;
787
- /** Short-option letters whose value is the rest of the token, or the NEXT token when the token ends on
788
- * them (`perl -I lib`). The bundle scan stops there — what follows in the token is that value. */
789
- readonly separatedValueLetters: string;
790
- /** Short-option letters whose value can only be ATTACHED (`perl -i.bak`, `-C<flags>`): the bundle scan
791
- * stops there too, but a bare spelling takes NOTHING from the next token — reading `perl -C -e '…'`
792
- * as "-C whose value is -e" swallowed the option that carries the program. */
793
- readonly attachedValueLetters: string;
794
- /** Short-option letters that take no value at all. Declaring them is what makes an invocation EXPLAINED
795
- * (see `explained` in the recognizer); they change nothing else. */
796
- readonly plainLetters: string;
797
- /** Short-option letters that make this interpreter PRINT AND EXIT. Per interpreter, because the same
798
- * letter is a banner in one and something else entirely in another (`-v` is the version in ruby and
799
- * VERBOSE EXECUTION in python; `-h` is the version banner in lua and the HOST in psql). */
800
- readonly bannerLetters: string;
801
- /** Short-option letters that make the interpreter read commands INTERACTIVELY after whatever else it
802
- * was given — a banner or a named script does not end the session, so the program still arrives on
803
- * standard input (`lua -v -i`, `lua -i script.lua`). */
804
- readonly interactiveLetters: string;
805
- /** Which OPERAND names the program, when any does, and whether it is program TEXT (the awk family, a
806
- * jq filter, the SQL after a database) or a program FILE (every script interpreter). Absent when no
807
- * operand ever names the program — psql's are connection arguments, and an interactive compiler's are
808
- * modules it loads before reading commands from its input. */
809
- readonly programOperand?: {
810
- readonly at: number;
811
- readonly isText: boolean;
812
- };
813
- /** Whether an invocation that names no program anywhere reads one from its standard input. */
814
- readonly stdinWhenUnnamed: boolean;
815
- }
816
- /** The interpreters this file has a row for, keyed by the basename bash resolves, with the trailing
817
- * version dropped ({@link interpreterKey} — which is also why the key for `sqlite3` is `sqlite`). */
818
- export declare const INTERPRETER_INLINE_PROGRAMS: ReadonlyMap<string, InlineProgramModel>;
819
- /** The row a versioned spelling belongs to: `python3`, `python3.11` and `python` are one program with
820
- * one program-delivery grammar, so the trailing version is dropped before the lookup. */
821
- export declare function interpreterKey(name: string): string;
822
- /**
823
- * How this invocation receives its program, or `undefined` when it NAMES one (a script file, a module,
824
- * a program file option) or names none at all on an interpreter that then reads none.
825
- *
826
- * Read over the folded arguments with the program word excluded. Three sources in one pass — an option
827
- * whose value is program text, the operand a row declares as the program, and standard input — and one
828
- * rule for every doubt: an option this file has no row for never ENDS the search for program text. The
829
- * word that names the program stops the scan (past a script, `-p` belongs to the SCRIPT), but only while
830
- * every option so far was one the row EXPLAINS: after an option of unknown arity the following word may
831
- * be that option's value rather than the script, so the search has to run to the end.
832
- */
833
- export declare function inlineProgramClause(model: InlineProgramModel, args: readonly string[]): string | undefined;
834
- /** Does this already-vetted segment (FOLDED tokens — quoting does not change what getopt sees) invoke
835
- * a {@link RECURSIVE_READ_FORMS} verb in a recursive form that DISCLOSES CONTENTS? `args` excludes the
836
- * command name. Names-only traversals (`find`, `ls -R`, `du`, `tree`, an archive write) are in the table
837
- * and answer `false` here — see {@link RecursiveReadFormModel.discloses}. */
838
- export declare function segmentSelectsRecursiveRead(name: string, args: readonly string[]): boolean;
839
- /** WHICH programs are DECLARED not to open the value of a `NAME=value` ARGUMENT — an allow-list, because
840
- * the other polarity was measured false. `make PREFIX=/usr/local`, `cmake -D…`, `docker run -e HOME=/root`
841
- * name a build prefix and an environment value their program never opens, and judging those was the one
842
- * shape of the verb-blind rule that MANDATED the everyday build line. The exemption is theirs alone.
843
- *
844
- * The polarity is the whole point. Listing the programs that DO open such a value means anything the walk
845
- * fails to recognise is exempt — and what it fails to recognise is WHICH PROGRAM RUNS: an undeclared
846
- * wrapper is read as the program (`caffeinate dd if=<path>`), and a launcher can carry the program inside
847
- * an option payload with no word equal to it (`env -Sdd if=<path>`). Both were verified to execute the
848
- * read. Inverted, none of those is on this list, so none is exempt — nor is a fifth spelling of the same
849
- * trick. A further program is a member, not a branch, and adding one is a claim about it alone.
850
- *
851
- * NOT its business: the LEADING environment assignments and an OPTION word's payload, each with its own arm. */
852
- export declare const ASSIGNMENT_VALUE_NOT_PATHS: ReadonlySet<string>;
452
+ /** Every file and command line the program text of a read-language row names, under EVERY implementation's grammar
453
+ * (the union, deduplicated): what a candidate extraction hands the read judge (`reads`), the write face (`writes`) and
454
+ * a nested plan (`commands`). `undefined` for a row whose program text the station does not read. A reading that saw
455
+ * no text names nothing here — that fact rides the verdict face. */
456
+ export declare function programTextSlotFiles(row: ProgramRow, args: readonly string[]): SedScriptNames | undefined;
853
457
  /** The program the shell will RUN here and where its OWN argv begins — the two seats
854
458
  * {@link HeadedSegment.argvProgram} / {@link HeadedSegment.argvFrom} carry, from one reader so they cannot
855
459
  * disagree. The LEADING assignments (both spellings) are the program-position reader's own step, so this
@@ -869,35 +473,14 @@ export declare function attachedOptionPayloads(tok: string): string[];
869
473
  * (`x$HOME`, `$HOME.bak`, `$HOMES`) is a substitution the classify faces refuse and the read station cannot
870
474
  * place, and an unquoted spelling of a home bash would split or glob ({@link HOME_EXPANDS_TO_ONE_WORD}) is not
871
475
  * one word. The caller reads it only against a declared home (with none declared the child's `$HOME` may differ
872
- * from what `~` falls back to) and only when the command cannot rebind `HOME` ({@link homeMayBeRebound}).
476
+ * from what `~` falls back to) and only when the command cannot rebind `HOME` ({@link textBindsHome}).
873
477
  */
874
478
  export declare function homeExpansionOf(w: LexedWord, home: string): {
875
479
  readonly spelled: string;
876
480
  } | undefined;
877
- /** May this command text REBIND `HOME` before a later word expands it? Read LEXICALLY, not by grammar: the text
878
- * spells the name `HOME` somewhere other than as a plain read ({@link HOME_PLAIN_READ}) — after `\<newline>`
879
- * continuations are joined and quotes (with the `$` of a `$'…'` / `$"…"` opener) and backslashes are removed, so
880
- * `"HO"ME`, `HO\ME`, `HO$'ME'` and an `eval` string spell it the same as a bare word. That covers an assignment at ANY nesting depth (a `{ … }` group, a
881
- * function body, a `case` arm, a loop), a declaration builtin's operand, a `for` / `select` variable, a `read` /
882
- * `printf -v` / `mapfile` / `getopts` / `unset` target, a nameref value, an arithmetic or `${HOME:=…}` assignment,
883
- * without naming any of them. A reader that substitutes the declared home for `$HOME` / `${HOME}` / a leading `~`
884
- * asks this first; a text it answers yes for leaves those words unplaced (the fail-closed side).
885
- * WHY not a grammar reading: every "where does the name stand" reading of this question (the leading assignment
886
- * words, a declaration builtin's operands) has had a nesting level or a builtin it did not see.
887
- * ACCEPTED COST: a text that merely spells the name while reading through the home — `echo HOME; cat ~/x`, a longer
888
- * name ending in it (`MY_HOME=…`), a comment — asks instead of running.
889
- * A name the shell COMPUTES spells no `HOME` to find, so four more readings count as a rebinding: an unquoted GLOB
890
- * word whose pattern can match the name `HOME` or an array element `HOME[…]` of it ({@link globMayMatchHome} —
891
- * `read H?ME`, `unset [H]OME`, `read H?ME[0]`, `unset *` glob against the working directory when an entry named
892
- * `HOME` sits there); an unquoted EXTGLOB opener ({@link hasUnquotedExtglobOpener} — `read !(x)` matches nearly
893
- * every name); an unquoted BRACE list ({@link wordHasBraceList} — `read H{O,X}ME` expands to a list whose first
894
- * word is the name); an option word that carries a glob ({@link optionWordCarriesGlob} — `read -aH?ME`, where a
895
- * matched entry named `-aHOME` hands the builtin `-a HOME`); and a `printf -v` name that is not a literal
896
- * identifier ({@link printfNamesComputed} — `printf` opens no path, so its words are no candidate of their own).
897
- * Elsewhere a computed word is its own unresolvable candidate, and an escape the lexer does not decode is
898
- * unresolved on its own (asked). */
899
- export declare function homeMayBeRebound(text: string): boolean;
900
- /** {@link hasUnquotedExtglobOpener} over an already-lexed text. A here-document delimiter counts too: the lexer ends
481
+ /** An `?(` `*(` `+(` `@(` `!(` extended-glob opener spelled UNQUOTED, over an already-lexed text: a word whose last piece
482
+ * stands unquoted and whose written text ends in one of `? * + @ !`, with the source `(` right after it (across `\<newline>`
483
+ * continuations only). A here-document delimiter counts too: the lexer ends
901
484
  * it at the `(` (`<<@(x)` reads as the delimiter `@` and a group), where bash with `extglob` on reads the one word
902
485
  * `@(x)` — a different delimiter, so the body the lexer read as data is not the body bash reads. The token keeps no
903
486
  * per-character quoting, so a delimiter quoted anywhere (`<<'E'@(X)`) counts as well: a quoted opener is bash's
@@ -915,16 +498,6 @@ export declare function classifyCompoundReadonlyDetailed(command: string, allow:
915
498
  boundary?: {
916
499
  readonly homeDir?: string;
917
500
  }): CompoundReadonlyVerdict;
918
- /** Working-directory moves {@link evaluateReadBoundary} does NOT model. `cd` is deliberately absent —
919
- * it IS modelled (the walk threads the base through it), which is the whole difference: a move the
920
- * walk follows keeps the verdict decidable, and one it cannot follow does not. */
921
- export declare const UNMODELLED_BASE_MOVERS: ReadonlySet<string>;
922
- /** Test seam for the lockstep pin that the launcher table (the ONE launcher truth, in the program-position
923
- * reader's module) stays a SUBSET of the rule lane's curated `BARE_INTERPRETER_NAMES`. Exported for that one
924
- * assertion — production code reads the table directly. The containment face ({@link classifyOutOfRootReadGate})
925
- * does NOT look through a launcher: there every segment whose program is not a listed reader is judged whole,
926
- * launcher or not, so looking through one would only narrow what it reads. */
927
- export declare const COMMAND_LAUNCHERS_FOR_TEST: ReadonlySet<string>;
928
501
  /**
929
502
  * Compound read-only classification, reason-only face. Returns the demotion reason, or
930
503
  * undefined when the command classifies read-only. ⚠️ `undefined` is NOT "safe to auto-execute":