@basou/cli 0.53.0 → 0.55.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 CHANGED
@@ -139,6 +139,7 @@ import {
139
139
  LOCAL_CLI_EVENT_SOURCE,
140
140
  linkYamlFile,
141
141
  loadApproval,
142
+ normalizeApprovalTimestamps,
142
143
  prefixedUlid,
143
144
  readSessionYaml,
144
145
  readYamlFile,
@@ -226,7 +227,7 @@ async function readApprovalListRecord(paths, id, location, now) {
226
227
  console.error(`Skipped ${shortId(id)}: ${describeReadError(error)}`);
227
228
  return null;
228
229
  }
229
- const parse = ApprovalSchema.safeParse(raw);
230
+ const parse = ApprovalSchema.safeParse(normalizeApprovalTimestamps(raw));
230
231
  if (!parse.success) {
231
232
  console.error(`Skipped ${shortId(id)}: invalid approval schema`);
232
233
  return null;
@@ -323,7 +324,7 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
323
324
  }
324
325
  throw new Error("Failed to read approval", { cause: error });
325
326
  }
326
- const approvalParse = ApprovalSchema.safeParse(pendingRaw);
327
+ const approvalParse = ApprovalSchema.safeParse(normalizeApprovalTimestamps(pendingRaw));
327
328
  if (!approvalParse.success) {
328
329
  throw new Error("Failed to read approval", { cause: approvalParse.error });
329
330
  }
@@ -4876,6 +4877,9 @@ async function resolveRepositoryRootForInit(cwd) {
4876
4877
  }
4877
4878
 
4878
4879
  // src/commands/note.ts
4880
+ import { readFile as readFile4 } from "fs/promises";
4881
+ import { homedir as homedir9 } from "os";
4882
+ import { resolve as resolve8 } from "path";
4879
4883
  import {
4880
4884
  acquireLock as acquireLock4,
4881
4885
  appendEventToExistingSession as appendEventToExistingSession2,
@@ -4886,7 +4890,8 @@ import {
4886
4890
  findErrorCode as findErrorCode7,
4887
4891
  LOCAL_CLI_EVENT_SOURCE as LOCAL_CLI_EVENT_SOURCE3,
4888
4892
  readManifest as readManifest6,
4889
- resolveSessionId as resolveSessionId2
4893
+ resolveSessionId as resolveSessionId2,
4894
+ sanitizePath as sanitizePath2
4890
4895
  } from "@basou/core";
4891
4896
  import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
4892
4897
  var NOTE_SUBCOMMAND_LOOKALIKES = /* @__PURE__ */ new Set([
@@ -4904,11 +4909,33 @@ var NOTE_SUBCOMMAND_LOOKALIKES = /* @__PURE__ */ new Set([
4904
4909
  ]);
4905
4910
  var LABEL_BODY_MAX = 80;
4906
4911
  var LABEL_TRUNCATE_HEAD2 = LABEL_BODY_MAX - 3;
4912
+ var NOTE_HELP = `
4913
+ Text that contains backticks, $(...), $VAR or ! is safest on stdin through a
4914
+ heredoc whose delimiter is QUOTED: the shell then passes the text through
4915
+ untouched. Inside double quotes the shell runs backticks and $(...) as commands
4916
+ and records their output in place of the text, without any error.
4917
+
4918
+ Example (heredoc on stdin):
4919
+ basou note <<'EOF'
4920
+ Next: rebase \`topic\` onto main, then rerun the $CI job.
4921
+ EOF
4922
+
4923
+ Keep the text on its own lines: words on the same line as <<'EOF' are ordinary
4924
+ shell words, not part of the quoted text. 'basou note -' does not read stdin;
4925
+ omit the argument instead.
4926
+
4927
+ Trailing newlines in text read from stdin or --file are dropped (a heredoc
4928
+ always ends with one); everything else is recorded exactly as read.
4929
+ `;
4930
+ var HEREDOC_EXAMPLE = [" basou note <<'EOF'", " <your note>", " EOF"].join("\n");
4931
+ var NO_INPUT_HINT2 = `No note text. Pass it on stdin through a quoted heredoc, with the text on its own lines:
4932
+ ${HEREDOC_EXAMPLE}
4933
+ or pass it as an argument, or with --file <path>.`;
4907
4934
  function registerNoteCommand(program2) {
4908
- program2.command("note").description("Record a free-text note (orientation surfaces the latest as the next step)").argument("<body>", "Note text", parseBody).option(
4935
+ program2.command("note").description("Record a free-text note (orientation surfaces the latest as the next step)").argument("[body]", "Note text (omit it to read the text from stdin or --file)", parseBody).option("--file <path>", "Read the note text from a file instead of the argument or stdin").option(
4909
4936
  "--session <session_id>",
4910
4937
  "Attach to an existing session; otherwise an ad-hoc session is created"
4911
- ).option("--json", "Output the result as JSON").option("-v, --verbose", "Show error causes").action(async (body, options) => {
4938
+ ).option("--json", "Output the result as JSON").option("-v, --verbose", "Show error causes").addHelpText("after", NOTE_HELP).action(async (body, options) => {
4912
4939
  await runNote(body, options);
4913
4940
  });
4914
4941
  }
@@ -4923,17 +4950,29 @@ async function runNote(body, options, ctx = {}) {
4923
4950
  process.exitCode = 1;
4924
4951
  }
4925
4952
  }
4926
- async function doRunNote(body, options, ctx) {
4953
+ async function doRunNote(bodyArgument, options, ctx) {
4954
+ const cwd = ctx.cwd ?? process.cwd();
4955
+ const { body, source } = await readNoteBody(bodyArgument, options, ctx, cwd);
4956
+ if (source === "stdin" && body.trim().length === 0) {
4957
+ throw new Error(NO_INPUT_HINT2);
4958
+ }
4927
4959
  if (body.trim().length === 0) {
4928
4960
  throw new Error("Note body must not be empty");
4929
4961
  }
4930
4962
  const reserved = body.trim().toLowerCase();
4931
4963
  if (NOTE_SUBCOMMAND_LOOKALIKES.has(reserved)) {
4932
4964
  throw new Error(
4933
- `'basou note' records a free-text note and has no '${body.trim()}' subcommand. To record a note, pass its full text (e.g. \`basou note "<your note>"\`).`
4965
+ `'basou note' records a free-text note and has no '${body.trim()}' subcommand. To record a note, pass its full text, e.g. on stdin through a quoted heredoc, with the text on its own lines:
4966
+ ${HEREDOC_EXAMPLE}`
4967
+ );
4968
+ }
4969
+ if (reserved === "-") {
4970
+ throw new Error(
4971
+ source === "argument" ? `'basou note -' does not read stdin; it would record '-' as the note. To pass the note on stdin, omit the argument:
4972
+ ${HEREDOC_EXAMPLE}` : `The note text is just '-', which would be recorded as the next step. Write the note itself, e.g.:
4973
+ ${HEREDOC_EXAMPLE}`
4934
4974
  );
4935
4975
  }
4936
- const cwd = ctx.cwd ?? process.cwd();
4937
4976
  const repositoryRoot = await resolveBasouRootForCommand(cwd, "note");
4938
4977
  const paths = basouPaths11(repositoryRoot);
4939
4978
  await assertWorkspaceInitialized7(paths.root);
@@ -4972,7 +5011,7 @@ async function doRunNote(body, options, ctx) {
4972
5011
  workingDirectory: repositoryRoot,
4973
5012
  invocation: {
4974
5013
  command: "basou note",
4975
- args: [body]
5014
+ args: noteInvocationArgs({ body, source, file: options.file, cwd, repositoryRoot })
4976
5015
  },
4977
5016
  targetEventBuilders: [
4978
5017
  (sessionId, eventId) => buildNoteEvent({ eventId, sessionId, occurredAt, body })
@@ -5005,6 +5044,64 @@ function buildAdHocLabel2(body) {
5005
5044
  const truncated = oneLine3.length > LABEL_BODY_MAX ? `${oneLine3.slice(0, LABEL_TRUNCATE_HEAD2)}...` : oneLine3;
5006
5045
  return `Ad-hoc note: ${truncated}`;
5007
5046
  }
5047
+ async function readNoteBody(bodyArgument, options, ctx, cwd) {
5048
+ if (bodyArgument !== void 0 && options.file !== void 0) {
5049
+ throw new Error("Pass the note text either as an argument or with --file, not both.");
5050
+ }
5051
+ if (bodyArgument !== void 0) {
5052
+ return { body: bodyArgument, source: "argument" };
5053
+ }
5054
+ if (options.file !== void 0) {
5055
+ let raw;
5056
+ try {
5057
+ raw = await readFile4(resolve8(cwd, options.file), "utf8");
5058
+ } catch (error) {
5059
+ if (findErrorCode7(error, "ENOENT")) {
5060
+ throw new Error("--file names a file that does not exist", { cause: error });
5061
+ }
5062
+ if (findErrorCode7(error, "EISDIR")) {
5063
+ throw new Error("--file names a directory, not a file", { cause: error });
5064
+ }
5065
+ throw new Error("Could not read the file --file names", { cause: error });
5066
+ }
5067
+ return { body: dropTrailingNewlines(raw), source: "file" };
5068
+ }
5069
+ if (ctx.readInput !== void 0) {
5070
+ return { body: dropTrailingNewlines(await ctx.readInput()), source: "stdin" };
5071
+ }
5072
+ if (process.stdin.isTTY === true) {
5073
+ throw new Error(NO_INPUT_HINT2);
5074
+ }
5075
+ return { body: dropTrailingNewlines(await readStdinToEnd2()), source: "stdin" };
5076
+ }
5077
+ function dropTrailingNewlines(text) {
5078
+ let end = text.length;
5079
+ while (end > 0 && text[end - 1] === "\n") {
5080
+ end -= 1;
5081
+ if (end > 0 && text[end - 1] === "\r") end -= 1;
5082
+ }
5083
+ return text.slice(0, end);
5084
+ }
5085
+ async function readStdinToEnd2() {
5086
+ const chunks = [];
5087
+ for await (const chunk of process.stdin) {
5088
+ chunks.push(Buffer.from(chunk));
5089
+ }
5090
+ return Buffer.concat(chunks).toString("utf8");
5091
+ }
5092
+ function noteInvocationArgs(input) {
5093
+ if (input.source === "argument") return [input.body];
5094
+ if (input.source === "file" && input.file !== void 0) {
5095
+ return [
5096
+ "--file",
5097
+ sanitizePath2(resolve8(input.cwd, input.file), {
5098
+ workingDirectory: input.repositoryRoot,
5099
+ homedir: homedir9()
5100
+ })
5101
+ ];
5102
+ }
5103
+ return [];
5104
+ }
5008
5105
  function parseBody(raw) {
5009
5106
  if (raw.trim().length === 0) {
5010
5107
  throw new InvalidArgumentError3("Note body must not be empty");
@@ -5155,7 +5252,7 @@ import {
5155
5252
  writeFileSync,
5156
5253
  writeSync
5157
5254
  } from "fs";
5158
- import { basename as basename6, dirname as dirname4, isAbsolute as isAbsolute4, join as join12, relative as relative2, resolve as resolve8 } from "path";
5255
+ import { basename as basename6, dirname as dirname4, isAbsolute as isAbsolute4, join as join12, relative as relative2, resolve as resolve9 } from "path";
5159
5256
  import {
5160
5257
  appendBasouGitignore as appendBasouGitignore2,
5161
5258
  basouPaths as basouPaths12,
@@ -5530,7 +5627,7 @@ async function runProjectAdopt(options, ctx = {}) {
5530
5627
  }
5531
5628
  }
5532
5629
  function classifySourceRoot(repositoryRoot, declaredPath) {
5533
- const absolute = resolve8(repositoryRoot, declaredPath);
5630
+ const absolute = resolve9(repositoryRoot, declaredPath);
5534
5631
  let real;
5535
5632
  try {
5536
5633
  real = realpathSync(absolute);
@@ -5637,7 +5734,7 @@ async function gatherRepoWiring(repositoryRoot, entry) {
5637
5734
  };
5638
5735
  let real;
5639
5736
  try {
5640
- real = realpathSync(resolve8(repositoryRoot, entry.path));
5737
+ real = realpathSync(resolve9(repositoryRoot, entry.path));
5641
5738
  } catch {
5642
5739
  return { ...base, reachable: false, instructionFiles: [] };
5643
5740
  }
@@ -5756,7 +5853,7 @@ function gatherRepoGitignore(repositoryRoot, entry) {
5756
5853
  };
5757
5854
  let real;
5758
5855
  try {
5759
- real = realpathSync(resolve8(repositoryRoot, entry.path));
5856
+ real = realpathSync(resolve9(repositoryRoot, entry.path));
5760
5857
  } catch {
5761
5858
  return { ...base, reachable: false, currentLines: [] };
5762
5859
  }
@@ -5777,7 +5874,7 @@ function readGitignoreLines(file) {
5777
5874
  }
5778
5875
  }
5779
5876
  function applyGitignorePlan(repositoryRoot, plan) {
5780
- const file = join12(realpathSync(resolve8(repositoryRoot, plan.path)), ".gitignore");
5877
+ const file = join12(realpathSync(resolve9(repositoryRoot, plan.path)), ".gitignore");
5781
5878
  let existing = "";
5782
5879
  try {
5783
5880
  existing = readFileSync(file, "utf8");
@@ -5912,7 +6009,7 @@ function gatherRepoSymlinks(repositoryRoot, anchorReal, entry) {
5912
6009
  const base = { path: entry.path, ...isSelf ? { self: true } : {} };
5913
6010
  let real;
5914
6011
  try {
5915
- real = realpathSync(resolve8(repositoryRoot, entry.path));
6012
+ real = realpathSync(resolve9(repositoryRoot, entry.path));
5916
6013
  } catch {
5917
6014
  return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };
5918
6015
  }
@@ -5984,7 +6081,7 @@ function gatherRepoSymlinks(repositoryRoot, anchorReal, entry) {
5984
6081
  function applySymlinkPlan(repositoryRoot, plan) {
5985
6082
  let real;
5986
6083
  try {
5987
- real = realpathSync(resolve8(repositoryRoot, plan.path));
6084
+ real = realpathSync(resolve9(repositoryRoot, plan.path));
5988
6085
  } catch (error) {
5989
6086
  const message = failureReason(error);
5990
6087
  return { created: [], failed: plan.toCreate.map((c) => ({ file: c.name, message })) };
@@ -6010,9 +6107,9 @@ function viewCanonicalCollision(repositoryRoot, roster, viewName) {
6010
6107
  for (const entry of roster) {
6011
6108
  let name;
6012
6109
  try {
6013
- name = basename6(realpathSync(resolve8(repositoryRoot, entry.path)));
6110
+ name = basename6(realpathSync(resolve9(repositoryRoot, entry.path)));
6014
6111
  } catch {
6015
- name = basename6(resolve8(repositoryRoot, entry.path));
6112
+ name = basename6(resolve9(repositoryRoot, entry.path));
6016
6113
  }
6017
6114
  if (name === viewName) return entry.path;
6018
6115
  }
@@ -6259,7 +6356,7 @@ async function runProjectWorkspace(options, ctx = {}) {
6259
6356
  }
6260
6357
  }
6261
6358
  function resolveViewDir(repositoryRoot, viewPath) {
6262
- const abs = resolve8(repositoryRoot, viewPath);
6359
+ const abs = resolve9(repositoryRoot, viewPath);
6263
6360
  try {
6264
6361
  return realpathSync(abs);
6265
6362
  } catch {
@@ -6273,7 +6370,7 @@ function resolveViewDir(repositoryRoot, viewPath) {
6273
6370
  function gatherViewRepo(repositoryRoot, viewDir, entry) {
6274
6371
  let repoReal;
6275
6372
  try {
6276
- repoReal = realpathSync(resolve8(repositoryRoot, entry.path));
6373
+ repoReal = realpathSync(resolve9(repositoryRoot, entry.path));
6277
6374
  } catch {
6278
6375
  return { path: entry.path, reachable: false };
6279
6376
  }
@@ -6325,7 +6422,7 @@ function classifyViewLink(viewDir, name, rosterRealpaths) {
6325
6422
  } catch {
6326
6423
  return null;
6327
6424
  }
6328
- const resolved = isAbsolute4(target) ? target : resolve8(viewDir, target);
6425
+ const resolved = isAbsolute4(target) ? target : resolve9(viewDir, target);
6329
6426
  try {
6330
6427
  if (rosterRealpaths.has(realpathSync(resolved))) return null;
6331
6428
  } catch {
@@ -6411,11 +6508,11 @@ async function doRunProjectWorkspace(options, ctx) {
6411
6508
  } else {
6412
6509
  const viewDir = resolveViewDir(repositoryRoot, viewPath);
6413
6510
  const facts = roster.map((entry) => gatherViewRepo(repositoryRoot, viewDir, entry));
6414
- const rosterNames = roster.map((entry) => basename6(resolve8(repositoryRoot, entry.path)));
6511
+ const rosterNames = roster.map((entry) => basename6(resolve9(repositoryRoot, entry.path)));
6415
6512
  const rosterRealpaths = /* @__PURE__ */ new Set();
6416
6513
  for (const entry of roster) {
6417
6514
  try {
6418
- rosterRealpaths.add(realpathSync(resolve8(repositoryRoot, entry.path)));
6515
+ rosterRealpaths.add(realpathSync(resolve9(repositoryRoot, entry.path)));
6419
6516
  } catch {
6420
6517
  }
6421
6518
  }
@@ -6595,7 +6692,7 @@ async function gatherRepoPreset(repositoryRoot, anchorReal, entry) {
6595
6692
  }
6596
6693
  let real;
6597
6694
  try {
6598
- real = realpathSync(resolve8(repositoryRoot, entry.path));
6695
+ real = realpathSync(resolve9(repositoryRoot, entry.path));
6599
6696
  } catch {
6600
6697
  return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };
6601
6698
  }
@@ -6651,7 +6748,7 @@ function viewPresetReposFor(repositoryRoot, roster) {
6651
6748
  anchorReal = void 0;
6652
6749
  }
6653
6750
  return roster.map((entry) => {
6654
- const abs = resolve8(repositoryRoot, entry.path);
6751
+ const abs = resolve9(repositoryRoot, entry.path);
6655
6752
  let real;
6656
6753
  try {
6657
6754
  real = realpathSync(abs);
@@ -6975,7 +7072,7 @@ function gatherArchiveTeardown(repositoryRoot, manifest, target) {
6975
7072
  };
6976
7073
  let real;
6977
7074
  try {
6978
- real = realpathSync(resolve8(repositoryRoot, target));
7075
+ real = realpathSync(resolve9(repositoryRoot, target));
6979
7076
  } catch {
6980
7077
  return empty;
6981
7078
  }
@@ -7024,7 +7121,7 @@ function viewLinkPointsAt(viewDir, name, repoReal) {
7024
7121
  if (!lstatSync(filePath).isSymbolicLink()) return false;
7025
7122
  const target = readlinkSync(filePath);
7026
7123
  if (isAbsolute4(target)) return false;
7027
- return realpathSync(resolve8(viewDir, target)) === repoReal;
7124
+ return realpathSync(resolve9(viewDir, target)) === repoReal;
7028
7125
  } catch {
7029
7126
  return false;
7030
7127
  }
@@ -7035,7 +7132,7 @@ function viewLinkPointsAtPath(viewDir, name, expectedRepoPath) {
7035
7132
  if (!lstatSync(filePath).isSymbolicLink()) return false;
7036
7133
  const target = readlinkSync(filePath);
7037
7134
  if (isAbsolute4(target)) return false;
7038
- return resolve8(viewDir, target) === expectedRepoPath;
7135
+ return resolve9(viewDir, target) === expectedRepoPath;
7039
7136
  } catch {
7040
7137
  return false;
7041
7138
  }
@@ -7044,19 +7141,19 @@ function gatherRepoTeardown(repositoryRoot, manifest, target) {
7044
7141
  const anchorReal = realpathSync(repositoryRoot);
7045
7142
  let repoReal;
7046
7143
  try {
7047
- repoReal = realpathSync(resolve8(repositoryRoot, target));
7144
+ repoReal = realpathSync(resolve9(repositoryRoot, target));
7048
7145
  } catch {
7049
7146
  repoReal = void 0;
7050
7147
  }
7051
7148
  const isAnchor = repoReal !== void 0 && repoReal === anchorReal;
7052
- const targetAbs = resolve8(repositoryRoot, target);
7149
+ const targetAbs = resolve9(repositoryRoot, target);
7053
7150
  const canonicalName = basename6(repoReal ?? targetAbs);
7054
7151
  const roster = manifest.repos ?? [];
7055
7152
  const declaredEntry = roster.find((r) => {
7056
7153
  try {
7057
- return realpathSync(resolve8(repositoryRoot, r.path)) === (repoReal ?? "\0");
7154
+ return realpathSync(resolve9(repositoryRoot, r.path)) === (repoReal ?? "\0");
7058
7155
  } catch {
7059
- return resolve8(repositoryRoot, r.path) === targetAbs;
7156
+ return resolve9(repositoryRoot, r.path) === targetAbs;
7060
7157
  }
7061
7158
  });
7062
7159
  const inRoster = declaredEntry !== void 0;
@@ -7065,7 +7162,7 @@ function gatherRepoTeardown(repositoryRoot, manifest, target) {
7065
7162
  const canonicalShared = roster.some((r) => {
7066
7163
  let rReal = null;
7067
7164
  try {
7068
- rReal = realpathSync(resolve8(repositoryRoot, r.path));
7165
+ rReal = realpathSync(resolve9(repositoryRoot, r.path));
7069
7166
  } catch {
7070
7167
  rReal = null;
7071
7168
  }
@@ -7073,8 +7170,8 @@ function gatherRepoTeardown(repositoryRoot, manifest, target) {
7073
7170
  if (repoReal !== void 0 && rReal === repoReal) return false;
7074
7171
  return basename6(rReal).toLowerCase() === cnFold;
7075
7172
  }
7076
- if (resolve8(repositoryRoot, r.path) === targetAbs) return false;
7077
- return basename6(resolve8(repositoryRoot, r.path)).toLowerCase() === cnFold;
7173
+ if (resolve9(repositoryRoot, r.path) === targetAbs) return false;
7174
+ return basename6(resolve9(repositoryRoot, r.path)).toLowerCase() === cnFold;
7078
7175
  });
7079
7176
  const collisionNote = "shared with another repo of the same basename, so it cannot be removed (check manually)";
7080
7177
  const items = [];
@@ -7255,7 +7352,7 @@ function applyRepoTeardown(repositoryRoot, manifest, plan) {
7255
7352
  const changed = (label) => failed.push({ label, message: "the state changed since the scan (re-run)" });
7256
7353
  let currentRepoReal = null;
7257
7354
  try {
7258
- currentRepoReal = realpathSync(resolve8(repositoryRoot, plan.target));
7355
+ currentRepoReal = realpathSync(resolve9(repositoryRoot, plan.target));
7259
7356
  } catch {
7260
7357
  currentRepoReal = null;
7261
7358
  }
@@ -7290,7 +7387,7 @@ function applyRepoTeardown(repositoryRoot, manifest, plan) {
7290
7387
  continue;
7291
7388
  }
7292
7389
  const viewDir = resolveViewDir(repositoryRoot, viewPath);
7293
- const owned = repoReal !== null ? viewLinkPointsAt(viewDir, item.label, repoReal) : viewLinkPointsAtPath(viewDir, item.label, resolve8(repositoryRoot, plan.target));
7390
+ const owned = repoReal !== null ? viewLinkPointsAt(viewDir, item.label, repoReal) : viewLinkPointsAtPath(viewDir, item.label, resolve9(repositoryRoot, plan.target));
7294
7391
  if (!owned) {
7295
7392
  changed(item.label);
7296
7393
  continue;
@@ -7452,7 +7549,7 @@ async function doRunProjectArchive(target, options, ctx) {
7452
7549
  const roster = manifest.repos ?? [];
7453
7550
  let targetIsAnchor = false;
7454
7551
  try {
7455
- targetIsAnchor = realpathSync(resolve8(repositoryRoot, target)) === realpathSync(repositoryRoot);
7552
+ targetIsAnchor = realpathSync(resolve9(repositoryRoot, target)) === realpathSync(repositoryRoot);
7456
7553
  } catch {
7457
7554
  targetIsAnchor = false;
7458
7555
  }
@@ -7609,7 +7706,7 @@ async function doRunProjectRename(oldPath, newPath, options, ctx) {
7609
7706
  const roster = manifest.repos ?? [];
7610
7707
  let oldIsAnchor = false;
7611
7708
  try {
7612
- oldIsAnchor = realpathSync(resolve8(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);
7709
+ oldIsAnchor = realpathSync(resolve9(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);
7613
7710
  } catch {
7614
7711
  oldIsAnchor = false;
7615
7712
  }
@@ -7755,7 +7852,7 @@ async function doRunProjectNew(repos, options, ctx) {
7755
7852
  const viewStem = productName ?? workspaceName;
7756
7853
  const viewOverridesProjectName = productName !== void 0 && typeof options.view === "string";
7757
7854
  const declared = repos.map((p) => {
7758
- const abs = resolve8(cwd, p);
7855
+ const abs = resolve9(cwd, p);
7759
7856
  let real;
7760
7857
  try {
7761
7858
  real = realpathSync(abs);
@@ -8020,7 +8117,7 @@ function pathPresent(p) {
8020
8117
  }
8021
8118
  function gatherRetrofit(repositoryRoot, anchorReal, roster, argAbs, argReal, viewCanonicalName) {
8022
8119
  const declaredEntry = roster.find((entry) => {
8023
- const entryAbs = resolve8(repositoryRoot, entry.path);
8120
+ const entryAbs = resolve9(repositoryRoot, entry.path);
8024
8121
  if (argReal !== void 0) {
8025
8122
  try {
8026
8123
  if (realpathSync(entryAbs) === argReal) return true;
@@ -8160,7 +8257,7 @@ async function doRunProjectRetrofit(repo, options, ctx) {
8160
8257
  }
8161
8258
  return result2;
8162
8259
  }
8163
- const argAbs = resolve8(repositoryRoot, repo);
8260
+ const argAbs = resolve9(repositoryRoot, repo);
8164
8261
  let argReal;
8165
8262
  try {
8166
8263
  argReal = realpathSync(argAbs);
@@ -8381,7 +8478,7 @@ function renderProjectRetrofit(result) {
8381
8478
  }
8382
8479
 
8383
8480
  // src/commands/protocol.ts
8384
- import { readFile as readFile4, stat as stat5 } from "fs/promises";
8481
+ import { readFile as readFile5, stat as stat5 } from "fs/promises";
8385
8482
  import {
8386
8483
  carryForwardProtocolStamp,
8387
8484
  PROTOCOL_END as PROTOCOL_END2,
@@ -8438,7 +8535,7 @@ async function readProtocolSources(entries) {
8438
8535
  for (const entry of entries) {
8439
8536
  let content;
8440
8537
  try {
8441
- content = await readFile4(entry.source, "utf8");
8538
+ content = await readFile5(entry.source, "utf8");
8442
8539
  } catch (error) {
8443
8540
  if (error instanceof Error && error.code === "ENOENT") {
8444
8541
  throw new Error(
@@ -8571,7 +8668,7 @@ import { InvalidArgumentError as InvalidArgumentError4 } from "commander";
8571
8668
 
8572
8669
  // src/commands/refresh-watch.ts
8573
8670
  import { readdir as readdir2, stat as stat6 } from "fs/promises";
8574
- import { homedir as homedir9 } from "os";
8671
+ import { homedir as homedir10 } from "os";
8575
8672
  import { join as join13 } from "path";
8576
8673
  import { findErrorCode as findErrorCode8 } from "@basou/core";
8577
8674
  var DEFAULT_WATCH_INTERVAL_SEC = 30;
@@ -8579,8 +8676,8 @@ var MIN_WATCH_INTERVAL_SEC = 5;
8579
8676
  var MAX_WATCH_INTERVAL_SEC = 86400;
8580
8677
  function watchedRoots(ctx) {
8581
8678
  return [
8582
- ctx.codexSessionsDir ?? join13(homedir9(), ".codex", "sessions"),
8583
- ctx.claudeProjectsDir ?? join13(homedir9(), ".claude", "projects")
8679
+ ctx.codexSessionsDir ?? join13(homedir10(), ".codex", "sessions"),
8680
+ ctx.claudeProjectsDir ?? join13(homedir10(), ".claude", "projects")
8584
8681
  ];
8585
8682
  }
8586
8683
  async function scanSourceLogs(roots) {
@@ -8701,19 +8798,19 @@ function parseInterval(value) {
8701
8798
  return seconds;
8702
8799
  }
8703
8800
  function abortableSleep(ms, signal) {
8704
- return new Promise((resolve14) => {
8801
+ return new Promise((resolve15) => {
8705
8802
  if (signal.aborted) {
8706
- resolve14();
8803
+ resolve15();
8707
8804
  return;
8708
8805
  }
8709
8806
  let timer;
8710
8807
  const onAbort = () => {
8711
8808
  clearTimeout(timer);
8712
- resolve14();
8809
+ resolve15();
8713
8810
  };
8714
8811
  timer = setTimeout(() => {
8715
8812
  signal.removeEventListener("abort", onAbort);
8716
- resolve14();
8813
+ resolve15();
8717
8814
  }, ms);
8718
8815
  signal.addEventListener("abort", onAbort, { once: true });
8719
8816
  });
@@ -8939,7 +9036,7 @@ async function assertWorkspaceInitialized8(basouRoot) {
8939
9036
  }
8940
9037
 
8941
9038
  // src/commands/report.ts
8942
- import { isAbsolute as isAbsolute5, resolve as resolve9 } from "path";
9039
+ import { isAbsolute as isAbsolute5, resolve as resolve10 } from "path";
8943
9040
  import {
8944
9041
  assertBasouRootSafe as assertBasouRootSafe10,
8945
9042
  basouPaths as basouPaths14,
@@ -8979,7 +9076,7 @@ async function doRunReportGenerate(options, ctx) {
8979
9076
  onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason)
8980
9077
  });
8981
9078
  if (options.out !== void 0) {
8982
- const outPath = isAbsolute5(options.out) ? options.out : resolve9(cwd, options.out);
9079
+ const outPath = isAbsolute5(options.out) ? options.out : resolve10(cwd, options.out);
8983
9080
  await writeMarkdownFile6(outPath, result.body);
8984
9081
  const { sessions, decisions, tasks } = result.data;
8985
9082
  console.error(
@@ -9017,9 +9114,9 @@ async function assertWorkspaceInitialized9(basouRoot) {
9017
9114
  }
9018
9115
 
9019
9116
  // src/commands/review.ts
9020
- import { readFile as readFile5 } from "fs/promises";
9021
- import { homedir as homedir10 } from "os";
9022
- import { resolve as resolve10 } from "path";
9117
+ import { readFile as readFile6 } from "fs/promises";
9118
+ import { homedir as homedir11 } from "os";
9119
+ import { resolve as resolve11 } from "path";
9023
9120
  import {
9024
9121
  assertBasouRootSafe as assertBasouRootSafe11,
9025
9122
  basouPaths as basouPaths15,
@@ -9031,7 +9128,7 @@ import {
9031
9128
  parseReviewRecordInput,
9032
9129
  readManifest as readManifest9,
9033
9130
  resolveRepoRoot,
9034
- sanitizePath as sanitizePath2
9131
+ sanitizePath as sanitizePath3
9035
9132
  } from "@basou/core";
9036
9133
  function registerReviewCommand(program2) {
9037
9134
  const review = program2.command("review").description("Record reviews that ran (the durable signal a review happened)");
@@ -9119,9 +9216,9 @@ async function doRunReviewRecord(options, ctx) {
9119
9216
  const manifest = await readManifest9(paths);
9120
9217
  const invocationArgs = options.file !== void 0 ? [
9121
9218
  "--file",
9122
- sanitizePath2(resolve10(cwd, options.file), {
9219
+ sanitizePath3(resolve11(cwd, options.file), {
9123
9220
  workingDirectory: repositoryRoot,
9124
- homedir: homedir10()
9221
+ homedir: homedir11()
9125
9222
  })
9126
9223
  ] : [];
9127
9224
  const adHoc = await createAdHocSessionWithEvent3({
@@ -9161,7 +9258,7 @@ ${detail}
9161
9258
  async function readReviewInput(options, ctx) {
9162
9259
  if (options.file !== void 0) {
9163
9260
  try {
9164
- return await readFile5(options.file, "utf8");
9261
+ return await readFile6(options.file, "utf8");
9165
9262
  } catch (error) {
9166
9263
  if (findErrorCode11(error, "ENOENT")) {
9167
9264
  throw new Error(`Input file not found: ${options.file}`);
@@ -9173,18 +9270,18 @@ async function readReviewInput(options, ctx) {
9173
9270
  return await ctx.readInput();
9174
9271
  }
9175
9272
  if (process.stdin.isTTY === true) {
9176
- throw new Error(NO_INPUT_HINT2);
9273
+ throw new Error(NO_INPUT_HINT3);
9177
9274
  }
9178
- return await readStdinToEnd2();
9275
+ return await readStdinToEnd3();
9179
9276
  }
9180
- async function readStdinToEnd2() {
9277
+ async function readStdinToEnd3() {
9181
9278
  const chunks = [];
9182
9279
  for await (const chunk of process.stdin) {
9183
9280
  chunks.push(Buffer.from(chunk));
9184
9281
  }
9185
9282
  return Buffer.concat(chunks).toString("utf8");
9186
9283
  }
9187
- var NO_INPUT_HINT2 = "No input: pipe a JSON object describing the review to stdin or pass --file <path>.";
9284
+ var NO_INPUT_HINT3 = "No input: pipe a JSON object describing the review to stdin or pass --file <path>.";
9188
9285
  function reviewToPayload(review) {
9189
9286
  const payload = {
9190
9287
  reviewer: review.reviewer,
@@ -9454,8 +9551,8 @@ function unattachedLines(u) {
9454
9551
  }
9455
9552
 
9456
9553
  // src/commands/run.ts
9457
- import { mkdir as mkdir2, readFile as readFile6 } from "fs/promises";
9458
- import { homedir as homedir11 } from "os";
9554
+ import { mkdir as mkdir2, readFile as readFile7 } from "fs/promises";
9555
+ import { homedir as homedir12 } from "os";
9459
9556
  import { join as join14 } from "path";
9460
9557
  import {
9461
9558
  acquireLock as acquireLock5,
@@ -9681,7 +9778,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
9681
9778
  const rawRelated = computeRelatedFiles(preSnapshot, postSnapshot, diff);
9682
9779
  const relatedFiles = sanitizeRelatedFiles(rawRelated, {
9683
9780
  workingDirectory: repoRoot,
9684
- homedir: homedir11()
9781
+ homedir: homedir12()
9685
9782
  }).sanitized;
9686
9783
  const finalStatus = decideFinalStatus2(result, signalReceived);
9687
9784
  await appendEvent(sessionDir, {
@@ -9825,7 +9922,7 @@ function buildInitialSession2(input) {
9825
9922
  source: { ...input.source },
9826
9923
  started_at: input.startedAt,
9827
9924
  status: "initialized",
9828
- working_directory: sanitizeWorkingDirectory2(input.cwd, { homedir: homedir11() }),
9925
+ working_directory: sanitizeWorkingDirectory2(input.cwd, { homedir: homedir12() }),
9829
9926
  invocation: {
9830
9927
  command: input.command,
9831
9928
  args: [...input.args],
@@ -9901,7 +9998,7 @@ async function noteCodexHookStatusPreSpawn(_cwd, ctx) {
9901
9998
  const hooksPath = ctx.codexHooksPath ?? DEFAULT_CODEX_HOOKS_PATH;
9902
9999
  let location;
9903
10000
  try {
9904
- location = findBasouSessionStartHook2(JSON.parse(await readFile6(hooksPath, "utf8")));
10001
+ location = findBasouSessionStartHook2(JSON.parse(await readFile7(hooksPath, "utf8")));
9905
10002
  } catch (error) {
9906
10003
  if (!(error instanceof Error && error.code === "ENOENT")) return null;
9907
10004
  location = null;
@@ -9915,7 +10012,7 @@ async function noteCodexHookStatusPreSpawn(_cwd, ctx) {
9915
10012
  }
9916
10013
 
9917
10014
  // src/commands/session.ts
9918
- import { readFile as readFile7 } from "fs/promises";
10015
+ import { readFile as readFile8 } from "fs/promises";
9919
10016
  import { basename as basename7, isAbsolute as isAbsolute6, join as join15, relative as relative3, sep as sep2 } from "path";
9920
10017
  import {
9921
10018
  acquireLock as acquireLock6,
@@ -9929,6 +10026,7 @@ import {
9929
10026
  importSessionFromJson as importSessionFromJson2,
9930
10027
  LOCAL_CLI_EVENT_SOURCE as LOCAL_CLI_EVENT_SOURCE4,
9931
10028
  loadSessionEntries as loadSessionEntries2,
10029
+ normalizeSessionTimestamps,
9932
10030
  readAllEvents,
9933
10031
  readManifest as readManifest11,
9934
10032
  readObservedDuration,
@@ -10051,7 +10149,7 @@ async function doRunSessionShow(idInput, options, ctx) {
10051
10149
  let session;
10052
10150
  try {
10053
10151
  const raw = await readYamlFile7(sessionYamlPath);
10054
- session = SessionSchema3.parse(raw);
10152
+ session = SessionSchema3.parse(normalizeSessionTimestamps(raw));
10055
10153
  } catch (error) {
10056
10154
  if (findErrorCode12(error, "ENOENT")) {
10057
10155
  throw new Error(`Session not found: ${idInput}`);
@@ -10386,7 +10484,7 @@ async function doRunSessionImport(options, ctx) {
10386
10484
  }
10387
10485
  async function readInputFile(path) {
10388
10486
  try {
10389
- return await readFile7(path, "utf8");
10487
+ return await readFile8(path, "utf8");
10390
10488
  } catch (error) {
10391
10489
  if (findErrorCode12(error, "ENOENT")) {
10392
10490
  throw new Error("Import source not found", { cause: error });
@@ -10503,7 +10601,7 @@ async function doRunSessionNote(sessionIdInput, options, ctx) {
10503
10601
  }
10504
10602
  async function readNoteFile(path) {
10505
10603
  try {
10506
- return await readFile7(path, "utf8");
10604
+ return await readFile8(path, "utf8");
10507
10605
  } catch (error) {
10508
10606
  if (findErrorCode12(error, "ENOENT")) {
10509
10607
  throw new Error("Note source not found", { cause: error });
@@ -10828,7 +10926,7 @@ function formatVersionGateMessage(error) {
10828
10926
  }
10829
10927
 
10830
10928
  // src/commands/task.ts
10831
- import { readFile as readFile8 } from "fs/promises";
10929
+ import { readFile as readFile9 } from "fs/promises";
10832
10930
  import { join as join16 } from "path";
10833
10931
  import {
10834
10932
  archiveTask,
@@ -11843,7 +11941,7 @@ function parsePositiveInt2(raw) {
11843
11941
  }
11844
11942
  async function readDescriptionFile(path) {
11845
11943
  try {
11846
- return await readFile8(path, "utf8");
11944
+ return await readFile9(path, "utf8");
11847
11945
  } catch (error) {
11848
11946
  if (findErrorCode15(error, "ENOENT")) {
11849
11947
  throw new Error("Description source not found", { cause: error });
@@ -12048,7 +12146,7 @@ async function assertWorkspaceInitialized14(basouRoot) {
12048
12146
  // src/commands/view.ts
12049
12147
  import { spawn } from "child_process";
12050
12148
  import { createHash as createHash2 } from "crypto";
12051
- import { basename as basename10, resolve as resolve13 } from "path";
12149
+ import { basename as basename10, resolve as resolve14 } from "path";
12052
12150
  import {
12053
12151
  assertBasouRootSafe as assertBasouRootSafe18,
12054
12152
  basouPaths as basouPaths24,
@@ -12061,7 +12159,7 @@ import { InvalidArgumentError as InvalidArgumentError8 } from "commander";
12061
12159
  // src/lib/portfolio-coverage.ts
12062
12160
  import { createReadStream as createReadStream2 } from "fs";
12063
12161
  import { readdir as readdir3, stat as stat7 } from "fs/promises";
12064
- import { homedir as homedir12 } from "os";
12162
+ import { homedir as homedir13 } from "os";
12065
12163
  import { basename as basename8, dirname as dirname5, join as join17 } from "path";
12066
12164
  import { createInterface as createInterface2 } from "readline";
12067
12165
  import { basouPaths as basouPaths23, readManifest as readManifest14, resolveRepositoryRoot as resolveRepositoryRoot13 } from "@basou/core";
@@ -12071,8 +12169,8 @@ function uncapturedTotal(result) {
12071
12169
  async function checkPortfolioCoverage(workspaces, ctx = {}) {
12072
12170
  const { roots, inertWorkspaces } = await collectDeclaredRoots(workspaces);
12073
12171
  const listedDirs = new Set([...roots].map((root) => encodeProjectDir(root)));
12074
- const claudeProjectsDir = ctx.claudeProjectsDir ?? join17(homedir12(), ".claude", "projects");
12075
- const codexSessionsDir = ctx.codexSessionsDir ?? join17(homedir12(), ".codex", "sessions");
12172
+ const claudeProjectsDir = ctx.claudeProjectsDir ?? join17(homedir13(), ".claude", "projects");
12173
+ const codexSessionsDir = ctx.codexSessionsDir ?? join17(homedir13(), ".codex", "sessions");
12076
12174
  const tally = new Tally(roots);
12077
12175
  const absentTrees = [];
12078
12176
  const claudeFiles = await listClaudeTranscripts(claudeProjectsDir);
@@ -12376,7 +12474,7 @@ function inertLines(result) {
12376
12474
  // src/lib/portfolio-safety.ts
12377
12475
  import { execFile as execFile2 } from "child_process";
12378
12476
  import { lstat as lstat2, realpath as realpath4 } from "fs/promises";
12379
- import { isAbsolute as isAbsolute7, join as join18, relative as relative4, resolve as resolve11, sep as sep3 } from "path";
12477
+ import { isAbsolute as isAbsolute7, join as join18, relative as relative4, resolve as resolve12, sep as sep3 } from "path";
12380
12478
  import { promisify as promisify2 } from "util";
12381
12479
  import { readManifest as readManifest15 } from "@basou/core";
12382
12480
  var execFileAsync2 = promisify2(execFile2);
@@ -12387,7 +12485,7 @@ async function canonical(p) {
12387
12485
  try {
12388
12486
  return await realpath4(p);
12389
12487
  } catch {
12390
- return resolve11(p);
12488
+ return resolve12(p);
12391
12489
  }
12392
12490
  }
12393
12491
  function isInside(child, parent) {
@@ -12455,13 +12553,13 @@ async function checkPortfolioSafety(workspaces) {
12455
12553
  }
12456
12554
  const monitored = /* @__PURE__ */ new Map();
12457
12555
  for (const root of sourceRoots) {
12458
- const display = resolve11(ws.repoRoot, root);
12556
+ const display = resolve12(ws.repoRoot, root);
12459
12557
  const real = await canonical(display);
12460
12558
  if (real !== wsReal) monitored.set(real, display);
12461
12559
  }
12462
12560
  const claimed = new Set(monitored.keys());
12463
12561
  if (isMaster && viewPath !== void 0) {
12464
- const viewReal = await canonical(resolve11(ws.repoRoot, viewPath));
12562
+ const viewReal = await canonical(resolve12(ws.repoRoot, viewPath));
12465
12563
  if (viewReal !== wsReal) claimed.add(viewReal);
12466
12564
  }
12467
12565
  records.push({ ws, real: wsReal, isMaster, claimed });
@@ -12554,7 +12652,7 @@ function formatSafetyReport(result) {
12554
12652
 
12555
12653
  // src/lib/view-server.ts
12556
12654
  import { createServer } from "http";
12557
- import { basename as basename9, join as join19, resolve as resolve12 } from "path";
12655
+ import { basename as basename9, join as join19, resolve as resolve13 } from "path";
12558
12656
  import {
12559
12657
  computeWorkStats as computeWorkStats2,
12560
12658
  enumerateApprovals as enumerateApprovals2,
@@ -13308,7 +13406,7 @@ function startViewServer(opts) {
13308
13406
  };
13309
13407
  let boundPort = port;
13310
13408
  const getPort = () => boundPort;
13311
- return new Promise((resolve14, reject) => {
13409
+ return new Promise((resolve15, reject) => {
13312
13410
  const server = createServer((req, res) => {
13313
13411
  handleRequest(req, res, deps, getPort, runExclusive).catch((error) => {
13314
13412
  sendError(res, error instanceof HttpError ? error.status : 500, pathlessMessage(error));
@@ -13319,7 +13417,7 @@ function startViewServer(opts) {
13319
13417
  const address = server.address();
13320
13418
  boundPort = isAddressInfo(address) ? address.port : port;
13321
13419
  server.off("error", reject);
13322
- resolve14({
13420
+ resolve15({
13323
13421
  url: `http://${host}:${boundPort}`,
13324
13422
  port: boundPort,
13325
13423
  close: () => closeServer(server)
@@ -13331,8 +13429,8 @@ function isAddressInfo(value) {
13331
13429
  return value !== null && typeof value === "object";
13332
13430
  }
13333
13431
  function closeServer(server) {
13334
- return new Promise((resolve14) => {
13335
- server.close(() => resolve14());
13432
+ return new Promise((resolve15) => {
13433
+ server.close(() => resolve15());
13336
13434
  server.closeAllConnections();
13337
13435
  });
13338
13436
  }
@@ -13604,7 +13702,7 @@ async function rosterRepos(repoRoot, manifest, resolveRemoteUrl) {
13604
13702
  const roster = manifest.repos ?? [];
13605
13703
  return Promise.all(
13606
13704
  roster.map(async (repo) => {
13607
- const abs = resolve12(repoRoot, repo.path);
13705
+ const abs = resolve13(repoRoot, repo.path);
13608
13706
  const remote = await resolveRemoteUrl(abs);
13609
13707
  const url = remote !== void 0 ? toBrowserUrl(remote) : null;
13610
13708
  return {
@@ -13880,12 +13978,12 @@ async function buildSingleDeps(ctx, cwd) {
13880
13978
  };
13881
13979
  }
13882
13980
  async function buildPortfolioDeps(workspaceFlags, ctx, cwd) {
13883
- const specs = workspaceFlags.length > 0 ? workspaceFlags.map((p) => ({ path: resolve13(cwd, p) })) : await loadPortfolioConfig(ctx.portfolioConfigPath);
13981
+ const specs = workspaceFlags.length > 0 ? workspaceFlags.map((p) => ({ path: resolve14(cwd, p) })) : await loadPortfolioConfig(ctx.portfolioConfigPath);
13884
13982
  const entries = [];
13885
13983
  const seenPath = /* @__PURE__ */ new Set();
13886
13984
  const seenKey = /* @__PURE__ */ new Set();
13887
13985
  for (const spec of specs) {
13888
- const repoRoot = resolve13(spec.path);
13986
+ const repoRoot = resolve14(spec.path);
13889
13987
  if (seenPath.has(repoRoot)) continue;
13890
13988
  seenPath.add(repoRoot);
13891
13989
  const entry = await buildWorkspaceEntry(repoRoot, ctx, spec.label);
@@ -13962,7 +14060,7 @@ function openInBrowser(url, override) {
13962
14060
  }
13963
14061
  }
13964
14062
  function waitForShutdown(signal) {
13965
- return new Promise((resolve14) => {
14063
+ return new Promise((resolve15) => {
13966
14064
  const cleanup = () => {
13967
14065
  process.off("SIGINT", onSignal);
13968
14066
  process.off("SIGTERM", onSignal);
@@ -13970,18 +14068,18 @@ function waitForShutdown(signal) {
13970
14068
  };
13971
14069
  const onSignal = () => {
13972
14070
  cleanup();
13973
- resolve14();
14071
+ resolve15();
13974
14072
  };
13975
14073
  const onAbort = () => {
13976
14074
  cleanup();
13977
- resolve14();
14075
+ resolve15();
13978
14076
  };
13979
14077
  process.on("SIGINT", onSignal);
13980
14078
  process.on("SIGTERM", onSignal);
13981
14079
  if (signal !== void 0) {
13982
14080
  if (signal.aborted) {
13983
14081
  cleanup();
13984
- resolve14();
14082
+ resolve15();
13985
14083
  return;
13986
14084
  }
13987
14085
  signal.addEventListener("abort", onAbort);
@@ -14015,7 +14113,7 @@ async function assertWorkspaceInitialized15(basouRoot) {
14015
14113
  function readBuildStamp() {
14016
14114
  if (false) return void 0;
14017
14115
  try {
14018
- return JSON.parse('{"version":"0.53.0","commit":"b27ba83","committedAt":"2026-09-25T17:22:51+09:00"}');
14116
+ return JSON.parse('{"version":"0.55.0","commit":"c59daeb","committedAt":"2026-09-30T10:04:37+09:00"}');
14019
14117
  } catch {
14020
14118
  return void 0;
14021
14119
  }