@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.
- package/SECURITY.md +35 -0
- package/dist/bin/deepseek.js +14 -8
- package/dist/bin/deepseek.js.map +1 -1
- package/dist/capabilities/index.d.ts +6 -0
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +6 -0
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/interactionCapability.d.ts +6 -0
- package/dist/capabilities/interactionCapability.d.ts.map +1 -0
- package/dist/capabilities/interactionCapability.js +17 -0
- package/dist/capabilities/interactionCapability.js.map +1 -0
- package/dist/capabilities/mcpCapability.d.ts.map +1 -1
- package/dist/capabilities/mcpCapability.js +4 -2
- package/dist/capabilities/mcpCapability.js.map +1 -1
- package/dist/capabilities/monitorCapability.d.ts +6 -0
- package/dist/capabilities/monitorCapability.d.ts.map +1 -0
- package/dist/capabilities/monitorCapability.js +19 -0
- package/dist/capabilities/monitorCapability.js.map +1 -0
- package/dist/capabilities/planModeCapability.d.ts +6 -0
- package/dist/capabilities/planModeCapability.d.ts.map +1 -0
- package/dist/capabilities/planModeCapability.js +16 -0
- package/dist/capabilities/planModeCapability.js.map +1 -0
- package/dist/capabilities/scheduleCapability.d.ts +6 -0
- package/dist/capabilities/scheduleCapability.d.ts.map +1 -0
- package/dist/capabilities/scheduleCapability.js +16 -0
- package/dist/capabilities/scheduleCapability.js.map +1 -0
- package/dist/capabilities/triggerCapability.d.ts +6 -0
- package/dist/capabilities/triggerCapability.d.ts.map +1 -0
- package/dist/capabilities/triggerCapability.js +16 -0
- package/dist/capabilities/triggerCapability.js.map +1 -0
- package/dist/capabilities/worktreeCapability.d.ts +6 -0
- package/dist/capabilities/worktreeCapability.d.ts.map +1 -0
- package/dist/capabilities/worktreeCapability.js +16 -0
- package/dist/capabilities/worktreeCapability.js.map +1 -0
- package/dist/contracts/agent-schemas.json +1 -1
- package/dist/core/projectTracker.d.ts +96 -0
- package/dist/core/projectTracker.d.ts.map +1 -0
- package/dist/core/projectTracker.js +275 -0
- package/dist/core/projectTracker.js.map +1 -0
- package/dist/core/reviewerGuard.d.ts +37 -0
- package/dist/core/reviewerGuard.d.ts.map +1 -0
- package/dist/core/reviewerGuard.js +188 -0
- package/dist/core/reviewerGuard.js.map +1 -0
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +51 -0
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/userApproval.d.ts +21 -0
- package/dist/core/userApproval.d.ts.map +1 -1
- package/dist/core/userApproval.js +45 -0
- package/dist/core/userApproval.js.map +1 -1
- package/dist/headless/interactiveShell.js +35 -0
- package/dist/headless/interactiveShell.js.map +1 -1
- package/dist/plugins/tools/mcp/mcpClient.d.ts +10 -0
- package/dist/plugins/tools/mcp/mcpClient.d.ts.map +1 -1
- package/dist/plugins/tools/mcp/mcpClient.js +6 -0
- package/dist/plugins/tools/mcp/mcpClient.js.map +1 -1
- package/dist/runtime/node.d.ts +2 -0
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +28 -28
- package/dist/runtime/node.js.map +1 -1
- package/dist/runtime/profileGates.d.ts +19 -0
- package/dist/runtime/profileGates.d.ts.map +1 -0
- package/dist/runtime/profileGates.js +23 -0
- package/dist/runtime/profileGates.js.map +1 -0
- package/dist/tools/interactionTools.d.ts +16 -0
- package/dist/tools/interactionTools.d.ts.map +1 -0
- package/dist/tools/interactionTools.js +207 -0
- package/dist/tools/interactionTools.js.map +1 -0
- package/dist/tools/monitorTools.d.ts +16 -0
- package/dist/tools/monitorTools.d.ts.map +1 -0
- package/dist/tools/monitorTools.js +159 -0
- package/dist/tools/monitorTools.js.map +1 -0
- package/dist/tools/planModeTools.d.ts +32 -0
- package/dist/tools/planModeTools.d.ts.map +1 -0
- package/dist/tools/planModeTools.js +200 -0
- package/dist/tools/planModeTools.js.map +1 -0
- package/dist/tools/scheduleTools.d.ts +39 -0
- package/dist/tools/scheduleTools.d.ts.map +1 -0
- package/dist/tools/scheduleTools.js +182 -0
- package/dist/tools/scheduleTools.js.map +1 -0
- package/dist/tools/triggerTools.d.ts +28 -0
- package/dist/tools/triggerTools.d.ts.map +1 -0
- package/dist/tools/triggerTools.js +210 -0
- package/dist/tools/triggerTools.js.map +1 -0
- package/dist/tools/worktreeTools.d.ts +21 -0
- package/dist/tools/worktreeTools.d.ts.map +1 -0
- package/dist/tools/worktreeTools.js +158 -0
- package/dist/tools/worktreeTools.js.map +1 -0
- package/dist/ui/ink/App.d.ts.map +1 -1
- package/dist/ui/ink/App.js +2 -1
- package/dist/ui/ink/App.js.map +1 -1
- package/dist/ui/ink/ChatStatic.d.ts.map +1 -1
- package/dist/ui/ink/ChatStatic.js +7 -6
- package/dist/ui/ink/ChatStatic.js.map +1 -1
- package/dist/ui/ink/StatusLine.d.ts.map +1 -1
- package/dist/ui/ink/StatusLine.js +2 -1
- package/dist/ui/ink/StatusLine.js.map +1 -1
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/theme.js +31 -29
- package/dist/ui/theme.js.map +1 -1
- package/dist/utils/lambdaClient.d.ts +35 -0
- package/dist/utils/lambdaClient.d.ts.map +1 -0
- package/dist/utils/lambdaClient.js +81 -0
- package/dist/utils/lambdaClient.js.map +1 -0
- 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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"}
|
package/dist/core/toolRuntime.js
CHANGED
|
@@ -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
|