@basou/cli 0.66.0 → 0.67.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
@@ -842,6 +842,7 @@ import {
842
842
  displayPath as displayPath3,
843
843
  findErrorCode as findErrorCode3,
844
844
  measureBoard,
845
+ measureBoardLive,
845
846
  NO_PREVIOUS_RECORDS,
846
847
  parseBoardDeclaration,
847
848
  parseRecordInput,
@@ -1517,7 +1518,13 @@ async function assertWorkspaceInitialized2(basouRoot) {
1517
1518
  }
1518
1519
 
1519
1520
  // src/lib/provenance-actions.ts
1520
- async function captureImportJson(fn) {
1521
+ var capturing = Promise.resolve();
1522
+ function captureImportJson(fn) {
1523
+ const turn = capturing.then(() => captureNow(fn));
1524
+ capturing = turn.catch(() => void 0);
1525
+ return turn;
1526
+ }
1527
+ async function captureNow(fn) {
1521
1528
  const stdout = [];
1522
1529
  const originalLog = console.log;
1523
1530
  const originalError = console.error;
@@ -2026,6 +2033,41 @@ async function measureLoaded(loaded, ctx, model, previous) {
2026
2033
  previous
2027
2034
  });
2028
2035
  }
2036
+ async function measureLiveBoard(root, ctx) {
2037
+ const paths = basouPaths4(root);
2038
+ let repos = ["."];
2039
+ let manifestUnread = false;
2040
+ try {
2041
+ const declared = ((await readManifest3(paths)).repos ?? []).map((repo) => repo.path);
2042
+ if (declared.length > 0) repos = declared;
2043
+ } catch {
2044
+ manifestUnread = true;
2045
+ }
2046
+ const now = ctx.nowProvider?.() ?? /* @__PURE__ */ new Date();
2047
+ const probeCtx = { cwd: root };
2048
+ if (ctx.claudeProjectsDir !== void 0) probeCtx.claudeProjectsDir = ctx.claudeProjectsDir;
2049
+ if (ctx.codexSessionsDir !== void 0) probeCtx.codexSessionsDir = ctx.codexSessionsDir;
2050
+ const measured = await measureBoardLive({
2051
+ root,
2052
+ repos,
2053
+ paths,
2054
+ now,
2055
+ measuredWith: { basou: BASOU_CLI_VERSION, build: BASOU_BUILD?.commit ?? null },
2056
+ probeImports: () => probeStaleness({ ctx: probeCtx, paths, nowIso: now.toISOString() })
2057
+ });
2058
+ if (!manifestUnread) return measured;
2059
+ return {
2060
+ ...measured,
2061
+ complete: false,
2062
+ not_found: [
2063
+ {
2064
+ at: "repos",
2065
+ reason: "the manifest could not be read, so only the workspace's own repo was measured"
2066
+ },
2067
+ ...measured.not_found
2068
+ ]
2069
+ };
2070
+ }
2029
2071
  function boardPath(options, cwd, root, manifest) {
2030
2072
  if (options.board !== void 0)
2031
2073
  return { path: resolve3(cwd, options.board), shown: options.board, given: true };
@@ -13236,6 +13278,7 @@ function formatSafetyReport(result) {
13236
13278
  import { createServer } from "http";
13237
13279
  import { basename as basename10, join as join18, resolve as resolve13 } from "path";
13238
13280
  import {
13281
+ boardLivePage,
13239
13282
  boardPage,
13240
13283
  boardPageStrings,
13241
13284
  boardPageUnavailable,
@@ -13377,6 +13420,7 @@ var BOARD_HTML = `<!doctype html>
13377
13420
  if (k === 'text') node.textContent = attrs[k];
13378
13421
  else if (k === 'class') node.className = attrs[k];
13379
13422
  else if (k === 'onchange') node.addEventListener('change', attrs[k]);
13423
+ else if (k === 'onclick') node.addEventListener('click', attrs[k]);
13380
13424
  else node.setAttribute(k, attrs[k]);
13381
13425
  });
13382
13426
  }
@@ -13470,7 +13514,11 @@ var BOARD_HTML = `<!doctype html>
13470
13514
  clear(nav);
13471
13515
  var page = d.page;
13472
13516
  var list = page.records || [];
13473
- if (list.length === 0) return;
13517
+ if (list.length > 0) recordLinks(nav, page, list);
13518
+ nav.appendChild(el('a', { href: '/board?live=1', text: S.live.measureNow }));
13519
+ }
13520
+
13521
+ function recordLinks(nav, page, list) {
13474
13522
  var link = function (id, label) {
13475
13523
  return el('a', { href: '/board?record=' + encodeURIComponent(id), text: label });
13476
13524
  };
@@ -13951,8 +13999,12 @@ var BOARD_HTML = `<!doctype html>
13951
13999
  not_found: S.unavailable.notFound, not_json: S.unavailable.notJson,
13952
14000
  unknown_version: S.unavailable.unknownVersion, not_a_record: S.unavailable.notARecord
13953
14001
  };
13954
- var quiet = page.why === 'no_board' || page.why === 'no_records';
13955
- setStatus(fill(messages[page.why] || page.why, { record: page.id || '', version: page.version }), !quiet);
14002
+ // With no board or no record yet, draw what basou measures now instead.
14003
+ if (page.why === 'no_board' || page.why === 'no_records') {
14004
+ loadLive(page.why);
14005
+ return;
14006
+ }
14007
+ setStatus(fill(messages[page.why] || page.why, { record: page.id || '', version: page.version }), true);
13956
14008
  return;
13957
14009
  }
13958
14010
  setStatus('', false);
@@ -13961,17 +14013,153 @@ var BOARD_HTML = `<!doctype html>
13961
14013
  .forEach(function (node) { root.appendChild(node); });
13962
14014
  }
13963
14015
 
13964
- var record = new URLSearchParams(location.search).get('record');
13965
- setStatus('...', false);
13966
- fetch('/api/board' + (record ? '/' + encodeURIComponent(record) : ''))
13967
- .then(function (res) {
14016
+ // The board measured now: the sections basou measures with nothing declared
14017
+ // or judged. why is the reason there was no record to draw, or null when
14018
+ // asked for with ?live=1.
14019
+ function liveTile(k, v, sub) {
14020
+ return el('div', { class: 'tile' }, [
14021
+ el('div', { class: 'k', text: k }), el('div', { class: 'v', text: v }),
14022
+ sub ? el('div', { class: 's', text: sub }) : null
14023
+ ]);
14024
+ }
14025
+ function liveHeading(l, why) {
14026
+ var h = l.heading;
14027
+ var measured = h.complete ? S.heading.complete : fill(S.heading.incomplete, { n: h.not_found });
14028
+ var again = el('button', { type: 'button', text: S.live.remeasure, onclick: function () { loadLive(why); } });
14029
+ return el('header', null, [
14030
+ el('h1', { text: h.title }),
14031
+ el('div', { class: 'stamp' }, [fill(S.live.measuredAt, { at: when(h.measured_at) }) + ' / ' + measured + ' ', again])
14032
+ ]);
14033
+ }
14034
+ // Whether the measurement says why the value at a place was not measured.
14035
+ function missingIn(l) {
14036
+ return function (at) { return l.footnotes.not_found.some(function (n) { return n.at === at; }); };
14037
+ }
14038
+ function liveRepos(l) {
14039
+ var missing = missingIn(l);
14040
+ var labels = [S.live.repo, S.live.branch, S.live.head, S.live.lastCommit, S.live.commits, S.live.uncommitted, S.live.behindMain];
14041
+ var head = el('tr', null, labels.map(function (label, i) { return el('th', { class: i >= 4 ? 'n' : '', text: label }); }));
14042
+ var rows = l.repos.map(function (r) {
14043
+ var at = 'repos[' + r.path + ']';
14044
+ // A null the measurement says it could not measure, or one that means
14045
+ // so (a detached HEAD, no commit yet, no origin/main), drawn as '-'.
14046
+ var value = function (field, v, show) {
14047
+ if (v !== null) return show(v);
14048
+ return missing(at) || missing(at + '.' + field) ? S.tiles.notMeasured : '-';
14049
+ };
14050
+ return el('tr', null, [
14051
+ el('td', { text: r.name === null ? r.path : r.name }),
14052
+ el('td', { text: value('branch', r.branch, String) }),
14053
+ el('td', { text: value('head', r.head, function (h) { return h.slice(0, 7); }) }),
14054
+ el('td', { text: value('last_commit', r.last_commit, when) }),
14055
+ el('td', { class: 'n', text: num(r.commits) }),
14056
+ el('td', { class: 'n', text: num(r.uncommitted) }),
14057
+ el('td', { class: 'n', text: value('behind_main', r.behind_main, num) })
14058
+ ]);
14059
+ });
14060
+ return section(S.live.repos, false, [el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [head].concat(rows))])]);
14061
+ }
14062
+ function liveTrail(l) {
14063
+ var t = l.trail;
14064
+ var i = l.integrity;
14065
+ var f = l.freshness;
14066
+ var missing = missingIn(l);
14067
+ var newest = f.newest_session_at !== null ? when(f.newest_session_at)
14068
+ : missing('freshness.newest_session_at') ? S.tiles.notMeasured : S.live.noSession;
14069
+ var unimported = f.unimported === null ? S.live.unimportedNotMeasured : fill(S.live.unimported, {
14070
+ new: f.unimported.new, updated: f.unimported.updated, unverifiable: f.unimported.unverifiable
14071
+ });
14072
+ var counts = function (byKey) {
14073
+ if (byKey === null) return S.tiles.notMeasured;
14074
+ return Object.keys(byKey).map(function (k) { return k + ' ' + num(byKey[k]); }).join(' / ');
14075
+ };
14076
+ var tiles = el('div', { class: 'tiles' }, [
14077
+ liveTile(S.live.decisions, num(t.decisions_live), t.decisions_all === null ? null : fill(S.live.decisionsAll, { n: num(t.decisions_all) })),
14078
+ liveTile(S.tiles.openTracks, t.tracks_open === null ? S.tiles.notMeasured : num(t.tracks_open.length), null),
14079
+ liveTile(S.tiles.sessions, num(i.sessions), i.not_verified === null ? null : fill(S.tiles.sessionsNotVerified, { n: num(i.not_verified) })),
14080
+ liveTile(S.live.reviewGaps, num(l.review_gaps.gaps), null),
14081
+ liveTile(S.live.newestSession, newest, unimported)
14082
+ ]);
14083
+ var tracks = t.tracks_open === null ? el('p', { class: 'muted', text: S.tiles.notMeasured })
14084
+ : t.tracks_open.length === 0 ? el('p', { class: 'muted', text: S.live.noTracks })
14085
+ : el('ul', null, t.tracks_open.map(function (tr) {
14086
+ return el('li', null, [el('span', { class: 'muted', text: tr.id + ' ' }), tr.title]);
14087
+ }));
14088
+ var breakdown = el('div', { class: 'muted' }, [
14089
+ el('div', { text: fill(S.live.byStatus, { list: counts(i.by_status) }) }),
14090
+ el('div', { text: fill(S.live.byVerdict, { list: counts(l.review_gaps.by_verdict) }) })
14091
+ ]);
14092
+ return section(S.live.trail, false, [tiles, breakdown, el('h3', { text: S.live.tracks }), tracks]);
14093
+ }
14094
+ function liveComponents(l) {
14095
+ var c = l.components;
14096
+ var body = c === null ? el('p', { class: 'muted', text: S.tiles.notMeasured })
14097
+ : c.length === 0 ? el('p', { class: 'muted', text: S.live.noComponents })
14098
+ : el('ul', null, c.map(function (x) {
14099
+ return el('li', null, [el('code', { text: x.key }), el('span', { class: 'muted', text: ' ' + x.kinds.join(', ') })]);
14100
+ }));
14101
+ return section(S.live.components, false, [body]);
14102
+ }
14103
+ function liveFootnotes(l, why) {
14104
+ var f = l.footnotes;
14105
+ var items = [el('li', { text: S.live.note }), el('li', { text: S.live.judged })];
14106
+ if (why === 'no_board') items.push(el('li', { text: S.unavailable.noBoard }));
14107
+ if (f.not_found.length > 0) {
14108
+ items.push(el('li', null, [el('b', { text: S.footnotes.notMeasured }), el('ul', null, f.not_found.map(function (n) {
14109
+ return el('li', { text: n.at + ': ' + n.reason });
14110
+ }))]));
14111
+ }
14112
+ var build = f.measured_with.build === null ? '' : ' (' + f.measured_with.build + ')';
14113
+ items.push(el('li', { text: fill(S.footnotes.measuredWith, { basou: f.measured_with.basou, build: build }) }));
14114
+ return section(S.sections.footnotes, false, [el('ul', { class: 'foot' }, items)]);
14115
+ }
14116
+ var liveDrawn = 0;
14117
+ function drawLive(d, why) {
14118
+ S = d.strings;
14119
+ lang = d.language;
14120
+ document.documentElement.lang = lang;
14121
+ document.title = S.pageTitle;
14122
+ var drawn = ++liveDrawn;
14123
+ var nav = $('records');
14124
+ clear(nav);
14125
+ // Asked for with ?live=1: lead back to the records, when there are any.
14126
+ if (why === null) {
14127
+ getJson('/api/board').then(function (b) {
14128
+ var list = b && b.page && b.page.records ? b.page.records : [];
14129
+ if (drawn === liveDrawn && list.length > 0) nav.appendChild(el('a', { href: '/board', text: S.live.toRecords }));
14130
+ }).catch(function () {});
14131
+ }
14132
+ var root = $('board');
14133
+ clear(root);
14134
+ setStatus('', false);
14135
+ var l = d.live;
14136
+ [liveHeading(l, why), effort(l), liveRepos(l), liveTrail(l), liveComponents(l), liveFootnotes(l, why)]
14137
+ .forEach(function (node) { root.appendChild(node); });
14138
+ }
14139
+
14140
+ function getJson(url) {
14141
+ return fetch(url).then(function (res) {
13968
14142
  return res.json().then(function (body) {
13969
14143
  if (!res.ok) throw new Error(body && body.error ? body.error : String(res.status));
13970
14144
  return body;
13971
14145
  });
13972
- })
13973
- .then(draw)
13974
- .catch(function (err) { setStatus(S ? fill(S.loadFailed, { message: err.message }) : String(err.message), true); });
14146
+ });
14147
+ }
14148
+ function failed(err) { setStatus(S ? fill(S.loadFailed, { message: err.message }) : String(err.message), true); }
14149
+ // Measuring takes seconds, so the page says so until it is done.
14150
+ function loadLive(why) {
14151
+ setStatus(S ? S.live.measuring : '...', false);
14152
+ getJson('/api/board/live').then(function (d) { drawLive(d, why); }).catch(failed);
14153
+ }
14154
+
14155
+ var params = new URLSearchParams(location.search);
14156
+ var record = params.get('record');
14157
+ if (params.get('live') !== null) {
14158
+ loadLive(null);
14159
+ } else {
14160
+ setStatus('...', false);
14161
+ getJson('/api/board' + (record ? '/' + encodeURIComponent(record) : '')).then(draw).catch(failed);
14162
+ }
13975
14163
  })();
13976
14164
  </script>
13977
14165
  </body>
@@ -14792,7 +14980,8 @@ async function handleGet(res, pathname, deps) {
14792
14980
  ws,
14793
14981
  deps.nowProvider,
14794
14982
  remoteUrlOf(deps),
14795
- boardOf(deps)
14983
+ boardOf(deps),
14984
+ boardLiveOf(deps)
14796
14985
  )) {
14797
14986
  sendError(res, 404, "Not found");
14798
14987
  }
@@ -14806,7 +14995,8 @@ async function handleGet(res, pathname, deps) {
14806
14995
  primaryWorkspace(deps),
14807
14996
  deps.nowProvider,
14808
14997
  remoteUrlOf(deps),
14809
- boardOf(deps)
14998
+ boardOf(deps),
14999
+ boardLiveOf(deps)
14810
15000
  )) {
14811
15001
  sendError(res, 404, "Not found");
14812
15002
  }
@@ -14817,6 +15007,9 @@ async function handleGet(res, pathname, deps) {
14817
15007
  function boardOf(deps) {
14818
15008
  return deps.mode === "single" ? deps.board : void 0;
14819
15009
  }
15010
+ function boardLiveOf(deps) {
15011
+ return deps.mode === "single" ? deps.boardLive : void 0;
15012
+ }
14820
15013
  function remoteUrlOf(deps) {
14821
15014
  return deps.remoteUrlOf ?? tryRemoteUrl;
14822
15015
  }
@@ -14842,7 +15035,11 @@ async function handlePost(res, pathname, body, deps, runExclusive) {
14842
15035
  }
14843
15036
  sendError(res, 404, "Not found");
14844
15037
  }
14845
- async function handleWorkspaceGet(res, sub, ws, nowProvider, resolveRemoteUrl, board) {
15038
+ async function handleWorkspaceGet(res, sub, ws, nowProvider, resolveRemoteUrl, board, live) {
15039
+ if (live !== void 0 && sub === "board/live") {
15040
+ sendJson(res, 200, await boardLiveView(ws, live));
15041
+ return true;
15042
+ }
14846
15043
  if (board !== void 0) {
14847
15044
  if (sub === "board") {
14848
15045
  sendJson(res, 200, await boardView(ws, board, void 0));
@@ -14958,6 +15155,14 @@ async function boardView(ws, board, recordId) {
14958
15155
  const page = "why" in board ? boardPageUnavailable(board.why) : await boardPage(board.recordsDir, recordId);
14959
15156
  return { language, strings: boardPageStrings(language), page };
14960
15157
  }
15158
+ async function boardLiveView(ws, live) {
15159
+ const language = await resolveViewLanguageFromPaths(ws.paths);
15160
+ return {
15161
+ language,
15162
+ strings: boardPageStrings(language),
15163
+ live: boardLivePage(ws.label, await live())
15164
+ };
15165
+ }
14961
15166
  async function portfolio(deps) {
14962
15167
  const nowIso = deps.nowProvider().toISOString();
14963
15168
  const workspaces = await Promise.all(deps.workspaces.map((ws) => portfolioCard(ws, nowIso)));
@@ -15330,7 +15535,26 @@ async function buildSingleDeps(ctx, cwd) {
15330
15535
  mode: "single",
15331
15536
  nowProvider: nowProviderOf(ctx),
15332
15537
  ...ctx.remoteUrlOf !== void 0 ? { remoteUrlOf: ctx.remoteUrlOf } : {},
15333
- board: await viewBoardOf(repositoryRoot, paths)
15538
+ board: await viewBoardOf(repositoryRoot, paths),
15539
+ boardLive: liveBoardOf(repositoryRoot, ctx)
15540
+ };
15541
+ }
15542
+ function liveBoardOf(root, ctx) {
15543
+ return sharedWhileRunning(
15544
+ () => measureLiveBoard(root, {
15545
+ ...ctx.nowProvider !== void 0 ? { nowProvider: ctx.nowProvider } : {},
15546
+ ...ctx.claudeProjectsDir !== void 0 ? { claudeProjectsDir: ctx.claudeProjectsDir } : {},
15547
+ ...ctx.codexSessionsDir !== void 0 ? { codexSessionsDir: ctx.codexSessionsDir } : {}
15548
+ })
15549
+ );
15550
+ }
15551
+ function sharedWhileRunning(run) {
15552
+ let running = null;
15553
+ return () => {
15554
+ running ??= run().finally(() => {
15555
+ running = null;
15556
+ });
15557
+ return running;
15334
15558
  };
15335
15559
  }
15336
15560
  async function viewBoardOf(root, paths) {
@@ -15495,7 +15719,7 @@ function installExperimentalNotice(program2, names = EXPERIMENTAL_COMMANDS, writ
15495
15719
  function readBuildStamp() {
15496
15720
  if (false) return void 0;
15497
15721
  try {
15498
- return JSON.parse('{"version":"0.66.0","commit":"2cd6700","committedAt":"2026-10-08T13:10:32+09:00"}');
15722
+ return JSON.parse('{"version":"0.67.0","commit":"c4c4ebb","committedAt":"2026-10-08T23:33:17+09:00"}');
15499
15723
  } catch {
15500
15724
  return void 0;
15501
15725
  }