@trenchwork/erosolar 1.1.28 → 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/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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEhF,MAAM,cAAc,GAAG,gDAAgD,mBAAmB,gCAAgC,CAAC;AAW3H,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;YAC5D,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACtE,CAAC;AAED,SAAS,OAAO,CAAC,UAAkB;IACjC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjF,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC;QAClE,MAAM,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC;QAClD,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,UAAU,CAAC;KACtE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,UAAkB;IACpD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,OAAO;QACL,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG;QAC1B,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,MAAM;KAClB,CAAC;AACJ,CAAC;AAWD,SAAS,QAAQ,CAAC,CAA4B;IAC5C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACtD,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAkB;IAKtD,MAAM,OAAO,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAC;QACxC,oEAAoE;QACpE,qEAAqE;QACrE,gEAAgE;QAChE,mEAAmE;QACnE,8BAA8B;QAC9B,MAAM,OAAO,GAAG,YAAY,OAAO,CAAC,SAAS,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,YAAY,mBAAmB,kCAAkC,OAAO,EAAE,CAAC;QAE5F,0DAA0D;QAC1D,qDAAqD;QACrD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,cAAc,IAAI,OAAO,EAAE,EAAE;YACzD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE;SAChD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC;QAErC,MAAM,MAAM,GAAmC;YAC7C,QAAQ,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,GAAG,EAAE;YACrC,IAAI,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE;YACnC,UAAU,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,UAAU,EAAE;YAC/C,cAAc,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,SAAS,EAAE;YAClD,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;YACtC,UAAU,EAAE,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;YACxD,MAAM,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE;SAClC,CAAC;QACF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YACnE,MAAM,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACzD,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;YAC/C,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;QAChD,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1F,MAAM,QAAQ,GAAG,GAAG,cAAc,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YACrC,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACnF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;SACjC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;YAC3D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;QAC1F,CAAC;QAED,sEAAsE;QACtE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,SAAS,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAAC;YACnF,MAAM,UAAU,GAAG;gBACjB,MAAM,EAAE,CAAC;wBACP,SAAS,EAAE;4BACT,QAAQ,EAAE,QAAQ;4BAClB,eAAe,EAAE,CAAC;oCAChB,SAAS,EAAE,cAAc;oCACzB,SAAS,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;iCACjC,CAAC;yBACH;qBACF,CAAC;aACH,CAAC;YACF,MAAM,KAAK,CAAC,SAAS,EAAE;gBACrB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBACnF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;aACjC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAkD,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1F,CAAC;AACH,CAAC;AAUD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAwB;IAK9D,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC5E,MAAM,GAAG,GAAG,GAAG,cAAc,eAAe,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,wBAAwB,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;QAClI,MAAM,IAAI,GAAG;YACX,MAAM,EAAE;gBACN,GAAG,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,GAAG,EAAE;gBAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;gBACnC,SAAS,EAAE,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;gBACvD,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,OAAO,EAAE;gBACvC,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,KAAK,EAAE;gBACnC,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,OAAO,EAAE;gBACvC,QAAQ,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,QAAQ,EAAE;gBACzC,SAAS,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE;gBACnD,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;gBAC5C,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;gBAC5C,OAAO,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE;gBACvC,QAAQ,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;gBAC/B,SAAS,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;aACjC;SACF,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACnF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;YACtD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;QACjG,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAClG,CAAC;AACH,CAAC;AAYD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAsB;IAC1D,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAChD,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,cAAc,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAClH,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QACpG,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrF,MAAM,WAAW,GAAG;YAClB,MAAM,EAAE;gBACN,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,OAAO,EAAE;gBACvC,OAAO,EAAE,EAAE,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;gBACrD,aAAa,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;gBAC7G,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;gBACrG,QAAQ,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;gBAClD,SAAS,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;aACrD;SACF,CAAC;QACF,MAAM,KAAK,CAAC,GAAG,cAAc,IAAI,UAAU,IAAI,WAAW,EAAE,EAAE;YAC5D,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACnF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;SAClC,CAAC,CAAC;QAEH,gEAAgE;QAChE,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;QACpD,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,SAAS,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAAC;YACnF,MAAM,UAAU,GAAG;gBACjB,MAAM,EAAE,CAAC;wBACP,SAAS,EAAE;4BACT,QAAQ,EAAE,YAAY,mBAAmB,2CAA2C,KAAK,CAAC,SAAS,EAAE;4BACrG,eAAe,EAAE,CAAC;oCAChB,SAAS,EAAE,aAAa;oCACxB,SAAS,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE;iCAChD,CAAC;yBACH;qBACF,CAAC;aACH,CAAC;YACF,MAAM,KAAK,CAAC,SAAS,EAAE;gBACrB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBACnF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;aACjC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACjF,CAAC;AACH,CAAC"}
|
|
@@ -206,6 +206,13 @@ class InteractiveShell {
|
|
|
206
206
|
// immediately resume the work the user just cancelled. Cleared when the
|
|
207
207
|
// user submits a fresh prompt.
|
|
208
208
|
userInterruptedRun = false;
|
|
209
|
+
// Session-level aggregates rolled up across every processPrompt call
|
|
210
|
+
// and flushed to Firestore on shutdown. Bounded by the writeSessionEnd
|
|
211
|
+
// slicer (top 100 of each).
|
|
212
|
+
sessionToolsUsed = new Set();
|
|
213
|
+
sessionFilesModified = new Set();
|
|
214
|
+
sessionTokensIn = 0;
|
|
215
|
+
sessionTokensOut = 0;
|
|
209
216
|
cachedProviders = null;
|
|
210
217
|
secretInputMode = {
|
|
211
218
|
active: false,
|
|
@@ -291,6 +298,29 @@ class InteractiveShell {
|
|
|
291
298
|
this.promptController?.stop();
|
|
292
299
|
setStatusSink(null);
|
|
293
300
|
});
|
|
301
|
+
// Session-end Firestore write — transitions the session row from
|
|
302
|
+
// `in_progress` to `completed` and rolls up the project's
|
|
303
|
+
// totalTokens. Best-effort: a kill -9 leaves the row stale at
|
|
304
|
+
// `in_progress`, which the audit portal can highlight.
|
|
305
|
+
onShutdown(async () => {
|
|
306
|
+
const sessionId = process.env['EROSOLAR_SESSION_ID'];
|
|
307
|
+
const projectId = process.env['EROSOLAR_PROJECT_ID'];
|
|
308
|
+
if (!sessionId || !projectId)
|
|
309
|
+
return;
|
|
310
|
+
try {
|
|
311
|
+
const { writeSessionEnd } = await import('../core/projectTracker.js');
|
|
312
|
+
await writeSessionEnd({
|
|
313
|
+
sessionId,
|
|
314
|
+
projectId,
|
|
315
|
+
outcome: this.userInterruptedRun ? 'cancelled' : 'completed',
|
|
316
|
+
filesModified: Array.from(this.sessionFilesModified).slice(0, 100),
|
|
317
|
+
toolsUsed: Array.from(this.sessionToolsUsed).slice(0, 100),
|
|
318
|
+
tokensIn: this.sessionTokensIn,
|
|
319
|
+
tokensOut: this.sessionTokensOut,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch { /* best-effort */ }
|
|
323
|
+
});
|
|
294
324
|
setStatusSink((message) => this.promptController?.setStatusMessage(message));
|
|
295
325
|
// Hand the terminal off to the HITL prompt while it's open: suspend
|
|
296
326
|
// prompt rendering and detach our keypress handler so arrow keys aren't
|
|
@@ -1646,11 +1676,13 @@ class InteractiveShell {
|
|
|
1646
1676
|
if (!toolsUsed.includes(toolName)) {
|
|
1647
1677
|
toolsUsed.push(toolName);
|
|
1648
1678
|
}
|
|
1679
|
+
this.sessionToolsUsed.add(toolName);
|
|
1649
1680
|
const filePath = args?.['file_path'];
|
|
1650
1681
|
if (filePath && (toolName === 'Write' || toolName === 'Edit')) {
|
|
1651
1682
|
if (!filesModified.includes(filePath)) {
|
|
1652
1683
|
filesModified.push(filePath);
|
|
1653
1684
|
}
|
|
1685
|
+
this.sessionFilesModified.add(filePath);
|
|
1654
1686
|
}
|
|
1655
1687
|
if (toolName === 'Bash' && args?.['command']) {
|
|
1656
1688
|
toolDisplay = `Bash(${String(args['command']).slice(0, 120)})`;
|
|
@@ -1758,6 +1790,9 @@ class InteractiveShell {
|
|
|
1758
1790
|
tokensUsed: event.totalTokens,
|
|
1759
1791
|
tokenLimit: 200000, // Approximate limit
|
|
1760
1792
|
});
|
|
1793
|
+
// Roll up to session totals for the session-end Firestore write.
|
|
1794
|
+
this.sessionTokensIn += event.inputTokens || 0;
|
|
1795
|
+
this.sessionTokensOut += event.outputTokens || 0;
|
|
1761
1796
|
break;
|
|
1762
1797
|
case 'provider.fallback': {
|
|
1763
1798
|
// Display fallback notification
|