@basou/core 0.23.0 → 0.24.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/dist/index.d.ts +27 -18
- package/dist/index.js +193 -127
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,69 +21,161 @@ function summarizeAdapterOutput(_stream, _raw) {
|
|
|
21
21
|
throw new Error("adapter_output summary is not implemented in this release");
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// src/adapters/claude-code/ask-user-question.ts
|
|
25
|
+
function readString(value) {
|
|
26
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
27
|
+
}
|
|
28
|
+
function isObject(value) {
|
|
29
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
function toolUsesOf(record) {
|
|
32
|
+
const message = isObject(record.message) ? record.message : void 0;
|
|
33
|
+
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
34
|
+
const result = [];
|
|
35
|
+
for (const item of content) {
|
|
36
|
+
if (isObject(item) && readString(item.type) === "tool_use") result.push(item);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function indexAskAnswers(records) {
|
|
41
|
+
const byId = /* @__PURE__ */ new Map();
|
|
42
|
+
for (const record of records) {
|
|
43
|
+
const result = record.toolUseResult;
|
|
44
|
+
if (!isObject(result)) continue;
|
|
45
|
+
const answers = result.answers;
|
|
46
|
+
if (!isObject(answers)) continue;
|
|
47
|
+
const message = isObject(record.message) ? record.message : void 0;
|
|
48
|
+
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
49
|
+
for (const item of content) {
|
|
50
|
+
if (isObject(item) && readString(item.type) === "tool_result") {
|
|
51
|
+
const id = readString(item.tool_use_id);
|
|
52
|
+
if (id !== void 0) byId.set(id, answers);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return byId;
|
|
57
|
+
}
|
|
58
|
+
function readOfferedOptions(input) {
|
|
59
|
+
const byQuestion = /* @__PURE__ */ new Map();
|
|
60
|
+
const questions = Array.isArray(input.questions) ? input.questions : [];
|
|
61
|
+
for (const q of questions) {
|
|
62
|
+
if (!isObject(q)) continue;
|
|
63
|
+
const text = readString(q.question);
|
|
64
|
+
if (text === void 0) continue;
|
|
65
|
+
const labels = /* @__PURE__ */ new Set();
|
|
66
|
+
const options = Array.isArray(q.options) ? q.options : [];
|
|
67
|
+
for (const o of options) {
|
|
68
|
+
if (!isObject(o)) continue;
|
|
69
|
+
const label = readString(o.label);
|
|
70
|
+
if (label !== void 0) labels.add(label.trim());
|
|
71
|
+
}
|
|
72
|
+
byQuestion.set(text, labels);
|
|
73
|
+
}
|
|
74
|
+
return byQuestion;
|
|
75
|
+
}
|
|
76
|
+
function countUncapturedDecisionPoints(records) {
|
|
77
|
+
const answersById = indexAskAnswers(records);
|
|
78
|
+
if (answersById.size === 0) return 0;
|
|
79
|
+
let count = 0;
|
|
80
|
+
for (const record of records) {
|
|
81
|
+
if (readString(record.type) !== "assistant") continue;
|
|
82
|
+
for (const tool of toolUsesOf(record)) {
|
|
83
|
+
if (readString(tool.name) !== "AskUserQuestion") continue;
|
|
84
|
+
const useId = readString(tool.id);
|
|
85
|
+
const answers = useId !== void 0 ? answersById.get(useId) : void 0;
|
|
86
|
+
if (answers === void 0) continue;
|
|
87
|
+
const input = isObject(tool.input) ? tool.input : void 0;
|
|
88
|
+
if (input === void 0) continue;
|
|
89
|
+
const offeredByQuestion = readOfferedOptions(input);
|
|
90
|
+
for (const [question, answer] of Object.entries(answers)) {
|
|
91
|
+
if (question.length === 0) continue;
|
|
92
|
+
const trimmed = typeof answer === "string" ? answer.trim() : "";
|
|
93
|
+
if (trimmed.length === 0) continue;
|
|
94
|
+
const offered = offeredByQuestion.get(question);
|
|
95
|
+
if (offered === void 0 || !offered.has(trimmed)) count += 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return count;
|
|
100
|
+
}
|
|
101
|
+
|
|
24
102
|
// src/adapters/claude-code/stop-hook.ts
|
|
25
|
-
var
|
|
103
|
+
var DEFAULT_STOP_HOOK_MIN_EDITS = 2;
|
|
26
104
|
var CAPTURE_COMMAND_PATTERN = /(?:^|[\n;&|(])\s*basou\s+(?:decision\s+(?:capture|record)|note)\b/;
|
|
27
105
|
var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "NotebookEdit"]);
|
|
28
106
|
function evaluateStopHook(input) {
|
|
29
|
-
const
|
|
107
|
+
const minEdits = input.minEdits ?? DEFAULT_STOP_HOOK_MIN_EDITS;
|
|
30
108
|
if (input.stopHookActive) {
|
|
31
|
-
return {
|
|
109
|
+
return {
|
|
110
|
+
kind: "silent",
|
|
111
|
+
reason: "stop_hook_active",
|
|
112
|
+
commandCount: 0,
|
|
113
|
+
fileCount: 0,
|
|
114
|
+
decisionPointCount: 0
|
|
115
|
+
};
|
|
32
116
|
}
|
|
33
117
|
let commandCount = 0;
|
|
34
118
|
let fileCount = 0;
|
|
35
119
|
let captured = false;
|
|
36
120
|
for (const record of input.records) {
|
|
37
|
-
if (
|
|
38
|
-
for (const tool of
|
|
39
|
-
const name =
|
|
121
|
+
if (readString2(record.type) !== "assistant") continue;
|
|
122
|
+
for (const tool of toolUsesOf2(record)) {
|
|
123
|
+
const name = readString2(tool.name);
|
|
40
124
|
if (name === void 0) continue;
|
|
41
125
|
if (name === "Bash") {
|
|
42
126
|
commandCount += 1;
|
|
43
|
-
const
|
|
44
|
-
const command =
|
|
127
|
+
const toolInput = isObject2(tool.input) ? tool.input : void 0;
|
|
128
|
+
const command = toolInput !== void 0 ? readString2(toolInput.command) : void 0;
|
|
45
129
|
if (command !== void 0 && CAPTURE_COMMAND_PATTERN.test(command)) captured = true;
|
|
46
130
|
} else if (FILE_EDIT_TOOLS.has(name)) {
|
|
47
131
|
fileCount += 1;
|
|
48
132
|
}
|
|
49
133
|
}
|
|
50
134
|
}
|
|
135
|
+
const decisionPointCount = countUncapturedDecisionPoints(input.records);
|
|
136
|
+
const counts = { commandCount, fileCount, decisionPointCount };
|
|
51
137
|
if (captured) {
|
|
52
|
-
return { kind: "silent", reason: "already_captured",
|
|
138
|
+
return { kind: "silent", reason: "already_captured", ...counts };
|
|
53
139
|
}
|
|
54
|
-
|
|
55
|
-
|
|
140
|
+
const substantive = fileCount >= minEdits || decisionPointCount > 0;
|
|
141
|
+
if (!substantive) {
|
|
142
|
+
return { kind: "silent", reason: "not_substantive", ...counts };
|
|
56
143
|
}
|
|
57
|
-
return {
|
|
58
|
-
kind: "nudge",
|
|
59
|
-
additionalContext: renderNudge(commandCount, fileCount),
|
|
60
|
-
commandCount,
|
|
61
|
-
fileCount
|
|
62
|
-
};
|
|
144
|
+
return { kind: "nudge", additionalContext: renderNudge(counts), ...counts };
|
|
63
145
|
}
|
|
64
|
-
function renderNudge(
|
|
65
|
-
const
|
|
66
|
-
|
|
146
|
+
function renderNudge(counts) {
|
|
147
|
+
const did = [];
|
|
148
|
+
if (counts.commandCount > 0) {
|
|
149
|
+
did.push(`ran ${counts.commandCount} ${counts.commandCount === 1 ? "command" : "commands"}`);
|
|
150
|
+
}
|
|
151
|
+
if (counts.fileCount > 0) {
|
|
152
|
+
did.push(`edited ${counts.fileCount} ${counts.fileCount === 1 ? "file" : "files"}`);
|
|
153
|
+
}
|
|
154
|
+
if (counts.decisionPointCount > 0) {
|
|
155
|
+
const n = counts.decisionPointCount;
|
|
156
|
+
did.push(`answered ${n} open-ended ${n === 1 ? "question" : "questions"}`);
|
|
157
|
+
}
|
|
158
|
+
const summary = did.length > 0 ? did.join(", ") : "did substantive work";
|
|
67
159
|
return [
|
|
68
|
-
`This session
|
|
160
|
+
`This session ${summary} but recorded no decisions or next step.`,
|
|
69
161
|
"If meaningful decisions were made (the chosen approach, rejected alternatives, and why) or there is a clear next step, capture them now so the next session can resume correctly:",
|
|
70
162
|
' - Decisions: run `basou decision capture` and pipe a JSON array (one object per decision; "title" required, plus optional rationale/alternatives/rejected_reason/linked_files; set "kind":"track" for an unfinished strategic direction).',
|
|
71
163
|
' - Next step: run `basou note "<what you would do next>"`.',
|
|
72
164
|
"If nothing is worth capturing, just stop \u2014 do not invent decisions."
|
|
73
165
|
].join("\n");
|
|
74
166
|
}
|
|
75
|
-
function
|
|
167
|
+
function readString2(value) {
|
|
76
168
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
77
169
|
}
|
|
78
|
-
function
|
|
170
|
+
function isObject2(value) {
|
|
79
171
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
80
172
|
}
|
|
81
|
-
function
|
|
82
|
-
const message =
|
|
173
|
+
function toolUsesOf2(record) {
|
|
174
|
+
const message = isObject2(record.message) ? record.message : void 0;
|
|
83
175
|
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
84
176
|
const result = [];
|
|
85
177
|
for (const item of content) {
|
|
86
|
-
if (
|
|
178
|
+
if (isObject2(item) && readString2(item.type) === "tool_use") result.push(item);
|
|
87
179
|
}
|
|
88
180
|
return result;
|
|
89
181
|
}
|
|
@@ -195,21 +287,21 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
195
287
|
const engagementTsMs = [];
|
|
196
288
|
const seenEngagementMessageIds = /* @__PURE__ */ new Set();
|
|
197
289
|
for (const record of records) {
|
|
198
|
-
const ts =
|
|
290
|
+
const ts = readString3(record.timestamp);
|
|
199
291
|
if (ts === void 0) continue;
|
|
200
292
|
if (minTs === void 0 || Date.parse(ts) < Date.parse(minTs)) minTs = ts;
|
|
201
293
|
if (maxTs === void 0 || Date.parse(ts) > Date.parse(maxTs)) maxTs = ts;
|
|
202
|
-
if (workingDir === void 0) workingDir =
|
|
203
|
-
if (claudeSessionId === void 0) claudeSessionId =
|
|
294
|
+
if (workingDir === void 0) workingDir = readString3(record.cwd);
|
|
295
|
+
if (claudeSessionId === void 0) claudeSessionId = readString3(record.sessionId);
|
|
204
296
|
if (record.isSidechain !== true) {
|
|
205
297
|
const tsMs = Date.parse(ts);
|
|
206
298
|
if (Number.isFinite(tsMs)) {
|
|
207
|
-
const recType =
|
|
299
|
+
const recType = readString3(record.type);
|
|
208
300
|
if (recType === "user") {
|
|
209
301
|
if (isHumanUserMessage(record)) engagementTsMs.push(tsMs);
|
|
210
302
|
} else if (recType === "assistant") {
|
|
211
|
-
const msg =
|
|
212
|
-
const mid = msg !== void 0 ?
|
|
303
|
+
const msg = isObject3(record.message) ? record.message : void 0;
|
|
304
|
+
const mid = msg !== void 0 ? readString3(msg.id) : void 0;
|
|
213
305
|
if (mid === void 0 || !seenEngagementMessageIds.has(mid)) {
|
|
214
306
|
if (mid !== void 0) seenEngagementMessageIds.add(mid);
|
|
215
307
|
engagementTsMs.push(tsMs);
|
|
@@ -217,11 +309,11 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
217
309
|
}
|
|
218
310
|
}
|
|
219
311
|
}
|
|
220
|
-
if (
|
|
221
|
-
const message =
|
|
222
|
-
const usage = message !== void 0 &&
|
|
312
|
+
if (readString3(record.type) !== "assistant") continue;
|
|
313
|
+
const message = isObject3(record.message) ? record.message : void 0;
|
|
314
|
+
const usage = message !== void 0 && isObject3(message.usage) ? message.usage : void 0;
|
|
223
315
|
if (usage !== void 0) {
|
|
224
|
-
const messageId = message !== void 0 ?
|
|
316
|
+
const messageId = message !== void 0 ? readString3(message.id) : void 0;
|
|
225
317
|
const alreadyCounted = messageId !== void 0 && seenMessageIds.has(messageId);
|
|
226
318
|
if (!alreadyCounted) {
|
|
227
319
|
if (messageId !== void 0) seenMessageIds.add(messageId);
|
|
@@ -230,20 +322,20 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
230
322
|
cachedInputTokens += readNonNegInt(usage.cache_read_input_tokens);
|
|
231
323
|
}
|
|
232
324
|
}
|
|
233
|
-
const cwd =
|
|
325
|
+
const cwd = readString3(record.cwd) ?? workingDir ?? ".";
|
|
234
326
|
for (const item of toolUses(record)) {
|
|
235
|
-
const name =
|
|
236
|
-
const input =
|
|
327
|
+
const name = readString3(item.name);
|
|
328
|
+
const input = isObject3(item.input) ? item.input : void 0;
|
|
237
329
|
if (input === void 0) continue;
|
|
238
330
|
if (name === "Bash") {
|
|
239
|
-
const command =
|
|
331
|
+
const command = readString3(input.command);
|
|
240
332
|
if (command !== void 0) {
|
|
241
333
|
derived.push(commandExecutedEvent(ts, placeholderSessionId, command, cwd));
|
|
242
334
|
}
|
|
243
335
|
continue;
|
|
244
336
|
}
|
|
245
337
|
if (name === "AskUserQuestion") {
|
|
246
|
-
const useId =
|
|
338
|
+
const useId = readString3(item.id);
|
|
247
339
|
const answers = useId !== void 0 ? askAnswers.get(useId) : void 0;
|
|
248
340
|
if (answers !== void 0) {
|
|
249
341
|
const offeredByQuestion = readOfferedOptions(input);
|
|
@@ -261,7 +353,7 @@ function claudeTranscriptToImportPayload(records, options) {
|
|
|
261
353
|
continue;
|
|
262
354
|
}
|
|
263
355
|
if (name === "Edit" || name === "Write" || name === "NotebookEdit") {
|
|
264
|
-
const path2 =
|
|
356
|
+
const path2 = readString3(input.file_path) ?? readString3(input.notebook_path);
|
|
265
357
|
if (path2 !== void 0) {
|
|
266
358
|
const changeType = name === "Write" ? "added" : "modified";
|
|
267
359
|
relatedFiles.add(path2);
|
|
@@ -363,76 +455,40 @@ function decisionRecordedEvent(occurredAt, sessionId, title) {
|
|
|
363
455
|
title
|
|
364
456
|
};
|
|
365
457
|
}
|
|
366
|
-
function
|
|
458
|
+
function readString3(value) {
|
|
367
459
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
368
460
|
}
|
|
369
461
|
function readNonNegInt(value) {
|
|
370
462
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
371
463
|
}
|
|
372
|
-
function
|
|
464
|
+
function isObject3(value) {
|
|
373
465
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
374
466
|
}
|
|
375
467
|
function isHumanUserMessage(record) {
|
|
376
|
-
const message =
|
|
468
|
+
const message = isObject3(record.message) ? record.message : void 0;
|
|
377
469
|
if (message === void 0) return false;
|
|
378
470
|
const content = message.content;
|
|
379
471
|
if (typeof content === "string") return content.length > 0;
|
|
380
472
|
if (Array.isArray(content)) {
|
|
381
473
|
return content.some((block) => {
|
|
382
|
-
if (!
|
|
383
|
-
const type =
|
|
474
|
+
if (!isObject3(block)) return false;
|
|
475
|
+
const type = readString3(block.type);
|
|
384
476
|
return type !== void 0 && type !== "tool_result";
|
|
385
477
|
});
|
|
386
478
|
}
|
|
387
479
|
return false;
|
|
388
480
|
}
|
|
389
481
|
function toolUses(record) {
|
|
390
|
-
const message =
|
|
482
|
+
const message = isObject3(record.message) ? record.message : void 0;
|
|
391
483
|
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
392
484
|
const result = [];
|
|
393
485
|
for (const item of content) {
|
|
394
|
-
if (
|
|
486
|
+
if (isObject3(item) && readString3(item.type) === "tool_use") {
|
|
395
487
|
result.push(item);
|
|
396
488
|
}
|
|
397
489
|
}
|
|
398
490
|
return result;
|
|
399
491
|
}
|
|
400
|
-
function indexAskAnswers(records) {
|
|
401
|
-
const byId = /* @__PURE__ */ new Map();
|
|
402
|
-
for (const record of records) {
|
|
403
|
-
const result = record.toolUseResult;
|
|
404
|
-
if (!isObject2(result)) continue;
|
|
405
|
-
const answers = result.answers;
|
|
406
|
-
if (!isObject2(answers)) continue;
|
|
407
|
-
const message = isObject2(record.message) ? record.message : void 0;
|
|
408
|
-
const content = message !== void 0 && Array.isArray(message.content) ? message.content : [];
|
|
409
|
-
for (const item of content) {
|
|
410
|
-
if (isObject2(item) && readString2(item.type) === "tool_result") {
|
|
411
|
-
const id = readString2(item.tool_use_id);
|
|
412
|
-
if (id !== void 0) byId.set(id, answers);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
return byId;
|
|
417
|
-
}
|
|
418
|
-
function readOfferedOptions(input) {
|
|
419
|
-
const byQuestion = /* @__PURE__ */ new Map();
|
|
420
|
-
const questions = Array.isArray(input.questions) ? input.questions : [];
|
|
421
|
-
for (const q of questions) {
|
|
422
|
-
if (!isObject2(q)) continue;
|
|
423
|
-
const text = readString2(q.question);
|
|
424
|
-
if (text === void 0) continue;
|
|
425
|
-
const labels = /* @__PURE__ */ new Set();
|
|
426
|
-
const options = Array.isArray(q.options) ? q.options : [];
|
|
427
|
-
for (const o of options) {
|
|
428
|
-
if (!isObject2(o)) continue;
|
|
429
|
-
const label = readString2(o.label);
|
|
430
|
-
if (label !== void 0) labels.add(label.trim());
|
|
431
|
-
}
|
|
432
|
-
byQuestion.set(text, labels);
|
|
433
|
-
}
|
|
434
|
-
return byQuestion;
|
|
435
|
-
}
|
|
436
492
|
|
|
437
493
|
// src/adapters/codex/rollout-importer.ts
|
|
438
494
|
var CODEX_IMPORT_SOURCE = "codex-import";
|
|
@@ -450,31 +506,31 @@ function codexRolloutToImportPayload(records, options) {
|
|
|
450
506
|
const completions = [];
|
|
451
507
|
const completedTurnIds = /* @__PURE__ */ new Set();
|
|
452
508
|
for (const record of records) {
|
|
453
|
-
const ts =
|
|
509
|
+
const ts = readString4(record.timestamp);
|
|
454
510
|
if (ts === void 0) continue;
|
|
455
511
|
if (minTs === void 0 || Date.parse(ts) < Date.parse(minTs)) minTs = ts;
|
|
456
512
|
if (maxTs === void 0 || Date.parse(ts) > Date.parse(maxTs)) maxTs = ts;
|
|
457
|
-
const payload2 =
|
|
513
|
+
const payload2 = isObject4(record.payload) ? record.payload : void 0;
|
|
458
514
|
if (payload2 === void 0) continue;
|
|
459
|
-
if (
|
|
460
|
-
if (workingDir === void 0) workingDir =
|
|
461
|
-
if (codexSessionId === void 0) codexSessionId =
|
|
515
|
+
if (readString4(record.type) === "session_meta") {
|
|
516
|
+
if (workingDir === void 0) workingDir = readString4(payload2.cwd);
|
|
517
|
+
if (codexSessionId === void 0) codexSessionId = readString4(payload2.id);
|
|
462
518
|
continue;
|
|
463
519
|
}
|
|
464
|
-
if (
|
|
465
|
-
const info =
|
|
466
|
-
const totals = info !== void 0 &&
|
|
520
|
+
if (readString4(record.type) === "event_msg" && readString4(payload2.type) === "token_count") {
|
|
521
|
+
const info = isObject4(payload2.info) ? payload2.info : void 0;
|
|
522
|
+
const totals = info !== void 0 && isObject4(info.total_token_usage) ? info.total_token_usage : void 0;
|
|
467
523
|
if (totals !== void 0) lastTokenTotals = totals;
|
|
468
524
|
continue;
|
|
469
525
|
}
|
|
470
|
-
if (
|
|
471
|
-
const pt =
|
|
526
|
+
if (readString4(record.type) === "event_msg") {
|
|
527
|
+
const pt = readString4(payload2.type);
|
|
472
528
|
if (pt === "user_message" || pt === "agent_message" || pt === "task_started" || pt === "task_complete") {
|
|
473
529
|
const tsMs = Date.parse(ts);
|
|
474
530
|
if (Number.isFinite(tsMs)) engagementTsMs.push(tsMs);
|
|
475
531
|
}
|
|
476
532
|
if (pt === "task_complete") {
|
|
477
|
-
const turnId =
|
|
533
|
+
const turnId = readString4(payload2.turn_id);
|
|
478
534
|
if (turnId === void 0 || !completedTurnIds.has(turnId)) {
|
|
479
535
|
if (turnId !== void 0) completedTurnIds.add(turnId);
|
|
480
536
|
completions.push({
|
|
@@ -485,9 +541,9 @@ function codexRolloutToImportPayload(records, options) {
|
|
|
485
541
|
}
|
|
486
542
|
continue;
|
|
487
543
|
}
|
|
488
|
-
if (
|
|
489
|
-
if (
|
|
490
|
-
if (
|
|
544
|
+
if (readString4(record.type) !== "response_item") continue;
|
|
545
|
+
if (readString4(payload2.type) !== "function_call") continue;
|
|
546
|
+
if (readString4(payload2.name) !== "exec_command") continue;
|
|
491
547
|
const command = readExecCommand(payload2.arguments);
|
|
492
548
|
if (command === void 0) continue;
|
|
493
549
|
const cwd = command.workdir ?? workingDir ?? ".";
|
|
@@ -598,17 +654,17 @@ function commandExecutedEvent2(occurredAt, sessionId, command, cwd, outcome) {
|
|
|
598
654
|
duration_ms: outcome.durationMs
|
|
599
655
|
};
|
|
600
656
|
}
|
|
601
|
-
function
|
|
657
|
+
function readString4(value) {
|
|
602
658
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
603
659
|
}
|
|
604
660
|
function readNonNegInt2(value) {
|
|
605
661
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
606
662
|
}
|
|
607
|
-
function
|
|
663
|
+
function isObject4(value) {
|
|
608
664
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
609
665
|
}
|
|
610
666
|
function readExecCommand(value) {
|
|
611
|
-
const raw =
|
|
667
|
+
const raw = readString4(value);
|
|
612
668
|
if (raw === void 0) return void 0;
|
|
613
669
|
let parsed;
|
|
614
670
|
try {
|
|
@@ -616,19 +672,19 @@ function readExecCommand(value) {
|
|
|
616
672
|
} catch {
|
|
617
673
|
return void 0;
|
|
618
674
|
}
|
|
619
|
-
if (!
|
|
620
|
-
const cmd =
|
|
675
|
+
if (!isObject4(parsed)) return void 0;
|
|
676
|
+
const cmd = readString4(parsed.cmd);
|
|
621
677
|
if (cmd === void 0) return void 0;
|
|
622
|
-
return { cmd, workdir:
|
|
678
|
+
return { cmd, workdir: readString4(parsed.workdir) };
|
|
623
679
|
}
|
|
624
680
|
function readCallId(value, outputs) {
|
|
625
|
-
const callId =
|
|
681
|
+
const callId = readString4(value);
|
|
626
682
|
return callId !== void 0 ? outputs.get(callId) : void 0;
|
|
627
683
|
}
|
|
628
684
|
function turnIntervalFromComplete(endTs, payload, startMsByTurnId) {
|
|
629
685
|
const endMs = Date.parse(endTs);
|
|
630
686
|
if (!Number.isFinite(endMs)) return void 0;
|
|
631
|
-
const turnId =
|
|
687
|
+
const turnId = readString4(payload.turn_id);
|
|
632
688
|
const indexedStart = turnId !== void 0 ? startMsByTurnId.get(turnId) : void 0;
|
|
633
689
|
const durationMs = readNonNegInt2(payload.duration_ms);
|
|
634
690
|
const startMs = indexedStart !== void 0 ? indexedStart : durationMs > 0 ? endMs - durationMs : void 0;
|
|
@@ -638,11 +694,11 @@ function turnIntervalFromComplete(endTs, payload, startMsByTurnId) {
|
|
|
638
694
|
function indexTaskStarts(records) {
|
|
639
695
|
const byTurnId = /* @__PURE__ */ new Map();
|
|
640
696
|
for (const record of records) {
|
|
641
|
-
if (
|
|
642
|
-
const payload =
|
|
643
|
-
if (payload === void 0 ||
|
|
644
|
-
const turnId =
|
|
645
|
-
const startMs = Date.parse(
|
|
697
|
+
if (readString4(record.type) !== "event_msg") continue;
|
|
698
|
+
const payload = isObject4(record.payload) ? record.payload : void 0;
|
|
699
|
+
if (payload === void 0 || readString4(payload.type) !== "task_started") continue;
|
|
700
|
+
const turnId = readString4(payload.turn_id);
|
|
701
|
+
const startMs = Date.parse(readString4(record.timestamp) ?? "");
|
|
646
702
|
if (turnId !== void 0 && Number.isFinite(startMs) && !byTurnId.has(turnId)) {
|
|
647
703
|
byTurnId.set(turnId, startMs);
|
|
648
704
|
}
|
|
@@ -664,12 +720,12 @@ function parseWallTimeMs(output) {
|
|
|
664
720
|
function indexOutputs(records) {
|
|
665
721
|
const byId = /* @__PURE__ */ new Map();
|
|
666
722
|
for (const record of records) {
|
|
667
|
-
if (
|
|
668
|
-
const payload =
|
|
723
|
+
if (readString4(record.type) !== "response_item") continue;
|
|
724
|
+
const payload = isObject4(record.payload) ? record.payload : void 0;
|
|
669
725
|
if (payload === void 0) continue;
|
|
670
|
-
if (
|
|
671
|
-
const callId =
|
|
672
|
-
const output =
|
|
726
|
+
if (readString4(payload.type) !== "function_call_output") continue;
|
|
727
|
+
const callId = readString4(payload.call_id);
|
|
728
|
+
const output = readString4(payload.output);
|
|
673
729
|
if (callId !== void 0 && output !== void 0) byId.set(callId, output);
|
|
674
730
|
}
|
|
675
731
|
return byId;
|
|
@@ -5120,12 +5176,11 @@ function stalenessBanner(staleness) {
|
|
|
5120
5176
|
if (staleness === null) return [];
|
|
5121
5177
|
if ((staleness.unverifiableSessions ?? 0) > 0) {
|
|
5122
5178
|
return [
|
|
5123
|
-
`> \u26A0\uFE0F **\
|
|
5179
|
+
`> \u26A0\uFE0F **\u518D\u53D6\u308A\u8FBC\u307F\u304C\u5FC5\u8981** \u2014 native \u30ED\u30B0\u304C\u5909\u5316\u3057\u305F\u304C\u901A\u5E38\u306E refresh \u3067\u306F\u53D6\u308A\u8FBC\u3081\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.unverifiableSessions} \u4EF6\u3042\u308A\u307E\u3059\u3002\`basou refresh --force\` \u3067\u518D\u53D6\u308A\u8FBC\u307F\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`
|
|
5124
5180
|
];
|
|
5125
5181
|
}
|
|
5126
|
-
if (staleness.newSessions > 0
|
|
5127
|
-
const parts = [];
|
|
5128
|
-
if (staleness.newSessions > 0) parts.push(`\u65B0\u898F ${staleness.newSessions} \u4EF6`);
|
|
5182
|
+
if (staleness.newSessions > 0) {
|
|
5183
|
+
const parts = [`\u65B0\u898F ${staleness.newSessions} \u4EF6`];
|
|
5129
5184
|
if (staleness.updatedSessions > 0) parts.push(`\u66F4\u65B0 ${staleness.updatedSessions} \u4EF6`);
|
|
5130
5185
|
return [
|
|
5131
5186
|
`> \u26A0\uFE0F **\u53E4\u3044\u3067\u3059\uFF08\u672A\u53D6\u308A\u8FBC\u307F ${parts.join("\u30FB")}\uFF09** \u2014 \u7740\u624B\u524D\u306B\u5FC5\u305A \`basou refresh\` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`
|
|
@@ -5136,19 +5191,30 @@ function stalenessBanner(staleness) {
|
|
|
5136
5191
|
function freshnessVerdict(summary, staleness, now) {
|
|
5137
5192
|
if (staleness !== null && (staleness.unverifiableSessions ?? 0) > 0) {
|
|
5138
5193
|
return [
|
|
5139
|
-
`\u26A0\uFE0F \
|
|
5140
|
-
"`basou
|
|
5194
|
+
`\u26A0\uFE0F native \u30ED\u30B0\u304C\u5909\u5316\u3057\u307E\u3057\u305F\u304C\u3001\u901A\u5E38\u306E \`basou refresh\` \u3067\u306F\u5B89\u5168\u306B\u518D\u53D6\u308A\u8FBC\u307F\u3067\u304D\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.unverifiableSessions} \u4EF6\u3042\u308A\u307E\u3059(\u975E\u8FFD\u8A18\u5909\u66F4\u30FB\u524D\u30C1\u30A7\u30FC\u30F3\u4E0D\u6574\u5408\u306A\u3069)\u3002`,
|
|
5195
|
+
"`basou refresh --force` \u3067\u518D\u53D6\u308A\u8FBC\u307F\u3057\u3066\u304F\u3060\u3055\u3044\u3002(`basou verify` \u306F\u5225\u7269=\u53D6\u308A\u8FBC\u307F\u6E08\u307F\u30C7\u30FC\u30BF\u306E\u6539\u7AC4/\u7834\u640D\u691C\u67FB\u3067\u3001\u30D8\u30C3\u30C0\u306E suspect \u3068\u306F\u5225\u8EF8\u3067\u3059\u3002verify \u304C clean \u3067\u3082\u672A\u53D6\u308A\u8FBC\u307F\u306F\u6B8B\u308A\u5F97\u307E\u3059\u3002)"
|
|
5141
5196
|
];
|
|
5142
5197
|
}
|
|
5143
|
-
if (staleness !== null &&
|
|
5144
|
-
const parts = [];
|
|
5145
|
-
if (staleness.newSessions > 0) parts.push(`\u65B0\u898F ${staleness.newSessions} \u4EF6`);
|
|
5198
|
+
if (staleness !== null && staleness.newSessions > 0) {
|
|
5199
|
+
const parts = [`\u65B0\u898F ${staleness.newSessions} \u4EF6`];
|
|
5146
5200
|
if (staleness.updatedSessions > 0) parts.push(`\u66F4\u65B0 ${staleness.updatedSessions} \u4EF6`);
|
|
5147
5201
|
return [
|
|
5148
5202
|
`\u26A0\uFE0F \u53E4\u3044\u3067\u3059\u3002\u6700\u5F8C\u306E\u53D6\u308A\u8FBC\u307F\u4EE5\u964D\u306B\u672A\u53D6\u308A\u8FBC\u307F\u306E\u4F5C\u696D\u304C\u3042\u308A\u307E\u3059(${parts.join("\u30FB")})\u3002`,
|
|
5149
5203
|
"\u7740\u624B\u524D\u306B\u5FC5\u305A `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
5150
5204
|
];
|
|
5151
5205
|
}
|
|
5206
|
+
if (staleness !== null && staleness.updatedSessions > 0) {
|
|
5207
|
+
const lines2 = [
|
|
5208
|
+
`\u26A0\uFE0F \u66F4\u65B0\u3055\u308C\u305F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.updatedSessions} \u4EF6\u3042\u308A\u307E\u3059\u3002\`basou refresh\` \u3067\u53D6\u308A\u8FBC\u3081\u307E\u3059\u3002`,
|
|
5209
|
+
"(\u9032\u884C\u4E2D\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u3042\u308B\u5834\u5408\u3001\u305D\u308C\u81EA\u8EAB\u306F\u53D6\u308A\u8FBC\u307F\u5F8C\u3082\u5897\u3048\u7D9A\u3051\u308B\u305F\u3081\u6B8B\u308A\u307E\u3059\uFF1D\u6B63\u5E38\u3067\u3059\u3002)"
|
|
5210
|
+
];
|
|
5211
|
+
if (summary.suspects.length > 0) {
|
|
5212
|
+
lines2.push(
|
|
5213
|
+
`\u307E\u305F\u8981\u6CE8\u610F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${summary.suspects.length} \u4EF6\u3042\u308A\u307E\u3059(\u4E0A\u8A18\u300C\u8981\u6CE8\u610F session\u300D\u53C2\u7167)\u3002`
|
|
5214
|
+
);
|
|
5215
|
+
}
|
|
5216
|
+
return lines2;
|
|
5217
|
+
}
|
|
5152
5218
|
if (summary.freshness.newestStartedAt === null) {
|
|
5153
5219
|
return [
|
|
5154
5220
|
"\u2139\uFE0F \u307E\u3060\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
@@ -7529,7 +7595,7 @@ export {
|
|
|
7529
7595
|
CLAUDE_IMPORT_SOURCE,
|
|
7530
7596
|
CODEX_IMPORT_SOURCE,
|
|
7531
7597
|
ChildProcessRunner,
|
|
7532
|
-
|
|
7598
|
+
DEFAULT_STOP_HOOK_MIN_EDITS,
|
|
7533
7599
|
DecisionIdSchema,
|
|
7534
7600
|
EventIdSchema,
|
|
7535
7601
|
EventSchema,
|