@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.
Files changed (109) hide show
  1. package/README.md +1 -1
  2. package/dist/config/colour.d.ts +38 -0
  3. package/dist/config/colour.js +36 -0
  4. package/dist/config/colour.js.map +1 -0
  5. package/dist/config/defaults.d.ts +1 -0
  6. package/dist/config/defaults.js +1 -0
  7. package/dist/config/defaults.js.map +1 -1
  8. package/dist/config/loader.d.ts +13 -6
  9. package/dist/config/loader.js +171 -28
  10. package/dist/config/loader.js.map +1 -1
  11. package/dist/config/mouse.d.ts +50 -0
  12. package/dist/config/mouse.js +44 -0
  13. package/dist/config/mouse.js.map +1 -0
  14. package/dist/config/schema.d.ts +2372 -114
  15. package/dist/config/schema.js +845 -16
  16. package/dist/config/schema.js.map +1 -1
  17. package/dist/config/shell-policy.d.ts +466 -116
  18. package/dist/config/shell-policy.js +273 -62
  19. package/dist/config/shell-policy.js.map +1 -1
  20. package/dist/config/tool-descriptions.d.ts +165 -0
  21. package/dist/config/tool-descriptions.js +229 -0
  22. package/dist/config/tool-descriptions.js.map +1 -0
  23. package/dist/config/types.d.ts +36 -1
  24. package/dist/config/types.js.map +1 -1
  25. package/dist/config.d.ts +3 -0
  26. package/dist/config.js +3 -0
  27. package/dist/config.js.map +1 -1
  28. package/dist/core/GthAbstractAgent.d.ts +59 -1
  29. package/dist/core/GthAbstractAgent.js +72 -0
  30. package/dist/core/GthAbstractAgent.js.map +1 -1
  31. package/dist/core/GthAgentRunner.d.ts +341 -58
  32. package/dist/core/GthAgentRunner.js +817 -149
  33. package/dist/core/GthAgentRunner.js.map +1 -1
  34. package/dist/core/GthLangChainAgent.d.ts +16 -0
  35. package/dist/core/GthLangChainAgent.js +72 -2
  36. package/dist/core/GthLangChainAgent.js.map +1 -1
  37. package/dist/core/approvals/annotations.d.ts +122 -0
  38. package/dist/core/approvals/annotations.js +137 -0
  39. package/dist/core/approvals/annotations.js.map +1 -0
  40. package/dist/core/approvals/grants.d.ts +216 -0
  41. package/dist/core/approvals/grants.js +469 -0
  42. package/dist/core/approvals/grants.js.map +1 -0
  43. package/dist/core/approvals/matcher.d.ts +202 -0
  44. package/dist/core/approvals/matcher.js +267 -0
  45. package/dist/core/approvals/matcher.js.map +1 -0
  46. package/dist/core/approvals/mcpSubjects.d.ts +40 -0
  47. package/dist/core/approvals/mcpSubjects.js +99 -0
  48. package/dist/core/approvals/mcpSubjects.js.map +1 -0
  49. package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
  50. package/dist/core/approvals/toolAnnotationSources.js +277 -0
  51. package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
  52. package/dist/core/approvals/toolHost.d.ts +46 -0
  53. package/dist/core/approvals/toolHost.js +108 -0
  54. package/dist/core/approvals/toolHost.js.map +1 -0
  55. package/dist/core/launchBanner.d.ts +120 -0
  56. package/dist/core/launchBanner.js +399 -0
  57. package/dist/core/launchBanner.js.map +1 -0
  58. package/dist/core/plainToolIndication.js +13 -7
  59. package/dist/core/plainToolIndication.js.map +1 -1
  60. package/dist/core/shell/approvalStop.d.ts +75 -0
  61. package/dist/core/shell/approvalStop.js +108 -0
  62. package/dist/core/shell/approvalStop.js.map +1 -0
  63. package/dist/core/shell/arity.d.ts +6 -0
  64. package/dist/core/shell/arity.js +20 -6
  65. package/dist/core/shell/arity.js.map +1 -1
  66. package/dist/core/shell/denylist.d.ts +11 -0
  67. package/dist/core/shell/denylist.js +37 -0
  68. package/dist/core/shell/denylist.js.map +1 -0
  69. package/dist/core/shell/normalize.d.ts +41 -1
  70. package/dist/core/shell/normalize.js +58 -4
  71. package/dist/core/shell/normalize.js.map +1 -1
  72. package/dist/core/shell/openWorld.d.ts +138 -0
  73. package/dist/core/shell/openWorld.js +523 -0
  74. package/dist/core/shell/openWorld.js.map +1 -0
  75. package/dist/core/shell/rater.d.ts +560 -0
  76. package/dist/core/shell/rater.js +895 -0
  77. package/dist/core/shell/rater.js.map +1 -0
  78. package/dist/core/shell/raterModel.d.ts +41 -0
  79. package/dist/core/shell/raterModel.js +51 -0
  80. package/dist/core/shell/raterModel.js.map +1 -0
  81. package/dist/core/shell/rejection.d.ts +66 -0
  82. package/dist/core/shell/rejection.js +38 -0
  83. package/dist/core/shell/rejection.js.map +1 -0
  84. package/dist/core/types.d.ts +71 -9
  85. package/dist/core/types.js.map +1 -1
  86. package/dist/runtime/askStructured.d.ts +8 -7
  87. package/dist/runtime/askStructured.js +8 -7
  88. package/dist/runtime/askStructured.js.map +1 -1
  89. package/dist/runtime/conversation.js +89 -76
  90. package/dist/runtime/conversation.js.map +1 -1
  91. package/dist/runtime/singleShot.js +71 -60
  92. package/dist/runtime/singleShot.js.map +1 -1
  93. package/dist/utils/ProgressIndicator.d.ts +21 -0
  94. package/dist/utils/ProgressIndicator.js +30 -3
  95. package/dist/utils/ProgressIndicator.js.map +1 -1
  96. package/dist/utils/consoleUtils.d.ts +30 -0
  97. package/dist/utils/consoleUtils.js +27 -2
  98. package/dist/utils/consoleUtils.js.map +1 -1
  99. package/dist/utils/systemUtils.d.ts +17 -0
  100. package/dist/utils/systemUtils.js +17 -0
  101. package/dist/utils/systemUtils.js.map +1 -1
  102. package/package.json +5 -2
  103. package/schema/gsloth-config.schema.json +1216 -417
  104. package/dist/core/shell/allowlist.d.ts +0 -75
  105. package/dist/core/shell/allowlist.js +0 -187
  106. package/dist/core/shell/allowlist.js.map +0 -1
  107. package/dist/core/shell/judge.d.ts +0 -161
  108. package/dist/core/shell/judge.js +0 -261
  109. package/dist/core/shell/judge.js.map +0 -1
@@ -0,0 +1,216 @@
1
+ import type { ApprovalEntry, McpToolApprovalEntry, ShellApprovalEntry, ToolApprovalEntry, ToolAnnotationHint } from '#src/config/shell-policy.js';
2
+ import type { ShellApprovalGateNotice } from '#src/config/shell-policy.js';
3
+ import { type EffectiveToolAnnotations, type McpToolApprovalSubject, type ToolApprovalSubject } from '#src/core/approvals/matcher.js';
4
+ import { type ToolApprovalScope } from '#src/core/types.js';
5
+ /**
6
+ * The scopes a grant can be REMEMBERED at. `once` is absent by construction: it persists nothing,
7
+ * so it never becomes a grant.
8
+ */
9
+ export type ApprovalGrantScope = Exclude<ToolApprovalScope, 'once'>;
10
+ /**
11
+ * §3 — one thing the human granted: the entry that will be matched, plus what the approvals UI
12
+ * must be able to show about it (*what* was granted, *when*, and *at what scope*).
13
+ *
14
+ * The metadata is display only. The `entry` is the whole of what decides.
15
+ */
16
+ export interface ApprovalGrant {
17
+ /** §3.1 — the entry, in the one grammar. */
18
+ entry: ApprovalEntry;
19
+ /** ISO-8601 instant the grant was made. */
20
+ grantedAt: string;
21
+ /** `session` for the life of this runner instance, `always` for the persisted store. */
22
+ scope: ApprovalGrantScope;
23
+ /**
24
+ * §4.7.4 — **the effective annotation set (§4.7.1) this tool grant was made under**, so a later
25
+ * `tools/list` that weakens it can be seen to have done so ({@link annotationWeakenings}) and the
26
+ * approvals UI can show what the user believed they were granting.
27
+ *
28
+ * Absent on a `shell` grant, which has no annotations, and on a tool grant restored from a file
29
+ * written before this field existed — in both cases there is nothing to compare, so the grant
30
+ * simply stands.
31
+ *
32
+ * **A private copy, always**, made on the way into the store: an effective set is something the
33
+ * source may hand out afresh or a caller may hold, and a snapshot that aliased either would let
34
+ * one grant's record be rewritten by something outside it — which is the same class of bug as a
35
+ * source returning the shared fail-closed constant instead of a copy.
36
+ */
37
+ annotations?: EffectiveToolAnnotations;
38
+ }
39
+ /**
40
+ * §3.1/§6 — the entry the escalation menu writes for a shell command: **that command, and only
41
+ * that command**.
42
+ *
43
+ * The single place a menu grant's entry is built, so the line the prompt shows the human ("this is
44
+ * what will be stored") and the line that lands in the store cannot drift apart.
45
+ */
46
+ export declare function shellGrantEntry(command: string): ShellApprovalEntry;
47
+ /**
48
+ * §4.7.4/§6 — the entry the escalation menu writes for a **tool** call: the tool's identity, plus
49
+ * the host where the call carries one.
50
+ *
51
+ * The counterpart of {@link shellGrantEntry} and the single place a tool grant's entry is built, so
52
+ * the line the prompt shows the human and the line that lands in the store cannot drift apart.
53
+ *
54
+ * **Identity, never arguments.** A grant recording a full argument signature would never match a
55
+ * second time — not a narrower grant, a useless one. That is knowingly broader than the shell's
56
+ * exact-command grant, with one bound: on the shell path §4.6's escape carries the host inside the
57
+ * command string, so it is host-scoped by construction, while a tool-identity-only grant on a fetch
58
+ * tool would be every host, forever.
59
+ *
60
+ * `server` on an `mcpTool` grant is the user's own `mcpServers` config key (§4.7.5). Nothing a
61
+ * server declares about its own name participates, and a grant for one server's tool can never be
62
+ * claimed by another server's same-named tool because the other server sits under a different key.
63
+ *
64
+ * **Returns `null` for a call whose server could not be resolved.** {@link UNRESOLVED_MCP_SERVER}
65
+ * is the empty string, which `server` (`z.string().min(1)`) cannot hold: such an entry would be
66
+ * written to the file and then silently dropped by the grammar's own validator on the next read, so
67
+ * the human would be told their approval was remembered when it was not. A call nobody can attribute
68
+ * to a server is not one anything can remember.
69
+ */
70
+ export declare function toolGrantEntry(subject: ToolApprovalSubject | McpToolApprovalSubject): ToolApprovalEntry | McpToolApprovalEntry | null;
71
+ /**
72
+ * §4.7.4 — which hints moved in the weakening direction between the set a grant was made under and
73
+ * the set that holds now. Empty means the grant still stands.
74
+ *
75
+ * **Only the four booleans are compared, so schema and description changes invalidate nothing** —
76
+ * not by a rule that exempts them, but because a snapshot is four booleans and a description is not
77
+ * one of them. Descriptions churn on every server release, and a grant that dissolved on churn
78
+ * would teach users that grants are worthless.
79
+ *
80
+ * **An untrusted server's declaration change likewise invalidates nothing**, again by construction:
81
+ * §4.7.1 makes an untrusted server's effective set the constant fail-closed default, so both sides
82
+ * of this comparison are that constant however the server re-declares itself. Only a **trusted**
83
+ * server can move an effective value — which is exactly where invalidation matters, since the
84
+ * trusted server is the one whose rug-pull would otherwise ride an existing grant.
85
+ */
86
+ export declare function annotationWeakenings(snapshot: EffectiveToolAnnotations, current: EffectiveToolAnnotations): ToolAnnotationHint[];
87
+ /**
88
+ * §4.7.1/§4.7.4 — **can WITHDRAWING trust in this hint weaken an effective set?**
89
+ *
90
+ * Withdrawing trust pushes a hint back to its MCP fail-closed default, and every weakening move
91
+ * *ends* at that default, so the answer does not depend on what a server declared: it is exactly
92
+ * whether the move (not-the-default → the default) is one of {@link WEAKENING_MOVES}. Three of the
93
+ * four hints answer yes — `readOnlyHint`, `openWorldHint` and `destructiveHint`, whose fail-closed
94
+ * default is `true`, so a server whose `destructiveHint: false` was believed becomes destructive
95
+ * again the moment it is not. `idempotentHint` is the only one that answers no, because no
96
+ * weakening move names it.
97
+ *
98
+ * **It asks {@link annotationWeakenings} rather than restating the table.** A second statement of
99
+ * which moves weaken is how a warning comes to describe a rule the gate no longer has — which
100
+ * matters most here, since this decides whether the human is told their saved approvals are about
101
+ * to be withdrawn.
102
+ */
103
+ export declare function trustWithdrawalWeakens(hint: ToolAnnotationHint): boolean;
104
+ /**
105
+ * §4.7.4 — the notice a weakened grant is removed with. **It names the tool, the server and the
106
+ * hint that moved**, because the human approved a tool *as annotated*: a tool that re-annotates
107
+ * itself into a more dangerous shape is a different proposition wearing the same name, and a notice
108
+ * that did not say which name changed would be indistinguishable from the gate malfunctioning.
109
+ *
110
+ * It takes the **entry** rather than the call's subject, so it describes the grant that was actually
111
+ * withdrawn — including its host bound, where it had one. One call may withdraw both a host-bound
112
+ * grant and a tool-only one, and two notices that could not be told apart would be worse than one.
113
+ * The entry is rendered by {@link describeApprovalEntry}, the same one-liner every other provenance
114
+ * message uses.
115
+ */
116
+ export declare function describeWeakenedGrant(entry: ApprovalEntry, weakened: readonly ToolAnnotationHint[], snapshot: EffectiveToolAnnotations, current: EffectiveToolAnnotations): string;
117
+ /**
118
+ * A set of grants with entry-identity semantics. Pure data + membership: it holds what the human
119
+ * granted and answers *is this the same grant*, never *does this grant cover that command*.
120
+ */
121
+ export declare class ApprovalGrantStore {
122
+ private readonly grants;
123
+ constructor(initial?: readonly ApprovalGrant[]);
124
+ /**
125
+ * Add a grant. Returns whether it was new — an identical entry is not stored twice.
126
+ *
127
+ * The {@link ApprovalGrant.annotations} snapshot is **copied on the way in**, so what the store
128
+ * holds is private to this grant whatever the caller passed: the effective set may be a live
129
+ * object the caller keeps, or (were a source ever to regress) the shared fail-closed constant, and
130
+ * a store aliasing either would let one grant's record be rewritten from outside it. Copying here
131
+ * rather than at each call site makes that structural instead of a habit every caller must keep.
132
+ */
133
+ add(grant: ApprovalGrant): boolean;
134
+ /**
135
+ * The grant stored under this entry's identity, or `undefined`.
136
+ *
137
+ * **Identity, never a match decision** — the same de-duplication question {@link add} asks. It
138
+ * answers *"is this the same grant"*, and whether a grant covers a call remains
139
+ * `resolveApprovalRules`'s alone.
140
+ */
141
+ find(entry: ApprovalEntry): ApprovalGrant | undefined;
142
+ /**
143
+ * Drop the grant stored under this entry's identity. Returns whether one was there.
144
+ *
145
+ * §4.7.4's invalidation is a **removal** rather than a skip, and that is load-bearing: {@link add}
146
+ * de-duplicates by entry identity, so a grant left in place while being ignored would silently
147
+ * swallow the human's re-approval of the same tool — the grant would appear to be re-made and the
148
+ * stale snapshot would keep invalidating it.
149
+ */
150
+ remove(entry: ApprovalEntry): boolean;
151
+ /** Every grant, in the order they were made. */
152
+ list(): ApprovalGrant[];
153
+ /** Just the entries, for handing to the matcher as one of its rule lists. */
154
+ entries(): ApprovalEntry[];
155
+ /** How many grants are held. */
156
+ size(): number;
157
+ }
158
+ /** Optional seams for {@link PersistedApprovalGrants}. */
159
+ export interface PersistedApprovalGrantsOptions {
160
+ /**
161
+ * Where the v1→v2 migration notice goes — the established {@link ShellApprovalGateNotice} shape
162
+ * the runner forwards to `statusUpdate`. Absent means the migration happens silently, which is
163
+ * why the runner always passes one.
164
+ */
165
+ onNotice?: (notice: ShellApprovalGateNotice) => void;
166
+ }
167
+ /**
168
+ * The persisted (`always`) grant store, backed by a JSON file whose path is injected (the runner
169
+ * resolves it via fileUtils → `.gsloth/.gsloth-settings/shell-allowlist.json`) so tests can point it
170
+ * at a temp dir.
171
+ *
172
+ * ## The v1 migration, and the direction it goes
173
+ *
174
+ * The shipped v1 file held `prefixes: string[]` — classified command PREFIXES, so a stored
175
+ * `npm test` also auto-approved `npm test --watch`. Each prefix migrates to an **`exact` entry for
176
+ * the same string**, with **one** notice naming the file.
177
+ *
178
+ * That narrows what the file grants, on purpose: a v1 prefix was broader than what the human was
179
+ * actually shown when they answered the prompt, so narrowing it costs at worst a re-prompt and
180
+ * never an execution — the direction every ambiguity in this design resolves. The migrated file is
181
+ * rewritten as v2 immediately, so the notice is a one-time event rather than a per-session one; a
182
+ * write that fails (read-only checkout) is not fatal — the grants are in force for this session and
183
+ * the notice simply appears again next time.
184
+ */
185
+ export declare class PersistedApprovalGrants {
186
+ private readonly store;
187
+ private readonly filePath;
188
+ constructor(filePath: string, options?: PersistedApprovalGrantsOptions);
189
+ private static load;
190
+ /** Each v1 prefix → an `exact` entry for the same string, with ONE notice naming the file. */
191
+ private static migrateFromV1;
192
+ /** Every grant. */
193
+ list(): ApprovalGrant[];
194
+ /** Just the entries, for handing to the matcher as one of its rule lists. */
195
+ entries(): ApprovalEntry[];
196
+ /** How many grants are persisted. */
197
+ size(): number;
198
+ /** Add a grant and persist the whole store. A duplicate entry rewrites nothing. */
199
+ add(grant: ApprovalGrant): void;
200
+ /** The grant held under this entry's identity, or `undefined`. */
201
+ find(entry: ApprovalEntry): ApprovalGrant | undefined;
202
+ /**
203
+ * Drop the grant held under this entry's identity and rewrite the file. Returns whether one was
204
+ * there.
205
+ *
206
+ * The write is what makes §4.7.4's invalidation a one-time event: a removal held only in memory
207
+ * would be undone by the next session reloading the same stale snapshot, so the user would be
208
+ * told their grant had been withdrawn once per session, forever.
209
+ */
210
+ remove(entry: ApprovalEntry): boolean;
211
+ /**
212
+ * Write the file. Never throws: the grants are already in force for this session, and a
213
+ * read-only checkout must not end a run over a bookkeeping write.
214
+ */
215
+ private tryPersist;
216
+ }