hoomanjs 1.35.3 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -13
- package/dist/acp/acp-agent.d.ts +40 -66
- package/dist/acp/acp-agent.js +786 -398
- package/dist/acp/acp-agent.js.map +1 -1
- package/dist/acp/approvals.d.ts +2 -2
- package/dist/acp/approvals.js +66 -58
- package/dist/acp/approvals.js.map +1 -1
- package/dist/acp/commands.d.ts +20 -0
- package/dist/acp/commands.js +66 -0
- package/dist/acp/commands.js.map +1 -0
- package/dist/acp/index.d.ts +1 -1
- package/dist/acp/index.js +1 -1
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/mcp-servers.js +14 -8
- package/dist/acp/mcp-servers.js.map +1 -1
- package/dist/acp/prompt-invoke.js +103 -49
- package/dist/acp/prompt-invoke.js.map +1 -1
- package/dist/acp/session-config.d.ts +18 -0
- package/dist/acp/session-config.js +52 -0
- package/dist/acp/session-config.js.map +1 -0
- package/dist/acp/sessions/replay.d.ts +2 -2
- package/dist/acp/sessions/replay.js +28 -44
- package/dist/acp/sessions/replay.js.map +1 -1
- package/dist/acp/sessions/store.d.ts +4 -0
- package/dist/acp/sessions/store.js +5 -1
- package/dist/acp/sessions/store.js.map +1 -1
- package/dist/acp/utils/tool-kind.js +2 -2
- package/dist/acp/utils/tool-kind.js.map +1 -1
- package/dist/acp/utils/tool-result-content.d.ts +7 -0
- package/dist/acp/utils/tool-result-content.js +18 -0
- package/dist/acp/utils/tool-result-content.js.map +1 -1
- package/dist/chat/app.js +117 -1
- package/dist/chat/app.js.map +1 -1
- package/dist/chat/components/BottomChrome.d.ts +2 -1
- package/dist/chat/components/BottomChrome.js +2 -2
- package/dist/chat/components/BottomChrome.js.map +1 -1
- package/dist/chat/components/ReasoningStrip.js +3 -1
- package/dist/chat/components/ReasoningStrip.js.map +1 -1
- package/dist/chat/components/StatusBar.d.ts +2 -1
- package/dist/chat/components/StatusBar.js +18 -3
- package/dist/chat/components/StatusBar.js.map +1 -1
- package/dist/chat/components/ThoughtEvent.d.ts +3 -1
- package/dist/chat/components/ThoughtEvent.js +6 -2
- package/dist/chat/components/ThoughtEvent.js.map +1 -1
- package/dist/chat/components/Transcript.d.ts +5 -2
- package/dist/chat/components/Transcript.js +4 -4
- package/dist/chat/components/Transcript.js.map +1 -1
- package/dist/chat/components/markdown/CodeBlock.js.map +1 -1
- package/dist/cli.js +24 -1
- package/dist/cli.js.map +1 -1
- package/dist/configure/app.js +287 -64
- package/dist/configure/app.js.map +1 -1
- package/dist/configure/components/MenuScreen.js +29 -5
- package/dist/configure/components/MenuScreen.js.map +1 -1
- package/dist/configure/types.d.ts +8 -2
- package/dist/core/agent/index.js +17 -4
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/approvals/allowlist.d.ts +52 -0
- package/dist/core/approvals/allowlist.js +265 -0
- package/dist/core/approvals/allowlist.js.map +1 -0
- package/dist/core/approvals/bash-arity.d.ts +10 -0
- package/dist/core/approvals/bash-arity.js +178 -0
- package/dist/core/approvals/bash-arity.js.map +1 -0
- package/dist/core/approvals/intervention.d.ts +1 -2
- package/dist/core/approvals/intervention.js +5 -20
- package/dist/core/approvals/intervention.js.map +1 -1
- package/dist/core/approvals/wildcard.d.ts +14 -0
- package/dist/core/approvals/wildcard.js +27 -0
- package/dist/core/approvals/wildcard.js.map +1 -0
- package/dist/core/config.d.ts +352 -22
- package/dist/core/config.js +40 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/models/anthropic.d.ts +7 -1
- package/dist/core/models/anthropic.js +36 -7
- package/dist/core/models/anthropic.js.map +1 -1
- package/dist/core/models/azure.js +13 -0
- package/dist/core/models/azure.js.map +1 -1
- package/dist/core/models/bedrock.js +33 -0
- package/dist/core/models/bedrock.js.map +1 -1
- package/dist/core/models/google.js +5 -0
- package/dist/core/models/google.js.map +1 -1
- package/dist/core/models/groq.js +14 -0
- package/dist/core/models/groq.js.map +1 -1
- package/dist/core/models/minimax.js +2 -2
- package/dist/core/models/minimax.js.map +1 -1
- package/dist/core/models/moonshot.js +5 -0
- package/dist/core/models/moonshot.js.map +1 -1
- package/dist/core/models/ollama/index.js +5 -3
- package/dist/core/models/ollama/index.js.map +1 -1
- package/dist/core/models/openai.js +21 -1
- package/dist/core/models/openai.js.map +1 -1
- package/dist/core/models/openrouter.d.ts +2 -2
- package/dist/core/models/openrouter.js +28 -10
- package/dist/core/models/openrouter.js.map +1 -1
- package/dist/core/models/types.d.ts +759 -51
- package/dist/core/models/types.js +43 -7
- package/dist/core/models/types.js.map +1 -1
- package/dist/core/models/xai.js +12 -0
- package/dist/core/models/xai.js.map +1 -1
- package/dist/core/session-config.d.ts +10 -1
- package/dist/core/session-config.js +16 -0
- package/dist/core/session-config.js.map +1 -1
- package/dist/core/skills/built-in/hooman-config/SKILL.md +20 -12
- package/dist/core/state/file-tool-display.d.ts +6 -0
- package/dist/core/state/file-tool-display.js.map +1 -1
- package/dist/core/state/todos.d.ts +11 -0
- package/dist/core/state/todos.js +2 -0
- package/dist/core/state/todos.js.map +1 -1
- package/dist/core/state/tool-approvals.d.ts +6 -7
- package/dist/core/state/tool-approvals.js +7 -50
- package/dist/core/state/tool-approvals.js.map +1 -1
- package/dist/core/tools/filesystem.js +83 -27
- package/dist/core/tools/filesystem.js.map +1 -1
- package/dist/core/tools/shell.js +39 -0
- package/dist/core/tools/shell.js.map +1 -1
- package/dist/core/tools/terminal-backend.d.ts +41 -0
- package/dist/core/tools/terminal-backend.js +9 -0
- package/dist/core/tools/terminal-backend.js.map +1 -0
- package/dist/core/tools/text-fs-backend.d.ts +25 -0
- package/dist/core/tools/text-fs-backend.js +9 -0
- package/dist/core/tools/text-fs-backend.js.map +1 -0
- package/dist/core/tools/todo.d.ts +1 -0
- package/dist/core/tools/todo.js +2 -1
- package/dist/core/tools/todo.js.map +1 -1
- package/dist/core/tools/web-search.js +56 -1
- package/dist/core/tools/web-search.js.map +1 -1
- package/dist/core/utils/attachments.js.map +1 -1
- package/dist/core/utils/paths.d.ts +1 -0
- package/dist/core/utils/paths.js +1 -0
- package/dist/core/utils/paths.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/acp/sessions/options.d.ts +0 -10
- package/dist/acp/sessions/options.js +0 -89
- package/dist/acp/sessions/options.js.map +0 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { allowlistJsonPath } from "../utils/paths.js";
|
|
4
|
+
import { normalizeUserPath } from "../utils/normalize-user-path.js";
|
|
5
|
+
import { arityPrefix, splitCommands, tokenize } from "./bash-arity.js";
|
|
6
|
+
import { matchWildcard } from "./wildcard.js";
|
|
7
|
+
/** Sentinel resource/pattern meaning "the whole tool" (no argument dimension). */
|
|
8
|
+
const TOOL_WIDE = "*";
|
|
9
|
+
const SHELL_TOOL = "shell";
|
|
10
|
+
/**
|
|
11
|
+
* Input keys that carry filesystem paths, per tool. When present, "always
|
|
12
|
+
* allow" is scoped to those exact paths instead of the whole tool.
|
|
13
|
+
*/
|
|
14
|
+
const PATH_TOOL_KEYS = {
|
|
15
|
+
read_file: ["path"],
|
|
16
|
+
read_multiple_files: ["paths"],
|
|
17
|
+
write_file: ["path"],
|
|
18
|
+
edit_file: ["path"],
|
|
19
|
+
create_directory: ["path"],
|
|
20
|
+
move_file: ["source", "destination"],
|
|
21
|
+
get_file_info: ["path"],
|
|
22
|
+
};
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
/** Pull the raw command strings out of the shell tool's flexible input. */
|
|
27
|
+
function extractShellCommands(input) {
|
|
28
|
+
if (!isRecord(input)) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const raw = input.command;
|
|
32
|
+
const entries = Array.isArray(raw) ? raw : [raw];
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
if (typeof entry === "string") {
|
|
36
|
+
if (entry.trim()) {
|
|
37
|
+
out.push(entry.trim());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (isRecord(entry) &&
|
|
41
|
+
typeof entry.command === "string" &&
|
|
42
|
+
entry.command.trim()) {
|
|
43
|
+
out.push(entry.command.trim());
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/** Resolve the filesystem path(s) referenced by a path-bearing tool. */
|
|
49
|
+
function extractPaths(tool, input) {
|
|
50
|
+
const keys = PATH_TOOL_KEYS[tool];
|
|
51
|
+
if (!keys) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (!isRecord(input)) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const paths = [];
|
|
58
|
+
for (const key of keys) {
|
|
59
|
+
const value = input[key];
|
|
60
|
+
if (typeof value === "string" && value.trim()) {
|
|
61
|
+
paths.push(normalizeUserPath(value));
|
|
62
|
+
}
|
|
63
|
+
else if (Array.isArray(value)) {
|
|
64
|
+
for (const item of value) {
|
|
65
|
+
if (typeof item === "string" && item.trim()) {
|
|
66
|
+
paths.push(normalizeUserPath(item));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return paths;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Reduce a tool call to the resource strings that a rule must match. Shell
|
|
75
|
+
* calls yield one string per sub-command; path tools yield resolved paths;
|
|
76
|
+
* everything else is treated as tool-wide.
|
|
77
|
+
*/
|
|
78
|
+
function deriveResources(tool, input) {
|
|
79
|
+
if (tool === SHELL_TOOL) {
|
|
80
|
+
const segments = extractShellCommands(input).flatMap(splitCommands);
|
|
81
|
+
return {
|
|
82
|
+
kind: "command",
|
|
83
|
+
values: segments.length > 0 ? segments : [TOOL_WIDE],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const paths = extractPaths(tool, input);
|
|
87
|
+
if (paths) {
|
|
88
|
+
return { kind: "path", values: paths.length > 0 ? paths : [TOOL_WIDE] };
|
|
89
|
+
}
|
|
90
|
+
return { kind: "generic", values: [TOOL_WIDE] };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Given a tool call, propose the reusable patterns that "always allow" should
|
|
94
|
+
* persist. Shell commands are broadened via {@link arityPrefix} (`git log *`);
|
|
95
|
+
* path tools keep the exact resolved path; other tools become tool-wide.
|
|
96
|
+
*/
|
|
97
|
+
function deriveProposals(tool, input) {
|
|
98
|
+
const { kind, values } = deriveResources(tool, input);
|
|
99
|
+
if (kind === "command") {
|
|
100
|
+
const patterns = new Set();
|
|
101
|
+
for (const segment of values) {
|
|
102
|
+
if (segment === TOOL_WIDE) {
|
|
103
|
+
patterns.add(TOOL_WIDE);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const prefix = arityPrefix(tokenize(segment));
|
|
107
|
+
patterns.add(prefix.length > 0 ? `${prefix.join(" ")} *` : TOOL_WIDE);
|
|
108
|
+
}
|
|
109
|
+
return [...patterns];
|
|
110
|
+
}
|
|
111
|
+
if (kind === "path") {
|
|
112
|
+
return [...new Set(values)];
|
|
113
|
+
}
|
|
114
|
+
return [TOOL_WIDE];
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Disk-backed, pattern-based allowlist for "always allow" tool approvals.
|
|
118
|
+
*
|
|
119
|
+
* Rules are keyed by tool name and matched against an argument-derived
|
|
120
|
+
* resource string using {@link matchWildcard}. The design follows the
|
|
121
|
+
* opencode/kilocode/Claude Code permission engines: shell commands match on a
|
|
122
|
+
* (broadened) command prefix, filesystem tools match on resolved paths, and
|
|
123
|
+
* argument-less tools are stored tool-wide (`*`).
|
|
124
|
+
*/
|
|
125
|
+
export class Allowlist {
|
|
126
|
+
filePath;
|
|
127
|
+
/** tool name -> set of allowed argument patterns */
|
|
128
|
+
store = new Map();
|
|
129
|
+
constructor(options) {
|
|
130
|
+
this.filePath = options?.filePath ?? allowlistJsonPath();
|
|
131
|
+
this.load();
|
|
132
|
+
}
|
|
133
|
+
/** Whether a tool call is already covered by a persisted allow rule. */
|
|
134
|
+
isAllowed(tool, input) {
|
|
135
|
+
const patterns = this.store.get(tool);
|
|
136
|
+
if (!patterns || patterns.size === 0) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const { values } = deriveResources(tool, input);
|
|
140
|
+
return values.every((resource) => [...patterns].some((pattern) => matchWildcard(resource, pattern)));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Preview the patterns that {@link allowAlways} would persist for a tool
|
|
144
|
+
* call, without writing anything. Useful for showing the user what "always
|
|
145
|
+
* allow" will grant.
|
|
146
|
+
*/
|
|
147
|
+
proposals(tool, input) {
|
|
148
|
+
return deriveProposals(tool, input);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Persist "always allow" for a tool call. Returns the patterns that were
|
|
152
|
+
* newly added (already-present patterns are skipped).
|
|
153
|
+
*/
|
|
154
|
+
allowAlways(tool, input) {
|
|
155
|
+
const added = [];
|
|
156
|
+
for (const pattern of deriveProposals(tool, input)) {
|
|
157
|
+
if (this.addPattern(tool, pattern)) {
|
|
158
|
+
added.push(pattern);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (added.length > 0) {
|
|
162
|
+
this.persist();
|
|
163
|
+
}
|
|
164
|
+
return added;
|
|
165
|
+
}
|
|
166
|
+
/** Add an explicit rule. Returns true if it was not already present. */
|
|
167
|
+
addRule(tool, pattern) {
|
|
168
|
+
const added = this.addPattern(tool, pattern);
|
|
169
|
+
if (added) {
|
|
170
|
+
this.persist();
|
|
171
|
+
}
|
|
172
|
+
return added;
|
|
173
|
+
}
|
|
174
|
+
/** Remove an explicit rule. Returns true if it existed. */
|
|
175
|
+
removeRule(tool, pattern) {
|
|
176
|
+
const patterns = this.store.get(tool);
|
|
177
|
+
if (!patterns?.delete(pattern.trim())) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
if (patterns.size === 0) {
|
|
181
|
+
this.store.delete(tool);
|
|
182
|
+
}
|
|
183
|
+
this.persist();
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
/** All persisted rules, flattened. */
|
|
187
|
+
rules() {
|
|
188
|
+
const rules = [];
|
|
189
|
+
for (const [tool, patterns] of this.store) {
|
|
190
|
+
for (const pattern of patterns) {
|
|
191
|
+
rules.push({ tool, pattern });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return rules;
|
|
195
|
+
}
|
|
196
|
+
/** Remove every rule and persist the empty allowlist. */
|
|
197
|
+
clear() {
|
|
198
|
+
this.store.clear();
|
|
199
|
+
this.persist();
|
|
200
|
+
}
|
|
201
|
+
/** Re-read the allowlist from disk, discarding in-memory state. */
|
|
202
|
+
reload() {
|
|
203
|
+
this.load();
|
|
204
|
+
}
|
|
205
|
+
addPattern(tool, pattern) {
|
|
206
|
+
const toolName = tool.trim();
|
|
207
|
+
const normalized = pattern.trim();
|
|
208
|
+
if (!toolName || !normalized) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
let patterns = this.store.get(toolName);
|
|
212
|
+
if (!patterns) {
|
|
213
|
+
patterns = new Set();
|
|
214
|
+
this.store.set(toolName, patterns);
|
|
215
|
+
}
|
|
216
|
+
if (patterns.has(normalized)) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
patterns.add(normalized);
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
load() {
|
|
223
|
+
this.store.clear();
|
|
224
|
+
if (!existsSync(this.filePath)) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
let parsed;
|
|
228
|
+
try {
|
|
229
|
+
parsed = JSON.parse(readFileSync(this.filePath, "utf8"));
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (!isRecord(parsed)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
for (const [tool, value] of Object.entries(parsed)) {
|
|
238
|
+
if (!Array.isArray(value)) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
for (const pattern of value) {
|
|
242
|
+
if (typeof pattern === "string") {
|
|
243
|
+
this.addPattern(tool, pattern);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
persist() {
|
|
249
|
+
const data = {};
|
|
250
|
+
for (const [tool, patterns] of this.store) {
|
|
251
|
+
data[tool] = [...patterns];
|
|
252
|
+
}
|
|
253
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
254
|
+
writeFileSync(this.filePath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
let sharedAllowlist = null;
|
|
258
|
+
/** Process-wide {@link Allowlist} backed by `~/.hooman/allowlist.json`. */
|
|
259
|
+
export function getAllowlist() {
|
|
260
|
+
if (!sharedAllowlist) {
|
|
261
|
+
sharedAllowlist = new Allowlist();
|
|
262
|
+
}
|
|
263
|
+
return sharedAllowlist;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=allowlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowlist.js","sourceRoot":"","sources":["../../../src/core/approvals/allowlist.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Split a (possibly compound) command into its individual sub-commands. */
|
|
2
|
+
export declare function splitCommands(command: string): string[];
|
|
3
|
+
/** Naive whitespace tokenizer — sufficient for deriving a command prefix. */
|
|
4
|
+
export declare function tokenize(command: string): string[];
|
|
5
|
+
/**
|
|
6
|
+
* Return the leading tokens that identify the command, using the arity
|
|
7
|
+
* dictionary. Longest listed prefix wins; unknown commands fall back to their
|
|
8
|
+
* first token.
|
|
9
|
+
*/
|
|
10
|
+
export declare function arityPrefix(tokens: string[]): string[];
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "BashArity": maps a command prefix to the number of leading tokens that
|
|
3
|
+
* define the human-meaningful command, so that approving one command with
|
|
4
|
+
* "always allow" can propose a reusable pattern instead of the exact string.
|
|
5
|
+
*
|
|
6
|
+
* Example: approving `git log --oneline -5` proposes `git log *` because
|
|
7
|
+
* `git` has an arity of 2 (the subcommand counts, flags never do).
|
|
8
|
+
*
|
|
9
|
+
* Dictionary ported from the opencode/kilocode permission engines. Longest
|
|
10
|
+
* matching prefix wins; unlisted commands fall back to a single token.
|
|
11
|
+
*/
|
|
12
|
+
const ARITY = {
|
|
13
|
+
cat: 1,
|
|
14
|
+
cd: 1,
|
|
15
|
+
chmod: 1,
|
|
16
|
+
chown: 1,
|
|
17
|
+
cp: 1,
|
|
18
|
+
echo: 1,
|
|
19
|
+
env: 1,
|
|
20
|
+
export: 1,
|
|
21
|
+
grep: 1,
|
|
22
|
+
kill: 1,
|
|
23
|
+
killall: 1,
|
|
24
|
+
ln: 1,
|
|
25
|
+
ls: 1,
|
|
26
|
+
mkdir: 1,
|
|
27
|
+
mv: 1,
|
|
28
|
+
ps: 1,
|
|
29
|
+
pwd: 1,
|
|
30
|
+
rm: 1,
|
|
31
|
+
rmdir: 1,
|
|
32
|
+
sleep: 1,
|
|
33
|
+
source: 1,
|
|
34
|
+
tail: 1,
|
|
35
|
+
touch: 1,
|
|
36
|
+
unset: 1,
|
|
37
|
+
which: 1,
|
|
38
|
+
aws: 3,
|
|
39
|
+
az: 3,
|
|
40
|
+
bazel: 2,
|
|
41
|
+
brew: 2,
|
|
42
|
+
bun: 2,
|
|
43
|
+
"bun run": 3,
|
|
44
|
+
"bun x": 3,
|
|
45
|
+
cargo: 2,
|
|
46
|
+
"cargo add": 3,
|
|
47
|
+
"cargo run": 3,
|
|
48
|
+
cdk: 2,
|
|
49
|
+
cf: 2,
|
|
50
|
+
cmake: 2,
|
|
51
|
+
composer: 2,
|
|
52
|
+
consul: 2,
|
|
53
|
+
"consul kv": 3,
|
|
54
|
+
crictl: 2,
|
|
55
|
+
deno: 2,
|
|
56
|
+
"deno task": 3,
|
|
57
|
+
doctl: 3,
|
|
58
|
+
docker: 2,
|
|
59
|
+
"docker builder": 3,
|
|
60
|
+
"docker compose": 3,
|
|
61
|
+
"docker container": 3,
|
|
62
|
+
"docker image": 3,
|
|
63
|
+
"docker network": 3,
|
|
64
|
+
"docker volume": 3,
|
|
65
|
+
eksctl: 2,
|
|
66
|
+
"eksctl create": 3,
|
|
67
|
+
firebase: 2,
|
|
68
|
+
flyctl: 2,
|
|
69
|
+
gcloud: 3,
|
|
70
|
+
gh: 3,
|
|
71
|
+
git: 2,
|
|
72
|
+
"git config": 3,
|
|
73
|
+
"git remote": 3,
|
|
74
|
+
"git stash": 3,
|
|
75
|
+
go: 2,
|
|
76
|
+
gradle: 2,
|
|
77
|
+
helm: 2,
|
|
78
|
+
heroku: 2,
|
|
79
|
+
hugo: 2,
|
|
80
|
+
ip: 2,
|
|
81
|
+
"ip addr": 3,
|
|
82
|
+
"ip link": 3,
|
|
83
|
+
"ip netns": 3,
|
|
84
|
+
"ip route": 3,
|
|
85
|
+
kind: 2,
|
|
86
|
+
"kind create": 3,
|
|
87
|
+
kubectl: 2,
|
|
88
|
+
"kubectl kustomize": 3,
|
|
89
|
+
"kubectl rollout": 3,
|
|
90
|
+
kustomize: 2,
|
|
91
|
+
make: 2,
|
|
92
|
+
mc: 2,
|
|
93
|
+
"mc admin": 3,
|
|
94
|
+
minikube: 2,
|
|
95
|
+
mongosh: 2,
|
|
96
|
+
mysql: 2,
|
|
97
|
+
mvn: 2,
|
|
98
|
+
ng: 2,
|
|
99
|
+
npm: 2,
|
|
100
|
+
"npm exec": 3,
|
|
101
|
+
"npm init": 3,
|
|
102
|
+
"npm run": 3,
|
|
103
|
+
"npm view": 3,
|
|
104
|
+
nvm: 2,
|
|
105
|
+
nx: 2,
|
|
106
|
+
openssl: 2,
|
|
107
|
+
"openssl req": 3,
|
|
108
|
+
"openssl x509": 3,
|
|
109
|
+
pip: 2,
|
|
110
|
+
pipenv: 2,
|
|
111
|
+
pnpm: 2,
|
|
112
|
+
"pnpm dlx": 3,
|
|
113
|
+
"pnpm exec": 3,
|
|
114
|
+
"pnpm run": 3,
|
|
115
|
+
poetry: 2,
|
|
116
|
+
podman: 2,
|
|
117
|
+
"podman container": 3,
|
|
118
|
+
"podman image": 3,
|
|
119
|
+
psql: 2,
|
|
120
|
+
pulumi: 2,
|
|
121
|
+
"pulumi stack": 3,
|
|
122
|
+
pyenv: 2,
|
|
123
|
+
python: 2,
|
|
124
|
+
rake: 2,
|
|
125
|
+
rbenv: 2,
|
|
126
|
+
"redis-cli": 2,
|
|
127
|
+
rustup: 2,
|
|
128
|
+
serverless: 2,
|
|
129
|
+
sfdx: 3,
|
|
130
|
+
skaffold: 2,
|
|
131
|
+
sls: 2,
|
|
132
|
+
sst: 2,
|
|
133
|
+
swift: 2,
|
|
134
|
+
systemctl: 2,
|
|
135
|
+
terraform: 2,
|
|
136
|
+
"terraform workspace": 3,
|
|
137
|
+
tmux: 2,
|
|
138
|
+
turbo: 2,
|
|
139
|
+
ufw: 2,
|
|
140
|
+
vault: 2,
|
|
141
|
+
"vault auth": 3,
|
|
142
|
+
"vault kv": 3,
|
|
143
|
+
vercel: 2,
|
|
144
|
+
volta: 2,
|
|
145
|
+
wp: 2,
|
|
146
|
+
yarn: 2,
|
|
147
|
+
"yarn dlx": 3,
|
|
148
|
+
"yarn run": 3,
|
|
149
|
+
};
|
|
150
|
+
/** Command operators that separate a compound command into sub-commands. */
|
|
151
|
+
const COMMAND_SEPARATORS = /\s*(?:&&|\|\||[;|&\n])\s*/;
|
|
152
|
+
/** Split a (possibly compound) command into its individual sub-commands. */
|
|
153
|
+
export function splitCommands(command) {
|
|
154
|
+
return command
|
|
155
|
+
.split(COMMAND_SEPARATORS)
|
|
156
|
+
.map((part) => part.trim())
|
|
157
|
+
.filter(Boolean);
|
|
158
|
+
}
|
|
159
|
+
/** Naive whitespace tokenizer — sufficient for deriving a command prefix. */
|
|
160
|
+
export function tokenize(command) {
|
|
161
|
+
return command.trim().split(/\s+/).filter(Boolean);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Return the leading tokens that identify the command, using the arity
|
|
165
|
+
* dictionary. Longest listed prefix wins; unknown commands fall back to their
|
|
166
|
+
* first token.
|
|
167
|
+
*/
|
|
168
|
+
export function arityPrefix(tokens) {
|
|
169
|
+
for (let len = tokens.length; len > 0; len--) {
|
|
170
|
+
const candidate = tokens.slice(0, len).join(" ");
|
|
171
|
+
const arity = ARITY[candidate];
|
|
172
|
+
if (arity !== undefined) {
|
|
173
|
+
return tokens.slice(0, arity);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return tokens.length === 0 ? [] : tokens.slice(0, 1);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=bash-arity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-arity.js","sourceRoot":"","sources":["../../../src/core/approvals/bash-arity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,KAAK,GAA2B;IACpC,GAAG,EAAE,CAAC;IACN,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,EAAE,EAAE,CAAC;IACL,IAAI,EAAE,CAAC;IACP,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,CAAC;IACR,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,GAAG,EAAE,CAAC;IACN,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,GAAG,EAAE,CAAC;IACN,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,GAAG,EAAE,CAAC;IACN,SAAS,EAAE,CAAC;IACZ,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,WAAW,EAAE,CAAC;IACd,WAAW,EAAE,CAAC;IACd,GAAG,EAAE,CAAC;IACN,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,CAAC;IACR,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,WAAW,EAAE,CAAC;IACd,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,WAAW,EAAE,CAAC;IACd,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;IACT,gBAAgB,EAAE,CAAC;IACnB,gBAAgB,EAAE,CAAC;IACnB,kBAAkB,EAAE,CAAC;IACrB,cAAc,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC;IACnB,eAAe,EAAE,CAAC;IAClB,MAAM,EAAE,CAAC;IACT,eAAe,EAAE,CAAC;IAClB,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,EAAE,EAAE,CAAC;IACL,GAAG,EAAE,CAAC;IACN,YAAY,EAAE,CAAC;IACf,YAAY,EAAE,CAAC;IACf,WAAW,EAAE,CAAC;IACd,EAAE,EAAE,CAAC;IACL,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,EAAE,EAAE,CAAC;IACL,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,aAAa,EAAE,CAAC;IAChB,OAAO,EAAE,CAAC;IACV,mBAAmB,EAAE,CAAC;IACtB,iBAAiB,EAAE,CAAC;IACpB,SAAS,EAAE,CAAC;IACZ,IAAI,EAAE,CAAC;IACP,EAAE,EAAE,CAAC;IACL,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,GAAG,EAAE,CAAC;IACN,EAAE,EAAE,CAAC;IACL,GAAG,EAAE,CAAC;IACN,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,CAAC;IACZ,UAAU,EAAE,CAAC;IACb,GAAG,EAAE,CAAC;IACN,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;IACjB,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,CAAC;IACd,UAAU,EAAE,CAAC;IACb,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,kBAAkB,EAAE,CAAC;IACrB,cAAc,EAAE,CAAC;IACjB,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,cAAc,EAAE,CAAC;IACjB,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,WAAW,EAAE,CAAC;IACd,MAAM,EAAE,CAAC;IACT,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,CAAC;IACX,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,qBAAqB,EAAE,CAAC;IACxB,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,GAAG,EAAE,CAAC;IACN,KAAK,EAAE,CAAC;IACR,YAAY,EAAE,CAAC;IACf,UAAU,EAAE,CAAC;IACb,MAAM,EAAE,CAAC;IACT,KAAK,EAAE,CAAC;IACR,EAAE,EAAE,CAAC;IACL,IAAI,EAAE,CAAC;IACP,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;CACd,CAAC;AAEF,4EAA4E;AAC5E,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAEvD,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,OAAO;SACX,KAAK,CAAC,kBAAkB,CAAC;SACzB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,MAAgB;IAC1C,KAAK,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InterventionHandler, InterventionActions, type BeforeToolCallEvent
|
|
1
|
+
import { InterventionHandler, InterventionActions, type BeforeToolCallEvent } from "@strands-agents/sdk";
|
|
2
2
|
export type ToolApprovalDecision = "allow" | "always";
|
|
3
3
|
export type ToolApprovalResult = ToolApprovalDecision | "reject" | {
|
|
4
4
|
decision: "reject";
|
|
@@ -30,5 +30,4 @@ export declare class HoomanToolApprovalIntervention extends InterventionHandler
|
|
|
30
30
|
beforeToolCall(event: BeforeToolCallEvent): Promise<ReturnType<typeof InterventionActions.proceed> | ReturnType<typeof InterventionActions.deny>>;
|
|
31
31
|
private buildRequest;
|
|
32
32
|
}
|
|
33
|
-
export declare function normalizeApprovalResponse(response: JSONValue): ToolApprovalResult;
|
|
34
33
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { InterventionHandler, InterventionActions, } from "@strands-agents/sdk";
|
|
2
|
-
import { INTERNAL_ALWAYS_ALLOWED,
|
|
2
|
+
import { INTERNAL_ALWAYS_ALLOWED, isImplicitlyAllowed, planModeWriteEditRejectionMessage, } from "../state/tool-approvals.js";
|
|
3
3
|
import { isYoloEnabled } from "../state/yolo.js";
|
|
4
|
+
import { getAllowlist } from "./allowlist.js";
|
|
4
5
|
const INPUT_PREVIEW_LIMIT = 1_024;
|
|
5
6
|
function previewInput(input) {
|
|
6
7
|
try {
|
|
@@ -42,7 +43,8 @@ export class HoomanToolApprovalIntervention extends InterventionHandler {
|
|
|
42
43
|
}
|
|
43
44
|
if (isYoloEnabled(event.agent) ||
|
|
44
45
|
INTERNAL_ALWAYS_ALLOWED.has(toolName) ||
|
|
45
|
-
|
|
46
|
+
isImplicitlyAllowed(toolName, event.toolUse.input) ||
|
|
47
|
+
getAllowlist().isAllowed(toolName, event.toolUse.input)) {
|
|
46
48
|
await this.onApproved?.(request, event, "auto");
|
|
47
49
|
return InterventionActions.proceed();
|
|
48
50
|
}
|
|
@@ -53,7 +55,7 @@ export class HoomanToolApprovalIntervention extends InterventionHandler {
|
|
|
53
55
|
return InterventionActions.proceed();
|
|
54
56
|
}
|
|
55
57
|
if (result === "always") {
|
|
56
|
-
|
|
58
|
+
getAllowlist().allowAlways(toolName, event.toolUse.input);
|
|
57
59
|
await this.onApproved?.(request, event, "always");
|
|
58
60
|
return InterventionActions.proceed();
|
|
59
61
|
}
|
|
@@ -74,21 +76,4 @@ export class HoomanToolApprovalIntervention extends InterventionHandler {
|
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
|
-
export function normalizeApprovalResponse(response) {
|
|
78
|
-
if (response === true) {
|
|
79
|
-
return "allow";
|
|
80
|
-
}
|
|
81
|
-
if (typeof response === "string") {
|
|
82
|
-
const normalized = response.trim().toLowerCase();
|
|
83
|
-
if (normalized === "y" || normalized === "yes" || normalized === "allow") {
|
|
84
|
-
return "allow";
|
|
85
|
-
}
|
|
86
|
-
if (normalized === "t" ||
|
|
87
|
-
normalized === "trust" ||
|
|
88
|
-
normalized === "always") {
|
|
89
|
-
return "always";
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return "reject";
|
|
93
|
-
}
|
|
94
79
|
//# sourceMappingURL=intervention.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intervention.js","sourceRoot":"","sources":["../../../src/core/approvals/intervention.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"intervention.js","sourceRoot":"","sources":["../../../src/core/approvals/intervention.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal wildcard matcher used by the approval allowlist.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the opencode/kilocode permission engines:
|
|
5
|
+
* - `*` matches zero or more characters
|
|
6
|
+
* - `?` matches exactly one character
|
|
7
|
+
* - a trailing " *" is relaxed to "( .*)?" so a pattern like `git *` also
|
|
8
|
+
* matches the bare `git` command (arguments become optional)
|
|
9
|
+
*
|
|
10
|
+
* Matching is anchored (`^...$`) and treats the input as a single line so `*`
|
|
11
|
+
* spans newlines. Backslashes are normalized to forward slashes so path
|
|
12
|
+
* patterns behave the same on Windows.
|
|
13
|
+
*/
|
|
14
|
+
export declare function matchWildcard(input: string, pattern: string): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal wildcard matcher used by the approval allowlist.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the opencode/kilocode permission engines:
|
|
5
|
+
* - `*` matches zero or more characters
|
|
6
|
+
* - `?` matches exactly one character
|
|
7
|
+
* - a trailing " *" is relaxed to "( .*)?" so a pattern like `git *` also
|
|
8
|
+
* matches the bare `git` command (arguments become optional)
|
|
9
|
+
*
|
|
10
|
+
* Matching is anchored (`^...$`) and treats the input as a single line so `*`
|
|
11
|
+
* spans newlines. Backslashes are normalized to forward slashes so path
|
|
12
|
+
* patterns behave the same on Windows.
|
|
13
|
+
*/
|
|
14
|
+
export function matchWildcard(input, pattern) {
|
|
15
|
+
const normalized = input.replaceAll("\\", "/");
|
|
16
|
+
let escaped = pattern
|
|
17
|
+
.replaceAll("\\", "/")
|
|
18
|
+
.replace(/[.+^${}()|[\]]/g, "\\$&")
|
|
19
|
+
.replace(/\*/g, ".*")
|
|
20
|
+
.replace(/\?/g, ".");
|
|
21
|
+
if (escaped.endsWith(" .*")) {
|
|
22
|
+
escaped = `${escaped.slice(0, -3)}( .*)?`;
|
|
23
|
+
}
|
|
24
|
+
const flags = process.platform === "win32" ? "si" : "s";
|
|
25
|
+
return new RegExp(`^${escaped}$`, flags).test(normalized);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=wildcard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wildcard.js","sourceRoot":"","sources":["../../../src/core/approvals/wildcard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,OAAe;IAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/C,IAAI,OAAO,GAAG,OAAO;SAClB,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC;SAClC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEvB,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC5C,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;IACxD,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC5D,CAAC"}
|