@basou/cli 0.62.0 → 0.64.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 +84 -17
- package/dist/index.js.map +1 -1
- package/dist/program.js +84 -17
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -136,11 +136,13 @@ import {
|
|
|
136
136
|
acquireLock,
|
|
137
137
|
appendChainedEventLocked,
|
|
138
138
|
assertBasouRootSafe,
|
|
139
|
+
assertLockStoreSafe,
|
|
139
140
|
assertSessionDirSafe,
|
|
140
141
|
basouPaths,
|
|
141
142
|
EVENT_SCHEMA_VERSION,
|
|
142
143
|
enumerateApprovals,
|
|
143
144
|
findErrorCode,
|
|
145
|
+
inspectApprovalEntry,
|
|
144
146
|
inspectSessionEntry,
|
|
145
147
|
isLazyExpired,
|
|
146
148
|
LOCAL_CLI_EVENT_SOURCE,
|
|
@@ -192,6 +194,11 @@ async function doRunApprovalList(options, ctx) {
|
|
|
192
194
|
const paths = basouPaths(repositoryRoot);
|
|
193
195
|
await assertWorkspaceInitialized(paths.root);
|
|
194
196
|
const ids = await enumerateApprovals(paths);
|
|
197
|
+
for (const entry of ids.unfollowed) {
|
|
198
|
+
console.error(
|
|
199
|
+
`Skipped ${entry.id} in ${entry.location}: not a file (a symlink or a directory is not followed)`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
195
202
|
const now = /* @__PURE__ */ new Date();
|
|
196
203
|
const records = [];
|
|
197
204
|
const resolvedSet = new Set(ids.resolved);
|
|
@@ -259,7 +266,8 @@ async function doRunApprovalShow(idInput, options, ctx) {
|
|
|
259
266
|
const repositoryRoot = await resolveRepositoryRootForApproval(cwd, "show");
|
|
260
267
|
const paths = basouPaths(repositoryRoot);
|
|
261
268
|
await assertWorkspaceInitialized(paths.root);
|
|
262
|
-
const { id } = await resolveApprovalId(paths, idInput);
|
|
269
|
+
const { id, unfollowed } = await resolveApprovalId(paths, idInput);
|
|
270
|
+
for (const entry2 of unfollowed) console.error(`Warning: ${describeUnfollowed(entry2)}`);
|
|
263
271
|
const loaded = await loadApproval(paths, id);
|
|
264
272
|
if (loaded === null) {
|
|
265
273
|
throw new Error(`Approval not found: ${idInput}`);
|
|
@@ -328,6 +336,15 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
328
336
|
if (location === "resolved") {
|
|
329
337
|
throw new Error(`Approval already resolved: ${idInput}`);
|
|
330
338
|
}
|
|
339
|
+
const resolvedEntry = await inspectApprovalEntry(paths, "resolved", id);
|
|
340
|
+
if (resolvedEntry === "file") {
|
|
341
|
+
throw new Error(`Approval already resolved: ${idInput}`);
|
|
342
|
+
}
|
|
343
|
+
if (resolvedEntry !== "missing") {
|
|
344
|
+
throw new Error(
|
|
345
|
+
`Approval ${id} cannot be resolved: its entry in resolved is not a file (a symlink or a directory is not followed)`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
331
348
|
const pendingPath = join(paths.approvals.pending, `${id}.yaml`);
|
|
332
349
|
let pendingRaw;
|
|
333
350
|
try {
|
|
@@ -354,6 +371,7 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
354
371
|
const now = /* @__PURE__ */ new Date();
|
|
355
372
|
const occurredAt = now.toISOString();
|
|
356
373
|
const eventId = prefixedUlid("evt");
|
|
374
|
+
await assertLockStoreSafe(paths);
|
|
357
375
|
try {
|
|
358
376
|
await mkdir(paths.approvals.resolved, { recursive: true });
|
|
359
377
|
} catch (error) {
|
|
@@ -469,20 +487,31 @@ async function resolveApprovalId(paths, input) {
|
|
|
469
487
|
}
|
|
470
488
|
byId.set(id2, "resolved");
|
|
471
489
|
}
|
|
472
|
-
|
|
490
|
+
const matched = new Set(byId.keys());
|
|
491
|
+
for (const entry of enumeration.unfollowed) {
|
|
492
|
+
if (entry.id.startsWith(normalized)) matched.add(entry.id);
|
|
493
|
+
}
|
|
494
|
+
if (matched.size === 0) {
|
|
473
495
|
throw new Error(`Approval not found: ${input}`);
|
|
474
496
|
}
|
|
475
|
-
if (
|
|
497
|
+
if (matched.size > 1) {
|
|
476
498
|
throw new Error(
|
|
477
|
-
`Ambiguous approval id '${input}': matched ${
|
|
499
|
+
`Ambiguous approval id '${input}': matched ${matched.size} approvals. Disambiguate with a longer prefix.`
|
|
478
500
|
);
|
|
479
501
|
}
|
|
480
|
-
const
|
|
481
|
-
if (
|
|
502
|
+
const id = matched.values().next().value;
|
|
503
|
+
if (id === void 0) {
|
|
482
504
|
throw new Error(`Approval not found: ${input}`);
|
|
483
505
|
}
|
|
484
|
-
const
|
|
485
|
-
|
|
506
|
+
const location = byId.get(id);
|
|
507
|
+
if (location === void 0) {
|
|
508
|
+
throw new Error(`Approval ${id} is not a file; a symlink or a directory there is not followed`);
|
|
509
|
+
}
|
|
510
|
+
const unfollowed = enumeration.unfollowed.filter((entry) => entry.id === id);
|
|
511
|
+
return { id, location, unfollowed };
|
|
512
|
+
}
|
|
513
|
+
function describeUnfollowed(entry) {
|
|
514
|
+
return `${entry.id} in ${entry.location} is not a file (a symlink or a directory is not followed)`;
|
|
486
515
|
}
|
|
487
516
|
function isApprovalEvent(ev) {
|
|
488
517
|
return ev.type === "approval_requested" || ev.type === "approval_approved" || ev.type === "approval_rejected" || ev.type === "approval_expired";
|
|
@@ -2076,7 +2105,7 @@ async function assertWorkspaceInitialized3(basouRoot) {
|
|
|
2076
2105
|
}
|
|
2077
2106
|
|
|
2078
2107
|
// src/commands/exec.ts
|
|
2079
|
-
import { mkdir as mkdir2 } from "fs/promises";
|
|
2108
|
+
import { mkdir as mkdir2, rm } from "fs/promises";
|
|
2080
2109
|
import { homedir as homedir4 } from "os";
|
|
2081
2110
|
import { join as join6 } from "path";
|
|
2082
2111
|
import {
|
|
@@ -2124,7 +2153,6 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
2124
2153
|
await assertSessionStoreSafe(paths);
|
|
2125
2154
|
const sessionId = prefixedUlid3("ses");
|
|
2126
2155
|
const sessionDir = join6(paths.sessions, sessionId);
|
|
2127
|
-
await mkdir2(sessionDir, { recursive: true });
|
|
2128
2156
|
const appendEvent = ctx.appendEvent ?? (async (_sessionDir, event) => {
|
|
2129
2157
|
await coreAppendChainedEvent(paths, sessionId, event);
|
|
2130
2158
|
});
|
|
@@ -2138,7 +2166,22 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
2138
2166
|
workspaceId: manifest.workspace.id,
|
|
2139
2167
|
startedAt
|
|
2140
2168
|
});
|
|
2141
|
-
await
|
|
2169
|
+
const initialLock = await acquireLock3(paths, "session", sessionId);
|
|
2170
|
+
try {
|
|
2171
|
+
try {
|
|
2172
|
+
await mkdir2(sessionDir, { recursive: true });
|
|
2173
|
+
} catch (error) {
|
|
2174
|
+
throw new Error("Failed to create session directory", { cause: error });
|
|
2175
|
+
}
|
|
2176
|
+
try {
|
|
2177
|
+
await writeYamlFile(sessionYamlPath, session);
|
|
2178
|
+
} catch (error) {
|
|
2179
|
+
await rm(sessionDir, { recursive: true, force: true }).catch(() => void 0);
|
|
2180
|
+
throw error;
|
|
2181
|
+
}
|
|
2182
|
+
} finally {
|
|
2183
|
+
await initialLock.release();
|
|
2184
|
+
}
|
|
2142
2185
|
await appendEvent(sessionDir, {
|
|
2143
2186
|
schema_version: EVENT_SCHEMA_VERSION3,
|
|
2144
2187
|
type: "session_started",
|
|
@@ -2920,6 +2963,7 @@ async function loadHostsConfig(configPath = DEFAULT_HOSTS_CONFIG_PATH) {
|
|
|
2920
2963
|
// src/lib/provenance-actions.ts
|
|
2921
2964
|
import {
|
|
2922
2965
|
assertApprovalStoreSafe,
|
|
2966
|
+
assertLockStoreSafe as assertLockStoreSafe3,
|
|
2923
2967
|
assertTaskStoreSafe,
|
|
2924
2968
|
readMarkdownFile as readMarkdownFile5,
|
|
2925
2969
|
renderDecisions as renderDecisions2,
|
|
@@ -2931,13 +2975,14 @@ import {
|
|
|
2931
2975
|
|
|
2932
2976
|
// src/commands/import.ts
|
|
2933
2977
|
import { createReadStream } from "fs";
|
|
2934
|
-
import { readdir, readFile as readFile2, rm, stat as stat3 } from "fs/promises";
|
|
2978
|
+
import { readdir, readFile as readFile2, rm as rm2, stat as stat3 } from "fs/promises";
|
|
2935
2979
|
import { homedir as homedir7 } from "os";
|
|
2936
2980
|
import { basename as basename4, dirname as dirname3, join as join9, resolve as resolve6 } from "path";
|
|
2937
2981
|
import { createInterface } from "readline";
|
|
2938
2982
|
import {
|
|
2939
2983
|
AGENT_INFRA_DIRS as AGENT_INFRA_DIRS2,
|
|
2940
2984
|
assertBasouRootSafe as assertBasouRootSafe6,
|
|
2985
|
+
assertLockStoreSafe as assertLockStoreSafe2,
|
|
2941
2986
|
assertSessionStoreSafe as assertSessionStoreSafe2,
|
|
2942
2987
|
basouPaths as basouPaths8,
|
|
2943
2988
|
CLAUDE_IMPORT_SOURCE,
|
|
@@ -3111,6 +3156,7 @@ async function resolveImportTarget(ctx) {
|
|
|
3111
3156
|
}
|
|
3112
3157
|
async function importDerivedSessions(paths, manifest, options, sourceKind, candidates, projectPaths, boundaryDeclared) {
|
|
3113
3158
|
await assertSessionStoreSafe2(paths);
|
|
3159
|
+
if (options.dryRun !== true) await assertLockStoreSafe2(paths);
|
|
3114
3160
|
const { byExternalId: existingByExternalId, notDirectories } = await loadExistingByExternalId(
|
|
3115
3161
|
paths,
|
|
3116
3162
|
sourceKind
|
|
@@ -3202,7 +3248,7 @@ async function importDerivedSessions(paths, manifest, options, sourceKind, candi
|
|
|
3202
3248
|
if (priors.length > 0 && options.force === true) {
|
|
3203
3249
|
if (options.dryRun !== true) {
|
|
3204
3250
|
for (const { sessionId } of priors) {
|
|
3205
|
-
await
|
|
3251
|
+
await rm2(join9(paths.sessions, sessionId), { recursive: true, force: true });
|
|
3206
3252
|
}
|
|
3207
3253
|
}
|
|
3208
3254
|
counts.replaced++;
|
|
@@ -3692,6 +3738,7 @@ async function refreshAll(args) {
|
|
|
3692
3738
|
if (!dryRun) {
|
|
3693
3739
|
await assertTaskStoreSafe(paths);
|
|
3694
3740
|
await assertApprovalStoreSafe(paths);
|
|
3741
|
+
await assertLockStoreSafe3(paths);
|
|
3695
3742
|
}
|
|
3696
3743
|
const claudeCode = await importClaudeCode(options, ctx);
|
|
3697
3744
|
const codex = await importCodex(options, ctx);
|
|
@@ -8714,6 +8761,7 @@ import { homedir as homedir10 } from "os";
|
|
|
8714
8761
|
import { join as join13 } from "path";
|
|
8715
8762
|
import {
|
|
8716
8763
|
assertApprovalStoreSafe as assertApprovalStoreSafe2,
|
|
8764
|
+
assertLockStoreSafe as assertLockStoreSafe4,
|
|
8717
8765
|
assertTaskStoreSafe as assertTaskStoreSafe2,
|
|
8718
8766
|
findErrorCode as findErrorCode8
|
|
8719
8767
|
} from "@basou/core";
|
|
@@ -8778,6 +8826,7 @@ function hms(date) {
|
|
|
8778
8826
|
async function runImports(deps) {
|
|
8779
8827
|
await assertTaskStoreSafe2(deps.paths);
|
|
8780
8828
|
await assertApprovalStoreSafe2(deps.paths);
|
|
8829
|
+
await assertLockStoreSafe4(deps.paths);
|
|
8781
8830
|
const claude = await importClaudeCode(deps.importOptions, deps.ctx);
|
|
8782
8831
|
const codex = await importCodex(deps.importOptions, deps.ctx);
|
|
8783
8832
|
return { claude, codex, changed: changedCount(claude) + changedCount(codex) };
|
|
@@ -9599,7 +9648,7 @@ function unattachedLines(u) {
|
|
|
9599
9648
|
}
|
|
9600
9649
|
|
|
9601
9650
|
// src/commands/run.ts
|
|
9602
|
-
import { mkdir as mkdir3, readFile as readFile7 } from "fs/promises";
|
|
9651
|
+
import { mkdir as mkdir3, readFile as readFile7, rm as rm3 } from "fs/promises";
|
|
9603
9652
|
import { homedir as homedir12 } from "os";
|
|
9604
9653
|
import { join as join14 } from "path";
|
|
9605
9654
|
import {
|
|
@@ -9684,7 +9733,6 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9684
9733
|
await assertSessionStoreSafe3(paths);
|
|
9685
9734
|
const sessionId = prefixedUlid4("ses");
|
|
9686
9735
|
const sessionDir = join14(paths.sessions, sessionId);
|
|
9687
|
-
await mkdir3(sessionDir, { recursive: true });
|
|
9688
9736
|
const appendEvent = ctx.appendEvent ?? (async (_sessionDir, event) => {
|
|
9689
9737
|
await coreAppendChainedEvent2(paths, sessionId, event);
|
|
9690
9738
|
});
|
|
@@ -9699,7 +9747,22 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9699
9747
|
startedAt,
|
|
9700
9748
|
source: adapter.metadata
|
|
9701
9749
|
});
|
|
9702
|
-
await
|
|
9750
|
+
const initialLock = await acquireLock5(paths, "session", sessionId);
|
|
9751
|
+
try {
|
|
9752
|
+
try {
|
|
9753
|
+
await mkdir3(sessionDir, { recursive: true });
|
|
9754
|
+
} catch (error) {
|
|
9755
|
+
throw new Error("Failed to create session directory", { cause: error });
|
|
9756
|
+
}
|
|
9757
|
+
try {
|
|
9758
|
+
await writeYamlFile2(sessionYamlPath, session);
|
|
9759
|
+
} catch (error) {
|
|
9760
|
+
await rm3(sessionDir, { recursive: true, force: true }).catch(() => void 0);
|
|
9761
|
+
throw error;
|
|
9762
|
+
}
|
|
9763
|
+
} finally {
|
|
9764
|
+
await initialLock.release();
|
|
9765
|
+
}
|
|
9703
9766
|
await appendEvent(sessionDir, {
|
|
9704
9767
|
schema_version: EVENT_SCHEMA_VERSION5,
|
|
9705
9768
|
type: "session_started",
|
|
@@ -10068,6 +10131,7 @@ import {
|
|
|
10068
10131
|
acquireLock as acquireLock6,
|
|
10069
10132
|
appendEventToExistingSession as appendEventToExistingSession3,
|
|
10070
10133
|
assertBasouRootSafe as assertBasouRootSafe13,
|
|
10134
|
+
assertLockStoreSafe as assertLockStoreSafe5,
|
|
10071
10135
|
basouPaths as basouPaths18,
|
|
10072
10136
|
displayPath as displayPath3,
|
|
10073
10137
|
EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION6,
|
|
@@ -10703,6 +10767,7 @@ async function doRunSessionRechain(options, ctx) {
|
|
|
10703
10767
|
const repositoryRoot = await resolveRepositoryRootForSession(cwd, "rechain");
|
|
10704
10768
|
const paths = basouPaths18(repositoryRoot);
|
|
10705
10769
|
await assertWorkspaceInitialized11(paths.root);
|
|
10770
|
+
await assertLockStoreSafe5(paths);
|
|
10706
10771
|
const sessionIds = options.session !== void 0 ? [await resolveSessionId3(paths, options.session)] : await enumerateAllSessionNames(paths);
|
|
10707
10772
|
const dryRun = options.dryRun === true;
|
|
10708
10773
|
const rows = [];
|
|
@@ -10991,6 +11056,7 @@ import { join as join16 } from "path";
|
|
|
10991
11056
|
import {
|
|
10992
11057
|
archiveTask,
|
|
10993
11058
|
assertBasouRootSafe as assertBasouRootSafe16,
|
|
11059
|
+
assertLockStoreSafe as assertLockStoreSafe6,
|
|
10994
11060
|
basouPaths as basouPaths21,
|
|
10995
11061
|
createTaskWithEvent,
|
|
10996
11062
|
deleteTask,
|
|
@@ -11528,6 +11594,7 @@ async function doRunTaskReconcile(options, ctx) {
|
|
|
11528
11594
|
const repositoryRoot = await resolveRepositoryRootForTask(cwd, "reconcile");
|
|
11529
11595
|
const paths = basouPaths21(repositoryRoot);
|
|
11530
11596
|
await assertWorkspaceInitialized13(paths.root);
|
|
11597
|
+
await assertLockStoreSafe6(paths);
|
|
11531
11598
|
const manifest = await readManifest13(paths);
|
|
11532
11599
|
const nowProvider = ctx.nowProvider ?? (() => /* @__PURE__ */ new Date());
|
|
11533
11600
|
const write = options.write === true;
|
|
@@ -14199,7 +14266,7 @@ async function assertWorkspaceInitialized15(basouRoot) {
|
|
|
14199
14266
|
function readBuildStamp() {
|
|
14200
14267
|
if (false) return void 0;
|
|
14201
14268
|
try {
|
|
14202
|
-
return JSON.parse('{"version":"0.
|
|
14269
|
+
return JSON.parse('{"version":"0.64.0","commit":"1caea85","committedAt":"2026-10-04T11:34:39+09:00"}');
|
|
14203
14270
|
} catch {
|
|
14204
14271
|
return void 0;
|
|
14205
14272
|
}
|