@bububuger/spanory 0.1.14

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.
@@ -0,0 +1,242 @@
1
+ // @ts-nocheck
2
+ import { readFile, stat } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { RUNTIME_CAPABILITIES } from '../shared/capabilities.js';
5
+ import { normalizeTranscriptMessages, parseProjectIdFromTranscriptPath, pickUsage } from '../shared/normalize.js';
6
+ function parseTimestamp(entry) {
7
+ const raw = entry?.timestamp ?? entry?.created_at ?? entry?.createdAt;
8
+ const date = raw ? new Date(raw) : new Date();
9
+ if (Number.isNaN(date.getTime()))
10
+ return new Date();
11
+ return date;
12
+ }
13
+ function normalizeToolName(name) {
14
+ if (name === 'exec')
15
+ return 'Bash';
16
+ return name;
17
+ }
18
+ function normalizeContentBlocks(content) {
19
+ if (typeof content === 'string')
20
+ return content;
21
+ if (!Array.isArray(content))
22
+ return '';
23
+ const blocks = [];
24
+ for (const block of content) {
25
+ if (typeof block === 'string') {
26
+ blocks.push(block);
27
+ continue;
28
+ }
29
+ if (!block || typeof block !== 'object')
30
+ continue;
31
+ if (block.type === 'text') {
32
+ blocks.push({ type: 'text', text: block.text ?? '' });
33
+ continue;
34
+ }
35
+ if (block.type === 'toolCall') {
36
+ blocks.push({
37
+ type: 'tool_use',
38
+ id: block.id ?? block.toolCallId ?? '',
39
+ name: normalizeToolName(block.name ?? block.toolName ?? ''),
40
+ input: block.arguments ?? block.input ?? {},
41
+ });
42
+ continue;
43
+ }
44
+ if (block.type === 'toolResult') {
45
+ blocks.push({
46
+ type: 'tool_result',
47
+ tool_use_id: block.toolCallId ?? block.tool_call_id ?? block.id ?? '',
48
+ content: block.content ?? '',
49
+ });
50
+ continue;
51
+ }
52
+ if (block.type === 'tool_use' || block.type === 'tool_result') {
53
+ blocks.push(block);
54
+ continue;
55
+ }
56
+ }
57
+ return blocks;
58
+ }
59
+ function normalizeRole(entry) {
60
+ if (entry?.type === 'message') {
61
+ const role = entry?.message?.role;
62
+ if (role === 'toolResult')
63
+ return 'user';
64
+ if (role)
65
+ return role;
66
+ return null;
67
+ }
68
+ if (entry?.role)
69
+ return entry.role;
70
+ if (entry?.message?.role)
71
+ return entry.message.role;
72
+ if (entry?.payload?.role)
73
+ return entry.payload.role;
74
+ if (entry?.type === 'user' || entry?.type === 'assistant' || entry?.type === 'system')
75
+ return entry.type;
76
+ return null;
77
+ }
78
+ function normalizeContent(entry) {
79
+ if (entry?.type === 'message') {
80
+ const role = entry?.message?.role;
81
+ if (role === 'toolResult') {
82
+ return [
83
+ {
84
+ type: 'tool_result',
85
+ tool_use_id: entry?.message?.toolCallId ?? entry?.message?.tool_call_id ?? '',
86
+ content: entry?.message?.content ?? '',
87
+ },
88
+ ];
89
+ }
90
+ return normalizeContentBlocks(entry?.message?.content ?? '');
91
+ }
92
+ return normalizeContentBlocks(entry?.message?.content ?? entry?.content ?? entry?.payload?.content ?? '');
93
+ }
94
+ function normalizeModel(entry) {
95
+ return entry?.message?.model ?? entry?.model ?? entry?.payload?.model;
96
+ }
97
+ function normalizeMessageId(entry) {
98
+ return entry?.message?.id ?? entry?.messageId ?? entry?.message_id ?? entry?.id;
99
+ }
100
+ function normalizeToolUseResult(entry) {
101
+ return entry?.toolUseResult ?? entry?.tool_use_result ?? entry?.tool_result;
102
+ }
103
+ function normalizeSourceToolUseId(entry) {
104
+ return (entry?.sourceToolUseID
105
+ ?? entry?.sourceToolUseId
106
+ ?? entry?.source_tool_use_id
107
+ ?? entry?.message?.toolCallId
108
+ ?? entry?.message?.tool_call_id);
109
+ }
110
+ function normalizeUsage(entry) {
111
+ const raw = entry?.message?.usage
112
+ ?? entry?.usage
113
+ ?? entry?.message_usage
114
+ ?? entry?.token_usage
115
+ ?? entry?.payload?.usage;
116
+ if (!raw || typeof raw !== 'object')
117
+ return undefined;
118
+ return pickUsage({
119
+ input_tokens: raw.input_tokens ?? raw.prompt_tokens ?? raw.input,
120
+ output_tokens: raw.output_tokens ?? raw.completion_tokens ?? raw.output,
121
+ total_tokens: raw.total_tokens ?? raw.totalTokens,
122
+ cache_read_input_tokens: raw.cache_read_input_tokens ?? raw.cacheRead,
123
+ cache_creation_input_tokens: raw.cache_creation_input_tokens ?? raw.cacheWrite,
124
+ });
125
+ }
126
+ function normalizeIsSidechain(entry) {
127
+ const raw = entry?.isSidechain
128
+ ?? entry?.is_sidechain
129
+ ?? entry?.message?.isSidechain
130
+ ?? entry?.message?.is_sidechain
131
+ ?? entry?.payload?.isSidechain
132
+ ?? entry?.payload?.is_sidechain;
133
+ return raw === true;
134
+ }
135
+ function normalizeAgentId(entry) {
136
+ return (entry?.agentId
137
+ ?? entry?.agent_id
138
+ ?? entry?.message?.agentId
139
+ ?? entry?.message?.agent_id
140
+ ?? entry?.payload?.agentId
141
+ ?? entry?.payload?.agent_id);
142
+ }
143
+ async function readOpenclawTranscript(transcriptPath) {
144
+ const raw = await readFile(transcriptPath, 'utf-8');
145
+ const lines = raw.split('\n').map((line) => line.trim()).filter(Boolean);
146
+ const messages = [];
147
+ let runtimeVersion;
148
+ for (const line of lines) {
149
+ try {
150
+ const entry = JSON.parse(line);
151
+ if (entry?.type === 'session') {
152
+ runtimeVersion = entry?.runtimeVersion
153
+ ?? entry?.runtime_version
154
+ ?? entry?.openclawVersion
155
+ ?? entry?.openclaw_version
156
+ ?? entry?.version
157
+ ?? runtimeVersion;
158
+ continue;
159
+ }
160
+ const role = normalizeRole(entry);
161
+ if (!role)
162
+ continue;
163
+ messages.push({
164
+ role,
165
+ isMeta: entry?.isMeta ?? entry?.is_meta ?? false,
166
+ isSidechain: normalizeIsSidechain(entry),
167
+ agentId: normalizeAgentId(entry),
168
+ content: normalizeContent(entry),
169
+ model: normalizeModel(entry),
170
+ usage: normalizeUsage(entry),
171
+ messageId: normalizeMessageId(entry),
172
+ toolUseResult: normalizeToolUseResult(entry),
173
+ sourceToolUseId: normalizeSourceToolUseId(entry),
174
+ runtimeVersion: entry?.runtimeVersion
175
+ ?? entry?.runtime_version
176
+ ?? entry?.version
177
+ ?? entry?.app_version
178
+ ?? entry?.appVersion
179
+ ?? runtimeVersion,
180
+ timestamp: parseTimestamp(entry),
181
+ });
182
+ }
183
+ catch {
184
+ // ignore malformed lines
185
+ }
186
+ }
187
+ messages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
188
+ return messages;
189
+ }
190
+ function resolveRuntimeHome(context) {
191
+ return (context.runtimeHome
192
+ ?? process.env.SPANORY_OPENCLOW_HOME
193
+ ?? process.env.SPANORY_OPENCLAW_HOME
194
+ ?? path.join(process.env.HOME || '', '.openclaw'));
195
+ }
196
+ function parseOpenclawProjectId(transcriptPath) {
197
+ return (parseProjectIdFromTranscriptPath(transcriptPath, '/.openclaw/projects/')
198
+ ?? parseProjectIdFromTranscriptPath(transcriptPath, '/.openclaw/agents/'));
199
+ }
200
+ async function resolveTranscriptPath(context) {
201
+ if (context.transcriptPath)
202
+ return context.transcriptPath;
203
+ const runtimeHome = resolveRuntimeHome(context);
204
+ const candidates = [
205
+ path.join(runtimeHome, 'projects', context.projectId, `${context.sessionId}.jsonl`),
206
+ path.join(runtimeHome, 'agents', context.projectId, 'sessions', `${context.sessionId}.jsonl`),
207
+ ];
208
+ for (const p of candidates) {
209
+ try {
210
+ await stat(p);
211
+ return p;
212
+ }
213
+ catch {
214
+ // try next candidate
215
+ }
216
+ }
217
+ return candidates[0];
218
+ }
219
+ export const openclawAdapter = {
220
+ runtimeName: 'openclaw',
221
+ capabilities: RUNTIME_CAPABILITIES.openclaw,
222
+ resolveContextFromHook(payload) {
223
+ const sessionId = payload.sessionId;
224
+ const transcriptPath = payload.transcriptPath;
225
+ if (!sessionId || !transcriptPath)
226
+ return null;
227
+ const projectId = parseOpenclawProjectId(transcriptPath);
228
+ if (!projectId)
229
+ return null;
230
+ return { projectId, sessionId, transcriptPath };
231
+ },
232
+ async collectEvents(context) {
233
+ const transcriptPath = await resolveTranscriptPath(context);
234
+ const messages = await readOpenclawTranscript(transcriptPath);
235
+ return normalizeTranscriptMessages({
236
+ runtime: 'openclaw',
237
+ projectId: context.projectId,
238
+ sessionId: context.sessionId,
239
+ messages,
240
+ });
241
+ },
242
+ };
@@ -0,0 +1,30 @@
1
+ export declare const CAPABILITY_KEYS: string[];
2
+ export declare const RUNTIME_CAPABILITIES: {
3
+ 'claude-code': {
4
+ turnDetection: boolean;
5
+ toolCallAttribution: boolean;
6
+ toolResultCorrelation: boolean;
7
+ modelName: boolean;
8
+ usageDetails: boolean;
9
+ slashCommandExtraction: boolean;
10
+ mcpServerExtraction: boolean;
11
+ };
12
+ openclaw: {
13
+ turnDetection: boolean;
14
+ toolCallAttribution: boolean;
15
+ toolResultCorrelation: boolean;
16
+ modelName: boolean;
17
+ usageDetails: boolean;
18
+ slashCommandExtraction: boolean;
19
+ mcpServerExtraction: boolean;
20
+ };
21
+ codex: {
22
+ turnDetection: boolean;
23
+ toolCallAttribution: boolean;
24
+ toolResultCorrelation: boolean;
25
+ modelName: boolean;
26
+ usageDetails: boolean;
27
+ slashCommandExtraction: boolean;
28
+ mcpServerExtraction: boolean;
29
+ };
30
+ };
@@ -0,0 +1,39 @@
1
+ // @ts-nocheck
2
+ export const CAPABILITY_KEYS = [
3
+ 'turnDetection',
4
+ 'toolCallAttribution',
5
+ 'toolResultCorrelation',
6
+ 'modelName',
7
+ 'usageDetails',
8
+ 'slashCommandExtraction',
9
+ 'mcpServerExtraction',
10
+ ];
11
+ export const RUNTIME_CAPABILITIES = {
12
+ 'claude-code': {
13
+ turnDetection: true,
14
+ toolCallAttribution: true,
15
+ toolResultCorrelation: true,
16
+ modelName: true,
17
+ usageDetails: true,
18
+ slashCommandExtraction: true,
19
+ mcpServerExtraction: true,
20
+ },
21
+ openclaw: {
22
+ turnDetection: true,
23
+ toolCallAttribution: true,
24
+ toolResultCorrelation: true,
25
+ modelName: true,
26
+ usageDetails: true,
27
+ slashCommandExtraction: true,
28
+ mcpServerExtraction: true,
29
+ },
30
+ codex: {
31
+ turnDetection: true,
32
+ toolCallAttribution: true,
33
+ toolResultCorrelation: true,
34
+ modelName: true,
35
+ usageDetails: true,
36
+ slashCommandExtraction: true,
37
+ mcpServerExtraction: true,
38
+ },
39
+ };
@@ -0,0 +1,9 @@
1
+ export declare function pickUsage(raw: any): {};
2
+ export declare function groupByTurns(messages: any): any[];
3
+ export declare function normalizeTranscriptMessages({ runtime, projectId, sessionId, messages }: {
4
+ runtime: any;
5
+ projectId: any;
6
+ sessionId: any;
7
+ messages: any;
8
+ }): any[];
9
+ export declare function parseProjectIdFromTranscriptPath(transcriptPath: any, marker: any): any;