@element47/ag 4.5.1 → 4.5.3
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 +184 -8
- package/dist/cli/__tests__/repl-rawmode.test.d.ts +2 -0
- package/dist/cli/__tests__/repl-rawmode.test.d.ts.map +1 -0
- package/dist/cli/__tests__/repl-rawmode.test.js +46 -0
- package/dist/cli/__tests__/repl-rawmode.test.js.map +1 -0
- package/dist/cli/repl.d.ts +7 -2
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +203 -25
- package/dist/cli/repl.js.map +1 -1
- package/dist/cli.js +10 -8
- package/dist/cli.js.map +1 -1
- package/dist/core/__tests__/agent.test.js +42 -1
- package/dist/core/__tests__/agent.test.js.map +1 -1
- package/dist/core/__tests__/context.test.js +81 -0
- package/dist/core/__tests__/context.test.js.map +1 -1
- package/dist/core/__tests__/events.test.d.ts +2 -0
- package/dist/core/__tests__/events.test.d.ts.map +1 -0
- package/dist/core/__tests__/events.test.js +131 -0
- package/dist/core/__tests__/events.test.js.map +1 -0
- package/dist/core/__tests__/extensions.test.d.ts +2 -0
- package/dist/core/__tests__/extensions.test.d.ts.map +1 -0
- package/dist/core/__tests__/extensions.test.js +59 -0
- package/dist/core/__tests__/extensions.test.js.map +1 -0
- package/dist/core/__tests__/guardrails.test.d.ts +2 -0
- package/dist/core/__tests__/guardrails.test.d.ts.map +1 -0
- package/dist/core/__tests__/guardrails.test.js +418 -0
- package/dist/core/__tests__/guardrails.test.js.map +1 -0
- package/dist/core/__tests__/permission-manager.test.d.ts +2 -0
- package/dist/core/__tests__/permission-manager.test.d.ts.map +1 -0
- package/dist/core/__tests__/permission-manager.test.js +246 -0
- package/dist/core/__tests__/permission-manager.test.js.map +1 -0
- package/dist/core/__tests__/streaming.test.js +8 -1
- package/dist/core/__tests__/streaming.test.js.map +1 -1
- package/dist/core/agent.d.ts +27 -0
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +263 -121
- package/dist/core/agent.js.map +1 -1
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +14 -6
- package/dist/core/context.js.map +1 -1
- package/dist/core/events.d.ts +62 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +23 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/extensions.d.ts +10 -0
- package/dist/core/extensions.d.ts.map +1 -0
- package/dist/core/extensions.js +66 -0
- package/dist/core/extensions.js.map +1 -0
- package/dist/core/guardrails.d.ts +32 -0
- package/dist/core/guardrails.d.ts.map +1 -0
- package/dist/core/guardrails.js +149 -0
- package/dist/core/guardrails.js.map +1 -0
- package/dist/core/loader.d.ts +6 -2
- package/dist/core/loader.d.ts.map +1 -1
- package/dist/core/loader.js +23 -9
- package/dist/core/loader.js.map +1 -1
- package/dist/core/permissions.d.ts +60 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +252 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js +16 -0
- package/dist/core/registry.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +26 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/types.d.ts +15 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/memory/__tests__/memory.test.js +28 -0
- package/dist/memory/__tests__/memory.test.js.map +1 -1
- package/dist/memory/memory.js +1 -1
- package/dist/memory/memory.js.map +1 -1
- package/dist/tools/__tests__/bash.test.js +4 -0
- package/dist/tools/__tests__/bash.test.js.map +1 -1
- package/dist/tools/__tests__/file.test.js +7 -1
- package/dist/tools/__tests__/file.test.js.map +1 -1
- package/package.json +1 -4
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export const GUARDRAIL_PATTERNS = [
|
|
2
|
+
// Direct injection — attempts to override system instructions
|
|
3
|
+
{ pattern: /ignore\s+(all\s+)?previous\s+instructions/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "ignore previous instructions"' },
|
|
4
|
+
{ pattern: /you\s+are\s+now\s+(in\s+)?developer\s+mode/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "developer mode" activation' },
|
|
5
|
+
{ pattern: /system\s+override/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "system override"' },
|
|
6
|
+
{ pattern: /reveal\s+(your\s+)?(system\s+)?prompt/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: prompt exfiltration attempt' },
|
|
7
|
+
{ pattern: /disregard\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions|rules|guidelines)/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "disregard previous instructions"' },
|
|
8
|
+
{ pattern: /forget\s+(all\s+)?(previous|prior|your)\s+(instructions|rules|guidelines)/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "forget instructions"' },
|
|
9
|
+
{ pattern: /new\s+instructions?\s*:/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "new instructions" directive' },
|
|
10
|
+
{ pattern: /act\s+as\s+(if\s+you\s+are\s+|a\s+)?(unrestricted|jailbroken|unfiltered)/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: jailbreak attempt' },
|
|
11
|
+
{ pattern: /do\s+not\s+follow\s+(any\s+)?(your\s+)?(previous|original)\s+(instructions|rules)/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: "do not follow" directive' },
|
|
12
|
+
{ pattern: /pretend\s+(you\s+are|to\s+be)\s+(a\s+)?(different|new|unrestricted|unfiltered)/i, severity: 'block', category: 'direct-injection', message: 'prompt injection: identity override' },
|
|
13
|
+
// Suspicious override — language specifically targeting the agent's security/permission system
|
|
14
|
+
{ pattern: /\b(always|never|must)\s+(ignore|override|skip|bypass)\s+(permission|security|guard|confirmation|prompt|rule)/i, severity: 'warn', category: 'suspicious-override', message: 'suspicious instruction-like language targeting agent security' },
|
|
15
|
+
{ pattern: /\boverride\s+(system\s+prompt|security|permission|guardrail)/i, severity: 'warn', category: 'suspicious-override', message: 'suspicious "override system/security" language' },
|
|
16
|
+
{ pattern: /\b(bypass|disable|skip)\s+(permission|security|confirmation|guard)/i, severity: 'warn', category: 'suspicious-override', message: 'suspicious "bypass security" language', skipInCodeBlocks: true },
|
|
17
|
+
{ pattern: /\brun\s+without\s+(permission|confirmation|asking)/i, severity: 'warn', category: 'suspicious-override', message: 'suspicious "run without permission" language' },
|
|
18
|
+
{ pattern: /\bauto[\s-]?approve\s+(all|every|tool|action|command)/i, severity: 'warn', category: 'suspicious-override', message: 'suspicious "auto-approve" language' },
|
|
19
|
+
// Hidden content — invisible payloads
|
|
20
|
+
{ pattern: /<!--[\s\S]*?\b(ignore|override|instruction|disregard|forget|reveal)\b[\s\S]*?-->/i, severity: 'block', category: 'hidden-content', message: 'HTML comment contains suspicious instruction' },
|
|
21
|
+
{ pattern: /[\x00-\x08\x0E-\x1F]/, severity: 'block', category: 'hidden-content', message: 'content contains control characters' },
|
|
22
|
+
// Exfiltration — data exfil attempts in descriptions
|
|
23
|
+
{ pattern: /\b(fetch|curl|wget|axios)\s*\(/i, severity: 'block', category: 'exfiltration', message: 'description contains network call invocation' },
|
|
24
|
+
{ pattern: /https?:\/\/[^\s"')<>]{10,}/i, severity: 'warn', category: 'exfiltration', message: 'description contains URL', skipInCodeBlocks: true },
|
|
25
|
+
{ pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i, severity: 'warn', category: 'exfiltration', message: 'description contains email address', skipInCodeBlocks: true },
|
|
26
|
+
{ pattern: /\bwebhook\b/i, severity: 'warn', category: 'exfiltration', message: 'description references webhook', skipInCodeBlocks: true },
|
|
27
|
+
// Encoded payload — HTML entities that could hide instructions
|
|
28
|
+
{ pattern: /&#x?[0-9a-fA-F]+;.*&#x?[0-9a-fA-F]+;/i, severity: 'warn', category: 'encoded-payload', message: 'content contains HTML entity encoding' },
|
|
29
|
+
];
|
|
30
|
+
// Zero-width and bidirectional characters
|
|
31
|
+
const ZERO_WIDTH_RE = /[\u200B\u200C\u200D\uFEFF\u2060\u200E\u200F\u202A-\u202E]/;
|
|
32
|
+
// Base64: 40+ chars from the base64 alphabet, optionally ending with = or ==
|
|
33
|
+
const BASE64_RE = /[A-Za-z0-9+/]{40,}={0,2}/g;
|
|
34
|
+
// Suspicious tool names
|
|
35
|
+
const SUSPICIOUS_TOOL_NAME_RE = /\b(system_override|admin_override|sudo|root_access)\b/i;
|
|
36
|
+
// Fenced code block pattern — used to strip code blocks before exfiltration checks
|
|
37
|
+
const FENCED_CODE_BLOCK_RE = /```[\s\S]*?```/g;
|
|
38
|
+
// Inline code pattern
|
|
39
|
+
const INLINE_CODE_RE = /`[^`]+`/g;
|
|
40
|
+
/** Strip fenced and inline code blocks from content */
|
|
41
|
+
export function stripCodeBlocks(content) {
|
|
42
|
+
return content.replace(FENCED_CODE_BLOCK_RE, '').replace(INLINE_CODE_RE, '');
|
|
43
|
+
}
|
|
44
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
45
|
+
export function decodeBase64Safe(str) {
|
|
46
|
+
try {
|
|
47
|
+
const buf = Buffer.from(str, 'base64');
|
|
48
|
+
// Reject if it doesn't round-trip (not valid base64)
|
|
49
|
+
if (buf.toString('base64').replace(/=+$/, '') !== str.replace(/=+$/, ''))
|
|
50
|
+
return null;
|
|
51
|
+
const decoded = buf.toString('utf-8');
|
|
52
|
+
// Reject binary content (contains null bytes)
|
|
53
|
+
if (decoded.includes('\0'))
|
|
54
|
+
return null;
|
|
55
|
+
return decoded;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function hasZeroWidthChars(content) {
|
|
62
|
+
return ZERO_WIDTH_RE.test(content);
|
|
63
|
+
}
|
|
64
|
+
export function mergeResults(...results) {
|
|
65
|
+
const findings = [];
|
|
66
|
+
for (const r of results)
|
|
67
|
+
findings.push(...r.findings);
|
|
68
|
+
return { ok: findings.every(f => f.severity !== 'block'), findings };
|
|
69
|
+
}
|
|
70
|
+
// ── Core Scanning ────────────────────────────────────────────────────────────
|
|
71
|
+
export function scanContent(content, context, _depth = 0) {
|
|
72
|
+
if (!content)
|
|
73
|
+
return { ok: true, findings: [] };
|
|
74
|
+
const findings = [];
|
|
75
|
+
const strippedContent = stripCodeBlocks(content);
|
|
76
|
+
// Run all regex patterns
|
|
77
|
+
for (const { pattern, severity, category, message, skipInCodeBlocks } of GUARDRAIL_PATTERNS) {
|
|
78
|
+
const target = skipInCodeBlocks ? strippedContent : content;
|
|
79
|
+
const match = target.match(pattern);
|
|
80
|
+
if (match) {
|
|
81
|
+
findings.push({ severity, category, message: `${context}: ${message}`, matched: match[0] });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Check for zero-width characters
|
|
85
|
+
if (hasZeroWidthChars(content)) {
|
|
86
|
+
findings.push({
|
|
87
|
+
severity: 'block',
|
|
88
|
+
category: 'hidden-content',
|
|
89
|
+
message: `${context}: content contains zero-width or bidirectional characters`,
|
|
90
|
+
matched: content.match(ZERO_WIDTH_RE)[0],
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// Check for base64-encoded payloads (one level of recursion)
|
|
94
|
+
if (_depth === 0) {
|
|
95
|
+
const b64Matches = content.match(BASE64_RE);
|
|
96
|
+
if (b64Matches) {
|
|
97
|
+
for (const b64 of b64Matches) {
|
|
98
|
+
const decoded = decodeBase64Safe(b64);
|
|
99
|
+
if (decoded) {
|
|
100
|
+
const inner = scanContent(decoded, `${context} (decoded base64)`, 1);
|
|
101
|
+
if (!inner.ok) {
|
|
102
|
+
findings.push({
|
|
103
|
+
severity: 'block',
|
|
104
|
+
category: 'encoded-payload',
|
|
105
|
+
message: `${context}: base64-encoded content contains injection`,
|
|
106
|
+
matched: b64.slice(0, 60) + (b64.length > 60 ? '...' : ''),
|
|
107
|
+
});
|
|
108
|
+
findings.push(...inner.findings);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { ok: findings.every(f => f.severity !== 'block'), findings };
|
|
115
|
+
}
|
|
116
|
+
export function scanTool(tool) {
|
|
117
|
+
const name = tool.function.name;
|
|
118
|
+
const results = [];
|
|
119
|
+
// Scan tool description
|
|
120
|
+
results.push(scanContent(tool.function.description, `tool "${name}" description`));
|
|
121
|
+
// Scan parameter descriptions
|
|
122
|
+
const props = tool.function.parameters?.properties;
|
|
123
|
+
if (props) {
|
|
124
|
+
for (const [paramName, paramDef] of Object.entries(props)) {
|
|
125
|
+
const desc = paramDef.description;
|
|
126
|
+
if (desc) {
|
|
127
|
+
results.push(scanContent(desc, `tool "${name}" param "${paramName}"`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Check for suspicious tool names
|
|
132
|
+
if (SUSPICIOUS_TOOL_NAME_RE.test(name)) {
|
|
133
|
+
const finding = {
|
|
134
|
+
severity: 'warn',
|
|
135
|
+
category: 'suspicious-override',
|
|
136
|
+
message: `tool "${name}": suspicious tool name`,
|
|
137
|
+
matched: name,
|
|
138
|
+
};
|
|
139
|
+
results.push({ ok: true, findings: [finding] });
|
|
140
|
+
}
|
|
141
|
+
return mergeResults(...results);
|
|
142
|
+
}
|
|
143
|
+
export function scanSkill(skill) {
|
|
144
|
+
const results = [];
|
|
145
|
+
results.push(scanContent(skill.content, `skill "${skill.name}"`));
|
|
146
|
+
results.push(scanContent(skill.description, `skill "${skill.name}" description`));
|
|
147
|
+
return mergeResults(...results);
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=guardrails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardrails.js","sourceRoot":"","sources":["../../src/core/guardrails.ts"],"names":[],"mappings":"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"}
|
package/dist/core/loader.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { Tool } from './types.js';
|
|
2
|
-
export
|
|
1
|
+
import { Tool, ToolLoadFailure } from './types.js';
|
|
2
|
+
export interface LoadUserToolsResult {
|
|
3
|
+
tools: Tool[];
|
|
4
|
+
failures: ToolLoadFailure[];
|
|
5
|
+
}
|
|
6
|
+
export declare function loadUserTools(cwd: string): Promise<LoadUserToolsResult>;
|
|
3
7
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAwCnD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAY7E"}
|
package/dist/core/loader.js
CHANGED
|
@@ -2,38 +2,52 @@ import { existsSync, readdirSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { AG_DIR } from './constants.js';
|
|
5
|
+
import { scanTool } from './guardrails.js';
|
|
5
6
|
async function loadToolsFromDir(dir) {
|
|
6
7
|
if (!existsSync(dir))
|
|
7
|
-
return [];
|
|
8
|
+
return { tools: [], failures: [] };
|
|
8
9
|
const files = readdirSync(dir).filter(f => f.endsWith('.mjs'));
|
|
9
10
|
const tools = [];
|
|
11
|
+
const failures = [];
|
|
10
12
|
for (const file of files) {
|
|
11
13
|
try {
|
|
12
14
|
const mod = await import(pathToFileURL(join(dir, file)).href);
|
|
13
15
|
const tool = mod.default;
|
|
14
16
|
if (tool?.type === 'function' && tool?.function?.name && typeof tool?.execute === 'function') {
|
|
17
|
+
if (tool.permissionKey && typeof tool.permissionKey?.qualifier !== 'string') {
|
|
18
|
+
tool.permissionKey = undefined;
|
|
19
|
+
}
|
|
20
|
+
const scan = scanTool(tool);
|
|
21
|
+
if (!scan.ok) {
|
|
22
|
+
const reasons = scan.findings.filter(f => f.severity === 'block').map(f => f.message).join('; ');
|
|
23
|
+
failures.push({ file, name: tool.function.name, reason: reasons });
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
15
26
|
tools.push(tool);
|
|
16
27
|
}
|
|
17
28
|
else {
|
|
18
|
-
|
|
29
|
+
failures.push({ file, reason: 'invalid tool format' });
|
|
19
30
|
}
|
|
20
31
|
}
|
|
21
32
|
catch (e) {
|
|
22
33
|
const msg = e instanceof Error ? e.message : String(e);
|
|
23
|
-
|
|
34
|
+
failures.push({ file, reason: msg });
|
|
24
35
|
}
|
|
25
36
|
}
|
|
26
|
-
return tools;
|
|
37
|
+
return { tools, failures };
|
|
27
38
|
}
|
|
28
39
|
export async function loadUserTools(cwd) {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
40
|
+
const global = await loadToolsFromDir(join(AG_DIR, 'tools'));
|
|
41
|
+
const local = await loadToolsFromDir(join(cwd, '.ag', 'tools'));
|
|
31
42
|
// Local tools override global if same name
|
|
32
43
|
const byName = new Map();
|
|
33
|
-
for (const t of
|
|
44
|
+
for (const t of global.tools)
|
|
34
45
|
byName.set(t.function.name, t);
|
|
35
|
-
for (const t of
|
|
46
|
+
for (const t of local.tools)
|
|
36
47
|
byName.set(t.function.name, t);
|
|
37
|
-
return
|
|
48
|
+
return {
|
|
49
|
+
tools: Array.from(byName.values()),
|
|
50
|
+
failures: [...global.failures, ...local.failures],
|
|
51
|
+
};
|
|
38
52
|
}
|
|
39
53
|
//# sourceMappingURL=loader.js.map
|
package/dist/core/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PermissionKey } from './types.js';
|
|
2
|
+
export type PermissionEffect = 'allow' | 'deny';
|
|
3
|
+
export type PermissionScope = 'session' | 'project' | 'global';
|
|
4
|
+
export interface PermissionRule {
|
|
5
|
+
pattern: string;
|
|
6
|
+
effect: PermissionEffect;
|
|
7
|
+
}
|
|
8
|
+
export interface PermissionFile {
|
|
9
|
+
allow?: string[];
|
|
10
|
+
deny?: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface ParsedPattern {
|
|
13
|
+
tool: string;
|
|
14
|
+
qualifier: string;
|
|
15
|
+
glob: string | null;
|
|
16
|
+
}
|
|
17
|
+
/** Hand-rolled glob matcher — supports *, **, ? with no dependencies */
|
|
18
|
+
export declare function globMatch(pattern: string, value: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Parse a pattern string like "bash(npm:*)" into structured form.
|
|
21
|
+
* Supports: "Tool(qualifier:glob)", "Tool(qualifier)", "Tool(*)", "*"
|
|
22
|
+
*/
|
|
23
|
+
export declare function parsePattern(str: string): ParsedPattern;
|
|
24
|
+
interface MatchKey {
|
|
25
|
+
qualifier: string;
|
|
26
|
+
value: string;
|
|
27
|
+
}
|
|
28
|
+
/** Extract qualifier + value from a tool call for pattern matching */
|
|
29
|
+
export declare function extractMatchKey(toolName: string, args: Record<string, unknown>, permissionKey?: PermissionKey): MatchKey;
|
|
30
|
+
/** Generate a reasonable permission pattern from a concrete tool call */
|
|
31
|
+
export declare function inferPattern(toolName: string, args: Record<string, unknown>, permissionKey?: PermissionKey): string;
|
|
32
|
+
export declare class PermissionManager {
|
|
33
|
+
private readonly cwd;
|
|
34
|
+
private readonly projectPath;
|
|
35
|
+
private readonly globalPath;
|
|
36
|
+
private sessionRules;
|
|
37
|
+
private projectRules;
|
|
38
|
+
private globalRules;
|
|
39
|
+
constructor(cwd: string);
|
|
40
|
+
/** Reload project + global rules from disk */
|
|
41
|
+
reload(): void;
|
|
42
|
+
/** Check whether a tool call is allowed, denied, or needs prompting */
|
|
43
|
+
check(toolName: string, args: Record<string, unknown>, permissionKey?: PermissionKey): 'allow' | 'deny' | 'ask';
|
|
44
|
+
/** Add a permission rule to a scope */
|
|
45
|
+
addRule(rule: PermissionRule, scope: PermissionScope): void;
|
|
46
|
+
/** Remove a rule by pattern from a scope */
|
|
47
|
+
removeRule(pattern: string, scope: PermissionScope): boolean;
|
|
48
|
+
/** Get rules, optionally filtered by scope */
|
|
49
|
+
getRules(scope?: PermissionScope): Array<PermissionRule & {
|
|
50
|
+
scope: PermissionScope;
|
|
51
|
+
}>;
|
|
52
|
+
/** Persist rules to disk */
|
|
53
|
+
save(scope: 'project' | 'global'): void;
|
|
54
|
+
/** Clear rules for a scope */
|
|
55
|
+
clear(scope: PermissionScope): void;
|
|
56
|
+
private rulesForScope;
|
|
57
|
+
private loadFile;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAID,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAejE;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAsBvD;AAID,UAAU,QAAQ;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,aAAa,CAAC,EAAE,aAAa,GAC5B,QAAQ,CAmCV;AAID,yEAAyE;AACzE,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,aAAa,CAAC,EAAE,aAAa,GAC5B,MAAM,CAwCR;AAgBD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,WAAW,CAAwB;gBAE/B,GAAG,EAAE,MAAM;IAOvB,8CAA8C;IAC9C,MAAM,IAAI,IAAI;IAKd,uEAAuE;IACvE,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,GAAG,MAAM,GAAG,KAAK;IAqB3B,uCAAuC;IACvC,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI;IAQ3D,4CAA4C;IAC5C,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO;IAO5D,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,KAAK,CAAC,cAAc,GAAG;QAAE,KAAK,EAAE,eAAe,CAAA;KAAE,CAAC;IAWrF,4BAA4B;IAC5B,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI;IAYvC,8BAA8B;IAC9B,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAQnC,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,QAAQ;CAWjB"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { AG_DIR } from './constants.js';
|
|
4
|
+
// ── Glob Matching ───────────────────────────────────────────────────────────
|
|
5
|
+
/** Hand-rolled glob matcher — supports *, **, ? with no dependencies */
|
|
6
|
+
export function globMatch(pattern, value) {
|
|
7
|
+
if (pattern === '*')
|
|
8
|
+
return true;
|
|
9
|
+
// Convert glob to regex:
|
|
10
|
+
// 1. Escape regex-special chars (except our glob chars)
|
|
11
|
+
// 2. Replace ** → any sequence (including /)
|
|
12
|
+
// 3. Replace * → any sequence (excluding /)
|
|
13
|
+
// 4. Replace ? → single char
|
|
14
|
+
const SENTINEL = '\0GLOBSTAR\0';
|
|
15
|
+
const re = pattern
|
|
16
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex specials
|
|
17
|
+
.replace(/\*\*/g, SENTINEL) // protect **
|
|
18
|
+
.replace(/\*/g, '[^/]*') // * = non-slash seq
|
|
19
|
+
.replace(new RegExp(SENTINEL.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '.*') // ** = any seq
|
|
20
|
+
.replace(/\?/g, '.'); // ? = single char
|
|
21
|
+
return new RegExp(`^${re}$`).test(value);
|
|
22
|
+
}
|
|
23
|
+
// ── Pattern Parsing ─────────────────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Parse a pattern string like "bash(npm:*)" into structured form.
|
|
26
|
+
* Supports: "Tool(qualifier:glob)", "Tool(qualifier)", "Tool(*)", "*"
|
|
27
|
+
*/
|
|
28
|
+
export function parsePattern(str) {
|
|
29
|
+
const s = str.trim();
|
|
30
|
+
if (s === '*')
|
|
31
|
+
return { tool: '*', qualifier: '*', glob: null };
|
|
32
|
+
const parenIdx = s.indexOf('(');
|
|
33
|
+
if (parenIdx === -1) {
|
|
34
|
+
// Bare tool name: "bash" → bash(*)
|
|
35
|
+
return { tool: s.toLowerCase(), qualifier: '*', glob: null };
|
|
36
|
+
}
|
|
37
|
+
const tool = s.slice(0, parenIdx).toLowerCase();
|
|
38
|
+
const inner = s.slice(parenIdx + 1, s.endsWith(')') ? s.length - 1 : s.length);
|
|
39
|
+
const colonIdx = inner.indexOf(':');
|
|
40
|
+
if (colonIdx === -1) {
|
|
41
|
+
// No glob: "git(commit)" or "bash(*)"
|
|
42
|
+
return { tool, qualifier: inner || '*', glob: null };
|
|
43
|
+
}
|
|
44
|
+
const qualifier = inner.slice(0, colonIdx) || '*';
|
|
45
|
+
const glob = inner.slice(colonIdx + 1) || '*';
|
|
46
|
+
return { tool, qualifier, glob };
|
|
47
|
+
}
|
|
48
|
+
/** Extract qualifier + value from a tool call for pattern matching */
|
|
49
|
+
export function extractMatchKey(toolName, args, permissionKey) {
|
|
50
|
+
const name = toolName.toLowerCase();
|
|
51
|
+
// Built-in tools have hardcoded extraction
|
|
52
|
+
switch (name) {
|
|
53
|
+
case 'bash': {
|
|
54
|
+
const cmd = String(args.command || '');
|
|
55
|
+
const firstWord = cmd.trimStart().split(/\s+/)[0] || '';
|
|
56
|
+
return { qualifier: firstWord, value: cmd };
|
|
57
|
+
}
|
|
58
|
+
case 'file':
|
|
59
|
+
return { qualifier: String(args.action || '*'), value: String(args.path || '') };
|
|
60
|
+
case 'git':
|
|
61
|
+
return { qualifier: String(args.action || '*'), value: '' };
|
|
62
|
+
case 'web': {
|
|
63
|
+
const action = String(args.action || '*');
|
|
64
|
+
if (action === 'fetch' && args.url) {
|
|
65
|
+
try {
|
|
66
|
+
const hostname = new URL(String(args.url)).hostname;
|
|
67
|
+
return { qualifier: action, value: hostname };
|
|
68
|
+
}
|
|
69
|
+
catch { /* fall through */ }
|
|
70
|
+
}
|
|
71
|
+
return { qualifier: action, value: String(args.url || args.query || '') };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Custom tools: use permissionKey if provided
|
|
75
|
+
if (permissionKey?.qualifier) {
|
|
76
|
+
const q = String(args[permissionKey.qualifier] ?? '*');
|
|
77
|
+
const v = permissionKey.value ? String(args[permissionKey.value] ?? '') : '';
|
|
78
|
+
return { qualifier: q, value: v };
|
|
79
|
+
}
|
|
80
|
+
// No permissionKey: opaque tool
|
|
81
|
+
return { qualifier: '*', value: '' };
|
|
82
|
+
}
|
|
83
|
+
// ── Pattern Inference ───────────────────────────────────────────────────────
|
|
84
|
+
/** Generate a reasonable permission pattern from a concrete tool call */
|
|
85
|
+
export function inferPattern(toolName, args, permissionKey) {
|
|
86
|
+
const name = toolName.toLowerCase();
|
|
87
|
+
switch (name) {
|
|
88
|
+
case 'bash': {
|
|
89
|
+
const cmd = String(args.command || '');
|
|
90
|
+
const firstWord = cmd.trimStart().split(/\s+/)[0] || '*';
|
|
91
|
+
return `bash(${firstWord}:*)`;
|
|
92
|
+
}
|
|
93
|
+
case 'file': {
|
|
94
|
+
const action = String(args.action || '*');
|
|
95
|
+
const path = String(args.path || '');
|
|
96
|
+
const firstDir = path.split('/')[0];
|
|
97
|
+
const glob = firstDir && firstDir !== path ? `${firstDir}/**` : '*';
|
|
98
|
+
return `file(${action}:${glob})`;
|
|
99
|
+
}
|
|
100
|
+
case 'git':
|
|
101
|
+
return `git(${String(args.action || '*')})`;
|
|
102
|
+
case 'web': {
|
|
103
|
+
const action = String(args.action || '*');
|
|
104
|
+
if (action === 'fetch' && args.url) {
|
|
105
|
+
try {
|
|
106
|
+
const hostname = new URL(String(args.url)).hostname;
|
|
107
|
+
return `web(fetch:*${hostname}*)`;
|
|
108
|
+
}
|
|
109
|
+
catch { /* fall through */ }
|
|
110
|
+
}
|
|
111
|
+
return `web(${action}:*)`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Custom tools
|
|
115
|
+
if (permissionKey?.qualifier) {
|
|
116
|
+
const q = String(args[permissionKey.qualifier] ?? '*');
|
|
117
|
+
if (permissionKey.value) {
|
|
118
|
+
return `${name}(${q}:*)`;
|
|
119
|
+
}
|
|
120
|
+
return `${name}(${q})`;
|
|
121
|
+
}
|
|
122
|
+
return `${name}(*)`;
|
|
123
|
+
}
|
|
124
|
+
// ── Pattern Matching ────────────────────────────────────────────────────────
|
|
125
|
+
function matchesRule(pattern, toolName, key) {
|
|
126
|
+
// Tool name check
|
|
127
|
+
if (pattern.tool !== '*' && pattern.tool !== toolName.toLowerCase())
|
|
128
|
+
return false;
|
|
129
|
+
// Qualifier check
|
|
130
|
+
if (pattern.qualifier !== '*' && !globMatch(pattern.qualifier, key.qualifier))
|
|
131
|
+
return false;
|
|
132
|
+
// Glob check (if pattern has one)
|
|
133
|
+
if (pattern.glob !== null && key.value && !globMatch(pattern.glob, key.value))
|
|
134
|
+
return false;
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
// ── PermissionManager ───────────────────────────────────────────────────────
|
|
138
|
+
export class PermissionManager {
|
|
139
|
+
cwd;
|
|
140
|
+
projectPath;
|
|
141
|
+
globalPath;
|
|
142
|
+
sessionRules = [];
|
|
143
|
+
projectRules = [];
|
|
144
|
+
globalRules = [];
|
|
145
|
+
constructor(cwd) {
|
|
146
|
+
this.cwd = cwd;
|
|
147
|
+
this.projectPath = join(cwd, '.ag', 'permissions.json');
|
|
148
|
+
this.globalPath = join(AG_DIR, 'permissions.json');
|
|
149
|
+
this.reload();
|
|
150
|
+
}
|
|
151
|
+
/** Reload project + global rules from disk */
|
|
152
|
+
reload() {
|
|
153
|
+
this.projectRules = this.loadFile(this.projectPath);
|
|
154
|
+
this.globalRules = this.loadFile(this.globalPath);
|
|
155
|
+
}
|
|
156
|
+
/** Check whether a tool call is allowed, denied, or needs prompting */
|
|
157
|
+
check(toolName, args, permissionKey) {
|
|
158
|
+
const key = extractMatchKey(toolName, args, permissionKey);
|
|
159
|
+
const allRules = [...this.sessionRules, ...this.projectRules, ...this.globalRules];
|
|
160
|
+
// Deny wins: check deny rules first across all scopes
|
|
161
|
+
for (const rule of allRules) {
|
|
162
|
+
if (rule.effect === 'deny' && matchesRule(parsePattern(rule.pattern), toolName, key)) {
|
|
163
|
+
return 'deny';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Then check allow rules
|
|
167
|
+
for (const rule of allRules) {
|
|
168
|
+
if (rule.effect === 'allow' && matchesRule(parsePattern(rule.pattern), toolName, key)) {
|
|
169
|
+
return 'allow';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return 'ask';
|
|
173
|
+
}
|
|
174
|
+
/** Add a permission rule to a scope */
|
|
175
|
+
addRule(rule, scope) {
|
|
176
|
+
const list = this.rulesForScope(scope);
|
|
177
|
+
// Avoid duplicates
|
|
178
|
+
if (!list.some(r => r.pattern === rule.pattern && r.effect === rule.effect)) {
|
|
179
|
+
list.push(rule);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Remove a rule by pattern from a scope */
|
|
183
|
+
removeRule(pattern, scope) {
|
|
184
|
+
const list = this.rulesForScope(scope);
|
|
185
|
+
const idx = list.findIndex(r => r.pattern === pattern);
|
|
186
|
+
if (idx !== -1) {
|
|
187
|
+
list.splice(idx, 1);
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
/** Get rules, optionally filtered by scope */
|
|
193
|
+
getRules(scope) {
|
|
194
|
+
const result = [];
|
|
195
|
+
const add = (rules, s) => {
|
|
196
|
+
for (const r of rules)
|
|
197
|
+
result.push({ ...r, scope: s });
|
|
198
|
+
};
|
|
199
|
+
if (!scope || scope === 'session')
|
|
200
|
+
add(this.sessionRules, 'session');
|
|
201
|
+
if (!scope || scope === 'project')
|
|
202
|
+
add(this.projectRules, 'project');
|
|
203
|
+
if (!scope || scope === 'global')
|
|
204
|
+
add(this.globalRules, 'global');
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
/** Persist rules to disk */
|
|
208
|
+
save(scope) {
|
|
209
|
+
const path = scope === 'project' ? this.projectPath : this.globalPath;
|
|
210
|
+
const rules = scope === 'project' ? this.projectRules : this.globalRules;
|
|
211
|
+
const dir = join(path, '..');
|
|
212
|
+
if (!existsSync(dir))
|
|
213
|
+
mkdirSync(dir, { recursive: true });
|
|
214
|
+
const data = {
|
|
215
|
+
allow: rules.filter(r => r.effect === 'allow').map(r => r.pattern),
|
|
216
|
+
deny: rules.filter(r => r.effect === 'deny').map(r => r.pattern),
|
|
217
|
+
};
|
|
218
|
+
writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
|
|
219
|
+
}
|
|
220
|
+
/** Clear rules for a scope */
|
|
221
|
+
clear(scope) {
|
|
222
|
+
if (scope === 'session')
|
|
223
|
+
this.sessionRules = [];
|
|
224
|
+
else if (scope === 'project')
|
|
225
|
+
this.projectRules = [];
|
|
226
|
+
else if (scope === 'global')
|
|
227
|
+
this.globalRules = [];
|
|
228
|
+
}
|
|
229
|
+
// ── Private helpers ─────────────────────────────────────────────────────
|
|
230
|
+
rulesForScope(scope) {
|
|
231
|
+
switch (scope) {
|
|
232
|
+
case 'session': return this.sessionRules;
|
|
233
|
+
case 'project': return this.projectRules;
|
|
234
|
+
case 'global': return this.globalRules;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
loadFile(path) {
|
|
238
|
+
try {
|
|
239
|
+
const raw = JSON.parse(readFileSync(path, 'utf-8'));
|
|
240
|
+
const rules = [];
|
|
241
|
+
for (const p of raw.allow ?? [])
|
|
242
|
+
rules.push({ pattern: p, effect: 'allow' });
|
|
243
|
+
for (const p of raw.deny ?? [])
|
|
244
|
+
rules.push({ pattern: p, effect: 'deny' });
|
|
245
|
+
return rules;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAK5E;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DlE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGhD"}
|
package/dist/core/registry.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { writeFileSync, mkdirSync, existsSync, rmSync } from 'node:fs';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
|
+
import { scanContent } from './guardrails.js';
|
|
4
5
|
const SKILLS_DIR = join(homedir(), '.ag', 'skills');
|
|
5
6
|
const SEARCH_API = 'https://skills.sh/api/search';
|
|
6
7
|
function githubHeaders() {
|
|
@@ -84,6 +85,21 @@ export async function installSkill(source) {
|
|
|
84
85
|
continue;
|
|
85
86
|
}
|
|
86
87
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
88
|
+
if (relativePath.endsWith('.md') || relativePath.endsWith('.mjs')) {
|
|
89
|
+
const text = buffer.toString('utf-8');
|
|
90
|
+
const scan = scanContent(text, `installed file "${relativePath}" from ${repo}`);
|
|
91
|
+
if (!scan.ok) {
|
|
92
|
+
const reasons = scan.findings.filter(f => f.severity === 'block').map(f => f.message).join('; ');
|
|
93
|
+
errors.push(`Blocked ${relativePath}: ${reasons}`);
|
|
94
|
+
if (relativePath === 'SKILL.md') {
|
|
95
|
+
// Core skill file is compromised — abort entire installation
|
|
96
|
+
if (existsSync(skillDir))
|
|
97
|
+
rmSync(skillDir, { recursive: true });
|
|
98
|
+
throw new Error(`Skill "${skillName}" blocked by guardrails: ${reasons}`);
|
|
99
|
+
}
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
87
103
|
writeFileSync(destPath, buffer);
|
|
88
104
|
}
|
|
89
105
|
catch (err) {
|