@a2f0/agent-tool 0.1.53 → 0.1.54
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/package.json +1 -1
- package/src/bun/execute.ts +3 -3
- package/src/permissions/catalog.ts +10 -12
package/package.json
CHANGED
package/src/bun/execute.ts
CHANGED
|
@@ -16,9 +16,9 @@ const USAGE = `Usage:
|
|
|
16
16
|
const EXECUTABLE = /^[\w.+-][\w.+-]*$/;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* An executable whose class asks
|
|
20
|
-
* its classification, an older allowance could
|
|
21
|
-
* are regenerated.
|
|
19
|
+
* An executable whose class asks must have no generated allow rule. If the recorded rules
|
|
20
|
+
* predate its classification, an older allowance could preauthorize it, so refuse until
|
|
21
|
+
* they are regenerated.
|
|
22
22
|
*/
|
|
23
23
|
function assertCurrentRules(root: string, command: string): void {
|
|
24
24
|
if (!existsSync(path.join(root, ".agent-tool-permissions.json"))) return;
|
|
@@ -42,12 +42,6 @@ export const CATALOG: CatalogEntry[] = [
|
|
|
42
42
|
// `bun x` runs only executables that `permissions.executables` classifies; project.ts adds those.
|
|
43
43
|
// Package scripts are not classified, so `bun run` keeps the harness default.
|
|
44
44
|
|
|
45
|
-
/** Direct spellings of classified actions. Codex prompts for them, so a raw command cannot bypass its agent-tool form. */
|
|
46
|
-
export const GUARDS: { command: string; class: PermissionClass }[] = [
|
|
47
|
-
...["bun add", "bun a", "npm install", "npm i", "npm add", "pnpm add", "yarn add", "bunx", "bun x", "npx"].map(command => ({ command, class: "intake" as const })),
|
|
48
|
-
...["gh pr merge", "npm publish", "bun publish"].map(command => ({ command, class: "release" as const })),
|
|
49
|
-
];
|
|
50
|
-
|
|
51
45
|
/** How agents invoke an installed agent-tool: the package script, the bin link, or PATH. */
|
|
52
46
|
export const INVOCATIONS = ["bun run agent-tool", "node_modules/.bin/agent-tool", "agent-tool"];
|
|
53
47
|
|
|
@@ -83,30 +77,34 @@ export function claudePermissions(project: CatalogEntry[] = []): ClaudePermissio
|
|
|
83
77
|
const quote = (value: string) => JSON.stringify(value);
|
|
84
78
|
const element = (values: string[]) => values.length === 1 ? quote(values[0]!) : `[${values.map(quote).join(", ")}]`;
|
|
85
79
|
|
|
86
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Only allow rules are generated, as for Claude. Codex's explicit prompt rules
|
|
82
|
+
* reject commands when approval_policy is never, even with danger-full-access.
|
|
83
|
+
* Asking classes stay unlisted so the user's approval and sandbox policies apply.
|
|
84
|
+
*/
|
|
87
85
|
export function codexRules(project: CatalogEntry[] = []): string {
|
|
88
86
|
const lines = [
|
|
89
87
|
"# Managed by agent-tool; regenerate with `agent-tool permissions install --apply`.",
|
|
90
|
-
"#
|
|
91
|
-
"#
|
|
88
|
+
"# Only routine commands receive allow rules. Other commands keep the user's",
|
|
89
|
+
"# approval and sandbox policies; explicit prompts would reject them in never mode.",
|
|
90
|
+
"# A command whose --apply form asks gets no rule, since prefixes also match --apply.",
|
|
92
91
|
"# Equal decisions group under the applied effect, not the read-only preview.",
|
|
93
92
|
];
|
|
94
93
|
const groups = new Map<string, { prefix: string[]; last: string[]; class: PermissionClass }>();
|
|
95
94
|
const add = (tokens: string[], value: PermissionClass) => {
|
|
95
|
+
if (CLASSES[value].decision !== "allow") return;
|
|
96
96
|
const prefix = tokens.slice(0, -1), key = `${value}\0${prefix.join("\0")}`;
|
|
97
97
|
const group = groups.get(key) ?? { prefix, last: [], class: value };
|
|
98
98
|
group.last.push(tokens.at(-1)!); groups.set(key, group);
|
|
99
99
|
};
|
|
100
100
|
for (const invocation of INVOCATIONS) for (const entry of [...CATALOG, ...project]) add([...invocation.split(" "), ...entry.command.split(" ")], strictest(entry));
|
|
101
|
-
for (const guard of GUARDS) add(guard.command.split(" "), guard.class);
|
|
102
101
|
for (const value of Object.keys(CLASSES) as PermissionClass[]) {
|
|
103
102
|
const rules = [...groups.values()].filter(group => group.class === value);
|
|
104
103
|
if (!rules.length) continue;
|
|
105
104
|
lines.push("", `# ${value}: ${CLASSES[value].description}`);
|
|
106
105
|
for (const rule of rules) {
|
|
107
106
|
const pattern = [...rule.prefix.map(quote), element(rule.last)].join(", ");
|
|
108
|
-
|
|
109
|
-
lines.push(`prefix_rule(pattern=[${pattern}], ${reason}, match=[${quote([...rule.prefix, rule.last[0]!].join(" "))}])`);
|
|
107
|
+
lines.push(`prefix_rule(pattern=[${pattern}], decision="allow", match=[${quote([...rule.prefix, rule.last[0]!].join(" "))}])`);
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
110
|
return `${lines.join("\n")}\n`;
|