@gaunt-sloth/core 2.0.0-alpha.8 → 2.0.0-beta.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.
- package/.gsloth.review.md +2 -0
- package/README.md +71 -20
- 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/configDiscovery.d.ts +79 -0
- package/dist/config/configDiscovery.js +80 -0
- package/dist/config/configDiscovery.js.map +1 -0
- package/dist/config/defaults.d.ts +20 -20
- package/dist/config/defaults.js +10 -8
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/filesystem-tools.d.ts +41 -0
- package/dist/config/filesystem-tools.js +56 -0
- package/dist/config/filesystem-tools.js.map +1 -0
- package/dist/config/loader.d.ts +171 -19
- package/dist/config/loader.js +1054 -144
- 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/profiles.d.ts +68 -0
- package/dist/config/profiles.js +93 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/providerKeys.d.ts +69 -0
- package/dist/config/providerKeys.js +69 -0
- package/dist/config/providerKeys.js.map +1 -0
- package/dist/config/schema.d.ts +2671 -138
- package/dist/config/schema.js +1361 -85
- package/dist/config/schema.js.map +1 -1
- package/dist/config/shell-policy.d.ts +899 -111
- package/dist/config/shell-policy.js +800 -70
- package/dist/config/shell-policy.js.map +1 -1
- package/dist/config/tool-descriptions.d.ts +211 -0
- package/dist/config/tool-descriptions.js +272 -0
- package/dist/config/tool-descriptions.js.map +1 -0
- package/dist/config/types.d.ts +352 -41
- package/dist/config/types.js +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/config.d.ts +35 -1
- package/dist/config.js +16 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +28 -1
- package/dist/constants.js +28 -1
- package/dist/constants.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +166 -11
- package/dist/core/GthAbstractAgent.js +484 -45
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +543 -57
- package/dist/core/GthAgentRunner.js +1494 -140
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/GthLangChainAgent.d.ts +117 -2
- package/dist/core/GthLangChainAgent.js +602 -29
- 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/promptHeader.d.ts +28 -0
- package/dist/core/approvals/promptHeader.js +62 -0
- package/dist/core/approvals/promptHeader.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/debugCapture.d.ts +74 -0
- package/dist/core/debugCapture.js +100 -0
- package/dist/core/debugCapture.js.map +1 -0
- package/dist/core/gthLeanAgentFactory.d.ts +4 -4
- package/dist/core/gthLeanAgentFactory.js +4 -4
- package/dist/core/launchBanner.d.ts +127 -0
- package/dist/core/launchBanner.js +414 -0
- package/dist/core/launchBanner.js.map +1 -0
- package/dist/core/modelLabel.d.ts +19 -0
- package/dist/core/modelLabel.js +26 -0
- package/dist/core/modelLabel.js.map +1 -0
- package/dist/core/plainToolIndication.d.ts +15 -0
- package/dist/core/plainToolIndication.js +174 -0
- package/dist/core/plainToolIndication.js.map +1 -0
- package/dist/core/reasoningBlocks.d.ts +65 -0
- package/dist/core/reasoningBlocks.js +103 -0
- package/dist/core/reasoningBlocks.js.map +1 -0
- package/dist/core/refusal.d.ts +53 -0
- package/dist/core/refusal.js +133 -0
- package/dist/core/refusal.js.map +1 -0
- package/dist/core/runHeader.d.ts +38 -0
- package/dist/core/runHeader.js +42 -0
- package/dist/core/runHeader.js.map +1 -0
- package/dist/core/runStats.d.ts +14 -3
- package/dist/core/runStats.js +48 -3
- package/dist/core/runStats.js.map +1 -1
- package/dist/core/shell/ShellCommandFailedError.d.ts +3 -4
- package/dist/core/shell/ShellCommandFailedError.js +3 -4
- package/dist/core/shell/ShellCommandFailedError.js.map +1 -1
- package/dist/core/shell/abstention.d.ts +88 -0
- package/dist/core/shell/abstention.js +184 -0
- package/dist/core/shell/abstention.js.map +1 -0
- package/dist/core/shell/approvalCapture.d.ts +271 -0
- package/dist/core/shell/approvalCapture.js +108 -0
- package/dist/core/shell/approvalCapture.js.map +1 -0
- package/dist/core/shell/approvalStop.d.ts +123 -0
- package/dist/core/shell/approvalStop.js +269 -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/escalationSeverity.d.ts +141 -0
- package/dist/core/shell/escalationSeverity.js +89 -0
- package/dist/core/shell/escalationSeverity.js.map +1 -0
- package/dist/core/shell/framing.d.ts +190 -0
- package/dist/core/shell/framing.js +633 -0
- package/dist/core/shell/framing.js.map +1 -0
- package/dist/core/shell/hardline.d.ts +103 -0
- package/dist/core/shell/hardline.js +780 -0
- package/dist/core/shell/hardline.js.map +1 -0
- package/dist/core/shell/negotiation.d.ts +328 -0
- package/dist/core/shell/negotiation.js +488 -0
- package/dist/core/shell/negotiation.js.map +1 -0
- package/dist/core/shell/normalize.d.ts +44 -4
- package/dist/core/shell/normalize.js +61 -7
- package/dist/core/shell/normalize.js.map +1 -1
- package/dist/core/shell/openWorld.d.ts +263 -0
- package/dist/core/shell/openWorld.js +1188 -0
- package/dist/core/shell/openWorld.js.map +1 -0
- package/dist/core/shell/rater.d.ts +873 -0
- package/dist/core/shell/rater.js +1454 -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/raterVocabulary.d.ts +121 -0
- package/dist/core/shell/raterVocabulary.js +116 -0
- package/dist/core/shell/raterVocabulary.js.map +1 -0
- package/dist/core/shell/rejection.d.ts +69 -0
- package/dist/core/shell/rejection.js +38 -0
- package/dist/core/shell/rejection.js.map +1 -0
- package/dist/core/toolCallRepair/grammar.d.ts +41 -0
- package/dist/core/toolCallRepair/grammar.js +116 -0
- package/dist/core/toolCallRepair/grammar.js.map +1 -0
- package/dist/core/toolCallRepair/index.d.ts +2 -0
- package/dist/core/toolCallRepair/index.js +7 -0
- package/dist/core/toolCallRepair/index.js.map +1 -0
- package/dist/core/toolCallRepair/payload.d.ts +36 -0
- package/dist/core/toolCallRepair/payload.js +341 -0
- package/dist/core/toolCallRepair/payload.js.map +1 -0
- package/dist/core/toolCallRepair/promote.d.ts +45 -0
- package/dist/core/toolCallRepair/promote.js +90 -0
- package/dist/core/toolCallRepair/promote.js.map +1 -0
- package/dist/core/toolDisplay.d.ts +123 -0
- package/dist/core/toolDisplay.js +451 -0
- package/dist/core/toolDisplay.js.map +1 -0
- package/dist/core/toolOutputChannel.d.ts +95 -0
- package/dist/core/toolOutputChannel.js +165 -0
- package/dist/core/toolOutputChannel.js.map +1 -0
- package/dist/core/types.d.ts +349 -16
- package/dist/core/types.js.map +1 -1
- package/dist/history/historyFormat.d.ts +12 -3
- package/dist/history/historyFormat.js +50 -8
- package/dist/history/historyFormat.js.map +1 -1
- package/dist/history/historyStore.d.ts +77 -0
- package/dist/history/historyStore.js +173 -6
- package/dist/history/historyStore.js.map +1 -1
- package/dist/history/recordSession.d.ts +10 -1
- package/dist/history/recordSession.js +27 -0
- package/dist/history/recordSession.js.map +1 -1
- package/dist/providers/anthropic.js +12 -0
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/configurationPassthrough.d.ts +107 -0
- package/dist/providers/configurationPassthrough.js +148 -0
- package/dist/providers/configurationPassthrough.js.map +1 -0
- package/dist/providers/geminiSchemaSanitizer.d.ts +55 -0
- package/dist/providers/geminiSchemaSanitizer.js +347 -0
- package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
- package/dist/providers/geminiThinking.d.ts +60 -0
- package/dist/providers/geminiThinking.js +92 -0
- package/dist/providers/geminiThinking.js.map +1 -0
- package/dist/providers/google-genai.js +18 -1
- package/dist/providers/google-genai.js.map +1 -1
- package/dist/providers/groq.js +12 -0
- package/dist/providers/groq.js.map +1 -1
- package/dist/providers/huggingface.d.ts +25 -0
- package/dist/providers/huggingface.js +69 -0
- package/dist/providers/huggingface.js.map +1 -0
- package/dist/providers/modelCatalog.d.ts +109 -0
- package/dist/providers/modelCatalog.js +245 -0
- package/dist/providers/modelCatalog.js.map +1 -0
- package/dist/providers/modelDiscovery.d.ts +99 -5
- package/dist/providers/modelDiscovery.js +191 -35
- package/dist/providers/modelDiscovery.js.map +1 -1
- package/dist/providers/ollama.d.ts +18 -4
- package/dist/providers/ollama.js +67 -37
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.js +34 -0
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +26 -4
- package/dist/providers/openrouter.js +83 -26
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/vertexai.js +19 -1
- package/dist/providers/vertexai.js.map +1 -1
- package/dist/providers/xai.js +20 -0
- package/dist/providers/xai.js.map +1 -1
- package/dist/runtime/askStructured.d.ts +105 -0
- package/dist/runtime/askStructured.js +120 -0
- package/dist/runtime/askStructured.js.map +1 -0
- package/dist/runtime/conversation.d.ts +64 -0
- package/dist/runtime/conversation.js +171 -0
- package/dist/runtime/conversation.js.map +1 -0
- package/dist/runtime/singleShot.d.ts +37 -6
- package/dist/runtime/singleShot.js +113 -67
- package/dist/runtime/singleShot.js.map +1 -1
- package/dist/runtime/structuredOutput.d.ts +104 -0
- package/dist/runtime/structuredOutput.js +393 -0
- package/dist/runtime/structuredOutput.js.map +1 -0
- 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/aiignoreUtils.js.map +1 -1
- package/dist/utils/binaryOutputUtils.js.map +1 -1
- package/dist/utils/consoleUtils.d.ts +95 -0
- package/dist/utils/consoleUtils.js +112 -2
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/crashHandler.d.ts +87 -0
- package/dist/utils/crashHandler.js +128 -0
- package/dist/utils/crashHandler.js.map +1 -0
- package/dist/utils/debugDump.d.ts +134 -0
- package/dist/utils/debugDump.js +381 -0
- package/dist/utils/debugDump.js.map +1 -0
- package/dist/utils/debugUtils.d.ts +13 -4
- package/dist/utils/debugUtils.js +36 -13
- package/dist/utils/debugUtils.js.map +1 -1
- package/dist/utils/displayWidth.d.ts +53 -0
- package/dist/utils/displayWidth.js +195 -0
- package/dist/utils/displayWidth.js.map +1 -0
- package/dist/utils/fileUtils.js.map +1 -1
- package/dist/utils/globalConfigUtils.d.ts +14 -2
- package/dist/utils/globalConfigUtils.js +22 -4
- package/dist/utils/globalConfigUtils.js.map +1 -1
- package/dist/utils/llmUtils.d.ts +39 -8
- package/dist/utils/llmUtils.js +76 -8
- package/dist/utils/llmUtils.js.map +1 -1
- package/dist/utils/redactSecrets.d.ts +63 -0
- package/dist/utils/redactSecrets.js +286 -0
- package/dist/utils/redactSecrets.js.map +1 -0
- package/dist/utils/systemPromptNotes.d.ts +222 -0
- package/dist/utils/systemPromptNotes.js +338 -0
- package/dist/utils/systemPromptNotes.js.map +1 -0
- package/dist/utils/systemUtils.d.ts +18 -1
- package/dist/utils/systemUtils.js +38 -3
- package/dist/utils/systemUtils.js.map +1 -1
- package/dist/utils/toolMatching.d.ts +30 -0
- package/dist/utils/toolMatching.js +44 -0
- package/dist/utils/toolMatching.js.map +1 -0
- package/dist/utils/untrustedText.d.ts +86 -0
- package/dist/utils/untrustedText.js +101 -0
- package/dist/utils/untrustedText.js.map +1 -0
- package/package.json +21 -7
- package/schema/gsloth-config.schema.json +1921 -326
- 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,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/approvals/grants
|
|
3
|
+
*
|
|
4
|
+
* EXT-71 (spec §3, §3.1, §6) — **what the escalation menu remembers**, in the one entry grammar.
|
|
5
|
+
*
|
|
6
|
+
* A grant is an {@link ApprovalEntry} plus the metadata §3 requires a list to be able to show:
|
|
7
|
+
* **when** it was made and **at what scope**. Two stores hold them — an in-memory
|
|
8
|
+
* {@link ApprovalGrantStore} for the life of one runner instance, and a
|
|
9
|
+
* {@link PersistedApprovalGrants} backed by the project's JSON file for `always` — and neither
|
|
10
|
+
* decides anything. They hold entries; `core/approvals/matcher.ts` compares them. There is exactly
|
|
11
|
+
* one comparison engine and it is not here.
|
|
12
|
+
*
|
|
13
|
+
* ## The menu never widens
|
|
14
|
+
*
|
|
15
|
+
* §3.1/§6: *always approve* and *always reject* write **the command the human saw**, as a
|
|
16
|
+
* fully-explicit `exact` entry ({@link shellGrantEntry}) — never a prefix, never a pattern, never a
|
|
17
|
+
* generalization. Breadth is always something a human typed into a config file. The other half of
|
|
18
|
+
* that rule is equally load-bearing: **there is no second-guessing layer on top of a match**, so a
|
|
19
|
+
* user's own entry naming a flag someone once thought dangerous (`curl -o out.txt`) is honored like
|
|
20
|
+
* any other. Overruling it would be a control offered and then refused.
|
|
21
|
+
*
|
|
22
|
+
* **A tool grant records identity, not arguments** ({@link toolGrantEntry}, §4.7.4) — the tool, its
|
|
23
|
+
* server where it has one, and the host where the call carries one. That is knowingly broader than
|
|
24
|
+
* the shell's exact-command grant, because a repeat shell command usually is identical and a repeat
|
|
25
|
+
* tool call usually is not; the host is the bound that keeps "broader" from meaning "every
|
|
26
|
+
* counterparty, forever". A tool grant additionally carries the effective annotation set it was made
|
|
27
|
+
* under, and weakening that set invalidates it ({@link annotationWeakenings}).
|
|
28
|
+
*
|
|
29
|
+
* The one thing {@link shellGrantEntry} does to the command is {@link normalizeCommand} it, because
|
|
30
|
+
* that is the form every comparison runs over (§3.1: *"spacing and quoting spellings of one command
|
|
31
|
+
* are therefore one command"*). Storing the raw string instead would mean the most ordinary grant
|
|
32
|
+
* imaginable — `always approve` on the `"npm test\n"` a tool argument routinely carries — never
|
|
33
|
+
* matching the command that produced it, which is the same "offered and then refused" failure with
|
|
34
|
+
* the evidence hidden.
|
|
35
|
+
*
|
|
36
|
+
* ## The persisted file
|
|
37
|
+
*
|
|
38
|
+
* ```jsonc
|
|
39
|
+
* {
|
|
40
|
+
* "version": 2,
|
|
41
|
+
* "grants": [
|
|
42
|
+
* { "entry": { "type": "shell", "matcher": "exact", "pattern": "npm test" },
|
|
43
|
+
* "grantedAt": "2026-08-02T09:15:00.000Z", "scope": "always" },
|
|
44
|
+
* { "entry": { "type": "mcpTool", "server": "fetcher", "matcher": "exact",
|
|
45
|
+
* "pattern": "fetch_url", "host": "docs.internal.example" },
|
|
46
|
+
* "grantedAt": "2026-08-02T09:16:00.000Z", "scope": "always",
|
|
47
|
+
* "annotations": { "readOnlyHint": true, "destructiveHint": false,
|
|
48
|
+
* "idempotentHint": true, "openWorldHint": true } }
|
|
49
|
+
* ]
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* `annotations` is absent on a `shell` grant and on any grant written before it existed; a grant
|
|
54
|
+
* without one simply has nothing to invalidate it and stands as it did.
|
|
55
|
+
*
|
|
56
|
+
* Reads stay fail-closed-on-auto-approval: a missing, unreadable, malformed or partly-malformed
|
|
57
|
+
* file yields fewer grants (at worst none) rather than throwing, because an empty allow-list only
|
|
58
|
+
* ever means *prompt*.
|
|
59
|
+
*/
|
|
60
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
61
|
+
import { approvalEntrySchema, renderApprovalEntryObject } from '#src/config/schema.js';
|
|
62
|
+
import { TOOL_ANNOTATION_HINTS } from '#src/config/shell-policy.js';
|
|
63
|
+
import { describeApprovalEntry, MCP_FAIL_CLOSED_ANNOTATIONS, } from '#src/core/approvals/matcher.js';
|
|
64
|
+
import { UNRESOLVED_MCP_SERVER } from '#src/core/approvals/mcpSubjects.js';
|
|
65
|
+
import { normalizeCommand } from '#src/core/shell/normalize.js';
|
|
66
|
+
import { StatusLevel } from '#src/core/types.js';
|
|
67
|
+
/** The version this module writes. */
|
|
68
|
+
const PERSISTED_VERSION = 2;
|
|
69
|
+
/**
|
|
70
|
+
* §3.1/§6 — the entry the escalation menu writes for a shell command: **that command, and only
|
|
71
|
+
* that command**.
|
|
72
|
+
*
|
|
73
|
+
* The single place a menu grant's entry is built, so the line the prompt shows the human ("this is
|
|
74
|
+
* what will be stored") and the line that lands in the store cannot drift apart.
|
|
75
|
+
*/
|
|
76
|
+
export function shellGrantEntry(command) {
|
|
77
|
+
return { type: 'shell', matcher: 'exact', pattern: normalizeCommand(command) };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* §4.7.4/§6 — the entry the escalation menu writes for a **tool** call: the tool's identity, plus
|
|
81
|
+
* the host where the call carries one.
|
|
82
|
+
*
|
|
83
|
+
* The counterpart of {@link shellGrantEntry} and the single place a tool grant's entry is built, so
|
|
84
|
+
* the line the prompt shows the human and the line that lands in the store cannot drift apart.
|
|
85
|
+
*
|
|
86
|
+
* **Identity, never arguments.** A grant recording a full argument signature would never match a
|
|
87
|
+
* second time — not a narrower grant, a useless one. That is knowingly broader than the shell's
|
|
88
|
+
* exact-command grant, with one bound: on the shell path §4.6's escape carries the host inside the
|
|
89
|
+
* command string, so it is host-scoped by construction, while a tool-identity-only grant on a fetch
|
|
90
|
+
* tool would be every host, forever.
|
|
91
|
+
*
|
|
92
|
+
* `server` on an `mcpTool` grant is the user's own `mcpServers` config key (§4.7.5). Nothing a
|
|
93
|
+
* server declares about its own name participates, and a grant for one server's tool can never be
|
|
94
|
+
* claimed by another server's same-named tool because the other server sits under a different key.
|
|
95
|
+
*
|
|
96
|
+
* **Returns `null` for a call whose server could not be resolved.** {@link UNRESOLVED_MCP_SERVER}
|
|
97
|
+
* is the empty string, which `server` (`z.string().min(1)`) cannot hold: such an entry would be
|
|
98
|
+
* written to the file and then silently dropped by the grammar's own validator on the next read, so
|
|
99
|
+
* the human would be told their approval was remembered when it was not. A call nobody can attribute
|
|
100
|
+
* to a server is not one anything can remember.
|
|
101
|
+
*/
|
|
102
|
+
export function toolGrantEntry(subject) {
|
|
103
|
+
const host = subject.host !== undefined && subject.host.length > 0 ? subject.host : undefined;
|
|
104
|
+
if (subject.kind === 'mcpTool') {
|
|
105
|
+
if (subject.server === UNRESOLVED_MCP_SERVER)
|
|
106
|
+
return null;
|
|
107
|
+
return {
|
|
108
|
+
type: 'mcpTool',
|
|
109
|
+
server: subject.server,
|
|
110
|
+
matcher: 'exact',
|
|
111
|
+
pattern: subject.name,
|
|
112
|
+
...(host !== undefined ? { host } : {}),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
type: 'tool',
|
|
117
|
+
matcher: 'exact',
|
|
118
|
+
pattern: subject.name,
|
|
119
|
+
...(host !== undefined ? { host } : {}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* §4.7.4 — **the three moves that weaken an effective annotation set**, and the whole of what
|
|
124
|
+
* invalidates a grant. Each names the hint and the transition, so the notice a human reads can say
|
|
125
|
+
* which one moved.
|
|
126
|
+
*
|
|
127
|
+
* They are exactly the moves that make a tool a more dangerous proposition than the one that was
|
|
128
|
+
* approved. The mirror images — a tool becoming read-only, closing to the open world, or ceasing to
|
|
129
|
+
* destroy — are strengthenings and change nothing: a grant is a permission, and a tool that has
|
|
130
|
+
* become safer is still covered by it.
|
|
131
|
+
*/
|
|
132
|
+
const WEAKENING_MOVES = [
|
|
133
|
+
{ hint: 'readOnlyHint', from: true, to: false },
|
|
134
|
+
{ hint: 'openWorldHint', from: false, to: true },
|
|
135
|
+
{ hint: 'destructiveHint', from: false, to: true },
|
|
136
|
+
];
|
|
137
|
+
/**
|
|
138
|
+
* §4.7.4 — which hints moved in the weakening direction between the set a grant was made under and
|
|
139
|
+
* the set that holds now. Empty means the grant still stands.
|
|
140
|
+
*
|
|
141
|
+
* **Only the four booleans are compared, so schema and description changes invalidate nothing** —
|
|
142
|
+
* not by a rule that exempts them, but because a snapshot is four booleans and a description is not
|
|
143
|
+
* one of them. Descriptions churn on every server release, and a grant that dissolved on churn
|
|
144
|
+
* would teach users that grants are worthless.
|
|
145
|
+
*
|
|
146
|
+
* **An untrusted server's declaration change likewise invalidates nothing**, again by construction:
|
|
147
|
+
* §4.7.1 makes an untrusted server's effective set the constant fail-closed default, so both sides
|
|
148
|
+
* of this comparison are that constant however the server re-declares itself. Only a **trusted**
|
|
149
|
+
* server can move an effective value — which is exactly where invalidation matters, since the
|
|
150
|
+
* trusted server is the one whose rug-pull would otherwise ride an existing grant.
|
|
151
|
+
*/
|
|
152
|
+
export function annotationWeakenings(snapshot, current) {
|
|
153
|
+
return WEAKENING_MOVES.filter(({ hint, from, to }) => snapshot[hint] === from && current[hint] === to).map(({ hint }) => hint);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* §4.7.1/§4.7.4 — **can WITHDRAWING trust in this hint weaken an effective set?**
|
|
157
|
+
*
|
|
158
|
+
* Withdrawing trust pushes a hint back to its MCP fail-closed default, and every weakening move
|
|
159
|
+
* *ends* at that default, so the answer does not depend on what a server declared: it is exactly
|
|
160
|
+
* whether the move (not-the-default → the default) is one of {@link WEAKENING_MOVES}. Three of the
|
|
161
|
+
* four hints answer yes — `readOnlyHint`, `openWorldHint` and `destructiveHint`, whose fail-closed
|
|
162
|
+
* default is `true`, so a server whose `destructiveHint: false` was believed becomes destructive
|
|
163
|
+
* again the moment it is not. `idempotentHint` is the only one that answers no, because no
|
|
164
|
+
* weakening move names it.
|
|
165
|
+
*
|
|
166
|
+
* **It asks {@link annotationWeakenings} rather than restating the table.** A second statement of
|
|
167
|
+
* which moves weaken is how a warning comes to describe a rule the gate no longer has — which
|
|
168
|
+
* matters most here, since this decides whether the human is told their saved approvals are about
|
|
169
|
+
* to be withdrawn.
|
|
170
|
+
*/
|
|
171
|
+
export function trustWithdrawalWeakens(hint) {
|
|
172
|
+
const untrusted = { ...MCP_FAIL_CLOSED_ANNOTATIONS };
|
|
173
|
+
const trusted = { ...untrusted, [hint]: !untrusted[hint] };
|
|
174
|
+
return annotationWeakenings(trusted, untrusted).includes(hint);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* §4.7.4 — the notice a weakened grant is removed with. **It names the tool, the server and the
|
|
178
|
+
* hint that moved**, because the human approved a tool *as annotated*: a tool that re-annotates
|
|
179
|
+
* itself into a more dangerous shape is a different proposition wearing the same name, and a notice
|
|
180
|
+
* that did not say which name changed would be indistinguishable from the gate malfunctioning.
|
|
181
|
+
*
|
|
182
|
+
* It takes the **entry** rather than the call's subject, so it describes the grant that was actually
|
|
183
|
+
* withdrawn — including its host bound, where it had one. One call may withdraw both a host-bound
|
|
184
|
+
* grant and a tool-only one, and two notices that could not be told apart would be worse than one.
|
|
185
|
+
* The entry is rendered by {@link describeApprovalEntry}, the same one-liner every other provenance
|
|
186
|
+
* message uses.
|
|
187
|
+
*/
|
|
188
|
+
export function describeWeakenedGrant(entry, weakened, snapshot, current) {
|
|
189
|
+
const moves = weakened
|
|
190
|
+
.map((hint) => `${hint} changed from ${snapshot[hint]} to ${current[hint]}`)
|
|
191
|
+
.join(', ');
|
|
192
|
+
return (`Your saved approval for ${describeApprovalEntry(entry)} was removed: the tool now describes ` +
|
|
193
|
+
`itself as more dangerous than when you approved it (${moves}). You will be asked about the ` +
|
|
194
|
+
'next call.');
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Identity of an entry, for **de-duplication only** — never a match decision. Two grants are the
|
|
198
|
+
* same grant when they would be the same line in a config file; whether an entry matches a call is
|
|
199
|
+
* `resolveApprovalRules`'s alone, and nothing in this module may answer that question.
|
|
200
|
+
*/
|
|
201
|
+
function grantKey(entry) {
|
|
202
|
+
return renderApprovalEntryObject(entry);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The `always` timestamp for entries migrated from the v1 file, which recorded none: the file's own
|
|
206
|
+
* last-write time, which is when the last of those grants was actually made. Falls back to now when
|
|
207
|
+
* the file cannot be stat'd.
|
|
208
|
+
*/
|
|
209
|
+
function fileWriteTime(filePath) {
|
|
210
|
+
try {
|
|
211
|
+
return new Date(statSync(filePath).mtimeMs).toISOString();
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return new Date().toISOString();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Read a persisted {@link ApprovalGrant.annotations} snapshot.
|
|
219
|
+
*
|
|
220
|
+
* Three outcomes, and the middle one is the point: `undefined` when the field is absent (a `shell`
|
|
221
|
+
* grant, or a tool grant written before the field existed — nothing to compare, so the grant
|
|
222
|
+
* stands), the set when it is four booleans, and `null` when it is **present and malformed**, which
|
|
223
|
+
* drops the whole grant.
|
|
224
|
+
*
|
|
225
|
+
* That last case is deliberately harsher than the rest of {@link readGrant}, and for a reason that
|
|
226
|
+
* does not apply to the other metadata: **this field decides something.** `grantedAt` and `scope`
|
|
227
|
+
* are display, so coercing them costs nothing; a snapshot is what invalidation compares against, so
|
|
228
|
+
* a coerced one (a string `"true"` read as truthy) would feed a wrong comparison into the check and
|
|
229
|
+
* could conclude that a weakened tool had not weakened. Between dropping the snapshot — which leaves
|
|
230
|
+
* a rug-pull free to ride the grant — and dropping the grant, which costs a re-prompt, the field
|
|
231
|
+
* exists to fail closed and so does this.
|
|
232
|
+
*/
|
|
233
|
+
function readAnnotationSnapshot(value) {
|
|
234
|
+
if (value === undefined)
|
|
235
|
+
return undefined;
|
|
236
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
237
|
+
return null;
|
|
238
|
+
const record = value;
|
|
239
|
+
const snapshot = {};
|
|
240
|
+
for (const hint of TOOL_ANNOTATION_HINTS) {
|
|
241
|
+
if (typeof record[hint] !== 'boolean')
|
|
242
|
+
return null;
|
|
243
|
+
snapshot[hint] = record[hint];
|
|
244
|
+
}
|
|
245
|
+
return snapshot;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Read one persisted grant defensively. The **entry is validated by the config grammar's own
|
|
249
|
+
* schema** — one grammar, one validator — so a malformed entry is dropped here and can never reach
|
|
250
|
+
* the matcher. Timestamp and scope are coerced rather than validated: they decide nothing, and
|
|
251
|
+
* discarding a real grant over a missing timestamp would cost an approval the human already gave.
|
|
252
|
+
* The annotation snapshot is the exception ({@link readAnnotationSnapshot}), because it decides.
|
|
253
|
+
*/
|
|
254
|
+
function readGrant(value, fallbackTime) {
|
|
255
|
+
if (!value || typeof value !== 'object')
|
|
256
|
+
return null;
|
|
257
|
+
const record = value;
|
|
258
|
+
const parsed = approvalEntrySchema.safeParse(record.entry);
|
|
259
|
+
if (!parsed.success)
|
|
260
|
+
return null;
|
|
261
|
+
const annotations = readAnnotationSnapshot(record.annotations);
|
|
262
|
+
if (annotations === null)
|
|
263
|
+
return null;
|
|
264
|
+
return {
|
|
265
|
+
entry: parsed.data,
|
|
266
|
+
grantedAt: typeof record.grantedAt === 'string' ? record.grantedAt : fallbackTime,
|
|
267
|
+
scope: record.scope === 'session' ? 'session' : 'always',
|
|
268
|
+
...(annotations !== undefined ? { annotations } : {}),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* A set of grants with entry-identity semantics. Pure data + membership: it holds what the human
|
|
273
|
+
* granted and answers *is this the same grant*, never *does this grant cover that command*.
|
|
274
|
+
*/
|
|
275
|
+
export class ApprovalGrantStore {
|
|
276
|
+
grants = [];
|
|
277
|
+
constructor(initial = []) {
|
|
278
|
+
for (const grant of initial)
|
|
279
|
+
this.add(grant);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Add a grant. Returns whether it was new — an identical entry is not stored twice.
|
|
283
|
+
*
|
|
284
|
+
* The {@link ApprovalGrant.annotations} snapshot is **copied on the way in**, so what the store
|
|
285
|
+
* holds is private to this grant whatever the caller passed: the effective set may be a live
|
|
286
|
+
* object the caller keeps, or (were a source ever to regress) the shared fail-closed constant, and
|
|
287
|
+
* a store aliasing either would let one grant's record be rewritten from outside it. Copying here
|
|
288
|
+
* rather than at each call site makes that structural instead of a habit every caller must keep.
|
|
289
|
+
*/
|
|
290
|
+
add(grant) {
|
|
291
|
+
const key = grantKey(grant.entry);
|
|
292
|
+
if (this.grants.some((held) => grantKey(held.entry) === key))
|
|
293
|
+
return false;
|
|
294
|
+
this.grants.push(grant.annotations ? { ...grant, annotations: { ...grant.annotations } } : grant);
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* The grant stored under this entry's identity, or `undefined`.
|
|
299
|
+
*
|
|
300
|
+
* **Identity, never a match decision** — the same de-duplication question {@link add} asks. It
|
|
301
|
+
* answers *"is this the same grant"*, and whether a grant covers a call remains
|
|
302
|
+
* `resolveApprovalRules`'s alone.
|
|
303
|
+
*/
|
|
304
|
+
find(entry) {
|
|
305
|
+
const key = grantKey(entry);
|
|
306
|
+
return this.grants.find((held) => grantKey(held.entry) === key);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Drop the grant stored under this entry's identity. Returns whether one was there.
|
|
310
|
+
*
|
|
311
|
+
* §4.7.4's invalidation is a **removal** rather than a skip, and that is load-bearing: {@link add}
|
|
312
|
+
* de-duplicates by entry identity, so a grant left in place while being ignored would silently
|
|
313
|
+
* swallow the human's re-approval of the same tool — the grant would appear to be re-made and the
|
|
314
|
+
* stale snapshot would keep invalidating it.
|
|
315
|
+
*/
|
|
316
|
+
remove(entry) {
|
|
317
|
+
const key = grantKey(entry);
|
|
318
|
+
const index = this.grants.findIndex((held) => grantKey(held.entry) === key);
|
|
319
|
+
if (index < 0)
|
|
320
|
+
return false;
|
|
321
|
+
this.grants.splice(index, 1);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
/** Every grant, in the order they were made. */
|
|
325
|
+
list() {
|
|
326
|
+
return [...this.grants];
|
|
327
|
+
}
|
|
328
|
+
/** Just the entries, for handing to the matcher as one of its rule lists. */
|
|
329
|
+
entries() {
|
|
330
|
+
return this.grants.map((grant) => grant.entry);
|
|
331
|
+
}
|
|
332
|
+
/** How many grants are held. */
|
|
333
|
+
size() {
|
|
334
|
+
return this.grants.length;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* The persisted (`always`) grant store, backed by a JSON file whose path is injected (the runner
|
|
339
|
+
* resolves it via fileUtils → `.gsloth/.gsloth-settings/shell-allowlist.json`) so tests can point it
|
|
340
|
+
* at a temp dir.
|
|
341
|
+
*
|
|
342
|
+
* ## The v1 migration, and the direction it goes
|
|
343
|
+
*
|
|
344
|
+
* The shipped v1 file held `prefixes: string[]` — classified command PREFIXES, so a stored
|
|
345
|
+
* `npm test` also auto-approved `npm test --watch`. Each prefix migrates to an **`exact` entry for
|
|
346
|
+
* the same string**, with **one** notice naming the file.
|
|
347
|
+
*
|
|
348
|
+
* That narrows what the file grants, on purpose: a v1 prefix was broader than what the human was
|
|
349
|
+
* actually shown when they answered the prompt, so narrowing it costs at worst a re-prompt and
|
|
350
|
+
* never an execution — the direction every ambiguity in this design resolves. The migrated file is
|
|
351
|
+
* rewritten as v2 immediately, so the notice is a one-time event rather than a per-session one; a
|
|
352
|
+
* write that fails (read-only checkout) is not fatal — the grants are in force for this session and
|
|
353
|
+
* the notice simply appears again next time.
|
|
354
|
+
*/
|
|
355
|
+
export class PersistedApprovalGrants {
|
|
356
|
+
store;
|
|
357
|
+
filePath;
|
|
358
|
+
constructor(filePath, options) {
|
|
359
|
+
this.filePath = filePath;
|
|
360
|
+
const { grants, migrated } = PersistedApprovalGrants.load(filePath, options?.onNotice);
|
|
361
|
+
this.store = new ApprovalGrantStore(grants);
|
|
362
|
+
if (migrated)
|
|
363
|
+
this.tryPersist();
|
|
364
|
+
}
|
|
365
|
+
static load(filePath, onNotice) {
|
|
366
|
+
try {
|
|
367
|
+
if (!existsSync(filePath))
|
|
368
|
+
return { grants: [], migrated: false };
|
|
369
|
+
const parsed = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
370
|
+
if (!parsed || typeof parsed !== 'object')
|
|
371
|
+
return { grants: [], migrated: false };
|
|
372
|
+
const record = parsed;
|
|
373
|
+
if (Array.isArray(record.grants)) {
|
|
374
|
+
const fallbackTime = fileWriteTime(filePath);
|
|
375
|
+
const grants = record.grants
|
|
376
|
+
.map((value) => readGrant(value, fallbackTime))
|
|
377
|
+
.filter((grant) => grant !== null);
|
|
378
|
+
return { grants, migrated: false };
|
|
379
|
+
}
|
|
380
|
+
if (Array.isArray(record.prefixes)) {
|
|
381
|
+
return PersistedApprovalGrants.migrateFromV1(record.prefixes, filePath, onNotice);
|
|
382
|
+
}
|
|
383
|
+
return { grants: [], migrated: false };
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
// Corrupt / unreadable → behave as empty. Fail-closed on auto-approval: an empty store only
|
|
387
|
+
// ever means "prompt", so there is nothing to gain by throwing at a user mid-run.
|
|
388
|
+
return { grants: [], migrated: false };
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/** Each v1 prefix → an `exact` entry for the same string, with ONE notice naming the file. */
|
|
392
|
+
static migrateFromV1(prefixes, filePath, onNotice) {
|
|
393
|
+
const grantedAt = fileWriteTime(filePath);
|
|
394
|
+
const migrated = new ApprovalGrantStore();
|
|
395
|
+
for (const prefix of prefixes) {
|
|
396
|
+
if (typeof prefix !== 'string')
|
|
397
|
+
continue;
|
|
398
|
+
const entry = shellGrantEntry(prefix);
|
|
399
|
+
if (entry.pattern.length === 0)
|
|
400
|
+
continue;
|
|
401
|
+
migrated.add({ entry, grantedAt, scope: 'always' });
|
|
402
|
+
}
|
|
403
|
+
if (migrated.size() > 0) {
|
|
404
|
+
// ONE notice for the whole file, not one per entry: the user needs to know their saved
|
|
405
|
+
// approvals changed meaning, once, and a line per entry would bury that in its own repetition.
|
|
406
|
+
onNotice?.({
|
|
407
|
+
level: StatusLevel.INFO,
|
|
408
|
+
message: `Your saved shell approvals (${filePath}) were stored in an older format that remembered ` +
|
|
409
|
+
'a command PREFIX, which also approved longer commands starting with it. Each is now ' +
|
|
410
|
+
'remembered as exactly the command it was, so a variant with extra arguments will ask ' +
|
|
411
|
+
'again. Nothing was removed; some commands may prompt once more.',
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return { grants: migrated.list(), migrated: true };
|
|
415
|
+
}
|
|
416
|
+
/** Every grant. */
|
|
417
|
+
list() {
|
|
418
|
+
return this.store.list();
|
|
419
|
+
}
|
|
420
|
+
/** Just the entries, for handing to the matcher as one of its rule lists. */
|
|
421
|
+
entries() {
|
|
422
|
+
return this.store.entries();
|
|
423
|
+
}
|
|
424
|
+
/** How many grants are persisted. */
|
|
425
|
+
size() {
|
|
426
|
+
return this.store.size();
|
|
427
|
+
}
|
|
428
|
+
/** Add a grant and persist the whole store. A duplicate entry rewrites nothing. */
|
|
429
|
+
add(grant) {
|
|
430
|
+
if (!this.store.add(grant))
|
|
431
|
+
return;
|
|
432
|
+
this.tryPersist();
|
|
433
|
+
}
|
|
434
|
+
/** The grant held under this entry's identity, or `undefined`. */
|
|
435
|
+
find(entry) {
|
|
436
|
+
return this.store.find(entry);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Drop the grant held under this entry's identity and rewrite the file. Returns whether one was
|
|
440
|
+
* there.
|
|
441
|
+
*
|
|
442
|
+
* The write is what makes §4.7.4's invalidation a one-time event: a removal held only in memory
|
|
443
|
+
* would be undone by the next session reloading the same stale snapshot, so the user would be
|
|
444
|
+
* told their grant had been withdrawn once per session, forever.
|
|
445
|
+
*/
|
|
446
|
+
remove(entry) {
|
|
447
|
+
if (!this.store.remove(entry))
|
|
448
|
+
return false;
|
|
449
|
+
this.tryPersist();
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Write the file. Never throws: the grants are already in force for this session, and a
|
|
454
|
+
* read-only checkout must not end a run over a bookkeeping write.
|
|
455
|
+
*/
|
|
456
|
+
tryPersist() {
|
|
457
|
+
const file = {
|
|
458
|
+
version: PERSISTED_VERSION,
|
|
459
|
+
grants: this.store.list(),
|
|
460
|
+
};
|
|
461
|
+
try {
|
|
462
|
+
writeFileSync(this.filePath, JSON.stringify(file, null, 2) + '\n', 'utf8');
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
// Intentionally swallowed — see the doc comment.
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
//# sourceMappingURL=grants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grants.js","sourceRoot":"","sources":["../../../src/core/approvals/grants.ts"],"names":[],"mappings":"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"}
|