compact-agent 1.18.0 → 1.19.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.
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Execpolicy DSL — a lightweight command-intent allowlist that gates
3
+ * bash commands BEFORE the existing ask/auto/yolo permission flow.
4
+ *
5
+ * Inspired by codex-rs/execpolicy/. Three decisions per rule:
6
+ * allow — skip the permission prompt (treat as yolo for this cmd)
7
+ * prompt — force the prompt even in `auto` mode
8
+ * forbidden — block outright, don't even prompt; print reason
9
+ *
10
+ * First matching rule wins. If no rule matches, the original
11
+ * permission mode is honored (so the default is "no change to behavior").
12
+ *
13
+ * The DEFAULT_RULES below codify the most-common safety intents the
14
+ * Codex execpolicy ships, condensed to what's portable across Win/
15
+ * macOS/Linux. Users can override at runtime via /perm-policy and the
16
+ * config field `execpolicy` (TODO in v1.20).
17
+ *
18
+ * Real OS-native sandboxing (Seatbelt/landlock/ACL) is intentionally
19
+ * out of scope for this layer — it's an evening's work in TS for an
20
+ * intent gate, vs weeks for proper sandboxing. This is the audit's
21
+ * pragmatic recommendation.
22
+ */
23
+ export type Decision = 'allow' | 'prompt' | 'forbidden';
24
+ export interface ExecRule {
25
+ /** Command prefix or regex. String values are treated as `^<value>`. */
26
+ pattern: RegExp | string;
27
+ decision: Decision;
28
+ /** Optional: only match if this also tests true */
29
+ match?: RegExp | string;
30
+ /** Optional: only match if this tests FALSE */
31
+ notMatch?: RegExp | string;
32
+ /** Shown to the user when decision != 'allow' */
33
+ reason?: string;
34
+ /** Human-readable rule name for logging / debugging */
35
+ id?: string;
36
+ }
37
+ export interface PolicyResult {
38
+ decision: Decision;
39
+ reason?: string;
40
+ ruleId?: string;
41
+ }
42
+ /**
43
+ * Built-in policy. Ordered: most-specific dangerous patterns first
44
+ * so they fire before broader category rules. Allows come last so
45
+ * a dangerous variant of "git" hits the prompt rule before the
46
+ * "git read ops" allow.
47
+ */
48
+ export declare const DEFAULT_RULES: ExecRule[];
49
+ /**
50
+ * Evaluate a bash command against the policy. Returns the FIRST
51
+ * matching rule's decision. If nothing matches, returns
52
+ * { decision: 'prompt' } so the user's configured permission mode
53
+ * decides — i.e. a no-op for `auto` (non-destructive tools pass)
54
+ * and a single prompt for `ask`.
55
+ */
56
+ export declare function evaluateCommand(cmd: string, rules?: ExecRule[]): PolicyResult;
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Execpolicy DSL — a lightweight command-intent allowlist that gates
3
+ * bash commands BEFORE the existing ask/auto/yolo permission flow.
4
+ *
5
+ * Inspired by codex-rs/execpolicy/. Three decisions per rule:
6
+ * allow — skip the permission prompt (treat as yolo for this cmd)
7
+ * prompt — force the prompt even in `auto` mode
8
+ * forbidden — block outright, don't even prompt; print reason
9
+ *
10
+ * First matching rule wins. If no rule matches, the original
11
+ * permission mode is honored (so the default is "no change to behavior").
12
+ *
13
+ * The DEFAULT_RULES below codify the most-common safety intents the
14
+ * Codex execpolicy ships, condensed to what's portable across Win/
15
+ * macOS/Linux. Users can override at runtime via /perm-policy and the
16
+ * config field `execpolicy` (TODO in v1.20).
17
+ *
18
+ * Real OS-native sandboxing (Seatbelt/landlock/ACL) is intentionally
19
+ * out of scope for this layer — it's an evening's work in TS for an
20
+ * intent gate, vs weeks for proper sandboxing. This is the audit's
21
+ * pragmatic recommendation.
22
+ */
23
+ /**
24
+ * Built-in policy. Ordered: most-specific dangerous patterns first
25
+ * so they fire before broader category rules. Allows come last so
26
+ * a dangerous variant of "git" hits the prompt rule before the
27
+ * "git read ops" allow.
28
+ */
29
+ export const DEFAULT_RULES = [
30
+ // ── FORBIDDEN (block outright) ────────────────────────
31
+ {
32
+ id: 'rm-rf-root',
33
+ pattern: /\brm\s/,
34
+ match: /-r[a-z]*f|-f[a-z]*r/,
35
+ notMatch: /^[\s\S]*?\srm\s.*\s\.\.?\/?$/, // allow rm -rf . or ..
36
+ decision: 'forbidden',
37
+ reason: 'rm with recursive force flag; require explicit user approval',
38
+ },
39
+ {
40
+ id: 'rm-system-path',
41
+ pattern: /\brm\s.*\s(\/|C:\\?|\/usr|\/etc|\/bin|\/sbin|\/var|\/boot)\b/,
42
+ decision: 'forbidden',
43
+ reason: 'targeting a system path',
44
+ },
45
+ {
46
+ id: 'shutdown',
47
+ pattern: /^(shutdown|reboot|halt|poweroff)\b/,
48
+ decision: 'forbidden',
49
+ reason: 'system shutdown / reboot',
50
+ },
51
+ {
52
+ id: 'dd-disk',
53
+ pattern: /^dd\s/,
54
+ match: /of=\/dev\/(sd|nvme|hd|disk)/,
55
+ decision: 'forbidden',
56
+ reason: 'dd writing to raw disk device',
57
+ },
58
+ {
59
+ id: 'format-disk',
60
+ pattern: /^(format|mkfs|diskpart)\b/,
61
+ decision: 'forbidden',
62
+ reason: 'disk formatting',
63
+ },
64
+ // ── PROMPT (force prompt even in auto mode) ───────────
65
+ {
66
+ id: 'sudo',
67
+ pattern: /^sudo\b/,
68
+ decision: 'prompt',
69
+ reason: 'requires elevated privileges',
70
+ },
71
+ {
72
+ id: 'rm-recursive',
73
+ pattern: /\brm\s/,
74
+ match: /-r/,
75
+ decision: 'prompt',
76
+ reason: 'recursive removal',
77
+ },
78
+ {
79
+ id: 'curl-pipe-shell',
80
+ pattern: /\bcurl\b/,
81
+ match: /\|\s*(sh|bash|zsh|fish)\b/,
82
+ decision: 'prompt',
83
+ reason: 'piping curl output directly to shell',
84
+ },
85
+ {
86
+ id: 'wget-pipe-shell',
87
+ pattern: /\bwget\b/,
88
+ match: /\|\s*(sh|bash|zsh|fish)\b/,
89
+ decision: 'prompt',
90
+ reason: 'piping wget output directly to shell',
91
+ },
92
+ {
93
+ id: 'git-force-push',
94
+ pattern: /^git\s+push\b/,
95
+ match: /--force(?!-with-lease)|--mirror|\+/,
96
+ decision: 'prompt',
97
+ reason: 'force-push (rewrites remote history)',
98
+ },
99
+ {
100
+ id: 'git-reset-hard',
101
+ pattern: /^git\s+reset\b/,
102
+ match: /--hard/,
103
+ decision: 'prompt',
104
+ reason: 'hard reset discards uncommitted work',
105
+ },
106
+ {
107
+ id: 'git-clean-force',
108
+ pattern: /^git\s+clean\b/,
109
+ match: /-f/,
110
+ decision: 'prompt',
111
+ reason: 'git clean -f deletes untracked files',
112
+ },
113
+ {
114
+ id: 'npm-mutate-registry',
115
+ pattern: /^npm\s+(unpublish|deprecate)\b/,
116
+ decision: 'prompt',
117
+ reason: 'mutating the npm registry',
118
+ },
119
+ {
120
+ id: 'pip-uninstall',
121
+ pattern: /^pip(3)?\s+uninstall\b/,
122
+ decision: 'prompt',
123
+ reason: 'pip uninstall',
124
+ },
125
+ {
126
+ id: 'docker-rm-volume',
127
+ pattern: /^docker\s+(volume\s+rm|system\s+prune|rm\s+--force|kill)\b/,
128
+ decision: 'prompt',
129
+ reason: 'docker destructive operation',
130
+ },
131
+ // ── ALLOW (skip prompt entirely) ──────────────────────
132
+ // Pure read / inspection ops — safe to auto-approve even in `ask` mode
133
+ { id: 'cat', pattern: /^cat\s/, decision: 'allow' },
134
+ { id: 'less', pattern: /^less\s/, decision: 'allow' },
135
+ { id: 'more', pattern: /^more\s/, decision: 'allow' },
136
+ { id: 'head', pattern: /^head\s/, decision: 'allow' },
137
+ { id: 'tail', pattern: /^tail\s/, decision: 'allow' },
138
+ { id: 'ls', pattern: /^ls\b/, decision: 'allow' },
139
+ { id: 'dir', pattern: /^dir\b/, decision: 'allow' },
140
+ { id: 'pwd', pattern: /^pwd\s*$/, decision: 'allow' },
141
+ { id: 'echo', pattern: /^echo\s/, decision: 'allow' },
142
+ { id: 'which', pattern: /^which\s/, decision: 'allow' },
143
+ { id: 'where', pattern: /^where\s/, decision: 'allow' },
144
+ { id: 'whoami', pattern: /^whoami\s*$/, decision: 'allow' },
145
+ { id: 'env', pattern: /^env\s*$|^env\s+\|\s/, decision: 'allow' },
146
+ { id: 'date', pattern: /^date\s*$|^date\s+\+/, decision: 'allow' },
147
+ { id: 'uname', pattern: /^uname\b/, decision: 'allow' },
148
+ { id: 'file', pattern: /^file\s/, decision: 'allow' },
149
+ { id: 'wc', pattern: /^wc\s/, decision: 'allow' },
150
+ { id: 'stat', pattern: /^stat\s/, decision: 'allow' },
151
+ // Git read ops
152
+ {
153
+ id: 'git-read',
154
+ pattern: /^git\s+(status|log|diff|show|branch|tag|remote(\s+-v)?|stash\s+list|config\s+--get|reflog|describe|blame|rev-parse|ls-files)\b/,
155
+ decision: 'allow',
156
+ },
157
+ // npm/pnpm/yarn read ops
158
+ {
159
+ id: 'npm-read',
160
+ pattern: /^(npm|pnpm|yarn)\s+(list|ls|view|info|outdated|audit|why|exec|run\s+--list)\b/,
161
+ decision: 'allow',
162
+ },
163
+ // pip / python read ops
164
+ {
165
+ id: 'pip-read',
166
+ pattern: /^(pip|pip3)\s+(list|show|freeze|check|search)\b/,
167
+ decision: 'allow',
168
+ },
169
+ // Process listing
170
+ {
171
+ id: 'process-list',
172
+ pattern: /^(ps|top|htop|tasklist|jobs)\b/,
173
+ decision: 'allow',
174
+ },
175
+ ];
176
+ function compileMatcher(p, anchor) {
177
+ if (p instanceof RegExp)
178
+ return p;
179
+ return new RegExp(anchor ? `^${p}` : p);
180
+ }
181
+ function applyRule(cmd, rule) {
182
+ if (!compileMatcher(rule.pattern, true).test(cmd))
183
+ return false;
184
+ if (rule.match && !compileMatcher(rule.match, false).test(cmd))
185
+ return false;
186
+ if (rule.notMatch && compileMatcher(rule.notMatch, false).test(cmd))
187
+ return false;
188
+ return true;
189
+ }
190
+ /**
191
+ * Evaluate a bash command against the policy. Returns the FIRST
192
+ * matching rule's decision. If nothing matches, returns
193
+ * { decision: 'prompt' } so the user's configured permission mode
194
+ * decides — i.e. a no-op for `auto` (non-destructive tools pass)
195
+ * and a single prompt for `ask`.
196
+ */
197
+ export function evaluateCommand(cmd, rules = DEFAULT_RULES) {
198
+ const c = cmd.trim();
199
+ if (!c)
200
+ return { decision: 'prompt' };
201
+ for (const r of rules) {
202
+ if (applyRule(c, r)) {
203
+ return { decision: r.decision, reason: r.reason, ruleId: r.id };
204
+ }
205
+ }
206
+ // No rule matched — defer to the normal permission flow
207
+ return { decision: 'prompt' };
208
+ }
209
+ //# sourceMappingURL=execpolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execpolicy.js","sourceRoot":"","sources":["../src/execpolicy.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { saveConfig } from './config.js';
3
+ import { evaluateCommand } from './execpolicy.js';
3
4
  /**
4
5
  * Check if a tool call is allowed under the current permission mode.
5
6
  * Returns true if allowed, false if denied.
@@ -11,7 +12,28 @@ import { saveConfig } from './config.js';
11
12
  * @returns True if the tool call is allowed, false if denied
12
13
  */
13
14
  export async function checkPermission(tool, input, config, rl) {
14
- // yolo mode = everything allowed
15
+ // ── Execpolicy intent-gate (runs BEFORE other checks) ──
16
+ // For bash commands, evaluate the static-policy DSL first. This lets
17
+ // us auto-approve obviously-safe ops (cat, ls, git log) AND block
18
+ // obviously-dangerous ones (rm -rf system path, shutdown) without
19
+ // burning a user prompt either way. Only fires for the `bash` tool.
20
+ if (tool.name === 'bash') {
21
+ const cmd = String(input.command || '');
22
+ const policy = evaluateCommand(cmd);
23
+ if (policy.decision === 'forbidden') {
24
+ console.log(chalk.red(`\n ✗ Blocked by execpolicy${policy.ruleId ? ` (${policy.ruleId})` : ''}: ${policy.reason || 'command not permitted'}`));
25
+ console.log(chalk.dim(` $ ${cmd.slice(0, 120)}`));
26
+ return false;
27
+ }
28
+ if (policy.decision === 'allow') {
29
+ // Skip the full permission flow — policy says this is safe
30
+ return true;
31
+ }
32
+ // policy.decision === 'prompt' → fall through to the usual flow
33
+ // (alwaysAllowedTools check, mode check, ask if needed)
34
+ }
35
+ // yolo mode = everything allowed (execpolicy 'forbidden' still wins,
36
+ // applied above; allow + prompt both pass through yolo)
15
37
  if (config.permissionMode === 'yolo')
16
38
  return true;
17
39
  // Read-only tools always allowed
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAU,EACV,KAA8B,EAC9B,MAAuB,EACvB,EAAsB;IAEtB,iCAAiC;IACjC,IAAI,MAAM,CAAC,cAAc,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAElD,iCAAiC;IACjC,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAEjC,kEAAkE;IAClE,sEAAsE;IACtE,oEAAoE;IACpE,qEAAqE;IACrE,uEAAuE;IACvE,mCAAmC;IACnC,IAAI,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhE,yDAAyD;IACzD,IAAI,MAAM,CAAC,cAAc,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAEzE,qDAAqD;IACrD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAE7B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACvE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAEtC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;QACnB,wEAAwE;QACxE,sEAAsE;QACtE,kEAAkE;QAClE,MAAM,CAAC,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAC5D,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,IAAI,CAAC,IAAI,iEAAiE,CAAC,CAAC,CAAC;QACzH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC;AAC9C,CAAC;AAED,SAAS,cAAc,CAAC,IAAU,EAAE,KAA8B;IAChE,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;QAChC,KAAK,YAAY;YACf,OAAO,eAAe,KAAK,CAAC,SAAS,KAAK,CAAE,KAAK,CAAC,OAAkB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC;QAC1G,KAAK,WAAW;YACd,OAAO,WAAW,KAAK,CAAC,SAAS,EAAE,CAAC;QACtC;YACE,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACtD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compact-agent",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "A dense, feature-rich AI coding agent for the terminal. Built-in voice dictation (Whisper) + TTS readout (ElevenLabs) + screen-reader mode for blind / low-vision users. 80+ slash commands, 9 modes including Hermes self-improving loop, multi-agent orchestration, bundled everything-claude-code skills library, learning system, and observable LLM transport. Works with OpenRouter, OpenAI, Anthropic-compatible, Ollama, LM Studio, DeepSeek, or any OpenAI-compatible API.",
5
5
  "type": "module",
6
6
  "license": "MIT",