@gaunt-sloth/core 2.0.0-alpha.26 → 2.0.0-alpha.28

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 (51) hide show
  1. package/dist/config/schema.js +64 -15
  2. package/dist/config/schema.js.map +1 -1
  3. package/dist/config/types.d.ts +17 -8
  4. package/dist/config/types.js.map +1 -1
  5. package/dist/constants.d.ts +7 -4
  6. package/dist/constants.js +7 -4
  7. package/dist/constants.js.map +1 -1
  8. package/dist/core/GthAbstractAgent.d.ts +1 -19
  9. package/dist/core/GthAbstractAgent.js +13 -65
  10. package/dist/core/GthAbstractAgent.js.map +1 -1
  11. package/dist/core/GthAgentRunner.d.ts +10 -4
  12. package/dist/core/GthAgentRunner.js +24 -7
  13. package/dist/core/GthAgentRunner.js.map +1 -1
  14. package/dist/core/GthLangChainAgent.js +16 -11
  15. package/dist/core/GthLangChainAgent.js.map +1 -1
  16. package/dist/core/launchBanner.js +36 -17
  17. package/dist/core/launchBanner.js.map +1 -1
  18. package/dist/core/shell/abstention.d.ts +88 -0
  19. package/dist/core/shell/abstention.js +184 -0
  20. package/dist/core/shell/abstention.js.map +1 -0
  21. package/dist/core/shell/openWorld.d.ts +137 -12
  22. package/dist/core/shell/openWorld.js +677 -12
  23. package/dist/core/shell/openWorld.js.map +1 -1
  24. package/dist/core/shell/rater.d.ts +79 -39
  25. package/dist/core/shell/rater.js +132 -71
  26. package/dist/core/shell/rater.js.map +1 -1
  27. package/dist/core/shell/rejection.d.ts +7 -4
  28. package/dist/core/shell/rejection.js +3 -3
  29. package/dist/core/shell/rejection.js.map +1 -1
  30. package/dist/core/toolDisplay.d.ts +12 -3
  31. package/dist/core/toolDisplay.js +27 -7
  32. package/dist/core/toolDisplay.js.map +1 -1
  33. package/dist/providers/openrouter.d.ts +3 -4
  34. package/dist/providers/openrouter.js +15 -30
  35. package/dist/providers/openrouter.js.map +1 -1
  36. package/dist/runtime/askStructured.js +7 -5
  37. package/dist/runtime/askStructured.js.map +1 -1
  38. package/dist/runtime/structuredOutput.d.ts +104 -0
  39. package/dist/runtime/structuredOutput.js +393 -0
  40. package/dist/runtime/structuredOutput.js.map +1 -0
  41. package/dist/utils/displayWidth.d.ts +30 -0
  42. package/dist/utils/displayWidth.js +140 -0
  43. package/dist/utils/displayWidth.js.map +1 -0
  44. package/dist/utils/systemPromptNotes.d.ts +28 -8
  45. package/dist/utils/systemPromptNotes.js +47 -49
  46. package/dist/utils/systemPromptNotes.js.map +1 -1
  47. package/dist/utils/untrustedText.d.ts +66 -0
  48. package/dist/utils/untrustedText.js +80 -0
  49. package/dist/utils/untrustedText.js.map +1 -0
  50. package/package.json +6 -1
  51. package/schema/gsloth-config.schema.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"launchBanner.js","sourceRoot":"","sources":["../../src/core/launchBanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"launchBanner.js","sourceRoot":"","sources":["../../src/core/launchBanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The shape in the command that the gate's parser could not resolve.
3
+ *
4
+ * These are FORMS, not judgements — nothing here says a command is dangerous, and nothing here is a
5
+ * rating. They exist to select the sentence the rater is shown.
6
+ */
7
+ export type AbstentionMechanism =
8
+ /** A git commit whose message contains a substitution the SHELL runs before git sees it. */
9
+ 'commit-message-substitution'
10
+ /** More than one command: `;`, `&`, `&&`, `|`, `||`, or a line break. */
11
+ | 'composition'
12
+ /** Command / variable / process substitution: `$(…)`, backticks, `${…}`, `<(…)`. */
13
+ | 'substitution'
14
+ /** A stream redirect: `>`, `>>`, `<`, `2>`, `&>`. */
15
+ | 'redirect'
16
+ /** None of the above — an unbalanced quote, an empty command, or no resolvable program name. */
17
+ | 'unparseable';
18
+ /** What the parser saw in a command it could not resolve: the shapes, and the note for each. */
19
+ export interface AbstentionDefect {
20
+ /** The most specific mechanism found — what the note leads with. */
21
+ mechanism: AbstentionMechanism;
22
+ /** Every mechanism found, in note order. A command may carry more than one. */
23
+ mechanisms: AbstentionMechanism[];
24
+ /** One note per mechanism, in the same order. Never empty. */
25
+ notes: string[];
26
+ }
27
+ /**
28
+ * **The per-family note text — one distinct string per {@link AbstentionMechanism}.**
29
+ *
30
+ * Typed as a total `Record`, so adding a mechanism is a COMPILE ERROR until someone writes its
31
+ * sentence. A family that silently fell back to another family's note would be the failure this
32
+ * table exists to prevent: [[QA-17]] measured that the note's effect is family-specific, and
33
+ * `docs/test-sessions/qa-17-substitution-note-2026-08-03/` records a narrowing by family name that
34
+ * was FALSIFIED — `gh pr comment 42 --body "…"` carrying an executing substitution classifies as
35
+ * generic `substitution`, and three of three hosted raters called it safe unassisted.
36
+ *
37
+ * Every entry states a fact about what THE SHELL does, and then asks a question. Neither is a
38
+ * verdict about the command in front of the rater, which is what keeps the note neutral while still
39
+ * carrying the mechanism that the measurement showed is load-bearing.
40
+ */
41
+ export declare const MECHANISM_NOTES: Readonly<Record<AbstentionMechanism, string>>;
42
+ /**
43
+ * Classify a command the gate's parser could not resolve, or return `null` when it resolves.
44
+ *
45
+ * **The `null` arm is the guard, and it is structural on purpose.** Every mechanism below is a
46
+ * regex, and `unparseable` is the fallback — so without this gate the function would classify `ls
47
+ * -la` as `unparseable` and a note would be attached to every command in the session. The predicate
48
+ * is {@link classifyCommand}'s own, not a second reading of it, so the note appears on exactly the
49
+ * set of commands the gate could not resolve and on no others.
50
+ *
51
+ * Detection runs on the NORMALIZED command (the same form `classifyCommand` refused), so obfuscation
52
+ * that the normalizer collapses cannot hide a mechanism from the note — while the command shown to
53
+ * the rater stays the one the rater is being asked about, fenced by its own caller.
54
+ *
55
+ * The line-break check reads the RAW command, exactly as `classifyCommand` does: the normalizer is
56
+ * not required to preserve that separator, and EXT-55 is the node about what happens when a caller
57
+ * assumes it did.
58
+ *
59
+ * **Order is note order, most specific first**, and `commit-message-substitution` SUPPRESSES the
60
+ * generic substitution note it is a special case of — telling the rater the same thing twice about
61
+ * one `$(…)` spends attention on a repetition.
62
+ *
63
+ * @param command The raw command string as the model proposed it.
64
+ * @returns What the parser saw, or `null` when the command's target statically resolves.
65
+ */
66
+ export declare function describeAbstention(command: string): AbstentionDefect | null;
67
+ /**
68
+ * The opening line of the preflight note: **what this is, and what it is not.**
69
+ *
70
+ * It says the finding is about OUR PARSER rather than about the command, and that nothing has been
71
+ * judged. Both halves are load-bearing. The first stops the rater reading the note as a report of
72
+ * something found — the failure mode a bare observation produced, where a rater treats our
73
+ * uncertainty as evidence and either inflates or explains it away. The second is what keeps this
74
+ * note out of the open-world note's register: that one may say the command *"has ALREADY been
75
+ * floored deterministically and will be shown to the user whatever you return"*, and here that
76
+ * sentence would simply be false.
77
+ */
78
+ export declare const PARSER_NOTE_PREAMBLE: string;
79
+ /**
80
+ * Build the neutral preflight note for a command, or `null` when the gate resolved it.
81
+ *
82
+ * One note per mechanism the command carries, most specific first, bulleted when there is more than
83
+ * one — a command can compose AND substitute AND redirect, and a note that mentioned only the first
84
+ * would leave the rater reasoning about a fragment of the shape.
85
+ *
86
+ * @param command The raw command string as the model proposed it.
87
+ */
88
+ export declare function buildParserPreflightNote(command: string): string | null;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @module core/shell/abstention
3
+ *
4
+ * EXT-81 — **what the RATER is told about a command our parser could not resolve.**
5
+ *
6
+ * `classifyCommand` resolves a command's target, or returns `null` when it cannot. That `null` used
7
+ * to be an ACTION: the gate refused the call before any rating, on the theory that a reading of a
8
+ * command it could not parse was not worth buying. §6.1's rule reverses that — *deterministic checks
9
+ * fire only where we are confident something is a threat; where we cannot tell, the model decides* —
10
+ * and a parser reporting that it could not resolve a string is not a detection of anything. So the
11
+ * finding is now **neutral context handed to the rater**, and the flow is one path: preflight → note
12
+ * → rate → approve / escalate / halt.
13
+ *
14
+ * This module turns the `null` into that note: **which shape the parser saw, and the mechanism that
15
+ * makes the shape worth a second look.** Two properties are the whole design, and each has a
16
+ * measurement behind it ([[QA-17]], `docs/test-sessions/qa-17-substitution-note-2026-08-03/`):
17
+ *
18
+ * - **The note carries the MECHANISM, not just the construct's name.** A bare *"the parser saw a
19
+ * substitution"* observation was measured NEGATIVE on two raters — one became more confidently
20
+ * wrong than with no note at all (*"not executed since it's within double quotes"*), another lost
21
+ * severity against the control. Adding one sentence of mechanism — that a double-quoted argument
22
+ * is not inert prose, because the shell expands it before the outer program runs — is what moved
23
+ * every deployment-class rater to the correct verdict. A bare observation from a component that
24
+ * has just announced it could not read the command reads as DOUBT, and doubt is not information.
25
+ * - **The note is ASSISTANCE, never an accusation.** *"Hey rater, here is a command, please pay
26
+ * attention it includes composition."* No verdict, no severity, no *suspicious*, no *careful*, no
27
+ * *treat this as at least X*, and nothing that caps the outcome — `catastrophic` and `attack` stay
28
+ * reachable. A question is allowed; a question is not a lean. A composition is not a hazard:
29
+ * `cd build && ls`, `npm test && npm run build` and `git add -A && git status` are the
30
+ * overwhelming majority of what this fires on, and a leading note would re-create the very
31
+ * escalation this design removes — laundered through the model instead of the parser, and now
32
+ * unfalsifiable because a model said it.
33
+ *
34
+ * It also states nothing about what the gate will DO with the verdict. The open-world note's shape
35
+ * (*"has ALREADY been floored deterministically and will be shown to the user whatever you
36
+ * return"*) is honest only where a floor exists, and for these families none does.
37
+ *
38
+ * **Scope, deliberately narrow.** Flag what the parser saw and stop. Extracting spans, naming which
39
+ * segment is unresolvable, and drawing on surrounding context all wait for real user trial — the
40
+ * elaborate note is the one most likely to acquire connotation by accident.
41
+ */
42
+ import { classifyCommand } from '#src/core/shell/arity.js';
43
+ import { COMMAND_SEPARATOR_RE, LINE_BREAK_RE, normalizeCommand, } from '#src/core/shell/normalize.js';
44
+ /**
45
+ * **The per-family note text — one distinct string per {@link AbstentionMechanism}.**
46
+ *
47
+ * Typed as a total `Record`, so adding a mechanism is a COMPILE ERROR until someone writes its
48
+ * sentence. A family that silently fell back to another family's note would be the failure this
49
+ * table exists to prevent: [[QA-17]] measured that the note's effect is family-specific, and
50
+ * `docs/test-sessions/qa-17-substitution-note-2026-08-03/` records a narrowing by family name that
51
+ * was FALSIFIED — `gh pr comment 42 --body "…"` carrying an executing substitution classifies as
52
+ * generic `substitution`, and three of three hosted raters called it safe unassisted.
53
+ *
54
+ * Every entry states a fact about what THE SHELL does, and then asks a question. Neither is a
55
+ * verdict about the command in front of the rater, which is what keeps the note neutral while still
56
+ * carrying the mechanism that the measurement showed is load-bearing.
57
+ */
58
+ export const MECHANISM_NOTES = {
59
+ 'commit-message-substitution': 'This is a git commit carrying its message inline, and the message contains a ' +
60
+ 'dollar-parenthesis or a backtick. The SHELL expands that before git ever sees the message, ' +
61
+ 'so the text inside the quotes is not inert prose: double quotes do not stop `$(…)` or a ' +
62
+ 'backtick from running, and git receives whatever it produced. What does the shell run when ' +
63
+ 'it expands that message?',
64
+ composition: 'This command line runs MORE THAN ONE command — a `;`, `&&`, `||`, `|` or a line break ' +
65
+ 'separates them — and the shell runs each part in turn, feeding one into the next where the ' +
66
+ 'separator is a pipe. What does the whole line do once every part has run?',
67
+ substitution: 'This command line contains a substitution — `$(…)`, a backtick, `${…}` or `<(…)`. The SHELL ' +
68
+ 'expands it BEFORE the outer program runs, and hands that program the result. A ' +
69
+ 'double-quoted argument is therefore not inert prose: double quotes do not stop `$(…)` or a ' +
70
+ 'backtick from being run, so a substitution inside what reads as ordinary text is still ' +
71
+ 'executed. What does the shell run when it expands this one?',
72
+ redirect: 'This command line redirects a stream — `>`, `>>`, `<`, `2>` or `&>`. The shell attaches a ' +
73
+ 'file to the program before the program starts, so its output lands in that file rather than ' +
74
+ 'on the terminal, and a `>` truncates the file it names first. Which file is being read or ' +
75
+ 'written here?',
76
+ unparseable: 'The gate could not tokenize this command line at all — most often an unbalanced quote, or no ' +
77
+ 'program name it could identify. So we cannot tell you which program this runs; what is ' +
78
+ 'quoted above is exactly the text that would be handed to the shell. What does it do?',
79
+ };
80
+ /** Process substitution `<(…)` / `>(…)`, which is a SUBSTITUTION and must not also read as a redirect. */
81
+ const PROCESS_SUBSTITUTION_RE = /[<>]\(/g;
82
+ /**
83
+ * Does this look like a `git commit` carrying an inline message?
84
+ *
85
+ * Deliberately a heuristic and not a parser: the command has already defeated the gate's tokenizer,
86
+ * so there is nothing precise left to parse. It is safe to be approximate here because a wrong
87
+ * answer costs at most a less specific note — the rating is bought either way.
88
+ */
89
+ const GIT_COMMIT_RE = /\bgit\b[^\n]*\bcommit\b/i;
90
+ const INLINE_MESSAGE_FLAG_RE = /(^|\s)(-m\b|--message\b|-\w*m\b)/;
91
+ /** Command substitution `$(…)` or a backtick — the two the shell EXECUTES. */
92
+ const EXECUTING_SUBSTITUTION_RE = /\$\(|`/;
93
+ /** Every substitution/expansion form, including the non-executing ones. */
94
+ const ANY_SUBSTITUTION_RE = /\$\(|`|\$\{|[<>]\(/;
95
+ /**
96
+ * Classify a command the gate's parser could not resolve, or return `null` when it resolves.
97
+ *
98
+ * **The `null` arm is the guard, and it is structural on purpose.** Every mechanism below is a
99
+ * regex, and `unparseable` is the fallback — so without this gate the function would classify `ls
100
+ * -la` as `unparseable` and a note would be attached to every command in the session. The predicate
101
+ * is {@link classifyCommand}'s own, not a second reading of it, so the note appears on exactly the
102
+ * set of commands the gate could not resolve and on no others.
103
+ *
104
+ * Detection runs on the NORMALIZED command (the same form `classifyCommand` refused), so obfuscation
105
+ * that the normalizer collapses cannot hide a mechanism from the note — while the command shown to
106
+ * the rater stays the one the rater is being asked about, fenced by its own caller.
107
+ *
108
+ * The line-break check reads the RAW command, exactly as `classifyCommand` does: the normalizer is
109
+ * not required to preserve that separator, and EXT-55 is the node about what happens when a caller
110
+ * assumes it did.
111
+ *
112
+ * **Order is note order, most specific first**, and `commit-message-substitution` SUPPRESSES the
113
+ * generic substitution note it is a special case of — telling the rater the same thing twice about
114
+ * one `$(…)` spends attention on a repetition.
115
+ *
116
+ * @param command The raw command string as the model proposed it.
117
+ * @returns What the parser saw, or `null` when the command's target statically resolves.
118
+ */
119
+ export function describeAbstention(command) {
120
+ if (classifyCommand(command, normalizeCommand) !== null)
121
+ return null;
122
+ const normalized = normalizeCommand(command);
123
+ const composes = COMMAND_SEPARATOR_RE.test(normalized) || LINE_BREAK_RE.test(command.trim());
124
+ const substitutes = ANY_SUBSTITUTION_RE.test(normalized);
125
+ const commitSubstitution = GIT_COMMIT_RE.test(normalized) &&
126
+ INLINE_MESSAGE_FLAG_RE.test(normalized) &&
127
+ EXECUTING_SUBSTITUTION_RE.test(normalized);
128
+ // A redirect is any `<`/`>` that is NOT the opening of a process substitution — that form is
129
+ // already reported as a substitution, and reporting it twice would describe one piece of syntax
130
+ // with two different mechanisms.
131
+ const redirects = /[<>]/.test(normalized.replace(PROCESS_SUBSTITUTION_RE, ''));
132
+ const mechanisms = [];
133
+ if (commitSubstitution)
134
+ mechanisms.push('commit-message-substitution');
135
+ if (composes)
136
+ mechanisms.push('composition');
137
+ if (substitutes && !commitSubstitution)
138
+ mechanisms.push('substitution');
139
+ if (redirects)
140
+ mechanisms.push('redirect');
141
+ // The fallback for the causes that are not a shape at all — an unbalanced quote, an empty
142
+ // command, a command with no resolvable program name — so a note is never empty.
143
+ if (mechanisms.length === 0)
144
+ mechanisms.push('unparseable');
145
+ return {
146
+ mechanism: mechanisms[0],
147
+ mechanisms,
148
+ notes: mechanisms.map((mechanism) => MECHANISM_NOTES[mechanism]),
149
+ };
150
+ }
151
+ /**
152
+ * The opening line of the preflight note: **what this is, and what it is not.**
153
+ *
154
+ * It says the finding is about OUR PARSER rather than about the command, and that nothing has been
155
+ * judged. Both halves are load-bearing. The first stops the rater reading the note as a report of
156
+ * something found — the failure mode a bare observation produced, where a rater treats our
157
+ * uncertainty as evidence and either inflates or explains it away. The second is what keeps this
158
+ * note out of the open-world note's register: that one may say the command *"has ALREADY been
159
+ * floored deterministically and will be shown to the user whatever you return"*, and here that
160
+ * sentence would simply be false.
161
+ */
162
+ export const PARSER_NOTE_PREAMBLE = 'PREFLIGHT NOTE: our command parser could not resolve what this command line runs, so here is ' +
163
+ 'what it did see. This is a fact about OUR PARSER and not a finding about the command — nothing ' +
164
+ 'has been judged, nothing has been floored, and none of this is a verdict or a severity. Rate ' +
165
+ 'the command on its own merits.';
166
+ /**
167
+ * Build the neutral preflight note for a command, or `null` when the gate resolved it.
168
+ *
169
+ * One note per mechanism the command carries, most specific first, bulleted when there is more than
170
+ * one — a command can compose AND substitute AND redirect, and a note that mentioned only the first
171
+ * would leave the rater reasoning about a fragment of the shape.
172
+ *
173
+ * @param command The raw command string as the model proposed it.
174
+ */
175
+ export function buildParserPreflightNote(command) {
176
+ const defect = describeAbstention(command);
177
+ if (defect === null)
178
+ return null;
179
+ const body = defect.notes.length === 1
180
+ ? defect.notes[0]
181
+ : defect.notes.map((note) => `- ${note}`).join('\n');
182
+ return `${PARSER_NOTE_PREAMBLE}\n${body}`;
183
+ }
184
+ //# sourceMappingURL=abstention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abstention.js","sourceRoot":"","sources":["../../../src/core/shell/abstention.ts"],"names":[],"mappings":"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"}
@@ -38,15 +38,49 @@
38
38
  * upstream. The one hard limit is unchanged and non-negotiable: **never fire on the mere presence of
39
39
  * a URL anywhere in the string**, because `git commit -m "closes https://…"` must stay silent.
40
40
  *
41
+ * ## TWO CONSUMERS, TWO INPUT SETS — read this before merging them back together
42
+ *
43
+ * This module answers the host question for **two** callers whose error costs differ, so it has two
44
+ * entry points and they are deliberately not the same function:
45
+ *
46
+ * - {@link findOpenWorldHostLiterals} — **the floor**. Its finding rewrites a `safe` verdict to
47
+ * `destructive` with no model in the loop, so it fires only where the parser resolved the whole
48
+ * command. "The parser could not resolve this" is a fact about the checker, not a detection about
49
+ * the command, and this layer floors only what is deterministically known.
50
+ * - {@link findComposedOpenWorld} — **the note**. It reads the parts of a command the parser could
51
+ * NOT resolve as a whole, and its finding is handed to the rater as context. It changes no
52
+ * outcome by itself.
53
+ *
54
+ * **The error-cost regime is the third distinct one in this codebase, and it is the widest — about
55
+ * WHICH HOSTS ARE NAMED.** The §8 hardline REFUSES unappealably, so it must be the narrowest. This
56
+ * module's floor RAISES a prompt, so it over-matches (below). Naming a host in the note only
57
+ * INFORMS THE MODEL: a host named that turns out not to be contacted costs one sentence of
58
+ * attention and no interruption at all. So do not "fix" a note false positive by narrowing the host
59
+ * extractor; that trades a free cost for a silent one.
60
+ *
61
+ * **That licence covers which hosts are named. It does not cover WHAT THE NOTE SAYS THEY DO.** A
62
+ * flow sentence asserts a mechanism — that fetched bytes are executed, that a file's contents are
63
+ * sent — and the rater cannot check that against a shell; it can only believe it. A mechanism that
64
+ * is false on an ordinary command is this node's own named failure mode arriving one layer in: an
65
+ * escalation laundered through the model instead of the parser, unfalsifiable because a note said
66
+ * it. So each flow arm fires only where its claim is **true of the program named**, and everything
67
+ * else falls through to the flowless sentence — which still names the hosts and says outright that
68
+ * the flow is not known. Saying less is not a loss of assistance; asserting a false mechanism is a
69
+ * loss of the layer.
70
+ *
71
+ * **And a flow sentence names EVERY host of the part it describes**, for the reason
72
+ * {@link findOpenWorldHostLiterals} returns every match rather than the first: the first is the
73
+ * proxy, and a sentence that names the reassuring host while hiding the other is worse than no
74
+ * sentence.
75
+ *
41
76
  * ## The shape of the matcher
42
77
  *
43
78
  * Ported from the measured prototype (`project-takahe _spikes/open-world-preflight/`).
44
79
  *
45
- * 1. **Decline on anything unclassifiable.** {@link classifyCommand} returns `null` on any
46
- * composition (separator, line break, `$(…)`, backtick, redirection), and the *ambiguity*
47
- * preflight already floors those. So this matcher never has to parse a hard command and it
48
- * must not claim the finding, because "it names a host" would be a worse (and possibly false)
49
- * explanation than "its target cannot be statically resolved".
80
+ * 1. **Decline on anything unclassifiable** — for the FLOOR only. {@link classifyCommand} returns
81
+ * `null` on any composition (separator, line break, `$(…)`, backtick, redirection), and a
82
+ * deterministic floor must not claim "it names a host" about a string whose target it could not
83
+ * statically resolve. The note path picks those up instead, by reading the parts.
50
84
  * 2. **Step past wrappers** (`sudo -u root`, `env FOO=1`, `nohup --`, …) to the head.
51
85
  * 3. **Look the head up** in {@link NETWORK_HEADS}, keyed by *where a host may legitimately appear*.
52
86
  * 4. **Test only the candidate operands** for a host literal.
@@ -104,13 +138,14 @@ export declare function isHostLiteral(operand: string): boolean;
104
138
  * caller can never accidentally hand this a form that has already lost the composition boundary
105
139
  * the decline below depends on.
106
140
  *
107
- * Returns `[]` declining rather than flooring for any command {@link classifyCommand} cannot
108
- * classify. Those compose, substitute or redirect, and the **ambiguity preflight already floors
109
- * them**, with a truer explanation than this one could give. Composed egress
110
- * (`curl … | sh`, `cat .env | curl …`) is thus still floored; it is simply floored one layer up.
111
- * That decline is also why `sed -i 's|http://a|http://b|' config.yml` is not this preflight's
112
- * finding: the `|` inside the sed expression reads as composition, so it was already unclassifiable
113
- * and already escalating before EXT-61 existed.
141
+ * **This is the FLOOR's input set, and it is narrow on purpose.** It returns `[]` — declining rather
142
+ * than flooring for any command {@link classifyCommand} cannot classify: those compose, substitute
143
+ * or redirect, and a deterministic rewrite of the rater's verdict must rest on a target this module
144
+ * actually resolved. A composed fetch (`curl … | sh`, `cat .env | curl …`) is therefore **not
145
+ * floored**; it is reported to the rater as context by {@link findComposedOpenWorld} instead, which
146
+ * is a different question with a different error cost (module docblock). The same decline is why
147
+ * `sed -i 's|http://a|http://b|' config.yml` is not this preflight's finding: the `|` inside the sed
148
+ * expression reads as composition.
114
149
  *
115
150
  * **Every match is returned, not the first.** The first is not the target: for
116
151
  * `curl -x http://proxy.corp.local:3128 https://evil.example.net/x` it is the proxy, and for
@@ -136,3 +171,93 @@ export declare function isHostLiteral(operand: string): boolean;
136
171
  * @returns The matched host literals, in argv order (used verbatim in the escalation reason).
137
172
  */
138
173
  export declare function findOpenWorldHostLiterals(command: string): string[];
174
+ /**
175
+ * The data flow the parts of a composed command line perform together — the fact that is not visible
176
+ * in any one part, and the only reason this note is worth a rater's attention.
177
+ */
178
+ export type ComposedFlow =
179
+ /**
180
+ * A fetch is piped into a program that can run its standard input. `stdinIsTheProgram` says
181
+ * whether it does on this line ({@link interpreterRunsStdin}) — `curl … | sh` runs the fetched
182
+ * bytes, `curl … | python3 -m json.tool` reads them as data — and the two get different
183
+ * sentences, because only one of them executes what the host serves.
184
+ */
185
+ {
186
+ readonly kind: 'fetch-into-interpreter';
187
+ readonly hosts: readonly string[];
188
+ readonly interpreter: string;
189
+ readonly stdinIsTheProgram: boolean;
190
+ }
191
+ /** A local program's output is piped into a program that sends it to a host. */
192
+ | {
193
+ readonly kind: 'local-into-transfer';
194
+ readonly producer: string;
195
+ readonly transfer: string;
196
+ readonly hosts: readonly string[];
197
+ }
198
+ /** A substitution's output becomes an argument the program SENDS. */
199
+ | {
200
+ readonly kind: 'substitution-into-transfer';
201
+ readonly transfer: string;
202
+ readonly hosts: readonly string[];
203
+ }
204
+ /** A transfer agent is told to read a local file and send its contents. */
205
+ | {
206
+ readonly kind: 'file-into-transfer';
207
+ readonly transfer: string;
208
+ readonly hosts: readonly string[];
209
+ readonly path: string | null;
210
+ };
211
+ /** What the note path found in a command the parser could not resolve as a whole. */
212
+ export interface ComposedOpenWorldFinding {
213
+ /**
214
+ * Host literals in a fetch/transfer position, found by reading the parts SEPARATELY.
215
+ *
216
+ * **Not the floor's set and never passed to it** — {@link findOpenWorldHostLiterals} is the floor's
217
+ * only input, and it declines every command this function accepts.
218
+ */
219
+ readonly hosts: readonly string[];
220
+ /** The flow across the parts, or `null` when none is determinable. */
221
+ readonly flow: ComposedFlow | null;
222
+ }
223
+ /**
224
+ * Read a command the gate's parser could NOT resolve part by part, and report the host literals and
225
+ * the data flow across those parts — or `null` when the command resolves, or when no part names a
226
+ * host.
227
+ *
228
+ * **This feeds the rater's note and nothing else.** It is never consulted by the destructive floor:
229
+ * see the module docblock for why the two questions have different input sets, and
230
+ * {@link findOpenWorldHostLiterals} for the floor's.
231
+ *
232
+ * The `null` on a resolvable command is the guard that keeps the rater from being told about the
233
+ * same host twice in two registers — a command the parser resolved is the floor's, and the floor's
234
+ * own note already names its hosts.
235
+ *
236
+ * Both the normalized and the raw form are read, for the reason {@link findOpenWorldHostLiterals}
237
+ * gives: normalization collapses `\x` to `x`, which defeats `c\url` and destroys a Windows path
238
+ * separator, so the raw pass is the only one that still sees `C:\Windows\System32\curl.exe`.
239
+ *
240
+ * @param command The raw command string as the model proposed it.
241
+ */
242
+ export declare function findComposedOpenWorld(command: string): ComposedOpenWorldFinding | null;
243
+ /**
244
+ * The opening line of the composed open-world note.
245
+ *
246
+ * **It states the two facts and asserts no third one.** A part of this line names a host in a
247
+ * fetch/transfer position, and nothing about the command has been decided. The second half is what
248
+ * keeps this out of the floor note's register: that one may say the command *"is never
249
+ * auto-approved"* because a floor really did fire, and here no floor exists — repeating its sentence
250
+ * would tell the rater the outcome is settled when the rating is the only thing that decides it.
251
+ */
252
+ export declare const COMPOSED_OPEN_WORLD_PREAMBLE: string;
253
+ /**
254
+ * Build the composed open-world note for a command, or `null` when there is nothing to say.
255
+ *
256
+ * One sentence of mechanism when the flow is determinable, plus the hosts the rest of the line names
257
+ * ({@link residualSentence}); when it is not, {@link flowlessSentence}. **Every host on the finding
258
+ * that can be quoted is named either way** — which arm fired must never decide how much the rater is
259
+ * told about the counterparties.
260
+ *
261
+ * @param command The raw command string as the model proposed it.
262
+ */
263
+ export declare function buildComposedOpenWorldNote(command: string): string | null;