sidekick-shared 0.21.2 → 0.21.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -45
- package/dist/accountManager.js +9 -7
- package/dist/accountRegistry.d.ts +17 -0
- package/dist/accountRegistry.js +18 -14
- package/dist/accountStatus.js +7 -7
- package/dist/accounts.d.ts +13 -0
- package/dist/accounts.js +110 -25
- package/dist/aggregation/EventAggregator.d.ts +14 -11
- package/dist/aggregation/EventAggregator.js +68 -31
- package/dist/aggregation/PatternExtractor.js +5 -4
- package/dist/autoSwitch.js +6 -12
- package/dist/claudeProfiles.js +3 -3
- package/dist/codexProfiles.d.ts +15 -1
- package/dist/codexProfiles.js +96 -22
- package/dist/codexQuota.js +44 -16
- package/dist/codexQuotaWatcher.js +19 -4
- package/dist/context/composer.js +8 -6
- package/dist/context/sessionContext.js +12 -9
- package/dist/credentialIO.js +10 -8
- package/dist/extractors/sessionAssets.js +9 -1
- package/dist/extractors/sources/claudeAssets.js +7 -1
- package/dist/extractors/sources/codexAssets.js +14 -3
- package/dist/extractors/toolCall.js +1 -4
- package/dist/formatters/eventHighlighter.js +148 -28
- package/dist/formatters/noiseClassifier.js +3 -11
- package/dist/formatters/sessionDump.js +22 -13
- package/dist/formatters/toolSummary.js +1 -3
- package/dist/index.d.ts +26 -26
- package/dist/index.js +10 -4
- package/dist/modelContext.js +10 -8
- package/dist/modelInfo.js +11 -6
- package/dist/multiProviderQuotaService.d.ts +2 -2
- package/dist/multiProviderQuotaService.js +14 -10
- package/dist/parsers/codexParser.js +170 -103
- package/dist/parsers/debugLogParser.js +5 -4
- package/dist/parsers/openCodeParser.js +66 -48
- package/dist/parsers/planExtractor.js +3 -3
- package/dist/parsers/sessionActivityDetector.js +10 -6
- package/dist/parsers/sessionPathResolver.js +29 -34
- package/dist/parsers/subagentScanner.js +21 -20
- package/dist/parsers/subagentTraceParser.js +7 -4
- package/dist/phrases.js +11 -11
- package/dist/providerStatus.js +3 -4
- package/dist/providers/claudeCode.js +3 -1
- package/dist/providers/codex.js +35 -14
- package/dist/providers/codexDatabase.js +14 -5
- package/dist/providers/detect.js +10 -6
- package/dist/providers/openCode.js +91 -63
- package/dist/providers/openCodeDatabase.js +44 -17
- package/dist/quota.d.ts +19 -0
- package/dist/quota.js +50 -8
- package/dist/quotaHistory.js +10 -3
- package/dist/quotaSnapshots.js +2 -2
- package/dist/readers/decisions.js +1 -1
- package/dist/readers/notes.js +5 -3
- package/dist/readers/plans.js +43 -23
- package/dist/readers/tasks.js +1 -1
- package/dist/report/htmlHelpers.js +135 -16
- package/dist/report/htmlReportGenerator.js +38 -12
- package/dist/report/transcriptParser.js +8 -2
- package/dist/schemas/index.d.ts +4 -4
- package/dist/schemas/quota.js +2 -10
- package/dist/schemas/sessionEvent.js +20 -10
- package/dist/search/advancedFilter.js +3 -3
- package/dist/search/sessionSearch.js +10 -4
- package/dist/terminalSync.js +4 -2
- package/dist/turns/assistantTurn.js +5 -1
- package/dist/watchers/eventBridge.js +56 -26
- package/dist/watchers/factory.js +5 -2
- package/dist/watchers/jsonlTail.js +3 -1
- package/dist/watchers/jsonlWatcher.js +128 -52
- package/dist/watchers/providerReaderWatcher.js +3 -1
- package/dist/watchers/sqliteWatcher.js +52 -22
- package/dist/zaiQuota.js +6 -10
- package/dist/zaiQuotaApi.js +13 -5
- package/dist/zaiQuotaWatcher.js +1 -1
- package/package.json +5 -2
|
@@ -63,18 +63,30 @@ function normalizeMessage(msg) {
|
|
|
63
63
|
const model = data.modelID || undefined;
|
|
64
64
|
if (role === 'user') {
|
|
65
65
|
events.push({
|
|
66
|
-
providerId: 'opencode',
|
|
67
|
-
|
|
66
|
+
providerId: 'opencode',
|
|
67
|
+
type: 'user',
|
|
68
|
+
timestamp: ts,
|
|
69
|
+
summary: content || '(user message)',
|
|
70
|
+
model,
|
|
71
|
+
raw: data,
|
|
68
72
|
});
|
|
69
73
|
}
|
|
70
74
|
else if (role === 'assistant') {
|
|
71
75
|
events.push({
|
|
72
|
-
providerId: 'opencode',
|
|
73
|
-
|
|
76
|
+
providerId: 'opencode',
|
|
77
|
+
type: 'assistant',
|
|
78
|
+
timestamp: ts,
|
|
79
|
+
summary: content || '(thinking...)',
|
|
80
|
+
tokens,
|
|
81
|
+
cost,
|
|
82
|
+
model,
|
|
83
|
+
raw: data,
|
|
74
84
|
});
|
|
75
85
|
}
|
|
76
86
|
}
|
|
77
|
-
catch {
|
|
87
|
+
catch {
|
|
88
|
+
/* skip malformed */
|
|
89
|
+
}
|
|
78
90
|
return events;
|
|
79
91
|
}
|
|
80
92
|
function normalizePart(part) {
|
|
@@ -93,13 +105,15 @@ function normalizePart(part) {
|
|
|
93
105
|
const toolInput = state?.input;
|
|
94
106
|
const input = data.args ? truncate(JSON.stringify(data.args), 80) : '';
|
|
95
107
|
// Include input in raw so PlanExtractor can access raw.input
|
|
96
|
-
const toolRaw = eventType === 'tool_use'
|
|
97
|
-
? { ...data, input: toolInput || {} }
|
|
98
|
-
: data;
|
|
108
|
+
const toolRaw = eventType === 'tool_use' ? { ...data, input: toolInput || {} } : data;
|
|
99
109
|
events.push({
|
|
100
|
-
providerId: 'opencode',
|
|
110
|
+
providerId: 'opencode',
|
|
111
|
+
type: eventType,
|
|
112
|
+
timestamp: ts,
|
|
101
113
|
summary: input ? `${toolName} ${input}` : toolName,
|
|
102
|
-
toolName,
|
|
114
|
+
toolName,
|
|
115
|
+
toolInput: input || undefined,
|
|
116
|
+
raw: toolRaw,
|
|
103
117
|
});
|
|
104
118
|
}
|
|
105
119
|
else if (type === 'text') {
|
|
@@ -107,7 +121,9 @@ function normalizePart(part) {
|
|
|
107
121
|
if (text) {
|
|
108
122
|
// Wrap raw to include message.content for <proposed_plan> extraction
|
|
109
123
|
events.push({
|
|
110
|
-
providerId: 'opencode',
|
|
124
|
+
providerId: 'opencode',
|
|
125
|
+
type: 'assistant',
|
|
126
|
+
timestamp: ts,
|
|
111
127
|
summary: truncate(text, 200),
|
|
112
128
|
raw: { ...data, message: { content: [{ type: 'text', text }] } },
|
|
113
129
|
});
|
|
@@ -116,7 +132,9 @@ function normalizePart(part) {
|
|
|
116
132
|
if (direction) {
|
|
117
133
|
const syntheticToolName = direction === 'enter' ? 'EnterPlanMode' : 'ExitPlanMode';
|
|
118
134
|
events.push({
|
|
119
|
-
providerId: 'opencode',
|
|
135
|
+
providerId: 'opencode',
|
|
136
|
+
type: 'tool_use',
|
|
137
|
+
timestamp: ts,
|
|
120
138
|
summary: syntheticToolName,
|
|
121
139
|
toolName: syntheticToolName,
|
|
122
140
|
raw: { input: { source: 'opencode_text_heuristic' } },
|
|
@@ -125,7 +143,9 @@ function normalizePart(part) {
|
|
|
125
143
|
}
|
|
126
144
|
}
|
|
127
145
|
}
|
|
128
|
-
catch {
|
|
146
|
+
catch {
|
|
147
|
+
/* skip malformed */
|
|
148
|
+
}
|
|
129
149
|
return events;
|
|
130
150
|
}
|
|
131
151
|
function extractContent(data) {
|
|
@@ -158,7 +178,9 @@ class SqliteSessionWatcher {
|
|
|
158
178
|
this.callbacks = callbacks;
|
|
159
179
|
this.db = new openCodeDatabase_1.OpenCodeDatabase(path.dirname(dbPath));
|
|
160
180
|
}
|
|
161
|
-
get isActive() {
|
|
181
|
+
get isActive() {
|
|
182
|
+
return this._isActive;
|
|
183
|
+
}
|
|
162
184
|
/** Seek to a timestamp position. Must be called before start(). */
|
|
163
185
|
seekTo(position) {
|
|
164
186
|
this.lastMessageTime = position;
|
|
@@ -186,8 +208,12 @@ class SqliteSessionWatcher {
|
|
|
186
208
|
this.skipToEnd();
|
|
187
209
|
}
|
|
188
210
|
// Watch db and wal files for changes
|
|
189
|
-
this.watchFile(this.dbPath, (w) => {
|
|
190
|
-
|
|
211
|
+
this.watchFile(this.dbPath, (w) => {
|
|
212
|
+
this.fsWatcher = w;
|
|
213
|
+
});
|
|
214
|
+
this.watchFile(this.dbPath + '-wal', (w) => {
|
|
215
|
+
this.walWatcher = w;
|
|
216
|
+
});
|
|
191
217
|
// Fallback polling
|
|
192
218
|
this.pollTimer = setInterval(() => {
|
|
193
219
|
if (this._isActive)
|
|
@@ -223,10 +249,14 @@ class SqliteSessionWatcher {
|
|
|
223
249
|
const watcher = fs.watch(filePath, { persistent: false }, () => {
|
|
224
250
|
this.debouncedPoll();
|
|
225
251
|
});
|
|
226
|
-
watcher.on('error', () => {
|
|
252
|
+
watcher.on('error', () => {
|
|
253
|
+
/* ignore watch errors */
|
|
254
|
+
});
|
|
227
255
|
setter(watcher);
|
|
228
256
|
}
|
|
229
|
-
catch {
|
|
257
|
+
catch {
|
|
258
|
+
/* fs.watch not available */
|
|
259
|
+
}
|
|
230
260
|
}
|
|
231
261
|
debouncedPoll() {
|
|
232
262
|
if (this.debounceTimer)
|
|
@@ -239,10 +269,10 @@ class SqliteSessionWatcher {
|
|
|
239
269
|
const messages = this.db.getMessagesForSession(this.sessionId);
|
|
240
270
|
const parts = this.db.getPartsForSession(this.sessionId);
|
|
241
271
|
if (messages.length > 0) {
|
|
242
|
-
this.lastMessageTime = Math.max(...messages.map(m => m.time_created));
|
|
272
|
+
this.lastMessageTime = Math.max(...messages.map((m) => m.time_created));
|
|
243
273
|
}
|
|
244
274
|
if (parts.length > 0) {
|
|
245
|
-
this.lastPartTime = Math.max(...parts.map(p => p.time_created));
|
|
275
|
+
this.lastPartTime = Math.max(...parts.map((p) => p.time_created));
|
|
246
276
|
}
|
|
247
277
|
}
|
|
248
278
|
pollNewData() {
|
|
@@ -252,7 +282,7 @@ class SqliteSessionWatcher {
|
|
|
252
282
|
const messages = this.db.getMessagesForSession(this.sessionId);
|
|
253
283
|
const parts = this.db.getPartsForSession(this.sessionId);
|
|
254
284
|
// Emit new messages
|
|
255
|
-
const newMessages = messages.filter(m => m.time_created > this.lastMessageTime);
|
|
285
|
+
const newMessages = messages.filter((m) => m.time_created > this.lastMessageTime);
|
|
256
286
|
for (const msg of newMessages) {
|
|
257
287
|
const events = normalizeMessage(msg);
|
|
258
288
|
for (const e of events)
|
|
@@ -261,7 +291,7 @@ class SqliteSessionWatcher {
|
|
|
261
291
|
this.lastMessageTime = msg.time_created;
|
|
262
292
|
}
|
|
263
293
|
// Emit new parts
|
|
264
|
-
const newParts = parts.filter(p => p.time_created > this.lastPartTime);
|
|
294
|
+
const newParts = parts.filter((p) => p.time_created > this.lastPartTime);
|
|
265
295
|
for (const part of newParts) {
|
|
266
296
|
const events = normalizePart(part);
|
|
267
297
|
for (const e of events)
|
package/dist/zaiQuota.js
CHANGED
|
@@ -132,18 +132,14 @@ function resolveZaiTier(configured, accumulated) {
|
|
|
132
132
|
function inferZaiQuotaState(accumulated, tier, options = {}) {
|
|
133
133
|
const budget = exports.ZAI_TIER_BUDGETS[tier];
|
|
134
134
|
const capturedAt = options.capturedAt ?? new Date().toISOString();
|
|
135
|
-
const fiveHourUtil = budget.fiveHour > 0
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
? Math.min((accumulated.weeklyPrompts / budget.weekly) * 100, 200)
|
|
140
|
-
: 0;
|
|
141
|
-
const fiveHourResetsAt = options.authoritativeFiveHourResetAt
|
|
142
|
-
?? (accumulated.fiveHourStartedAtMs !== null
|
|
135
|
+
const fiveHourUtil = budget.fiveHour > 0 ? Math.min((accumulated.fiveHourPrompts / budget.fiveHour) * 100, 200) : 0;
|
|
136
|
+
const weeklyUtil = budget.weekly > 0 ? Math.min((accumulated.weeklyPrompts / budget.weekly) * 100, 200) : 0;
|
|
137
|
+
const fiveHourResetsAt = options.authoritativeFiveHourResetAt ??
|
|
138
|
+
(accumulated.fiveHourStartedAtMs !== null
|
|
143
139
|
? new Date(accumulated.fiveHourStartedAtMs + FIVE_HOUR_MS).toISOString()
|
|
144
140
|
: '');
|
|
145
|
-
const sevenDayResetsAt = options.authoritativeWeeklyResetAt
|
|
146
|
-
|
|
141
|
+
const sevenDayResetsAt = options.authoritativeWeeklyResetAt ??
|
|
142
|
+
(accumulated.weeklyStartedAtMs !== null
|
|
147
143
|
? new Date(accumulated.weeklyStartedAtMs + SEVEN_DAY_MS).toISOString()
|
|
148
144
|
: '');
|
|
149
145
|
const fiveHour = {
|
package/dist/zaiQuotaApi.js
CHANGED
|
@@ -11,6 +11,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
11
11
|
const os_1 = __importDefault(require("os"));
|
|
12
12
|
const path_1 = __importDefault(require("path"));
|
|
13
13
|
const quotaSnapshots_1 = require("./quotaSnapshots");
|
|
14
|
+
const quota_1 = require("./quota");
|
|
14
15
|
const DEFAULT_ZAI_BASE_URL = 'https://api.z.ai/api/anthropic';
|
|
15
16
|
const QUOTA_PATH = '/api/monitor/usage/quota/limit';
|
|
16
17
|
const DEFAULT_ACCOUNT_ID = 'default';
|
|
@@ -39,7 +40,9 @@ function openCodeDataDirCandidates() {
|
|
|
39
40
|
candidates.push(path_1.default.join(os_1.default.homedir(), 'Library', 'Application Support', 'opencode'));
|
|
40
41
|
}
|
|
41
42
|
else if (process.platform === 'win32') {
|
|
42
|
-
candidates.push(path_1.default.join(process.env.LOCALAPPDATA ||
|
|
43
|
+
candidates.push(path_1.default.join(process.env.LOCALAPPDATA ||
|
|
44
|
+
process.env.APPDATA ||
|
|
45
|
+
path_1.default.join(os_1.default.homedir(), 'AppData', 'Local'), 'opencode'));
|
|
43
46
|
}
|
|
44
47
|
return Array.from(new Set(candidates));
|
|
45
48
|
}
|
|
@@ -129,14 +132,14 @@ function quotaStateFromZaiQuotaLimitPayload(payload, capturedAt = new Date().toI
|
|
|
129
132
|
const data = payload;
|
|
130
133
|
const tokenLimits = tokenLimitEntries(data);
|
|
131
134
|
const fiveHourLimit = tokenLimits.find(isFiveHourLimit) ?? tokenLimits[0];
|
|
132
|
-
const weeklyLimit = tokenLimits.find(isWeeklyLimit) ?? tokenLimits.find(item => item !== fiveHourLimit);
|
|
135
|
+
const weeklyLimit = tokenLimits.find(isWeeklyLimit) ?? tokenLimits.find((item) => item !== fiveHourLimit);
|
|
133
136
|
const level = data.data?.level;
|
|
134
137
|
if (!fiveHourLimit || !weeklyLimit) {
|
|
135
138
|
return unavailableZaiQuotaState('z.ai quota API returned no token quota windows.', {
|
|
136
139
|
failureKind: 'unknown',
|
|
137
140
|
}, capturedAt);
|
|
138
141
|
}
|
|
139
|
-
return {
|
|
142
|
+
return (0, quota_1.withQuotaProjections)({
|
|
140
143
|
fiveHour: {
|
|
141
144
|
utilization: fiveHourLimit.percentage ?? 0,
|
|
142
145
|
resetsAt: isoFromEpochMs(fiveHourLimit.nextResetTime),
|
|
@@ -154,7 +157,11 @@ function quotaStateFromZaiQuotaLimitPayload(payload, capturedAt = new Date().toI
|
|
|
154
157
|
planType: level,
|
|
155
158
|
limitId: level ? `zai-${level}` : 'zai-coding-plan',
|
|
156
159
|
limitName: displayPlanName(level),
|
|
157
|
-
}
|
|
160
|
+
}, {
|
|
161
|
+
fiveHourWindowMs: quota_1.FIVE_HOUR_WINDOW_MS,
|
|
162
|
+
sevenDayWindowMs: quota_1.SEVEN_DAY_WINDOW_MS,
|
|
163
|
+
capturedAt,
|
|
164
|
+
});
|
|
158
165
|
}
|
|
159
166
|
function parseRetryAfterMs(retryAfter) {
|
|
160
167
|
if (!retryAfter)
|
|
@@ -239,8 +246,9 @@ async function fetchZaiQuotaFromApi(options = {}) {
|
|
|
239
246
|
}
|
|
240
247
|
}
|
|
241
248
|
function enrichZaiQuota(state) {
|
|
249
|
+
const withProjections = (0, quota_1.withQuotaProjections)(state);
|
|
242
250
|
return {
|
|
243
|
-
...
|
|
251
|
+
...withProjections,
|
|
244
252
|
runtimeProvider: 'zai',
|
|
245
253
|
providerId: 'zai',
|
|
246
254
|
fiveHourLabel: state.fiveHourLabel ?? '5-Hour',
|
package/dist/zaiQuotaWatcher.js
CHANGED
|
@@ -251,7 +251,7 @@ class ZaiQuotaWatcher {
|
|
|
251
251
|
const cutoff = this.now() - SEVEN_DAY_MS;
|
|
252
252
|
if (this.turns.length === 0)
|
|
253
253
|
return;
|
|
254
|
-
const next = this.turns.filter(turn => turn.timestampMs >= cutoff);
|
|
254
|
+
const next = this.turns.filter((turn) => turn.timestampMs >= cutoff);
|
|
255
255
|
if (next.length !== this.turns.length) {
|
|
256
256
|
this.turns = next;
|
|
257
257
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sidekick-shared",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.4",
|
|
4
4
|
"description": "Shared data access layer for Sidekick — readers, types, providers, credentials, quota",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -55,6 +55,8 @@
|
|
|
55
55
|
"clean": "rm -rf dist",
|
|
56
56
|
"lint": "eslint src/",
|
|
57
57
|
"lint:fix": "eslint src/ --fix",
|
|
58
|
+
"format": "prettier --config ../prettier.config.cjs --ignore-path ../.prettierignore --write \"src/**/*.{ts,tsx,js,jsx,json,md,css,html,yml,yaml}\" \"*.{js,cjs,mjs,json,md,yml,yaml}\"",
|
|
59
|
+
"format:check": "prettier --config ../prettier.config.cjs --ignore-path ../.prettierignore --check \"src/**/*.{ts,tsx,js,jsx,json,md,css,html,yml,yaml}\" \"*.{js,cjs,mjs,json,md,yml,yaml}\"",
|
|
58
60
|
"pretest": "npm run build",
|
|
59
61
|
"test": "vitest run",
|
|
60
62
|
"test:watch": "vitest",
|
|
@@ -64,9 +66,10 @@
|
|
|
64
66
|
"@eslint/js": "^9.0.0",
|
|
65
67
|
"@types/node": "^22.0.0",
|
|
66
68
|
"eslint": "^9.0.0",
|
|
69
|
+
"prettier": "3.8.4",
|
|
67
70
|
"typescript": "^5.7.0",
|
|
68
71
|
"typescript-eslint": "^8.0.0",
|
|
69
|
-
"vitest": "^
|
|
72
|
+
"vitest": "^4.1.9"
|
|
70
73
|
},
|
|
71
74
|
"license": "MIT",
|
|
72
75
|
"dependencies": {
|