@basou/cli 0.61.0 → 0.63.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/program.js CHANGED
@@ -12,11 +12,13 @@ import {
12
12
  acquireLock,
13
13
  appendChainedEventLocked,
14
14
  assertBasouRootSafe,
15
+ assertLockStoreSafe,
15
16
  assertSessionDirSafe,
16
17
  basouPaths,
17
18
  EVENT_SCHEMA_VERSION,
18
19
  enumerateApprovals,
19
20
  findErrorCode,
21
+ inspectApprovalEntry,
20
22
  inspectSessionEntry,
21
23
  isLazyExpired,
22
24
  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
- if (byId.size === 0) {
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 (byId.size > 1) {
497
+ if (matched.size > 1) {
476
498
  throw new Error(
477
- `Ambiguous approval id '${input}': matched ${byId.size} approvals. Disambiguate with a longer prefix.`
499
+ `Ambiguous approval id '${input}': matched ${matched.size} approvals. Disambiguate with a longer prefix.`
478
500
  );
479
501
  }
480
- const first = byId.entries().next().value;
481
- if (first === void 0) {
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 [id, location] = first;
485
- return { id, location };
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";
@@ -2082,6 +2111,7 @@ import { join as join6 } from "path";
2082
2111
  import {
2083
2112
  acquireLock as acquireLock3,
2084
2113
  assertBasouRootSafe as assertBasouRootSafe4,
2114
+ assertLockStoreSafe as assertLockStoreSafe2,
2085
2115
  assertSessionStoreSafe,
2086
2116
  basouPaths as basouPaths6,
2087
2117
  ChildProcessRunner,
@@ -2122,6 +2152,7 @@ async function runExec(command, args, options, ctx = {}) {
2122
2152
  await assertBasouRootSafe4(paths.root);
2123
2153
  const manifest = await readManifest3(paths);
2124
2154
  await assertSessionStoreSafe(paths);
2155
+ await assertLockStoreSafe2(paths);
2125
2156
  const sessionId = prefixedUlid3("ses");
2126
2157
  const sessionDir = join6(paths.sessions, sessionId);
2127
2158
  await mkdir2(sessionDir, { recursive: true });
@@ -2920,6 +2951,7 @@ async function loadHostsConfig(configPath = DEFAULT_HOSTS_CONFIG_PATH) {
2920
2951
  // src/lib/provenance-actions.ts
2921
2952
  import {
2922
2953
  assertApprovalStoreSafe,
2954
+ assertLockStoreSafe as assertLockStoreSafe4,
2923
2955
  assertTaskStoreSafe,
2924
2956
  readMarkdownFile as readMarkdownFile5,
2925
2957
  renderDecisions as renderDecisions2,
@@ -2938,6 +2970,7 @@ import { createInterface } from "readline";
2938
2970
  import {
2939
2971
  AGENT_INFRA_DIRS as AGENT_INFRA_DIRS2,
2940
2972
  assertBasouRootSafe as assertBasouRootSafe6,
2973
+ assertLockStoreSafe as assertLockStoreSafe3,
2941
2974
  assertSessionStoreSafe as assertSessionStoreSafe2,
2942
2975
  basouPaths as basouPaths8,
2943
2976
  CLAUDE_IMPORT_SOURCE,
@@ -3111,6 +3144,7 @@ async function resolveImportTarget(ctx) {
3111
3144
  }
3112
3145
  async function importDerivedSessions(paths, manifest, options, sourceKind, candidates, projectPaths, boundaryDeclared) {
3113
3146
  await assertSessionStoreSafe2(paths);
3147
+ if (options.dryRun !== true) await assertLockStoreSafe3(paths);
3114
3148
  const { byExternalId: existingByExternalId, notDirectories } = await loadExistingByExternalId(
3115
3149
  paths,
3116
3150
  sourceKind
@@ -3692,6 +3726,7 @@ async function refreshAll(args) {
3692
3726
  if (!dryRun) {
3693
3727
  await assertTaskStoreSafe(paths);
3694
3728
  await assertApprovalStoreSafe(paths);
3729
+ await assertLockStoreSafe4(paths);
3695
3730
  }
3696
3731
  const claudeCode = await importClaudeCode(options, ctx);
3697
3732
  const codex = await importCodex(options, ctx);
@@ -8714,6 +8749,7 @@ import { homedir as homedir10 } from "os";
8714
8749
  import { join as join13 } from "path";
8715
8750
  import {
8716
8751
  assertApprovalStoreSafe as assertApprovalStoreSafe2,
8752
+ assertLockStoreSafe as assertLockStoreSafe5,
8717
8753
  assertTaskStoreSafe as assertTaskStoreSafe2,
8718
8754
  findErrorCode as findErrorCode8
8719
8755
  } from "@basou/core";
@@ -8778,6 +8814,7 @@ function hms(date) {
8778
8814
  async function runImports(deps) {
8779
8815
  await assertTaskStoreSafe2(deps.paths);
8780
8816
  await assertApprovalStoreSafe2(deps.paths);
8817
+ await assertLockStoreSafe5(deps.paths);
8781
8818
  const claude = await importClaudeCode(deps.importOptions, deps.ctx);
8782
8819
  const codex = await importCodex(deps.importOptions, deps.ctx);
8783
8820
  return { claude, codex, changed: changedCount(claude) + changedCount(codex) };
@@ -9605,6 +9642,7 @@ import { join as join14 } from "path";
9605
9642
  import {
9606
9643
  acquireLock as acquireLock5,
9607
9644
  assertBasouRootSafe as assertBasouRootSafe12,
9645
+ assertLockStoreSafe as assertLockStoreSafe6,
9608
9646
  assertSessionStoreSafe as assertSessionStoreSafe3,
9609
9647
  basouPaths as basouPaths17,
9610
9648
  ChildProcessRunner as ChildProcessRunner2,
@@ -9682,6 +9720,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
9682
9720
  await assertBasouRootSafe12(paths.root);
9683
9721
  const manifest = await readManifest10(paths);
9684
9722
  await assertSessionStoreSafe3(paths);
9723
+ await assertLockStoreSafe6(paths);
9685
9724
  const sessionId = prefixedUlid4("ses");
9686
9725
  const sessionDir = join14(paths.sessions, sessionId);
9687
9726
  await mkdir3(sessionDir, { recursive: true });
@@ -10068,6 +10107,7 @@ import {
10068
10107
  acquireLock as acquireLock6,
10069
10108
  appendEventToExistingSession as appendEventToExistingSession3,
10070
10109
  assertBasouRootSafe as assertBasouRootSafe13,
10110
+ assertLockStoreSafe as assertLockStoreSafe7,
10071
10111
  basouPaths as basouPaths18,
10072
10112
  displayPath as displayPath3,
10073
10113
  EVENT_SCHEMA_VERSION as EVENT_SCHEMA_VERSION6,
@@ -10703,6 +10743,7 @@ async function doRunSessionRechain(options, ctx) {
10703
10743
  const repositoryRoot = await resolveRepositoryRootForSession(cwd, "rechain");
10704
10744
  const paths = basouPaths18(repositoryRoot);
10705
10745
  await assertWorkspaceInitialized11(paths.root);
10746
+ await assertLockStoreSafe7(paths);
10706
10747
  const sessionIds = options.session !== void 0 ? [await resolveSessionId3(paths, options.session)] : await enumerateAllSessionNames(paths);
10707
10748
  const dryRun = options.dryRun === true;
10708
10749
  const rows = [];
@@ -10991,6 +11032,7 @@ import { join as join16 } from "path";
10991
11032
  import {
10992
11033
  archiveTask,
10993
11034
  assertBasouRootSafe as assertBasouRootSafe16,
11035
+ assertLockStoreSafe as assertLockStoreSafe8,
10994
11036
  basouPaths as basouPaths21,
10995
11037
  createTaskWithEvent,
10996
11038
  deleteTask,
@@ -11528,6 +11570,7 @@ async function doRunTaskReconcile(options, ctx) {
11528
11570
  const repositoryRoot = await resolveRepositoryRootForTask(cwd, "reconcile");
11529
11571
  const paths = basouPaths21(repositoryRoot);
11530
11572
  await assertWorkspaceInitialized13(paths.root);
11573
+ await assertLockStoreSafe8(paths);
11531
11574
  const manifest = await readManifest13(paths);
11532
11575
  const nowProvider = ctx.nowProvider ?? (() => /* @__PURE__ */ new Date());
11533
11576
  const write = options.write === true;
@@ -14199,7 +14242,7 @@ async function assertWorkspaceInitialized15(basouRoot) {
14199
14242
  function readBuildStamp() {
14200
14243
  if (false) return void 0;
14201
14244
  try {
14202
- return JSON.parse('{"version":"0.61.0","commit":"88f40fa","committedAt":"2026-10-02T12:13:29+09:00"}');
14245
+ return JSON.parse('{"version":"0.63.0","commit":"5a404e5","committedAt":"2026-10-03T10:49:51+09:00"}');
14203
14246
  } catch {
14204
14247
  return void 0;
14205
14248
  }