agent-permission 0.1.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/dist/api.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { BatchFile, CheckParams, CheckResponse, PermissionReceipt, VerifyReceiptResponse } from './types.js';
2
+ interface ApiOptions {
3
+ apiUrl: string;
4
+ apiKey?: string;
5
+ fetch: typeof fetch;
6
+ }
7
+ export declare class AgentPermissionApiError extends Error {
8
+ status: number;
9
+ constructor(status: number, message: string);
10
+ }
11
+ export declare function checkPermission(params: CheckParams, options: ApiOptions): Promise<CheckResponse>;
12
+ export declare function batchCheckPermissions(batch: BatchFile, options: ApiOptions): Promise<{
13
+ results: CheckResponse[];
14
+ }>;
15
+ export declare function verifyReceipt(receipt: PermissionReceipt, options: ApiOptions): Promise<VerifyReceiptResponse>;
16
+ export {};
17
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +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,CAetG;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAexH;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAUnH"}
package/dist/api.js ADDED
@@ -0,0 +1,57 @@
1
+ export class AgentPermissionApiError extends Error {
2
+ status;
3
+ constructor(status, message) {
4
+ super(message);
5
+ this.name = 'AgentPermissionApiError';
6
+ this.status = status;
7
+ }
8
+ }
9
+ export async function checkPermission(params, options) {
10
+ if (!options.apiKey) {
11
+ throw new AgentPermissionApiError(401, 'Missing API key. Set AGENT_PERMISSION_API_KEY or run `agent-permission config set api-key <key>`.');
12
+ }
13
+ const res = await options.fetch(`${trimSlash(options.apiUrl)}/v1/check`, {
14
+ method: 'POST',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ 'Authorization': `Bearer ${options.apiKey}`,
18
+ },
19
+ body: JSON.stringify(params),
20
+ });
21
+ return readResponse(res);
22
+ }
23
+ export async function batchCheckPermissions(batch, options) {
24
+ if (!options.apiKey) {
25
+ throw new AgentPermissionApiError(401, 'Missing API key. Set AGENT_PERMISSION_API_KEY or run `agent-permission config set api-key <key>`.');
26
+ }
27
+ const res = await options.fetch(`${trimSlash(options.apiUrl)}/v1/batch-check`, {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ 'Authorization': `Bearer ${options.apiKey}`,
32
+ },
33
+ body: JSON.stringify(batch),
34
+ });
35
+ return readResponse(res);
36
+ }
37
+ export async function verifyReceipt(receipt, options) {
38
+ const res = await options.fetch(`${trimSlash(options.apiUrl)}/v1/verify-receipt`, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ },
43
+ body: JSON.stringify(receipt),
44
+ });
45
+ return readResponse(res);
46
+ }
47
+ async function readResponse(res) {
48
+ const body = await res.json().catch(() => ({}));
49
+ if (!res.ok) {
50
+ const message = typeof body?.message === 'string' ? body.message : `API request failed with ${res.status}`;
51
+ throw new AgentPermissionApiError(res.status, message);
52
+ }
53
+ return body;
54
+ }
55
+ function trimSlash(value) {
56
+ return value.replace(/\/+$/, '');
57
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { CliIO, Runtime } from './types.js';
2
+ interface ParsedFlags {
3
+ flags: Record<string, string | boolean>;
4
+ positionals: string[];
5
+ }
6
+ export declare function runCli(argv: string[], runtime: Runtime, io: CliIO): Promise<number>;
7
+ export declare function parseFlags(args: string[]): ParsedFlags;
8
+ export {};
9
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +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;AA+GD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CA2BtD"}
package/dist/cli.js ADDED
@@ -0,0 +1,204 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { batchCheckPermissions, checkPermission, verifyReceipt } from './api.js';
3
+ import { getConfigPath, readConfig, resolveConfig, writeConfig } from './config.js';
4
+ import { decisionExitCode, formatBatchHuman, formatCheckHuman, formatVerifyHuman } from './format.js';
5
+ import { installAgentInstructions } from './install.js';
6
+ import { ACTIONS } from './types.js';
7
+ export async function runCli(argv, runtime, io) {
8
+ const invoked = argv[1] || 'agent-permission';
9
+ const args = argv.slice(2);
10
+ if (isSkillsInvocation(invoked, args)) {
11
+ return runCli([argv[0], argv[1], 'install', '--adapter', 'auto'], runtime, io);
12
+ }
13
+ const command = args[0];
14
+ const rest = args.slice(1);
15
+ try {
16
+ if (!command || command === '--help' || command === '-h') {
17
+ io.stdout(helpText());
18
+ return 0;
19
+ }
20
+ if (command === 'check')
21
+ return runCheck(rest, runtime, io);
22
+ if (command === 'batch')
23
+ return runBatch(rest, runtime, io);
24
+ if (command === 'verify-receipt')
25
+ return runVerify(rest, runtime, io);
26
+ if (command === 'install')
27
+ return runInstall(rest, runtime, io);
28
+ if (command === 'config')
29
+ return runConfig(rest, runtime, io);
30
+ io.stderr(`Unknown command: ${command}\n\n${helpText()}`);
31
+ return 1;
32
+ }
33
+ catch (err) {
34
+ io.stderr(err instanceof Error ? err.message : 'Unexpected CLI failure.');
35
+ return 1;
36
+ }
37
+ }
38
+ async function runCheck(args, runtime, io) {
39
+ const parsed = parseFlags(args);
40
+ const url = parsed.positionals[0];
41
+ const action = parseAction(stringFlag(parsed, 'action') || parsed.positionals[1]);
42
+ if (!url || !action) {
43
+ throw new Error('Usage: agent-permission check <url> --action <crawl|summarize|extract|train|transact|post>');
44
+ }
45
+ const config = await resolveConfig(runtime);
46
+ const params = {
47
+ url,
48
+ action,
49
+ mode: parseMode(stringFlag(parsed, 'mode')) || config.defaultMode,
50
+ agent_user_agent: stringFlag(parsed, 'user-agent') || stringFlag(parsed, 'agent-user-agent'),
51
+ bypass_cache: Boolean(parsed.flags['bypass-cache']),
52
+ };
53
+ const result = await checkPermission(params, {
54
+ apiUrl: stringFlag(parsed, 'api-url') || config.apiUrl,
55
+ apiKey: stringFlag(parsed, 'api-key') || config.apiKey,
56
+ fetch: runtime.fetch,
57
+ });
58
+ const format = outputFormat(parsed);
59
+ io.stdout(format === 'json' ? JSON.stringify(result, null, 2) : formatCheckHuman(result));
60
+ return parsed.flags['exit-code'] ? decisionExitCode(result.decision) : 0;
61
+ }
62
+ async function runBatch(args, runtime, io) {
63
+ const parsed = parseFlags(args);
64
+ const file = stringFlag(parsed, 'file');
65
+ if (!file) {
66
+ throw new Error('Usage: agent-permission batch --file checks.json');
67
+ }
68
+ const config = await resolveConfig(runtime);
69
+ const batch = JSON.parse(await readFile(file, 'utf8'));
70
+ const result = await batchCheckPermissions(batch, {
71
+ apiUrl: stringFlag(parsed, 'api-url') || config.apiUrl,
72
+ apiKey: stringFlag(parsed, 'api-key') || config.apiKey,
73
+ fetch: runtime.fetch,
74
+ });
75
+ const format = outputFormat(parsed);
76
+ io.stdout(format === 'json' ? JSON.stringify(result, null, 2) : formatBatchHuman(result.results));
77
+ if (parsed.flags['exit-code']) {
78
+ return result.results.reduce((max, item) => Math.max(max, decisionExitCode(item.decision)), 0);
79
+ }
80
+ return 0;
81
+ }
82
+ async function runVerify(args, runtime, io) {
83
+ const parsed = parseFlags(args);
84
+ const file = stringFlag(parsed, 'file');
85
+ if (!file) {
86
+ throw new Error('Usage: agent-permission verify-receipt --file receipt.json');
87
+ }
88
+ const config = await resolveConfig(runtime);
89
+ const receipt = JSON.parse(await readFile(file, 'utf8'));
90
+ const result = await verifyReceipt(receipt, {
91
+ apiUrl: stringFlag(parsed, 'api-url') || config.apiUrl,
92
+ fetch: runtime.fetch,
93
+ });
94
+ const format = outputFormat(parsed);
95
+ io.stdout(format === 'json' ? JSON.stringify(result, null, 2) : formatVerifyHuman(result));
96
+ return result.valid ? 0 : 1;
97
+ }
98
+ async function runInstall(args, runtime, io) {
99
+ const parsed = parseFlags(args);
100
+ const adapter = parseAdapter(stringFlag(parsed, 'adapter') || parsed.positionals[0] || 'auto');
101
+ const scope = parseScope(stringFlag(parsed, 'scope') || 'project');
102
+ const result = await installAgentInstructions(adapter, scope, runtime);
103
+ io.stdout(`Installed Agent Permission instructions for ${result.adapter} at ${result.path}`);
104
+ return 0;
105
+ }
106
+ async function runConfig(args, runtime, io) {
107
+ const subcommand = args[0];
108
+ if (subcommand === 'set' && args[1] === 'api-key' && args[2]) {
109
+ const current = await readConfig(runtime);
110
+ const path = await writeConfig(runtime, { ...current, apiKey: args[2] });
111
+ io.stdout(`Saved API key to ${path}`);
112
+ return 0;
113
+ }
114
+ if (subcommand === 'set' && args[1] === 'api-url' && args[2]) {
115
+ const current = await readConfig(runtime);
116
+ const path = await writeConfig(runtime, { ...current, apiUrl: args[2] });
117
+ io.stdout(`Saved API URL to ${path}`);
118
+ return 0;
119
+ }
120
+ if (subcommand === 'doctor') {
121
+ const config = await resolveConfig(runtime);
122
+ io.stdout([
123
+ `Config: ${getConfigPath(runtime)}`,
124
+ `API URL: ${config.apiUrl}`,
125
+ `API key: ${config.apiKey ? 'configured' : 'missing'}`,
126
+ `Default mode: ${config.defaultMode}`,
127
+ ].join('\n'));
128
+ return config.apiKey ? 0 : 1;
129
+ }
130
+ throw new Error('Usage: agent-permission config set api-key <key> | config set api-url <url> | config doctor');
131
+ }
132
+ export function parseFlags(args) {
133
+ const flags = {};
134
+ const positionals = [];
135
+ for (let i = 0; i < args.length; i += 1) {
136
+ const arg = args[i];
137
+ if (!arg.startsWith('--')) {
138
+ positionals.push(arg);
139
+ continue;
140
+ }
141
+ const [rawKey, inlineValue] = arg.slice(2).split('=', 2);
142
+ if (inlineValue !== undefined) {
143
+ flags[rawKey] = inlineValue;
144
+ continue;
145
+ }
146
+ const next = args[i + 1];
147
+ if (next && !next.startsWith('--')) {
148
+ flags[rawKey] = next;
149
+ i += 1;
150
+ }
151
+ else {
152
+ flags[rawKey] = true;
153
+ }
154
+ }
155
+ return { flags, positionals };
156
+ }
157
+ function stringFlag(parsed, name) {
158
+ const value = parsed.flags[name];
159
+ return typeof value === 'string' ? value : undefined;
160
+ }
161
+ function outputFormat(parsed) {
162
+ return parsed.flags.json ? 'json' : 'human';
163
+ }
164
+ function parseAction(value) {
165
+ return ACTIONS.includes(value) ? value : undefined;
166
+ }
167
+ function parseMode(value) {
168
+ if (!value)
169
+ return undefined;
170
+ if (value === 'strict' || value === 'permissive')
171
+ return value;
172
+ throw new Error('Mode must be strict or permissive.');
173
+ }
174
+ function parseAdapter(value) {
175
+ if (value === 'auto' || value === 'codex' || value === 'claude' || value === 'chatgpt' || value === 'openclaw')
176
+ return value;
177
+ throw new Error('Adapter must be auto, codex, claude, chatgpt, or openclaw.');
178
+ }
179
+ function parseScope(value) {
180
+ if (value === 'project' || value === 'user')
181
+ return value;
182
+ throw new Error('Scope must be project or user.');
183
+ }
184
+ function isSkillsInvocation(invoked, args) {
185
+ const name = invoked.split('/').pop() || invoked;
186
+ return name === 'skills' && args[0] === 'add' && args[1] === 'agent-permission';
187
+ }
188
+ function helpText() {
189
+ return `Agent Permission CLI
190
+
191
+ Usage:
192
+ agent-permission check <url> --action <action> [--json] [--exit-code]
193
+ agent-permission batch --file checks.json [--json]
194
+ agent-permission verify-receipt --file receipt.json
195
+ agent-permission install --adapter auto|codex|claude|chatgpt|openclaw [--scope project|user]
196
+ agent-permission config set api-key <key>
197
+ agent-permission config doctor
198
+
199
+ Actions:
200
+ crawl, summarize, extract, train, transact, post
201
+
202
+ Environment:
203
+ AGENT_PERMISSION_API_KEY, AGENT_PERMISSION_API_URL, AGENT_PERMISSION_DEFAULT_MODE`;
204
+ }
@@ -0,0 +1,6 @@
1
+ import { CliConfig, Runtime } from './types.js';
2
+ export declare function getConfigPath(runtime: Pick<Runtime, 'env' | 'platform' | 'homeDir'>): string;
3
+ export declare function readConfig(runtime: Runtime): Promise<CliConfig>;
4
+ export declare function writeConfig(runtime: Runtime, config: CliConfig): Promise<string>;
5
+ export declare function resolveConfig(runtime: Runtime): Promise<Required<CliConfig>>;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAyB,OAAO,EAAE,MAAM,YAAY,CAAC;AAIvE,wBAAgB,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC,UAenF;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAerE;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,mBAKpE;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAOlF"}
package/dist/config.js ADDED
@@ -0,0 +1,51 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { DEFAULT_API_URL } from './types.js';
4
+ const CONFIG_FILE_NAME = 'config.json';
5
+ export function getConfigPath(runtime) {
6
+ if (runtime.env.AGENT_PERMISSION_CONFIG) {
7
+ return runtime.env.AGENT_PERMISSION_CONFIG;
8
+ }
9
+ const home = runtime.homeDir || runtime.env.HOME || runtime.env.USERPROFILE || '.';
10
+ if (runtime.env.XDG_CONFIG_HOME) {
11
+ return join(runtime.env.XDG_CONFIG_HOME, 'agent-permission', CONFIG_FILE_NAME);
12
+ }
13
+ if (runtime.platform === 'darwin') {
14
+ return join(home, 'Library', 'Application Support', 'agent-permission', CONFIG_FILE_NAME);
15
+ }
16
+ return join(home, '.config', 'agent-permission', CONFIG_FILE_NAME);
17
+ }
18
+ export async function readConfig(runtime) {
19
+ try {
20
+ const raw = await readFile(getConfigPath(runtime), 'utf8');
21
+ const parsed = JSON.parse(raw);
22
+ return {
23
+ apiKey: typeof parsed.apiKey === 'string' ? parsed.apiKey : undefined,
24
+ apiUrl: typeof parsed.apiUrl === 'string' ? parsed.apiUrl : undefined,
25
+ defaultMode: parsed.defaultMode === 'permissive' || parsed.defaultMode === 'strict' ? parsed.defaultMode : undefined,
26
+ };
27
+ }
28
+ catch (err) {
29
+ if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') {
30
+ return {};
31
+ }
32
+ throw err;
33
+ }
34
+ }
35
+ export async function writeConfig(runtime, config) {
36
+ const path = getConfigPath(runtime);
37
+ await mkdir(dirname(path), { recursive: true });
38
+ await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
39
+ return path;
40
+ }
41
+ export async function resolveConfig(runtime) {
42
+ const stored = await readConfig(runtime);
43
+ return {
44
+ apiKey: runtime.env.AGENT_PERMISSION_API_KEY || stored.apiKey || '',
45
+ apiUrl: runtime.env.AGENT_PERMISSION_API_URL || stored.apiUrl || DEFAULT_API_URL,
46
+ defaultMode: parseMode(runtime.env.AGENT_PERMISSION_DEFAULT_MODE) || stored.defaultMode || 'strict',
47
+ };
48
+ }
49
+ function parseMode(value) {
50
+ return value === 'strict' || value === 'permissive' ? value : undefined;
51
+ }
@@ -0,0 +1,6 @@
1
+ import { CheckResponse, VerifyReceiptResponse } from './types.js';
2
+ export declare function decisionExitCode(decision: string): 2 | 0 | 3 | 1;
3
+ export declare function formatCheckHuman(result: CheckResponse): string;
4
+ export declare function formatBatchHuman(results: CheckResponse[]): string;
5
+ export declare function formatVerifyHuman(result: VerifyReceiptResponse): string;
6
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAElE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,iBAKhD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,UAwBrD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,UAKxD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,qBAAqB,UAK9D"}
package/dist/format.js ADDED
@@ -0,0 +1,43 @@
1
+ export function decisionExitCode(decision) {
2
+ if (decision === 'allow')
3
+ return 0;
4
+ if (decision === 'escalate')
5
+ return 2;
6
+ if (decision === 'deny')
7
+ return 3;
8
+ return 1;
9
+ }
10
+ export function formatCheckHuman(result) {
11
+ const lines = [
12
+ `Decision: ${result.decision}`,
13
+ `Confidence: ${result.confidence}`,
14
+ `Risk: ${result.risk}`,
15
+ `Check: ${result.id}`,
16
+ ];
17
+ if (result.reasons.length > 0) {
18
+ lines.push('', 'Reasons:');
19
+ for (const reason of result.reasons) {
20
+ lines.push(`- ${reason}`);
21
+ }
22
+ }
23
+ if (result.sources.length > 0) {
24
+ lines.push('', 'Sources:');
25
+ for (const source of result.sources) {
26
+ lines.push(`- ${source.type}: ${source.url}`);
27
+ }
28
+ }
29
+ lines.push('', `Receipt: ${result.receipt.receipt_id}`);
30
+ return lines.join('\n');
31
+ }
32
+ export function formatBatchHuman(results) {
33
+ return results.map((result) => {
34
+ const urlHash = result.receipt?.url_hash ? ` url_hash=${result.receipt.url_hash}` : '';
35
+ return `${result.decision.padEnd(8)} ${result.receipt?.action || 'unknown'} ${result.id}${urlHash}`;
36
+ }).join('\n');
37
+ }
38
+ export function formatVerifyHuman(result) {
39
+ return [
40
+ `Valid: ${result.valid ? 'yes' : 'no'}`,
41
+ `Message: ${result.message}`,
42
+ ].join('\n');
43
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { homedir } from 'node:os';
3
+ import { runCli } from './cli.js';
4
+ const exitCode = await runCli(process.argv, {
5
+ cwd: process.cwd(),
6
+ env: process.env,
7
+ platform: process.platform,
8
+ fetch,
9
+ homeDir: homedir(),
10
+ }, {
11
+ stdout: (message) => process.stdout.write(`${message}\n`),
12
+ stderr: (message) => process.stderr.write(`${message}\n`),
13
+ });
14
+ process.exitCode = exitCode;
@@ -0,0 +1,9 @@
1
+ import { Adapter, InstallScope, Runtime } from './types.js';
2
+ export interface InstallResult {
3
+ adapter: Exclude<Adapter, 'auto'>;
4
+ path: string;
5
+ }
6
+ export declare function installAgentInstructions(adapter: Adapter, scope: InstallScope, runtime: Runtime): Promise<InstallResult>;
7
+ export declare function upsertBlock(existing: string, blockBody: string): string;
8
+ export declare function buildInstructionBlock(adapter: Exclude<Adapter, 'auto'>): string;
9
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAK5D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAa9H;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAU9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,UAqBtE"}
@@ -0,0 +1,82 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ const BLOCK_START = '<!-- BEGIN:agent-permission -->';
4
+ const BLOCK_END = '<!-- END:agent-permission -->';
5
+ export async function installAgentInstructions(adapter, scope, runtime) {
6
+ const resolved = adapter === 'auto' ? await detectAdapter(runtime) : adapter;
7
+ const path = getInstructionPath(resolved, scope, runtime);
8
+ const existing = await readFile(path, 'utf8').catch((err) => {
9
+ if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT')
10
+ return '';
11
+ throw err;
12
+ });
13
+ const next = upsertBlock(existing, buildInstructionBlock(resolved));
14
+ await mkdir(dirname(path), { recursive: true });
15
+ await writeFile(path, next);
16
+ return { adapter: resolved, path };
17
+ }
18
+ export function upsertBlock(existing, blockBody) {
19
+ const block = `${BLOCK_START}\n${blockBody.trim()}\n${BLOCK_END}`;
20
+ const pattern = new RegExp(`${escapeRegExp(BLOCK_START)}[\\s\\S]*?${escapeRegExp(BLOCK_END)}`);
21
+ if (pattern.test(existing)) {
22
+ return existing.replace(pattern, block);
23
+ }
24
+ const prefix = existing.trimEnd();
25
+ return prefix ? `${prefix}\n\n${block}\n` : `${block}\n`;
26
+ }
27
+ export function buildInstructionBlock(adapter) {
28
+ const agentName = {
29
+ codex: 'Codex',
30
+ claude: 'Claude',
31
+ chatgpt: 'ChatGPT',
32
+ openclaw: 'OpenClaw',
33
+ }[adapter];
34
+ return `# Agent Permission
35
+
36
+ These instructions equip ${agentName} with Agent Permission preflight checks.
37
+
38
+ Before crawling, summarizing, extracting, training on, transacting with, or posting to a URL, run:
39
+
40
+ \`\`\`bash
41
+ agent-permission check <url> --action <crawl|summarize|extract|train|transact|post> --exit-code
42
+ \`\`\`
43
+
44
+ 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.
45
+
46
+ Treat \`allow\` as permitted, \`deny\` as blocked, and \`escalate\` as requiring human approval before continuing. Preserve the returned receipt ID in task notes when a permission decision affects user-visible work.`;
47
+ }
48
+ async function detectAdapter(runtime) {
49
+ const claudePath = join(runtime.cwd, 'CLAUDE.md');
50
+ const agentsPath = join(runtime.cwd, 'AGENTS.md');
51
+ if (await fileExists(claudePath))
52
+ return 'claude';
53
+ if (await fileExists(agentsPath))
54
+ return 'codex';
55
+ return 'codex';
56
+ }
57
+ function getInstructionPath(adapter, scope, runtime) {
58
+ if (scope === 'user') {
59
+ const home = runtime.homeDir || runtime.env.HOME || runtime.env.USERPROFILE || runtime.cwd;
60
+ const base = runtime.env.XDG_CONFIG_HOME || join(home, '.config');
61
+ return join(base, 'agent-permission', `${adapter}.md`);
62
+ }
63
+ if (adapter === 'claude')
64
+ return join(runtime.cwd, 'CLAUDE.md');
65
+ if (adapter === 'chatgpt')
66
+ return join(runtime.cwd, 'agent-permission.chatgpt.md');
67
+ if (adapter === 'openclaw')
68
+ return join(runtime.cwd, 'AGENTS.md');
69
+ return join(runtime.cwd, 'AGENTS.md');
70
+ }
71
+ async function fileExists(path) {
72
+ try {
73
+ await readFile(path, 'utf8');
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ function escapeRegExp(value) {
81
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
82
+ }
@@ -0,0 +1,66 @@
1
+ export declare const DEFAULT_API_URL = "https://agent-permission-api-788656703262.us-central1.run.app";
2
+ export declare const ACTIONS: readonly ["crawl", "summarize", "extract", "train", "transact", "post"];
3
+ export type AgentAction = typeof ACTIONS[number];
4
+ export type Mode = 'strict' | 'permissive';
5
+ export type OutputFormat = 'human' | 'json';
6
+ export type Adapter = 'auto' | 'codex' | 'claude' | 'chatgpt' | 'openclaw';
7
+ export type InstallScope = 'project' | 'user';
8
+ export interface CliConfig {
9
+ apiKey?: string;
10
+ apiUrl?: string;
11
+ defaultMode?: Mode;
12
+ }
13
+ export interface CheckParams {
14
+ url: string;
15
+ action: AgentAction;
16
+ agent_user_agent?: string;
17
+ mode?: Mode;
18
+ bypass_cache?: boolean;
19
+ }
20
+ export interface PermissionSource {
21
+ type: string;
22
+ url: string;
23
+ fetched_at: string;
24
+ evidence: string;
25
+ }
26
+ export interface PermissionReceipt {
27
+ receipt_id: string;
28
+ check_id: string;
29
+ url_hash: string;
30
+ action: string;
31
+ decision: string;
32
+ source_hashes: string[];
33
+ issued_at: string;
34
+ account_id: string;
35
+ signature_alg: string;
36
+ signature: string;
37
+ }
38
+ export interface CheckResponse {
39
+ id: string;
40
+ decision: 'allow' | 'deny' | 'escalate';
41
+ confidence: string;
42
+ risk: string;
43
+ reasons: string[];
44
+ sources: PermissionSource[];
45
+ receipt: PermissionReceipt;
46
+ }
47
+ export interface VerifyReceiptResponse {
48
+ valid: boolean;
49
+ message: string;
50
+ metadata?: Record<string, unknown>;
51
+ }
52
+ export interface BatchFile {
53
+ checks: CheckParams[];
54
+ }
55
+ export interface CliIO {
56
+ stdout: (message: string) => void;
57
+ stderr: (message: string) => void;
58
+ }
59
+ export interface Runtime {
60
+ cwd: string;
61
+ env: Record<string, string | undefined>;
62
+ platform: NodeJS.Platform;
63
+ fetch: typeof fetch;
64
+ homeDir?: string;
65
+ }
66
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,kEAAkE,CAAC;AAE/F,eAAO,MAAM,OAAO,yEAA0E,CAAC;AAC/F,MAAM,MAAM,WAAW,GAAG,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AAEjD,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,YAAY,CAAC;AAC3C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAC5C,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAC3E,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC1B,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_API_URL = 'https://agent-permission-api-788656703262.us-central1.run.app';
2
+ export const ACTIONS = ['crawl', 'summarize', 'extract', 'train', 'transact', 'post'];
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "agent-permission",
3
+ "version": "0.1.0",
4
+ "description": "Public CLI for Agent Permission checks and agent workspace installation.",
5
+ "type": "module",
6
+ "bin": {
7
+ "agent-permission": "dist/index.js",
8
+ "skills": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.json",
15
+ "prepack": "npm run build"
16
+ },
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "dependencies": {}
21
+ }