@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.
Files changed (275) hide show
  1. package/.gsloth.review.md +2 -0
  2. package/README.md +71 -20
  3. package/dist/config/colour.d.ts +38 -0
  4. package/dist/config/colour.js +36 -0
  5. package/dist/config/colour.js.map +1 -0
  6. package/dist/config/configDiscovery.d.ts +79 -0
  7. package/dist/config/configDiscovery.js +80 -0
  8. package/dist/config/configDiscovery.js.map +1 -0
  9. package/dist/config/defaults.d.ts +20 -20
  10. package/dist/config/defaults.js +10 -8
  11. package/dist/config/defaults.js.map +1 -1
  12. package/dist/config/filesystem-tools.d.ts +41 -0
  13. package/dist/config/filesystem-tools.js +56 -0
  14. package/dist/config/filesystem-tools.js.map +1 -0
  15. package/dist/config/loader.d.ts +171 -19
  16. package/dist/config/loader.js +1054 -144
  17. package/dist/config/loader.js.map +1 -1
  18. package/dist/config/mouse.d.ts +50 -0
  19. package/dist/config/mouse.js +44 -0
  20. package/dist/config/mouse.js.map +1 -0
  21. package/dist/config/profiles.d.ts +68 -0
  22. package/dist/config/profiles.js +93 -0
  23. package/dist/config/profiles.js.map +1 -0
  24. package/dist/config/providerKeys.d.ts +69 -0
  25. package/dist/config/providerKeys.js +69 -0
  26. package/dist/config/providerKeys.js.map +1 -0
  27. package/dist/config/schema.d.ts +2671 -138
  28. package/dist/config/schema.js +1361 -85
  29. package/dist/config/schema.js.map +1 -1
  30. package/dist/config/shell-policy.d.ts +899 -111
  31. package/dist/config/shell-policy.js +800 -70
  32. package/dist/config/shell-policy.js.map +1 -1
  33. package/dist/config/tool-descriptions.d.ts +211 -0
  34. package/dist/config/tool-descriptions.js +272 -0
  35. package/dist/config/tool-descriptions.js.map +1 -0
  36. package/dist/config/types.d.ts +352 -41
  37. package/dist/config/types.js +1 -0
  38. package/dist/config/types.js.map +1 -1
  39. package/dist/config.d.ts +35 -1
  40. package/dist/config.js +16 -1
  41. package/dist/config.js.map +1 -1
  42. package/dist/constants.d.ts +28 -1
  43. package/dist/constants.js +28 -1
  44. package/dist/constants.js.map +1 -1
  45. package/dist/core/GthAbstractAgent.d.ts +166 -11
  46. package/dist/core/GthAbstractAgent.js +484 -45
  47. package/dist/core/GthAbstractAgent.js.map +1 -1
  48. package/dist/core/GthAgentRunner.d.ts +543 -57
  49. package/dist/core/GthAgentRunner.js +1494 -140
  50. package/dist/core/GthAgentRunner.js.map +1 -1
  51. package/dist/core/GthLangChainAgent.d.ts +117 -2
  52. package/dist/core/GthLangChainAgent.js +602 -29
  53. package/dist/core/GthLangChainAgent.js.map +1 -1
  54. package/dist/core/approvals/annotations.d.ts +122 -0
  55. package/dist/core/approvals/annotations.js +137 -0
  56. package/dist/core/approvals/annotations.js.map +1 -0
  57. package/dist/core/approvals/grants.d.ts +216 -0
  58. package/dist/core/approvals/grants.js +469 -0
  59. package/dist/core/approvals/grants.js.map +1 -0
  60. package/dist/core/approvals/matcher.d.ts +202 -0
  61. package/dist/core/approvals/matcher.js +267 -0
  62. package/dist/core/approvals/matcher.js.map +1 -0
  63. package/dist/core/approvals/mcpSubjects.d.ts +40 -0
  64. package/dist/core/approvals/mcpSubjects.js +99 -0
  65. package/dist/core/approvals/mcpSubjects.js.map +1 -0
  66. package/dist/core/approvals/promptHeader.d.ts +28 -0
  67. package/dist/core/approvals/promptHeader.js +62 -0
  68. package/dist/core/approvals/promptHeader.js.map +1 -0
  69. package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
  70. package/dist/core/approvals/toolAnnotationSources.js +277 -0
  71. package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
  72. package/dist/core/approvals/toolHost.d.ts +46 -0
  73. package/dist/core/approvals/toolHost.js +108 -0
  74. package/dist/core/approvals/toolHost.js.map +1 -0
  75. package/dist/core/debugCapture.d.ts +74 -0
  76. package/dist/core/debugCapture.js +100 -0
  77. package/dist/core/debugCapture.js.map +1 -0
  78. package/dist/core/gthLeanAgentFactory.d.ts +4 -4
  79. package/dist/core/gthLeanAgentFactory.js +4 -4
  80. package/dist/core/launchBanner.d.ts +127 -0
  81. package/dist/core/launchBanner.js +414 -0
  82. package/dist/core/launchBanner.js.map +1 -0
  83. package/dist/core/modelLabel.d.ts +19 -0
  84. package/dist/core/modelLabel.js +26 -0
  85. package/dist/core/modelLabel.js.map +1 -0
  86. package/dist/core/plainToolIndication.d.ts +15 -0
  87. package/dist/core/plainToolIndication.js +174 -0
  88. package/dist/core/plainToolIndication.js.map +1 -0
  89. package/dist/core/reasoningBlocks.d.ts +65 -0
  90. package/dist/core/reasoningBlocks.js +103 -0
  91. package/dist/core/reasoningBlocks.js.map +1 -0
  92. package/dist/core/refusal.d.ts +53 -0
  93. package/dist/core/refusal.js +133 -0
  94. package/dist/core/refusal.js.map +1 -0
  95. package/dist/core/runHeader.d.ts +38 -0
  96. package/dist/core/runHeader.js +42 -0
  97. package/dist/core/runHeader.js.map +1 -0
  98. package/dist/core/runStats.d.ts +14 -3
  99. package/dist/core/runStats.js +48 -3
  100. package/dist/core/runStats.js.map +1 -1
  101. package/dist/core/shell/ShellCommandFailedError.d.ts +3 -4
  102. package/dist/core/shell/ShellCommandFailedError.js +3 -4
  103. package/dist/core/shell/ShellCommandFailedError.js.map +1 -1
  104. package/dist/core/shell/abstention.d.ts +88 -0
  105. package/dist/core/shell/abstention.js +184 -0
  106. package/dist/core/shell/abstention.js.map +1 -0
  107. package/dist/core/shell/approvalCapture.d.ts +271 -0
  108. package/dist/core/shell/approvalCapture.js +108 -0
  109. package/dist/core/shell/approvalCapture.js.map +1 -0
  110. package/dist/core/shell/approvalStop.d.ts +123 -0
  111. package/dist/core/shell/approvalStop.js +269 -0
  112. package/dist/core/shell/approvalStop.js.map +1 -0
  113. package/dist/core/shell/arity.d.ts +6 -0
  114. package/dist/core/shell/arity.js +20 -6
  115. package/dist/core/shell/arity.js.map +1 -1
  116. package/dist/core/shell/denylist.d.ts +11 -0
  117. package/dist/core/shell/denylist.js +37 -0
  118. package/dist/core/shell/denylist.js.map +1 -0
  119. package/dist/core/shell/escalationSeverity.d.ts +141 -0
  120. package/dist/core/shell/escalationSeverity.js +89 -0
  121. package/dist/core/shell/escalationSeverity.js.map +1 -0
  122. package/dist/core/shell/framing.d.ts +190 -0
  123. package/dist/core/shell/framing.js +633 -0
  124. package/dist/core/shell/framing.js.map +1 -0
  125. package/dist/core/shell/hardline.d.ts +103 -0
  126. package/dist/core/shell/hardline.js +780 -0
  127. package/dist/core/shell/hardline.js.map +1 -0
  128. package/dist/core/shell/negotiation.d.ts +328 -0
  129. package/dist/core/shell/negotiation.js +488 -0
  130. package/dist/core/shell/negotiation.js.map +1 -0
  131. package/dist/core/shell/normalize.d.ts +44 -4
  132. package/dist/core/shell/normalize.js +61 -7
  133. package/dist/core/shell/normalize.js.map +1 -1
  134. package/dist/core/shell/openWorld.d.ts +263 -0
  135. package/dist/core/shell/openWorld.js +1188 -0
  136. package/dist/core/shell/openWorld.js.map +1 -0
  137. package/dist/core/shell/rater.d.ts +873 -0
  138. package/dist/core/shell/rater.js +1454 -0
  139. package/dist/core/shell/rater.js.map +1 -0
  140. package/dist/core/shell/raterModel.d.ts +41 -0
  141. package/dist/core/shell/raterModel.js +51 -0
  142. package/dist/core/shell/raterModel.js.map +1 -0
  143. package/dist/core/shell/raterVocabulary.d.ts +121 -0
  144. package/dist/core/shell/raterVocabulary.js +116 -0
  145. package/dist/core/shell/raterVocabulary.js.map +1 -0
  146. package/dist/core/shell/rejection.d.ts +69 -0
  147. package/dist/core/shell/rejection.js +38 -0
  148. package/dist/core/shell/rejection.js.map +1 -0
  149. package/dist/core/toolCallRepair/grammar.d.ts +41 -0
  150. package/dist/core/toolCallRepair/grammar.js +116 -0
  151. package/dist/core/toolCallRepair/grammar.js.map +1 -0
  152. package/dist/core/toolCallRepair/index.d.ts +2 -0
  153. package/dist/core/toolCallRepair/index.js +7 -0
  154. package/dist/core/toolCallRepair/index.js.map +1 -0
  155. package/dist/core/toolCallRepair/payload.d.ts +36 -0
  156. package/dist/core/toolCallRepair/payload.js +341 -0
  157. package/dist/core/toolCallRepair/payload.js.map +1 -0
  158. package/dist/core/toolCallRepair/promote.d.ts +45 -0
  159. package/dist/core/toolCallRepair/promote.js +90 -0
  160. package/dist/core/toolCallRepair/promote.js.map +1 -0
  161. package/dist/core/toolDisplay.d.ts +123 -0
  162. package/dist/core/toolDisplay.js +451 -0
  163. package/dist/core/toolDisplay.js.map +1 -0
  164. package/dist/core/toolOutputChannel.d.ts +95 -0
  165. package/dist/core/toolOutputChannel.js +165 -0
  166. package/dist/core/toolOutputChannel.js.map +1 -0
  167. package/dist/core/types.d.ts +349 -16
  168. package/dist/core/types.js.map +1 -1
  169. package/dist/history/historyFormat.d.ts +12 -3
  170. package/dist/history/historyFormat.js +50 -8
  171. package/dist/history/historyFormat.js.map +1 -1
  172. package/dist/history/historyStore.d.ts +77 -0
  173. package/dist/history/historyStore.js +173 -6
  174. package/dist/history/historyStore.js.map +1 -1
  175. package/dist/history/recordSession.d.ts +10 -1
  176. package/dist/history/recordSession.js +27 -0
  177. package/dist/history/recordSession.js.map +1 -1
  178. package/dist/providers/anthropic.js +12 -0
  179. package/dist/providers/anthropic.js.map +1 -1
  180. package/dist/providers/configurationPassthrough.d.ts +107 -0
  181. package/dist/providers/configurationPassthrough.js +148 -0
  182. package/dist/providers/configurationPassthrough.js.map +1 -0
  183. package/dist/providers/geminiSchemaSanitizer.d.ts +55 -0
  184. package/dist/providers/geminiSchemaSanitizer.js +347 -0
  185. package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
  186. package/dist/providers/geminiThinking.d.ts +60 -0
  187. package/dist/providers/geminiThinking.js +92 -0
  188. package/dist/providers/geminiThinking.js.map +1 -0
  189. package/dist/providers/google-genai.js +18 -1
  190. package/dist/providers/google-genai.js.map +1 -1
  191. package/dist/providers/groq.js +12 -0
  192. package/dist/providers/groq.js.map +1 -1
  193. package/dist/providers/huggingface.d.ts +25 -0
  194. package/dist/providers/huggingface.js +69 -0
  195. package/dist/providers/huggingface.js.map +1 -0
  196. package/dist/providers/modelCatalog.d.ts +109 -0
  197. package/dist/providers/modelCatalog.js +245 -0
  198. package/dist/providers/modelCatalog.js.map +1 -0
  199. package/dist/providers/modelDiscovery.d.ts +99 -5
  200. package/dist/providers/modelDiscovery.js +191 -35
  201. package/dist/providers/modelDiscovery.js.map +1 -1
  202. package/dist/providers/ollama.d.ts +18 -4
  203. package/dist/providers/ollama.js +67 -37
  204. package/dist/providers/ollama.js.map +1 -1
  205. package/dist/providers/openai.js +34 -0
  206. package/dist/providers/openai.js.map +1 -1
  207. package/dist/providers/openrouter.d.ts +26 -4
  208. package/dist/providers/openrouter.js +83 -26
  209. package/dist/providers/openrouter.js.map +1 -1
  210. package/dist/providers/vertexai.js +19 -1
  211. package/dist/providers/vertexai.js.map +1 -1
  212. package/dist/providers/xai.js +20 -0
  213. package/dist/providers/xai.js.map +1 -1
  214. package/dist/runtime/askStructured.d.ts +105 -0
  215. package/dist/runtime/askStructured.js +120 -0
  216. package/dist/runtime/askStructured.js.map +1 -0
  217. package/dist/runtime/conversation.d.ts +64 -0
  218. package/dist/runtime/conversation.js +171 -0
  219. package/dist/runtime/conversation.js.map +1 -0
  220. package/dist/runtime/singleShot.d.ts +37 -6
  221. package/dist/runtime/singleShot.js +113 -67
  222. package/dist/runtime/singleShot.js.map +1 -1
  223. package/dist/runtime/structuredOutput.d.ts +104 -0
  224. package/dist/runtime/structuredOutput.js +393 -0
  225. package/dist/runtime/structuredOutput.js.map +1 -0
  226. package/dist/utils/ProgressIndicator.d.ts +21 -0
  227. package/dist/utils/ProgressIndicator.js +30 -3
  228. package/dist/utils/ProgressIndicator.js.map +1 -1
  229. package/dist/utils/aiignoreUtils.js.map +1 -1
  230. package/dist/utils/binaryOutputUtils.js.map +1 -1
  231. package/dist/utils/consoleUtils.d.ts +95 -0
  232. package/dist/utils/consoleUtils.js +112 -2
  233. package/dist/utils/consoleUtils.js.map +1 -1
  234. package/dist/utils/crashHandler.d.ts +87 -0
  235. package/dist/utils/crashHandler.js +128 -0
  236. package/dist/utils/crashHandler.js.map +1 -0
  237. package/dist/utils/debugDump.d.ts +134 -0
  238. package/dist/utils/debugDump.js +381 -0
  239. package/dist/utils/debugDump.js.map +1 -0
  240. package/dist/utils/debugUtils.d.ts +13 -4
  241. package/dist/utils/debugUtils.js +36 -13
  242. package/dist/utils/debugUtils.js.map +1 -1
  243. package/dist/utils/displayWidth.d.ts +53 -0
  244. package/dist/utils/displayWidth.js +195 -0
  245. package/dist/utils/displayWidth.js.map +1 -0
  246. package/dist/utils/fileUtils.js.map +1 -1
  247. package/dist/utils/globalConfigUtils.d.ts +14 -2
  248. package/dist/utils/globalConfigUtils.js +22 -4
  249. package/dist/utils/globalConfigUtils.js.map +1 -1
  250. package/dist/utils/llmUtils.d.ts +39 -8
  251. package/dist/utils/llmUtils.js +76 -8
  252. package/dist/utils/llmUtils.js.map +1 -1
  253. package/dist/utils/redactSecrets.d.ts +63 -0
  254. package/dist/utils/redactSecrets.js +286 -0
  255. package/dist/utils/redactSecrets.js.map +1 -0
  256. package/dist/utils/systemPromptNotes.d.ts +222 -0
  257. package/dist/utils/systemPromptNotes.js +338 -0
  258. package/dist/utils/systemPromptNotes.js.map +1 -0
  259. package/dist/utils/systemUtils.d.ts +18 -1
  260. package/dist/utils/systemUtils.js +38 -3
  261. package/dist/utils/systemUtils.js.map +1 -1
  262. package/dist/utils/toolMatching.d.ts +30 -0
  263. package/dist/utils/toolMatching.js +44 -0
  264. package/dist/utils/toolMatching.js.map +1 -0
  265. package/dist/utils/untrustedText.d.ts +86 -0
  266. package/dist/utils/untrustedText.js +101 -0
  267. package/dist/utils/untrustedText.js.map +1 -0
  268. package/package.json +21 -7
  269. package/schema/gsloth-config.schema.json +1921 -326
  270. package/dist/core/shell/allowlist.d.ts +0 -75
  271. package/dist/core/shell/allowlist.js +0 -187
  272. package/dist/core/shell/allowlist.js.map +0 -1
  273. package/dist/core/shell/judge.d.ts +0 -161
  274. package/dist/core/shell/judge.js +0 -261
  275. 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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"}