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