@shipfox/api-logs 9.3.0 → 10.1.0
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/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +35 -0
- package/dist/core/append-logs.d.ts.map +1 -1
- package/dist/core/append-logs.js +100 -12
- package/dist/core/append-logs.js.map +1 -1
- package/dist/core/close-stream.d.ts +6 -5
- package/dist/core/close-stream.d.ts.map +1 -1
- package/dist/core/close-stream.js +25 -7
- package/dist/core/close-stream.js.map +1 -1
- package/dist/core/entities/attempt-stream.d.ts +5 -0
- package/dist/core/entities/attempt-stream.d.ts.map +1 -1
- package/dist/core/entities/attempt-stream.js +1 -1
- package/dist/core/entities/attempt-stream.js.map +1 -1
- package/dist/core/session/claude/rows.d.ts +4 -2
- package/dist/core/session/claude/rows.d.ts.map +1 -1
- package/dist/core/session/claude/rows.js +137 -10
- package/dist/core/session/claude/rows.js.map +1 -1
- package/dist/core/session/claude-parser.d.ts +8 -1
- package/dist/core/session/claude-parser.d.ts.map +1 -1
- package/dist/core/session/claude-parser.js +30 -4
- package/dist/core/session/claude-parser.js.map +1 -1
- package/dist/core/session/parse-session.d.ts +6 -1
- package/dist/core/session/parse-session.d.ts.map +1 -1
- package/dist/core/session/parse-session.js +2 -2
- package/dist/core/session/parse-session.js.map +1 -1
- package/dist/db/db.d.ts +94 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/schema/attempt-streams.d.ts +94 -0
- package/dist/db/schema/attempt-streams.d.ts.map +1 -1
- package/dist/db/schema/attempt-streams.js +9 -1
- package/dist/db/schema/attempt-streams.js.map +1 -1
- package/dist/db/streams.d.ts +17 -6
- package/dist/db/streams.d.ts.map +1 -1
- package/dist/db/streams.js +21 -6
- package/dist/db/streams.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0001_strong_major_mapleleaf.sql +4 -0
- package/drizzle/meta/0001_snapshot.json +555 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +5 -5
- package/src/core/append-logs.test.ts +144 -4
- package/src/core/append-logs.ts +158 -6
- package/src/core/close-stream.ts +26 -7
- package/src/core/entities/attempt-stream.ts +6 -0
- package/src/core/finalize-attempt-stream.test.ts +57 -0
- package/src/core/session/claude/rows.ts +176 -7
- package/src/core/session/claude-parser.test.ts +279 -2
- package/src/core/session/claude-parser.ts +55 -4
- package/src/core/session/parse-session.ts +10 -1
- package/src/db/schema/attempt-streams.ts +10 -0
- package/src/db/streams.ts +43 -7
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,16 +1,132 @@
|
|
|
1
1
|
import { asLooseObject } from '../entry-schema.js';
|
|
2
|
-
import { booleanField, field, formatNumber, isMeta, metaItem, stringField, stringifyValue, toJson } from '../object.js';
|
|
2
|
+
import { booleanField, field, formatNumber, isMeta, metaItem, numberField, stringField, stringifyValue, toJson } from '../object.js';
|
|
3
3
|
import { lifecycleRow, messageRow, thinkingRow } from '../rows.js';
|
|
4
|
-
export
|
|
4
|
+
export const PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES = new Set([
|
|
5
|
+
'thinking_tokens',
|
|
6
|
+
'status',
|
|
7
|
+
'session_state_changed',
|
|
8
|
+
'task_progress',
|
|
9
|
+
'hook_progress',
|
|
10
|
+
'hook_started',
|
|
11
|
+
'commands_changed',
|
|
12
|
+
'files_persisted',
|
|
13
|
+
'memory_recall',
|
|
14
|
+
'local_command_output',
|
|
15
|
+
'plugin_install'
|
|
16
|
+
]);
|
|
17
|
+
const OUTPUT_REPROMPT_PREFIX = 'The previous turn ended without setting required workflow outputs:';
|
|
18
|
+
const SYSTEM_EVENT_MAPPINGS = {
|
|
19
|
+
permission_denied: {
|
|
20
|
+
label: 'Permission denied',
|
|
21
|
+
tone: 'error',
|
|
22
|
+
detail: (message)=>stringField(message, 'tool_name') ?? null,
|
|
23
|
+
meta: (message)=>[
|
|
24
|
+
metaItem('reason', stringField(message, 'decision_reason') ?? stringField(message, 'message'))
|
|
25
|
+
].filter(isMeta)
|
|
26
|
+
},
|
|
27
|
+
api_retry: {
|
|
28
|
+
label: 'API retry',
|
|
29
|
+
tone: 'warning',
|
|
30
|
+
detail: (message)=>{
|
|
31
|
+
const attempt = numberField(message, 'attempt');
|
|
32
|
+
const maxRetries = numberField(message, 'max_retries');
|
|
33
|
+
return attempt == null || maxRetries == null ? null : `attempt ${formatNumber(attempt)}/${formatNumber(maxRetries)}`;
|
|
34
|
+
},
|
|
35
|
+
meta: (message)=>[
|
|
36
|
+
numberMeta(message, 'error_status', 'status'),
|
|
37
|
+
numberMeta(message, 'retry_delay_ms', 'retry delay', 'ms')
|
|
38
|
+
].filter(isMeta)
|
|
39
|
+
},
|
|
40
|
+
informational: {
|
|
41
|
+
label: (message)=>titleCase(stringField(message, 'level') ?? 'informational'),
|
|
42
|
+
tone: (message)=>stringField(message, 'level') === 'warning' ? 'warning' : 'default',
|
|
43
|
+
detail: (message)=>stringField(message, 'content') ?? null
|
|
44
|
+
},
|
|
45
|
+
compact_boundary: {
|
|
46
|
+
label: 'Context compacted',
|
|
47
|
+
tone: 'default',
|
|
48
|
+
meta: (message)=>{
|
|
49
|
+
const compactMetadata = asLooseObject(field(message, 'compact_metadata')) ?? {};
|
|
50
|
+
return [
|
|
51
|
+
metaItem('trigger', stringField(compactMetadata, 'trigger')),
|
|
52
|
+
numberMeta(compactMetadata, 'pre_tokens', 'tokens before', 'tokens'),
|
|
53
|
+
numberMeta(compactMetadata, 'post_tokens', 'tokens after', 'tokens'),
|
|
54
|
+
numberMeta(compactMetadata, 'duration_ms', 'duration', 'ms')
|
|
55
|
+
].filter(isMeta);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
model_refusal_fallback: {
|
|
59
|
+
label: 'Model refused, fell back',
|
|
60
|
+
tone: 'warning'
|
|
61
|
+
},
|
|
62
|
+
model_refusal_no_fallback: {
|
|
63
|
+
label: 'Model refused',
|
|
64
|
+
tone: 'error'
|
|
65
|
+
},
|
|
66
|
+
mirror_error: {
|
|
67
|
+
label: 'Session mirror failed',
|
|
68
|
+
tone: 'error',
|
|
69
|
+
detail: (message)=>stringField(message, 'error') ?? null
|
|
70
|
+
},
|
|
71
|
+
worker_shutting_down: {
|
|
72
|
+
label: 'Worker shutting down',
|
|
73
|
+
tone: 'warning'
|
|
74
|
+
},
|
|
75
|
+
elicitation_complete: {
|
|
76
|
+
label: 'Elicitation complete',
|
|
77
|
+
tone: 'default'
|
|
78
|
+
},
|
|
79
|
+
notification: {
|
|
80
|
+
label: 'Notification',
|
|
81
|
+
tone: 'default'
|
|
82
|
+
},
|
|
83
|
+
task_started: {
|
|
84
|
+
label: 'Task started',
|
|
85
|
+
tone: 'default'
|
|
86
|
+
},
|
|
87
|
+
task_updated: {
|
|
88
|
+
label: 'Task updated',
|
|
89
|
+
tone: 'default'
|
|
90
|
+
},
|
|
91
|
+
task_notification: {
|
|
92
|
+
label: 'Task notification',
|
|
93
|
+
tone: 'default'
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
export function systemRow(timestamp, message, context) {
|
|
5
97
|
const subtype = stringField(message, 'subtype');
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
98
|
+
const sessionId = stringField(message, 'session_id') ?? stringField(message, 'sessionId');
|
|
99
|
+
const isInit = subtype === 'init' || message.type === 'init';
|
|
100
|
+
const baseMeta = [
|
|
9
101
|
metaItem('cwd', stringField(message, 'cwd'), false),
|
|
10
102
|
metaItem('model', stringField(message, 'model')),
|
|
11
103
|
metaItem('permission', stringField(message, 'permissionMode') ?? stringField(message, 'permission_mode'))
|
|
12
104
|
].filter(isMeta);
|
|
13
|
-
|
|
105
|
+
if (!isInit) {
|
|
106
|
+
const mapping = subtype === undefined ? undefined : SYSTEM_EVENT_MAPPINGS[subtype];
|
|
107
|
+
const label = mapping === undefined ? `Session event (${subtype ?? 'unknown'})` : typeof mapping.label === 'function' ? mapping.label(message) : mapping.label;
|
|
108
|
+
const tone = mapping === undefined ? 'default' : typeof mapping.tone === 'function' ? mapping.tone(message) : mapping.tone;
|
|
109
|
+
const detail = mapping?.detail?.(message) ?? null;
|
|
110
|
+
const meta = [
|
|
111
|
+
...baseMeta,
|
|
112
|
+
...mapping?.meta?.(message) ?? []
|
|
113
|
+
];
|
|
114
|
+
return lifecycleRow(timestamp, label, detail, tone, false, meta);
|
|
115
|
+
}
|
|
116
|
+
const isNewSession = !context.hasInit || sessionId === undefined || sessionId !== context.sessionId;
|
|
117
|
+
context.hasInit = true;
|
|
118
|
+
context.sessionId = sessionId ?? null;
|
|
119
|
+
context.turn = isNewSession ? 1 : context.turn + 1;
|
|
120
|
+
const label = isNewSession ? 'Session started' : `Turn ${context.turn} started`;
|
|
121
|
+
const meta = [
|
|
122
|
+
metaItem('session', isNewSession ? sessionId : null),
|
|
123
|
+
metaItem('turn', isNewSession ? null : String(context.turn)),
|
|
124
|
+
...baseMeta
|
|
125
|
+
].filter(isMeta);
|
|
126
|
+
return lifecycleRow(timestamp, label, null, 'default', false, meta);
|
|
127
|
+
}
|
|
128
|
+
function titleCase(value) {
|
|
129
|
+
return value.length === 0 ? value : `${value[0]?.toUpperCase()}${value.slice(1)}`;
|
|
14
130
|
}
|
|
15
131
|
export function assistantRows(timestamp, message) {
|
|
16
132
|
const sdkMessage = asLooseObject(message.message) ?? message;
|
|
@@ -55,11 +171,12 @@ export function assistantRows(timestamp, message) {
|
|
|
55
171
|
}
|
|
56
172
|
export function userRows(timestamp, message) {
|
|
57
173
|
const sdkMessage = asLooseObject(message.message) ?? message;
|
|
174
|
+
const role = isPlatformMessage(sdkMessage) ? 'platform' : 'user';
|
|
58
175
|
const rows = [];
|
|
59
176
|
const textParts = [];
|
|
60
177
|
const pushText = ()=>{
|
|
61
178
|
if (textParts.length === 0) return;
|
|
62
|
-
rows.push(messageRow(timestamp,
|
|
179
|
+
rows.push(messageRow(timestamp, role, role, textParts.join('\n\n'), false));
|
|
63
180
|
textParts.length = 0;
|
|
64
181
|
};
|
|
65
182
|
for (const block of contentBlocks(sdkMessage)){
|
|
@@ -76,21 +193,31 @@ export function userRows(timestamp, message) {
|
|
|
76
193
|
if (rows.length > 0) return rows;
|
|
77
194
|
const content = stringField(sdkMessage, 'content');
|
|
78
195
|
return [
|
|
79
|
-
messageRow(timestamp,
|
|
196
|
+
messageRow(timestamp, role, role, content ?? toJson(message), false)
|
|
80
197
|
];
|
|
81
198
|
}
|
|
82
|
-
export function resultRow(timestamp, message) {
|
|
199
|
+
export function resultRow(timestamp, message, turn, isFinalResult) {
|
|
83
200
|
const isError = booleanField(message, 'is_error') || booleanField(message, 'isError');
|
|
84
201
|
const subtype = stringField(message, 'subtype');
|
|
85
202
|
const terminalFailure = isError || subtype === 'error';
|
|
86
203
|
const detail = stringField(message, 'result') ?? stringField(message, 'error') ?? stringField(message, 'message') ?? null;
|
|
87
204
|
const meta = [
|
|
205
|
+
metaItem('turn', !terminalFailure && !isFinalResult && turn > 0 ? String(turn) : null),
|
|
88
206
|
numberMeta(message, 'duration_ms', 'duration', 'ms'),
|
|
89
207
|
numberMeta(message, 'duration_api_ms', 'api duration', 'ms'),
|
|
90
208
|
numberMeta(message, 'num_turns', 'turns'),
|
|
91
209
|
costMeta(message)
|
|
92
210
|
].filter(isMeta);
|
|
93
|
-
return lifecycleRow(timestamp, terminalFailure ? 'Session failed' : 'Session completed'
|
|
211
|
+
return lifecycleRow(timestamp, terminalFailure ? 'Session failed' : isFinalResult || turn === 0 ? 'Session completed' : `Turn ${turn} completed`, detail, terminalFailure ? 'error' : 'default', terminalFailure, meta);
|
|
212
|
+
}
|
|
213
|
+
function isPlatformMessage(message) {
|
|
214
|
+
const content = field(message, 'content');
|
|
215
|
+
if (typeof content === 'string') return content.startsWith(OUTPUT_REPROMPT_PREFIX);
|
|
216
|
+
if (!Array.isArray(content)) return false;
|
|
217
|
+
return content.some((block)=>{
|
|
218
|
+
const object = asLooseObject(block);
|
|
219
|
+
return stringField(object, 'text')?.startsWith(OUTPUT_REPROMPT_PREFIX) === true;
|
|
220
|
+
});
|
|
94
221
|
}
|
|
95
222
|
function contentBlocks(message) {
|
|
96
223
|
const content = message.content;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/session/claude/rows.ts"],"sourcesContent":["import type {\n SessionViewLifecycleRow,\n SessionViewRow,\n SessionViewRowMeta,\n SessionViewToolCallRow,\n SessionViewToolResultRow,\n} from '@shipfox/api-logs-dto';\nimport {asLooseObject} from '../entry-schema.js';\nimport {\n booleanField,\n field,\n formatNumber,\n isMeta,\n metaItem,\n stringField,\n stringifyValue,\n toJson,\n} from '../object.js';\nimport {lifecycleRow, messageRow, thinkingRow} from '../rows.js';\n\nexport function systemRow(\n timestamp: number,\n message: Record<string, unknown>,\n): SessionViewLifecycleRow {\n const subtype = stringField(message, 'subtype');\n const label = subtype === 'init' || message.type === 'init' ? 'Session started' : 'Session event';\n const detail = stringField(message, 'session_id') ?? stringField(message, 'sessionId') ?? null;\n const meta = [\n metaItem('cwd', stringField(message, 'cwd'), false),\n metaItem('model', stringField(message, 'model')),\n metaItem(\n 'permission',\n stringField(message, 'permissionMode') ?? stringField(message, 'permission_mode'),\n ),\n ].filter(isMeta);\n\n return lifecycleRow(timestamp, label, detail, 'default', false, meta);\n}\n\nexport function assistantRows(\n timestamp: number,\n message: Record<string, unknown>,\n): readonly SessionViewRow[] {\n const sdkMessage = asLooseObject(message.message) ?? message;\n const rows: SessionViewRow[] = [];\n const textParts: string[] = [];\n const thinkingParts: string[] = [];\n\n const pushText = () => {\n if (textParts.length === 0) return;\n rows.push(messageRow(timestamp, 'assistant', 'assistant', textParts.join('\\n\\n'), false));\n textParts.length = 0;\n };\n const pushThinking = () => {\n if (thinkingParts.length === 0) return;\n rows.push(thinkingRow(timestamp, thinkingParts.join('\\n\\n')));\n thinkingParts.length = 0;\n };\n\n for (const block of contentBlocks(sdkMessage)) {\n const type = stringField(block, 'type');\n if (type === 'tool_use' || type === 'tool-use' || type === 'toolCall') {\n pushText();\n pushThinking();\n rows.push(toolCallRow(timestamp, block));\n continue;\n }\n\n if (type === 'thinking' || type === 'reasoning') {\n pushText();\n const text = blockText(block);\n if (text) thinkingParts.push(text);\n continue;\n }\n\n pushThinking();\n const text = blockText(block);\n if (text) textParts.push(text);\n }\n\n pushText();\n pushThinking();\n\n if (rows.length > 0) return rows;\n\n const text = stringField(sdkMessage, 'content') ?? stringField(message, 'result');\n return [messageRow(timestamp, 'assistant', 'assistant', text ?? toJson(message), false)];\n}\n\nexport function userRows(\n timestamp: number,\n message: Record<string, unknown>,\n): readonly SessionViewRow[] {\n const sdkMessage = asLooseObject(message.message) ?? message;\n const rows: SessionViewRow[] = [];\n const textParts: string[] = [];\n const pushText = () => {\n if (textParts.length === 0) return;\n rows.push(messageRow(timestamp, 'user', 'user', textParts.join('\\n\\n'), false));\n textParts.length = 0;\n };\n\n for (const block of contentBlocks(sdkMessage)) {\n const type = stringField(block, 'type');\n if (type === 'tool_result' || type === 'tool-result') {\n pushText();\n rows.push(toolResultRow(timestamp, block));\n continue;\n }\n\n const text = blockText(block);\n if (text) textParts.push(text);\n }\n\n pushText();\n\n if (rows.length > 0) return rows;\n\n const content = stringField(sdkMessage, 'content');\n return [messageRow(timestamp, 'user', 'user', content ?? toJson(message), false)];\n}\n\nexport function resultRow(\n timestamp: number,\n message: Record<string, unknown>,\n): SessionViewLifecycleRow {\n const isError = booleanField(message, 'is_error') || booleanField(message, 'isError');\n const subtype = stringField(message, 'subtype');\n const terminalFailure = isError || subtype === 'error';\n const detail =\n stringField(message, 'result') ??\n stringField(message, 'error') ??\n stringField(message, 'message') ??\n null;\n const meta = [\n numberMeta(message, 'duration_ms', 'duration', 'ms'),\n numberMeta(message, 'duration_api_ms', 'api duration', 'ms'),\n numberMeta(message, 'num_turns', 'turns'),\n costMeta(message),\n ].filter(isMeta);\n\n return lifecycleRow(\n timestamp,\n terminalFailure ? 'Session failed' : 'Session completed',\n detail,\n terminalFailure ? 'error' : 'default',\n terminalFailure,\n meta,\n );\n}\n\nfunction contentBlocks(message: Record<string, unknown>): Record<string, unknown>[] {\n const content = message.content;\n if (!Array.isArray(content)) return [];\n\n return content.flatMap((block) => {\n const object = asLooseObject(block);\n return object ? [object] : [];\n });\n}\n\nfunction toolCallRow(timestamp: number, block: Record<string, unknown>): SessionViewToolCallRow {\n return {\n kind: 'tool-call',\n timestamp,\n id: stringField(block, 'id') ?? null,\n name: stringField(block, 'name') ?? 'tool',\n input: stringifyValue(field(block, 'input') ?? {}),\n };\n}\n\nfunction toolResultRow(\n timestamp: number,\n block: Record<string, unknown>,\n): SessionViewToolResultRow {\n return {\n kind: 'tool-result',\n timestamp,\n toolCallId: stringField(block, 'tool_use_id') ?? stringField(block, 'toolUseId') ?? null,\n toolName: stringField(block, 'name') ?? 'tool',\n output: blockText(block) || stringifyValue(field(block, 'content') ?? ''),\n isError: booleanField(block, 'is_error') || booleanField(block, 'isError'),\n };\n}\n\nfunction blockText(block: Record<string, unknown>): string {\n const content = field(block, 'content');\n if (Array.isArray(content)) {\n return content\n .map((item) => {\n const object = asLooseObject(item);\n return object ? blockText(object) : typeof item === 'string' ? item : '';\n })\n .filter(Boolean)\n .join('\\n\\n');\n }\n\n return (\n stringField(block, 'text') ??\n stringField(block, 'thinking') ??\n (typeof content === 'string' ? content : '') ??\n ''\n );\n}\n\nfunction numberMeta(\n value: unknown,\n key: string,\n label: string,\n unit?: string,\n): SessionViewRowMeta | null {\n const raw = field(value, key);\n if (typeof raw !== 'number' || !Number.isFinite(raw)) return null;\n\n return metaItem(label, unit ? `${formatNumber(raw)} ${unit}` : formatNumber(raw));\n}\n\nfunction costMeta(message: Record<string, unknown>): SessionViewRowMeta | null {\n const value = field(message, 'total_cost_usd') ?? field(message, 'totalCostUsd');\n if (typeof value !== 'number' || !Number.isFinite(value)) return null;\n\n return metaItem('cost', `$${value.toFixed(value < 0.01 ? 4 : 2)}`);\n}\n"],"names":["asLooseObject","booleanField","field","formatNumber","isMeta","metaItem","stringField","stringifyValue","toJson","lifecycleRow","messageRow","thinkingRow","systemRow","timestamp","message","subtype","label","type","detail","meta","filter","assistantRows","sdkMessage","rows","textParts","thinkingParts","pushText","length","push","join","pushThinking","block","contentBlocks","toolCallRow","text","blockText","userRows","toolResultRow","content","resultRow","isError","terminalFailure","numberMeta","costMeta","Array","isArray","flatMap","object","kind","id","name","input","toolCallId","toolName","output","map","item","Boolean","value","key","unit","raw","Number","isFinite","toFixed"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/session/claude/rows.ts"],"sourcesContent":["import type {\n SessionViewLifecycleRow,\n SessionViewRow,\n SessionViewRowMeta,\n SessionViewToolCallRow,\n SessionViewToolResultRow,\n} from '@shipfox/api-logs-dto';\nimport type {ClaudeParseContext} from '../claude-parser.js';\nimport {asLooseObject} from '../entry-schema.js';\nimport {\n booleanField,\n field,\n formatNumber,\n isMeta,\n metaItem,\n numberField,\n stringField,\n stringifyValue,\n toJson,\n} from '../object.js';\nimport {lifecycleRow, messageRow, thinkingRow} from '../rows.js';\n\nexport const PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES = new Set<string>([\n 'thinking_tokens',\n 'status',\n 'session_state_changed',\n 'task_progress',\n 'hook_progress',\n 'hook_started',\n 'commands_changed',\n 'files_persisted',\n 'memory_recall',\n 'local_command_output',\n 'plugin_install',\n]);\nconst OUTPUT_REPROMPT_PREFIX = 'The previous turn ended without setting required workflow outputs:';\n\ntype SystemEventMapping = {\n label: string | ((message: Record<string, unknown>) => string);\n tone:\n | SessionViewLifecycleRow['tone']\n | ((message: Record<string, unknown>) => SessionViewLifecycleRow['tone']);\n detail?: (message: Record<string, unknown>) => string | null;\n meta?: (message: Record<string, unknown>) => readonly SessionViewRowMeta[];\n};\n\nconst SYSTEM_EVENT_MAPPINGS: Record<string, SystemEventMapping> = {\n permission_denied: {\n label: 'Permission denied',\n tone: 'error',\n detail: (message) => stringField(message, 'tool_name') ?? null,\n meta: (message) =>\n [\n metaItem(\n 'reason',\n stringField(message, 'decision_reason') ?? stringField(message, 'message'),\n ),\n ].filter(isMeta),\n },\n api_retry: {\n label: 'API retry',\n tone: 'warning',\n detail: (message) => {\n const attempt = numberField(message, 'attempt');\n const maxRetries = numberField(message, 'max_retries');\n return attempt == null || maxRetries == null\n ? null\n : `attempt ${formatNumber(attempt)}/${formatNumber(maxRetries)}`;\n },\n meta: (message) =>\n [\n numberMeta(message, 'error_status', 'status'),\n numberMeta(message, 'retry_delay_ms', 'retry delay', 'ms'),\n ].filter(isMeta),\n },\n informational: {\n label: (message) => titleCase(stringField(message, 'level') ?? 'informational'),\n tone: (message) => (stringField(message, 'level') === 'warning' ? 'warning' : 'default'),\n detail: (message) => stringField(message, 'content') ?? null,\n },\n compact_boundary: {\n label: 'Context compacted',\n tone: 'default',\n meta: (message) => {\n const compactMetadata = asLooseObject(field(message, 'compact_metadata')) ?? {};\n return [\n metaItem('trigger', stringField(compactMetadata, 'trigger')),\n numberMeta(compactMetadata, 'pre_tokens', 'tokens before', 'tokens'),\n numberMeta(compactMetadata, 'post_tokens', 'tokens after', 'tokens'),\n numberMeta(compactMetadata, 'duration_ms', 'duration', 'ms'),\n ].filter(isMeta);\n },\n },\n model_refusal_fallback: {\n label: 'Model refused, fell back',\n tone: 'warning',\n },\n model_refusal_no_fallback: {\n label: 'Model refused',\n tone: 'error',\n },\n mirror_error: {\n label: 'Session mirror failed',\n tone: 'error',\n detail: (message) => stringField(message, 'error') ?? null,\n },\n worker_shutting_down: {\n label: 'Worker shutting down',\n tone: 'warning',\n },\n elicitation_complete: {\n label: 'Elicitation complete',\n tone: 'default',\n },\n notification: {\n label: 'Notification',\n tone: 'default',\n },\n task_started: {\n label: 'Task started',\n tone: 'default',\n },\n task_updated: {\n label: 'Task updated',\n tone: 'default',\n },\n task_notification: {\n label: 'Task notification',\n tone: 'default',\n },\n};\n\nexport function systemRow(\n timestamp: number,\n message: Record<string, unknown>,\n context: ClaudeParseContext,\n): SessionViewLifecycleRow {\n const subtype = stringField(message, 'subtype');\n const sessionId = stringField(message, 'session_id') ?? stringField(message, 'sessionId');\n const isInit = subtype === 'init' || message.type === 'init';\n const baseMeta = [\n metaItem('cwd', stringField(message, 'cwd'), false),\n metaItem('model', stringField(message, 'model')),\n metaItem(\n 'permission',\n stringField(message, 'permissionMode') ?? stringField(message, 'permission_mode'),\n ),\n ].filter(isMeta);\n\n if (!isInit) {\n const mapping = subtype === undefined ? undefined : SYSTEM_EVENT_MAPPINGS[subtype];\n const label =\n mapping === undefined\n ? `Session event (${subtype ?? 'unknown'})`\n : typeof mapping.label === 'function'\n ? mapping.label(message)\n : mapping.label;\n const tone =\n mapping === undefined\n ? 'default'\n : typeof mapping.tone === 'function'\n ? mapping.tone(message)\n : mapping.tone;\n const detail = mapping?.detail?.(message) ?? null;\n const meta = [...baseMeta, ...(mapping?.meta?.(message) ?? [])];\n\n return lifecycleRow(timestamp, label, detail, tone, false, meta);\n }\n\n const isNewSession =\n !context.hasInit || sessionId === undefined || sessionId !== context.sessionId;\n context.hasInit = true;\n context.sessionId = sessionId ?? null;\n context.turn = isNewSession ? 1 : context.turn + 1;\n\n const label = isNewSession ? 'Session started' : `Turn ${context.turn} started`;\n const meta = [\n metaItem('session', isNewSession ? sessionId : null),\n metaItem('turn', isNewSession ? null : String(context.turn)),\n ...baseMeta,\n ].filter(isMeta);\n\n return lifecycleRow(timestamp, label, null, 'default', false, meta);\n}\n\nfunction titleCase(value: string): string {\n return value.length === 0 ? value : `${value[0]?.toUpperCase()}${value.slice(1)}`;\n}\n\nexport function assistantRows(\n timestamp: number,\n message: Record<string, unknown>,\n): readonly SessionViewRow[] {\n const sdkMessage = asLooseObject(message.message) ?? message;\n const rows: SessionViewRow[] = [];\n const textParts: string[] = [];\n const thinkingParts: string[] = [];\n\n const pushText = () => {\n if (textParts.length === 0) return;\n rows.push(messageRow(timestamp, 'assistant', 'assistant', textParts.join('\\n\\n'), false));\n textParts.length = 0;\n };\n const pushThinking = () => {\n if (thinkingParts.length === 0) return;\n rows.push(thinkingRow(timestamp, thinkingParts.join('\\n\\n')));\n thinkingParts.length = 0;\n };\n\n for (const block of contentBlocks(sdkMessage)) {\n const type = stringField(block, 'type');\n if (type === 'tool_use' || type === 'tool-use' || type === 'toolCall') {\n pushText();\n pushThinking();\n rows.push(toolCallRow(timestamp, block));\n continue;\n }\n\n if (type === 'thinking' || type === 'reasoning') {\n pushText();\n const text = blockText(block);\n if (text) thinkingParts.push(text);\n continue;\n }\n\n pushThinking();\n const text = blockText(block);\n if (text) textParts.push(text);\n }\n\n pushText();\n pushThinking();\n\n if (rows.length > 0) return rows;\n\n const text = stringField(sdkMessage, 'content') ?? stringField(message, 'result');\n return [messageRow(timestamp, 'assistant', 'assistant', text ?? toJson(message), false)];\n}\n\nexport function userRows(\n timestamp: number,\n message: Record<string, unknown>,\n): readonly SessionViewRow[] {\n const sdkMessage = asLooseObject(message.message) ?? message;\n const role = isPlatformMessage(sdkMessage) ? 'platform' : 'user';\n const rows: SessionViewRow[] = [];\n const textParts: string[] = [];\n const pushText = () => {\n if (textParts.length === 0) return;\n rows.push(messageRow(timestamp, role, role, textParts.join('\\n\\n'), false));\n textParts.length = 0;\n };\n\n for (const block of contentBlocks(sdkMessage)) {\n const type = stringField(block, 'type');\n if (type === 'tool_result' || type === 'tool-result') {\n pushText();\n rows.push(toolResultRow(timestamp, block));\n continue;\n }\n\n const text = blockText(block);\n if (text) textParts.push(text);\n }\n\n pushText();\n\n if (rows.length > 0) return rows;\n\n const content = stringField(sdkMessage, 'content');\n return [messageRow(timestamp, role, role, content ?? toJson(message), false)];\n}\n\nexport function resultRow(\n timestamp: number,\n message: Record<string, unknown>,\n turn: number,\n isFinalResult: boolean,\n): SessionViewLifecycleRow {\n const isError = booleanField(message, 'is_error') || booleanField(message, 'isError');\n const subtype = stringField(message, 'subtype');\n const terminalFailure = isError || subtype === 'error';\n const detail =\n stringField(message, 'result') ??\n stringField(message, 'error') ??\n stringField(message, 'message') ??\n null;\n const meta = [\n metaItem('turn', !terminalFailure && !isFinalResult && turn > 0 ? String(turn) : null),\n numberMeta(message, 'duration_ms', 'duration', 'ms'),\n numberMeta(message, 'duration_api_ms', 'api duration', 'ms'),\n numberMeta(message, 'num_turns', 'turns'),\n costMeta(message),\n ].filter(isMeta);\n\n return lifecycleRow(\n timestamp,\n terminalFailure\n ? 'Session failed'\n : isFinalResult || turn === 0\n ? 'Session completed'\n : `Turn ${turn} completed`,\n detail,\n terminalFailure ? 'error' : 'default',\n terminalFailure,\n meta,\n );\n}\n\nfunction isPlatformMessage(message: Record<string, unknown>): boolean {\n const content = field(message, 'content');\n if (typeof content === 'string') return content.startsWith(OUTPUT_REPROMPT_PREFIX);\n if (!Array.isArray(content)) return false;\n\n return content.some((block) => {\n const object = asLooseObject(block);\n return stringField(object, 'text')?.startsWith(OUTPUT_REPROMPT_PREFIX) === true;\n });\n}\n\nfunction contentBlocks(message: Record<string, unknown>): Record<string, unknown>[] {\n const content = message.content;\n if (!Array.isArray(content)) return [];\n\n return content.flatMap((block) => {\n const object = asLooseObject(block);\n return object ? [object] : [];\n });\n}\n\nfunction toolCallRow(timestamp: number, block: Record<string, unknown>): SessionViewToolCallRow {\n return {\n kind: 'tool-call',\n timestamp,\n id: stringField(block, 'id') ?? null,\n name: stringField(block, 'name') ?? 'tool',\n input: stringifyValue(field(block, 'input') ?? {}),\n };\n}\n\nfunction toolResultRow(\n timestamp: number,\n block: Record<string, unknown>,\n): SessionViewToolResultRow {\n return {\n kind: 'tool-result',\n timestamp,\n toolCallId: stringField(block, 'tool_use_id') ?? stringField(block, 'toolUseId') ?? null,\n toolName: stringField(block, 'name') ?? 'tool',\n output: blockText(block) || stringifyValue(field(block, 'content') ?? ''),\n isError: booleanField(block, 'is_error') || booleanField(block, 'isError'),\n };\n}\n\nfunction blockText(block: Record<string, unknown>): string {\n const content = field(block, 'content');\n if (Array.isArray(content)) {\n return content\n .map((item) => {\n const object = asLooseObject(item);\n return object ? blockText(object) : typeof item === 'string' ? item : '';\n })\n .filter(Boolean)\n .join('\\n\\n');\n }\n\n return (\n stringField(block, 'text') ??\n stringField(block, 'thinking') ??\n (typeof content === 'string' ? content : '') ??\n ''\n );\n}\n\nfunction numberMeta(\n value: unknown,\n key: string,\n label: string,\n unit?: string,\n): SessionViewRowMeta | null {\n const raw = field(value, key);\n if (typeof raw !== 'number' || !Number.isFinite(raw)) return null;\n\n return metaItem(label, unit ? `${formatNumber(raw)} ${unit}` : formatNumber(raw));\n}\n\nfunction costMeta(message: Record<string, unknown>): SessionViewRowMeta | null {\n const value = field(message, 'total_cost_usd') ?? field(message, 'totalCostUsd');\n if (typeof value !== 'number' || !Number.isFinite(value)) return null;\n\n return metaItem('cost', `$${value.toFixed(value < 0.01 ? 4 : 2)}`);\n}\n"],"names":["asLooseObject","booleanField","field","formatNumber","isMeta","metaItem","numberField","stringField","stringifyValue","toJson","lifecycleRow","messageRow","thinkingRow","PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES","Set","OUTPUT_REPROMPT_PREFIX","SYSTEM_EVENT_MAPPINGS","permission_denied","label","tone","detail","message","meta","filter","api_retry","attempt","maxRetries","numberMeta","informational","titleCase","compact_boundary","compactMetadata","model_refusal_fallback","model_refusal_no_fallback","mirror_error","worker_shutting_down","elicitation_complete","notification","task_started","task_updated","task_notification","systemRow","timestamp","context","subtype","sessionId","isInit","type","baseMeta","mapping","undefined","isNewSession","hasInit","turn","String","value","length","toUpperCase","slice","assistantRows","sdkMessage","rows","textParts","thinkingParts","pushText","push","join","pushThinking","block","contentBlocks","toolCallRow","text","blockText","userRows","role","isPlatformMessage","toolResultRow","content","resultRow","isFinalResult","isError","terminalFailure","costMeta","startsWith","Array","isArray","some","object","flatMap","kind","id","name","input","toolCallId","toolName","output","map","item","Boolean","key","unit","raw","Number","isFinite","toFixed"],"mappings":"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"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { SessionViewRow } from '@shipfox/api-logs-dto';
|
|
2
2
|
import type { AgentSessionRecord } from './session-record.js';
|
|
3
|
-
export
|
|
3
|
+
export interface ClaudeParseContext {
|
|
4
|
+
hasInit: boolean;
|
|
5
|
+
sessionId: string | null;
|
|
6
|
+
turn: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function createClaudeParseContext(): ClaudeParseContext;
|
|
9
|
+
export declare function claudeInitSessionId(record: AgentSessionRecord): string | undefined;
|
|
10
|
+
export declare function parseClaudeSessionRecord(record: AgentSessionRecord, context?: ClaudeParseContext, isFinalResult?: boolean): readonly SessionViewRow[];
|
|
4
11
|
//# sourceMappingURL=claude-parser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-parser.d.ts","sourceRoot":"","sources":["../../../src/core/session/claude-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-parser.d.ts","sourceRoot":"","sources":["../../../src/core/session/claude-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAW1D,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAC;AAQ5D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAE7D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAoBlF;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,kBAA+C,EACxD,aAAa,UAAO,GACnB,SAAS,cAAc,EAAE,CAiC3B"}
|
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { assistantRows, resultRow, systemRow, userRows } from './claude/rows.js';
|
|
2
|
+
import { assistantRows, PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES, resultRow, systemRow, userRows } from './claude/rows.js';
|
|
3
|
+
import { stringField } from './object.js';
|
|
3
4
|
import { rawRecordRow } from './rows.js';
|
|
4
5
|
const claudeMessageSchema = z.object({
|
|
5
6
|
type: z.string().min(1)
|
|
6
7
|
}).catchall(z.unknown());
|
|
7
|
-
export function
|
|
8
|
+
export function createClaudeParseContext() {
|
|
9
|
+
return {
|
|
10
|
+
hasInit: false,
|
|
11
|
+
sessionId: null,
|
|
12
|
+
turn: 0
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function claudeInitSessionId(record) {
|
|
16
|
+
let json;
|
|
17
|
+
try {
|
|
18
|
+
json = JSON.parse(record.data);
|
|
19
|
+
} catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const parsed = claudeMessageSchema.safeParse(json);
|
|
23
|
+
if (!parsed.success) return undefined;
|
|
24
|
+
const message = parsed.data;
|
|
25
|
+
if (message.type !== 'init' && !(message.type === 'system' && stringField(message, 'subtype') === 'init')) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return stringField(message, 'session_id') ?? stringField(message, 'sessionId');
|
|
29
|
+
}
|
|
30
|
+
export function parseClaudeSessionRecord(record, context = createClaudeParseContext(), isFinalResult = true) {
|
|
8
31
|
let json;
|
|
9
32
|
try {
|
|
10
33
|
json = JSON.parse(record.data);
|
|
@@ -18,11 +41,14 @@ export function parseClaudeSessionRecord(record) {
|
|
|
18
41
|
rawRecordRow(record, 'Unsupported Claude message')
|
|
19
42
|
];
|
|
20
43
|
const message = parsed.data;
|
|
44
|
+
if (message.type === 'system' && typeof message.subtype === 'string' && PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES.has(message.subtype)) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
21
47
|
switch(message.type){
|
|
22
48
|
case 'system':
|
|
23
49
|
case 'init':
|
|
24
50
|
return [
|
|
25
|
-
systemRow(record.ts, message)
|
|
51
|
+
systemRow(record.ts, message, context)
|
|
26
52
|
];
|
|
27
53
|
case 'assistant':
|
|
28
54
|
return assistantRows(record.ts, message);
|
|
@@ -30,7 +56,7 @@ export function parseClaudeSessionRecord(record) {
|
|
|
30
56
|
return userRows(record.ts, message);
|
|
31
57
|
case 'result':
|
|
32
58
|
return [
|
|
33
|
-
resultRow(record.ts, message)
|
|
59
|
+
resultRow(record.ts, message, context.turn, isFinalResult)
|
|
34
60
|
];
|
|
35
61
|
default:
|
|
36
62
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/session/claude-parser.ts"],"sourcesContent":["import type {SessionViewRow} from '@shipfox/api-logs-dto';\nimport {z} from 'zod';\nimport {assistantRows
|
|
1
|
+
{"version":3,"sources":["../../../src/core/session/claude-parser.ts"],"sourcesContent":["import type {SessionViewRow} from '@shipfox/api-logs-dto';\nimport {z} from 'zod';\nimport {\n assistantRows,\n PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES,\n resultRow,\n systemRow,\n userRows,\n} from './claude/rows.js';\nimport {stringField} from './object.js';\nimport {rawRecordRow} from './rows.js';\nimport type {AgentSessionRecord} from './session-record.js';\n\nconst claudeMessageSchema = z\n .object({\n type: z.string().min(1),\n })\n .catchall(z.unknown());\n\nexport interface ClaudeParseContext {\n hasInit: boolean;\n sessionId: string | null;\n turn: number;\n}\n\nexport function createClaudeParseContext(): ClaudeParseContext {\n return {hasInit: false, sessionId: null, turn: 0};\n}\n\nexport function claudeInitSessionId(record: AgentSessionRecord): string | undefined {\n let json: unknown;\n try {\n json = JSON.parse(record.data);\n } catch {\n return undefined;\n }\n\n const parsed = claudeMessageSchema.safeParse(json);\n if (!parsed.success) return undefined;\n\n const message = parsed.data;\n if (\n message.type !== 'init' &&\n !(message.type === 'system' && stringField(message, 'subtype') === 'init')\n ) {\n return undefined;\n }\n\n return stringField(message, 'session_id') ?? stringField(message, 'sessionId');\n}\n\nexport function parseClaudeSessionRecord(\n record: AgentSessionRecord,\n context: ClaudeParseContext = createClaudeParseContext(),\n isFinalResult = true,\n): readonly SessionViewRow[] {\n let json: unknown;\n try {\n json = JSON.parse(record.data);\n } catch {\n return [rawRecordRow(record, 'Malformed session entry')];\n }\n\n const parsed = claudeMessageSchema.safeParse(json);\n if (!parsed.success) return [rawRecordRow(record, 'Unsupported Claude message')];\n\n const message = parsed.data;\n if (\n message.type === 'system' &&\n typeof message.subtype === 'string' &&\n PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES.has(message.subtype)\n ) {\n return [];\n }\n\n switch (message.type) {\n case 'system':\n case 'init':\n return [systemRow(record.ts, message, context)];\n case 'assistant':\n return assistantRows(record.ts, message);\n case 'user':\n return userRows(record.ts, message);\n case 'result':\n return [resultRow(record.ts, message, context.turn, isFinalResult)];\n default:\n return [rawRecordRow(record, `Unknown Claude message: ${message.type}`)];\n }\n}\n"],"names":["z","assistantRows","PURE_PROGRESS_CLAUDE_SYSTEM_SUBTYPES","resultRow","systemRow","userRows","stringField","rawRecordRow","claudeMessageSchema","object","type","string","min","catchall","unknown","createClaudeParseContext","hasInit","sessionId","turn","claudeInitSessionId","record","json","JSON","parse","data","undefined","parsed","safeParse","success","message","parseClaudeSessionRecord","context","isFinalResult","subtype","has","ts"],"mappings":"AACA,SAAQA,CAAC,QAAO,MAAM;AACtB,SACEC,aAAa,EACbC,oCAAoC,EACpCC,SAAS,EACTC,SAAS,EACTC,QAAQ,QACH,mBAAmB;AAC1B,SAAQC,WAAW,QAAO,cAAc;AACxC,SAAQC,YAAY,QAAO,YAAY;AAGvC,MAAMC,sBAAsBR,EACzBS,MAAM,CAAC;IACNC,MAAMV,EAAEW,MAAM,GAAGC,GAAG,CAAC;AACvB,GACCC,QAAQ,CAACb,EAAEc,OAAO;AAQrB,OAAO,SAASC;IACd,OAAO;QAACC,SAAS;QAAOC,WAAW;QAAMC,MAAM;IAAC;AAClD;AAEA,OAAO,SAASC,oBAAoBC,MAA0B;IAC5D,IAAIC;IACJ,IAAI;QACFA,OAAOC,KAAKC,KAAK,CAACH,OAAOI,IAAI;IAC/B,EAAE,OAAM;QACN,OAAOC;IACT;IAEA,MAAMC,SAASlB,oBAAoBmB,SAAS,CAACN;IAC7C,IAAI,CAACK,OAAOE,OAAO,EAAE,OAAOH;IAE5B,MAAMI,UAAUH,OAAOF,IAAI;IAC3B,IACEK,QAAQnB,IAAI,KAAK,UACjB,CAAEmB,CAAAA,QAAQnB,IAAI,KAAK,YAAYJ,YAAYuB,SAAS,eAAe,MAAK,GACxE;QACA,OAAOJ;IACT;IAEA,OAAOnB,YAAYuB,SAAS,iBAAiBvB,YAAYuB,SAAS;AACpE;AAEA,OAAO,SAASC,yBACdV,MAA0B,EAC1BW,UAA8BhB,0BAA0B,EACxDiB,gBAAgB,IAAI;IAEpB,IAAIX;IACJ,IAAI;QACFA,OAAOC,KAAKC,KAAK,CAACH,OAAOI,IAAI;IAC/B,EAAE,OAAM;QACN,OAAO;YAACjB,aAAaa,QAAQ;SAA2B;IAC1D;IAEA,MAAMM,SAASlB,oBAAoBmB,SAAS,CAACN;IAC7C,IAAI,CAACK,OAAOE,OAAO,EAAE,OAAO;QAACrB,aAAaa,QAAQ;KAA8B;IAEhF,MAAMS,UAAUH,OAAOF,IAAI;IAC3B,IACEK,QAAQnB,IAAI,KAAK,YACjB,OAAOmB,QAAQI,OAAO,KAAK,YAC3B/B,qCAAqCgC,GAAG,CAACL,QAAQI,OAAO,GACxD;QACA,OAAO,EAAE;IACX;IAEA,OAAQJ,QAAQnB,IAAI;QAClB,KAAK;QACL,KAAK;YACH,OAAO;gBAACN,UAAUgB,OAAOe,EAAE,EAAEN,SAASE;aAAS;QACjD,KAAK;YACH,OAAO9B,cAAcmB,OAAOe,EAAE,EAAEN;QAClC,KAAK;YACH,OAAOxB,SAASe,OAAOe,EAAE,EAAEN;QAC7B,KAAK;YACH,OAAO;gBAAC1B,UAAUiB,OAAOe,EAAE,EAAEN,SAASE,QAAQb,IAAI,EAAEc;aAAe;QACrE;YACE,OAAO;gBAACzB,aAAaa,QAAQ,CAAC,wBAAwB,EAAES,QAAQnB,IAAI,EAAE;aAAE;IAC5E;AACF"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { SessionViewRow } from '@shipfox/api-logs-dto';
|
|
2
2
|
import type { Harness } from '@shipfox/workflow-document';
|
|
3
|
+
import type { ClaudeParseContext } from './claude-parser.js';
|
|
3
4
|
import type { AgentSessionRecord } from './session-record.js';
|
|
4
|
-
export
|
|
5
|
+
export interface SessionParseContext {
|
|
6
|
+
claude?: ClaudeParseContext;
|
|
7
|
+
isFinalResult?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseSessionRecord(record: AgentSessionRecord, harness: Harness, context?: SessionParseContext): readonly SessionViewRow[];
|
|
5
10
|
//# sourceMappingURL=parse-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-session.d.ts","sourceRoot":"","sources":["../../../src/core/session/parse-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"parse-session.d.ts","sourceRoot":"","sources":["../../../src/core/session/parse-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAG3D,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,SAAS,cAAc,EAAE,CAe3B"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { parseClaudeSessionRecord } from './claude-parser.js';
|
|
2
2
|
import { parsePiSessionRecord } from './pi-parser.js';
|
|
3
|
-
export function parseSessionRecord(record, harness) {
|
|
3
|
+
export function parseSessionRecord(record, harness, context) {
|
|
4
4
|
try {
|
|
5
|
-
return harness === 'claude' ? parseClaudeSessionRecord(record) : parsePiSessionRecord(record);
|
|
5
|
+
return harness === 'claude' ? parseClaudeSessionRecord(record, context?.claude, context?.isFinalResult ?? true) : parsePiSessionRecord(record);
|
|
6
6
|
} catch {
|
|
7
7
|
return [
|
|
8
8
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/session/parse-session.ts"],"sourcesContent":["import type {SessionViewRow} from '@shipfox/api-logs-dto';\nimport type {Harness} from '@shipfox/workflow-document';\nimport {parseClaudeSessionRecord} from './claude-parser.js';\nimport {parsePiSessionRecord} from './pi-parser.js';\nimport type {AgentSessionRecord} from './session-record.js';\n\nexport function parseSessionRecord(\n record: AgentSessionRecord,\n harness: Harness,\n): readonly SessionViewRow[] {\n try {\n return harness === 'claude'
|
|
1
|
+
{"version":3,"sources":["../../../src/core/session/parse-session.ts"],"sourcesContent":["import type {SessionViewRow} from '@shipfox/api-logs-dto';\nimport type {Harness} from '@shipfox/workflow-document';\nimport type {ClaudeParseContext} from './claude-parser.js';\nimport {parseClaudeSessionRecord} from './claude-parser.js';\nimport {parsePiSessionRecord} from './pi-parser.js';\nimport type {AgentSessionRecord} from './session-record.js';\n\nexport interface SessionParseContext {\n claude?: ClaudeParseContext;\n isFinalResult?: boolean;\n}\n\nexport function parseSessionRecord(\n record: AgentSessionRecord,\n harness: Harness,\n context?: SessionParseContext,\n): readonly SessionViewRow[] {\n try {\n return harness === 'claude'\n ? parseClaudeSessionRecord(record, context?.claude, context?.isFinalResult ?? true)\n : parsePiSessionRecord(record);\n } catch {\n return [\n {\n kind: 'raw',\n timestamp: record.ts,\n label: 'Unsupported session entry',\n raw: record.data,\n },\n ];\n }\n}\n"],"names":["parseClaudeSessionRecord","parsePiSessionRecord","parseSessionRecord","record","harness","context","claude","isFinalResult","kind","timestamp","ts","label","raw","data"],"mappings":"AAGA,SAAQA,wBAAwB,QAAO,qBAAqB;AAC5D,SAAQC,oBAAoB,QAAO,iBAAiB;AAQpD,OAAO,SAASC,mBACdC,MAA0B,EAC1BC,OAAgB,EAChBC,OAA6B;IAE7B,IAAI;QACF,OAAOD,YAAY,WACfJ,yBAAyBG,QAAQE,SAASC,QAAQD,SAASE,iBAAiB,QAC5EN,qBAAqBE;IAC3B,EAAE,OAAM;QACN,OAAO;YACL;gBACEK,MAAM;gBACNC,WAAWN,OAAOO,EAAE;gBACpBC,OAAO;gBACPC,KAAKT,OAAOU,IAAI;YAClB;SACD;IACH;AACF"}
|
package/dist/db/db.d.ts
CHANGED
|
@@ -317,6 +317,100 @@ export declare const schema: {
|
|
|
317
317
|
identity: undefined;
|
|
318
318
|
generated: undefined;
|
|
319
319
|
}, {}, {}>;
|
|
320
|
+
claudeHasInit: import("drizzle-orm/pg-core").PgColumn<{
|
|
321
|
+
name: "claude_has_init";
|
|
322
|
+
tableName: "attempt_streams";
|
|
323
|
+
dataType: "boolean";
|
|
324
|
+
columnType: "PgBoolean";
|
|
325
|
+
data: boolean;
|
|
326
|
+
driverParam: boolean;
|
|
327
|
+
notNull: true;
|
|
328
|
+
hasDefault: true;
|
|
329
|
+
isPrimaryKey: false;
|
|
330
|
+
isAutoincrement: false;
|
|
331
|
+
hasRuntimeDefault: false;
|
|
332
|
+
enumValues: undefined;
|
|
333
|
+
baseColumn: never;
|
|
334
|
+
identity: undefined;
|
|
335
|
+
generated: undefined;
|
|
336
|
+
}, {}, {}>;
|
|
337
|
+
claudeSessionId: import("drizzle-orm/pg-core").PgColumn<{
|
|
338
|
+
name: "claude_session_id";
|
|
339
|
+
tableName: "attempt_streams";
|
|
340
|
+
dataType: "string";
|
|
341
|
+
columnType: "PgText";
|
|
342
|
+
data: string;
|
|
343
|
+
driverParam: string;
|
|
344
|
+
notNull: false;
|
|
345
|
+
hasDefault: false;
|
|
346
|
+
isPrimaryKey: false;
|
|
347
|
+
isAutoincrement: false;
|
|
348
|
+
hasRuntimeDefault: false;
|
|
349
|
+
enumValues: [string, ...string[]];
|
|
350
|
+
baseColumn: never;
|
|
351
|
+
identity: undefined;
|
|
352
|
+
generated: undefined;
|
|
353
|
+
}, {}, {}>;
|
|
354
|
+
claudeTurn: import("drizzle-orm/pg-core").PgColumn<{
|
|
355
|
+
name: "claude_turn";
|
|
356
|
+
tableName: "attempt_streams";
|
|
357
|
+
dataType: "number";
|
|
358
|
+
columnType: "PgInteger";
|
|
359
|
+
data: number;
|
|
360
|
+
driverParam: string | number;
|
|
361
|
+
notNull: true;
|
|
362
|
+
hasDefault: true;
|
|
363
|
+
isPrimaryKey: false;
|
|
364
|
+
isAutoincrement: false;
|
|
365
|
+
hasRuntimeDefault: false;
|
|
366
|
+
enumValues: undefined;
|
|
367
|
+
baseColumn: never;
|
|
368
|
+
identity: undefined;
|
|
369
|
+
generated: undefined;
|
|
370
|
+
}, {}, {}>;
|
|
371
|
+
claudePendingResult: import("drizzle-orm/pg-core").PgColumn<{
|
|
372
|
+
name: "claude_pending_result";
|
|
373
|
+
tableName: "attempt_streams";
|
|
374
|
+
dataType: "json";
|
|
375
|
+
columnType: "PgJsonb";
|
|
376
|
+
data: {
|
|
377
|
+
kind: "lifecycle";
|
|
378
|
+
label: string;
|
|
379
|
+
detail: string | null;
|
|
380
|
+
meta: readonly {
|
|
381
|
+
label: string;
|
|
382
|
+
value: string;
|
|
383
|
+
inline?: boolean | undefined;
|
|
384
|
+
}[];
|
|
385
|
+
tone: "default" | "error" | "warning";
|
|
386
|
+
terminalFailure: boolean;
|
|
387
|
+
timestamp: number;
|
|
388
|
+
};
|
|
389
|
+
driverParam: unknown;
|
|
390
|
+
notNull: false;
|
|
391
|
+
hasDefault: false;
|
|
392
|
+
isPrimaryKey: false;
|
|
393
|
+
isAutoincrement: false;
|
|
394
|
+
hasRuntimeDefault: false;
|
|
395
|
+
enumValues: undefined;
|
|
396
|
+
baseColumn: never;
|
|
397
|
+
identity: undefined;
|
|
398
|
+
generated: undefined;
|
|
399
|
+
}, {}, {
|
|
400
|
+
$type: {
|
|
401
|
+
kind: "lifecycle";
|
|
402
|
+
label: string;
|
|
403
|
+
detail: string | null;
|
|
404
|
+
meta: readonly {
|
|
405
|
+
label: string;
|
|
406
|
+
value: string;
|
|
407
|
+
inline?: boolean | undefined;
|
|
408
|
+
}[];
|
|
409
|
+
tone: "default" | "error" | "warning";
|
|
410
|
+
terminalFailure: boolean;
|
|
411
|
+
timestamp: number;
|
|
412
|
+
};
|
|
413
|
+
}>;
|
|
320
414
|
truncated: import("drizzle-orm/pg-core").PgColumn<{
|
|
321
415
|
name: "truncated";
|
|
322
416
|
tableName: "attempt_streams";
|
package/dist/db/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAOnE,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAOnE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAyD,CAAC;AAE7E,MAAM,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,MAAM,CAAC,CAAC;AACrD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAIhF,wBAAgB,EAAE,aAGjB;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B"}
|
|
@@ -210,6 +210,100 @@ export declare const attemptStreams: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
210
210
|
identity: undefined;
|
|
211
211
|
generated: undefined;
|
|
212
212
|
}, {}, {}>;
|
|
213
|
+
claudeHasInit: import("drizzle-orm/pg-core").PgColumn<{
|
|
214
|
+
name: "claude_has_init";
|
|
215
|
+
tableName: "attempt_streams";
|
|
216
|
+
dataType: "boolean";
|
|
217
|
+
columnType: "PgBoolean";
|
|
218
|
+
data: boolean;
|
|
219
|
+
driverParam: boolean;
|
|
220
|
+
notNull: true;
|
|
221
|
+
hasDefault: true;
|
|
222
|
+
isPrimaryKey: false;
|
|
223
|
+
isAutoincrement: false;
|
|
224
|
+
hasRuntimeDefault: false;
|
|
225
|
+
enumValues: undefined;
|
|
226
|
+
baseColumn: never;
|
|
227
|
+
identity: undefined;
|
|
228
|
+
generated: undefined;
|
|
229
|
+
}, {}, {}>;
|
|
230
|
+
claudeSessionId: import("drizzle-orm/pg-core").PgColumn<{
|
|
231
|
+
name: "claude_session_id";
|
|
232
|
+
tableName: "attempt_streams";
|
|
233
|
+
dataType: "string";
|
|
234
|
+
columnType: "PgText";
|
|
235
|
+
data: string;
|
|
236
|
+
driverParam: string;
|
|
237
|
+
notNull: false;
|
|
238
|
+
hasDefault: false;
|
|
239
|
+
isPrimaryKey: false;
|
|
240
|
+
isAutoincrement: false;
|
|
241
|
+
hasRuntimeDefault: false;
|
|
242
|
+
enumValues: [string, ...string[]];
|
|
243
|
+
baseColumn: never;
|
|
244
|
+
identity: undefined;
|
|
245
|
+
generated: undefined;
|
|
246
|
+
}, {}, {}>;
|
|
247
|
+
claudeTurn: import("drizzle-orm/pg-core").PgColumn<{
|
|
248
|
+
name: "claude_turn";
|
|
249
|
+
tableName: "attempt_streams";
|
|
250
|
+
dataType: "number";
|
|
251
|
+
columnType: "PgInteger";
|
|
252
|
+
data: number;
|
|
253
|
+
driverParam: string | number;
|
|
254
|
+
notNull: true;
|
|
255
|
+
hasDefault: true;
|
|
256
|
+
isPrimaryKey: false;
|
|
257
|
+
isAutoincrement: false;
|
|
258
|
+
hasRuntimeDefault: false;
|
|
259
|
+
enumValues: undefined;
|
|
260
|
+
baseColumn: never;
|
|
261
|
+
identity: undefined;
|
|
262
|
+
generated: undefined;
|
|
263
|
+
}, {}, {}>;
|
|
264
|
+
claudePendingResult: import("drizzle-orm/pg-core").PgColumn<{
|
|
265
|
+
name: "claude_pending_result";
|
|
266
|
+
tableName: "attempt_streams";
|
|
267
|
+
dataType: "json";
|
|
268
|
+
columnType: "PgJsonb";
|
|
269
|
+
data: {
|
|
270
|
+
kind: "lifecycle";
|
|
271
|
+
label: string;
|
|
272
|
+
detail: string | null;
|
|
273
|
+
meta: readonly {
|
|
274
|
+
label: string;
|
|
275
|
+
value: string;
|
|
276
|
+
inline?: boolean | undefined;
|
|
277
|
+
}[];
|
|
278
|
+
tone: "default" | "error" | "warning";
|
|
279
|
+
terminalFailure: boolean;
|
|
280
|
+
timestamp: number;
|
|
281
|
+
};
|
|
282
|
+
driverParam: unknown;
|
|
283
|
+
notNull: false;
|
|
284
|
+
hasDefault: false;
|
|
285
|
+
isPrimaryKey: false;
|
|
286
|
+
isAutoincrement: false;
|
|
287
|
+
hasRuntimeDefault: false;
|
|
288
|
+
enumValues: undefined;
|
|
289
|
+
baseColumn: never;
|
|
290
|
+
identity: undefined;
|
|
291
|
+
generated: undefined;
|
|
292
|
+
}, {}, {
|
|
293
|
+
$type: {
|
|
294
|
+
kind: "lifecycle";
|
|
295
|
+
label: string;
|
|
296
|
+
detail: string | null;
|
|
297
|
+
meta: readonly {
|
|
298
|
+
label: string;
|
|
299
|
+
value: string;
|
|
300
|
+
inline?: boolean | undefined;
|
|
301
|
+
}[];
|
|
302
|
+
tone: "default" | "error" | "warning";
|
|
303
|
+
terminalFailure: boolean;
|
|
304
|
+
timestamp: number;
|
|
305
|
+
};
|
|
306
|
+
}>;
|
|
213
307
|
truncated: import("drizzle-orm/pg-core").PgColumn<{
|
|
214
308
|
name: "truncated";
|
|
215
309
|
tableName: "attempt_streams";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attempt-streams.d.ts","sourceRoot":"","sources":["../../../src/db/schema/attempt-streams.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"attempt-streams.d.ts","sourceRoot":"","sources":["../../../src/db/schema/attempt-streams.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,kCAAkC,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkD1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AACjE,MAAM,MAAM,qBAAqB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAEvE,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,CAuBnE"}
|