agent-permission 0.1.3 → 0.1.4
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 +6 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -2
- package/dist/install.d.ts +3 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +287 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Give AI agents a permission gate before they touch external URLs.
|
|
|
8
8
|
npx agent-permission install --adapter auto
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
This adds an Agent Permission block to the local agent instruction file, such as `AGENTS.md`, `CLAUDE.md`, or `agent-permission.chatgpt.md`, depending on the selected adapter.
|
|
11
|
+
This adds an Agent Permission block to the local agent instruction file, such as `AGENTS.md`, `CLAUDE.md`, or `agent-permission.chatgpt.md`, depending on the selected adapter. It also writes a tiny project-local runner at `.agent-permission/agent-permission.mjs` so repeated checks do not need npm registry access.
|
|
12
12
|
|
|
13
13
|
To install instructions and configure live checks in one step:
|
|
14
14
|
|
|
@@ -19,8 +19,8 @@ npx agent-permission install --adapter auto --api-key <YOUR_API_KEY>
|
|
|
19
19
|
Add an API key when you want live checks from the command line, CI, or agent runs:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
node .agent-permission/agent-permission.mjs config set api-key <YOUR_API_KEY>
|
|
23
|
+
node .agent-permission/agent-permission.mjs check https://example.com/blog-post --action summarize --exit-code
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
## What the Agent Runs
|
|
@@ -28,15 +28,13 @@ npx -y agent-permission@latest check https://example.com/blog-post --action summ
|
|
|
28
28
|
After install, project instructions tell compatible agents to run:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
|
|
31
|
+
node .agent-permission/agent-permission.mjs check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
If the binary is already available in the agent shell, the same check can also run as:
|
|
34
|
+
If the local runner is missing, the installed instructions tell the agent to use npm as a fallback:
|
|
37
35
|
|
|
38
36
|
```bash
|
|
39
|
-
agent-permission check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
37
|
+
npx -y agent-permission@latest check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
40
38
|
```
|
|
41
39
|
|
|
42
40
|
## Commands
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,EAAyD,KAAK,EAAuD,OAAO,EAAE,MAAM,YAAY,CAAC;AAExJ,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACxC,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA6BzF;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,EAAyD,KAAK,EAAuD,OAAO,EAAE,MAAM,YAAY,CAAC;AAExJ,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACxC,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA6BzF;AAmID,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CA2BtD"}
|
package/dist/cli.js
CHANGED
|
@@ -100,7 +100,10 @@ async function runInstall(args, runtime, io) {
|
|
|
100
100
|
const adapter = parseAdapter(stringFlag(parsed, 'adapter') || parsed.positionals[0] || 'auto');
|
|
101
101
|
const scope = parseScope(stringFlag(parsed, 'scope') || 'project');
|
|
102
102
|
const result = await installAgentInstructions(adapter, scope, runtime);
|
|
103
|
-
const messages = [
|
|
103
|
+
const messages = [
|
|
104
|
+
`Installed Agent Permission instructions for ${result.adapter} at ${result.path}`,
|
|
105
|
+
`Installed local Agent Permission runner at ${result.runnerPath}`,
|
|
106
|
+
];
|
|
104
107
|
const apiKey = stringFlag(parsed, 'api-key');
|
|
105
108
|
if (apiKey) {
|
|
106
109
|
const current = await readConfig(runtime);
|
|
@@ -110,7 +113,7 @@ async function runInstall(args, runtime, io) {
|
|
|
110
113
|
else {
|
|
111
114
|
const config = await resolveConfig(runtime);
|
|
112
115
|
if (!config.apiKey) {
|
|
113
|
-
messages.push(
|
|
116
|
+
messages.push(`API key is not configured. Live checks will fail until you run \`${result.runnerCommand} config set api-key <YOUR_API_KEY>\` or set AGENT_PERMISSION_API_KEY.`, `Verify setup with \`${result.runnerCommand} config doctor\`.`);
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
io.stdout(messages.join('\n'));
|
package/dist/install.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { Adapter, InstallScope, Runtime } from './types.js';
|
|
|
2
2
|
export interface InstallResult {
|
|
3
3
|
adapter: Exclude<Adapter, 'auto'>;
|
|
4
4
|
path: string;
|
|
5
|
+
runnerPath: string;
|
|
6
|
+
runnerCommand: string;
|
|
5
7
|
}
|
|
6
8
|
export declare function installAgentInstructions(adapter: Adapter, scope: InstallScope, runtime: Runtime): Promise<InstallResult>;
|
|
7
9
|
export declare function upsertBlock(existing: string, blockBody: string): string;
|
|
8
|
-
export declare function buildInstructionBlock(adapter: Exclude<Adapter, 'auto'
|
|
10
|
+
export declare function buildInstructionBlock(adapter: Exclude<Adapter, 'auto'>, runnerCommand?: string): string;
|
|
9
11
|
//# sourceMappingURL=install.d.ts.map
|
package/dist/install.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAmB,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM7E,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAgB9H;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAU9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,SAAgC,UA2BrH"}
|
package/dist/install.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
+
import { DEFAULT_API_URL } from './types.js';
|
|
3
4
|
const BLOCK_START = '<!-- BEGIN:agent-permission -->';
|
|
4
5
|
const BLOCK_END = '<!-- END:agent-permission -->';
|
|
6
|
+
const PROJECT_RUNNER_PATH = '.agent-permission/agent-permission.mjs';
|
|
5
7
|
export async function installAgentInstructions(adapter, scope, runtime) {
|
|
6
8
|
const resolved = adapter === 'auto' ? await detectAdapter(runtime) : adapter;
|
|
7
9
|
const path = getInstructionPath(resolved, scope, runtime);
|
|
10
|
+
const runner = getRunnerPath(scope, runtime);
|
|
11
|
+
const runnerCommand = getRunnerCommand(scope, runner);
|
|
8
12
|
const existing = await readFile(path, 'utf8').catch((err) => {
|
|
9
13
|
if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT')
|
|
10
14
|
return '';
|
|
11
15
|
throw err;
|
|
12
16
|
});
|
|
13
|
-
const next = upsertBlock(existing, buildInstructionBlock(resolved));
|
|
17
|
+
const next = upsertBlock(existing, buildInstructionBlock(resolved, runnerCommand));
|
|
14
18
|
await mkdir(dirname(path), { recursive: true });
|
|
19
|
+
await writeLocalRunner(runner);
|
|
15
20
|
await writeFile(path, next);
|
|
16
|
-
return { adapter: resolved, path };
|
|
21
|
+
return { adapter: resolved, path, runnerPath: runner, runnerCommand };
|
|
17
22
|
}
|
|
18
23
|
export function upsertBlock(existing, blockBody) {
|
|
19
24
|
const block = `${BLOCK_START}\n${blockBody.trim()}\n${BLOCK_END}`;
|
|
@@ -24,7 +29,7 @@ export function upsertBlock(existing, blockBody) {
|
|
|
24
29
|
const prefix = existing.trimEnd();
|
|
25
30
|
return prefix ? `${prefix}\n\n${block}\n` : `${block}\n`;
|
|
26
31
|
}
|
|
27
|
-
export function buildInstructionBlock(adapter) {
|
|
32
|
+
export function buildInstructionBlock(adapter, runnerCommand = `node ${PROJECT_RUNNER_PATH}`) {
|
|
28
33
|
const agentName = {
|
|
29
34
|
codex: 'Codex',
|
|
30
35
|
claude: 'Claude',
|
|
@@ -38,13 +43,13 @@ These instructions equip ${agentName} with Agent Permission preflight checks.
|
|
|
38
43
|
Before crawling, summarizing, extracting, training on, transacting with, or posting to a URL, run:
|
|
39
44
|
|
|
40
45
|
\`\`\`bash
|
|
41
|
-
|
|
46
|
+
${runnerCommand} check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
42
47
|
\`\`\`
|
|
43
48
|
|
|
44
|
-
If the
|
|
49
|
+
If the local runner is missing, run the same check through npm:
|
|
45
50
|
|
|
46
51
|
\`\`\`bash
|
|
47
|
-
agent-permission check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
52
|
+
npx -y agent-permission@latest check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
48
53
|
\`\`\`
|
|
49
54
|
|
|
50
55
|
Use \`crawl\` for fetching or indexing pages, \`summarize\` for compacting page content, \`extract\` for structured data pulls, \`train\` for model training or dataset creation, \`transact\` for purchase/account-changing actions, and \`post\` for creating or modifying remote content.
|
|
@@ -78,6 +83,27 @@ function getInstructionPath(adapter, scope, runtime) {
|
|
|
78
83
|
return join(runtime.cwd, 'AGENTS.md');
|
|
79
84
|
return join(runtime.cwd, 'AGENTS.md');
|
|
80
85
|
}
|
|
86
|
+
function getRunnerPath(scope, runtime) {
|
|
87
|
+
if (scope === 'user') {
|
|
88
|
+
const home = runtime.homeDir || runtime.env.HOME || runtime.env.USERPROFILE || runtime.cwd;
|
|
89
|
+
const base = runtime.env.XDG_CONFIG_HOME || join(home, '.config');
|
|
90
|
+
return join(base, 'agent-permission', 'agent-permission.mjs');
|
|
91
|
+
}
|
|
92
|
+
return join(runtime.cwd, PROJECT_RUNNER_PATH);
|
|
93
|
+
}
|
|
94
|
+
function getRunnerCommand(scope, runnerPath) {
|
|
95
|
+
if (scope === 'user') {
|
|
96
|
+
return `node ${shellQuote(runnerPath)}`;
|
|
97
|
+
}
|
|
98
|
+
return `node ${PROJECT_RUNNER_PATH}`;
|
|
99
|
+
}
|
|
100
|
+
async function writeLocalRunner(path) {
|
|
101
|
+
await mkdir(dirname(path), { recursive: true });
|
|
102
|
+
await writeFile(path, buildLocalRunner(), { mode: 0o644 });
|
|
103
|
+
}
|
|
104
|
+
function shellQuote(value) {
|
|
105
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
106
|
+
}
|
|
81
107
|
async function fileExists(path) {
|
|
82
108
|
return (await readFileIfExists(path)) !== undefined;
|
|
83
109
|
}
|
|
@@ -97,3 +123,258 @@ function isOpenClawInstructions(content) {
|
|
|
97
123
|
function escapeRegExp(value) {
|
|
98
124
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
99
125
|
}
|
|
126
|
+
function buildLocalRunner() {
|
|
127
|
+
return `#!/usr/bin/env node
|
|
128
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
129
|
+
import { dirname, join } from 'node:path';
|
|
130
|
+
import { homedir } from 'node:os';
|
|
131
|
+
|
|
132
|
+
const DEFAULT_API_URL = '${DEFAULT_API_URL}';
|
|
133
|
+
const ACTIONS = ['crawl', 'summarize', 'extract', 'train', 'transact', 'post'];
|
|
134
|
+
|
|
135
|
+
const code = await main(process.argv.slice(2)).catch((err) => {
|
|
136
|
+
console.error(err instanceof Error ? err.message : 'Unexpected Agent Permission runner failure.');
|
|
137
|
+
return 1;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
process.exitCode = code;
|
|
141
|
+
|
|
142
|
+
async function main(args) {
|
|
143
|
+
const command = args[0];
|
|
144
|
+
const rest = args.slice(1);
|
|
145
|
+
|
|
146
|
+
if (!command || command === '--help' || command === '-h') {
|
|
147
|
+
console.log(helpText());
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (command === 'check') return runCheck(rest);
|
|
152
|
+
if (command === 'config') return runConfig(rest);
|
|
153
|
+
|
|
154
|
+
console.error(\`Unknown command: \${command}\\n\\n\${helpText()}\`);
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function runCheck(args) {
|
|
159
|
+
const parsed = parseFlags(args);
|
|
160
|
+
const url = parsed.positionals[0];
|
|
161
|
+
const action = parseAction(stringFlag(parsed, 'action') || parsed.positionals[1]);
|
|
162
|
+
if (!url || !action) {
|
|
163
|
+
throw new Error('Usage: agent-permission check <url> --action <crawl|summarize|extract|train|transact|post>');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const config = await resolveConfig();
|
|
167
|
+
const result = await checkPermission({
|
|
168
|
+
url,
|
|
169
|
+
action,
|
|
170
|
+
mode: parseMode(stringFlag(parsed, 'mode')) || config.defaultMode,
|
|
171
|
+
agent_user_agent: stringFlag(parsed, 'user-agent') || stringFlag(parsed, 'agent-user-agent'),
|
|
172
|
+
bypass_cache: Boolean(parsed.flags['bypass-cache']),
|
|
173
|
+
}, {
|
|
174
|
+
apiUrl: stringFlag(parsed, 'api-url') || config.apiUrl,
|
|
175
|
+
apiKey: stringFlag(parsed, 'api-key') || config.apiKey,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
console.log(parsed.flags.json ? JSON.stringify(result, null, 2) : formatCheckHuman(result));
|
|
179
|
+
return parsed.flags['exit-code'] ? decisionExitCode(result.decision) : 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function runConfig(args) {
|
|
183
|
+
const subcommand = args[0];
|
|
184
|
+
if (subcommand === 'set' && args[1] === 'api-key' && args[2]) {
|
|
185
|
+
const current = await readConfig();
|
|
186
|
+
const path = await writeConfig({ ...current, apiKey: args[2] });
|
|
187
|
+
console.log(\`Saved API key to \${path}\`);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (subcommand === 'set' && args[1] === 'api-url' && args[2]) {
|
|
192
|
+
const current = await readConfig();
|
|
193
|
+
const path = await writeConfig({ ...current, apiUrl: args[2] });
|
|
194
|
+
console.log(\`Saved API URL to \${path}\`);
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (subcommand === 'doctor') {
|
|
199
|
+
const config = await resolveConfig();
|
|
200
|
+
console.log([
|
|
201
|
+
\`Config: \${getConfigPath()}\`,
|
|
202
|
+
\`API URL: \${config.apiUrl}\`,
|
|
203
|
+
\`API key: \${config.apiKey ? 'configured' : 'missing'}\`,
|
|
204
|
+
\`Default mode: \${config.defaultMode}\`,
|
|
205
|
+
].join('\\n'));
|
|
206
|
+
return config.apiKey ? 0 : 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
throw new Error('Usage: agent-permission config set api-key <key> | config set api-url <url> | config doctor');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function checkPermission(params, options) {
|
|
213
|
+
if (!options.apiKey) {
|
|
214
|
+
throw new Error('Missing API key. Set AGENT_PERMISSION_API_KEY or run \`node .agent-permission/agent-permission.mjs config set api-key <key>\`.');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const res = await fetch(\`\${trimSlash(options.apiUrl)}/v1/check\`, {
|
|
218
|
+
method: 'POST',
|
|
219
|
+
headers: {
|
|
220
|
+
'Content-Type': 'application/json',
|
|
221
|
+
'Authorization': \`Bearer \${options.apiKey}\`,
|
|
222
|
+
},
|
|
223
|
+
body: JSON.stringify(params),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
return readResponse(res);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function readResponse(res) {
|
|
230
|
+
const body = await res.json().catch(() => ({}));
|
|
231
|
+
if (!res.ok) {
|
|
232
|
+
const message = typeof body?.message === 'string' ? body.message : \`API request failed with \${res.status}\`;
|
|
233
|
+
throw new Error(message);
|
|
234
|
+
}
|
|
235
|
+
return body;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function formatCheckHuman(result) {
|
|
239
|
+
const lines = [
|
|
240
|
+
\`Decision: \${result.decision}\`,
|
|
241
|
+
\`Confidence: \${result.confidence}\`,
|
|
242
|
+
\`Risk: \${result.risk}\`,
|
|
243
|
+
\`Check: \${result.id}\`,
|
|
244
|
+
'',
|
|
245
|
+
'Reasons:',
|
|
246
|
+
...result.reasons.map((reason) => \`- \${reason}\`),
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
if (result.sources?.length) {
|
|
250
|
+
lines.push('', 'Sources:', ...result.sources.map((source) => \`- \${source.type}: \${source.url}\`));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (result.receipt?.receipt_id) {
|
|
254
|
+
lines.push('', \`Receipt: \${result.receipt.receipt_id}\`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return lines.join('\\n');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function parseFlags(args) {
|
|
261
|
+
const flags = {};
|
|
262
|
+
const positionals = [];
|
|
263
|
+
|
|
264
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
265
|
+
const arg = args[i];
|
|
266
|
+
if (!arg.startsWith('--')) {
|
|
267
|
+
positionals.push(arg);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const [rawKey, inlineValue] = arg.slice(2).split('=', 2);
|
|
272
|
+
if (inlineValue !== undefined) {
|
|
273
|
+
flags[rawKey] = inlineValue;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const next = args[i + 1];
|
|
278
|
+
if (next && !next.startsWith('--')) {
|
|
279
|
+
flags[rawKey] = next;
|
|
280
|
+
i += 1;
|
|
281
|
+
} else {
|
|
282
|
+
flags[rawKey] = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return { flags, positionals };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function stringFlag(parsed, name) {
|
|
290
|
+
const value = parsed.flags[name];
|
|
291
|
+
return typeof value === 'string' ? value : undefined;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function parseAction(value) {
|
|
295
|
+
return ACTIONS.includes(value) ? value : undefined;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function parseMode(value) {
|
|
299
|
+
if (!value) return undefined;
|
|
300
|
+
if (value === 'strict' || value === 'permissive') return value;
|
|
301
|
+
throw new Error('Mode must be strict or permissive.');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function decisionExitCode(decision) {
|
|
305
|
+
if (decision === 'allow') return 0;
|
|
306
|
+
if (decision === 'escalate') return 2;
|
|
307
|
+
if (decision === 'deny') return 3;
|
|
308
|
+
return 1;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function getConfigPath() {
|
|
312
|
+
if (process.env.AGENT_PERMISSION_CONFIG) return process.env.AGENT_PERMISSION_CONFIG;
|
|
313
|
+
|
|
314
|
+
const home = process.env.HOME || process.env.USERPROFILE || homedir() || '.';
|
|
315
|
+
if (process.env.XDG_CONFIG_HOME) {
|
|
316
|
+
return join(process.env.XDG_CONFIG_HOME, 'agent-permission', 'config.json');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (process.platform === 'darwin') {
|
|
320
|
+
return join(home, 'Library', 'Application Support', 'agent-permission', 'config.json');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return join(home, '.config', 'agent-permission', 'config.json');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async function readConfig() {
|
|
327
|
+
try {
|
|
328
|
+
const raw = await readFile(getConfigPath(), 'utf8');
|
|
329
|
+
const parsed = JSON.parse(raw);
|
|
330
|
+
return {
|
|
331
|
+
apiKey: typeof parsed.apiKey === 'string' ? parsed.apiKey : undefined,
|
|
332
|
+
apiUrl: typeof parsed.apiUrl === 'string' ? parsed.apiUrl : undefined,
|
|
333
|
+
defaultMode: parsed.defaultMode === 'permissive' || parsed.defaultMode === 'strict' ? parsed.defaultMode : undefined,
|
|
334
|
+
};
|
|
335
|
+
} catch (err) {
|
|
336
|
+
if (err && typeof err === 'object' && err.code === 'ENOENT') return {};
|
|
337
|
+
throw err;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function writeConfig(config) {
|
|
342
|
+
const path = getConfigPath();
|
|
343
|
+
await mkdir(dirname(path), { recursive: true });
|
|
344
|
+
await writeFile(path, \`\${JSON.stringify(config, null, 2)}\\n\`, { mode: 0o600 });
|
|
345
|
+
return path;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async function resolveConfig() {
|
|
349
|
+
const stored = await readConfig();
|
|
350
|
+
return {
|
|
351
|
+
apiKey: process.env.AGENT_PERMISSION_API_KEY || stored.apiKey || '',
|
|
352
|
+
apiUrl: process.env.AGENT_PERMISSION_API_URL || stored.apiUrl || DEFAULT_API_URL,
|
|
353
|
+
defaultMode: parseStoredMode(process.env.AGENT_PERMISSION_DEFAULT_MODE) || stored.defaultMode || 'strict',
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function parseStoredMode(value) {
|
|
358
|
+
return value === 'strict' || value === 'permissive' ? value : undefined;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function trimSlash(value) {
|
|
362
|
+
return value.replace(/\\/+$/, '');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function helpText() {
|
|
366
|
+
return \`Agent Permission local runner
|
|
367
|
+
|
|
368
|
+
Usage:
|
|
369
|
+
node .agent-permission/agent-permission.mjs check <url> --action <action> [--json] [--exit-code]
|
|
370
|
+
node .agent-permission/agent-permission.mjs config set api-key <key>
|
|
371
|
+
node .agent-permission/agent-permission.mjs config doctor
|
|
372
|
+
|
|
373
|
+
Actions:
|
|
374
|
+
crawl, summarize, extract, train, transact, post
|
|
375
|
+
|
|
376
|
+
Environment:
|
|
377
|
+
AGENT_PERMISSION_API_KEY, AGENT_PERMISSION_API_URL, AGENT_PERMISSION_DEFAULT_MODE\`;
|
|
378
|
+
}
|
|
379
|
+
`;
|
|
380
|
+
}
|