@basou/cli 0.73.1 → 0.74.1
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 +242 -80
- package/dist/index.js.map +1 -1
- package/dist/program.js +242 -80
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/program.js
CHANGED
|
@@ -861,6 +861,7 @@ import {
|
|
|
861
861
|
readPreviousRecords,
|
|
862
862
|
recordIds,
|
|
863
863
|
resolveViewLanguage,
|
|
864
|
+
setEntryOf,
|
|
864
865
|
shellWord,
|
|
865
866
|
writeRecord
|
|
866
867
|
} from "@basou/core";
|
|
@@ -1080,6 +1081,18 @@ var SHORT_ID_LEN2 = 6;
|
|
|
1080
1081
|
function collectPath(value, previous) {
|
|
1081
1082
|
return [...previous, value];
|
|
1082
1083
|
}
|
|
1084
|
+
function reimportFallText(change) {
|
|
1085
|
+
const parts = [];
|
|
1086
|
+
if (change.decisions < 0) {
|
|
1087
|
+
const n = -change.decisions;
|
|
1088
|
+
parts.push(`${n.toLocaleString("en-US")} fewer decision${n === 1 ? "" : "s"}`);
|
|
1089
|
+
}
|
|
1090
|
+
if (change.outputTokens < 0) {
|
|
1091
|
+
const n = -change.outputTokens;
|
|
1092
|
+
parts.push(`${n.toLocaleString("en-US")} fewer output token${n === 1 ? "" : "s"}`);
|
|
1093
|
+
}
|
|
1094
|
+
return parts.length === 0 ? null : parts.join(", ");
|
|
1095
|
+
}
|
|
1083
1096
|
function registerImportCommand(program) {
|
|
1084
1097
|
const importCmd = program.command("import").description("Import provenance from an external AI tool's native logs");
|
|
1085
1098
|
importCmd.command("claude-code").description("Derive Basou sessions from Claude Code native transcripts (~/.claude/projects)").option(
|
|
@@ -1191,7 +1204,8 @@ async function doRunImportClaudeCode(options, ctx) {
|
|
|
1191
1204
|
store,
|
|
1192
1205
|
candidates,
|
|
1193
1206
|
projectPaths,
|
|
1194
|
-
hasDeclaredBoundary(options, manifest)
|
|
1207
|
+
hasDeclaredBoundary(options, manifest),
|
|
1208
|
+
ctx.onReimportChange
|
|
1195
1209
|
);
|
|
1196
1210
|
}
|
|
1197
1211
|
async function doRunImportCodex(options, ctx) {
|
|
@@ -1227,7 +1241,8 @@ async function doRunImportCodex(options, ctx) {
|
|
|
1227
1241
|
await loadImportStore(paths, options, CODEX_IMPORT_SOURCE),
|
|
1228
1242
|
candidates,
|
|
1229
1243
|
projectPaths,
|
|
1230
|
-
hasDeclaredBoundary(options, manifest)
|
|
1244
|
+
hasDeclaredBoundary(options, manifest),
|
|
1245
|
+
ctx.onReimportChange
|
|
1231
1246
|
);
|
|
1232
1247
|
}
|
|
1233
1248
|
function hasDeclaredBoundary(options, manifest) {
|
|
@@ -1249,7 +1264,7 @@ async function resolveImportTarget(ctx) {
|
|
|
1249
1264
|
const manifest = await readManifest2(paths);
|
|
1250
1265
|
return { repositoryRoot, paths, manifest };
|
|
1251
1266
|
}
|
|
1252
|
-
async function importDerivedSessions(paths, manifest, options, store, candidates, projectPaths, boundaryDeclared) {
|
|
1267
|
+
async function importDerivedSessions(paths, manifest, options, store, candidates, projectPaths, boundaryDeclared, onReimportChange) {
|
|
1253
1268
|
const { byExternalId: existingByExternalId, notDirectories, yamlNotFiles } = store;
|
|
1254
1269
|
let notDirectoriesWarned = false;
|
|
1255
1270
|
const seenThisRun = /* @__PURE__ */ new Set();
|
|
@@ -1279,7 +1294,8 @@ async function importDerivedSessions(paths, manifest, options, store, candidates
|
|
|
1279
1294
|
skippedDecreased: 0,
|
|
1280
1295
|
skippedDuplicate: 0,
|
|
1281
1296
|
skippedUnverifiable: 0,
|
|
1282
|
-
droppedCopies: 0
|
|
1297
|
+
droppedCopies: 0,
|
|
1298
|
+
change: { decisions: 0, outputTokens: 0 }
|
|
1283
1299
|
};
|
|
1284
1300
|
let sanitizedPaths = 0;
|
|
1285
1301
|
const validate = (payload) => {
|
|
@@ -1341,6 +1357,8 @@ async function importDerivedSessions(paths, manifest, options, store, candidates
|
|
|
1341
1357
|
continue;
|
|
1342
1358
|
}
|
|
1343
1359
|
counts.reimported++;
|
|
1360
|
+
counts.change.decisions += outcome.change.decisions;
|
|
1361
|
+
counts.change.outputTokens += outcome.change.outputTokens;
|
|
1344
1362
|
if (holdsCopies?.(prior) === true) counts.droppedCopies++;
|
|
1345
1363
|
seenThisRun.add(externalId);
|
|
1346
1364
|
await noteCrossProject(externalId, payload2);
|
|
@@ -1395,6 +1413,7 @@ async function importDerivedSessions(paths, manifest, options, store, candidates
|
|
|
1395
1413
|
);
|
|
1396
1414
|
}
|
|
1397
1415
|
}
|
|
1416
|
+
onReimportChange?.({ ...counts.change });
|
|
1398
1417
|
printImportResult(options, results, counts);
|
|
1399
1418
|
}
|
|
1400
1419
|
async function classifyReimport(priors, sourcePath, externalId, counts, holdsCopies) {
|
|
@@ -1847,7 +1866,9 @@ function printImportResult(options, results, counts) {
|
|
|
1847
1866
|
skipParts.push(`${skippedUnverifiable} unverifiable (run 'basou verify')`);
|
|
1848
1867
|
const skipSuffix = skipParts.length > 0 ? `; skipped ${skipParts.join(", ")}` : "";
|
|
1849
1868
|
const eventsPart = replaced > 0 ? `${eventTotal} events, ${replaced} replaced` : `${eventTotal} events`;
|
|
1850
|
-
const
|
|
1869
|
+
const copies = droppedCopies > 0 ? `${droppedCopies} without the records ${droppedCopies === 1 ? "its transcript" : "their transcripts"} copied from an older one` : null;
|
|
1870
|
+
const notes = [copies, reimportFallText(counts.change)].filter((n) => n !== null);
|
|
1871
|
+
const copiesPart = notes.length > 0 ? ` (${notes.join("; ")})` : "";
|
|
1851
1872
|
if (isDry) {
|
|
1852
1873
|
const parts = [];
|
|
1853
1874
|
if (results.length > 0) parts.push(`import ${results.length} session(s) (${eventsPart})`);
|
|
@@ -1946,10 +1967,23 @@ function isMissingSourceDir(error) {
|
|
|
1946
1967
|
if (!(error instanceof Error)) return false;
|
|
1947
1968
|
return error.message === "Claude transcript directory not found for project" || error.message === "Codex sessions directory not found";
|
|
1948
1969
|
}
|
|
1970
|
+
var reimportChanges = /* @__PURE__ */ new WeakMap();
|
|
1971
|
+
function reimportChangeOf(outcome) {
|
|
1972
|
+
return reimportChanges.get(outcome);
|
|
1973
|
+
}
|
|
1974
|
+
function noteReimportChange(outcome, change) {
|
|
1975
|
+
reimportChanges.set(outcome, change);
|
|
1976
|
+
return outcome;
|
|
1977
|
+
}
|
|
1949
1978
|
async function runImport(adapter, fn) {
|
|
1950
1979
|
try {
|
|
1951
|
-
|
|
1952
|
-
|
|
1980
|
+
let reimportChange = { decisions: 0, outputTokens: 0 };
|
|
1981
|
+
const json = await captureImportJson(
|
|
1982
|
+
() => fn((change) => {
|
|
1983
|
+
reimportChange = change;
|
|
1984
|
+
})
|
|
1985
|
+
);
|
|
1986
|
+
const outcome = {
|
|
1953
1987
|
adapter,
|
|
1954
1988
|
status: "ran",
|
|
1955
1989
|
importedCount: readCount(json.imported_count),
|
|
@@ -1965,6 +1999,7 @@ async function runImport(adapter, fn) {
|
|
|
1965
1999
|
eventTotal: readCount(json.event_total),
|
|
1966
2000
|
dryRun: json.dry_run === true
|
|
1967
2001
|
};
|
|
2002
|
+
return noteReimportChange(outcome, reimportChange);
|
|
1968
2003
|
} catch (error) {
|
|
1969
2004
|
if (isMissingSourceDir(error)) {
|
|
1970
2005
|
return { adapter, status: "skipped", reason: "no source logs for this project" };
|
|
@@ -1982,10 +2017,16 @@ function importOptions(options) {
|
|
|
1982
2017
|
};
|
|
1983
2018
|
}
|
|
1984
2019
|
function importClaudeCode(options, ctx) {
|
|
1985
|
-
return runImport(
|
|
2020
|
+
return runImport(
|
|
2021
|
+
"claude-code",
|
|
2022
|
+
(onReimportChange) => doRunImportClaudeCode(importOptions(options), { ...ctx, onReimportChange })
|
|
2023
|
+
);
|
|
1986
2024
|
}
|
|
1987
2025
|
function importCodex(options, ctx) {
|
|
1988
|
-
return runImport(
|
|
2026
|
+
return runImport(
|
|
2027
|
+
"codex",
|
|
2028
|
+
(onReimportChange) => doRunImportCodex(importOptions(options), { ...ctx, onReimportChange })
|
|
2029
|
+
);
|
|
1989
2030
|
}
|
|
1990
2031
|
async function regenerateHandoff(paths, nowIso, callbacks) {
|
|
1991
2032
|
const result = await renderHandoff({ paths, nowIso, ...callbacks });
|
|
@@ -2809,11 +2850,14 @@ function diffLines(diff, more) {
|
|
|
2809
2850
|
` ${displayPath3(c.at)}: ${shownJson(c.before)} -> ${shownJson(c.after)}${delta}${flag(c)}`
|
|
2810
2851
|
);
|
|
2811
2852
|
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
}
|
|
2853
|
+
const only = (sign, c) => {
|
|
2854
|
+
const entry = setEntryOf(c.at);
|
|
2855
|
+
if (entry === null) return ` ${sign} ${displayPath3(c.at)}: ${shownJson(c.value)}${flag(c)}`;
|
|
2856
|
+
const how = sign === "+" ? "now lists" : "no longer lists";
|
|
2857
|
+
return ` ${sign} ${displayPath3(entry.list)}: ${how} ${shownJson(entry.name)}${flag(c)}`;
|
|
2858
|
+
};
|
|
2859
|
+
for (const c of diff.added) lines.push(only("+", c));
|
|
2860
|
+
for (const c of diff.removed) lines.push(only("-", c));
|
|
2817
2861
|
if (lines.length === 0 && !more) lines.push(" nothing moved");
|
|
2818
2862
|
return lines;
|
|
2819
2863
|
}
|
|
@@ -10229,8 +10273,13 @@ function describeImport(outcome) {
|
|
|
10229
10273
|
const verb = outcome.dryRun ? "would import" : "imported";
|
|
10230
10274
|
const parts = [`${outcome.importedCount} session(s)`, `${outcome.eventTotal} events`];
|
|
10231
10275
|
if (outcome.reimportedCount > 0) {
|
|
10232
|
-
const
|
|
10233
|
-
|
|
10276
|
+
const notes = [
|
|
10277
|
+
outcome.droppedCopiesCount > 0 ? `${outcome.droppedCopiesCount} without records copied from an older transcript` : null,
|
|
10278
|
+
reimportFallText(reimportChangeOf(outcome) ?? { decisions: 0, outputTokens: 0 })
|
|
10279
|
+
].filter((n) => n !== null);
|
|
10280
|
+
parts.push(
|
|
10281
|
+
`${outcome.reimportedCount} re-imported${notes.length > 0 ? ` (${notes.join("; ")})` : ""}`
|
|
10282
|
+
);
|
|
10234
10283
|
}
|
|
10235
10284
|
if (outcome.replacedCount > 0) parts.push(`${outcome.replacedCount} replaced`);
|
|
10236
10285
|
if (outcome.skippedAlreadyImported > 0)
|
|
@@ -13964,12 +14013,31 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13964
14013
|
table { border-collapse: collapse; }
|
|
13965
14014
|
th, td { text-align: left; vertical-align: top; padding: 4px 10px 4px 0; }
|
|
13966
14015
|
td.n, th.n { text-align: right; font-variant-numeric: tabular-nums; }
|
|
14016
|
+
/* A number is never broken across lines, so a part of it cannot pass for another number. */
|
|
14017
|
+
td.n { white-space: nowrap; }
|
|
13967
14018
|
table.grid td, table.grid th { border-bottom: 1px solid var(--grid); }
|
|
13968
|
-
|
|
14019
|
+
/* Where a table is wider than its box, a shade at an edge says there is
|
|
14020
|
+
more that way, also where scrollbars are drawn over the content and
|
|
14021
|
+
hidden: each shade stays at its edge, and a cover of the page's color,
|
|
14022
|
+
moving with the content, hides it while that end is in view. */
|
|
14023
|
+
.scroll {
|
|
14024
|
+
overflow-x: auto; max-width: 100%;
|
|
14025
|
+
background:
|
|
14026
|
+
linear-gradient(to right, var(--bg) 40%, transparent) left center / 28px 100% no-repeat local,
|
|
14027
|
+
linear-gradient(to left, var(--bg) 40%, transparent) right center / 28px 100% no-repeat local,
|
|
14028
|
+
radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--fg-2) 40%, transparent), transparent) left center / 12px 100% no-repeat scroll,
|
|
14029
|
+
radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--fg-2) 40%, transparent), transparent) right center / 12px 100% no-repeat scroll;
|
|
14030
|
+
}
|
|
14031
|
+
/* Lane names, and the heads of the repos' table, break between words, not
|
|
14032
|
+
inside one (a name in Japanese is one word). */
|
|
14033
|
+
td.lanes, table.repos th { word-break: keep-all; }
|
|
13969
14034
|
table.matrix th.stage { font-weight: 400; font-size: 12px; text-align: center; min-width: 64px; }
|
|
13970
14035
|
table.matrix th.stage b { display: block; font-size: 13px; }
|
|
13971
14036
|
table.matrix td.cell { text-align: center; font-size: 18px; line-height: 1; }
|
|
13972
14037
|
.stage-meanings { display: none; list-style: none; padding: 0; margin: 6px 0 0; font-size: 12px; color: var(--fg-2); }
|
|
14038
|
+
/* Drawn only below about 600px, by the rule below. */
|
|
14039
|
+
tr.source { display: none; }
|
|
14040
|
+
tr.source td { padding-top: 0; }
|
|
13973
14041
|
/* Six stages do not fit beside their meanings below about 600px: each is
|
|
13974
14042
|
drawn by its id, the meanings are listed under the matrix, and a lane
|
|
13975
14043
|
name wraps. After the rules above, which it overrides. */
|
|
@@ -13985,8 +14053,13 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13985
14053
|
is cut off. The cell keeps no right padding, which a sticky note could
|
|
13986
14054
|
not cross. */
|
|
13987
14055
|
.scroll { container-type: inline-size; }
|
|
13988
|
-
tr.notes td { padding-right: 0; }
|
|
13989
|
-
tr.notes ul.sub { position: sticky; left: 0; max-width: calc(100vw - 32px); max-width: 100cqw; }
|
|
14056
|
+
tr.notes td, tr.source td { padding-right: 0; }
|
|
14057
|
+
tr.notes ul.sub, tr.source div.sub { position: sticky; left: 0; max-width: calc(100vw - 32px); max-width: 100cqw; }
|
|
14058
|
+
/* An observation's source is drawn in a row of its own under it, where
|
|
14059
|
+
it wraps at the width in view, not in a column off the screen that
|
|
14060
|
+
makes its row tall. */
|
|
14061
|
+
th.source, td.source { display: none; }
|
|
14062
|
+
tr.source { display: table-row; }
|
|
13990
14063
|
}
|
|
13991
14064
|
.st::before { display: inline-block; width: 1.2em; }
|
|
13992
14065
|
.st.done::before { content: "\\25CF"; color: var(--done); }
|
|
@@ -13995,7 +14068,9 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13995
14068
|
.st.shelved::before { content: "\\2298"; color: var(--fg-2); }
|
|
13996
14069
|
.st.none::before { content: "\\25CB"; color: var(--fg-2); }
|
|
13997
14070
|
.st.unverified::before { content: "?"; color: var(--info); font-weight: 700; }
|
|
13998
|
-
td.moved { outline: 2px solid var(--info); outline-offset: -3px; border-radius: 6px; }
|
|
14071
|
+
td.moved, .moved-key { outline: 2px solid var(--info); outline-offset: -3px; border-radius: 6px; }
|
|
14072
|
+
.moved-key { display: inline-block; width: 1.2em; height: 1.2em; margin-right: 4px; vertical-align: -0.3em; }
|
|
14073
|
+
ul.moved { margin: 6px 0 0; padding-left: 18px; font-size: 12px; }
|
|
13999
14074
|
.legend { font-size: 12px; color: var(--fg-2); display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px; }
|
|
14000
14075
|
.swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 4px; vertical-align: -1px; }
|
|
14001
14076
|
.swatch.s1 { background: var(--s1); }
|
|
@@ -14013,6 +14088,7 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14013
14088
|
td.wrap { overflow-wrap: anywhere; min-width: 10em; }
|
|
14014
14089
|
tr.notes td { padding-top: 0; }
|
|
14015
14090
|
.chip.changed { margin-left: 0; margin-right: 6px; background: var(--chip-unverified); }
|
|
14091
|
+
.chip.added { margin-left: 0; margin-right: 6px; background: var(--chip-live); }
|
|
14016
14092
|
.bar { height: 10px; background: var(--fill); border-radius: 5px; min-width: 120px; position: relative; overflow: hidden; }
|
|
14017
14093
|
.bar span { position: absolute; left: 0; top: 0; bottom: 0; background: var(--s1); }
|
|
14018
14094
|
figure { margin: 16px 0; }
|
|
@@ -14045,6 +14121,18 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14045
14121
|
(function () {
|
|
14046
14122
|
var S = null;
|
|
14047
14123
|
var lang = 'en';
|
|
14124
|
+
// The workspace of a portfolio the page is opened for (?ws=<key>), set
|
|
14125
|
+
// before anything is fetched: its board is read from its scoped routes, and
|
|
14126
|
+
// the page's links keep it. Null in single mode.
|
|
14127
|
+
var WS = null;
|
|
14128
|
+
function apiPath(sub) {
|
|
14129
|
+
return (WS === null ? '/api/' : '/api/ws/' + encodeURIComponent(WS) + '/') + sub;
|
|
14130
|
+
}
|
|
14131
|
+
function boardHref(query) {
|
|
14132
|
+
var parts = WS === null ? [] : ['ws=' + encodeURIComponent(WS)];
|
|
14133
|
+
if (query) parts.push(query);
|
|
14134
|
+
return '/board' + (parts.length > 0 ? '?' + parts.join('&') : '');
|
|
14135
|
+
}
|
|
14048
14136
|
function $(id) { return document.getElementById(id); }
|
|
14049
14137
|
function clear(node) { while (node.firstChild) node.removeChild(node.firstChild); }
|
|
14050
14138
|
function el(tag, attrs, children) {
|
|
@@ -14146,11 +14234,27 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14146
14234
|
var DOT = ' ' + String.fromCharCode(183) + ' ';
|
|
14147
14235
|
var FOUND = String.fromCharCode(10003);
|
|
14148
14236
|
var NOT_FOUND = String.fromCharCode(10007);
|
|
14237
|
+
// Whether a final_url is where the declared url points: the same origin and
|
|
14238
|
+
// path, and nothing more. A final_url written from basou 0.73.0 holds no
|
|
14239
|
+
// query, fragment, user or password; one in a record written before may, and
|
|
14240
|
+
// is then drawn, as what it holds can be what moved. A test lifts this function.
|
|
14241
|
+
function landsAsDeclared(url, finalUrl) {
|
|
14242
|
+
try {
|
|
14243
|
+
var a = new URL(url);
|
|
14244
|
+
var b = new URL(finalUrl);
|
|
14245
|
+
return a.origin === b.origin && a.pathname === b.pathname &&
|
|
14246
|
+
b.search === '' && b.hash === '' && b.username === '' && b.password === '';
|
|
14247
|
+
} catch (e) {
|
|
14248
|
+
return false;
|
|
14249
|
+
}
|
|
14250
|
+
}
|
|
14149
14251
|
// An http value read as its parts: the status, the redirects, where it
|
|
14150
|
-
// landed
|
|
14252
|
+
// landed (left out where it is the url declared, which is drawn under the
|
|
14253
|
+
// name), and what it read off the body (when the status is 2xx) or that it
|
|
14151
14254
|
// did not. Numbers and strings are drawn as they are.
|
|
14152
|
-
function httpText(h) {
|
|
14153
|
-
var parts = [String(h.status), fill(S.observed.redirects, { n: h.redirects })
|
|
14255
|
+
function httpText(h, url) {
|
|
14256
|
+
var parts = [String(h.status), fill(S.observed.redirects, { n: h.redirects })];
|
|
14257
|
+
if (!url || !landsAsDeclared(url, h.final_url)) parts.push(h.final_url);
|
|
14154
14258
|
if (h.body === null) parts.push(S.observed.bodyNotRead);
|
|
14155
14259
|
else if (h.body) {
|
|
14156
14260
|
if (h.body.words) {
|
|
@@ -14165,23 +14269,35 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14165
14269
|
}
|
|
14166
14270
|
// A value of an observation as the page draws it: an http value in its
|
|
14167
14271
|
// shape read as its parts, one with words beside what it says of each, and
|
|
14168
|
-
// any other as it is (a string) or as JSON.
|
|
14169
|
-
|
|
14170
|
-
|
|
14272
|
+
// any other as it is (a string) or as JSON. url: the url its declaration
|
|
14273
|
+
// gives, or null. A test lifts this function.
|
|
14274
|
+
function observedText(value, words, http, url) {
|
|
14275
|
+
if (http) return httpText(http, url);
|
|
14171
14276
|
if (words) return withWords(value, words);
|
|
14172
14277
|
return shown(value);
|
|
14173
14278
|
}
|
|
14279
|
+
// The url an http observation's declaration gives, or null.
|
|
14280
|
+
function declaredUrl(o) {
|
|
14281
|
+
return o.kind === 'http' && o.looks_at && o.looks_at.length > 0 ? o.looks_at[0] : null;
|
|
14282
|
+
}
|
|
14283
|
+
// When an observation was made, as the page draws a time; a day alone (a
|
|
14284
|
+
// manual observation may give one) is drawn as it is, not as its midnight.
|
|
14285
|
+
// A test lifts this function.
|
|
14286
|
+
function observedAtText(at) {
|
|
14287
|
+
return /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(String(at)) ? String(at) : when(at);
|
|
14288
|
+
}
|
|
14174
14289
|
// The value of an observation that moved, and what the previous record
|
|
14175
14290
|
// held: a value whose type alone moved ("12" and 12) is drawn as JSON, so
|
|
14176
14291
|
// that the two do not read the same. A test lifts this function.
|
|
14177
14292
|
function movedText(o) {
|
|
14178
14293
|
var m = o.moved;
|
|
14179
|
-
var
|
|
14294
|
+
var url = declaredUrl(o);
|
|
14295
|
+
var now = observedText(o.value, o.words, o.http, url);
|
|
14180
14296
|
if (m.status === 'none') return { now: now, then: S.observed.beforeNone };
|
|
14181
14297
|
if (m.value === null) {
|
|
14182
14298
|
return { now: now, then: S.observed.beforeNotObserved + (m.error ? ' (' + m.error + ')' : '') };
|
|
14183
14299
|
}
|
|
14184
|
-
var then = observedText(m.value, m.words, m.http);
|
|
14300
|
+
var then = observedText(m.value, m.words, m.http, url);
|
|
14185
14301
|
if ((typeof m.value === 'string') !== (typeof o.value === 'string')) {
|
|
14186
14302
|
then = JSON.stringify(m.value);
|
|
14187
14303
|
if (then === now) now = JSON.stringify(o.value);
|
|
@@ -14214,19 +14330,19 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14214
14330
|
var page = d.page;
|
|
14215
14331
|
var list = page.records || [];
|
|
14216
14332
|
if (list.length > 0) recordLinks(nav, page, list);
|
|
14217
|
-
nav.appendChild(el('a', { href: '
|
|
14333
|
+
nav.appendChild(el('a', { href: boardHref('live=1'), text: S.live.measureNow }));
|
|
14218
14334
|
}
|
|
14219
14335
|
|
|
14220
14336
|
function recordLinks(nav, page, list) {
|
|
14221
14337
|
var link = function (id, label) {
|
|
14222
|
-
return el('a', { href: '
|
|
14338
|
+
return el('a', { href: boardHref('record=' + encodeURIComponent(id)), text: label });
|
|
14223
14339
|
};
|
|
14224
14340
|
// Around the record asked for, whether or not it could be drawn.
|
|
14225
14341
|
if (page.older) nav.appendChild(link(page.older, S.older));
|
|
14226
14342
|
if (page.newer) nav.appendChild(link(page.newer, S.newer));
|
|
14227
|
-
nav.appendChild(el('a', { href: '
|
|
14343
|
+
nav.appendChild(el('a', { href: boardHref(''), text: S.latest }));
|
|
14228
14344
|
var select = el('select', {
|
|
14229
|
-
onchange: function () { location.href = '
|
|
14345
|
+
onchange: function () { location.href = boardHref('record=' + encodeURIComponent(select.value)); }
|
|
14230
14346
|
});
|
|
14231
14347
|
var listed = list.some(function (r) { return r.id === page.id; });
|
|
14232
14348
|
if (!listed) {
|
|
@@ -14291,14 +14407,19 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14291
14407
|
s.observed.forEach(function (o) {
|
|
14292
14408
|
var cell = el('td', { class: 'wrap' });
|
|
14293
14409
|
var value;
|
|
14294
|
-
if (o.value !== null && o.moved) {
|
|
14410
|
+
if (o.value !== null && o.moved && o.moved.status === 'none') {
|
|
14411
|
+
// Declared since the previous record: new, which is not a change.
|
|
14412
|
+
cell.appendChild(el('span', { class: 'chip added', text: S.observed.added }));
|
|
14413
|
+
value = observedText(o.value, o.words, o.http, declaredUrl(o));
|
|
14414
|
+
cell.appendChild(el('span', { text: value + (o.error ? ' (' + o.error + ')' : '') }));
|
|
14415
|
+
} else if (o.value !== null && o.moved) {
|
|
14295
14416
|
var pair = movedText(o);
|
|
14296
14417
|
cell.appendChild(el('span', { class: 'chip changed', text: S.observed.changed }));
|
|
14297
14418
|
value = pair.now;
|
|
14298
14419
|
cell.appendChild(el('span', { text: value + (o.error ? ' (' + o.error + ')' : '') }));
|
|
14299
14420
|
cell.appendChild(el('div', { class: 'sub', text: pair.then }));
|
|
14300
14421
|
} else {
|
|
14301
|
-
if (o.value !== null) value = observedText(o.value, o.words, o.http);
|
|
14422
|
+
if (o.value !== null) value = observedText(o.value, o.words, o.http, declaredUrl(o));
|
|
14302
14423
|
else if (o.previous && o.previous.status === 'value') value = fill(S.observed.missing, { value: shown(o.previous.value) });
|
|
14303
14424
|
else if (o.previous && o.previous.status === 'unreadable') value = S.observed.missingPreviousUnreadable;
|
|
14304
14425
|
else value = S.observed.missingNoPrevious;
|
|
@@ -14310,8 +14431,13 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14310
14431
|
rows.push(el('tr', null, [
|
|
14311
14432
|
el('td', null, [el('div', { text: o.name }), what === null ? null : el('div', { class: 'sub', text: what })]),
|
|
14312
14433
|
cell,
|
|
14313
|
-
el('td', { text: o.observed_at
|
|
14434
|
+
el('td', { text: observedAtText(o.observed_at), title: o.observed_at }),
|
|
14435
|
+
el('td', { class: 'wrap source', text: o.source })
|
|
14314
14436
|
]));
|
|
14437
|
+
// Its source again, drawn only on a narrow screen, where its column is not.
|
|
14438
|
+
rows.push(el('tr', { class: 'source' }, [el('td', { colspan: '4' }, [
|
|
14439
|
+
el('div', { class: 'sub', text: S.observed.source + ': ' + o.source })
|
|
14440
|
+
])]));
|
|
14315
14441
|
if (o.notes && o.notes.length > 0) {
|
|
14316
14442
|
rows.push(el('tr', { class: 'notes' }, [el('td', { colspan: '4' }, [
|
|
14317
14443
|
el('ul', { class: 'sub' }, o.notes.map(function (n) { return el('li', null, [prose(n, 'span')]); }))
|
|
@@ -14321,7 +14447,7 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14321
14447
|
observed = el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [
|
|
14322
14448
|
el('tr', null, [
|
|
14323
14449
|
el('th', { text: S.observed.name }), el('th', { text: S.observed.value }),
|
|
14324
|
-
el('th', { text: S.observed.observedAt }), el('th', { text: S.observed.source })
|
|
14450
|
+
el('th', { text: S.observed.observedAt }), el('th', { class: 'source', text: S.observed.source })
|
|
14325
14451
|
])
|
|
14326
14452
|
].concat(rows))]);
|
|
14327
14453
|
}
|
|
@@ -14652,7 +14778,22 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14652
14778
|
['done', 'part', 'blocked', 'shelved', 'none', 'unverified'].forEach(function (s) {
|
|
14653
14779
|
legend.appendChild(el('span', null, [el('span', { class: 'st ' + s }), stateName(s)]));
|
|
14654
14780
|
});
|
|
14781
|
+
// The cells that moved since the previous record: their mark in the
|
|
14782
|
+
// legend, and each with the state it had, which a cell's title alone says
|
|
14783
|
+
// only to a pointer that hovers.
|
|
14784
|
+
var moved = [];
|
|
14785
|
+
x.lanes.forEach(function (lane) {
|
|
14786
|
+
lane.cells.forEach(function (c, i) {
|
|
14787
|
+
if (c.moved_from) moved.push({ lane: lane.name, stage: x.stages[i] ? x.stages[i].id : '', before: c.moved_from, after: c.state });
|
|
14788
|
+
});
|
|
14789
|
+
});
|
|
14790
|
+
if (moved.length > 0) legend.appendChild(el('span', null, [el('span', { class: 'moved-key' }), S.matrix.movedKey]));
|
|
14655
14791
|
children.push(legend);
|
|
14792
|
+
if (moved.length > 0) {
|
|
14793
|
+
children.push(el('ul', { class: 'moved' }, moved.map(function (m) {
|
|
14794
|
+
return el('li', { text: fill(S.matrix.movedCell, { lane: m.lane, stage: m.stage, before: stateName(m.before), after: stateName(m.after) }) });
|
|
14795
|
+
})));
|
|
14796
|
+
}
|
|
14656
14797
|
return section(S.sections.matrix, true, children);
|
|
14657
14798
|
}
|
|
14658
14799
|
|
|
@@ -14701,16 +14842,18 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14701
14842
|
if (b.measures.length === 0) {
|
|
14702
14843
|
return section(S.sections.measures, false, [el('p', { class: 'muted', text: S.measures.none })]);
|
|
14703
14844
|
}
|
|
14845
|
+
// How much a number moved, right beside it: where the table is wider than
|
|
14846
|
+
// the screen, the lanes, which are words, are the column cut off.
|
|
14704
14847
|
var head = el('tr', null, [
|
|
14705
14848
|
el('th', { text: S.measures.id }), el('th', { text: S.measures.value }),
|
|
14706
|
-
el('th', { text: S.measures.
|
|
14849
|
+
el('th', { class: 'n', text: S.measures.delta }), el('th', { text: S.measures.lanes })
|
|
14707
14850
|
]);
|
|
14708
14851
|
var rows = b.measures.map(function (m) {
|
|
14709
14852
|
return el('tr', { 'data-measure': m.id }, [
|
|
14710
14853
|
el('td', null, [el('code', { text: m.id })]),
|
|
14711
14854
|
el('td', { class: 'wrap', text: measureText(m) }),
|
|
14712
|
-
el('td', { text: m.
|
|
14713
|
-
el('td', { class: '
|
|
14855
|
+
el('td', { class: 'n', text: m.delta === null || m.delta === undefined ? '' : signed(m.delta) }),
|
|
14856
|
+
el('td', { class: 'lanes', text: m.lanes.length === 0 ? '-' : m.lanes.join(', ') })
|
|
14714
14857
|
]);
|
|
14715
14858
|
});
|
|
14716
14859
|
return section(S.sections.measures, false, [el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [head].concat(rows))])]);
|
|
@@ -14804,9 +14947,10 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14804
14947
|
// The board's own title, so that boards open in other tabs can be told apart.
|
|
14805
14948
|
document.title = b.heading.title;
|
|
14806
14949
|
// Where each lane stops, right under the summary's tiles, and the lanes,
|
|
14807
|
-
// before the observations and the charts of the effort
|
|
14808
|
-
|
|
14809
|
-
|
|
14950
|
+
// before the observations and the charts of the effort; then the
|
|
14951
|
+
// operator's turns, which are read most, before the tables of every value.
|
|
14952
|
+
[heading(b), summary(b), matrix(b), lanes(b), observations(b), effort(b, false), turns(b), measures(b),
|
|
14953
|
+
composition(b), recordRepos(b), recordComponents(b), footnotes(b)]
|
|
14810
14954
|
.forEach(function (node) { root.appendChild(node); });
|
|
14811
14955
|
}
|
|
14812
14956
|
|
|
@@ -14863,7 +15007,7 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14863
15007
|
el('td', { text: unmeasured('fetched_at', r.fetched_at, when) })
|
|
14864
15008
|
]);
|
|
14865
15009
|
});
|
|
14866
|
-
return el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [head].concat(rows))]);
|
|
15010
|
+
return el('div', { class: 'scroll' }, [el('table', { class: 'grid repos' }, [head].concat(rows))]);
|
|
14867
15011
|
}
|
|
14868
15012
|
function liveRepos(l) {
|
|
14869
15013
|
return section(S.live.repos, false, [reposTable(l.repos, missingIn(l), false)]);
|
|
@@ -14960,9 +15104,12 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14960
15104
|
}));
|
|
14961
15105
|
return section(S.live.components, false, [body]);
|
|
14962
15106
|
}
|
|
14963
|
-
|
|
15107
|
+
// noRecord: whether to say how a record comes to be drawn, which is said
|
|
15108
|
+
// only where the workspace has no record.
|
|
15109
|
+
function liveFootnotes(l, why, noRecord) {
|
|
14964
15110
|
var f = l.footnotes;
|
|
14965
|
-
var items = [el('li', { text: S.live.note })
|
|
15111
|
+
var items = [el('li', { text: S.live.note })];
|
|
15112
|
+
if (noRecord) items.push(el('li', { text: S.live.judged }));
|
|
14966
15113
|
if (why === 'no_board') items.push(el('li', { text: S.unavailable.noBoard }));
|
|
14967
15114
|
if (f.not_found.length > 0) {
|
|
14968
15115
|
items.push(el('li', null, [el('b', { text: S.footnotes.notMeasured }), el('ul', null, f.not_found.map(function (n) {
|
|
@@ -14983,19 +15130,27 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14983
15130
|
var drawn = ++liveDrawn;
|
|
14984
15131
|
var nav = $('records');
|
|
14985
15132
|
clear(nav);
|
|
14986
|
-
// Asked for with ?live=1: lead back to the records, when there are any.
|
|
14987
|
-
if (why === null) {
|
|
14988
|
-
getJson('/api/board').then(function (b) {
|
|
14989
|
-
var list = b && b.page && b.page.records ? b.page.records : [];
|
|
14990
|
-
if (drawn === liveDrawn && list.length > 0) nav.appendChild(el('a', { href: '/board', text: S.live.toRecords }));
|
|
14991
|
-
}).catch(function () {});
|
|
14992
|
-
}
|
|
14993
15133
|
var root = $('board');
|
|
14994
15134
|
clear(root);
|
|
14995
15135
|
setStatus('', false);
|
|
14996
15136
|
var l = d.live;
|
|
14997
|
-
|
|
15137
|
+
var foot = liveFootnotes(l, why, why !== null);
|
|
15138
|
+
[liveHeading(l, why), effort(l, true), liveRepos(l), liveTrail(l), liveComponents(l), foot]
|
|
14998
15139
|
.forEach(function (node) { root.appendChild(node); });
|
|
15140
|
+
// Asked for with ?live=1: lead back to the records when there are any,
|
|
15141
|
+
// and say how one comes to be drawn when there are none.
|
|
15142
|
+
if (why === null) {
|
|
15143
|
+
getJson(apiPath('board')).then(function (b) {
|
|
15144
|
+
var list = b && b.page && b.page.records ? b.page.records : [];
|
|
15145
|
+
if (drawn !== liveDrawn) return;
|
|
15146
|
+
if (list.length > 0) {
|
|
15147
|
+
nav.appendChild(el('a', { href: boardHref(''), text: S.live.toRecords }));
|
|
15148
|
+
} else {
|
|
15149
|
+
root.removeChild(foot);
|
|
15150
|
+
root.appendChild(liveFootnotes(l, why, true));
|
|
15151
|
+
}
|
|
15152
|
+
}).catch(function () {});
|
|
15153
|
+
}
|
|
14999
15154
|
}
|
|
15000
15155
|
|
|
15001
15156
|
function getJson(url) {
|
|
@@ -15010,16 +15165,17 @@ var BOARD_HTML = `<!doctype html>
|
|
|
15010
15165
|
// Measuring takes seconds, so the page says so until it is done.
|
|
15011
15166
|
function loadLive(why) {
|
|
15012
15167
|
setStatus(S ? S.live.measuring : '...', false);
|
|
15013
|
-
getJson('
|
|
15168
|
+
getJson(apiPath('board/live')).then(function (d) { drawLive(d, why); }).catch(failed);
|
|
15014
15169
|
}
|
|
15015
15170
|
|
|
15016
15171
|
var params = new URLSearchParams(location.search);
|
|
15172
|
+
WS = params.get('ws');
|
|
15017
15173
|
var record = params.get('record');
|
|
15018
15174
|
if (params.get('live') !== null) {
|
|
15019
15175
|
loadLive(null);
|
|
15020
15176
|
} else {
|
|
15021
15177
|
setStatus('...', false);
|
|
15022
|
-
getJson('
|
|
15178
|
+
getJson(apiPath('board' + (record ? '/' + encodeURIComponent(record) : ''))).then(draw).catch(failed);
|
|
15023
15179
|
}
|
|
15024
15180
|
})();
|
|
15025
15181
|
</script>
|
|
@@ -15285,7 +15441,7 @@ var VIEW_HTML = `<!doctype html>
|
|
|
15285
15441
|
state.canAct = true;
|
|
15286
15442
|
document.body.classList.remove('landing');
|
|
15287
15443
|
$('btn-back').style.display = 'none';
|
|
15288
|
-
|
|
15444
|
+
$('board-link').href = '/board';
|
|
15289
15445
|
$('board-link').style.display = '';
|
|
15290
15446
|
updateActionBar();
|
|
15291
15447
|
buildTabs();
|
|
@@ -15299,6 +15455,8 @@ var VIEW_HTML = `<!doctype html>
|
|
|
15299
15455
|
state.canAct = false;
|
|
15300
15456
|
document.body.classList.add('landing');
|
|
15301
15457
|
$('btn-back').style.display = 'none';
|
|
15458
|
+
// No workspace is open: there is no board to lead to.
|
|
15459
|
+
$('board-link').style.display = 'none';
|
|
15302
15460
|
setStatus('', false);
|
|
15303
15461
|
clear($('tabs'));
|
|
15304
15462
|
updateActionBar();
|
|
@@ -15354,8 +15512,12 @@ var VIEW_HTML = `<!doctype html>
|
|
|
15354
15512
|
if (!st.checked) return el('span', { class: 'badge', text: 'freshness unknown' });
|
|
15355
15513
|
if (st.unverifiableSessions > 0)
|
|
15356
15514
|
return el('span', { class: 'badge danger', text: '\u26A0 ' + st.unverifiableSessions + ' unverifiable \u2014 run verify' });
|
|
15357
|
-
|
|
15358
|
-
|
|
15515
|
+
// The updated ones are said beside the uncaptured ones, so the badge counts
|
|
15516
|
+
// what measure's freshness does ("1 new, 1 updated").
|
|
15517
|
+
if (st.newSessions > 0) {
|
|
15518
|
+
var updated = st.updatedSessions > 0 ? ', ' + st.updatedSessions + ' updated' : '';
|
|
15519
|
+
return el('span', { class: 'badge danger', text: '\u26A0 ' + st.newSessions + ' uncaptured' + updated + ' \u2014 run refresh' });
|
|
15520
|
+
}
|
|
15359
15521
|
if (st.updatedSessions > 0)
|
|
15360
15522
|
return el('span', { class: 'badge warn', text: st.updatedSessions + ' updated \u2014 run refresh' });
|
|
15361
15523
|
return el('span', { class: 'badge ok', text: 'up to date' });
|
|
@@ -15413,6 +15575,10 @@ var VIEW_HTML = `<!doctype html>
|
|
|
15413
15575
|
state.canAct = true;
|
|
15414
15576
|
document.body.classList.remove('landing');
|
|
15415
15577
|
$('btn-back').style.display = '';
|
|
15578
|
+
// The board of the workspace open, read from its scoped routes. The cards
|
|
15579
|
+
// of the landing carry none of a board's figures.
|
|
15580
|
+
$('board-link').href = '/board?ws=' + encodeURIComponent(key);
|
|
15581
|
+
$('board-link').style.display = '';
|
|
15416
15582
|
updateActionBar();
|
|
15417
15583
|
setStatus('workspace: ' + label, false);
|
|
15418
15584
|
buildTabs();
|
|
@@ -15820,7 +15986,7 @@ async function handleGet(res, pathname, deps) {
|
|
|
15820
15986
|
sendHtml(res, VIEW_HTML);
|
|
15821
15987
|
return;
|
|
15822
15988
|
}
|
|
15823
|
-
if (pathname === "/board"
|
|
15989
|
+
if (pathname === "/board") {
|
|
15824
15990
|
sendHtml(res, BOARD_HTML);
|
|
15825
15991
|
return;
|
|
15826
15992
|
}
|
|
@@ -15841,8 +16007,8 @@ async function handleGet(res, pathname, deps) {
|
|
|
15841
16007
|
ws,
|
|
15842
16008
|
deps.nowProvider,
|
|
15843
16009
|
remoteUrlOf(deps),
|
|
15844
|
-
|
|
15845
|
-
|
|
16010
|
+
ws.board,
|
|
16011
|
+
ws.boardLive
|
|
15846
16012
|
)) {
|
|
15847
16013
|
sendError(res, 404, "Not found");
|
|
15848
16014
|
}
|
|
@@ -15856,8 +16022,8 @@ async function handleGet(res, pathname, deps) {
|
|
|
15856
16022
|
primaryWorkspace(deps),
|
|
15857
16023
|
deps.nowProvider,
|
|
15858
16024
|
remoteUrlOf(deps),
|
|
15859
|
-
|
|
15860
|
-
|
|
16025
|
+
flatBoardOf(deps),
|
|
16026
|
+
flatBoardLiveOf(deps)
|
|
15861
16027
|
)) {
|
|
15862
16028
|
sendError(res, 404, "Not found");
|
|
15863
16029
|
}
|
|
@@ -15865,11 +16031,11 @@ async function handleGet(res, pathname, deps) {
|
|
|
15865
16031
|
}
|
|
15866
16032
|
sendError(res, 404, "Not found");
|
|
15867
16033
|
}
|
|
15868
|
-
function
|
|
15869
|
-
return deps.mode === "single" ? deps.board : void 0;
|
|
16034
|
+
function flatBoardOf(deps) {
|
|
16035
|
+
return deps.mode === "single" ? primaryWorkspace(deps).board : void 0;
|
|
15870
16036
|
}
|
|
15871
|
-
function
|
|
15872
|
-
return deps.mode === "single" ? deps.boardLive : void 0;
|
|
16037
|
+
function flatBoardLiveOf(deps) {
|
|
16038
|
+
return deps.mode === "single" ? primaryWorkspace(deps).boardLive : void 0;
|
|
15873
16039
|
}
|
|
15874
16040
|
function remoteUrlOf(deps) {
|
|
15875
16041
|
return deps.remoteUrlOf ?? tryRemoteUrl;
|
|
@@ -16388,14 +16554,13 @@ async function buildSingleDeps(ctx, cwd) {
|
|
|
16388
16554
|
const repositoryRoot = await resolveBasouRootForCommand(cwd, "view");
|
|
16389
16555
|
const paths = basouPaths25(repositoryRoot);
|
|
16390
16556
|
await assertWorkspaceInitialized16(paths.root);
|
|
16391
|
-
const
|
|
16557
|
+
const built = await buildWorkspaceEntry(repositoryRoot, ctx);
|
|
16558
|
+
const entry = built.board !== void 0 ? built : { ...built, board: { why: "no_board" }, boardLive: liveBoardOf(repositoryRoot, ctx) };
|
|
16392
16559
|
return {
|
|
16393
16560
|
workspaces: [entry],
|
|
16394
16561
|
mode: "single",
|
|
16395
16562
|
nowProvider: nowProviderOf(ctx),
|
|
16396
|
-
...ctx.remoteUrlOf !== void 0 ? { remoteUrlOf: ctx.remoteUrlOf } : {}
|
|
16397
|
-
board: await viewBoardOf(repositoryRoot, paths),
|
|
16398
|
-
boardLive: liveBoardOf(repositoryRoot, ctx)
|
|
16563
|
+
...ctx.remoteUrlOf !== void 0 ? { remoteUrlOf: ctx.remoteUrlOf } : {}
|
|
16399
16564
|
};
|
|
16400
16565
|
}
|
|
16401
16566
|
function liveBoardOf(root, ctx) {
|
|
@@ -16416,13 +16581,8 @@ function sharedWhileRunning(run) {
|
|
|
16416
16581
|
return running;
|
|
16417
16582
|
};
|
|
16418
16583
|
}
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
try {
|
|
16422
|
-
own = (await readManifest19(paths)).repos?.find((repo) => repo.path === ".");
|
|
16423
|
-
} catch {
|
|
16424
|
-
own = void 0;
|
|
16425
|
-
}
|
|
16584
|
+
function viewBoardOf(root, manifest) {
|
|
16585
|
+
const own = manifest.repos?.find((repo) => repo.path === ".");
|
|
16426
16586
|
if (own?.visibility !== "private") return { why: "no_board" };
|
|
16427
16587
|
return { recordsDir: join17(root, dirname9(DEFAULT_BOARD_PATH), "records") };
|
|
16428
16588
|
}
|
|
@@ -16464,7 +16624,9 @@ async function buildWorkspaceEntry(repoRoot, ctx, labelOverride) {
|
|
|
16464
16624
|
paths,
|
|
16465
16625
|
repoRoot,
|
|
16466
16626
|
importCtx,
|
|
16467
|
-
initialized: true
|
|
16627
|
+
initialized: true,
|
|
16628
|
+
board: viewBoardOf(repoRoot, manifest),
|
|
16629
|
+
boardLive: liveBoardOf(repoRoot, ctx)
|
|
16468
16630
|
};
|
|
16469
16631
|
} catch (error) {
|
|
16470
16632
|
const notFound = error instanceof Error && error.message === "YAML file not found";
|
|
@@ -16578,7 +16740,7 @@ function installExperimentalNotice(program, names = EXPERIMENTAL_COMMANDS, write
|
|
|
16578
16740
|
function readBuildStamp() {
|
|
16579
16741
|
if (false) return void 0;
|
|
16580
16742
|
try {
|
|
16581
|
-
return JSON.parse('{"version":"0.
|
|
16743
|
+
return JSON.parse('{"version":"0.74.1","commit":"f08e08f","committedAt":"2026-10-23T19:05:22+09:00"}');
|
|
16582
16744
|
} catch {
|
|
16583
16745
|
return void 0;
|
|
16584
16746
|
}
|