@basou/cli 0.58.0 → 0.59.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 +66 -20
- package/dist/index.js.map +1 -1
- package/dist/program.js +66 -20
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/program.js
CHANGED
|
@@ -12,10 +12,12 @@ import {
|
|
|
12
12
|
acquireLock,
|
|
13
13
|
appendChainedEventLocked,
|
|
14
14
|
assertBasouRootSafe,
|
|
15
|
+
assertSessionDirSafe,
|
|
15
16
|
basouPaths,
|
|
16
17
|
EVENT_SCHEMA_VERSION,
|
|
17
18
|
enumerateApprovals,
|
|
18
19
|
findErrorCode,
|
|
20
|
+
inspectSessionEntry,
|
|
19
21
|
isLazyExpired,
|
|
20
22
|
LOCAL_CLI_EVENT_SOURCE,
|
|
21
23
|
linkYamlFile,
|
|
@@ -262,13 +264,20 @@ async function doRunApprovalShow(idInput, options, ctx) {
|
|
|
262
264
|
if (loaded === null) {
|
|
263
265
|
throw new Error(`Approval not found: ${idInput}`);
|
|
264
266
|
}
|
|
265
|
-
const
|
|
267
|
+
const sessionId = loaded.approval.session_id;
|
|
268
|
+
const entry = await inspectSessionEntry(paths, sessionId);
|
|
266
269
|
const relatedEvents = [];
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
if (entry === "symlink" || entry === "not_a_directory") {
|
|
271
|
+
console.error(
|
|
272
|
+
`Warning: session ${sessionId} is not a directory (a symlink or a file is not followed); its events are not shown`
|
|
273
|
+
);
|
|
274
|
+
} else {
|
|
275
|
+
for await (const ev of replayEvents(join(paths.sessions, sessionId), {
|
|
276
|
+
onWarning: (w) => printReplayWarning(w, sessionId)
|
|
277
|
+
})) {
|
|
278
|
+
if (isApprovalEvent(ev) && ev.approval_id === id) {
|
|
279
|
+
relatedEvents.push(ev);
|
|
280
|
+
}
|
|
272
281
|
}
|
|
273
282
|
}
|
|
274
283
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -347,6 +356,7 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
347
356
|
const eventId = prefixedUlid("evt");
|
|
348
357
|
const sessionLock = await acquireLock(paths, "session", approval.session_id);
|
|
349
358
|
try {
|
|
359
|
+
await assertSessionDirSafe(paths, approval.session_id);
|
|
350
360
|
const sessionDir = join(paths.sessions, approval.session_id);
|
|
351
361
|
for await (const ev of replayEvents(sessionDir, {
|
|
352
362
|
onWarning: (w) => printReplayWarning(w, approval.session_id)
|
|
@@ -2067,6 +2077,7 @@ import { join as join6 } from "path";
|
|
|
2067
2077
|
import {
|
|
2068
2078
|
acquireLock as acquireLock3,
|
|
2069
2079
|
assertBasouRootSafe as assertBasouRootSafe4,
|
|
2080
|
+
assertSessionStoreSafe,
|
|
2070
2081
|
basouPaths as basouPaths6,
|
|
2071
2082
|
ChildProcessRunner,
|
|
2072
2083
|
appendChainedEvent as coreAppendChainedEvent,
|
|
@@ -2105,6 +2116,7 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
2105
2116
|
const paths = basouPaths6(repoRoot);
|
|
2106
2117
|
await assertBasouRootSafe4(paths.root);
|
|
2107
2118
|
const manifest = await readManifest3(paths);
|
|
2119
|
+
await assertSessionStoreSafe(paths);
|
|
2108
2120
|
const sessionId = prefixedUlid3("ses");
|
|
2109
2121
|
const sessionDir = join6(paths.sessions, sessionId);
|
|
2110
2122
|
await mkdir(sessionDir, { recursive: true });
|
|
@@ -2919,6 +2931,7 @@ import { createInterface } from "readline";
|
|
|
2919
2931
|
import {
|
|
2920
2932
|
AGENT_INFRA_DIRS as AGENT_INFRA_DIRS2,
|
|
2921
2933
|
assertBasouRootSafe as assertBasouRootSafe6,
|
|
2934
|
+
assertSessionStoreSafe as assertSessionStoreSafe2,
|
|
2922
2935
|
basouPaths as basouPaths8,
|
|
2923
2936
|
CLAUDE_IMPORT_SOURCE,
|
|
2924
2937
|
CODEX_IMPORT_SOURCE,
|
|
@@ -2926,7 +2939,7 @@ import {
|
|
|
2926
2939
|
claudeTranscriptToImportPayload,
|
|
2927
2940
|
codexRolloutToImportPayload,
|
|
2928
2941
|
displayPath as displayPath2,
|
|
2929
|
-
|
|
2942
|
+
enumerateSessionEntries,
|
|
2930
2943
|
findErrorCode as findErrorCode5,
|
|
2931
2944
|
importSessionFromJson,
|
|
2932
2945
|
observedFilesOf,
|
|
@@ -3090,7 +3103,12 @@ async function resolveImportTarget(ctx) {
|
|
|
3090
3103
|
return { repositoryRoot, paths, manifest };
|
|
3091
3104
|
}
|
|
3092
3105
|
async function importDerivedSessions(paths, manifest, options, sourceKind, candidates, projectPaths, boundaryDeclared) {
|
|
3093
|
-
|
|
3106
|
+
await assertSessionStoreSafe2(paths);
|
|
3107
|
+
const { byExternalId: existingByExternalId, notDirectories } = await loadExistingByExternalId(
|
|
3108
|
+
paths,
|
|
3109
|
+
sourceKind
|
|
3110
|
+
);
|
|
3111
|
+
let notDirectoriesWarned = false;
|
|
3094
3112
|
const seenThisRun = /* @__PURE__ */ new Set();
|
|
3095
3113
|
const crossProjectCheck = boundaryDeclared;
|
|
3096
3114
|
const crossProject = [];
|
|
@@ -3182,6 +3200,13 @@ async function importDerivedSessions(paths, manifest, options, sourceKind, candi
|
|
|
3182
3200
|
}
|
|
3183
3201
|
counts.replaced++;
|
|
3184
3202
|
}
|
|
3203
|
+
if (priors.length === 0 && notDirectories.length > 0 && !notDirectoriesWarned) {
|
|
3204
|
+
notDirectoriesWarned = true;
|
|
3205
|
+
const one = notDirectories.length === 1;
|
|
3206
|
+
console.error(
|
|
3207
|
+
`Import: ${notDirectories.join(", ")} ${one ? "is not a directory" : "are not directories"} (a symlink or a file is not followed), so ${one ? "it was" : "they were"} not checked for an earlier import; a session imported there may be imported again`
|
|
3208
|
+
);
|
|
3209
|
+
}
|
|
3185
3210
|
const result = await importSessionFromJson(paths, manifest, payload, {
|
|
3186
3211
|
dryRun: options.dryRun === true
|
|
3187
3212
|
});
|
|
@@ -3258,10 +3283,11 @@ async function loadExistingByExternalId(paths, sourceKind) {
|
|
|
3258
3283
|
else list.push(prior);
|
|
3259
3284
|
};
|
|
3260
3285
|
let sessionIds;
|
|
3286
|
+
let notDirectories;
|
|
3261
3287
|
try {
|
|
3262
|
-
sessionIds = await
|
|
3288
|
+
({ dirs: sessionIds, notDirectories } = await enumerateSessionEntries(paths));
|
|
3263
3289
|
} catch {
|
|
3264
|
-
return byExternalId;
|
|
3290
|
+
return { byExternalId, notDirectories: [] };
|
|
3265
3291
|
}
|
|
3266
3292
|
for (const sessionId of sessionIds) {
|
|
3267
3293
|
let session;
|
|
@@ -3282,7 +3308,7 @@ async function loadExistingByExternalId(paths, sourceKind) {
|
|
|
3282
3308
|
const match = typeof label === "string" ? label.match(/^claude-code import (\S+)$/) : null;
|
|
3283
3309
|
if (match?.[1] !== void 0) add(match[1], prior);
|
|
3284
3310
|
}
|
|
3285
|
-
return byExternalId;
|
|
3311
|
+
return { byExternalId, notDirectories };
|
|
3286
3312
|
}
|
|
3287
3313
|
async function selectTranscriptFiles(projectsRoot, projectPaths, options) {
|
|
3288
3314
|
if (options.session !== void 0) {
|
|
@@ -9562,6 +9588,7 @@ import { join as join14 } from "path";
|
|
|
9562
9588
|
import {
|
|
9563
9589
|
acquireLock as acquireLock5,
|
|
9564
9590
|
assertBasouRootSafe as assertBasouRootSafe12,
|
|
9591
|
+
assertSessionStoreSafe as assertSessionStoreSafe3,
|
|
9565
9592
|
basouPaths as basouPaths17,
|
|
9566
9593
|
ChildProcessRunner as ChildProcessRunner2,
|
|
9567
9594
|
claudeCodeAdapterMetadata,
|
|
@@ -9637,6 +9664,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9637
9664
|
const paths = basouPaths17(repoRoot);
|
|
9638
9665
|
await assertBasouRootSafe12(paths.root);
|
|
9639
9666
|
const manifest = await readManifest10(paths);
|
|
9667
|
+
await assertSessionStoreSafe3(paths);
|
|
9640
9668
|
const sessionId = prefixedUlid4("ses");
|
|
9641
9669
|
const sessionDir = join14(paths.sessions, sessionId);
|
|
9642
9670
|
await mkdir2(sessionDir, { recursive: true });
|
|
@@ -10026,7 +10054,7 @@ import {
|
|
|
10026
10054
|
basouPaths as basouPaths18,
|
|
10027
10055
|
displayPath as displayPath3,
|
|
10028
10056
|
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION6,
|
|
10029
|
-
|
|
10057
|
+
enumerateSessionEntries as enumerateSessionEntries2,
|
|
10030
10058
|
findErrorCode as findErrorCode12,
|
|
10031
10059
|
importSessionFromJson as importSessionFromJson2,
|
|
10032
10060
|
LOCAL_CLI_EVENT_SOURCE as LOCAL_CLI_EVENT_SOURCE4,
|
|
@@ -10658,7 +10686,7 @@ async function doRunSessionRechain(options, ctx) {
|
|
|
10658
10686
|
const repositoryRoot = await resolveRepositoryRootForSession(cwd, "rechain");
|
|
10659
10687
|
const paths = basouPaths18(repositoryRoot);
|
|
10660
10688
|
await assertWorkspaceInitialized11(paths.root);
|
|
10661
|
-
const sessionIds = options.session !== void 0 ? [await resolveSessionId3(paths, options.session)] : await
|
|
10689
|
+
const sessionIds = options.session !== void 0 ? [await resolveSessionId3(paths, options.session)] : await enumerateAllSessionNames(paths);
|
|
10662
10690
|
const dryRun = options.dryRun === true;
|
|
10663
10691
|
const rows = [];
|
|
10664
10692
|
for (const sessionId of sessionIds) {
|
|
@@ -10679,7 +10707,9 @@ async function doRunSessionRechain(options, ctx) {
|
|
|
10679
10707
|
rows.push({ session_id: sessionId, status: "skipped", reason: outcome.reason });
|
|
10680
10708
|
}
|
|
10681
10709
|
}
|
|
10682
|
-
const tamperedCount = rows.filter(
|
|
10710
|
+
const tamperedCount = rows.filter(
|
|
10711
|
+
(r) => r.reason === "tampered" || r.reason === "symlink" || r.reason === "not_a_directory"
|
|
10712
|
+
).length;
|
|
10683
10713
|
const errorCount = rows.filter((r) => r.status === "error").length;
|
|
10684
10714
|
if (options.json === true) {
|
|
10685
10715
|
console.log(JSON.stringify(rows, null, 2));
|
|
@@ -10702,11 +10732,19 @@ function renderRechainRow(row, dryRun) {
|
|
|
10702
10732
|
case "rechained":
|
|
10703
10733
|
return `${dryRun ? "would rechain" : "rechained"} (${row.event_count} events)`;
|
|
10704
10734
|
case "skipped":
|
|
10705
|
-
|
|
10735
|
+
if (row.reason === "tampered") return "skipped (TAMPERED \u2014 inspect with 'basou verify')";
|
|
10736
|
+
if (row.reason === "symlink" || row.reason === "not_a_directory") {
|
|
10737
|
+
return `skipped (${row.reason === "symlink" ? "SYMLINK" : "NOT A DIRECTORY"} \u2014 not followed; inspect with 'basou verify')`;
|
|
10738
|
+
}
|
|
10739
|
+
return `skipped (${row.reason})`;
|
|
10706
10740
|
case "error":
|
|
10707
10741
|
return `error (${row.message})`;
|
|
10708
10742
|
}
|
|
10709
10743
|
}
|
|
10744
|
+
async function enumerateAllSessionNames(paths) {
|
|
10745
|
+
const { dirs, notDirectories } = await enumerateSessionEntries2(paths);
|
|
10746
|
+
return [...dirs, ...notDirectories].sort();
|
|
10747
|
+
}
|
|
10710
10748
|
|
|
10711
10749
|
// src/commands/stats.ts
|
|
10712
10750
|
import {
|
|
@@ -12054,7 +12092,7 @@ function maxLen3(values, floor) {
|
|
|
12054
12092
|
import {
|
|
12055
12093
|
assertBasouRootSafe as assertBasouRootSafe17,
|
|
12056
12094
|
basouPaths as basouPaths22,
|
|
12057
|
-
enumerateSessionEntries,
|
|
12095
|
+
enumerateSessionEntries as enumerateSessionEntries3,
|
|
12058
12096
|
findErrorCode as findErrorCode16,
|
|
12059
12097
|
resolveRepositoryRoot as resolveRepositoryRoot12,
|
|
12060
12098
|
resolveSessionId as resolveSessionId5,
|
|
@@ -12088,7 +12126,7 @@ async function doRunVerify(options, ctx) {
|
|
|
12088
12126
|
const repositoryRoot = await resolveRepositoryRootForVerify(cwd);
|
|
12089
12127
|
const paths = basouPaths22(repositoryRoot);
|
|
12090
12128
|
await assertWorkspaceInitialized14(paths.root);
|
|
12091
|
-
const sessionIds = options.session !== void 0 ? [await resolveSessionId5(paths, options.session, { allowNotDirectory: true })] : await
|
|
12129
|
+
const sessionIds = options.session !== void 0 ? [await resolveSessionId5(paths, options.session, { allowNotDirectory: true })] : await enumerateAllSessionNames2(paths);
|
|
12092
12130
|
const rows = [];
|
|
12093
12131
|
for (const sessionId of sessionIds) {
|
|
12094
12132
|
const verdict = await verifyEventsChain(paths, sessionId);
|
|
@@ -12135,8 +12173,8 @@ function renderVerdict(row) {
|
|
|
12135
12173
|
return "empty";
|
|
12136
12174
|
}
|
|
12137
12175
|
}
|
|
12138
|
-
async function
|
|
12139
|
-
const { dirs, notDirectories } = await
|
|
12176
|
+
async function enumerateAllSessionNames2(paths) {
|
|
12177
|
+
const { dirs, notDirectories } = await enumerateSessionEntries3(paths);
|
|
12140
12178
|
return [...dirs, ...notDirectories].sort();
|
|
12141
12179
|
}
|
|
12142
12180
|
async function resolveRepositoryRootForVerify(cwd) {
|
|
@@ -12676,6 +12714,7 @@ import {
|
|
|
12676
12714
|
computeWorkStats as computeWorkStats2,
|
|
12677
12715
|
enumerateApprovals as enumerateApprovals2,
|
|
12678
12716
|
findErrorCode as findErrorCode17,
|
|
12717
|
+
inspectSessionEntry as inspectSessionEntry2,
|
|
12679
12718
|
isLazyExpired as isLazyExpired2,
|
|
12680
12719
|
loadApproval as loadApproval2,
|
|
12681
12720
|
loadSessionEntries as loadSessionEntries4,
|
|
@@ -13754,6 +13793,13 @@ async function sessionDetail(ws, sessionId) {
|
|
|
13754
13793
|
if (!SessionIdSchema.safeParse(sessionId).success) {
|
|
13755
13794
|
throw new HttpError(404, "Session not found");
|
|
13756
13795
|
}
|
|
13796
|
+
const entry = await inspectSessionEntry2(ws.paths, sessionId);
|
|
13797
|
+
if (entry === "symlink" || entry === "not_a_directory") {
|
|
13798
|
+
throw new HttpError(
|
|
13799
|
+
404,
|
|
13800
|
+
`Session ${sessionId} is not a directory; a symlink or a file there is not followed`
|
|
13801
|
+
);
|
|
13802
|
+
}
|
|
13757
13803
|
let session;
|
|
13758
13804
|
try {
|
|
13759
13805
|
session = await readSessionYaml3(ws.paths, sessionId);
|
|
@@ -14136,7 +14182,7 @@ async function assertWorkspaceInitialized15(basouRoot) {
|
|
|
14136
14182
|
function readBuildStamp() {
|
|
14137
14183
|
if (false) return void 0;
|
|
14138
14184
|
try {
|
|
14139
|
-
return JSON.parse('{"version":"0.
|
|
14185
|
+
return JSON.parse('{"version":"0.59.0","commit":"431fe03","committedAt":"2026-10-01T20:32:13+09:00"}');
|
|
14140
14186
|
} catch {
|
|
14141
14187
|
return void 0;
|
|
14142
14188
|
}
|