@stratusagent/permissions 0.3.0 → 0.6.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.
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The command-scope engine: which *invocations* of a shell tool may run
3
+ * unattended.
4
+ *
5
+ * `ToolRisk` classifies a tool. That is too coarse for a shell, whose calls
6
+ * range from `git status` to `curl … | sh`, so this narrows a `gated` tool
7
+ * one call at a time — a base command plus the argument shapes that keep it
8
+ * read-only, never a bare executable and never a whole command string.
9
+ *
10
+ * Parsing is deliberately dumb, and that is the design rather than a
11
+ * shortcut: tokenize, take the base command, scan for control operators.
12
+ * Anything ambiguous is "not safe", so the failure mode of a parser that
13
+ * disagrees with `sh` is a prompt somebody has to answer, not a command
14
+ * nobody vetted.
15
+ */
16
+ /** One narrow permission to run a command: what, and in which forms. */
17
+ export interface CommandScope {
18
+ /** The base command, matched exactly — never a path (`/bin/git` is not `git`). */
19
+ command: string;
20
+ /** Literal arguments that must follow it, in order (`['push']`). */
21
+ args?: string[];
22
+ /**
23
+ * Long flags (`--force`) and short letters (`f`) that disqualify a match.
24
+ * Short letters are checked inside bundles, so `-fdx` trips on `f`.
25
+ */
26
+ deniedFlags?: string[];
27
+ /** Literal arguments that disqualify a match anywhere after `args`. */
28
+ deniedArgs?: string[];
29
+ /**
30
+ * Refuse *any* argument that is not a flag.
31
+ *
32
+ * The listing forms of `git branch` and `git tag` are the safe ones, and
33
+ * what separates them from the creating forms is a positional: `git
34
+ * branch` lists, `git branch release` creates. Excluding flags is not
35
+ * enough there, because creation needs none.
36
+ */
37
+ listOnly?: boolean;
38
+ /**
39
+ * The only flags this scope permits. Present, it replaces "anything not
40
+ * denied" with "nothing but these" — which is the direction to fail in
41
+ * for a command whose flags can mutate: `git branch --unset-upstream`
42
+ * changes repository config, takes no positional, and is not a delete or
43
+ * a force, so a deny list has to have thought of it and an allow list
44
+ * does not.
45
+ *
46
+ * Long flags match by name, so `--sort=-committerdate` is `--sort`.
47
+ * Short flags match per letter inside a bundle, and digits are ignored
48
+ * because they are arguments rather than flags (`git tag -n5`).
49
+ */
50
+ allowedFlags?: string[];
51
+ /**
52
+ * Refuse `:branch` and `+branch` arguments. Git's refspec syntax makes
53
+ * those a delete and a forced update *without any flag*, so a scope that
54
+ * only excluded flags would let `git push origin :main` through as an
55
+ * ordinary push.
56
+ */
57
+ denyRefspecForms?: boolean;
58
+ }
59
+ /**
60
+ * The commands that run unattended out of the box.
61
+ *
62
+ * Short on purpose. Every entry is a promise that no argument shape reaches
63
+ * outside the repository it is run in, and the tempting additions —
64
+ * `cat`, `ls`, `grep` — cannot make it: they read whatever path they are
65
+ * given, and `cat ~/.stratus/credentials.json` is a safe-listed credential
66
+ * read. An operator who wants those adds them deliberately, or approves
67
+ * them once and keeps the scope.
68
+ *
69
+ * The test is *what an argument can make the command do*, not what the
70
+ * command is called. `date` was on this list until someone pointed out
71
+ * `date --file=~/.stratus/credentials.json`, which is not a date lookup:
72
+ * GNU `date` reads that file and echoes each unparseable line back in its
73
+ * error text, which the shell tool returns. A command that can be handed a
74
+ * path is a file reader wearing another name.
75
+ */
76
+ export declare const SAFE_COMMAND_SCOPES: CommandScope[];
77
+ export interface CommandAnalysis {
78
+ /** The command as written, for messages and prompts. */
79
+ command: string;
80
+ /** The base command, absent when the string could not be tokenized. */
81
+ base?: string;
82
+ tokens: string[];
83
+ /**
84
+ * Why this invocation cannot be auto-approved at all — a control
85
+ * operator, an unbalanced quote, an absolute path. Undefined means it is
86
+ * a candidate for scope matching, not that it is allowed.
87
+ */
88
+ disqualifiedBy?: string;
89
+ }
90
+ /** Read a command string as far as it can be read safely. */
91
+ export declare const analyzeCommand: (command: string) => CommandAnalysis;
92
+ /** Whether an invocation falls inside one scope. */
93
+ export declare const matchesScope: (analysis: CommandAnalysis, scope: CommandScope) => boolean;
94
+ /** The first scope covering this invocation, if any covers it. */
95
+ export declare const findMatchingScope: (analysis: CommandAnalysis, scopes: readonly CommandScope[]) => CommandScope | undefined;
96
+ /**
97
+ * The scope an "always allow" persists.
98
+ *
99
+ * Base command plus its first literal argument — `git push`, not
100
+ * `git push origin main` (too narrow to be worth storing) and not `git`
101
+ * (too broad to be safe) — carrying the destructive-form constraints that
102
+ * make the distinction real, and inheriting anything the safe list already
103
+ * excludes for the same command so a persisted scope can never erase a
104
+ * flag distinction the built-in list draws.
105
+ */
106
+ export declare const normalizeCommandScope: (analysis: CommandAnalysis) => CommandScope | undefined;
107
+ /** One line an operator can read in a log or a whitelist listing. */
108
+ export declare const describeCommandScope: (scope: CommandScope) => string;
109
+ /** Whether two scopes permit the same thing, so a whitelist does not grow duplicates. */
110
+ export declare const sameScope: (left: CommandScope, right: CommandScope) => boolean;
111
+ /** Read one scope out of a whitelist file, or refuse it. */
112
+ export declare const parseCommandScope: (raw: unknown) => CommandScope | undefined;
113
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA+CD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,EAAE,YAAY,EAoD7C,CAAC;AAqBF,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA4CD,6DAA6D;AAC7D,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,eA0BhD,CAAC;AAgCF,oDAAoD;AACpD,eAAO,MAAM,YAAY,GAAI,UAAU,eAAe,EAAE,OAAO,YAAY,KAAG,OA0C7E,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,GAC5B,UAAU,eAAe,EACzB,QAAQ,SAAS,YAAY,EAAE,KAC9B,YAAY,GAAG,SAAkE,CAAC;AAErF;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,eAAe,KAAG,YAAY,GAAG,SAgChF,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,oBAAoB,GAAI,OAAO,YAAY,KAAG,MACT,CAAC;AAEnD,yFAAyF;AACzF,eAAO,MAAM,SAAS,GAAI,MAAM,YAAY,EAAE,OAAO,YAAY,KAAG,OACsB,CAAC;AAY3F,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,GAAI,KAAK,OAAO,KAAG,YAAY,GAAG,SAwB/D,CAAC"}
@@ -0,0 +1,363 @@
1
+ /**
2
+ * The command-scope engine: which *invocations* of a shell tool may run
3
+ * unattended.
4
+ *
5
+ * `ToolRisk` classifies a tool. That is too coarse for a shell, whose calls
6
+ * range from `git status` to `curl … | sh`, so this narrows a `gated` tool
7
+ * one call at a time — a base command plus the argument shapes that keep it
8
+ * read-only, never a bare executable and never a whole command string.
9
+ *
10
+ * Parsing is deliberately dumb, and that is the design rather than a
11
+ * shortcut: tokenize, take the base command, scan for control operators.
12
+ * Anything ambiguous is "not safe", so the failure mode of a parser that
13
+ * disagrees with `sh` is a prompt somebody has to answer, not a command
14
+ * nobody vetted.
15
+ */
16
+ /**
17
+ * Flags that turn something else into a program, a network peer, or a file
18
+ * write — and are therefore refused in every scope, safe-listed or
19
+ * persisted. `git -c core.pager=…` and `git diff --no-index /etc/passwd`
20
+ * are the reason: both are read-only commands by name.
21
+ */
22
+ const ALWAYS_DENIED_FLAGS = [
23
+ '-c',
24
+ '--config',
25
+ '--config-env',
26
+ '--exec',
27
+ '--exec-path',
28
+ '--upload-pack',
29
+ '--receive-pack',
30
+ '--ext-diff',
31
+ '--no-index',
32
+ '--output',
33
+ '--open-files-in-pager',
34
+ // Reads a path the scope never mentioned. `date --file=…/credentials.json`
35
+ // is not a date lookup; it is a file read whose contents come back in the
36
+ // error text, from a command whose name says otherwise.
37
+ '--file',
38
+ ];
39
+ /**
40
+ * What a persisted scope excludes, whatever it was approved for. Approving
41
+ * `git push origin main` must not persist a permission that covers
42
+ * `git push --force` — the point of storing a scope rather than a command
43
+ * string is to be useful next time, and the point of storing a scope rather
44
+ * than the bare executable is that it still says no to this.
45
+ */
46
+ const DESTRUCTIVE_FLAGS = [
47
+ '--force',
48
+ '--force-with-lease',
49
+ '--force-if-includes',
50
+ '--delete',
51
+ '--prune',
52
+ '--mirror',
53
+ '--hard',
54
+ '--no-verify',
55
+ 'f',
56
+ 'd',
57
+ 'D',
58
+ ];
59
+ /**
60
+ * The commands that run unattended out of the box.
61
+ *
62
+ * Short on purpose. Every entry is a promise that no argument shape reaches
63
+ * outside the repository it is run in, and the tempting additions —
64
+ * `cat`, `ls`, `grep` — cannot make it: they read whatever path they are
65
+ * given, and `cat ~/.stratus/credentials.json` is a safe-listed credential
66
+ * read. An operator who wants those adds them deliberately, or approves
67
+ * them once and keeps the scope.
68
+ *
69
+ * The test is *what an argument can make the command do*, not what the
70
+ * command is called. `date` was on this list until someone pointed out
71
+ * `date --file=~/.stratus/credentials.json`, which is not a date lookup:
72
+ * GNU `date` reads that file and echoes each unparseable line back in its
73
+ * error text, which the shell tool returns. A command that can be handed a
74
+ * path is a file reader wearing another name.
75
+ */
76
+ export const SAFE_COMMAND_SCOPES = [
77
+ { command: 'git', args: ['status'] },
78
+ { command: 'git', args: ['log'] },
79
+ { command: 'git', args: ['diff'] },
80
+ { command: 'git', args: ['show'] },
81
+ { command: 'git', args: ['blame'] },
82
+ { command: 'git', args: ['describe'] },
83
+ { command: 'git', args: ['rev-parse'] },
84
+ { command: 'git', args: ['ls-files'] },
85
+ { command: 'git', args: ['shortlog'] },
86
+ // Listing branches, tags, and remotes is read-only. Creating one needs no
87
+ // flag at all — `git branch release` is a mutation and `git branch` is
88
+ // not — so these are list-only, and every other form asks.
89
+ {
90
+ command: 'git',
91
+ args: ['branch'],
92
+ listOnly: true,
93
+ // Named rather than excluded: `git branch` has flag-only mutations
94
+ // (`--unset-upstream`, `-u origin/main`) that no list of destructive
95
+ // *shapes* would have caught, so this scope covers the listing flags
96
+ // and nothing else.
97
+ allowedFlags: [
98
+ '--list', '--all', '--remotes', '--show-current', '--verbose', '--no-verbose',
99
+ '--color', '--no-color', '--column', '--no-column', '--sort', '--format',
100
+ '--contains', '--no-contains', '--merged', '--no-merged', '--points-at',
101
+ '--ignore-case', '--omit-empty', '--abbrev', '--no-abbrev',
102
+ 'l', 'a', 'r', 'v', 'i', 'q',
103
+ ],
104
+ deniedFlags: ['--delete', '--move', '--copy', '--force', 'd', 'D', 'm', 'M', 'C', 'u'],
105
+ },
106
+ {
107
+ command: 'git',
108
+ args: ['tag'],
109
+ listOnly: true,
110
+ allowedFlags: [
111
+ '--list', '--contains', '--no-contains', '--merged', '--no-merged', '--points-at',
112
+ '--sort', '--format', '--color', '--no-color', '--column', '--no-column',
113
+ '--ignore-case', '--omit-empty',
114
+ 'l', 'n', 'i',
115
+ ],
116
+ deniedFlags: ['--delete', '--force', 'd', 'f'],
117
+ },
118
+ {
119
+ command: 'git',
120
+ args: ['remote'],
121
+ listOnly: true,
122
+ allowedFlags: ['--verbose', 'v'],
123
+ deniedArgs: ['add', 'remove', 'rm', 'rename', 'set-url', 'set-head', 'set-branches', 'prune', 'update'],
124
+ },
125
+ { command: 'pwd' },
126
+ { command: 'whoami' },
127
+ { command: 'uname' },
128
+ ];
129
+ /**
130
+ * Every shell control operator, as a rejection set rather than a blacklist
131
+ * of the memorable ones. A single `&` backgrounds a command as surely as
132
+ * `&&` chains one, and a newline runs the next line whatever came before
133
+ * it — an enumerated list is exactly how `git status\ncurl evil.sh` gets
134
+ * auto-approved.
135
+ */
136
+ const CONTROL_OPERATORS = [
137
+ { pattern: /\$\(/, name: 'command substitution ($( ))' },
138
+ { pattern: /`/, name: 'command substitution (backticks)' },
139
+ { pattern: /\|/, name: 'a pipe (|)' },
140
+ { pattern: /&/, name: 'an ampersand (& or &&)' },
141
+ { pattern: /;/, name: 'a semicolon (;)' },
142
+ { pattern: /[\r\n]/, name: 'a newline' },
143
+ { pattern: /[()]/, name: 'a subshell (parentheses)' },
144
+ { pattern: /[<>]/, name: 'a redirection (< or >)' },
145
+ { pattern: /\$\{/, name: 'a parameter expansion (${ })' },
146
+ ];
147
+ const tokenize = (command) => {
148
+ const tokens = [];
149
+ let current = '';
150
+ let quote;
151
+ let started = false;
152
+ for (const char of command) {
153
+ if (quote) {
154
+ if (char === quote) {
155
+ quote = undefined;
156
+ }
157
+ else {
158
+ current += char;
159
+ }
160
+ continue;
161
+ }
162
+ if (char === '"' || char === "'") {
163
+ quote = char;
164
+ started = true;
165
+ continue;
166
+ }
167
+ if (char === ' ' || char === '\t') {
168
+ if (started) {
169
+ tokens.push(current);
170
+ current = '';
171
+ started = false;
172
+ }
173
+ continue;
174
+ }
175
+ current += char;
176
+ started = true;
177
+ }
178
+ if (quote) {
179
+ // An unbalanced quote means this parser and the shell disagree about
180
+ // where the command ends. There is no safe reading of that.
181
+ return undefined;
182
+ }
183
+ if (started) {
184
+ tokens.push(current);
185
+ }
186
+ return tokens;
187
+ };
188
+ /** Read a command string as far as it can be read safely. */
189
+ export const analyzeCommand = (command) => {
190
+ for (const operator of CONTROL_OPERATORS) {
191
+ if (operator.pattern.test(command)) {
192
+ return { command, tokens: [], disqualifiedBy: `it contains ${operator.name}` };
193
+ }
194
+ }
195
+ const tokens = tokenize(command);
196
+ if (!tokens || tokens.length === 0) {
197
+ return { command, tokens: [], disqualifiedBy: 'it could not be read as a command' };
198
+ }
199
+ const base = tokens[0];
200
+ if (base.includes('/') || base.includes('\\')) {
201
+ // A scope names a command, and `/usr/bin/git` is not that name. Refusing
202
+ // beats resolving: `./git` in a cloned repository is a different program
203
+ // with the same basename.
204
+ return { command, tokens, disqualifiedBy: 'it names a path rather than a command' };
205
+ }
206
+ if (base.startsWith('-') || base.includes('=')) {
207
+ // `FOO=bar cmd` is an environment assignment, which is the shell's job
208
+ // and not this parser's.
209
+ return { command, tokens, disqualifiedBy: 'it does not start with a command' };
210
+ }
211
+ return { command, base, tokens };
212
+ };
213
+ const flagsOf = (token) => {
214
+ if (token.startsWith('--')) {
215
+ const [name] = token.split('=');
216
+ return { long: name ?? token, shorts: [] };
217
+ }
218
+ if (token.startsWith('-') && token.length > 1) {
219
+ const [bundle] = token.slice(1).split('=');
220
+ return { shorts: [...(bundle ?? '')] };
221
+ }
222
+ return { shorts: [] };
223
+ };
224
+ const deniesFlag = (denied, token) => {
225
+ const { long, shorts } = flagsOf(token);
226
+ if (long && denied.includes(long)) {
227
+ return true;
228
+ }
229
+ return shorts.some((letter) => denied.includes(letter));
230
+ };
231
+ /** Whether every part of a flag token is on an allowlist. */
232
+ const allowsFlag = (allowed, token) => {
233
+ const { long, shorts } = flagsOf(token);
234
+ if (long) {
235
+ return allowed.includes(long);
236
+ }
237
+ const letters = shorts.filter((letter) => !/[0-9]/.test(letter));
238
+ return letters.length > 0 && letters.every((letter) => allowed.includes(letter));
239
+ };
240
+ /** Whether an invocation falls inside one scope. */
241
+ export const matchesScope = (analysis, scope) => {
242
+ if (analysis.disqualifiedBy || analysis.base === undefined) {
243
+ return false;
244
+ }
245
+ if (analysis.base !== scope.command) {
246
+ return false;
247
+ }
248
+ const args = analysis.tokens.slice(1);
249
+ const required = scope.args ?? [];
250
+ if (args.length < required.length) {
251
+ return false;
252
+ }
253
+ for (const [index, expected] of required.entries()) {
254
+ if (args[index] !== expected) {
255
+ return false;
256
+ }
257
+ }
258
+ const denied = [...ALWAYS_DENIED_FLAGS, ...(scope.deniedFlags ?? [])];
259
+ const rest = args.slice(required.length);
260
+ for (const token of rest) {
261
+ if (token.startsWith('-')) {
262
+ if (deniesFlag(denied, token)) {
263
+ return false;
264
+ }
265
+ if (scope.allowedFlags && !allowsFlag(scope.allowedFlags, token)) {
266
+ return false;
267
+ }
268
+ continue;
269
+ }
270
+ if (scope.listOnly) {
271
+ return false;
272
+ }
273
+ if (scope.deniedArgs?.includes(token)) {
274
+ return false;
275
+ }
276
+ if (scope.denyRefspecForms && (token.startsWith(':') || token.startsWith('+'))) {
277
+ return false;
278
+ }
279
+ }
280
+ return true;
281
+ };
282
+ /** The first scope covering this invocation, if any covers it. */
283
+ export const findMatchingScope = (analysis, scopes) => scopes.find((scope) => matchesScope(analysis, scope));
284
+ /**
285
+ * The scope an "always allow" persists.
286
+ *
287
+ * Base command plus its first literal argument — `git push`, not
288
+ * `git push origin main` (too narrow to be worth storing) and not `git`
289
+ * (too broad to be safe) — carrying the destructive-form constraints that
290
+ * make the distinction real, and inheriting anything the safe list already
291
+ * excludes for the same command so a persisted scope can never erase a
292
+ * flag distinction the built-in list draws.
293
+ */
294
+ export const normalizeCommandScope = (analysis) => {
295
+ if (analysis.disqualifiedBy || analysis.base === undefined) {
296
+ return undefined;
297
+ }
298
+ const first = analysis.tokens.slice(1).find((token) => !token.startsWith('-'));
299
+ const args = first === undefined ? [] : [first];
300
+ const sameScope = SAFE_COMMAND_SCOPES
301
+ .filter((scope) => scope.command === analysis.base && (scope.args ?? []).join(' ') === args.join(' '));
302
+ const inherited = sameScope.flatMap((scope) => scope.deniedFlags ?? []);
303
+ const deniedArgs = sameScope.flatMap((scope) => scope.deniedArgs ?? []);
304
+ // Only when every safe scope for this command names one: a persisted
305
+ // scope must be no wider than the built-in, and an allowlist from one of
306
+ // two scopes would narrow the other by accident.
307
+ const allowedFlags = sameScope.length > 0 && sameScope.every((scope) => scope.allowedFlags)
308
+ ? [...new Set(sameScope.flatMap((scope) => scope.allowedFlags ?? []))]
309
+ : undefined;
310
+ return {
311
+ command: analysis.base,
312
+ ...(args.length > 0 ? { args } : {}),
313
+ deniedFlags: [...new Set([...DESTRUCTIVE_FLAGS, ...inherited])],
314
+ ...(deniedArgs.length > 0 ? { deniedArgs: [...new Set(deniedArgs)] } : {}),
315
+ // A persisted scope cannot be wider than the safe list's own for the
316
+ // same command: approving `git branch` once must not turn creating a
317
+ // branch into something that runs unattended forever after.
318
+ ...(sameScope.some((scope) => scope.listOnly) ? { listOnly: true } : {}),
319
+ ...(allowedFlags ? { allowedFlags } : {}),
320
+ // Git's syntax, so git's rule: elsewhere a leading `+` is an ordinary
321
+ // argument (`chmod +x`) and refusing it would only cost a prompt for no
322
+ // safety.
323
+ ...(analysis.base === 'git' ? { denyRefspecForms: true } : {}),
324
+ };
325
+ };
326
+ /** One line an operator can read in a log or a whitelist listing. */
327
+ export const describeCommandScope = (scope) => [scope.command, ...(scope.args ?? [])].join(' ');
328
+ /** Whether two scopes permit the same thing, so a whitelist does not grow duplicates. */
329
+ export const sameScope = (left, right) => JSON.stringify(normalizeForCompare(left)) === JSON.stringify(normalizeForCompare(right));
330
+ const normalizeForCompare = (scope) => ({
331
+ command: scope.command,
332
+ args: scope.args ?? [],
333
+ deniedFlags: [...(scope.deniedFlags ?? [])].sort(),
334
+ deniedArgs: [...(scope.deniedArgs ?? [])].sort(),
335
+ denyRefspecForms: scope.denyRefspecForms ?? false,
336
+ listOnly: scope.listOnly ?? false,
337
+ allowedFlags: [...(scope.allowedFlags ?? [])].sort(),
338
+ });
339
+ /** Read one scope out of a whitelist file, or refuse it. */
340
+ export const parseCommandScope = (raw) => {
341
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
342
+ return undefined;
343
+ }
344
+ const source = raw;
345
+ if (typeof source.command !== 'string' || source.command.length === 0) {
346
+ return undefined;
347
+ }
348
+ const strings = (value) => Array.isArray(value) && value.every((entry) => typeof entry === 'string') ? value : undefined;
349
+ const args = strings(source.args);
350
+ const deniedFlags = strings(source.deniedFlags);
351
+ const deniedArgs = strings(source.deniedArgs);
352
+ const allowedFlags = strings(source.allowedFlags);
353
+ return {
354
+ command: source.command,
355
+ ...(args ? { args } : {}),
356
+ ...(deniedFlags ? { deniedFlags } : {}),
357
+ ...(deniedArgs ? { deniedArgs } : {}),
358
+ ...(source.denyRefspecForms === true ? { denyRefspecForms: true } : {}),
359
+ ...(source.listOnly === true ? { listOnly: true } : {}),
360
+ ...(allowedFlags ? { allowedFlags } : {}),
361
+ };
362
+ };
363
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,14 @@
1
- import type { ApprovalPolicy, ToolRisk } from '@stratusagent/core';
1
+ import type { ApprovalAnswer, ApprovalPolicy, Session, Tool, ToolCall, ToolRisk } from '@stratusagent/core';
2
+ /**
3
+ * Re-exported, not re-implemented: the risk ordering moved to the kernel
4
+ * when the plugin loader became its second consumer, and this package
5
+ * published the name first.
6
+ */
7
+ export { atLeastAsRisky } from '@stratusagent/core';
8
+ import { type CommandScope } from './commands.ts';
9
+ import type { CommandWhitelistStore } from './whitelist.ts';
10
+ export { analyzeCommand, describeCommandScope, findMatchingScope, matchesScope, normalizeCommandScope, parseCommandScope, sameScope, SAFE_COMMAND_SCOPES, type CommandAnalysis, type CommandScope, } from './commands.ts';
11
+ export { createFileCommandWhitelist, whitelistPathFor, type CommandWhitelistStore, } from './whitelist.ts';
2
12
  /**
3
13
  * How a policy reaches a human — or admits that it cannot.
4
14
  *
@@ -7,12 +17,48 @@ import type { ApprovalPolicy, ToolRisk } from '@stratusagent/core';
7
17
  * - `headless` — nobody is reachable. Safe calls run, everything else is
8
18
  * refused and the refusal is reported, because a daemon that silently
9
19
  * drops half a turn is worse than one that says what it would not do.
20
+ * - `remote` — nobody is at a terminal, but somebody is reachable through
21
+ * a channel. The turn parks on a request published elsewhere and resumes
22
+ * on the answer.
10
23
  *
11
- * `remote` (park the turn, ask through a channel, resume on the answer)
12
- * is the next step and is deliberately absent here rather than stubbed:
13
- * a mode that exists but never resolves would look supported.
24
+ * `remote` needs a `request` transport for the same reason `interactive`
25
+ * needs `ask`: this package decides *whether* a human is required and what
26
+ * their answer means, and never how to reach one. Delivery is the
27
+ * gateway's (a bus event) and the channel's (Slack buttons).
28
+ */
29
+ export type PermissionMode = 'interactive' | 'headless' | 'remote';
30
+ /**
31
+ * One gated call, handed to whatever can reach a person. Deliberately the
32
+ * same shape the kernel hands the policy — a transport that had to
33
+ * reconstruct the call from a name would be guessing at exactly the
34
+ * details an approver is being asked about.
35
+ */
36
+ export interface ApprovalRequest {
37
+ session: Session;
38
+ call: ToolCall;
39
+ tool: Tool;
40
+ risk: ToolRisk;
41
+ /**
42
+ * When this call first parked, if it is being re-asked after a restart.
43
+ * A transport that imposes a deadline measures from here rather than
44
+ * granting a fresh window.
45
+ */
46
+ parkedAt?: string;
47
+ /**
48
+ * The turn's abort signal. A transport MUST invalidate its outstanding
49
+ * request when this fires: the answer would otherwise arrive for a turn
50
+ * that no longer exists, and acting on it would run a tool for cancelled
51
+ * work.
52
+ */
53
+ signal?: AbortSignal;
54
+ }
55
+ /**
56
+ * Publishes a request and settles when a human answers it — or when
57
+ * whatever is carrying it gives up. It never rejects for a timeout: an
58
+ * expired request is a `deny`, which is a decision the turn can continue
59
+ * from, not an error that fails it.
14
60
  */
15
- export type PermissionMode = 'interactive' | 'headless';
61
+ export type ApprovalRequester = (request: ApprovalRequest) => Promise<ApprovalAnswer>;
16
62
  /** Why a call was allowed or refused, for logs and events. */
17
63
  export interface PermissionDecision {
18
64
  allowed: boolean;
@@ -21,8 +67,26 @@ export interface PermissionDecision {
21
67
  toolName: string;
22
68
  sessionId: string;
23
69
  agentId: string;
24
- /** One line, written for a person reading a daemon log at 3am. */
70
+ /**
71
+ * One line, written for a person reading a daemon log at 3am — and
72
+ * deliberately free of the tool's input.
73
+ *
74
+ * The daemon log is a trace, not a second transcript: it records that a
75
+ * tool ran, never what it was called with. A refusal that quoted the
76
+ * command would put an agent-composed string — a URL, a token somebody
77
+ * pasted into a prompt — into a file this project documents as safe to
78
+ * read and to share. What the reason names instead is the *scope*: the
79
+ * base command and its subcommand, which is the actionable half and is a
80
+ * classification rather than the arguments.
81
+ */
25
82
  reason: string;
83
+ /**
84
+ * The command this decision was about, for a surface that is showing a
85
+ * person the thing they are approving — a Slack prompt, a live console.
86
+ * Carried separately precisely so it is not in `reason`, and a consumer
87
+ * that logs it is making that choice knowingly.
88
+ */
89
+ command?: string;
26
90
  }
27
91
  export interface PermissionPolicyOptions {
28
92
  mode: PermissionMode;
@@ -31,24 +95,51 @@ export interface PermissionPolicyOptions {
31
95
  * leniently, since it comes from someone typing at a prompt.
32
96
  */
33
97
  ask?: (question: string) => Promise<string>;
98
+ /** Reaches the human through a channel. Required for `remote`. */
99
+ request?: ApprovalRequester;
34
100
  /**
35
101
  * Called for every decision, allowed or not. The daemon routes this to
36
102
  * its log: an unattended refusal that appears nowhere is indistinguishable
37
103
  * from an agent that chose not to act.
38
104
  */
39
105
  onDecision?: (decision: PermissionDecision) => void;
106
+ /**
107
+ * The command-scope engine, for tools that carry a command string
108
+ * (`Tool.commandFor`). Omitted, every gated call needs a human however
109
+ * innocuous its arguments — which is the honest behaviour for a daemon
110
+ * with no scope list, and an unusable one for a shell.
111
+ */
112
+ commands?: CommandScopeOptions;
113
+ }
114
+ export interface CommandScopeOptions {
115
+ /**
116
+ * Scopes that run unattended. Defaults to `SAFE_COMMAND_SCOPES`; pass a
117
+ * list to replace it, or spread it to extend.
118
+ */
119
+ safeScopes?: readonly CommandScope[];
120
+ /** Where "always allow" persists a scope, and where one is read back. */
121
+ whitelist?: CommandWhitelistStore;
122
+ /**
123
+ * Called when a scope is persisted. The daemon logs it: an approval that
124
+ * widens what runs unattended, for every future session, is exactly the
125
+ * decision that must not be the one leaving no trace.
126
+ */
127
+ onScopeRemembered?: (event: {
128
+ agentId: string;
129
+ scope: CommandScope;
130
+ }) => void;
40
131
  }
41
- /** Whether `risk` is at least as risky as `floor`. */
42
- export declare const atLeastAsRisky: (risk: ToolRisk, floor: ToolRisk) => boolean;
43
132
  /**
44
- * The kernel's ApprovalPolicy, deciding by the tool's declared risk rather
45
- * than by its name. `safe` runs unattended; anything else needs a human,
46
- * and whether one exists is what `mode` answers.
133
+ * The kernel's ApprovalPolicy, deciding by the tool's declared risk and —
134
+ * for a tool that carries one — by the command an invocation would run.
135
+ * `safe` runs unattended; anything else needs a human unless a scope covers
136
+ * it, and whether a human exists at all is what `mode` answers.
47
137
  *
48
- * This is deliberately coarse. Fine-grained judgment — which *arguments* to
49
- * a shell tool are safe, which flags turn a read into a write — belongs with
50
- * the shell tool itself, which does not exist yet; writing that machinery
51
- * now would mean guessing at the shape of a caller nobody has built.
138
+ * The three tiers resolve in order: scopes granted "always" in this session,
139
+ * then the agent's persistent whitelist, then the built-in safe list —
140
+ * after which there is nothing left but asking. A `dangerous` tool skips
141
+ * the scope engine entirely: its risk is a statement about the tool, and no
142
+ * argument shape makes `rm -rf` a read.
52
143
  */
53
144
  export declare const createPermissionPolicy: (options: PermissionPolicyOptions) => ApprovalPolicy;
54
145
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EACd,QAAQ,EACT,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,UAAU,CAAC;AAExD,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACrD;AAID,sDAAsD;AACtD,eAAO,MAAM,cAAc,GAAI,MAAM,QAAQ,EAAE,OAAO,QAAQ,KAAG,OAC1B,CAAC;AA4DxC;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,uBAAuB,KAAG,cA0EzE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,cAAc,EACd,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,QAAQ,EACT,MAAM,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAEtF,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,kEAAkE;IAClE,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACpD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACrC,yEAAyE;IACzE,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,KAAK,IAAI,CAAC;CAC/E;AA6HD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,uBAAuB,KAAG,cAwKzE,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,12 @@
1
- const RISK_ORDER = { safe: 0, gated: 1, dangerous: 2 };
2
- /** Whether `risk` is at least as risky as `floor`. */
3
- export const atLeastAsRisky = (risk, floor) => RISK_ORDER[risk] >= RISK_ORDER[floor];
1
+ /**
2
+ * Re-exported, not re-implemented: the risk ordering moved to the kernel
3
+ * when the plugin loader became its second consumer, and this package
4
+ * published the name first.
5
+ */
6
+ export { atLeastAsRisky } from '@stratusagent/core';
7
+ import { analyzeCommand, describeCommandScope, findMatchingScope, normalizeCommandScope, SAFE_COMMAND_SCOPES, } from "./commands.js";
8
+ export { analyzeCommand, describeCommandScope, findMatchingScope, matchesScope, normalizeCommandScope, parseCommandScope, sameScope, SAFE_COMMAND_SCOPES, } from "./commands.js";
9
+ export { createFileCommandWhitelist, whitelistPathFor, } from "./whitelist.js";
4
10
  const YES = new Set(['y', 'yes', 'always', 'a']);
5
11
  const ALWAYS = new Set(['always', 'a']);
6
12
  const ABORTED = Symbol('aborted');
@@ -53,22 +59,83 @@ const untilAborted = async (work, signal) => {
53
59
  */
54
60
  const sessionKey = (sessionId, toolName) => `${sessionId}\u0000${toolName}`;
55
61
  /**
56
- * The kernel's ApprovalPolicy, deciding by the tool's declared risk rather
57
- * than by its name. `safe` runs unattended; anything else needs a human,
58
- * and whether one exists is what `mode` answers.
62
+ * Puts the question to someone at a terminal. A prompt's answer is free
63
+ * text from a person mid-typing, so it is read leniently and anything that
64
+ * is not recognisably a yes is a no.
65
+ */
66
+ const awaitPrompt = async (context, ask, command) => {
67
+ const { call, risk, session } = context;
68
+ // The command, when there is one: for a shell call the tool name is the
69
+ // least interesting half of the question, and an approver shown only
70
+ // `shell.run (gated)` is being asked to trust something they cannot see.
71
+ const what = command === undefined ? `${call.toolName} (${risk})` : `${call.toolName}: ${command}`;
72
+ const always = command === undefined ? 'always this session' : 'always this scope';
73
+ const pending = ask(`Allow ${what} for ${session.agent.name}? [y]es / [a]lways (${always}) / [N]o: `);
74
+ // The answer is never read after this point if the turn ends first,
75
+ // so a late yes cannot execute a tool for work that no longer exists.
76
+ pending.catch(() => undefined);
77
+ const response = await untilAborted(pending, context.signal);
78
+ if (response === ABORTED) {
79
+ return ABORTED;
80
+ }
81
+ const answer = response.trim().toLowerCase();
82
+ if (!YES.has(answer)) {
83
+ return 'deny';
84
+ }
85
+ return ALWAYS.has(answer) ? 'always' : 'once';
86
+ };
87
+ /**
88
+ * Puts the question to someone reachable through a channel. Unlike the
89
+ * prompt, the answer arrives already typed — a button carries one of three
90
+ * values — so there is nothing to interpret; the work is entirely in not
91
+ * outliving the turn.
59
92
  *
60
- * This is deliberately coarse. Fine-grained judgment — which *arguments* to
61
- * a shell tool are safe, which flags turn a read into a write — belongs with
62
- * the shell tool itself, which does not exist yet; writing that machinery
63
- * now would mean guessing at the shape of a caller nobody has built.
93
+ * A transport that rejects (its channel is down, the request could not be
94
+ * delivered) denies rather than failing the turn: the agent should be told
95
+ * its call was not approved and carry on, not crash on the machinery that
96
+ * was supposed to ask.
97
+ */
98
+ const awaitRemote = async (context, request) => {
99
+ const pending = request({
100
+ session: context.session,
101
+ call: context.call,
102
+ tool: context.tool,
103
+ risk: context.risk,
104
+ ...(context.parkedAt ? { parkedAt: context.parkedAt } : {}),
105
+ ...(context.signal ? { signal: context.signal } : {}),
106
+ }).then((answer) => answer, () => 'deny');
107
+ return untilAborted(pending, context.signal);
108
+ };
109
+ /**
110
+ * The kernel's ApprovalPolicy, deciding by the tool's declared risk and —
111
+ * for a tool that carries one — by the command an invocation would run.
112
+ * `safe` runs unattended; anything else needs a human unless a scope covers
113
+ * it, and whether a human exists at all is what `mode` answers.
114
+ *
115
+ * The three tiers resolve in order: scopes granted "always" in this session,
116
+ * then the agent's persistent whitelist, then the built-in safe list —
117
+ * after which there is nothing left but asking. A `dangerous` tool skips
118
+ * the scope engine entirely: its risk is a statement about the tool, and no
119
+ * argument shape makes `rm -rf` a read.
64
120
  */
65
121
  export const createPermissionPolicy = (options) => {
66
- const { mode, ask, onDecision } = options;
122
+ const { mode, ask, request, onDecision, commands } = options;
67
123
  if (mode === 'interactive' && !ask) {
68
124
  throw new Error('interactive permission mode needs an `ask` function to reach a human.');
69
125
  }
126
+ // Same reason as `ask`, and the more important half: a remote policy with
127
+ // nothing to publish through would park every gated call on a request no
128
+ // one ever sees, which reads as a hung agent rather than a refusal.
129
+ if (mode === 'remote' && !request) {
130
+ throw new Error('remote permission mode needs a `request` function to reach a human.');
131
+ }
70
132
  const alwaysAllowed = new Set();
71
- const report = (context, allowed, reason) => {
133
+ // Tier one of the three: scopes granted with "always" during this
134
+ // process's life. It is not merely a cache of the file — a policy built
135
+ // with no whitelist store still has to remember an answer for the rest of
136
+ // the session, which is what `always` means at a terminal.
137
+ const sessionScopes = new Map();
138
+ const report = (context, allowed, reason, command) => {
72
139
  onDecision?.({
73
140
  allowed,
74
141
  mode,
@@ -77,6 +144,7 @@ export const createPermissionPolicy = (options) => {
77
144
  sessionId: context.session.id,
78
145
  agentId: context.session.agent.id,
79
146
  reason,
147
+ ...(command === undefined ? {} : { command }),
80
148
  });
81
149
  return allowed;
82
150
  };
@@ -86,11 +154,41 @@ export const createPermissionPolicy = (options) => {
86
154
  if (risk === 'safe') {
87
155
  return report(context, true, `${call.toolName} is safe and runs without approval`);
88
156
  }
89
- if (alwaysAllowed.has(sessionKey(session.id, call.toolName))) {
157
+ // What this *invocation* would run, for a tool whose danger lives in
158
+ // its arguments. Resolved before anything else so that the tool-wide
159
+ // "always" below can never apply to it: one yes to `git status` must
160
+ // not become a standing yes to every command the shell can run.
161
+ const command = risk === 'gated' ? context.tool.commandFor?.(call.input) : undefined;
162
+ const analysis = command === undefined ? undefined : analyzeCommand(command);
163
+ if (analysis) {
164
+ if (analysis.disqualifiedBy) {
165
+ // Never auto-approved, whatever the base command is: a safe scope
166
+ // in front of a pipe is the exact shape this rule exists for.
167
+ if (mode === 'headless') {
168
+ return report(context, false, `${call.toolName} cannot run unattended: ${analysis.disqualifiedBy}`, command);
169
+ }
170
+ }
171
+ else {
172
+ const stored = commands?.whitelist ? await commands.whitelist.scopesFor(session.agent.id) : [];
173
+ const candidates = [
174
+ ...(sessionScopes.get(session.agent.id) ?? []),
175
+ ...stored,
176
+ ...(commands?.safeScopes ?? SAFE_COMMAND_SCOPES),
177
+ ];
178
+ const scope = findMatchingScope(analysis, candidates);
179
+ if (scope) {
180
+ return report(context, true, `${call.toolName} ran inside the approved scope "${describeCommandScope(scope)}"`, command);
181
+ }
182
+ }
183
+ }
184
+ else if (alwaysAllowed.has(sessionKey(session.id, call.toolName))) {
90
185
  return report(context, true, `${call.toolName} was approved for the rest of this session`);
91
186
  }
92
187
  if (mode === 'headless') {
93
- return report(context, false, `${call.toolName} is ${risk} and nobody is available to approve it`);
188
+ return report(context, false, command === undefined
189
+ ? `${call.toolName} is ${risk} and nobody is available to approve it`
190
+ : `${call.toolName} was called outside every approved scope`
191
+ + `${analysis?.base ? ` (${analysis.base})` : ''} and nobody is available to approve it`, command);
94
192
  }
95
193
  // An aborted turn must not sit on a prompt: the human would be
96
194
  // answering for work that no longer exists, and an answer arriving
@@ -98,23 +196,48 @@ export const createPermissionPolicy = (options) => {
98
196
  if (context.signal?.aborted) {
99
197
  return report(context, false, `${call.toolName} was cancelled before it could be approved`);
100
198
  }
101
- const pending = ask(`Allow ${call.toolName} (${risk}) for ${session.agent.name}? [y]es / [a]lways this session / [N]o: `);
102
- // The answer is never read after this point if the turn ends first,
103
- // so a late yes cannot execute a tool for work that no longer exists.
104
- pending.catch(() => undefined);
105
- const response = await untilAborted(pending, context.signal);
106
- if (response === ABORTED) {
199
+ // Both remaining modes wait on a person; only the way of reaching one
200
+ // differs. Everything after the wait — what `always` means, how a
201
+ // refusal is reported — is deliberately shared, so a decision made in
202
+ // Slack and one typed at a terminal cannot drift into meaning
203
+ // different things.
204
+ const answer = mode === 'remote'
205
+ ? await awaitRemote(context, request)
206
+ : await awaitPrompt(context, ask, command);
207
+ if (answer === ABORTED) {
107
208
  return report(context, false, `${call.toolName} was cancelled while awaiting approval`);
108
209
  }
109
- const answer = response.trim().toLowerCase();
110
- if (!YES.has(answer)) {
111
- return report(context, false, `${call.toolName} was refused at the prompt`);
210
+ if (answer === 'deny') {
211
+ return report(context, false, mode === 'remote'
212
+ ? `${call.toolName} was not approved`
213
+ : `${call.toolName} was refused at the prompt`, command);
112
214
  }
113
- if (ALWAYS.has(answer)) {
215
+ if (answer === 'always') {
216
+ const scope = analysis ? normalizeCommandScope(analysis) : undefined;
217
+ if (analysis && !scope) {
218
+ // A command this parser could not reduce to a scope — a pipe, a
219
+ // subshell, an unbalanced quote. "Always" must not fall back to
220
+ // the tool-wide grant here: the approver widened one command they
221
+ // read, and remembering `shell.run` instead would hand the agent
222
+ // every command for the rest of the session.
223
+ return report(context, true, `${call.toolName} was approved once; it cannot be reduced to a scope, so it will ask again`, command);
224
+ }
225
+ if (scope) {
226
+ // A scope, never the command string (useless next time) and never
227
+ // the bare executable (a shell). `git push origin main` persists
228
+ // `git push` minus its destructive forms, so `git push --force`
229
+ // asks again.
230
+ sessionScopes.set(session.agent.id, [...(sessionScopes.get(session.agent.id) ?? []), scope]);
231
+ if (commands?.whitelist) {
232
+ await commands.whitelist.remember(session.agent.id, scope);
233
+ commands.onScopeRemembered?.({ agentId: session.agent.id, scope });
234
+ }
235
+ return report(context, true, `${call.toolName} was approved, and "${describeCommandScope(scope)}" now runs without asking`, command);
236
+ }
114
237
  alwaysAllowed.add(sessionKey(session.id, call.toolName));
115
238
  return report(context, true, `${call.toolName} was approved for the rest of this session`);
116
239
  }
117
- return report(context, true, `${call.toolName} was approved once`);
240
+ return report(context, true, `${call.toolName} was approved once`, command);
118
241
  },
119
242
  };
120
243
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type CommandScope } from './commands.ts';
2
+ /**
3
+ * What one agent may run unattended, beyond the built-in safe list.
4
+ *
5
+ * Per agent, because "always allow" is an answer about one identity's work
6
+ * — a scope somebody granted Ava in a repository of theirs is not a scope
7
+ * Juno inherits.
8
+ */
9
+ export interface CommandWhitelistStore {
10
+ scopesFor(agentId: string): Promise<CommandScope[]>;
11
+ remember(agentId: string, scope: CommandScope): Promise<void>;
12
+ }
13
+ /** `<id>.whitelist.json`, beside the agent's soul in ~/.stratus/agents. */
14
+ export declare const whitelistPathFor: (directory: string, agentId: string) => string;
15
+ /**
16
+ * The persistent half of the three-tier resolution, on disk.
17
+ *
18
+ * Written `0600` with an explicit `chmod`, like every other file in
19
+ * `~/.stratus` that decides something: this one lists commands that run
20
+ * with nobody watching, so another account on the machine appending a line
21
+ * to it is the whole permission engine defeated. `writeFile`'s mode only
22
+ * applies when it creates the file, so an upgrade over a looser install
23
+ * would otherwise keep the old permissions.
24
+ *
25
+ * Scopes are cached in memory once read. A daemon therefore does not notice
26
+ * a hand-edited file until it restarts — which is the right way round for a
27
+ * file whose edits grant permissions, and the same bargain the credential
28
+ * store makes.
29
+ */
30
+ export declare const createFileCommandWhitelist: (options: {
31
+ directory: string;
32
+ }) => CommandWhitelistStore;
33
+ //# sourceMappingURL=whitelist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whitelist.d.ts","sourceRoot":"","sources":["../src/whitelist.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAEhF;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AASD,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,EAAE,SAAS,MAAM,KAAG,MACnB,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,0BAA0B,GAAI,SAAS;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,KAAG,qBA+C3E,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { parseCommandScope, sameScope } from "./commands.js";
4
+ const WHITELIST_VERSION = 1;
5
+ /** `<id>.whitelist.json`, beside the agent's soul in ~/.stratus/agents. */
6
+ export const whitelistPathFor = (directory, agentId) => path.join(directory, `${agentId}.whitelist.json`);
7
+ /**
8
+ * The persistent half of the three-tier resolution, on disk.
9
+ *
10
+ * Written `0600` with an explicit `chmod`, like every other file in
11
+ * `~/.stratus` that decides something: this one lists commands that run
12
+ * with nobody watching, so another account on the machine appending a line
13
+ * to it is the whole permission engine defeated. `writeFile`'s mode only
14
+ * applies when it creates the file, so an upgrade over a looser install
15
+ * would otherwise keep the old permissions.
16
+ *
17
+ * Scopes are cached in memory once read. A daemon therefore does not notice
18
+ * a hand-edited file until it restarts — which is the right way round for a
19
+ * file whose edits grant permissions, and the same bargain the credential
20
+ * store makes.
21
+ */
22
+ export const createFileCommandWhitelist = (options) => {
23
+ const cache = new Map();
24
+ const read = async (agentId) => {
25
+ const cached = cache.get(agentId);
26
+ if (cached) {
27
+ return cached;
28
+ }
29
+ let scopes = [];
30
+ try {
31
+ // The agent id is a validated invariant by the time it reaches any
32
+ // path join (see 03) — it is a single path segment or it was refused
33
+ // at the parse boundary, so this does not re-check it.
34
+ const raw = await readFile(whitelistPathFor(options.directory, agentId), 'utf8');
35
+ const parsed = JSON.parse(raw);
36
+ scopes = Array.isArray(parsed.scopes)
37
+ ? parsed.scopes.map(parseCommandScope).filter((scope) => scope !== undefined)
38
+ : [];
39
+ }
40
+ catch {
41
+ // No whitelist, or one that will not parse. Both mean the same thing
42
+ // to a caller — no stored scopes — and neither is worth failing a
43
+ // turn over: the fallback is asking a human, which is where an agent
44
+ // with no whitelist starts anyway.
45
+ scopes = [];
46
+ }
47
+ cache.set(agentId, scopes);
48
+ return scopes;
49
+ };
50
+ return {
51
+ async scopesFor(agentId) {
52
+ return [...(await read(agentId))];
53
+ },
54
+ async remember(agentId, scope) {
55
+ const scopes = await read(agentId);
56
+ if (scopes.some((existing) => sameScope(existing, scope))) {
57
+ return;
58
+ }
59
+ const updated = [...scopes, scope];
60
+ cache.set(agentId, updated);
61
+ await mkdir(options.directory, { recursive: true });
62
+ const file = { version: WHITELIST_VERSION, scopes: updated };
63
+ const target = whitelistPathFor(options.directory, agentId);
64
+ await writeFile(target, `${JSON.stringify(file, null, 2)}\n`, { mode: 0o600 });
65
+ await chmod(target, 0o600);
66
+ },
67
+ };
68
+ };
69
+ //# sourceMappingURL=whitelist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whitelist.js","sourceRoot":"","sources":["../src/whitelist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAqB,MAAM,eAAe,CAAC;AAmBhF,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAiB,EAAE,OAAe,EAAU,EAAE,CAC7E,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO,iBAAiB,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAA8B,EAAyB,EAAE;IAClG,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEhD,MAAM,IAAI,GAAG,KAAK,EAAE,OAAe,EAA2B,EAAE;QAC9D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,MAAM,GAAmB,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,mEAAmE;YACnE,qEAAqE;YACrE,uDAAuD;YACvD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;YACjF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2B,CAAC;YACzD,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;gBACnC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAyB,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;gBACpG,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,kEAAkE;YAClE,qEAAqE;YACrE,mCAAmC;YACnC,MAAM,GAAG,EAAE,CAAC;QACd,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,OAAO;YACrB,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;YACnC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC1D,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC;YACnC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5B,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,MAAM,IAAI,GAAkB,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;YAC5E,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC5D,MAAM,SAAS,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/E,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratusagent/permissions",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -17,9 +17,10 @@
17
17
  "node": ">=22.13 <23 || >=23.4"
18
18
  },
19
19
  "dependencies": {
20
- "@stratusagent/core": "0.3.0"
20
+ "@stratusagent/core": "0.6.0"
21
21
  },
22
22
  "devDependencies": {
23
+ "@types/node": "^24.6.0",
23
24
  "typescript": "^5.9.3"
24
25
  },
25
26
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"fileNames":["../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.scripthost.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.full.d.ts","../../core/dist/index.d.ts","../src/index.ts"],"fileIdsList":[[64]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7a3c8b952931daebdfc7a2897c53c0a1c73624593fa070e46bd537e64dcd20a","affectsGlobalScope":true,"impliedFormat":1},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"3cbad9a1ba4453443026ed38e4b8be018abb26565fa7c944376463ad9df07c41","impliedFormat":1},{"version":"2684504f5ac9d0d77f79c2971ad2cca76d0cc0669dceb1a79bfa18754f6351c3","impliedFormat":99},{"version":"45115b15bdd714ca361c03deab56f27f17d8c44222f2f8feb60c3f3388ac1f00","impliedFormat":99}],"root":[65],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"exactOptionalPropertyTypes":true,"module":199,"noUncheckedIndexedAccess":true,"outDir":"./","rootDir":"..","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9},"referencedMap":[[65,1]],"affectedFilesPendingEmit":[[65,51]],"emitSignatures":[65],"version":"5.9.3"}