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
|
@@ -43,27 +43,37 @@ exports.sessionEventSchema = zod_1.z.object({
|
|
|
43
43
|
timestamp: zod_1.z.string(),
|
|
44
44
|
isSidechain: zod_1.z.boolean().optional(),
|
|
45
45
|
permissionMode: exports.permissionModeSchema.optional(),
|
|
46
|
-
rateLimits: zod_1.z
|
|
47
|
-
|
|
46
|
+
rateLimits: zod_1.z
|
|
47
|
+
.object({
|
|
48
|
+
primary: zod_1.z
|
|
49
|
+
.object({
|
|
48
50
|
usedPercent: zod_1.z.number(),
|
|
49
51
|
windowMinutes: zod_1.z.number(),
|
|
50
52
|
resetsAt: zod_1.z.number(),
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
+
})
|
|
54
|
+
.optional(),
|
|
55
|
+
secondary: zod_1.z
|
|
56
|
+
.object({
|
|
53
57
|
usedPercent: zod_1.z.number(),
|
|
54
58
|
windowMinutes: zod_1.z.number(),
|
|
55
59
|
resetsAt: zod_1.z.number(),
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
})
|
|
61
|
+
.optional(),
|
|
62
|
+
})
|
|
63
|
+
.optional(),
|
|
64
|
+
tool: zod_1.z
|
|
65
|
+
.object({
|
|
59
66
|
name: zod_1.z.string(),
|
|
60
67
|
input: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
61
|
-
})
|
|
62
|
-
|
|
68
|
+
})
|
|
69
|
+
.optional(),
|
|
70
|
+
result: zod_1.z
|
|
71
|
+
.object({
|
|
63
72
|
tool_use_id: zod_1.z.string(),
|
|
64
73
|
output: zod_1.z.unknown().optional(),
|
|
65
74
|
is_error: zod_1.z.boolean().optional(),
|
|
66
|
-
})
|
|
75
|
+
})
|
|
76
|
+
.optional(),
|
|
67
77
|
});
|
|
68
78
|
// ── Progress unwrapping ──
|
|
69
79
|
/** Recursion bound for nested progress envelopes; real data nests 1 level. */
|
|
@@ -114,7 +114,7 @@ class FilterEngine {
|
|
|
114
114
|
}
|
|
115
115
|
matchFuzzy(text) {
|
|
116
116
|
const lower = text.toLowerCase();
|
|
117
|
-
return this.fuzzyWords.every(w => lower.includes(w));
|
|
117
|
+
return this.fuzzyWords.every((w) => lower.includes(w));
|
|
118
118
|
}
|
|
119
119
|
matchRegex(text) {
|
|
120
120
|
if (!this.compiledRegex)
|
|
@@ -139,7 +139,7 @@ class FilterEngine {
|
|
|
139
139
|
if (this.fuzzyWords.length === 0)
|
|
140
140
|
return text;
|
|
141
141
|
// Highlight each fuzzy word independently
|
|
142
|
-
const pattern = this.fuzzyWords.map(w => this.escapeRegex(w)).join('|');
|
|
142
|
+
const pattern = this.fuzzyWords.map((w) => this.escapeRegex(w)).join('|');
|
|
143
143
|
return this.wrapMatches(text, pattern, format, 'gi');
|
|
144
144
|
}
|
|
145
145
|
highlightRegex(text, format) {
|
|
@@ -190,7 +190,7 @@ class FilterEngine {
|
|
|
190
190
|
this.fuzzyWords = this.query
|
|
191
191
|
.toLowerCase()
|
|
192
192
|
.split(/\s+/)
|
|
193
|
-
.filter(w => w.length > 0);
|
|
193
|
+
.filter((w) => w.length > 0);
|
|
194
194
|
break;
|
|
195
195
|
}
|
|
196
196
|
}
|
|
@@ -59,11 +59,15 @@ async function searchSessions(provider, query, opts) {
|
|
|
59
59
|
try {
|
|
60
60
|
const dir = folder.dir;
|
|
61
61
|
if (fs.existsSync(dir)) {
|
|
62
|
-
const entries = fs
|
|
63
|
-
|
|
62
|
+
const entries = fs
|
|
63
|
+
.readdirSync(dir)
|
|
64
|
+
.filter((f) => f.endsWith('.jsonl') || f.endsWith('.json'));
|
|
65
|
+
sessionFiles = entries.map((f) => path.join(dir, f));
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
|
-
catch {
|
|
68
|
+
catch {
|
|
69
|
+
/* skip */
|
|
70
|
+
}
|
|
67
71
|
// If no files found from dir scan, try findAllSessions with the folder name
|
|
68
72
|
if (sessionFiles.length === 0) {
|
|
69
73
|
// Use provider.findSessionFiles with the folder path as workspace
|
|
@@ -88,6 +92,8 @@ async function searchSessions(provider, query, opts) {
|
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
|
-
catch {
|
|
95
|
+
catch {
|
|
96
|
+
/* skip */
|
|
97
|
+
}
|
|
92
98
|
return results.slice(0, maxResults);
|
|
93
99
|
}
|
package/dist/terminalSync.js
CHANGED
|
@@ -73,7 +73,9 @@ function atomicWriteFile(filePath, content, mode = 0o600) {
|
|
|
73
73
|
try {
|
|
74
74
|
fs.rmSync(tmp, { force: true });
|
|
75
75
|
}
|
|
76
|
-
catch {
|
|
76
|
+
catch {
|
|
77
|
+
/* nothing to clean up */
|
|
78
|
+
}
|
|
77
79
|
throw err;
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -136,7 +138,7 @@ function uninstallShellHook() {
|
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
function isShellHookInstalled() {
|
|
139
|
-
return getShellRcPaths().some(rcPath => {
|
|
141
|
+
return getShellRcPaths().some((rcPath) => {
|
|
140
142
|
try {
|
|
141
143
|
const content = fs.readFileSync(rcPath, 'utf8');
|
|
142
144
|
return content.includes(HOOK_START) && content.includes(HOOK_END);
|
|
@@ -262,7 +262,11 @@ function capProcessSteps(steps, maxRetainedSteps) {
|
|
|
262
262
|
}
|
|
263
263
|
const omitted = steps.length - kept.length;
|
|
264
264
|
const omittedMarker = `... ${omitted} earlier process step${omitted === 1 ? '' : 's'} omitted`;
|
|
265
|
-
return {
|
|
265
|
+
return {
|
|
266
|
+
steps: [{ kind: 'narration', text: omittedMarker }, ...kept],
|
|
267
|
+
retainedIndexes,
|
|
268
|
+
omittedMarker,
|
|
269
|
+
};
|
|
266
270
|
}
|
|
267
271
|
function capReasoningBlocks(blocks, maxRetainedBlocks) {
|
|
268
272
|
const retainedIndexes = new Set();
|
|
@@ -38,12 +38,13 @@ function toFollowEvents(event, providerId) {
|
|
|
38
38
|
if (Array.isArray(content)) {
|
|
39
39
|
for (const block of content) {
|
|
40
40
|
if (block.type === 'tool_result' && typeof block.tool_use_id === 'string') {
|
|
41
|
-
const resultText = typeof block.content === 'string'
|
|
42
|
-
? truncate(block.content, 120)
|
|
43
|
-
: '';
|
|
41
|
+
const resultText = typeof block.content === 'string' ? truncate(block.content, 120) : '';
|
|
44
42
|
events.push({
|
|
45
|
-
providerId,
|
|
46
|
-
|
|
43
|
+
providerId,
|
|
44
|
+
type: 'tool_result',
|
|
45
|
+
timestamp: ts,
|
|
46
|
+
summary: resultText || '(tool result)',
|
|
47
|
+
raw: block,
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -51,8 +52,12 @@ function toFollowEvents(event, providerId) {
|
|
|
51
52
|
const text = extractTextContent(content);
|
|
52
53
|
if (text || events.length === 0) {
|
|
53
54
|
events.push({
|
|
54
|
-
providerId,
|
|
55
|
-
|
|
55
|
+
providerId,
|
|
56
|
+
type: 'user',
|
|
57
|
+
timestamp: ts,
|
|
58
|
+
summary: text || '(user message)',
|
|
59
|
+
model,
|
|
60
|
+
raw: event,
|
|
56
61
|
});
|
|
57
62
|
}
|
|
58
63
|
break;
|
|
@@ -67,9 +72,14 @@ function toFollowEvents(event, providerId) {
|
|
|
67
72
|
? summarizeToolInput(block.name, block.input)
|
|
68
73
|
: '';
|
|
69
74
|
events.push({
|
|
70
|
-
providerId,
|
|
75
|
+
providerId,
|
|
76
|
+
type: 'tool_use',
|
|
77
|
+
timestamp: ts,
|
|
71
78
|
summary: input ? `${block.name} ${input}` : block.name,
|
|
72
|
-
toolName: block.name,
|
|
79
|
+
toolName: block.name,
|
|
80
|
+
toolInput: input,
|
|
81
|
+
model,
|
|
82
|
+
raw: block,
|
|
73
83
|
});
|
|
74
84
|
}
|
|
75
85
|
}
|
|
@@ -78,8 +88,15 @@ function toFollowEvents(event, providerId) {
|
|
|
78
88
|
const text = extractTextContent(content);
|
|
79
89
|
if (text || events.length === 0) {
|
|
80
90
|
events.push({
|
|
81
|
-
providerId,
|
|
82
|
-
|
|
91
|
+
providerId,
|
|
92
|
+
type: 'assistant',
|
|
93
|
+
timestamp: ts,
|
|
94
|
+
summary: text || '(thinking...)',
|
|
95
|
+
tokens,
|
|
96
|
+
cacheTokens,
|
|
97
|
+
cost,
|
|
98
|
+
model,
|
|
99
|
+
raw: event,
|
|
83
100
|
});
|
|
84
101
|
}
|
|
85
102
|
else if (tokens) {
|
|
@@ -93,13 +110,16 @@ function toFollowEvents(event, providerId) {
|
|
|
93
110
|
}
|
|
94
111
|
case 'tool_use': {
|
|
95
112
|
const name = event.tool?.name || 'unknown';
|
|
96
|
-
const input = event.tool?.input
|
|
97
|
-
? summarizeToolInput(name, event.tool.input)
|
|
98
|
-
: '';
|
|
113
|
+
const input = event.tool?.input ? summarizeToolInput(name, event.tool.input) : '';
|
|
99
114
|
events.push({
|
|
100
|
-
providerId,
|
|
115
|
+
providerId,
|
|
116
|
+
type: 'tool_use',
|
|
117
|
+
timestamp: ts,
|
|
101
118
|
summary: input ? `${name} ${input}` : name,
|
|
102
|
-
toolName: name,
|
|
119
|
+
toolName: name,
|
|
120
|
+
toolInput: input,
|
|
121
|
+
model,
|
|
122
|
+
raw: event,
|
|
103
123
|
});
|
|
104
124
|
break;
|
|
105
125
|
}
|
|
@@ -107,26 +127,33 @@ function toFollowEvents(event, providerId) {
|
|
|
107
127
|
const output = event.result?.output;
|
|
108
128
|
const text = typeof output === 'string' ? truncate(output, 120) : '';
|
|
109
129
|
events.push({
|
|
110
|
-
providerId,
|
|
111
|
-
|
|
130
|
+
providerId,
|
|
131
|
+
type: 'tool_result',
|
|
132
|
+
timestamp: ts,
|
|
133
|
+
summary: text || '(tool result)',
|
|
134
|
+
raw: event,
|
|
112
135
|
});
|
|
113
136
|
break;
|
|
114
137
|
}
|
|
115
138
|
case 'summary': {
|
|
116
139
|
events.push({
|
|
117
|
-
providerId,
|
|
118
|
-
|
|
140
|
+
providerId,
|
|
141
|
+
type: 'summary',
|
|
142
|
+
timestamp: ts,
|
|
143
|
+
summary: 'Context compacted',
|
|
144
|
+
raw: event,
|
|
119
145
|
});
|
|
120
146
|
break;
|
|
121
147
|
}
|
|
122
148
|
case 'system': {
|
|
123
149
|
const text = extractTextContent(event.message?.content);
|
|
124
150
|
const label = event.message?.sourceLabel || event.message?.role || 'system';
|
|
125
|
-
const summary = text ||
|
|
126
|
-
? `Tokens: ${usage.input_tokens || 0} in / ${usage.output_tokens || 0} out`
|
|
127
|
-
: label);
|
|
151
|
+
const summary = text ||
|
|
152
|
+
(usage ? `Tokens: ${usage.input_tokens || 0} in / ${usage.output_tokens || 0} out` : label);
|
|
128
153
|
events.push({
|
|
129
|
-
providerId,
|
|
154
|
+
providerId,
|
|
155
|
+
type: 'system',
|
|
156
|
+
timestamp: ts,
|
|
130
157
|
summary: label && text ? `${label}: ${text}` : summary,
|
|
131
158
|
tokens,
|
|
132
159
|
cacheTokens,
|
|
@@ -142,8 +169,11 @@ function toFollowEvents(event, providerId) {
|
|
|
142
169
|
const evtType = event.type;
|
|
143
170
|
if (evtType === 'result') {
|
|
144
171
|
events.push({
|
|
145
|
-
providerId,
|
|
146
|
-
|
|
172
|
+
providerId,
|
|
173
|
+
type: 'system',
|
|
174
|
+
timestamp: ts,
|
|
175
|
+
summary: 'Session ended',
|
|
176
|
+
raw: event,
|
|
147
177
|
});
|
|
148
178
|
}
|
|
149
179
|
break;
|
package/dist/watchers/factory.js
CHANGED
|
@@ -56,9 +56,12 @@ function createWatcher(options) {
|
|
|
56
56
|
}
|
|
57
57
|
let sessionPath;
|
|
58
58
|
if (sessionId) {
|
|
59
|
-
const match = sessions.find(s => s.includes(sessionId));
|
|
59
|
+
const match = sessions.find((s) => s.includes(sessionId));
|
|
60
60
|
if (!match) {
|
|
61
|
-
throw new Error(`Session ${sessionId} not found. Available: ${sessions
|
|
61
|
+
throw new Error(`Session ${sessionId} not found. Available: ${sessions
|
|
62
|
+
.slice(0, 5)
|
|
63
|
+
.map((s) => path.basename(s))
|
|
64
|
+
.join(', ')}`);
|
|
62
65
|
}
|
|
63
66
|
sessionPath = match;
|
|
64
67
|
}
|
|
@@ -140,7 +140,9 @@ class JsonlTailReader {
|
|
|
140
140
|
try {
|
|
141
141
|
fs.closeSync(fd);
|
|
142
142
|
}
|
|
143
|
-
catch {
|
|
143
|
+
catch {
|
|
144
|
+
/* ignore close errors */
|
|
145
|
+
}
|
|
144
146
|
}
|
|
145
147
|
this.options.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
146
148
|
}
|
|
@@ -50,7 +50,9 @@ function normalizeClaudeCodeEvent(raw) {
|
|
|
50
50
|
const ts = raw.timestamp || new Date().toISOString();
|
|
51
51
|
const permissionMode = raw.permissionMode;
|
|
52
52
|
const usage = raw.message?.usage;
|
|
53
|
-
const tokens = usage
|
|
53
|
+
const tokens = usage
|
|
54
|
+
? { input: usage.input_tokens || 0, output: usage.output_tokens || 0 }
|
|
55
|
+
: undefined;
|
|
54
56
|
const cacheTokens = usage && (usage.cache_read_input_tokens || usage.cache_creation_input_tokens)
|
|
55
57
|
? { read: usage.cache_read_input_tokens || 0, write: usage.cache_creation_input_tokens || 0 }
|
|
56
58
|
: undefined;
|
|
@@ -62,12 +64,13 @@ function normalizeClaudeCodeEvent(raw) {
|
|
|
62
64
|
if (Array.isArray(content)) {
|
|
63
65
|
for (const block of content) {
|
|
64
66
|
if (block.type === 'tool_result' && typeof block.tool_use_id === 'string') {
|
|
65
|
-
const resultText = typeof block.content === 'string'
|
|
66
|
-
? truncate(block.content, 120)
|
|
67
|
-
: '';
|
|
67
|
+
const resultText = typeof block.content === 'string' ? truncate(block.content, 120) : '';
|
|
68
68
|
events.push({
|
|
69
|
-
providerId: 'claude-code',
|
|
70
|
-
|
|
69
|
+
providerId: 'claude-code',
|
|
70
|
+
type: 'tool_result',
|
|
71
|
+
timestamp: ts,
|
|
72
|
+
summary: resultText || '(tool result)',
|
|
73
|
+
raw: block,
|
|
71
74
|
});
|
|
72
75
|
}
|
|
73
76
|
}
|
|
@@ -75,8 +78,12 @@ function normalizeClaudeCodeEvent(raw) {
|
|
|
75
78
|
const text = extractTextContent(content);
|
|
76
79
|
if (text || events.length === 0) {
|
|
77
80
|
events.push({
|
|
78
|
-
providerId: 'claude-code',
|
|
79
|
-
|
|
81
|
+
providerId: 'claude-code',
|
|
82
|
+
type: 'user',
|
|
83
|
+
timestamp: ts,
|
|
84
|
+
summary: text || '(user message)',
|
|
85
|
+
model,
|
|
86
|
+
raw,
|
|
80
87
|
});
|
|
81
88
|
}
|
|
82
89
|
}
|
|
@@ -86,11 +93,18 @@ function normalizeClaudeCodeEvent(raw) {
|
|
|
86
93
|
if (Array.isArray(content)) {
|
|
87
94
|
for (const block of content) {
|
|
88
95
|
if (block.type === 'tool_use' && typeof block.name === 'string') {
|
|
89
|
-
const input = block.input
|
|
96
|
+
const input = block.input
|
|
97
|
+
? summarizeToolInput(block.name, block.input)
|
|
98
|
+
: '';
|
|
90
99
|
events.push({
|
|
91
|
-
providerId: 'claude-code',
|
|
100
|
+
providerId: 'claude-code',
|
|
101
|
+
type: 'tool_use',
|
|
102
|
+
timestamp: ts,
|
|
92
103
|
summary: input ? `${block.name} ${input}` : block.name,
|
|
93
|
-
toolName: block.name,
|
|
104
|
+
toolName: block.name,
|
|
105
|
+
toolInput: input,
|
|
106
|
+
model,
|
|
107
|
+
raw: block,
|
|
94
108
|
});
|
|
95
109
|
}
|
|
96
110
|
}
|
|
@@ -99,8 +113,15 @@ function normalizeClaudeCodeEvent(raw) {
|
|
|
99
113
|
const text = extractTextContent(content);
|
|
100
114
|
if (text || events.length === 0) {
|
|
101
115
|
events.push({
|
|
102
|
-
providerId: 'claude-code',
|
|
103
|
-
|
|
116
|
+
providerId: 'claude-code',
|
|
117
|
+
type: 'assistant',
|
|
118
|
+
timestamp: ts,
|
|
119
|
+
summary: text || '(thinking...)',
|
|
120
|
+
tokens,
|
|
121
|
+
cacheTokens,
|
|
122
|
+
cost,
|
|
123
|
+
model,
|
|
124
|
+
raw,
|
|
104
125
|
});
|
|
105
126
|
}
|
|
106
127
|
else if (tokens) {
|
|
@@ -113,16 +134,22 @@ function normalizeClaudeCodeEvent(raw) {
|
|
|
113
134
|
}
|
|
114
135
|
else if (raw.type === 'summary') {
|
|
115
136
|
events.push({
|
|
116
|
-
providerId: 'claude-code',
|
|
117
|
-
|
|
137
|
+
providerId: 'claude-code',
|
|
138
|
+
type: 'summary',
|
|
139
|
+
timestamp: ts,
|
|
140
|
+
summary: 'Context compacted',
|
|
141
|
+
raw,
|
|
118
142
|
});
|
|
119
143
|
}
|
|
120
144
|
else {
|
|
121
145
|
// system / result events
|
|
122
146
|
if (raw.type === 'result') {
|
|
123
147
|
events.push({
|
|
124
|
-
providerId: 'claude-code',
|
|
125
|
-
|
|
148
|
+
providerId: 'claude-code',
|
|
149
|
+
type: 'system',
|
|
150
|
+
timestamp: ts,
|
|
151
|
+
summary: 'Session ended',
|
|
152
|
+
raw,
|
|
126
153
|
});
|
|
127
154
|
}
|
|
128
155
|
}
|
|
@@ -171,16 +198,20 @@ function extractRateLimits(rl) {
|
|
|
171
198
|
if (!primary && !secondary)
|
|
172
199
|
return undefined;
|
|
173
200
|
return {
|
|
174
|
-
primary: primary
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
201
|
+
primary: primary
|
|
202
|
+
? {
|
|
203
|
+
usedPercent: primary.used_percent || 0,
|
|
204
|
+
windowMinutes: primary.window_minutes || 0,
|
|
205
|
+
resetsAt: primary.resets_at || 0,
|
|
206
|
+
}
|
|
207
|
+
: undefined,
|
|
208
|
+
secondary: secondary
|
|
209
|
+
? {
|
|
210
|
+
usedPercent: secondary.used_percent || 0,
|
|
211
|
+
windowMinutes: secondary.window_minutes || 0,
|
|
212
|
+
resetsAt: secondary.resets_at || 0,
|
|
213
|
+
}
|
|
214
|
+
: undefined,
|
|
184
215
|
};
|
|
185
216
|
}
|
|
186
217
|
function truncate(text, maxLen) {
|
|
@@ -208,7 +239,9 @@ class JsonlSessionWatcher {
|
|
|
208
239
|
onError: (err) => callbacks.onError?.(err),
|
|
209
240
|
});
|
|
210
241
|
}
|
|
211
|
-
get isActive() {
|
|
242
|
+
get isActive() {
|
|
243
|
+
return this._isActive;
|
|
244
|
+
}
|
|
212
245
|
/** Seek to a byte offset. Must be called before start(). */
|
|
213
246
|
seekTo(position) {
|
|
214
247
|
this.filePosition = position;
|
|
@@ -311,7 +344,9 @@ class JsonlSessionWatcher {
|
|
|
311
344
|
try {
|
|
312
345
|
fs.closeSync(fd);
|
|
313
346
|
}
|
|
314
|
-
catch {
|
|
347
|
+
catch {
|
|
348
|
+
/* ignore */
|
|
349
|
+
}
|
|
315
350
|
}
|
|
316
351
|
this.callbacks.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
317
352
|
}
|
|
@@ -332,16 +367,23 @@ class JsonlSessionWatcher {
|
|
|
332
367
|
const type = raw.type;
|
|
333
368
|
if (type === 'session_meta') {
|
|
334
369
|
events.push({
|
|
335
|
-
providerId: 'codex',
|
|
336
|
-
|
|
370
|
+
providerId: 'codex',
|
|
371
|
+
type: 'system',
|
|
372
|
+
timestamp: ts,
|
|
373
|
+
summary: `Session started in ${raw.payload?.cwd || '?'}`,
|
|
374
|
+
raw,
|
|
337
375
|
});
|
|
338
376
|
}
|
|
339
377
|
else if (type === 'turn_context') {
|
|
340
378
|
const payload = raw.payload;
|
|
341
379
|
if (payload?.model) {
|
|
342
380
|
events.push({
|
|
343
|
-
providerId: 'codex',
|
|
344
|
-
|
|
381
|
+
providerId: 'codex',
|
|
382
|
+
type: 'system',
|
|
383
|
+
timestamp: ts,
|
|
384
|
+
summary: `Model: ${payload.model}`,
|
|
385
|
+
model: payload.model,
|
|
386
|
+
raw,
|
|
345
387
|
});
|
|
346
388
|
}
|
|
347
389
|
}
|
|
@@ -352,15 +394,21 @@ class JsonlSessionWatcher {
|
|
|
352
394
|
if (p.role === 'user') {
|
|
353
395
|
const text = extractPayloadContent(p);
|
|
354
396
|
events.push({
|
|
355
|
-
providerId: 'codex',
|
|
356
|
-
|
|
397
|
+
providerId: 'codex',
|
|
398
|
+
type: 'user',
|
|
399
|
+
timestamp: ts,
|
|
400
|
+
summary: text || '(user message)',
|
|
401
|
+
raw,
|
|
357
402
|
});
|
|
358
403
|
}
|
|
359
404
|
else if (p.role === 'assistant' || p.type === 'message') {
|
|
360
405
|
const text = extractPayloadContent(p);
|
|
361
406
|
events.push({
|
|
362
|
-
providerId: 'codex',
|
|
363
|
-
|
|
407
|
+
providerId: 'codex',
|
|
408
|
+
type: 'assistant',
|
|
409
|
+
timestamp: ts,
|
|
410
|
+
summary: text || '(thinking...)',
|
|
411
|
+
raw,
|
|
364
412
|
});
|
|
365
413
|
}
|
|
366
414
|
else if (p.type === 'function_call' || p.type === 'custom_tool_call') {
|
|
@@ -370,25 +418,39 @@ class JsonlSessionWatcher {
|
|
|
370
418
|
try {
|
|
371
419
|
parsedArgs = JSON.parse(p.arguments);
|
|
372
420
|
}
|
|
373
|
-
catch {
|
|
421
|
+
catch {
|
|
422
|
+
/* keep empty */
|
|
423
|
+
}
|
|
374
424
|
const args = typeof p.arguments === 'string' ? truncate(p.arguments, 80) : '';
|
|
375
425
|
events.push({
|
|
376
|
-
providerId: 'codex',
|
|
426
|
+
providerId: 'codex',
|
|
427
|
+
type: 'tool_use',
|
|
428
|
+
timestamp: ts,
|
|
377
429
|
summary: args ? `${name} ${args}` : name,
|
|
378
|
-
toolName: name,
|
|
430
|
+
toolName: name,
|
|
431
|
+
toolInput: args,
|
|
432
|
+
raw: { input: parsedArgs },
|
|
379
433
|
});
|
|
380
434
|
}
|
|
381
435
|
else if (p.type === 'local_shell_call') {
|
|
382
436
|
const cmd = truncate(JSON.stringify(p.command ?? p.arguments ?? ''), 80);
|
|
383
437
|
events.push({
|
|
384
|
-
providerId: 'codex',
|
|
385
|
-
|
|
438
|
+
providerId: 'codex',
|
|
439
|
+
type: 'tool_use',
|
|
440
|
+
timestamp: ts,
|
|
441
|
+
summary: `Bash ${cmd}`,
|
|
442
|
+
toolName: 'Bash',
|
|
443
|
+
toolInput: cmd,
|
|
444
|
+
raw,
|
|
386
445
|
});
|
|
387
446
|
}
|
|
388
447
|
else if (p.type === 'function_call_output') {
|
|
389
448
|
events.push({
|
|
390
|
-
providerId: 'codex',
|
|
391
|
-
|
|
449
|
+
providerId: 'codex',
|
|
450
|
+
type: 'tool_result',
|
|
451
|
+
timestamp: ts,
|
|
452
|
+
summary: truncate(String(p.output ?? ''), 120),
|
|
453
|
+
raw,
|
|
392
454
|
});
|
|
393
455
|
}
|
|
394
456
|
}
|
|
@@ -402,12 +464,17 @@ class JsonlSessionWatcher {
|
|
|
402
464
|
const rateLimits = rl ? extractRateLimits(rl) : undefined;
|
|
403
465
|
if (usage || rateLimits) {
|
|
404
466
|
events.push({
|
|
405
|
-
providerId: 'codex',
|
|
467
|
+
providerId: 'codex',
|
|
468
|
+
type: 'system',
|
|
469
|
+
timestamp: ts,
|
|
406
470
|
summary: usage
|
|
407
471
|
? `Tokens: ${usage.input_tokens ?? 0} in / ${usage.output_tokens ?? 0} out`
|
|
408
472
|
: 'Rate limits updated',
|
|
409
473
|
tokens: usage
|
|
410
|
-
? {
|
|
474
|
+
? {
|
|
475
|
+
input: usage.input_tokens || 0,
|
|
476
|
+
output: usage.output_tokens || 0,
|
|
477
|
+
}
|
|
411
478
|
: undefined,
|
|
412
479
|
rateLimits,
|
|
413
480
|
raw,
|
|
@@ -419,8 +486,11 @@ class JsonlSessionWatcher {
|
|
|
419
486
|
if (collaboration === 'plan' && !this.codexInPlanMode) {
|
|
420
487
|
this.codexInPlanMode = true;
|
|
421
488
|
events.push({
|
|
422
|
-
providerId: 'codex',
|
|
423
|
-
|
|
489
|
+
providerId: 'codex',
|
|
490
|
+
type: 'tool_use',
|
|
491
|
+
timestamp: ts,
|
|
492
|
+
summary: 'EnterPlanMode',
|
|
493
|
+
toolName: 'EnterPlanMode',
|
|
424
494
|
raw: { input: { source: 'codex_task_started' } },
|
|
425
495
|
});
|
|
426
496
|
}
|
|
@@ -429,8 +499,11 @@ class JsonlSessionWatcher {
|
|
|
429
499
|
if (this.codexInPlanMode) {
|
|
430
500
|
this.codexInPlanMode = false;
|
|
431
501
|
events.push({
|
|
432
|
-
providerId: 'codex',
|
|
433
|
-
|
|
502
|
+
providerId: 'codex',
|
|
503
|
+
type: 'tool_use',
|
|
504
|
+
timestamp: ts,
|
|
505
|
+
summary: 'ExitPlanMode',
|
|
506
|
+
toolName: 'ExitPlanMode',
|
|
434
507
|
raw: { input: { source: 'codex_task_complete' } },
|
|
435
508
|
});
|
|
436
509
|
}
|
|
@@ -438,8 +511,11 @@ class JsonlSessionWatcher {
|
|
|
438
511
|
}
|
|
439
512
|
else if (type === 'compacted') {
|
|
440
513
|
events.push({
|
|
441
|
-
providerId: 'codex',
|
|
442
|
-
|
|
514
|
+
providerId: 'codex',
|
|
515
|
+
type: 'summary',
|
|
516
|
+
timestamp: ts,
|
|
517
|
+
summary: 'Context compacted',
|
|
518
|
+
raw,
|
|
443
519
|
});
|
|
444
520
|
}
|
|
445
521
|
return events;
|
|
@@ -59,7 +59,9 @@ class ProviderReaderSessionWatcher {
|
|
|
59
59
|
this.callbacks = callbacks;
|
|
60
60
|
this.reader = provider.createReader(sessionPath);
|
|
61
61
|
}
|
|
62
|
-
get isActive() {
|
|
62
|
+
get isActive() {
|
|
63
|
+
return this._isActive;
|
|
64
|
+
}
|
|
63
65
|
seekTo(position) {
|
|
64
66
|
this.reader.seekTo(position);
|
|
65
67
|
}
|