agent-permission 0.1.4 → 0.1.6
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 +13 -5
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +19 -3
- package/dist/cli.js +5 -5
- package/dist/format.d.ts +1 -1
- package/dist/install.d.ts +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +39 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Give AI agents a permission gate before they touch external URLs.
|
|
|
5
5
|
## Quickstart
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx agent-permission install --adapter auto
|
|
8
|
+
npx -y agent-permission@latest install --adapter auto
|
|
9
9
|
```
|
|
10
10
|
|
|
11
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.
|
|
@@ -13,7 +13,13 @@ This adds an Agent Permission block to the local agent instruction file, such as
|
|
|
13
13
|
To install instructions and configure live checks in one step:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npx agent-permission install --adapter auto --api-key <YOUR_API_KEY>
|
|
16
|
+
npx -y agent-permission@latest install --adapter auto --api-key <YOUR_API_KEY>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
To avoid installing a project runner in every repository, install once at user scope:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx -y agent-permission@latest install --adapter codex --scope user
|
|
17
23
|
```
|
|
18
24
|
|
|
19
25
|
Add an API key when you want live checks from the command line, CI, or agent runs:
|
|
@@ -31,19 +37,21 @@ After install, project instructions tell compatible agents to run:
|
|
|
31
37
|
node .agent-permission/agent-permission.mjs check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
32
38
|
```
|
|
33
39
|
|
|
34
|
-
If the
|
|
40
|
+
If the runner is missing, the installed instructions tell the agent to stop and ask you to repair the installation once:
|
|
35
41
|
|
|
36
42
|
```bash
|
|
37
|
-
npx -y agent-permission@latest
|
|
43
|
+
npx -y agent-permission@latest install --adapter auto --scope project
|
|
38
44
|
```
|
|
39
45
|
|
|
46
|
+
The generated preflight block does not tell agents to run `npx ... check` during a URL request, so repeated checks do not need registry access or unpinned-code approval.
|
|
47
|
+
|
|
40
48
|
## Commands
|
|
41
49
|
|
|
42
50
|
```bash
|
|
43
51
|
agent-permission check <url> --action <crawl|summarize|extract|train|transact|post>
|
|
44
52
|
agent-permission batch --file checks.json
|
|
45
53
|
agent-permission verify-receipt --file receipt.json
|
|
46
|
-
agent-permission install --adapter auto|codex|claude|chatgpt|openclaw [--api-key <key>]
|
|
54
|
+
agent-permission install --adapter auto|codex|claude|chatgpt|openclaw [--scope project|user] [--api-key <key>]
|
|
47
55
|
agent-permission config set api-key <key>
|
|
48
56
|
agent-permission config doctor
|
|
49
57
|
```
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE7G,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE7G,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBtG;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAgBxH;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAWnH"}
|
package/dist/api.js
CHANGED
|
@@ -10,7 +10,8 @@ export async function checkPermission(params, options) {
|
|
|
10
10
|
if (!options.apiKey) {
|
|
11
11
|
throw new AgentPermissionApiError(401, 'Missing API key. Set AGENT_PERMISSION_API_KEY or run `agent-permission config set api-key <key>`.');
|
|
12
12
|
}
|
|
13
|
-
const
|
|
13
|
+
const apiUrl = trimSlash(options.apiUrl);
|
|
14
|
+
const res = await fetchApi(apiUrl, '/v1/check', options.fetch, {
|
|
14
15
|
method: 'POST',
|
|
15
16
|
headers: {
|
|
16
17
|
'Content-Type': 'application/json',
|
|
@@ -24,7 +25,8 @@ export async function batchCheckPermissions(batch, options) {
|
|
|
24
25
|
if (!options.apiKey) {
|
|
25
26
|
throw new AgentPermissionApiError(401, 'Missing API key. Set AGENT_PERMISSION_API_KEY or run `agent-permission config set api-key <key>`.');
|
|
26
27
|
}
|
|
27
|
-
const
|
|
28
|
+
const apiUrl = trimSlash(options.apiUrl);
|
|
29
|
+
const res = await fetchApi(apiUrl, '/v1/batch-check', options.fetch, {
|
|
28
30
|
method: 'POST',
|
|
29
31
|
headers: {
|
|
30
32
|
'Content-Type': 'application/json',
|
|
@@ -35,7 +37,8 @@ export async function batchCheckPermissions(batch, options) {
|
|
|
35
37
|
return readResponse(res);
|
|
36
38
|
}
|
|
37
39
|
export async function verifyReceipt(receipt, options) {
|
|
38
|
-
const
|
|
40
|
+
const apiUrl = trimSlash(options.apiUrl);
|
|
41
|
+
const res = await fetchApi(apiUrl, '/v1/verify-receipt', options.fetch, {
|
|
39
42
|
method: 'POST',
|
|
40
43
|
headers: {
|
|
41
44
|
'Content-Type': 'application/json',
|
|
@@ -44,6 +47,19 @@ export async function verifyReceipt(receipt, options) {
|
|
|
44
47
|
});
|
|
45
48
|
return readResponse(res);
|
|
46
49
|
}
|
|
50
|
+
async function fetchApi(apiUrl, path, fetchImpl, init) {
|
|
51
|
+
try {
|
|
52
|
+
return await fetchImpl(`${apiUrl}${path}`, init);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const detail = err instanceof Error && err.message ? ` (${err.message})` : '';
|
|
56
|
+
throw new AgentPermissionApiError(0, [
|
|
57
|
+
`Agent Permission API request failed before reaching the service${detail}.`,
|
|
58
|
+
`Check network access to ${apiUrl}.`,
|
|
59
|
+
'In sandboxed agents, approve outbound network access and retry.',
|
|
60
|
+
].join('\n'));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
47
63
|
async function readResponse(res) {
|
|
48
64
|
const body = await res.json().catch(() => ({}));
|
|
49
65
|
if (!res.ok) {
|
package/dist/cli.js
CHANGED
|
@@ -18,15 +18,15 @@ export async function runCli(argv, runtime, io) {
|
|
|
18
18
|
return 0;
|
|
19
19
|
}
|
|
20
20
|
if (command === 'check')
|
|
21
|
-
return runCheck(rest, runtime, io);
|
|
21
|
+
return await runCheck(rest, runtime, io);
|
|
22
22
|
if (command === 'batch')
|
|
23
|
-
return runBatch(rest, runtime, io);
|
|
23
|
+
return await runBatch(rest, runtime, io);
|
|
24
24
|
if (command === 'verify-receipt')
|
|
25
|
-
return runVerify(rest, runtime, io);
|
|
25
|
+
return await runVerify(rest, runtime, io);
|
|
26
26
|
if (command === 'install')
|
|
27
|
-
return runInstall(rest, runtime, io);
|
|
27
|
+
return await runInstall(rest, runtime, io);
|
|
28
28
|
if (command === 'config')
|
|
29
|
-
return runConfig(rest, runtime, io);
|
|
29
|
+
return await runConfig(rest, runtime, io);
|
|
30
30
|
io.stderr(`Unknown command: ${command}\n\n${helpText()}`);
|
|
31
31
|
return 1;
|
|
32
32
|
}
|
package/dist/format.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CheckResponse, VerifyReceiptResponse } from './types.js';
|
|
2
|
-
export declare function decisionExitCode(decision: string):
|
|
2
|
+
export declare function decisionExitCode(decision: string): 0 | 2 | 3 | 1;
|
|
3
3
|
export declare function formatCheckHuman(result: CheckResponse): string;
|
|
4
4
|
export declare function formatBatchHuman(results: CheckResponse[]): string;
|
|
5
5
|
export declare function formatVerifyHuman(result: VerifyReceiptResponse): string;
|
package/dist/install.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export interface InstallResult {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function installAgentInstructions(adapter: Adapter, scope: InstallScope, runtime: Runtime): Promise<InstallResult>;
|
|
9
9
|
export declare function upsertBlock(existing: string, blockBody: string): string;
|
|
10
|
-
export declare function buildInstructionBlock(adapter: Exclude<Adapter, 'auto'>, runnerCommand?: string): string;
|
|
10
|
+
export declare function buildInstructionBlock(adapter: Exclude<Adapter, 'auto'>, runnerCommand?: string, repairCommand?: string): string;
|
|
11
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,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,
|
|
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,CAiB9H;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAU9D;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,EACjC,aAAa,SAAgC,EAC7C,aAAa,SAAgF,UA4B9F"}
|
package/dist/install.js
CHANGED
|
@@ -9,14 +9,15 @@ export async function installAgentInstructions(adapter, scope, runtime) {
|
|
|
9
9
|
const path = getInstructionPath(resolved, scope, runtime);
|
|
10
10
|
const runner = getRunnerPath(scope, runtime);
|
|
11
11
|
const runnerCommand = getRunnerCommand(scope, runner);
|
|
12
|
+
const repairCommand = getRepairCommand(resolved, scope);
|
|
12
13
|
const existing = await readFile(path, 'utf8').catch((err) => {
|
|
13
14
|
if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT')
|
|
14
15
|
return '';
|
|
15
16
|
throw err;
|
|
16
17
|
});
|
|
17
|
-
const next = upsertBlock(existing, buildInstructionBlock(resolved, runnerCommand));
|
|
18
|
+
const next = upsertBlock(existing, buildInstructionBlock(resolved, runnerCommand, repairCommand));
|
|
18
19
|
await mkdir(dirname(path), { recursive: true });
|
|
19
|
-
await writeLocalRunner(runner);
|
|
20
|
+
await writeLocalRunner(runner, runnerCommand);
|
|
20
21
|
await writeFile(path, next);
|
|
21
22
|
return { adapter: resolved, path, runnerPath: runner, runnerCommand };
|
|
22
23
|
}
|
|
@@ -29,7 +30,7 @@ export function upsertBlock(existing, blockBody) {
|
|
|
29
30
|
const prefix = existing.trimEnd();
|
|
30
31
|
return prefix ? `${prefix}\n\n${block}\n` : `${block}\n`;
|
|
31
32
|
}
|
|
32
|
-
export function buildInstructionBlock(adapter, runnerCommand = `node ${PROJECT_RUNNER_PATH}`) {
|
|
33
|
+
export function buildInstructionBlock(adapter, runnerCommand = `node ${PROJECT_RUNNER_PATH}`, repairCommand = `npx -y agent-permission@latest install --adapter ${adapter} --scope project`) {
|
|
33
34
|
const agentName = {
|
|
34
35
|
codex: 'Codex',
|
|
35
36
|
claude: 'Claude',
|
|
@@ -46,10 +47,10 @@ Before crawling, summarizing, extracting, training on, transacting with, or post
|
|
|
46
47
|
${runnerCommand} check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
|
|
47
48
|
\`\`\`
|
|
48
49
|
|
|
49
|
-
If the
|
|
50
|
+
Do not use npm while handling an individual URL request. If the runner command is missing or cannot start, stop and ask the user to repair the installation once with:
|
|
50
51
|
|
|
51
52
|
\`\`\`bash
|
|
52
|
-
|
|
53
|
+
${repairCommand}
|
|
53
54
|
\`\`\`
|
|
54
55
|
|
|
55
56
|
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.
|
|
@@ -97,9 +98,12 @@ function getRunnerCommand(scope, runnerPath) {
|
|
|
97
98
|
}
|
|
98
99
|
return `node ${PROJECT_RUNNER_PATH}`;
|
|
99
100
|
}
|
|
100
|
-
|
|
101
|
+
function getRepairCommand(adapter, scope) {
|
|
102
|
+
return `npx -y agent-permission@latest install --adapter ${adapter} --scope ${scope}`;
|
|
103
|
+
}
|
|
104
|
+
async function writeLocalRunner(path, runnerCommand) {
|
|
101
105
|
await mkdir(dirname(path), { recursive: true });
|
|
102
|
-
await writeFile(path, buildLocalRunner(), { mode: 0o644 });
|
|
106
|
+
await writeFile(path, buildLocalRunner(runnerCommand), { mode: 0o644 });
|
|
103
107
|
}
|
|
104
108
|
function shellQuote(value) {
|
|
105
109
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -123,13 +127,14 @@ function isOpenClawInstructions(content) {
|
|
|
123
127
|
function escapeRegExp(value) {
|
|
124
128
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
125
129
|
}
|
|
126
|
-
function buildLocalRunner() {
|
|
130
|
+
function buildLocalRunner(runnerCommand = `node ${PROJECT_RUNNER_PATH}`) {
|
|
127
131
|
return `#!/usr/bin/env node
|
|
128
132
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
129
133
|
import { dirname, join } from 'node:path';
|
|
130
134
|
import { homedir } from 'node:os';
|
|
131
135
|
|
|
132
136
|
const DEFAULT_API_URL = '${DEFAULT_API_URL}';
|
|
137
|
+
const RUNNER_COMMAND = ${JSON.stringify(runnerCommand)};
|
|
133
138
|
const ACTIONS = ['crawl', 'summarize', 'extract', 'train', 'transact', 'post'];
|
|
134
139
|
|
|
135
140
|
const code = await main(process.argv.slice(2)).catch((err) => {
|
|
@@ -211,21 +216,35 @@ async function runConfig(args) {
|
|
|
211
216
|
|
|
212
217
|
async function checkPermission(params, options) {
|
|
213
218
|
if (!options.apiKey) {
|
|
214
|
-
throw new Error(
|
|
219
|
+
throw new Error(\`Missing API key. Set AGENT_PERMISSION_API_KEY or run \\\`\${RUNNER_COMMAND} config set api-key <key>\\\`.\`);
|
|
215
220
|
}
|
|
216
221
|
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
const apiUrl = trimSlash(options.apiUrl);
|
|
223
|
+
const res = await fetchApi(apiUrl, '/v1/check', {
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: {
|
|
226
|
+
'Content-Type': 'application/json',
|
|
227
|
+
'Authorization': \`Bearer \${options.apiKey}\`,
|
|
228
|
+
},
|
|
229
|
+
body: JSON.stringify(params),
|
|
230
|
+
});
|
|
225
231
|
|
|
226
232
|
return readResponse(res);
|
|
227
233
|
}
|
|
228
234
|
|
|
235
|
+
async function fetchApi(apiUrl, path, init) {
|
|
236
|
+
try {
|
|
237
|
+
return await fetch(\`\${apiUrl}\${path}\`, init);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const detail = err instanceof Error && err.message ? \` (\${err.message})\` : '';
|
|
240
|
+
throw new Error([
|
|
241
|
+
\`Agent Permission API request failed before reaching the service\${detail}.\`,
|
|
242
|
+
\`Check network access to \${apiUrl}.\`,
|
|
243
|
+
'In sandboxed agents, approve outbound network access and retry.',
|
|
244
|
+
].join('\\n'));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
229
248
|
async function readResponse(res) {
|
|
230
249
|
const body = await res.json().catch(() => ({}));
|
|
231
250
|
if (!res.ok) {
|
|
@@ -366,9 +385,9 @@ function helpText() {
|
|
|
366
385
|
return \`Agent Permission local runner
|
|
367
386
|
|
|
368
387
|
Usage:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
388
|
+
\${RUNNER_COMMAND} check <url> --action <action> [--json] [--exit-code]
|
|
389
|
+
\${RUNNER_COMMAND} config set api-key <key>
|
|
390
|
+
\${RUNNER_COMMAND} config doctor
|
|
372
391
|
|
|
373
392
|
Actions:
|
|
374
393
|
crawl, summarize, extract, train, transact, post
|