@gaunt-sloth/core 2.0.0-alpha.2 → 2.0.0-alpha.21

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 (158) hide show
  1. package/.gsloth.code.md +10 -0
  2. package/README.md +6 -6
  3. package/dist/config/defaults.d.ts +85 -0
  4. package/dist/config/defaults.js +103 -0
  5. package/dist/config/defaults.js.map +1 -0
  6. package/dist/config/jsonc.d.ts +12 -0
  7. package/dist/config/jsonc.js +41 -0
  8. package/dist/config/jsonc.js.map +1 -0
  9. package/dist/config/loader.d.ts +169 -0
  10. package/dist/config/loader.js +872 -0
  11. package/dist/config/loader.js.map +1 -0
  12. package/dist/config/schema.d.ts +673 -0
  13. package/dist/config/schema.js +524 -0
  14. package/dist/config/schema.js.map +1 -0
  15. package/dist/config/shell-policy.d.ts +331 -0
  16. package/dist/config/shell-policy.js +238 -0
  17. package/dist/config/shell-policy.js.map +1 -0
  18. package/dist/config/types.d.ts +596 -0
  19. package/dist/config/types.js +13 -0
  20. package/dist/config/types.js.map +1 -0
  21. package/dist/config.d.ts +18 -647
  22. package/dist/config.js +15 -516
  23. package/dist/config.js.map +1 -1
  24. package/dist/constants.d.ts +42 -0
  25. package/dist/constants.js +42 -0
  26. package/dist/constants.js.map +1 -1
  27. package/dist/core/GthAbstractAgent.d.ts +85 -2
  28. package/dist/core/GthAbstractAgent.js +398 -28
  29. package/dist/core/GthAbstractAgent.js.map +1 -1
  30. package/dist/core/GthAgentRunner.d.ts +158 -1
  31. package/dist/core/GthAgentRunner.js +367 -4
  32. package/dist/core/GthAgentRunner.js.map +1 -1
  33. package/dist/core/GthLangChainAgent.js +193 -16
  34. package/dist/core/GthLangChainAgent.js.map +1 -1
  35. package/dist/core/debugCapture.d.ts +59 -0
  36. package/dist/core/debugCapture.js +101 -0
  37. package/dist/core/debugCapture.js.map +1 -0
  38. package/dist/core/gthLeanAgentFactory.d.ts +9 -0
  39. package/dist/core/gthLeanAgentFactory.js +10 -0
  40. package/dist/core/gthLeanAgentFactory.js.map +1 -0
  41. package/dist/core/plainToolIndication.d.ts +15 -0
  42. package/dist/core/plainToolIndication.js +148 -0
  43. package/dist/core/plainToolIndication.js.map +1 -0
  44. package/dist/core/runStats.d.ts +41 -0
  45. package/dist/core/runStats.js +73 -0
  46. package/dist/core/runStats.js.map +1 -0
  47. package/dist/core/shell/ShellCommandFailedError.d.ts +54 -0
  48. package/dist/core/shell/ShellCommandFailedError.js +68 -0
  49. package/dist/core/shell/ShellCommandFailedError.js.map +1 -0
  50. package/dist/core/shell/allowlist.d.ts +75 -0
  51. package/dist/core/shell/allowlist.js +187 -0
  52. package/dist/core/shell/allowlist.js.map +1 -0
  53. package/dist/core/shell/arity.d.ts +75 -0
  54. package/dist/core/shell/arity.js +313 -0
  55. package/dist/core/shell/arity.js.map +1 -0
  56. package/dist/core/shell/judge.d.ts +161 -0
  57. package/dist/core/shell/judge.js +261 -0
  58. package/dist/core/shell/judge.js.map +1 -0
  59. package/dist/core/shell/normalize.d.ts +27 -0
  60. package/dist/core/shell/normalize.js +53 -0
  61. package/dist/core/shell/normalize.js.map +1 -0
  62. package/dist/core/toolDisplay.d.ts +101 -0
  63. package/dist/core/toolDisplay.js +374 -0
  64. package/dist/core/toolDisplay.js.map +1 -0
  65. package/dist/core/toolOutputChannel.d.ts +68 -0
  66. package/dist/core/toolOutputChannel.js +112 -0
  67. package/dist/core/toolOutputChannel.js.map +1 -0
  68. package/dist/core/types.d.ts +173 -0
  69. package/dist/core/types.js.map +1 -1
  70. package/dist/history/historyFormat.d.ts +28 -0
  71. package/dist/history/historyFormat.js +127 -0
  72. package/dist/history/historyFormat.js.map +1 -0
  73. package/dist/history/historyStore.d.ts +198 -0
  74. package/dist/history/historyStore.js +482 -0
  75. package/dist/history/historyStore.js.map +1 -0
  76. package/dist/history/recordSession.d.ts +37 -0
  77. package/dist/history/recordSession.js +56 -0
  78. package/dist/history/recordSession.js.map +1 -0
  79. package/dist/index.d.ts +4 -0
  80. package/dist/index.js +4 -0
  81. package/dist/index.js.map +1 -1
  82. package/dist/providers/anthropic.d.ts +1 -1
  83. package/dist/providers/anthropic.js +5 -10
  84. package/dist/providers/anthropic.js.map +1 -1
  85. package/dist/providers/deepseek.d.ts +1 -1
  86. package/dist/providers/deepseek.js +5 -10
  87. package/dist/providers/deepseek.js.map +1 -1
  88. package/dist/providers/geminiSchemaSanitizer.d.ts +52 -0
  89. package/dist/providers/geminiSchemaSanitizer.js +201 -0
  90. package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
  91. package/dist/providers/google-genai.d.ts +1 -1
  92. package/dist/providers/google-genai.js +9 -11
  93. package/dist/providers/google-genai.js.map +1 -1
  94. package/dist/providers/groq.d.ts +1 -1
  95. package/dist/providers/groq.js +5 -10
  96. package/dist/providers/groq.js.map +1 -1
  97. package/dist/providers/huggingface.d.ts +25 -0
  98. package/dist/providers/huggingface.js +69 -0
  99. package/dist/providers/huggingface.js.map +1 -0
  100. package/dist/providers/modelCatalog.d.ts +109 -0
  101. package/dist/providers/modelCatalog.js +245 -0
  102. package/dist/providers/modelCatalog.js.map +1 -0
  103. package/dist/providers/modelDiscovery.d.ts +111 -3
  104. package/dist/providers/modelDiscovery.js +183 -27
  105. package/dist/providers/modelDiscovery.js.map +1 -1
  106. package/dist/providers/ollama.d.ts +19 -5
  107. package/dist/providers/ollama.js +60 -52
  108. package/dist/providers/ollama.js.map +1 -1
  109. package/dist/providers/openai.d.ts +1 -1
  110. package/dist/providers/openai.js +5 -10
  111. package/dist/providers/openai.js.map +1 -1
  112. package/dist/providers/openrouter.d.ts +1 -1
  113. package/dist/providers/openrouter.js +12 -12
  114. package/dist/providers/openrouter.js.map +1 -1
  115. package/dist/providers/vertexai.d.ts +1 -1
  116. package/dist/providers/vertexai.js +9 -11
  117. package/dist/providers/vertexai.js.map +1 -1
  118. package/dist/providers/xai.d.ts +1 -1
  119. package/dist/providers/xai.js +5 -10
  120. package/dist/providers/xai.js.map +1 -1
  121. package/dist/runtime/askStructured.d.ts +62 -0
  122. package/dist/runtime/askStructured.js +76 -0
  123. package/dist/runtime/askStructured.js.map +1 -0
  124. package/dist/runtime/conversation.d.ts +59 -0
  125. package/dist/runtime/conversation.js +137 -0
  126. package/dist/runtime/conversation.js.map +1 -0
  127. package/dist/runtime/singleShot.d.ts +24 -5
  128. package/dist/runtime/singleShot.js +56 -9
  129. package/dist/runtime/singleShot.js.map +1 -1
  130. package/dist/utils/aiignoreUtils.js.map +1 -1
  131. package/dist/utils/binaryOutputUtils.js.map +1 -1
  132. package/dist/utils/consoleUtils.d.ts +22 -0
  133. package/dist/utils/consoleUtils.js +45 -0
  134. package/dist/utils/consoleUtils.js.map +1 -1
  135. package/dist/utils/debugDump.d.ts +57 -0
  136. package/dist/utils/debugDump.js +236 -0
  137. package/dist/utils/debugDump.js.map +1 -0
  138. package/dist/utils/debugUtils.d.ts +13 -4
  139. package/dist/utils/debugUtils.js +36 -13
  140. package/dist/utils/debugUtils.js.map +1 -1
  141. package/dist/utils/fileUtils.d.ts +24 -2
  142. package/dist/utils/fileUtils.js +54 -12
  143. package/dist/utils/fileUtils.js.map +1 -1
  144. package/dist/utils/llmUtils.js.map +1 -1
  145. package/dist/utils/redactSecrets.d.ts +63 -0
  146. package/dist/utils/redactSecrets.js +238 -0
  147. package/dist/utils/redactSecrets.js.map +1 -0
  148. package/dist/utils/systemPromptNotes.d.ts +181 -0
  149. package/dist/utils/systemPromptNotes.js +298 -0
  150. package/dist/utils/systemPromptNotes.js.map +1 -0
  151. package/dist/utils/systemUtils.d.ts +32 -1
  152. package/dist/utils/systemUtils.js +50 -3
  153. package/dist/utils/systemUtils.js.map +1 -1
  154. package/dist/utils/toolMatching.d.ts +30 -0
  155. package/dist/utils/toolMatching.js +44 -0
  156. package/dist/utils/toolMatching.js.map +1 -0
  157. package/package.json +17 -8
  158. package/schema/gsloth-config.schema.json +2111 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @module core/shell/allowlist
3
+ *
4
+ * EXT-9 Tier-2: the persisted + session-scoped allow-list engine for the opt-in
5
+ * `run_shell_command` tool. Once a human approves a command at `session` or `always`
6
+ * scope, future commands with the same classified prefix ({@link classifyCommand}) are
7
+ * auto-approved without re-prompting — the ergonomics improvement mature agents
8
+ * (opencode/openclaw/hermes) ship.
9
+ *
10
+ * SECURITY — a naive "remember the prefix" allow-list is an injection vector. Two layers
11
+ * guard it:
12
+ * 1. **Classification fail-closed** (arity.ts): any command with shell composition,
13
+ * substitution, or redirection returns `null` and can NEVER match, so
14
+ * `git checkout x; rm -rf /` does not ride an approved `git checkout *`.
15
+ * 2. **Safe-bin anti-widening re-validation** (here, after opencode/openclaw): a stored
16
+ * approval is matched ONLY if the candidate command's first non-flag operand region
17
+ * does not introduce a flag that *widens or redirects* the approved operation. The
18
+ * exact rule is documented on {@link matchesApproval} / {@link hasWideningFlag}.
19
+ *
20
+ * No module-global mutable state: the session store is a per-instance class so concurrent
21
+ * sessions (ACP / AG-UI multi-session) cannot stomp each other. The persisted (`always`)
22
+ * store is a small JSON file the runner loads once per instance.
23
+ */
24
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
25
+ import { classifyCommand, tokenize } from '#src/core/shell/arity.js';
26
+ import { normalizeCommand } from '#src/core/shell/normalize.js';
27
+ const PERSISTED_VERSION = 1;
28
+ /**
29
+ * Flags that, if present in a candidate command but not implied by the approved prefix,
30
+ * could change the *operation* the human approved (point it at a different transport,
31
+ * exec a hook, follow an attacker-controlled URL). Approving `git clone` must not
32
+ * green-light `git clone --upload-pack=evil`. This list is intentionally conservative:
33
+ * it is the openclaw "safe-bin" idea reduced to a deny-set of operation-changing flags
34
+ * that commonly appear in shell-injection / supply-chain abuse.
35
+ *
36
+ * Matched against the flag token with any `=value` stripped, case-insensitively.
37
+ */
38
+ const WIDENING_FLAGS = new Set([
39
+ // git: remote command / hook overrides.
40
+ '--upload-pack',
41
+ '--receive-pack',
42
+ '--exec',
43
+ '-u', // git clone -u <upload-pack>
44
+ '--config', // git -c is the short form; --config can inject core.sshCommand etc.
45
+ '-c', // git -c core.sshCommand='...' — arbitrary command execution
46
+ // generic "run this program" escape hatches across tools.
47
+ '--exec-path',
48
+ '-exec', // find -exec <cmd>
49
+ '--use-askpass',
50
+ '--ssh-command',
51
+ // package managers: lifecycle-script / arbitrary-script toggles.
52
+ '--unsafe-perm',
53
+ '--ignore-scripts=false',
54
+ '--allow-scripts',
55
+ // curl/wget style follow/exec (in case a bare binary is approved).
56
+ '-o', // write to arbitrary path
57
+ '--output',
58
+ '-T', // upload
59
+ '--upload-file',
60
+ ]);
61
+ /**
62
+ * Decide whether a candidate argv contains a flag that *widens* the approved operation.
63
+ *
64
+ * Rule implemented (documented for the coordinator):
65
+ * - Re-derive the meaningful prefix from the candidate's actual argv.
66
+ * - Inspect every token of the candidate that is a flag (starts with `-`).
67
+ * - If any flag token — normalized by stripping a trailing `=value` and lowercasing —
68
+ * is in {@link WIDENING_FLAGS}, the command is considered a widening of the approved
69
+ * operation and the match is REFUSED (returns true).
70
+ *
71
+ * This is purposely a deny-list of operation-changing flags rather than an allow-list of
72
+ * benign flags: benign flag variants (`-b`, `--oneline`, `-la`) are exactly what we WANT
73
+ * to keep auto-approving, while the handful of "run-an-arbitrary-program / redirect-the-
74
+ * transport" flags are what an injected approval must never silently enable.
75
+ */
76
+ export function hasWideningFlag(argv) {
77
+ for (const tok of argv) {
78
+ if (!tok.startsWith('-'))
79
+ continue;
80
+ const bare = tok.split('=', 1)[0].toLowerCase();
81
+ if (WIDENING_FLAGS.has(bare))
82
+ return true;
83
+ }
84
+ return false;
85
+ }
86
+ /**
87
+ * A holder of approved prefixes with set semantics. Used for both the in-memory session
88
+ * store and the loaded persisted store. Pure data + membership; persistence is layered on
89
+ * top by {@link PersistedAllowlist}.
90
+ */
91
+ export class AllowlistStore {
92
+ prefixes;
93
+ constructor(initial = []) {
94
+ this.prefixes = new Set(initial);
95
+ }
96
+ has(prefix) {
97
+ return this.prefixes.has(prefix);
98
+ }
99
+ add(prefix) {
100
+ this.prefixes.add(prefix);
101
+ }
102
+ list() {
103
+ return [...this.prefixes];
104
+ }
105
+ }
106
+ /**
107
+ * The persisted (`always`) allow-list, backed by a JSON file. The path is injected (the
108
+ * runner resolves it via fileUtils → `.gsloth/.gsloth-settings/shell-allowlist.json`) so
109
+ * tests can point it at a temp dir. Loads lazily/defensively: a missing or malformed file
110
+ * yields an empty store rather than throwing (fail-open on READ is safe — an empty
111
+ * allow-list just means "prompt"; it never auto-approves anything).
112
+ */
113
+ export class PersistedAllowlist {
114
+ store;
115
+ filePath;
116
+ constructor(filePath) {
117
+ this.filePath = filePath;
118
+ this.store = new AllowlistStore(PersistedAllowlist.load(filePath));
119
+ }
120
+ static load(filePath) {
121
+ try {
122
+ if (!existsSync(filePath))
123
+ return [];
124
+ const raw = readFileSync(filePath, 'utf8');
125
+ const parsed = JSON.parse(raw);
126
+ if (!parsed || !Array.isArray(parsed.prefixes))
127
+ return [];
128
+ return parsed.prefixes.filter((p) => typeof p === 'string');
129
+ }
130
+ catch {
131
+ // Corrupt/unreadable file → behave as empty (fail-closed on auto-approval).
132
+ return [];
133
+ }
134
+ }
135
+ has(prefix) {
136
+ return this.store.has(prefix);
137
+ }
138
+ list() {
139
+ return this.store.list();
140
+ }
141
+ /** Add a prefix and persist the whole set to disk. */
142
+ add(prefix) {
143
+ if (this.store.has(prefix))
144
+ return;
145
+ this.store.add(prefix);
146
+ this.persist();
147
+ }
148
+ persist() {
149
+ const file = {
150
+ version: PERSISTED_VERSION,
151
+ prefixes: this.store.list().sort(),
152
+ };
153
+ writeFileSync(this.filePath, JSON.stringify(file, null, 2) + '\n', 'utf8');
154
+ }
155
+ }
156
+ /**
157
+ * Decide whether `command` is already approved by the given stores — the gate the runner
158
+ * consults BEFORE prompting the human.
159
+ *
160
+ * Returns true ONLY when ALL of the following hold:
161
+ * 1. {@link classifyCommand} returns a non-null classification (so composition /
162
+ * substitution / redirection commands can never match — anti-injection layer 1);
163
+ * 2. the classified prefix is present in the session OR persisted (`always`) store; AND
164
+ * 3. the safe-bin re-validation passes: the candidate's actual argv contains no
165
+ * operation-widening flag (anti-injection layer 2 — see {@link hasWideningFlag}).
166
+ *
167
+ * Anything else (unclassifiable, unknown prefix, or a widening flag) → false → the human
168
+ * is prompted. Fail-closed by construction.
169
+ */
170
+ export function matchesApproval(command, stores) {
171
+ const classification = classifyCommand(command, normalizeCommand);
172
+ if (!classification)
173
+ return false; // layer 1: composition/redirection/substitution.
174
+ const approved = stores.session.has(classification.prefix) ||
175
+ (stores.always?.has(classification.prefix) ?? false);
176
+ if (!approved)
177
+ return false;
178
+ // Layer 2: re-derive argv from the normalized command and refuse if an operation-
179
+ // widening flag is present that the human's prefix-level approval never implied.
180
+ const argv = tokenize(normalizeCommand(command));
181
+ if (!argv)
182
+ return false; // unbalanced quoting → fail-closed.
183
+ if (hasWideningFlag(argv))
184
+ return false;
185
+ return true;
186
+ }
187
+ //# sourceMappingURL=allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.js","sourceRoot":"","sources":["../../../src/core/shell/allowlist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @module core/shell/arity
3
+ *
4
+ * EXT-9 Tier-2 ergonomics: classify a shell command into a stable, human-readable
5
+ * **prefix** (binary + N meaningful subcommands) so an approval the human grants once
6
+ * (`git checkout main`) can be remembered as a pattern (`git checkout *`) and matched
7
+ * against later flag-variants (`git checkout -b foo bar`) WITHOUT re-prompting.
8
+ *
9
+ * The arity table (which tokens past the binary are "meaningful subcommands" rather
10
+ * than operands/flags) is a port of a subset of opencode's ~160-command table
11
+ * (`opencode/packages/opencode/src/permission/arity.ts`). Binaries not in the table
12
+ * default to arity 0 = just the binary.
13
+ *
14
+ * SECURITY — this is the anti-injection core. {@link classifyCommand} returns `null`
15
+ * (fail-closed) whenever the command contains shell composition that could change the
16
+ * target of the operation: separators (`;`, `&&`, `||`, `|`, `&`), newlines, command
17
+ * substitution (`$(...)`, backticks), process substitution (`<(...)`/`>(...)`), or
18
+ * redirections. Such commands NEVER auto-match an allow-list entry — they always go to
19
+ * fresh human approval. This is what stops `git checkout x; rm -rf /` from matching an
20
+ * approved `git checkout *`.
21
+ */
22
+ /**
23
+ * Result of classifying a command for allow-list matching.
24
+ */
25
+ export interface CommandClassification {
26
+ /**
27
+ * The meaningful command prefix — binary plus subcommands per the arity table, with
28
+ * flags removed. This is the allow-list KEY: two commands with the same prefix are the
29
+ * "same operation" for approval purposes (`git checkout main` and `git checkout -b x`
30
+ * both → `git checkout`).
31
+ */
32
+ prefix: string;
33
+ /**
34
+ * Human-facing display pattern, e.g. `git checkout *` (or `ls *`). The trailing `*`
35
+ * signals "any args/flags". A prefix that already consumed the whole command (no extra
36
+ * operands) still gets ` *` for a consistent, honest "future args allowed" affordance.
37
+ */
38
+ pattern: string;
39
+ }
40
+ /**
41
+ * Tokenize a shell command into argv, honoring single and double quotes. Quotes group
42
+ * (and are stripped from) a token; backslash-escaping inside double quotes is collapsed
43
+ * by the prior normalize step, so this tokenizer treats a residual `\` literally.
44
+ *
45
+ * This is a deliberately small tokenizer used ONLY for prefix detection — never for
46
+ * execution. The original command string is what runs.
47
+ *
48
+ * Returns `null` if quoting is unbalanced (an open quote with no close), which is itself
49
+ * a reason to refuse classification (ambiguous parse → fail-closed).
50
+ */
51
+ export declare function tokenize(command: string): string[] | null;
52
+ /**
53
+ * Look up the arity (number of leading meaningful tokens) for an argv, using the
54
+ * longest-matching-prefix rule against {@link ARITY}. Flag tokens (starting with `-`) are
55
+ * dropped when forming the candidate prefixes so boolean flags like `git --no-pager
56
+ * checkout` still resolve `git checkout`. Unknown binaries default to arity 0 → just the
57
+ * binary.
58
+ *
59
+ * LIMITATION (intentional, fail-closed): we do NOT maintain a per-flag arity table, so an
60
+ * arg-taking flag leaves its operand in the non-flag stream (e.g. `git -C . checkout` →
61
+ * `git .`). That simply fails to match an approved `git checkout` and re-prompts — safe, by
62
+ * design — rather than risking a mis-classification that mis-approves.
63
+ *
64
+ * Returns the list of meaningful tokens (binary + subcommands), flag tokens excluded.
65
+ */
66
+ export declare function meaningfulPrefixTokens(argv: string[]): string[];
67
+ /**
68
+ * Classify a command into a stable allow-list prefix + display pattern, or `null` when it
69
+ * cannot be safely classified for matching (composition/redirection/substitution present,
70
+ * empty, or unbalanced quotes).
71
+ *
72
+ * @param command Raw command string as the model proposed it.
73
+ * @param normalize Normalizer to apply for the detection form (inject normalizeCommand).
74
+ */
75
+ export declare function classifyCommand(command: string, normalize: (cmd: string) => string): CommandClassification | null;
@@ -0,0 +1,313 @@
1
+ /**
2
+ * @module core/shell/arity
3
+ *
4
+ * EXT-9 Tier-2 ergonomics: classify a shell command into a stable, human-readable
5
+ * **prefix** (binary + N meaningful subcommands) so an approval the human grants once
6
+ * (`git checkout main`) can be remembered as a pattern (`git checkout *`) and matched
7
+ * against later flag-variants (`git checkout -b foo bar`) WITHOUT re-prompting.
8
+ *
9
+ * The arity table (which tokens past the binary are "meaningful subcommands" rather
10
+ * than operands/flags) is a port of a subset of opencode's ~160-command table
11
+ * (`opencode/packages/opencode/src/permission/arity.ts`). Binaries not in the table
12
+ * default to arity 0 = just the binary.
13
+ *
14
+ * SECURITY — this is the anti-injection core. {@link classifyCommand} returns `null`
15
+ * (fail-closed) whenever the command contains shell composition that could change the
16
+ * target of the operation: separators (`;`, `&&`, `||`, `|`, `&`), newlines, command
17
+ * substitution (`$(...)`, backticks), process substitution (`<(...)`/`>(...)`), or
18
+ * redirections. Such commands NEVER auto-match an allow-list entry — they always go to
19
+ * fresh human approval. This is what stops `git checkout x; rm -rf /` from matching an
20
+ * approved `git checkout *`.
21
+ */
22
+ /**
23
+ * Arity table: command-prefix string → number of leading tokens (binary + subcommands,
24
+ * flags excluded) that define the "human-understandable command". Longest matching
25
+ * prefix wins. Ported subset of opencode's table — git/npm/pnpm/yarn/docker/kubectl/
26
+ * cargo/go/etc. Binaries absent here default to arity 0 (just the binary), see
27
+ * {@link arityFor}.
28
+ *
29
+ * Rule (from opencode): flags never count as tokens; only subcommands do. Include a
30
+ * longer prefix only when its arity differs from what the shorter prefix implies.
31
+ */
32
+ const ARITY = {
33
+ // Single-token utilities (arity 1 = just the binary; here for completeness/clarity).
34
+ cat: 1,
35
+ cd: 1,
36
+ chmod: 1,
37
+ chown: 1,
38
+ cp: 1,
39
+ echo: 1,
40
+ env: 1,
41
+ export: 1,
42
+ grep: 1,
43
+ kill: 1,
44
+ killall: 1,
45
+ ln: 1,
46
+ ls: 1,
47
+ mkdir: 1,
48
+ mv: 1,
49
+ ps: 1,
50
+ pwd: 1,
51
+ rm: 1,
52
+ rmdir: 1,
53
+ sleep: 1,
54
+ source: 1,
55
+ tail: 1,
56
+ head: 1,
57
+ touch: 1,
58
+ unset: 1,
59
+ which: 1,
60
+ find: 1,
61
+ // Cloud / infra CLIs.
62
+ aws: 3,
63
+ az: 3,
64
+ bazel: 2,
65
+ brew: 2,
66
+ bun: 2,
67
+ 'bun run': 3,
68
+ 'bun x': 3,
69
+ cargo: 2,
70
+ 'cargo add': 3,
71
+ 'cargo run': 3,
72
+ cdk: 2,
73
+ cf: 2,
74
+ cmake: 2,
75
+ composer: 2,
76
+ consul: 2,
77
+ 'consul kv': 3,
78
+ crictl: 2,
79
+ deno: 2,
80
+ 'deno task': 3,
81
+ doctl: 3,
82
+ docker: 2,
83
+ 'docker builder': 3,
84
+ 'docker compose': 3,
85
+ 'docker container': 3,
86
+ 'docker image': 3,
87
+ 'docker network': 3,
88
+ 'docker volume': 3,
89
+ eksctl: 2,
90
+ 'eksctl create': 3,
91
+ firebase: 2,
92
+ flyctl: 2,
93
+ gcloud: 3,
94
+ gh: 3,
95
+ git: 2,
96
+ 'git config': 3,
97
+ 'git remote': 3,
98
+ 'git stash': 3,
99
+ go: 2,
100
+ gradle: 2,
101
+ helm: 2,
102
+ heroku: 2,
103
+ hugo: 2,
104
+ ip: 2,
105
+ 'ip addr': 3,
106
+ 'ip link': 3,
107
+ 'ip netns': 3,
108
+ 'ip route': 3,
109
+ kind: 2,
110
+ 'kind create': 3,
111
+ kubectl: 2,
112
+ 'kubectl kustomize': 3,
113
+ 'kubectl rollout': 3,
114
+ kustomize: 2,
115
+ make: 2,
116
+ mc: 2,
117
+ 'mc admin': 3,
118
+ minikube: 2,
119
+ mongosh: 2,
120
+ mysql: 2,
121
+ mvn: 2,
122
+ ng: 2,
123
+ npm: 2,
124
+ 'npm exec': 3,
125
+ 'npm init': 3,
126
+ 'npm run': 3,
127
+ 'npm view': 3,
128
+ npx: 2,
129
+ nvm: 2,
130
+ nx: 2,
131
+ openssl: 2,
132
+ 'openssl req': 3,
133
+ 'openssl x509': 3,
134
+ pip: 2,
135
+ pipenv: 2,
136
+ pnpm: 2,
137
+ 'pnpm dlx': 3,
138
+ 'pnpm exec': 3,
139
+ 'pnpm run': 3,
140
+ poetry: 2,
141
+ podman: 2,
142
+ 'podman container': 3,
143
+ 'podman image': 3,
144
+ psql: 2,
145
+ pulumi: 2,
146
+ 'pulumi stack': 3,
147
+ pyenv: 2,
148
+ python: 2,
149
+ python3: 2,
150
+ rake: 2,
151
+ rbenv: 2,
152
+ 'redis-cli': 2,
153
+ rustup: 2,
154
+ serverless: 2,
155
+ sfdx: 3,
156
+ skaffold: 2,
157
+ sls: 2,
158
+ sst: 2,
159
+ swift: 2,
160
+ systemctl: 2,
161
+ terraform: 2,
162
+ 'terraform workspace': 3,
163
+ tmux: 2,
164
+ turbo: 2,
165
+ ufw: 2,
166
+ vault: 2,
167
+ 'vault auth': 3,
168
+ 'vault kv': 3,
169
+ vercel: 2,
170
+ volta: 2,
171
+ wp: 2,
172
+ yarn: 2,
173
+ 'yarn dlx': 3,
174
+ 'yarn run': 3,
175
+ };
176
+ /**
177
+ * Tokens / sequences whose presence means the command composes or redirects in a way that
178
+ * could change what actually runs — so it must NOT be classifiable for auto-match. Checked
179
+ * against the NORMALIZED command (see normalize.ts) which has already collapsed obfuscation.
180
+ *
181
+ * Note: `&&`/`||`/`|` are covered by the bare `&`/`|` character scan; listed conceptually.
182
+ */
183
+ function hasUnsafeComposition(normalized) {
184
+ // Newlines are folded by normalizeCommand, but guard anyway in case a raw string is passed.
185
+ if (/[\n\r]/.test(normalized))
186
+ return true;
187
+ // Shell control / separator operators and background.
188
+ if (/[;|&]/.test(normalized))
189
+ return true;
190
+ // Command substitution: $(...) or `...`.
191
+ if (/\$\(/.test(normalized))
192
+ return true;
193
+ if (/`/.test(normalized))
194
+ return true;
195
+ // Variable/arith expansion that could inject: ${...} and $((...)).
196
+ if (/\$\{/.test(normalized))
197
+ return true;
198
+ // Process substitution: <(...) or >(...).
199
+ if (/[<>]\(/.test(normalized))
200
+ return true;
201
+ // Redirections (any < or > not already caught as process substitution): >, >>, <, 2>, &>.
202
+ if (/[<>]/.test(normalized))
203
+ return true;
204
+ return false;
205
+ }
206
+ /**
207
+ * Tokenize a shell command into argv, honoring single and double quotes. Quotes group
208
+ * (and are stripped from) a token; backslash-escaping inside double quotes is collapsed
209
+ * by the prior normalize step, so this tokenizer treats a residual `\` literally.
210
+ *
211
+ * This is a deliberately small tokenizer used ONLY for prefix detection — never for
212
+ * execution. The original command string is what runs.
213
+ *
214
+ * Returns `null` if quoting is unbalanced (an open quote with no close), which is itself
215
+ * a reason to refuse classification (ambiguous parse → fail-closed).
216
+ */
217
+ export function tokenize(command) {
218
+ const tokens = [];
219
+ let current = '';
220
+ let inToken = false;
221
+ let quote = null;
222
+ for (let i = 0; i < command.length; i++) {
223
+ const ch = command[i];
224
+ if (quote) {
225
+ if (ch === quote) {
226
+ quote = null;
227
+ }
228
+ else {
229
+ current += ch;
230
+ }
231
+ continue;
232
+ }
233
+ if (ch === '"' || ch === "'") {
234
+ quote = ch;
235
+ inToken = true;
236
+ continue;
237
+ }
238
+ if (ch === ' ' || ch === '\t') {
239
+ if (inToken) {
240
+ tokens.push(current);
241
+ current = '';
242
+ inToken = false;
243
+ }
244
+ continue;
245
+ }
246
+ current += ch;
247
+ inToken = true;
248
+ }
249
+ if (quote)
250
+ return null; // unbalanced quote
251
+ if (inToken)
252
+ tokens.push(current);
253
+ return tokens;
254
+ }
255
+ /**
256
+ * Look up the arity (number of leading meaningful tokens) for an argv, using the
257
+ * longest-matching-prefix rule against {@link ARITY}. Flag tokens (starting with `-`) are
258
+ * dropped when forming the candidate prefixes so boolean flags like `git --no-pager
259
+ * checkout` still resolve `git checkout`. Unknown binaries default to arity 0 → just the
260
+ * binary.
261
+ *
262
+ * LIMITATION (intentional, fail-closed): we do NOT maintain a per-flag arity table, so an
263
+ * arg-taking flag leaves its operand in the non-flag stream (e.g. `git -C . checkout` →
264
+ * `git .`). That simply fails to match an approved `git checkout` and re-prompts — safe, by
265
+ * design — rather than risking a mis-classification that mis-approves.
266
+ *
267
+ * Returns the list of meaningful tokens (binary + subcommands), flag tokens excluded.
268
+ */
269
+ export function meaningfulPrefixTokens(argv) {
270
+ // Drop leading flags before the binary cannot happen (binary is first), but a binary
271
+ // can be followed by flags interleaved with subcommands (e.g. `git -C . checkout`).
272
+ // Build the flag-free token sequence first, preserving order.
273
+ const nonFlag = argv.filter((t) => !t.startsWith('-'));
274
+ if (nonFlag.length === 0)
275
+ return [];
276
+ // Longest matching prefix in the arity table wins.
277
+ for (let len = nonFlag.length; len > 0; len--) {
278
+ const candidate = nonFlag.slice(0, len).join(' ');
279
+ const arity = ARITY[candidate];
280
+ if (arity !== undefined) {
281
+ // arity counts meaningful tokens from the start of the non-flag sequence.
282
+ return nonFlag.slice(0, Math.min(arity, nonFlag.length));
283
+ }
284
+ }
285
+ // Not in the table → arity 0 means "just the binary".
286
+ return nonFlag.slice(0, 1);
287
+ }
288
+ /**
289
+ * Classify a command into a stable allow-list prefix + display pattern, or `null` when it
290
+ * cannot be safely classified for matching (composition/redirection/substitution present,
291
+ * empty, or unbalanced quotes).
292
+ *
293
+ * @param command Raw command string as the model proposed it.
294
+ * @param normalize Normalizer to apply for the detection form (inject normalizeCommand).
295
+ */
296
+ export function classifyCommand(command, normalize) {
297
+ const normalized = normalize(command);
298
+ if (!normalized)
299
+ return null;
300
+ // FAIL-CLOSED on any composition/redirection/substitution. This is the anti-injection
301
+ // guarantee: such commands never auto-match an allow-list entry.
302
+ if (hasUnsafeComposition(normalized))
303
+ return null;
304
+ const argv = tokenize(normalized);
305
+ if (!argv || argv.length === 0)
306
+ return null;
307
+ const prefixTokens = meaningfulPrefixTokens(argv);
308
+ if (prefixTokens.length === 0)
309
+ return null;
310
+ const prefix = prefixTokens.join(' ');
311
+ return { prefix, pattern: `${prefix} *` };
312
+ }
313
+ //# sourceMappingURL=arity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arity.js","sourceRoot":"","sources":["../../../src/core/shell/arity.ts"],"names":[],"mappings":"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"}