@trenchwork/erosolar 1.1.27 → 1.1.29

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.
Files changed (105) hide show
  1. package/SECURITY.md +35 -0
  2. package/dist/bin/deepseek.js +14 -8
  3. package/dist/bin/deepseek.js.map +1 -1
  4. package/dist/capabilities/index.d.ts +6 -0
  5. package/dist/capabilities/index.d.ts.map +1 -1
  6. package/dist/capabilities/index.js +6 -0
  7. package/dist/capabilities/index.js.map +1 -1
  8. package/dist/capabilities/interactionCapability.d.ts +6 -0
  9. package/dist/capabilities/interactionCapability.d.ts.map +1 -0
  10. package/dist/capabilities/interactionCapability.js +17 -0
  11. package/dist/capabilities/interactionCapability.js.map +1 -0
  12. package/dist/capabilities/mcpCapability.d.ts.map +1 -1
  13. package/dist/capabilities/mcpCapability.js +4 -2
  14. package/dist/capabilities/mcpCapability.js.map +1 -1
  15. package/dist/capabilities/monitorCapability.d.ts +6 -0
  16. package/dist/capabilities/monitorCapability.d.ts.map +1 -0
  17. package/dist/capabilities/monitorCapability.js +19 -0
  18. package/dist/capabilities/monitorCapability.js.map +1 -0
  19. package/dist/capabilities/planModeCapability.d.ts +6 -0
  20. package/dist/capabilities/planModeCapability.d.ts.map +1 -0
  21. package/dist/capabilities/planModeCapability.js +16 -0
  22. package/dist/capabilities/planModeCapability.js.map +1 -0
  23. package/dist/capabilities/scheduleCapability.d.ts +6 -0
  24. package/dist/capabilities/scheduleCapability.d.ts.map +1 -0
  25. package/dist/capabilities/scheduleCapability.js +16 -0
  26. package/dist/capabilities/scheduleCapability.js.map +1 -0
  27. package/dist/capabilities/triggerCapability.d.ts +6 -0
  28. package/dist/capabilities/triggerCapability.d.ts.map +1 -0
  29. package/dist/capabilities/triggerCapability.js +16 -0
  30. package/dist/capabilities/triggerCapability.js.map +1 -0
  31. package/dist/capabilities/worktreeCapability.d.ts +6 -0
  32. package/dist/capabilities/worktreeCapability.d.ts.map +1 -0
  33. package/dist/capabilities/worktreeCapability.js +16 -0
  34. package/dist/capabilities/worktreeCapability.js.map +1 -0
  35. package/dist/contracts/agent-schemas.json +1 -1
  36. package/dist/core/projectTracker.d.ts +96 -0
  37. package/dist/core/projectTracker.d.ts.map +1 -0
  38. package/dist/core/projectTracker.js +275 -0
  39. package/dist/core/projectTracker.js.map +1 -0
  40. package/dist/core/reviewerGuard.d.ts +37 -0
  41. package/dist/core/reviewerGuard.d.ts.map +1 -0
  42. package/dist/core/reviewerGuard.js +188 -0
  43. package/dist/core/reviewerGuard.js.map +1 -0
  44. package/dist/core/toolRuntime.d.ts.map +1 -1
  45. package/dist/core/toolRuntime.js +51 -0
  46. package/dist/core/toolRuntime.js.map +1 -1
  47. package/dist/core/userApproval.d.ts +21 -0
  48. package/dist/core/userApproval.d.ts.map +1 -1
  49. package/dist/core/userApproval.js +45 -0
  50. package/dist/core/userApproval.js.map +1 -1
  51. package/dist/headless/interactiveShell.js +35 -0
  52. package/dist/headless/interactiveShell.js.map +1 -1
  53. package/dist/plugins/tools/mcp/mcpClient.d.ts +10 -0
  54. package/dist/plugins/tools/mcp/mcpClient.d.ts.map +1 -1
  55. package/dist/plugins/tools/mcp/mcpClient.js +6 -0
  56. package/dist/plugins/tools/mcp/mcpClient.js.map +1 -1
  57. package/dist/runtime/node.d.ts +2 -0
  58. package/dist/runtime/node.d.ts.map +1 -1
  59. package/dist/runtime/node.js +28 -28
  60. package/dist/runtime/node.js.map +1 -1
  61. package/dist/runtime/profileGates.d.ts +19 -0
  62. package/dist/runtime/profileGates.d.ts.map +1 -0
  63. package/dist/runtime/profileGates.js +23 -0
  64. package/dist/runtime/profileGates.js.map +1 -0
  65. package/dist/tools/interactionTools.d.ts +16 -0
  66. package/dist/tools/interactionTools.d.ts.map +1 -0
  67. package/dist/tools/interactionTools.js +207 -0
  68. package/dist/tools/interactionTools.js.map +1 -0
  69. package/dist/tools/monitorTools.d.ts +16 -0
  70. package/dist/tools/monitorTools.d.ts.map +1 -0
  71. package/dist/tools/monitorTools.js +159 -0
  72. package/dist/tools/monitorTools.js.map +1 -0
  73. package/dist/tools/planModeTools.d.ts +32 -0
  74. package/dist/tools/planModeTools.d.ts.map +1 -0
  75. package/dist/tools/planModeTools.js +200 -0
  76. package/dist/tools/planModeTools.js.map +1 -0
  77. package/dist/tools/scheduleTools.d.ts +39 -0
  78. package/dist/tools/scheduleTools.d.ts.map +1 -0
  79. package/dist/tools/scheduleTools.js +182 -0
  80. package/dist/tools/scheduleTools.js.map +1 -0
  81. package/dist/tools/triggerTools.d.ts +28 -0
  82. package/dist/tools/triggerTools.d.ts.map +1 -0
  83. package/dist/tools/triggerTools.js +210 -0
  84. package/dist/tools/triggerTools.js.map +1 -0
  85. package/dist/tools/worktreeTools.d.ts +21 -0
  86. package/dist/tools/worktreeTools.d.ts.map +1 -0
  87. package/dist/tools/worktreeTools.js +158 -0
  88. package/dist/tools/worktreeTools.js.map +1 -0
  89. package/dist/ui/ink/App.d.ts.map +1 -1
  90. package/dist/ui/ink/App.js +2 -1
  91. package/dist/ui/ink/App.js.map +1 -1
  92. package/dist/ui/ink/ChatStatic.d.ts.map +1 -1
  93. package/dist/ui/ink/ChatStatic.js +7 -6
  94. package/dist/ui/ink/ChatStatic.js.map +1 -1
  95. package/dist/ui/ink/StatusLine.d.ts.map +1 -1
  96. package/dist/ui/ink/StatusLine.js +2 -1
  97. package/dist/ui/ink/StatusLine.js.map +1 -1
  98. package/dist/ui/theme.d.ts.map +1 -1
  99. package/dist/ui/theme.js +31 -29
  100. package/dist/ui/theme.js.map +1 -1
  101. package/dist/utils/lambdaClient.d.ts +35 -0
  102. package/dist/utils/lambdaClient.d.ts.map +1 -0
  103. package/dist/utils/lambdaClient.js +81 -0
  104. package/dist/utils/lambdaClient.js.map +1 -0
  105. package/package.json +1 -1
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Project tracking — pairs every CLI session with a stable project
3
+ * doc keyed off the working directory. The project doc rolls up
4
+ * lastSeenAt / sessionCount / totalTokens so the audit portal can
5
+ * show "what's the CLI been doing in /home/bo/GitHub/foo lately"
6
+ * without scanning every session.
7
+ *
8
+ * Identity:
9
+ * projectId = sha256(absolute path).slice(0, 12)
10
+ * Same checkout on the same machine → same project across launches,
11
+ * with no operator input needed.
12
+ *
13
+ * Schema (Firestore):
14
+ * projects/{projectId}
15
+ * ownerUid: string
16
+ * name: string (basename of workingDir)
17
+ * workingDir: string
18
+ * workingDirHash: string (the projectId, repeated for queries)
19
+ * gitRemote: string | null
20
+ * gitBranchAtFirst: string | null
21
+ * createdAt: timestamp (server time)
22
+ * lastSeenAt: timestamp (server time, every boot)
23
+ * sessionCount: int (Firestore Increment(+1) per boot)
24
+ * totalTokens: int (Increment on session-end with usage)
25
+ * status: 'active' | 'archived'
26
+ *
27
+ * usage_logs/{uid}/sessions/{sessionId}
28
+ * ... existing session-start fields ...
29
+ * projectId: string (FK)
30
+ * gitBranch: string | null
31
+ * gitCommit: string | null
32
+ * outcome: 'in_progress' | 'completed' | 'cancelled' | 'errored'
33
+ * filesModified: string[] (post-end update)
34
+ * toolsUsed: string[] (post-end update)
35
+ * tokensIn / tokensOut: int (post-end update)
36
+ * endedAt: timestamp | null (post-end update)
37
+ */
38
+ import { createHash } from 'node:crypto';
39
+ import { execSync } from 'node:child_process';
40
+ import { existsSync } from 'node:fs';
41
+ import { basename, resolve } from 'node:path';
42
+ import { FIREBASE_PROJECT_ID, getAuthStatus, getValidIdToken } from './auth.js';
43
+ const FIRESTORE_BASE = `https://firestore.googleapis.com/v1/projects/${FIREBASE_PROJECT_ID}/databases/(default)/documents`;
44
+ export function deriveProjectId(workingDir) {
45
+ return createHash('sha256').update(resolve(workingDir)).digest('hex').slice(0, 12);
46
+ }
47
+ function safeGit(args, cwd) {
48
+ try {
49
+ const out = execSync(`git ${args.map(shellQuote).join(' ')}`, {
50
+ cwd,
51
+ encoding: 'utf8',
52
+ stdio: ['ignore', 'pipe', 'ignore'],
53
+ timeout: 2000,
54
+ });
55
+ return out.trim() || null;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ function shellQuote(s) {
62
+ return /^[\w./:=-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
63
+ }
64
+ function gitInfo(workingDir) {
65
+ if (!existsSync(workingDir))
66
+ return { branch: null, commit: null, remote: null };
67
+ return {
68
+ branch: safeGit(['rev-parse', '--abbrev-ref', 'HEAD'], workingDir),
69
+ commit: safeGit(['rev-parse', 'HEAD'], workingDir),
70
+ remote: safeGit(['config', '--get', 'remote.origin.url'], workingDir),
71
+ };
72
+ }
73
+ export function buildProjectContext(workingDir) {
74
+ const abs = resolve(workingDir);
75
+ const id = deriveProjectId(abs);
76
+ const { branch, commit, remote } = gitInfo(abs);
77
+ return {
78
+ projectId: id,
79
+ workingDir: abs,
80
+ name: basename(abs) || abs,
81
+ gitBranch: branch,
82
+ gitCommit: commit,
83
+ gitRemote: remote,
84
+ };
85
+ }
86
+ function strField(v) {
87
+ if (v == null || v === '')
88
+ return { nullValue: null };
89
+ return { stringValue: v };
90
+ }
91
+ /**
92
+ * Idempotent register of `projects/{projectId}`. Uses Firestore's
93
+ * REST `commit` endpoint with two writes in a transaction-like
94
+ * batch: an upsert of mutable fields + a server-side
95
+ * `Increment(1)` on sessionCount. The createdAt-vs-lastSeenAt
96
+ * distinction is preserved because Firestore PATCH with a partial
97
+ * field mask only touches the listed fields.
98
+ */
99
+ export async function registerProject(workingDir) {
100
+ const context = buildProjectContext(workingDir);
101
+ const status = getAuthStatus();
102
+ if (!status.authenticated || !status.uid) {
103
+ return { ok: false, context, reason: 'not signed in' };
104
+ }
105
+ try {
106
+ const idToken = await getValidIdToken();
107
+ // Two writes via :commit so server-side timestamps + Increment fire
108
+ // atomically. The first PATCH ensures createdAt and gitBranchAtFirst
109
+ // only land on first write (updateMask omits them on subsequent
110
+ // calls — see below). The second write Increments sessionCount and
111
+ // sets lastSeenAt every boot.
112
+ const docPath = `projects/${context.projectId}`;
113
+ const fullName = `projects/${FIREBASE_PROJECT_ID}/databases/(default)/documents/${docPath}`;
114
+ // Discover whether the doc exists (so we can skip writing
115
+ // createdAt / gitBranchAtFirst on subsequent boots).
116
+ const getRes = await fetch(`${FIRESTORE_BASE}/${docPath}`, {
117
+ headers: { Authorization: `Bearer ${idToken}` },
118
+ });
119
+ const exists = getRes.status === 200;
120
+ const fields = {
121
+ ownerUid: { stringValue: status.uid },
122
+ name: { stringValue: context.name },
123
+ workingDir: { stringValue: context.workingDir },
124
+ workingDirHash: { stringValue: context.projectId },
125
+ gitRemote: strField(context.gitRemote),
126
+ lastSeenAt: { timestampValue: new Date().toISOString() },
127
+ status: { stringValue: 'active' },
128
+ };
129
+ if (!exists) {
130
+ fields['createdAt'] = { timestampValue: new Date().toISOString() };
131
+ fields['gitBranchAtFirst'] = strField(context.gitBranch);
132
+ fields['sessionCount'] = { integerValue: '1' };
133
+ fields['totalTokens'] = { integerValue: '0' };
134
+ }
135
+ const updateMask = Object.keys(fields).map((k) => `updateMask.fieldPaths=${k}`).join('&');
136
+ const patchUrl = `${FIRESTORE_BASE}/${docPath}?${updateMask}`;
137
+ const patchRes = await fetch(patchUrl, {
138
+ method: 'PATCH',
139
+ headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
140
+ body: JSON.stringify({ fields }),
141
+ });
142
+ if (!patchRes.ok) {
143
+ const txt = await patchRes.text().catch(() => '<no body>');
144
+ return { ok: false, context, reason: `PATCH ${patchRes.status}: ${txt.slice(0, 200)}` };
145
+ }
146
+ // For existing docs, increment sessionCount via the :commit endpoint.
147
+ if (exists) {
148
+ const commitUrl = `${FIRESTORE_BASE.replace(/\/documents$/, '')}/documents:commit`;
149
+ const commitBody = {
150
+ writes: [{
151
+ transform: {
152
+ document: fullName,
153
+ fieldTransforms: [{
154
+ fieldPath: 'sessionCount',
155
+ increment: { integerValue: '1' },
156
+ }],
157
+ },
158
+ }],
159
+ };
160
+ await fetch(commitUrl, {
161
+ method: 'POST',
162
+ headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
163
+ body: JSON.stringify(commitBody),
164
+ }).catch(() => { });
165
+ }
166
+ return { ok: true, context };
167
+ }
168
+ catch (err) {
169
+ return { ok: false, context, reason: err instanceof Error ? err.message : String(err) };
170
+ }
171
+ }
172
+ /**
173
+ * Append `usage_logs/{uid}/sessions/{sessionId}` with the project FK.
174
+ * Returns the sessionId so the caller can later write session-end.
175
+ * Replaces the prior `writeUsageLog` for the project-aware path.
176
+ */
177
+ export async function writeSessionStart(entry) {
178
+ const status = getAuthStatus();
179
+ if (!status.authenticated || !status.uid) {
180
+ return { ok: false, sessionId: null, reason: 'not signed in' };
181
+ }
182
+ try {
183
+ const idToken = await getValidIdToken();
184
+ const sessionId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
185
+ const url = `${FIRESTORE_BASE}/usage_logs/${encodeURIComponent(status.uid)}/sessions?documentId=${encodeURIComponent(sessionId)}`;
186
+ const body = {
187
+ fields: {
188
+ uid: { stringValue: status.uid },
189
+ email: strField(status.email ?? ''),
190
+ startedAt: { timestampValue: new Date().toISOString() },
191
+ profile: { stringValue: entry.profile },
192
+ model: { stringValue: entry.model },
193
+ version: { stringValue: entry.version },
194
+ platform: { stringValue: entry.platform },
195
+ projectId: { stringValue: entry.project.projectId },
196
+ gitBranch: strField(entry.project.gitBranch),
197
+ gitCommit: strField(entry.project.gitCommit),
198
+ outcome: { stringValue: 'in_progress' },
199
+ tokensIn: { integerValue: '0' },
200
+ tokensOut: { integerValue: '0' },
201
+ },
202
+ };
203
+ const res = await fetch(url, {
204
+ method: 'POST',
205
+ headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
206
+ body: JSON.stringify(body),
207
+ });
208
+ if (!res.ok) {
209
+ const txt = await res.text().catch(() => '<no body>');
210
+ return { ok: false, sessionId: null, reason: `Firestore ${res.status}: ${txt.slice(0, 200)}` };
211
+ }
212
+ return { ok: true, sessionId };
213
+ }
214
+ catch (err) {
215
+ return { ok: false, sessionId: null, reason: err instanceof Error ? err.message : String(err) };
216
+ }
217
+ }
218
+ /**
219
+ * Patch the session row on shell exit + bump the parent project's
220
+ * totalTokens. Best-effort; a kill -9 leaves the session at
221
+ * `outcome: in_progress` which the audit page can highlight.
222
+ */
223
+ export async function writeSessionEnd(entry) {
224
+ const status = getAuthStatus();
225
+ if (!status.authenticated || !status.uid) {
226
+ return { ok: false, reason: 'not signed in' };
227
+ }
228
+ try {
229
+ const idToken = await getValidIdToken();
230
+ const sessionDoc = `usage_logs/${encodeURIComponent(status.uid)}/sessions/${encodeURIComponent(entry.sessionId)}`;
231
+ const sessionFields = ['outcome', 'endedAt', 'filesModified', 'toolsUsed', 'tokensIn', 'tokensOut'];
232
+ const sessionMask = sessionFields.map((k) => `updateMask.fieldPaths=${k}`).join('&');
233
+ const sessionBody = {
234
+ fields: {
235
+ outcome: { stringValue: entry.outcome },
236
+ endedAt: { timestampValue: new Date().toISOString() },
237
+ filesModified: { arrayValue: { values: entry.filesModified.slice(0, 100).map((s) => ({ stringValue: s })) } },
238
+ toolsUsed: { arrayValue: { values: entry.toolsUsed.slice(0, 100).map((s) => ({ stringValue: s })) } },
239
+ tokensIn: { integerValue: String(entry.tokensIn) },
240
+ tokensOut: { integerValue: String(entry.tokensOut) },
241
+ },
242
+ };
243
+ await fetch(`${FIRESTORE_BASE}/${sessionDoc}?${sessionMask}`, {
244
+ method: 'PATCH',
245
+ headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
246
+ body: JSON.stringify(sessionBody),
247
+ });
248
+ // Increment the project's totalTokens via the :commit endpoint.
249
+ const totalDelta = entry.tokensIn + entry.tokensOut;
250
+ if (totalDelta > 0) {
251
+ const commitUrl = `${FIRESTORE_BASE.replace(/\/documents$/, '')}/documents:commit`;
252
+ const commitBody = {
253
+ writes: [{
254
+ transform: {
255
+ document: `projects/${FIREBASE_PROJECT_ID}/databases/(default)/documents/projects/${entry.projectId}`,
256
+ fieldTransforms: [{
257
+ fieldPath: 'totalTokens',
258
+ increment: { integerValue: String(totalDelta) },
259
+ }],
260
+ },
261
+ }],
262
+ };
263
+ await fetch(commitUrl, {
264
+ method: 'POST',
265
+ headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
266
+ body: JSON.stringify(commitBody),
267
+ }).catch(() => { });
268
+ }
269
+ return { ok: true };
270
+ }
271
+ catch (err) {
272
+ return { ok: false, reason: err instanceof Error ? err.message : String(err) };
273
+ }
274
+ }
275
+ //# sourceMappingURL=projectTracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectTracker.js","sourceRoot":"","sources":["../../src/core/projectTracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Constitutional reviewer-agent guard. Runs between user-configured
3
+ * shell hooks and the actual tool handler. Two layers:
4
+ *
5
+ * 1. **Hardcoded heuristic guard (always on)**. Catches the
6
+ * well-known catastrophic patterns (rm -rf /, curl-to-shell,
7
+ * anything that targets a path outside the workspace AND
8
+ * destroys data). Cheap, deterministic, no LLM call.
9
+ *
10
+ * 2. **LLM reviewer (gated by EROSOLAR_REVIEWER=1)**. Sends the
11
+ * proposed tool call + a brief constitution to a small, cheap
12
+ * reviewer model (Anthropic Haiku by default). Returns one of
13
+ * `approve | refine | veto` with a reason. The decision is
14
+ * logged to Firestore at reviewer_log/{uid}/decisions/{id} for
15
+ * operator review.
16
+ *
17
+ * The reviewer fails *open* on any error (network blip, unparseable
18
+ * model response, missing API key). Refusing-by-default would brick
19
+ * the CLI for users without the reviewer model configured. Instead,
20
+ * a failure is itself an audit-log event the operator can review.
21
+ */
22
+ export interface ReviewDecision {
23
+ decision: 'approve' | 'refine' | 'veto';
24
+ reason: string;
25
+ source: 'heuristic' | 'llm' | 'disabled' | 'error';
26
+ }
27
+ export declare function buildReviewPrompt(toolName: string, args: unknown): string;
28
+ export declare function parseReviewDecision(text: string): ReviewDecision | null;
29
+ /**
30
+ * Review a proposed tool call. Decision flow:
31
+ * 1. Heuristic veto patterns — if any match, veto immediately (no LLM).
32
+ * 2. If EROSOLAR_REVIEWER env is on AND ANTHROPIC_API_KEY is present,
33
+ * call the reviewer model.
34
+ * 3. Otherwise, approve.
35
+ */
36
+ export declare function reviewToolCall(toolName: string, args: unknown): Promise<ReviewDecision>;
37
+ //# sourceMappingURL=reviewerGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewerGuard.d.ts","sourceRoot":"","sources":["../../src/core/reviewerGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,CAAC;CACpD;AAwGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAazE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAWvE;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAmC7F"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Constitutional reviewer-agent guard. Runs between user-configured
3
+ * shell hooks and the actual tool handler. Two layers:
4
+ *
5
+ * 1. **Hardcoded heuristic guard (always on)**. Catches the
6
+ * well-known catastrophic patterns (rm -rf /, curl-to-shell,
7
+ * anything that targets a path outside the workspace AND
8
+ * destroys data). Cheap, deterministic, no LLM call.
9
+ *
10
+ * 2. **LLM reviewer (gated by EROSOLAR_REVIEWER=1)**. Sends the
11
+ * proposed tool call + a brief constitution to a small, cheap
12
+ * reviewer model (Anthropic Haiku by default). Returns one of
13
+ * `approve | refine | veto` with a reason. The decision is
14
+ * logged to Firestore at reviewer_log/{uid}/decisions/{id} for
15
+ * operator review.
16
+ *
17
+ * The reviewer fails *open* on any error (network blip, unparseable
18
+ * model response, missing API key). Refusing-by-default would brick
19
+ * the CLI for users without the reviewer model configured. Instead,
20
+ * a failure is itself an audit-log event the operator can review.
21
+ */
22
+ const CONSTITUTION = `You are the constitutional reviewer for a CLI agent that holds offsec
23
+ tooling. Before any tool call fires, you say approve / refine / veto.
24
+
25
+ PRINCIPLES (most important first):
26
+
27
+ 1. Operator authorization is the load-bearing assumption. The user has
28
+ pre-authorized targets via the rulebook + their own engagement
29
+ scope. You don't second-guess that. You DO catch drift: tools
30
+ targeting hosts/files/URLs that have nothing to do with the recent
31
+ conversation.
32
+
33
+ 2. Coordinated disclosure is pinned. Any tool call whose effect is to
34
+ exfiltrate, sell, or silently retain a finding without sending it
35
+ through hackerone / vendor PSIRT / CERT-CC / published-advisory /
36
+ internal-writeup must be vetoed. "Broker" / "buyer" / "private
37
+ sale" in args means veto.
38
+
39
+ 3. Destructive operations on shared infrastructure get refined. rm -rf
40
+ on a path the agent didn't itself create, force-push to main,
41
+ DROP TABLE on prod-shaped DBs — these get a refine with a tighter
42
+ scope suggestion, not a veto (the operator can override).
43
+
44
+ 4. Scope creep beats target drift. "We were investigating X but the
45
+ agent now wants to scan Y" gets a veto. "We were on phase.recon
46
+ but the agent skipped to phase.disclose" gets a refine.
47
+
48
+ 5. Fail open. If you can't decide, approve with reason="uncertain —
49
+ approving conservatively". Refusing every uncertain call locks the
50
+ CLI for no benefit.`;
51
+ const VETO_PATTERNS_BASH = [
52
+ // rm -rf where the target is the filesystem root, $HOME, or ~ as the
53
+ // full atom (not a path prefix). The lookahead requires a shell-
54
+ // separator or end-of-string immediately after, so `rm -rf /tmp/x`
55
+ // is allowed and `rm -rf /` / `rm -rf $HOME` are vetoed.
56
+ { pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f?\s+(?:\/|\$HOME|~)(?=\s|$|;|&|\|)/, reason: 'rm -rf on filesystem root, $HOME, or ~' },
57
+ // dd / mkfs to block devices
58
+ { pattern: /\bdd\s+if=\/dev\/(?:zero|random|urandom)\s+of=\/(?:dev\/[hsv]d[a-z]|[A-Za-z])/, reason: 'dd-zero/random to a block device or filesystem root' },
59
+ { pattern: /\bmkfs\b.*\/dev\/[hsv]d[a-z]/, reason: 'mkfs targeting a block device' },
60
+ // fork bomb
61
+ { pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;\s*:/, reason: 'fork bomb' },
62
+ // curl/wget piped to shell. Match wget/curl, any non-pipe/separator
63
+ // text up to the first |, then a shell name as the next word.
64
+ { pattern: /\bcurl\b[^|;&]*\|\s*(?:bash|sh|zsh|fish)\b/i, reason: 'curl-to-shell' },
65
+ { pattern: /\bwget\b[^|;&]*\|\s*(?:bash|sh|zsh|fish)\b/i, reason: 'wget-to-shell' },
66
+ ];
67
+ const VETO_PATTERNS_DISCLOSURE = /\b(?:broker|brokerage|zerodium|crowdfense|silent\s+sale|private\s+buyer|sell\s+(?:exploit|0day|zero[- ]day))\b/i;
68
+ function heuristicReview(toolName, args) {
69
+ if (toolName === 'Bash' || toolName === 'kali_sqlmap' /* … other shell-shaped tools */) {
70
+ const cmd = args?.command || '';
71
+ for (const { pattern, reason } of VETO_PATTERNS_BASH) {
72
+ if (pattern.test(cmd)) {
73
+ return { decision: 'veto', reason, source: 'heuristic' };
74
+ }
75
+ }
76
+ }
77
+ // Cross-tool: any args field that looks like a brokerage handoff is
78
+ // a hard veto regardless of the tool surface.
79
+ const argsJson = JSON.stringify(args ?? {});
80
+ if (VETO_PATTERNS_DISCLOSURE.test(argsJson)) {
81
+ return { decision: 'veto', reason: 'disclosure path resembles brokerage / private sale', source: 'heuristic' };
82
+ }
83
+ return null; // no heuristic verdict — defer to LLM (or approve)
84
+ }
85
+ function isLlmReviewerEnabled() {
86
+ const v = (process.env['EROSOLAR_REVIEWER'] || '').toLowerCase();
87
+ return v === '1' || v === 'true' || v === 'on';
88
+ }
89
+ let cachedReviewer = null;
90
+ let reviewerInitFailed = false;
91
+ async function getLlmReviewer() {
92
+ if (reviewerInitFailed)
93
+ return null;
94
+ if (cachedReviewer)
95
+ return cachedReviewer;
96
+ if (!process.env['ANTHROPIC_API_KEY']) {
97
+ reviewerInitFailed = true;
98
+ return null;
99
+ }
100
+ try {
101
+ const { createProvider, hasProvider } = await import('../providers/providerFactory.js');
102
+ if (!hasProvider('anthropic')) {
103
+ // Provider plugin not registered yet — happens when reviewerGuard
104
+ // runs before agent boot completes the registration. Mark as
105
+ // failed (we'll fail open) and let the next boot retry.
106
+ reviewerInitFailed = true;
107
+ return null;
108
+ }
109
+ cachedReviewer = createProvider({
110
+ provider: 'anthropic',
111
+ model: process.env['EROSOLAR_REVIEWER_MODEL'] || 'claude-haiku-4-5-20251001',
112
+ });
113
+ return cachedReviewer;
114
+ }
115
+ catch {
116
+ reviewerInitFailed = true;
117
+ return null;
118
+ }
119
+ }
120
+ export function buildReviewPrompt(toolName, args) {
121
+ return [
122
+ CONSTITUTION,
123
+ '',
124
+ '## Proposed tool call',
125
+ `tool: ${toolName}`,
126
+ `args: ${JSON.stringify(args, null, 2).slice(0, 4000)}`,
127
+ '',
128
+ '## Output',
129
+ 'Reply with ONLY a JSON object on a single line:',
130
+ '{"decision": "approve" | "refine" | "veto", "reason": "≤200 chars"}',
131
+ 'No preamble, no markdown fences, no commentary.',
132
+ ].join('\n');
133
+ }
134
+ export function parseReviewDecision(text) {
135
+ const match = text.match(/\{[\s\S]*?\}/);
136
+ if (!match)
137
+ return null;
138
+ try {
139
+ const obj = JSON.parse(match[0]);
140
+ const d = String(obj.decision || '').toLowerCase();
141
+ if (d === 'approve' || d === 'refine' || d === 'veto') {
142
+ return { decision: d, reason: String(obj.reason || '').slice(0, 200), source: 'llm' };
143
+ }
144
+ }
145
+ catch { /* fall through */ }
146
+ return null;
147
+ }
148
+ /**
149
+ * Review a proposed tool call. Decision flow:
150
+ * 1. Heuristic veto patterns — if any match, veto immediately (no LLM).
151
+ * 2. If EROSOLAR_REVIEWER env is on AND ANTHROPIC_API_KEY is present,
152
+ * call the reviewer model.
153
+ * 3. Otherwise, approve.
154
+ */
155
+ export async function reviewToolCall(toolName, args) {
156
+ const heuristic = heuristicReview(toolName, args);
157
+ if (heuristic)
158
+ return heuristic;
159
+ if (!isLlmReviewerEnabled()) {
160
+ return { decision: 'approve', reason: 'reviewer disabled', source: 'disabled' };
161
+ }
162
+ const reviewer = await getLlmReviewer();
163
+ if (!reviewer) {
164
+ return { decision: 'approve', reason: 'no LLM reviewer configured', source: 'disabled' };
165
+ }
166
+ try {
167
+ const prompt = buildReviewPrompt(toolName, args);
168
+ const res = await reviewer.generate([{ role: 'user', content: prompt }], []);
169
+ const text = res.type === 'message' ? res.content : (res.content ?? '');
170
+ const parsed = parseReviewDecision(text);
171
+ if (!parsed) {
172
+ return {
173
+ decision: 'approve',
174
+ reason: 'unparseable reviewer response — failing open',
175
+ source: 'error',
176
+ };
177
+ }
178
+ return parsed;
179
+ }
180
+ catch (err) {
181
+ return {
182
+ decision: 'approve',
183
+ reason: `reviewer error: ${err.message.slice(0, 100)} — failing open`,
184
+ source: 'error',
185
+ };
186
+ }
187
+ }
188
+ //# sourceMappingURL=reviewerGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewerGuard.js","sourceRoot":"","sources":["../../src/core/reviewerGuard.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"toolRuntime.d.ts","sourceRoot":"","sources":["../../src/core/toolRuntime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolRuntime.d.ts","sourceRoot":"","sources":["../../src/core/toolRuntime.ts"],"names":[],"mappings":"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"}
@@ -248,6 +248,57 @@ export class ToolRuntime {
248
248
  // A buggy hook should never crash the agent. Log + continue.
249
249
  logDebug('[hooks] PreToolUse error: ' + err.message);
250
250
  }
251
+ // Constitutional reviewer guard. Two layers:
252
+ // - Heuristic veto patterns (always on) — `rm -rf /` style
253
+ // destructive ops, fork bombs, curl-to-shell, broker-shaped
254
+ // disclosure args.
255
+ // - LLM reviewer (gated by EROSOLAR_REVIEWER=1, default off)
256
+ // — Anthropic Haiku-tier model checks the call against a
257
+ // short constitution, returns approve/refine/veto.
258
+ // Vetoes block the call. Refines log + continue (soft warning).
259
+ // All non-approve decisions are audit-logged (best-effort) to
260
+ // Firestore at reviewer_log/{uid}/decisions/{id}. The reviewer
261
+ // fails open on any internal error — refusing every uncertain
262
+ // call would brick the CLI for users without the reviewer
263
+ // model configured.
264
+ try {
265
+ const { reviewToolCall } = await import('./reviewerGuard.js');
266
+ const review = await reviewToolCall(call.name, args);
267
+ if (review.decision !== 'approve') {
268
+ // Best-effort audit log — fire-and-forget.
269
+ void (async () => {
270
+ try {
271
+ const { writeReviewerLog } = await import('./userApproval.js');
272
+ await writeReviewerLog({
273
+ toolName: call.name,
274
+ decision: review.decision,
275
+ reason: review.reason,
276
+ source: review.source,
277
+ argsSummary: JSON.stringify(args).slice(0, 500),
278
+ });
279
+ }
280
+ catch { /* swallow — audit is non-critical */ }
281
+ })();
282
+ if (review.decision === 'veto') {
283
+ const message = `Error: ${call.name} vetoed by constitutional reviewer (${review.source}): ${review.reason}`;
284
+ this.observer?.onToolError?.(augmentedCall, message);
285
+ this.recordToolHistory({
286
+ toolName: call.name,
287
+ args,
288
+ timestamp: Date.now(),
289
+ success: false,
290
+ hasOutput: false,
291
+ });
292
+ return message;
293
+ }
294
+ // 'refine' is a soft warning — log and proceed; the model
295
+ // will see the tool output and can self-correct on retry.
296
+ logDebug(`[reviewer] refine ${call.name}: ${review.reason}`);
297
+ }
298
+ }
299
+ catch (err) {
300
+ logDebug('[reviewer] guard error: ' + err.message);
301
+ }
251
302
  const result = await toolExecutionContext.run({ call: augmentedCall, observer: this.observer ?? undefined }, async () => record.definition.handler(args));
252
303
  let output = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
253
304
  // PostToolUse hooks: append text from each matching hook so