@basou/cli 0.41.0 → 0.42.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.js +107 -43
- package/dist/index.js.map +1 -1
- package/dist/program.js +107 -43
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/program.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
appendChainedEventLocked,
|
|
13
13
|
assertBasouRootSafe,
|
|
14
14
|
basouPaths,
|
|
15
|
+
EVENT_SCHEMA_VERSION,
|
|
15
16
|
enumerateApprovals,
|
|
16
17
|
findErrorCode,
|
|
17
18
|
isLazyExpired,
|
|
@@ -101,6 +102,18 @@ function printReplayWarning(warning, sessionId) {
|
|
|
101
102
|
`Warning: skipped invalid event at line ${warning.line} in ${short}/events.jsonl`
|
|
102
103
|
);
|
|
103
104
|
break;
|
|
105
|
+
case "retired_zero_duration":
|
|
106
|
+
console.error(
|
|
107
|
+
`Warning: kept an event with duration_ms: 0 at line ${warning.line} in ${short}/events.jsonl \u2014 no writer at that schema_version emits one; reading it as unobserved`
|
|
108
|
+
);
|
|
109
|
+
break;
|
|
110
|
+
default: {
|
|
111
|
+
const unhandled = warning;
|
|
112
|
+
console.error(
|
|
113
|
+
`Warning: unhandled replay warning in ${short}/events.jsonl: ${String(unhandled.kind)}`
|
|
114
|
+
);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
104
117
|
}
|
|
105
118
|
}
|
|
106
119
|
function printSessionSkip(sid, reason) {
|
|
@@ -352,7 +365,7 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
352
365
|
if (decision === "approve") {
|
|
353
366
|
const note = options.note ?? null;
|
|
354
367
|
await appendChainedEventLocked(paths, approval.session_id, {
|
|
355
|
-
schema_version:
|
|
368
|
+
schema_version: EVENT_SCHEMA_VERSION,
|
|
356
369
|
id: eventId,
|
|
357
370
|
session_id: approval.session_id,
|
|
358
371
|
occurred_at: occurredAt,
|
|
@@ -365,7 +378,7 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
365
378
|
} else {
|
|
366
379
|
const reason = options.reason;
|
|
367
380
|
await appendChainedEventLocked(paths, approval.session_id, {
|
|
368
|
-
schema_version:
|
|
381
|
+
schema_version: EVENT_SCHEMA_VERSION,
|
|
369
382
|
id: eventId,
|
|
370
383
|
session_id: approval.session_id,
|
|
371
384
|
occurred_at: occurredAt,
|
|
@@ -851,6 +864,7 @@ import {
|
|
|
851
864
|
basouPaths as basouPaths3,
|
|
852
865
|
classifyFilesBySourceRoot,
|
|
853
866
|
createAdHocSessionWithEvent,
|
|
867
|
+
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION2,
|
|
854
868
|
findErrorCode as findErrorCode2,
|
|
855
869
|
isValidPrefixedId,
|
|
856
870
|
loadSessionEntries,
|
|
@@ -1400,7 +1414,7 @@ async function decisionExists(paths, decisionId) {
|
|
|
1400
1414
|
}
|
|
1401
1415
|
function buildDecisionVoidedEvent(input) {
|
|
1402
1416
|
return {
|
|
1403
|
-
schema_version:
|
|
1417
|
+
schema_version: EVENT_SCHEMA_VERSION2,
|
|
1404
1418
|
id: input.eventId,
|
|
1405
1419
|
session_id: input.sessionId,
|
|
1406
1420
|
occurred_at: input.occurredAt,
|
|
@@ -1658,7 +1672,7 @@ function pickRichFields(options) {
|
|
|
1658
1672
|
}
|
|
1659
1673
|
function buildDecisionEvent(input) {
|
|
1660
1674
|
return {
|
|
1661
|
-
schema_version:
|
|
1675
|
+
schema_version: EVENT_SCHEMA_VERSION2,
|
|
1662
1676
|
id: input.eventId,
|
|
1663
1677
|
session_id: input.sessionId,
|
|
1664
1678
|
occurred_at: input.occurredAt,
|
|
@@ -1855,6 +1869,7 @@ import {
|
|
|
1855
1869
|
basouPaths as basouPaths5,
|
|
1856
1870
|
ChildProcessRunner,
|
|
1857
1871
|
appendChainedEvent as coreAppendChainedEvent,
|
|
1872
|
+
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION3,
|
|
1858
1873
|
finalizeSessionYaml,
|
|
1859
1874
|
getSnapshot,
|
|
1860
1875
|
overwriteYamlFile,
|
|
@@ -1865,6 +1880,7 @@ import {
|
|
|
1865
1880
|
resolveRepositoryRoot as resolveRepositoryRoot4,
|
|
1866
1881
|
SessionSchema,
|
|
1867
1882
|
sanitizeWorkingDirectory,
|
|
1883
|
+
writeObservedDuration,
|
|
1868
1884
|
writeYamlFile
|
|
1869
1885
|
} from "@basou/core";
|
|
1870
1886
|
function registerExecCommand(program) {
|
|
@@ -1905,7 +1921,7 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
1905
1921
|
});
|
|
1906
1922
|
await writeYamlFile(sessionYamlPath, session);
|
|
1907
1923
|
await appendEvent(sessionDir, {
|
|
1908
|
-
schema_version:
|
|
1924
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
1909
1925
|
type: "session_started",
|
|
1910
1926
|
id: prefixedUlid3("evt"),
|
|
1911
1927
|
session_id: sessionId,
|
|
@@ -1917,7 +1933,7 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
1917
1933
|
}
|
|
1918
1934
|
const runningAt = now().toISOString();
|
|
1919
1935
|
await appendEvent(sessionDir, {
|
|
1920
|
-
schema_version:
|
|
1936
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
1921
1937
|
type: "session_status_changed",
|
|
1922
1938
|
id: prefixedUlid3("evt"),
|
|
1923
1939
|
session_id: sessionId,
|
|
@@ -1986,7 +2002,7 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
1986
2002
|
}
|
|
1987
2003
|
const endedAt = now().toISOString();
|
|
1988
2004
|
await appendEvent(sessionDir, {
|
|
1989
|
-
schema_version:
|
|
2005
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
1990
2006
|
type: "command_executed",
|
|
1991
2007
|
id: prefixedUlid3("evt"),
|
|
1992
2008
|
session_id: sessionId,
|
|
@@ -1998,14 +2014,21 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
1998
2014
|
exit_code: result.exit_code,
|
|
1999
2015
|
...result.signal !== null ? { signal: result.signal } : {},
|
|
2000
2016
|
...signalReceived !== null ? { received_signal: signalReceived } : {},
|
|
2001
|
-
|
|
2017
|
+
// Reached only when the child actually ran, and the runner times it on a
|
|
2018
|
+
// monotonic sub-millisecond clock, so the cheapest spawn on this host
|
|
2019
|
+
// (`/usr/bin/true`, median 0.83ms) still rounds to 1ms. A non-positive
|
|
2020
|
+
// value therefore means the measurement is unusable, not that the command
|
|
2021
|
+
// was instant, and is recorded as unobserved. A spawn that never ran
|
|
2022
|
+
// (ENOENT) does not reach this line at all: the runner rejects and
|
|
2023
|
+
// `finalizeSessionAsFailed` writes its own null.
|
|
2024
|
+
duration_ms: writeObservedDuration(result.duration_ms)
|
|
2002
2025
|
});
|
|
2003
2026
|
if (options.snapshot !== false) {
|
|
2004
2027
|
await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);
|
|
2005
2028
|
}
|
|
2006
2029
|
const finalStatus = decideFinalStatus(result, signalReceived);
|
|
2007
2030
|
await appendEvent(sessionDir, {
|
|
2008
|
-
schema_version:
|
|
2031
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2009
2032
|
type: "session_status_changed",
|
|
2010
2033
|
id: prefixedUlid3("evt"),
|
|
2011
2034
|
session_id: sessionId,
|
|
@@ -2015,7 +2038,7 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
2015
2038
|
to: finalStatus
|
|
2016
2039
|
});
|
|
2017
2040
|
await appendEvent(sessionDir, {
|
|
2018
|
-
schema_version:
|
|
2041
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2019
2042
|
type: "session_ended",
|
|
2020
2043
|
id: prefixedUlid3("evt"),
|
|
2021
2044
|
session_id: sessionId,
|
|
@@ -2062,7 +2085,7 @@ async function tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, append
|
|
|
2062
2085
|
return;
|
|
2063
2086
|
}
|
|
2064
2087
|
await appendEvent(sessionDir, {
|
|
2065
|
-
schema_version:
|
|
2088
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2066
2089
|
type: "git_snapshot",
|
|
2067
2090
|
id: prefixedUlid3("evt"),
|
|
2068
2091
|
session_id: sessionId,
|
|
@@ -2119,7 +2142,7 @@ async function mutateSessionYaml(filePath, mutator) {
|
|
|
2119
2142
|
}
|
|
2120
2143
|
async function finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent, ctx) {
|
|
2121
2144
|
await appendEvent(sessionDir, {
|
|
2122
|
-
schema_version:
|
|
2145
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2123
2146
|
type: "command_executed",
|
|
2124
2147
|
id: prefixedUlid3("evt"),
|
|
2125
2148
|
session_id: sessionId,
|
|
@@ -2131,10 +2154,12 @@ async function finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent
|
|
|
2131
2154
|
exit_code: null,
|
|
2132
2155
|
signal: null,
|
|
2133
2156
|
...ctx.signalReceived !== null ? { received_signal: ctx.signalReceived } : {},
|
|
2134
|
-
|
|
2157
|
+
// Not observed: this event stands in for a run that ended before a duration
|
|
2158
|
+
// could be measured, so 0 would claim a measured zero.
|
|
2159
|
+
duration_ms: null
|
|
2135
2160
|
});
|
|
2136
2161
|
await appendEvent(sessionDir, {
|
|
2137
|
-
schema_version:
|
|
2162
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2138
2163
|
type: "session_status_changed",
|
|
2139
2164
|
id: prefixedUlid3("evt"),
|
|
2140
2165
|
session_id: sessionId,
|
|
@@ -2144,7 +2169,7 @@ async function finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent
|
|
|
2144
2169
|
to: "failed"
|
|
2145
2170
|
});
|
|
2146
2171
|
await appendEvent(sessionDir, {
|
|
2147
|
-
schema_version:
|
|
2172
|
+
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2148
2173
|
type: "session_ended",
|
|
2149
2174
|
id: prefixedUlid3("evt"),
|
|
2150
2175
|
session_id: sessionId,
|
|
@@ -2609,6 +2634,7 @@ import {
|
|
|
2609
2634
|
readSessionYaml as readSessionYaml2,
|
|
2610
2635
|
reimportPreservingId,
|
|
2611
2636
|
resolveRepositoryRoot as resolveRepositoryRoot6,
|
|
2637
|
+
SESSION_IMPORT_SCHEMA_VERSION,
|
|
2612
2638
|
SessionImportPayloadSchema
|
|
2613
2639
|
} from "@basou/core";
|
|
2614
2640
|
var SES_PREFIX2 = "ses_";
|
|
@@ -2796,7 +2822,7 @@ async function importDerivedSessions(paths, manifest, options, sourceKind, candi
|
|
|
2796
2822
|
if (!parsed.success) {
|
|
2797
2823
|
throw new Error("Invalid import payload", { cause: parsed.error });
|
|
2798
2824
|
}
|
|
2799
|
-
if (parsed.data.schema_version !==
|
|
2825
|
+
if (parsed.data.schema_version !== SESSION_IMPORT_SCHEMA_VERSION) {
|
|
2800
2826
|
throw new Error(`Unsupported import schema_version: ${parsed.data.schema_version}`);
|
|
2801
2827
|
}
|
|
2802
2828
|
return parsed.data;
|
|
@@ -4223,6 +4249,7 @@ import {
|
|
|
4223
4249
|
assertBasouRootSafe as assertBasouRootSafe8,
|
|
4224
4250
|
basouPaths as basouPaths9,
|
|
4225
4251
|
createAdHocSessionWithEvent as createAdHocSessionWithEvent2,
|
|
4252
|
+
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION4,
|
|
4226
4253
|
findErrorCode as findErrorCode7,
|
|
4227
4254
|
readManifest as readManifest5,
|
|
4228
4255
|
resolveSessionId as resolveSessionId2
|
|
@@ -4327,7 +4354,7 @@ async function doRunNote(body, options, ctx) {
|
|
|
4327
4354
|
}
|
|
4328
4355
|
function buildNoteEvent(input) {
|
|
4329
4356
|
return {
|
|
4330
|
-
schema_version:
|
|
4357
|
+
schema_version: EVENT_SCHEMA_VERSION4,
|
|
4331
4358
|
id: input.eventId,
|
|
4332
4359
|
session_id: input.sessionId,
|
|
4333
4360
|
occurred_at: input.occurredAt,
|
|
@@ -8844,6 +8871,7 @@ import {
|
|
|
8844
8871
|
claudeCodeAdapterMetadata,
|
|
8845
8872
|
codexAdapterMetadata,
|
|
8846
8873
|
appendChainedEvent as coreAppendChainedEvent2,
|
|
8874
|
+
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION5,
|
|
8847
8875
|
finalizeSessionYaml as finalizeSessionYaml2,
|
|
8848
8876
|
findBasouSessionStartHook as findBasouSessionStartHook2,
|
|
8849
8877
|
getDiff,
|
|
@@ -8858,6 +8886,7 @@ import {
|
|
|
8858
8886
|
SessionSchema as SessionSchema2,
|
|
8859
8887
|
sanitizeRelatedFiles,
|
|
8860
8888
|
sanitizeWorkingDirectory as sanitizeWorkingDirectory2,
|
|
8889
|
+
writeObservedDuration as writeObservedDuration2,
|
|
8861
8890
|
writeYamlFile as writeYamlFile2
|
|
8862
8891
|
} from "@basou/core";
|
|
8863
8892
|
function registerRunCommand(program, ctx = {}) {
|
|
@@ -8930,7 +8959,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
8930
8959
|
});
|
|
8931
8960
|
await writeYamlFile2(sessionYamlPath, session);
|
|
8932
8961
|
await appendEvent(sessionDir, {
|
|
8933
|
-
schema_version:
|
|
8962
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
8934
8963
|
type: "session_started",
|
|
8935
8964
|
id: prefixedUlid4("evt"),
|
|
8936
8965
|
session_id: sessionId,
|
|
@@ -8943,7 +8972,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
8943
8972
|
}
|
|
8944
8973
|
const runningAt = now().toISOString();
|
|
8945
8974
|
await appendEvent(sessionDir, {
|
|
8946
|
-
schema_version:
|
|
8975
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
8947
8976
|
type: "session_status_changed",
|
|
8948
8977
|
id: prefixedUlid4("evt"),
|
|
8949
8978
|
session_id: sessionId,
|
|
@@ -9016,7 +9045,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9016
9045
|
}
|
|
9017
9046
|
const endedAt = now().toISOString();
|
|
9018
9047
|
await appendEvent(sessionDir, {
|
|
9019
|
-
schema_version:
|
|
9048
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9020
9049
|
type: "command_executed",
|
|
9021
9050
|
id: prefixedUlid4("evt"),
|
|
9022
9051
|
session_id: sessionId,
|
|
@@ -9028,7 +9057,14 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9028
9057
|
exit_code: result.exit_code,
|
|
9029
9058
|
...result.signal !== null ? { signal: result.signal } : {},
|
|
9030
9059
|
...signalReceived !== null ? { received_signal: signalReceived } : {},
|
|
9031
|
-
|
|
9060
|
+
// Reached only when the child actually ran, and the runner times it on a
|
|
9061
|
+
// monotonic sub-millisecond clock, so the cheapest spawn on this host
|
|
9062
|
+
// (`/usr/bin/true`, median 0.83ms) still rounds to 1ms. A non-positive
|
|
9063
|
+
// value therefore means the measurement is unusable, not that the command
|
|
9064
|
+
// was instant, and is recorded as unobserved. A spawn that never ran
|
|
9065
|
+
// (ENOENT) does not reach this line at all: the runner rejects and
|
|
9066
|
+
// `finalizeSessionAsFailed` writes its own null.
|
|
9067
|
+
duration_ms: writeObservedDuration2(result.duration_ms)
|
|
9032
9068
|
});
|
|
9033
9069
|
let postSnapshot = null;
|
|
9034
9070
|
if (options.snapshot !== false) {
|
|
@@ -9054,7 +9090,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9054
9090
|
}).sanitized;
|
|
9055
9091
|
const finalStatus = decideFinalStatus2(result, signalReceived);
|
|
9056
9092
|
await appendEvent(sessionDir, {
|
|
9057
|
-
schema_version:
|
|
9093
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9058
9094
|
type: "session_status_changed",
|
|
9059
9095
|
id: prefixedUlid4("evt"),
|
|
9060
9096
|
session_id: sessionId,
|
|
@@ -9064,7 +9100,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9064
9100
|
to: finalStatus
|
|
9065
9101
|
});
|
|
9066
9102
|
await appendEvent(sessionDir, {
|
|
9067
|
-
schema_version:
|
|
9103
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9068
9104
|
type: "session_ended",
|
|
9069
9105
|
id: prefixedUlid4("evt"),
|
|
9070
9106
|
session_id: sessionId,
|
|
@@ -9110,7 +9146,7 @@ async function tryAppendGitSnapshot2(sessionDir, sessionId, repoRoot, now, appen
|
|
|
9110
9146
|
return null;
|
|
9111
9147
|
}
|
|
9112
9148
|
await appendEvent(sessionDir, {
|
|
9113
|
-
schema_version:
|
|
9149
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9114
9150
|
type: "git_snapshot",
|
|
9115
9151
|
id: prefixedUlid4("evt"),
|
|
9116
9152
|
session_id: sessionId,
|
|
@@ -9130,7 +9166,7 @@ async function tryAppendFileChangedEvents(sessionDir, sessionId, repoRoot, baseR
|
|
|
9130
9166
|
}
|
|
9131
9167
|
for (const change of diff.changed_files) {
|
|
9132
9168
|
await appendEvent(sessionDir, {
|
|
9133
|
-
schema_version:
|
|
9169
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9134
9170
|
type: "file_changed",
|
|
9135
9171
|
id: prefixedUlid4("evt"),
|
|
9136
9172
|
session_id: sessionId,
|
|
@@ -9214,7 +9250,7 @@ async function mutateSessionYaml2(filePath, mutator) {
|
|
|
9214
9250
|
}
|
|
9215
9251
|
async function finalizeSessionAsFailed2(paths, sessionDir, sessionId, appendEvent, ctx) {
|
|
9216
9252
|
await appendEvent(sessionDir, {
|
|
9217
|
-
schema_version:
|
|
9253
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9218
9254
|
type: "command_executed",
|
|
9219
9255
|
id: prefixedUlid4("evt"),
|
|
9220
9256
|
session_id: sessionId,
|
|
@@ -9226,10 +9262,12 @@ async function finalizeSessionAsFailed2(paths, sessionDir, sessionId, appendEven
|
|
|
9226
9262
|
exit_code: null,
|
|
9227
9263
|
signal: null,
|
|
9228
9264
|
...ctx.signalReceived !== null ? { received_signal: ctx.signalReceived } : {},
|
|
9229
|
-
|
|
9265
|
+
// Not observed: this event stands in for a run that ended before a duration
|
|
9266
|
+
// could be measured, so 0 would claim a measured zero.
|
|
9267
|
+
duration_ms: null
|
|
9230
9268
|
});
|
|
9231
9269
|
await appendEvent(sessionDir, {
|
|
9232
|
-
schema_version:
|
|
9270
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9233
9271
|
type: "session_status_changed",
|
|
9234
9272
|
id: prefixedUlid4("evt"),
|
|
9235
9273
|
session_id: sessionId,
|
|
@@ -9239,7 +9277,7 @@ async function finalizeSessionAsFailed2(paths, sessionDir, sessionId, appendEven
|
|
|
9239
9277
|
to: "failed"
|
|
9240
9278
|
});
|
|
9241
9279
|
await appendEvent(sessionDir, {
|
|
9242
|
-
schema_version:
|
|
9280
|
+
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9243
9281
|
type: "session_ended",
|
|
9244
9282
|
id: prefixedUlid4("evt"),
|
|
9245
9283
|
session_id: sessionId,
|
|
@@ -9289,16 +9327,19 @@ import {
|
|
|
9289
9327
|
appendEventToExistingSession as appendEventToExistingSession3,
|
|
9290
9328
|
assertBasouRootSafe as assertBasouRootSafe13,
|
|
9291
9329
|
basouPaths as basouPaths16,
|
|
9330
|
+
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION6,
|
|
9292
9331
|
enumerateSessionDirs as enumerateSessionDirs2,
|
|
9293
9332
|
findErrorCode as findErrorCode12,
|
|
9294
9333
|
importSessionFromJson as importSessionFromJson2,
|
|
9295
9334
|
loadSessionEntries as loadSessionEntries2,
|
|
9296
9335
|
readAllEvents,
|
|
9297
9336
|
readManifest as readManifest10,
|
|
9337
|
+
readObservedDuration,
|
|
9298
9338
|
readYamlFile as readYamlFile7,
|
|
9299
9339
|
rechainSessionInPlace,
|
|
9300
9340
|
resolveSessionId as resolveSessionId3,
|
|
9301
9341
|
resolveTaskId,
|
|
9342
|
+
SESSION_IMPORT_SCHEMA_VERSION as SESSION_IMPORT_SCHEMA_VERSION2,
|
|
9302
9343
|
SessionImportPayloadSchema as SessionImportPayloadSchema2,
|
|
9303
9344
|
SessionSchema as SessionSchema3,
|
|
9304
9345
|
SessionStatusSchema,
|
|
@@ -9420,15 +9461,19 @@ async function doRunSessionShow(idInput, options, ctx) {
|
|
|
9420
9461
|
}
|
|
9421
9462
|
throw new Error("Failed to read session", { cause: error });
|
|
9422
9463
|
}
|
|
9464
|
+
let eventsLostLines = 0;
|
|
9423
9465
|
const events = await readAllEvents(sessionDir, {
|
|
9424
|
-
onWarning: (w) =>
|
|
9466
|
+
onWarning: (w) => {
|
|
9467
|
+
if (w.kind === "malformed_json" || w.kind === "schema_violation") eventsLostLines++;
|
|
9468
|
+
printReplayWarning(w, sessionId);
|
|
9469
|
+
}
|
|
9425
9470
|
});
|
|
9426
9471
|
if (options.json === true) {
|
|
9427
9472
|
console.log(JSON.stringify({ session: session.session, events }, null, 2));
|
|
9428
9473
|
return;
|
|
9429
9474
|
}
|
|
9430
9475
|
const now = ctx.nowProvider?.() ?? /* @__PURE__ */ new Date();
|
|
9431
|
-
printSessionShowText(session, events, options, repositoryRoot, now);
|
|
9476
|
+
printSessionShowText(session, events, options, repositoryRoot, now, eventsLostLines);
|
|
9432
9477
|
}
|
|
9433
9478
|
function suspectLabel(reason) {
|
|
9434
9479
|
if (reason === "events_say_ended_but_yaml_running") return " \u26A0 ended (yaml stale)";
|
|
@@ -9474,7 +9519,7 @@ function printSessionListText(records) {
|
|
|
9474
9519
|
);
|
|
9475
9520
|
}
|
|
9476
9521
|
}
|
|
9477
|
-
function printSessionShowText(session, events, options, repositoryRoot, now) {
|
|
9522
|
+
function printSessionShowText(session, events, options, repositoryRoot, now, eventsLostLines) {
|
|
9478
9523
|
const s = session.session;
|
|
9479
9524
|
console.log(`Session: ${s.id} (status: ${s.status})`);
|
|
9480
9525
|
console.log(`Source: ${s.source.kind} (v${s.source.version})`);
|
|
@@ -9500,7 +9545,7 @@ function printSessionShowText(session, events, options, repositoryRoot, now) {
|
|
|
9500
9545
|
console.log(` ${pad2(`${type}:`, 24)} ${n}`);
|
|
9501
9546
|
}
|
|
9502
9547
|
console.log("");
|
|
9503
|
-
console.log(`Work: ${formatSessionWork(session, events, now)}`);
|
|
9548
|
+
console.log(`Work: ${formatSessionWork(session, events, now, eventsLostLines)}`);
|
|
9504
9549
|
if (events.length === 0) return;
|
|
9505
9550
|
const last = options.last ?? 5;
|
|
9506
9551
|
const showAll = options.events === true && options.last === void 0;
|
|
@@ -9512,8 +9557,15 @@ function printSessionShowText(session, events, options, repositoryRoot, now) {
|
|
|
9512
9557
|
console.log(` ${formatEventLine(ev)}`);
|
|
9513
9558
|
}
|
|
9514
9559
|
}
|
|
9515
|
-
function formatSessionWork(session, events, now) {
|
|
9516
|
-
const w = sessionWorkStatsFromEvents(
|
|
9560
|
+
function formatSessionWork(session, events, now, eventsLostLines) {
|
|
9561
|
+
const w = sessionWorkStatsFromEvents(
|
|
9562
|
+
session.session.id,
|
|
9563
|
+
session.session,
|
|
9564
|
+
events,
|
|
9565
|
+
now,
|
|
9566
|
+
false,
|
|
9567
|
+
eventsLostLines
|
|
9568
|
+
);
|
|
9517
9569
|
const parts = [];
|
|
9518
9570
|
if (w.tokens.output > 0) parts.push(`${w.tokens.output.toLocaleString("en-US")} output tokens`);
|
|
9519
9571
|
parts.push(`${w.commandCount} cmd / ${w.fileChangedCount} files / ${w.decisionCount} dec`);
|
|
@@ -9524,7 +9576,7 @@ function formatSessionWork(session, events, now) {
|
|
|
9524
9576
|
}
|
|
9525
9577
|
parts.push(`span ${formatDurationMs(w.sessionSpanMs)}${w.open ? " (open)" : ""}`);
|
|
9526
9578
|
parts.push(
|
|
9527
|
-
w.availability.commandTime ? `command ${formatDurationMs(w.commandTimeMs)}` : "command n/a (
|
|
9579
|
+
w.availability.commandTime ? `command ${formatDurationMs(w.commandTimeMs)}` : "command n/a (no duration observed, or the stream was not read in full)"
|
|
9528
9580
|
);
|
|
9529
9581
|
return parts.join(", ");
|
|
9530
9582
|
}
|
|
@@ -9563,7 +9615,9 @@ function eventVariantSummary(ev) {
|
|
|
9563
9615
|
const argsPart = ev.args.length > 0 ? ` ${ev.args.join(" ")}` : "";
|
|
9564
9616
|
const executorPart = ev.command ?? "(executor unrecorded)";
|
|
9565
9617
|
const exitPart = ev.exit_code === null ? "exit=unknown" : `exit=${ev.exit_code}`;
|
|
9566
|
-
|
|
9618
|
+
const observedDuration = readObservedDuration(ev);
|
|
9619
|
+
const durationPart = observedDuration === null ? "duration=unknown" : `${observedDuration}ms`;
|
|
9620
|
+
return `${executorPart}${argsPart} (${exitPart}, ${durationPart})`;
|
|
9567
9621
|
}
|
|
9568
9622
|
case "git_snapshot":
|
|
9569
9623
|
return `branch=${ev.branch} dirty=${ev.dirty}`;
|
|
@@ -9713,7 +9767,7 @@ async function doRunSessionImport(options, ctx) {
|
|
|
9713
9767
|
if (!parsed.success) {
|
|
9714
9768
|
throw new Error("Invalid import payload", { cause: parsed.error });
|
|
9715
9769
|
}
|
|
9716
|
-
if (parsed.data.schema_version !==
|
|
9770
|
+
if (parsed.data.schema_version !== SESSION_IMPORT_SCHEMA_VERSION2) {
|
|
9717
9771
|
throw new Error(`Unsupported import schema_version: ${parsed.data.schema_version}`);
|
|
9718
9772
|
}
|
|
9719
9773
|
const importOptions2 = { dryRun: options.dryRun === true };
|
|
@@ -9834,7 +9888,7 @@ async function doRunSessionNote(sessionIdInput, options, ctx) {
|
|
|
9834
9888
|
paths,
|
|
9835
9889
|
sessionId: sesId,
|
|
9836
9890
|
eventBuilder: (eventId) => ({
|
|
9837
|
-
schema_version:
|
|
9891
|
+
schema_version: EVENT_SCHEMA_VERSION6,
|
|
9838
9892
|
id: eventId,
|
|
9839
9893
|
session_id: sesId,
|
|
9840
9894
|
occurred_at: occurredAt,
|
|
@@ -10028,7 +10082,7 @@ function printStatsText(result, bySource, byDay) {
|
|
|
10028
10082
|
console.log(
|
|
10029
10083
|
` Span: ${formatDurationMs(t.sessionSpanMs)} (total elapsed${openPart})`
|
|
10030
10084
|
);
|
|
10031
|
-
const cmdCaveat = t.commandTimeReliable ? "" : "; some sessions
|
|
10085
|
+
const cmdCaveat = t.commandTimeReliable ? "; at least, only durations the sources reported are counted" : "; some sessions ran commands with no duration observed, or could not be read in full, so this is a floor";
|
|
10032
10086
|
console.log(
|
|
10033
10087
|
` Command: ${formatDurationMs(t.commandTimeMs)} (real shell execution${cmdCaveat})`
|
|
10034
10088
|
);
|
|
@@ -10051,11 +10105,15 @@ function printStatsText(result, bySource, byDay) {
|
|
|
10051
10105
|
}
|
|
10052
10106
|
}
|
|
10053
10107
|
function describeSource(s) {
|
|
10054
|
-
const cmd = s.commandTimeReliable ? formatDurationMs(s.commandTimeMs) : "n/a";
|
|
10108
|
+
const cmd = s.commandTimeReliable ? formatDurationMs(s.commandTimeMs) : s.commandTimeMs > 0 ? `>=${formatFloorMs(s.commandTimeMs)}` : "n/a";
|
|
10055
10109
|
const tokens = s.tokensAvailable ? `${formatInt(s.tokens.output)} out tok` : "no tokens";
|
|
10056
10110
|
const machine = s.machineActiveAvailable ? `, model ${formatDurationMs(s.machineActiveTimeMs)}` : "";
|
|
10057
10111
|
return `${s.sessionCount} sessions, ${tokens}, active ${formatDurationMs(s.activeTimeMs)}${machine}, command ${cmd}`;
|
|
10058
10112
|
}
|
|
10113
|
+
function formatFloorMs(ms) {
|
|
10114
|
+
const coarse = formatDurationMs(ms);
|
|
10115
|
+
return coarse === "0s" ? `${Math.round(ms)}ms` : coarse;
|
|
10116
|
+
}
|
|
10059
10117
|
function formatInt(n) {
|
|
10060
10118
|
return n.toLocaleString("en-US");
|
|
10061
10119
|
}
|
|
@@ -12386,6 +12444,12 @@ var VIEW_HTML = `<!doctype html>
|
|
|
12386
12444
|
if (m > 0) return m + 'm ' + (sec < 10 ? '0' : '') + sec + 's';
|
|
12387
12445
|
return sec + 's';
|
|
12388
12446
|
}
|
|
12447
|
+
// A floor under half a second renders as '>=0s' -- true of any total, and
|
|
12448
|
+
// reading as a measured zero. Show those milliseconds instead.
|
|
12449
|
+
function fmtFloor(ms) {
|
|
12450
|
+
var coarse = fmtDur(ms);
|
|
12451
|
+
return coarse === '0s' ? Math.round(ms || 0) + 'ms' : coarse;
|
|
12452
|
+
}
|
|
12389
12453
|
function kvrow(k, v) {
|
|
12390
12454
|
return el('tr', {}, [el('td', { class: 'k', text: k }), el('td', { text: v })]);
|
|
12391
12455
|
}
|
|
@@ -12427,12 +12491,12 @@ var VIEW_HTML = `<!doctype html>
|
|
|
12427
12491
|
timeRows.push(kvrow('model working', fmtDur(t.machineActiveTimeMs) + ' (model compute, subset of active; Codex turn duration on ' + machineSessions + ' of ' + t.sessionCount + ' sessions; not wall-clock-deduped)'));
|
|
12428
12492
|
}
|
|
12429
12493
|
timeRows.push(kvrow('span', fmtDur(t.sessionSpanMs) + (t.openSessionCount > 0 ? ' (' + t.openSessionCount + ' open)' : '')));
|
|
12430
|
-
timeRows.push(kvrow('command', fmtDur(t.commandTimeMs) + (t.commandTimeReliable ? '' : ' (some sessions
|
|
12494
|
+
timeRows.push(kvrow('command', fmtDur(t.commandTimeMs) + (t.commandTimeReliable ? '' : ' (floor: some sessions had no duration observed, or could not be read in full)')));
|
|
12431
12495
|
detail.appendChild(el('table', { class: 'kv' }, [el('tbody', {}, timeRows)]));
|
|
12432
12496
|
if (d.bySource && d.bySource.length) {
|
|
12433
12497
|
detail.appendChild(el('h3', { text: 'By source' }));
|
|
12434
12498
|
d.bySource.forEach(function (s) {
|
|
12435
|
-
var cmd = s.commandTimeReliable ? fmtDur(s.commandTimeMs) : 'n/a';
|
|
12499
|
+
var cmd = s.commandTimeReliable ? fmtDur(s.commandTimeMs) : (s.commandTimeMs > 0 ? '>=' + fmtFloor(s.commandTimeMs) : 'n/a');
|
|
12436
12500
|
var machine = s.machineActiveAvailable ? ', model ' + fmtDur(s.machineActiveTimeMs) : '';
|
|
12437
12501
|
detail.appendChild(el('div', { class: 'row' }, [
|
|
12438
12502
|
el('span', { text: s.sourceKind + ': ' + s.sessionCount + ' sessions, ' + numfmt(s.tokens.output) + ' out tok, active ' + fmtDur(s.activeTimeMs) + machine + ', command ' + cmd })
|