@basou/cli 0.71.2 → 0.73.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 +275 -48
- package/dist/index.js.map +1 -1
- package/dist/program.js +275 -48
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -842,11 +842,13 @@ import {
|
|
|
842
842
|
assertBasouRootSafe as assertBasouRootSafe3,
|
|
843
843
|
BOARD_INIT_SAVE,
|
|
844
844
|
basouPaths as basouPaths4,
|
|
845
|
+
boardDeclarationSnapshot,
|
|
845
846
|
boardGuide,
|
|
846
847
|
boardInitText,
|
|
847
848
|
buildRecord,
|
|
848
849
|
byCodePoint,
|
|
849
850
|
diffCells,
|
|
851
|
+
diffDeclarations,
|
|
850
852
|
diffObserved,
|
|
851
853
|
displayPath as displayPath3,
|
|
852
854
|
effortStartOf,
|
|
@@ -2345,9 +2347,10 @@ async function doRunBoardMeasure(options, ctx) {
|
|
|
2345
2347
|
throw new Error("--model must name a model.");
|
|
2346
2348
|
}
|
|
2347
2349
|
const loaded = await loadBoard(options, ctx, "board measure");
|
|
2348
|
-
const
|
|
2350
|
+
const previous = await previousOf(loaded);
|
|
2351
|
+
const measurement = await measureLoaded(loaded, ctx, options.model, previous);
|
|
2349
2352
|
if (options.json === true) console.log(JSON.stringify(measurement, null, 2));
|
|
2350
|
-
else printMeasurementText(measurement, hasRecords(loaded));
|
|
2353
|
+
else printMeasurementText(measurement, hasRecords(loaded), declarationChanges(loaded, previous));
|
|
2351
2354
|
if (!measurement.complete) process.exitCode = 1;
|
|
2352
2355
|
return measurement;
|
|
2353
2356
|
}
|
|
@@ -2362,16 +2365,17 @@ async function runBoardRecord(options, ctx = {}) {
|
|
|
2362
2365
|
var RecordRefusal = class extends Error {
|
|
2363
2366
|
};
|
|
2364
2367
|
async function doRunBoardRecord(options, ctx) {
|
|
2365
|
-
let
|
|
2368
|
+
let checked;
|
|
2366
2369
|
try {
|
|
2367
|
-
|
|
2370
|
+
checked = await checkAndRecord(options, ctx);
|
|
2368
2371
|
} catch (error) {
|
|
2369
2372
|
if (error instanceof RecordRefusal || !(error instanceof Error)) throw error;
|
|
2370
2373
|
throw new RecordRefusal(`${error.message}
|
|
2371
2374
|
Nothing was written.`, { cause: error.cause });
|
|
2372
2375
|
}
|
|
2376
|
+
const { result, declared } = checked;
|
|
2373
2377
|
if (options.json === true) console.log(JSON.stringify(result, null, 2));
|
|
2374
|
-
else printRecordText(result);
|
|
2378
|
+
else printRecordText(result, declared ?? null);
|
|
2375
2379
|
return result;
|
|
2376
2380
|
}
|
|
2377
2381
|
async function checkAndRecord(options, ctx) {
|
|
@@ -2412,6 +2416,7 @@ ${parsed.errors.map((e) => ` - ${displayPath3(e)}`).join("\n")}`
|
|
|
2412
2416
|
recordedAt,
|
|
2413
2417
|
recordedWith: { basou: BASOU_CLI_VERSION, build: BASOU_BUILD?.commit ?? null }
|
|
2414
2418
|
});
|
|
2419
|
+
const declared = options.json === true ? void 0 : declarationChanges(loaded, previous);
|
|
2415
2420
|
let written = null;
|
|
2416
2421
|
if (options.dryRun !== true) {
|
|
2417
2422
|
let name;
|
|
@@ -2438,14 +2443,22 @@ ${parsed.errors.map((e) => ` - ${displayPath3(e)}`).join("\n")}`
|
|
|
2438
2443
|
};
|
|
2439
2444
|
}
|
|
2440
2445
|
return {
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2446
|
+
result: {
|
|
2447
|
+
record: written,
|
|
2448
|
+
dry_run: options.dryRun === true,
|
|
2449
|
+
complete: measurement.complete,
|
|
2450
|
+
not_found: measurement.not_found,
|
|
2451
|
+
order_anomalies: record.order_anomalies,
|
|
2452
|
+
diff
|
|
2453
|
+
},
|
|
2454
|
+
...declared === void 0 ? {} : { declared }
|
|
2447
2455
|
};
|
|
2448
2456
|
}
|
|
2457
|
+
function declarationChanges(loaded, previous) {
|
|
2458
|
+
const { last } = previous;
|
|
2459
|
+
if (last.status !== "found") return null;
|
|
2460
|
+
return diffDeclarations(last.record.declaration, boardDeclarationSnapshot(loaded.declaration));
|
|
2461
|
+
}
|
|
2449
2462
|
var INPUT_KEYS = /* @__PURE__ */ new Set([
|
|
2450
2463
|
"measure_digest",
|
|
2451
2464
|
"observed",
|
|
@@ -2595,7 +2608,7 @@ async function checkRecordsPlace(loaded, recordsDir, shown, notPrivate) {
|
|
|
2595
2608
|
}
|
|
2596
2609
|
}
|
|
2597
2610
|
}
|
|
2598
|
-
function printRecordText(result) {
|
|
2611
|
+
function printRecordText(result, declared) {
|
|
2599
2612
|
const lines = [
|
|
2600
2613
|
result.record === null ? "Dry run: the record checked out (nothing was written)." : `Recorded ${displayPath3(result.record)}`
|
|
2601
2614
|
];
|
|
@@ -2616,7 +2629,11 @@ function printRecordText(result) {
|
|
|
2616
2629
|
` observed ${displayPath3(o.name)}: ${observation(o.before)} -> ${observation(o.after)}`
|
|
2617
2630
|
);
|
|
2618
2631
|
}
|
|
2619
|
-
|
|
2632
|
+
const declaration = declarationLines(declared);
|
|
2633
|
+
lines.push(
|
|
2634
|
+
...diffLines(result.diff.measure, cells.length + observed.length + declaration.length > 0),
|
|
2635
|
+
...declaration
|
|
2636
|
+
);
|
|
2620
2637
|
}
|
|
2621
2638
|
if (!result.complete) {
|
|
2622
2639
|
lines.push(`The measurement recorded is not complete (${result.not_found.length}):`);
|
|
@@ -2802,6 +2819,16 @@ function diffLines(diff, more) {
|
|
|
2802
2819
|
if (lines.length === 0 && !more) lines.push(" nothing moved");
|
|
2803
2820
|
return lines;
|
|
2804
2821
|
}
|
|
2822
|
+
function declarationLines(changes) {
|
|
2823
|
+
if (changes === null) {
|
|
2824
|
+
return [
|
|
2825
|
+
" declaration: not compared (the previous record holds no declaration basou can compare with)"
|
|
2826
|
+
];
|
|
2827
|
+
}
|
|
2828
|
+
return changes.map(
|
|
2829
|
+
(c) => ` declaration ${displayPath3(c.at)}: ${c.change === "reordered" ? "the order changed" : c.change}`
|
|
2830
|
+
);
|
|
2831
|
+
}
|
|
2805
2832
|
function shownValue(value) {
|
|
2806
2833
|
if (value === null) return "not measured";
|
|
2807
2834
|
if (typeof value === "number") return String(Math.round(value * 1e4) / 1e4);
|
|
@@ -2933,12 +2960,18 @@ function axisLines(m) {
|
|
|
2933
2960
|
for (const u of a.unjudged) lines.push(` (${u.trigger}) not judged: ${u.why}`);
|
|
2934
2961
|
return lines;
|
|
2935
2962
|
}
|
|
2936
|
-
function printMeasurementText(m, hasRecords2) {
|
|
2963
|
+
function printMeasurementText(m, hasRecords2, declared) {
|
|
2937
2964
|
const lines = [displayPath3(m.title)];
|
|
2938
2965
|
const build = m.measured_with.build === null ? "" : ` (build ${m.measured_with.build})`;
|
|
2939
2966
|
lines.push(`Measured ${m.measured_at} with basou ${m.measured_with.basou}${build}`);
|
|
2940
2967
|
if (m.diff !== null) {
|
|
2941
|
-
|
|
2968
|
+
const declaration = declarationLines(declared);
|
|
2969
|
+
lines.push(
|
|
2970
|
+
"",
|
|
2971
|
+
`Since the previous record ${m.diff.against}:`,
|
|
2972
|
+
...diffLines(m.diff, declaration.length > 0),
|
|
2973
|
+
...declaration
|
|
2974
|
+
);
|
|
2942
2975
|
} else if (m.not_found.some((n) => n.at === "diff")) {
|
|
2943
2976
|
lines.push("", "The previous record could not be read (see Not measured).");
|
|
2944
2977
|
} else {
|
|
@@ -13938,6 +13971,17 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13938
13971
|
table.matrix th.stage { font-weight: 400; font-size: 12px; text-align: center; min-width: 64px; }
|
|
13939
13972
|
table.matrix th.stage b { display: block; font-size: 13px; }
|
|
13940
13973
|
table.matrix td.cell { text-align: center; font-size: 18px; line-height: 1; }
|
|
13974
|
+
.stage-meanings { display: none; list-style: none; padding: 0; margin: 6px 0 0; font-size: 12px; color: var(--fg-2); }
|
|
13975
|
+
/* Six stages do not fit beside their meanings below about 600px: each is
|
|
13976
|
+
drawn by its id, the meanings are listed under the matrix, and a lane
|
|
13977
|
+
name wraps. After the rules above, which it overrides. */
|
|
13978
|
+
@media (max-width: 600px) {
|
|
13979
|
+
table.matrix th.stage { min-width: 0; padding: 4px 2px; }
|
|
13980
|
+
table.matrix th.stage .meaning { display: none; }
|
|
13981
|
+
table.matrix td.cell { font-size: 16px; padding: 4px 2px; }
|
|
13982
|
+
table.matrix th:first-child { max-width: 10em; overflow-wrap: anywhere; }
|
|
13983
|
+
.stage-meanings { display: block; }
|
|
13984
|
+
}
|
|
13941
13985
|
.st::before { display: inline-block; width: 1.2em; }
|
|
13942
13986
|
.st.done::before { content: "\\25CF"; color: var(--done); }
|
|
13943
13987
|
.st.part::before { content: "\\25D0"; color: var(--done); }
|
|
@@ -13958,6 +14002,11 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13958
14002
|
.chip.blocked { background: var(--chip-blocked); }
|
|
13959
14003
|
.chip.unverified { background: var(--chip-unverified); }
|
|
13960
14004
|
.muted { color: var(--fg-2); }
|
|
14005
|
+
.sub { font-size: 12px; color: var(--fg-2); overflow-wrap: anywhere; }
|
|
14006
|
+
ul.sub { margin: 0; padding-left: 18px; }
|
|
14007
|
+
td.wrap { overflow-wrap: anywhere; min-width: 10em; }
|
|
14008
|
+
tr.notes td { padding-top: 0; }
|
|
14009
|
+
.chip.changed { margin-left: 0; margin-right: 6px; background: var(--chip-unverified); }
|
|
13961
14010
|
.bar { height: 10px; background: var(--fill); border-radius: 5px; min-width: 120px; position: relative; overflow: hidden; }
|
|
13962
14011
|
.bar span { position: absolute; left: 0; top: 0; bottom: 0; background: var(--s1); }
|
|
13963
14012
|
figure { margin: 16px 0; }
|
|
@@ -14087,6 +14136,60 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14087
14136
|
return JSON.stringify(k) + ':' + v;
|
|
14088
14137
|
}).join(',') + '}';
|
|
14089
14138
|
}
|
|
14139
|
+
// The parts of a value drawn on one line, and what an http value says of each word.
|
|
14140
|
+
var DOT = ' ' + String.fromCharCode(183) + ' ';
|
|
14141
|
+
var FOUND = String.fromCharCode(10003);
|
|
14142
|
+
var NOT_FOUND = String.fromCharCode(10007);
|
|
14143
|
+
// An http value read as its parts: the status, the redirects, where it
|
|
14144
|
+
// landed, and what it read off the body (when the status is 2xx) or that it
|
|
14145
|
+
// did not. Numbers and strings are drawn as they are.
|
|
14146
|
+
function httpText(h) {
|
|
14147
|
+
var parts = [String(h.status), fill(S.observed.redirects, { n: h.redirects }), h.final_url];
|
|
14148
|
+
if (h.body === null) parts.push(S.observed.bodyNotRead);
|
|
14149
|
+
else if (h.body) {
|
|
14150
|
+
if (h.body.words) {
|
|
14151
|
+
parts.push(h.body.words.map(function (w) { return w.word + ' ' + (w.found ? FOUND : NOT_FOUND); }).join(' '));
|
|
14152
|
+
}
|
|
14153
|
+
if (h.body.count !== undefined) parts.push(fill(S.observed.count, { n: h.body.count }));
|
|
14154
|
+
if (h.body.capture !== undefined) {
|
|
14155
|
+
parts.push(h.body.capture === null ? S.observed.captureNone : fill(S.observed.capture, { value: JSON.stringify(h.body.capture) }));
|
|
14156
|
+
}
|
|
14157
|
+
}
|
|
14158
|
+
return parts.join(DOT);
|
|
14159
|
+
}
|
|
14160
|
+
// A value of an observation as the page draws it: an http value in its
|
|
14161
|
+
// shape read as its parts, one with words beside what it says of each, and
|
|
14162
|
+
// any other as it is (a string) or as JSON. A test lifts this function.
|
|
14163
|
+
function observedText(value, words, http) {
|
|
14164
|
+
if (http) return httpText(http);
|
|
14165
|
+
if (words) return withWords(value, words);
|
|
14166
|
+
return shown(value);
|
|
14167
|
+
}
|
|
14168
|
+
// The value of an observation that moved, and what the previous record
|
|
14169
|
+
// held: a value whose type alone moved ("12" and 12) is drawn as JSON, so
|
|
14170
|
+
// that the two do not read the same. A test lifts this function.
|
|
14171
|
+
function movedText(o) {
|
|
14172
|
+
var m = o.moved;
|
|
14173
|
+
var now = observedText(o.value, o.words, o.http);
|
|
14174
|
+
if (m.status === 'none') return { now: now, then: S.observed.beforeNone };
|
|
14175
|
+
if (m.value === null) {
|
|
14176
|
+
return { now: now, then: S.observed.beforeNotObserved + (m.error ? ' (' + m.error + ')' : '') };
|
|
14177
|
+
}
|
|
14178
|
+
var then = observedText(m.value, m.words, m.http);
|
|
14179
|
+
if ((typeof m.value === 'string') !== (typeof o.value === 'string')) {
|
|
14180
|
+
then = JSON.stringify(m.value);
|
|
14181
|
+
if (then === now) now = JSON.stringify(o.value);
|
|
14182
|
+
}
|
|
14183
|
+
return { now: now, then: fill(S.observed.before, { value: then }) + (m.error ? ' (' + m.error + ')' : '') };
|
|
14184
|
+
}
|
|
14185
|
+
// A measure's value: the paths of a file_paths by how many, a number with
|
|
14186
|
+
// its unit, and a string (a file's name, a capture), which is no amount,
|
|
14187
|
+
// without it.
|
|
14188
|
+
function measureText(m) {
|
|
14189
|
+
if (Array.isArray(m.value)) return num(m.value.length) + ' ' + m.unit;
|
|
14190
|
+
return num(m.value) + (typeof m.value === 'number' ? ' ' + m.unit : '');
|
|
14191
|
+
}
|
|
14192
|
+
function signed(n) { return (n > 0 ? '+' : '') + num(n); }
|
|
14090
14193
|
function stateName(state) { return S.states[state] || state; }
|
|
14091
14194
|
function setStatus(message, isErr) {
|
|
14092
14195
|
var s = $('status');
|
|
@@ -14167,21 +14270,47 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14167
14270
|
k, el('div', { class: 'v', text: num(t.value) }), sub === null ? null : el('div', { class: 's', text: sub })
|
|
14168
14271
|
]));
|
|
14169
14272
|
});
|
|
14273
|
+
return section(S.sections.summary, false, [el('div', null, [prose(s.text), reported()]), tiles]);
|
|
14274
|
+
}
|
|
14275
|
+
|
|
14276
|
+
// The observations outside, which the record holds in its summary, in a
|
|
14277
|
+
// section of their own after the lanes.
|
|
14278
|
+
function observations(b) {
|
|
14279
|
+
var s = b.summary;
|
|
14170
14280
|
var observed;
|
|
14171
14281
|
if (s.observed.length === 0) {
|
|
14172
14282
|
observed = el('p', { class: 'muted', text: S.observed.none });
|
|
14173
14283
|
} else {
|
|
14174
|
-
var rows =
|
|
14284
|
+
var rows = [];
|
|
14285
|
+
s.observed.forEach(function (o) {
|
|
14286
|
+
var cell = el('td', { class: 'wrap' });
|
|
14175
14287
|
var value;
|
|
14176
|
-
if (o.value !== null
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14288
|
+
if (o.value !== null && o.moved) {
|
|
14289
|
+
var pair = movedText(o);
|
|
14290
|
+
cell.appendChild(el('span', { class: 'chip changed', text: S.observed.changed }));
|
|
14291
|
+
value = pair.now;
|
|
14292
|
+
cell.appendChild(el('span', { text: value + (o.error ? ' (' + o.error + ')' : '') }));
|
|
14293
|
+
cell.appendChild(el('div', { class: 'sub', text: pair.then }));
|
|
14294
|
+
} else {
|
|
14295
|
+
if (o.value !== null) value = observedText(o.value, o.words, o.http);
|
|
14296
|
+
else if (o.previous && o.previous.status === 'value') value = fill(S.observed.missing, { value: shown(o.previous.value) });
|
|
14297
|
+
else if (o.previous && o.previous.status === 'unreadable') value = S.observed.missingPreviousUnreadable;
|
|
14298
|
+
else value = S.observed.missingNoPrevious;
|
|
14299
|
+
if (o.error) value += ' (' + o.error + ')';
|
|
14300
|
+
cell.appendChild(el('span', { text: value }));
|
|
14301
|
+
}
|
|
14302
|
+
// What the record's declaration says it is and looks at, under its name.
|
|
14303
|
+
var what = o.kind ? [o.kind].concat(o.looks_at || []).join(DOT) : null;
|
|
14304
|
+
rows.push(el('tr', null, [
|
|
14305
|
+
el('td', null, [el('div', { text: o.name }), what === null ? null : el('div', { class: 'sub', text: what })]),
|
|
14306
|
+
cell,
|
|
14307
|
+
el('td', { text: o.observed_at }), el('td', { class: 'wrap', text: o.source })
|
|
14308
|
+
]));
|
|
14309
|
+
if (o.notes && o.notes.length > 0) {
|
|
14310
|
+
rows.push(el('tr', { class: 'notes' }, [el('td', { colspan: '4' }, [
|
|
14311
|
+
el('ul', { class: 'sub' }, o.notes.map(function (n) { return el('li', null, [prose(n, 'span')]); }))
|
|
14312
|
+
])]));
|
|
14313
|
+
}
|
|
14185
14314
|
});
|
|
14186
14315
|
observed = el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [
|
|
14187
14316
|
el('tr', null, [
|
|
@@ -14190,13 +14319,11 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14190
14319
|
])
|
|
14191
14320
|
].concat(rows))]);
|
|
14192
14321
|
}
|
|
14193
|
-
var
|
|
14194
|
-
|
|
14195
|
-
el('
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
observed
|
|
14199
|
-
]);
|
|
14322
|
+
var children = [observed];
|
|
14323
|
+
if (s.previous_record === 'unreadable' && s.observed.length > 0) {
|
|
14324
|
+
children.push(el('p', { class: 'muted', text: S.observed.previousUnreadable }));
|
|
14325
|
+
}
|
|
14326
|
+
return section(S.observed.heading, true, children);
|
|
14200
14327
|
}
|
|
14201
14328
|
|
|
14202
14329
|
var SVGNS = 'http://www.w3.org/2000/svg';
|
|
@@ -14428,16 +14555,24 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14428
14555
|
]);
|
|
14429
14556
|
};
|
|
14430
14557
|
var union = e.active_ms.union;
|
|
14558
|
+
// Over the daily rows, today's included (one more than the days elapsed),
|
|
14559
|
+
// so that the first day is a day; the sub-text names the divisor.
|
|
14431
14560
|
var perDay = union === null || !e.period_days ? null : union / e.period_days;
|
|
14432
14561
|
var perWorked = union === null || !e.active_days ? null : union / e.active_days;
|
|
14562
|
+
var perDaySub = [
|
|
14563
|
+
perDay === null ? null : fill(S.effort.perDayOver, { days: num(e.period_days) }),
|
|
14564
|
+
perWorked === null ? null : fill(S.effort.perDayWorked, { time: hm(perWorked) })
|
|
14565
|
+
].filter(function (part) { return part !== null; }).join(DOT);
|
|
14433
14566
|
var tokens = e.sessions_without_tokens ? fill(S.effort.withoutTokens, { n: e.sessions_without_tokens }) : null;
|
|
14567
|
+
// Each tool's time is the union of its sessions' intervals, as Active is.
|
|
14568
|
+
var unionOf = function (ms) { return ms === null ? null : S.effort.toolUnion; };
|
|
14434
14569
|
var tiles = el('div', { class: 'tiles' }, [
|
|
14435
14570
|
tile(S.effort.elapsed, e.elapsed_days === null ? S.effort.notMeasured : fill(S.effort.days, { days: e.elapsed_days }),
|
|
14436
14571
|
e.time_zone === null ? fill(S.effort.from, { date: e.start }) : fill(S.effort.fromZone, { date: e.start, zone: e.time_zone })),
|
|
14437
14572
|
tile(S.effort.active, hm(union), e.active_days === null ? null : fill(S.effort.daysWorked, { n: e.active_days })),
|
|
14438
|
-
tile(S.effort.claude, hm(e.active_ms.claude),
|
|
14439
|
-
tile(S.effort.codex, e.active_ms.codex === null && union !== null ? S.effort.noCodex : hm(e.active_ms.codex),
|
|
14440
|
-
tile(S.effort.perDay, hm(perDay),
|
|
14573
|
+
tile(S.effort.claude, hm(e.active_ms.claude), unionOf(e.active_ms.claude)),
|
|
14574
|
+
tile(S.effort.codex, e.active_ms.codex === null && union !== null ? S.effort.noCodex : hm(e.active_ms.codex), unionOf(e.active_ms.codex)),
|
|
14575
|
+
tile(S.effort.perDay, hm(perDay), perDaySub),
|
|
14441
14576
|
tile(S.effort.outputTokens, num(e.output_tokens), tokens)
|
|
14442
14577
|
]);
|
|
14443
14578
|
var commits = e.commits === null ? S.effort.notMeasured : e.commits.map(function (c) {
|
|
@@ -14475,8 +14610,13 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14475
14610
|
})
|
|
14476
14611
|
)));
|
|
14477
14612
|
}
|
|
14613
|
+
// The meaning is the head's title too, as a screen reader reads it and a
|
|
14614
|
+
// pointer that hovers shows it, and the text beside the id is left out of
|
|
14615
|
+
// what a screen reader reads, so that it is read once.
|
|
14478
14616
|
var head = el('tr', null, [el('th', { text: S.matrix.lane })].concat(x.stages.map(function (s) {
|
|
14479
|
-
return el('th', { class: 'stage'
|
|
14617
|
+
return el('th', { class: 'stage', title: s.meaning }, [
|
|
14618
|
+
el('b', { text: s.id }), el('span', { class: 'meaning', 'aria-hidden': 'true', text: s.meaning })
|
|
14619
|
+
]);
|
|
14480
14620
|
})));
|
|
14481
14621
|
var rows = x.lanes.map(function (lane) {
|
|
14482
14622
|
return el('tr', null, [el('th', { text: lane.name })].concat(lane.cells.map(function (c) {
|
|
@@ -14488,6 +14628,11 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14488
14628
|
})));
|
|
14489
14629
|
});
|
|
14490
14630
|
children.push(el('div', { class: 'scroll' }, [el('table', { class: 'matrix' }, [head].concat(rows))]));
|
|
14631
|
+
// What each stage means, drawn where a narrow screen gives a stage its id
|
|
14632
|
+
// alone (and hidden where the heads say it).
|
|
14633
|
+
children.push(el('ul', { class: 'stage-meanings' }, x.stages.map(function (s) {
|
|
14634
|
+
return el('li', null, [el('b', { text: s.id }), ' ' + s.meaning]);
|
|
14635
|
+
})));
|
|
14491
14636
|
var legend = el('div', { class: 'legend' });
|
|
14492
14637
|
['done', 'part', 'blocked', 'shelved', 'none', 'unverified'].forEach(function (s) {
|
|
14493
14638
|
legend.appendChild(el('span', null, [el('span', { class: 'st ' + s }), stateName(s)]));
|
|
@@ -14535,6 +14680,27 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14535
14680
|
}));
|
|
14536
14681
|
}
|
|
14537
14682
|
|
|
14683
|
+
// Every measure of the record, with the lanes it is drawn in and how much a
|
|
14684
|
+
// number moved since the previous record.
|
|
14685
|
+
function measures(b) {
|
|
14686
|
+
if (b.measures.length === 0) {
|
|
14687
|
+
return section(S.sections.measures, false, [el('p', { class: 'muted', text: S.measures.none })]);
|
|
14688
|
+
}
|
|
14689
|
+
var head = el('tr', null, [
|
|
14690
|
+
el('th', { text: S.measures.id }), el('th', { text: S.measures.value }),
|
|
14691
|
+
el('th', { text: S.measures.lanes }), el('th', { class: 'n', text: S.measures.delta })
|
|
14692
|
+
]);
|
|
14693
|
+
var rows = b.measures.map(function (m) {
|
|
14694
|
+
return el('tr', { 'data-measure': m.id }, [
|
|
14695
|
+
el('td', null, [el('code', { text: m.id })]),
|
|
14696
|
+
el('td', { class: 'wrap', text: measureText(m) }),
|
|
14697
|
+
el('td', { text: m.lanes.length === 0 ? '-' : m.lanes.join(', ') }),
|
|
14698
|
+
el('td', { class: 'n', text: m.delta === null || m.delta === undefined ? '' : signed(m.delta) })
|
|
14699
|
+
]);
|
|
14700
|
+
});
|
|
14701
|
+
return section(S.sections.measures, false, [el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [head].concat(rows))])]);
|
|
14702
|
+
}
|
|
14703
|
+
|
|
14538
14704
|
function composition(b) {
|
|
14539
14705
|
if (b.composition.length === 0) {
|
|
14540
14706
|
return section(S.sections.composition, false, [el('p', { class: 'muted', text: S.composition.none })]);
|
|
@@ -14622,7 +14788,10 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14622
14788
|
var b = page.board;
|
|
14623
14789
|
// The board's own title, so that boards open in other tabs can be told apart.
|
|
14624
14790
|
document.title = b.heading.title;
|
|
14625
|
-
|
|
14791
|
+
// Where each lane stops, right under the summary's tiles, and the lanes,
|
|
14792
|
+
// before the observations and the charts of the effort.
|
|
14793
|
+
[heading(b), summary(b), matrix(b), lanes(b), observations(b), effort(b, false), measures(b), composition(b),
|
|
14794
|
+
turns(b), recordRepos(b), recordComponents(b), footnotes(b)]
|
|
14626
14795
|
.forEach(function (node) { root.appendChild(node); });
|
|
14627
14796
|
}
|
|
14628
14797
|
|
|
@@ -14648,12 +14817,14 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14648
14817
|
function missingIn(l) {
|
|
14649
14818
|
return function (at) { return l.footnotes.not_found.some(function (n) { return n.at === at; }); };
|
|
14650
14819
|
}
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14820
|
+
// The repositories as a table. older: a record of version 1 or 2, which
|
|
14821
|
+
// measured no base, ahead or fetch time (drawn as '-') and held the
|
|
14822
|
+
// commits behind as behind_main.
|
|
14823
|
+
function reposTable(list, missing, older) {
|
|
14824
|
+
var labels = [S.live.repo, S.live.branch, S.live.head, S.live.lastCommit, S.live.commits, S.live.files, S.live.uncommitted, S.live.base, S.live.behind, S.live.ahead, S.live.fetchedAt];
|
|
14825
|
+
var numeric = [4, 5, 6, 8, 9];
|
|
14655
14826
|
var head = el('tr', null, labels.map(function (label, i) { return el('th', { class: numeric.indexOf(i) !== -1 ? 'n' : '', text: label }); }));
|
|
14656
|
-
var rows =
|
|
14827
|
+
var rows = list.map(function (r) {
|
|
14657
14828
|
var at = 'repos[' + r.path + ']';
|
|
14658
14829
|
// A null the measurement says it could not measure, or one that means
|
|
14659
14830
|
// so (a detached HEAD, no commit yet, no base, no fetch of it on
|
|
@@ -14662,20 +14833,76 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14662
14833
|
if (v !== null) return show(v);
|
|
14663
14834
|
return missing(at) || missing(at + '.' + field) ? S.tiles.notMeasured : '-';
|
|
14664
14835
|
};
|
|
14836
|
+
var unmeasured = function (field, v, show) { return older ? '-' : value(field, v, show); };
|
|
14665
14837
|
return el('tr', null, [
|
|
14666
14838
|
el('td', { text: r.name === null ? r.path : r.name }),
|
|
14667
14839
|
el('td', { text: value('branch', r.branch, String) }),
|
|
14668
14840
|
el('td', { text: value('head', r.head, function (h) { return h.slice(0, 7); }) }),
|
|
14669
14841
|
el('td', { text: value('last_commit', r.last_commit, when) }),
|
|
14670
14842
|
el('td', { class: 'n', text: num(r.commits) }),
|
|
14843
|
+
el('td', { class: 'n', text: num(r.files) }),
|
|
14671
14844
|
el('td', { class: 'n', text: num(r.uncommitted) }),
|
|
14672
|
-
el('td', { text:
|
|
14673
|
-
el('td', { class: 'n', text: value('behind', r.behind, num) }),
|
|
14674
|
-
el('td', { class: 'n', text:
|
|
14675
|
-
el('td', { text:
|
|
14845
|
+
el('td', { text: unmeasured('base', r.base, String) }),
|
|
14846
|
+
el('td', { class: 'n', text: value(older ? 'behind_main' : 'behind', r.behind, num) }),
|
|
14847
|
+
el('td', { class: 'n', text: unmeasured('ahead', r.ahead, num) }),
|
|
14848
|
+
el('td', { text: unmeasured('fetched_at', r.fetched_at, when) })
|
|
14676
14849
|
]);
|
|
14677
14850
|
});
|
|
14678
|
-
return
|
|
14851
|
+
return el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [head].concat(rows))]);
|
|
14852
|
+
}
|
|
14853
|
+
function liveRepos(l) {
|
|
14854
|
+
return section(S.live.repos, false, [reposTable(l.repos, missingIn(l), false)]);
|
|
14855
|
+
}
|
|
14856
|
+
// The repositories as the record measured them, by its version.
|
|
14857
|
+
function recordRepos(b) {
|
|
14858
|
+
var r = b.repos;
|
|
14859
|
+
if (!r) return section(S.live.repos, false, [el('p', { class: 'muted', text: S.record.reposUnread })]);
|
|
14860
|
+
var children = [reposTable(r.list, missingIn(b), !r.base_measured)];
|
|
14861
|
+
if (!r.base_measured) children.push(el('p', { class: 'muted', text: fill(S.record.notMeasuredByVersion, { version: r.record_version }) }));
|
|
14862
|
+
return section(S.live.repos, false, children);
|
|
14863
|
+
}
|
|
14864
|
+
// The components the record found, by the lanes its registry counts them
|
|
14865
|
+
// in, then those in no lane (folded), those not registered, and those gone.
|
|
14866
|
+
function recordComponents(b) {
|
|
14867
|
+
var c = b.components;
|
|
14868
|
+
if (!c) return section(S.live.components, false, [el('p', { class: 'muted', text: S.record.componentsUnread })]);
|
|
14869
|
+
if (!c.measured) {
|
|
14870
|
+
return section(S.live.components, false, [
|
|
14871
|
+
el('p', { class: 'muted', text: S.record.componentsNotMeasured }),
|
|
14872
|
+
el('ul', null, c.reasons.map(function (reason) { return el('li', { text: reason }); }))
|
|
14873
|
+
]);
|
|
14874
|
+
}
|
|
14875
|
+
var item = function (x) {
|
|
14876
|
+
var kinds = x.kinds === null ? S.record.notFound : x.kinds.join(', ');
|
|
14877
|
+
var parts = [el('code', { text: x.key }), el('span', { class: 'muted', text: ' ' + kinds })];
|
|
14878
|
+
if (x.kind_changed) {
|
|
14879
|
+
parts.push(el('span', { class: 'chip changed', text: fill(S.record.kindChanged, { before: x.kind_changed.before.join(', ') }) }));
|
|
14880
|
+
}
|
|
14881
|
+
if (x.note) parts.push(el('div', { class: 'sub', text: x.note }));
|
|
14882
|
+
return el('li', { 'data-component': x.key }, parts);
|
|
14883
|
+
};
|
|
14884
|
+
var group = function (title, list, empty) {
|
|
14885
|
+
return [el('h3', { text: title }), list.length === 0 ? el('p', { class: 'muted', text: empty }) : el('ul', null, list.map(item))];
|
|
14886
|
+
};
|
|
14887
|
+
var children = [];
|
|
14888
|
+
c.lanes.forEach(function (lane) {
|
|
14889
|
+
children = children.concat(group(lane.name, lane.components, S.record.noComponentInLane));
|
|
14890
|
+
});
|
|
14891
|
+
// Those in no lane can be most of them: folded under how many they are.
|
|
14892
|
+
if (c.uncounted.length > 0) {
|
|
14893
|
+
children.push(el('details', null, [
|
|
14894
|
+
el('summary', { text: fill(S.record.uncountedFolded, { n: num(c.uncounted.length) }) }),
|
|
14895
|
+
el('ul', null, c.uncounted.map(item))
|
|
14896
|
+
]));
|
|
14897
|
+
} else {
|
|
14898
|
+
children = children.concat(group(S.record.uncounted, c.uncounted, S.record.none));
|
|
14899
|
+
}
|
|
14900
|
+
children = children.concat(group(S.record.unacknowledged, c.unacknowledged, S.record.none));
|
|
14901
|
+
children.push(el('h3', { text: S.record.gone }));
|
|
14902
|
+
children.push(c.gone === null ? el('p', { class: 'muted', text: S.record.goneUnknown })
|
|
14903
|
+
: c.gone.length === 0 ? el('p', { class: 'muted', text: S.record.none })
|
|
14904
|
+
: el('ul', null, c.gone.map(function (key) { return el('li', null, [el('code', { text: key })]); })));
|
|
14905
|
+
return section(S.live.components, false, children);
|
|
14679
14906
|
}
|
|
14680
14907
|
function liveTrail(l) {
|
|
14681
14908
|
var t = l.trail;
|
|
@@ -16336,7 +16563,7 @@ function installExperimentalNotice(program2, names = EXPERIMENTAL_COMMANDS, writ
|
|
|
16336
16563
|
function readBuildStamp() {
|
|
16337
16564
|
if (false) return void 0;
|
|
16338
16565
|
try {
|
|
16339
|
-
return JSON.parse('{"version":"0.
|
|
16566
|
+
return JSON.parse('{"version":"0.73.0","commit":"fdfa3a5","committedAt":"2026-10-20T20:30:59+09:00"}');
|
|
16340
16567
|
} catch {
|
|
16341
16568
|
return void 0;
|
|
16342
16569
|
}
|