@astrosheep/keiyaku 2.9.8 → 2.9.9
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/build/.tsbuildinfo +1 -1
- package/build/agents/harness/projection.js +8 -6
- package/build/cli/render/kanshi.js +238 -80
- package/build/cli/render/projection-activity.js +62 -27
- package/build/cli/render/status.js +4 -19
- package/build/cli/render/wait.js +42 -64
- package/build/config/env-keys.js +1 -1
- package/build/config/env.js +1 -1
- package/build/core/projection/generation/projection-generation-execution.js +7 -1
- package/build/core/projection/projection-activity.js +2 -0
- package/build/core/projection/projection-status.js +44 -9
- package/build/core/status/board.js +13 -10
- package/build/core/task/settlement-git.js +2 -2
- package/build/generated/version.js +2 -2
- package/package.json +1 -1
package/build/cli/render/wait.js
CHANGED
|
@@ -1,29 +1,8 @@
|
|
|
1
|
-
import { formatTimelineDuration,
|
|
1
|
+
import { formatTimelineDuration, renderPendingProjectionTell, renderProjectionActivity, } from "./projection-activity.js";
|
|
2
2
|
import { displayColumns, resolveLineColumns, truncateColumns } from "./line-width.js";
|
|
3
3
|
import { formatTellCommand, projectionRejoinHintLines, textResponse } from "./shared.js";
|
|
4
4
|
import { renderTerminalFailureFace } from "./terminal-failure.js";
|
|
5
5
|
const WAIT_HEADER_MAX_COLUMNS = 60;
|
|
6
|
-
const WAIT_BODY_MAX_ROWS = 10;
|
|
7
|
-
const WAIT_ROW_PRIORITY = {
|
|
8
|
-
"end-anchor": 100,
|
|
9
|
-
"storage-diagnostic": 90,
|
|
10
|
-
diagnostic: 90,
|
|
11
|
-
tell: 80,
|
|
12
|
-
summary: 70,
|
|
13
|
-
activity: 60,
|
|
14
|
-
plan: 55,
|
|
15
|
-
liveness: 50,
|
|
16
|
-
silence: 65,
|
|
17
|
-
file: 20,
|
|
18
|
-
};
|
|
19
|
-
/** One owner admits every wait-body row, then restores presentation order. */
|
|
20
|
-
export function selectWaitBodyRows(rows, limit = WAIT_BODY_MAX_ROWS) {
|
|
21
|
-
const selected = rows
|
|
22
|
-
.slice()
|
|
23
|
-
.sort((left, right) => WAIT_ROW_PRIORITY[right.kind] - WAIT_ROW_PRIORITY[left.kind] || left.order - right.order)
|
|
24
|
-
.slice(0, limit);
|
|
25
|
-
return selected.sort((left, right) => left.order - right.order);
|
|
26
|
-
}
|
|
27
6
|
function shortAddress(projectionId) {
|
|
28
7
|
return /\/([0-9a-f]{8})$/.exec(projectionId)?.[1] ?? projectionId;
|
|
29
8
|
}
|
|
@@ -70,12 +49,23 @@ function waitHeader(projectionId, akuma, snapshot, outputColumns) {
|
|
|
70
49
|
const dashCount = Math.max(1, maxColumns - displayColumns(`${prefix} ${state}`));
|
|
71
50
|
return `${prefix} ${"─".repeat(dashCount)} ${state}`;
|
|
72
51
|
}
|
|
73
|
-
function
|
|
74
|
-
return snapshot.tells.window.map((tell) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
52
|
+
function pendingTellRows(snapshot, maxColumns, orderOffset) {
|
|
53
|
+
return snapshot.tells.window.map((tell, index) => ({
|
|
54
|
+
line: renderPendingProjectionTell(tell, {
|
|
55
|
+
anchorMs: snapshot.observedAtMs,
|
|
56
|
+
maxColumns,
|
|
57
|
+
}),
|
|
58
|
+
at: tell.createdAt,
|
|
59
|
+
order: orderOffset + index,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
function orderFlowRows(rows) {
|
|
63
|
+
return rows.slice().sort((left, right) => {
|
|
64
|
+
const leftAt = Date.parse(left.at ?? "");
|
|
65
|
+
const rightAt = Date.parse(right.at ?? "");
|
|
66
|
+
const safeLeft = Number.isFinite(leftAt) ? leftAt : Number.POSITIVE_INFINITY;
|
|
67
|
+
const safeRight = Number.isFinite(rightAt) ? rightAt : Number.POSITIVE_INFINITY;
|
|
68
|
+
return safeLeft - safeRight || left.order - right.order;
|
|
79
69
|
});
|
|
80
70
|
}
|
|
81
71
|
function ledgerHint(projectionId, snapshot) {
|
|
@@ -142,14 +132,13 @@ function unknownResponse(projectionId, akuma, snapshot, maxColumns) {
|
|
|
142
132
|
anchorMs: snapshot.observedAtMs,
|
|
143
133
|
state: "unknown",
|
|
144
134
|
showPlan: false,
|
|
135
|
+
showSilence: false,
|
|
136
|
+
showTerminalFiles: false,
|
|
145
137
|
...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
|
|
146
138
|
maxColumns,
|
|
139
|
+
leadingOmittedCount: snapshot.activity.omittedSettledCount,
|
|
147
140
|
});
|
|
148
|
-
const historicalLines =
|
|
149
|
-
kind: rendered.rowKinds[index] ?? "activity",
|
|
150
|
-
line,
|
|
151
|
-
order: index,
|
|
152
|
-
}))).map((row) => row.line.replace(/[┆├]/, "│"));
|
|
141
|
+
const historicalLines = rendered.lines.map((line) => line.replace(/[┆├]/, "│"));
|
|
153
142
|
return {
|
|
154
143
|
...textResponse([
|
|
155
144
|
`? ${akuma} · projection: ${projectionId} · unknown`,
|
|
@@ -216,43 +205,32 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
216
205
|
if (state === "returned") {
|
|
217
206
|
return returnedResponse(projectionId, result);
|
|
218
207
|
}
|
|
219
|
-
const tells = pendingTellLines(snapshot, maxColumns);
|
|
220
|
-
const summary = ["running", "stalled", "unknown"].includes(state)
|
|
221
|
-
? renderProjectionActivitySummary(snapshot.activity, {
|
|
222
|
-
state,
|
|
223
|
-
...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
|
|
224
|
-
maxColumns,
|
|
225
|
-
})
|
|
226
|
-
: undefined;
|
|
227
208
|
const rendered = renderProjectionActivity(snapshot.activity, {
|
|
228
209
|
anchorMs: snapshot.observedAtMs,
|
|
229
210
|
state,
|
|
230
|
-
showPlan:
|
|
211
|
+
showPlan: false,
|
|
212
|
+
showSilence: false,
|
|
213
|
+
showTerminalFiles: false,
|
|
231
214
|
...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
|
|
232
215
|
maxColumns,
|
|
216
|
+
leadingOmittedCount: snapshot.activity.omittedSettledCount,
|
|
233
217
|
});
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const bodyLines = selectWaitBodyRows(bodyPlan).map((row) => truncateColumns(row.line, maxColumns));
|
|
251
|
-
const lines = [waitHeader(projectionId, result.pact.akuma, snapshot, maxColumns), ...bodyLines];
|
|
252
|
-
const pendingTellCount = snapshot.tells.totals.undelivered;
|
|
253
|
-
if (pendingTellCount > 0) {
|
|
254
|
-
lines.push(`${pendingTellCount} tell${pendingTellCount === 1 ? "" : "s"} undelivered`);
|
|
255
|
-
}
|
|
218
|
+
const diagnosticLines = (snapshot.eventDiagnostics ?? [])
|
|
219
|
+
.map((diagnostic) => `‼ ${diagnostic.kind} · ${diagnostic.detail}`);
|
|
220
|
+
const activityRows = rendered.lines.map((line, index) => ({
|
|
221
|
+
line,
|
|
222
|
+
at: rendered.rowAts[index],
|
|
223
|
+
order: index,
|
|
224
|
+
}));
|
|
225
|
+
const flowLines = orderFlowRows([
|
|
226
|
+
...activityRows,
|
|
227
|
+
...pendingTellRows(snapshot, maxColumns, activityRows.length),
|
|
228
|
+
]).map((row) => truncateColumns(row.line, maxColumns));
|
|
229
|
+
const lines = [
|
|
230
|
+
waitHeader(projectionId, result.pact.akuma, snapshot, maxColumns),
|
|
231
|
+
...diagnosticLines,
|
|
232
|
+
...flowLines,
|
|
233
|
+
];
|
|
256
234
|
const nextActions = state === "running" && options.runningActions === false
|
|
257
235
|
? []
|
|
258
236
|
: nextActionLines(options.alias ?? projectionId, result, state);
|
package/build/config/env-keys.js
CHANGED
|
@@ -27,7 +27,7 @@ const ENV_KEY_ENTRIES = [
|
|
|
27
27
|
{ key: ENV_KEYS.AGENT_OVERRIDE, defaultValue: "", description: "Override default agent name", category: "subagent" },
|
|
28
28
|
{ key: ENV_KEYS.DISABLE_SUBAGENT_SPAWN, defaultValue: "0", description: "Disable subprocess subagent spawning when set to 1", category: "subagent" },
|
|
29
29
|
{ key: ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS, defaultValue: "300000", description: "Subagent provider-ingress idle timeout in milliseconds", category: "subagent" },
|
|
30
|
-
{ key: ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS, defaultValue: "
|
|
30
|
+
{ key: ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS, defaultValue: "0", description: "Subagent absolute execution policy budget in milliseconds; 0 disables it", category: "subagent" },
|
|
31
31
|
{ key: ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "Codex runtime output/diagnostics capture cap", category: "subagent" },
|
|
32
32
|
{ key: ENV_KEYS.CLAUDE_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "Claude runtime output/diagnostics capture cap", category: "subagent" },
|
|
33
33
|
{ key: ENV_KEYS.OPENCODE_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "OpenCode runtime output/diagnostics capture cap", category: "subagent" },
|
package/build/config/env.js
CHANGED
|
@@ -141,7 +141,7 @@ const subagentSchema = z.object({
|
|
|
141
141
|
nameOverride: z.string().default(getEnvDefaultValue(ENV_KEYS.AGENT_OVERRIDE)).transform((value) => value.trim()),
|
|
142
142
|
disableSpawn: booleanFlagEnv(ENV_KEYS.DISABLE_SUBAGENT_SPAWN),
|
|
143
143
|
execIdleTimeoutMs: positiveIntEnv(ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS),
|
|
144
|
-
execMaxDurationMs:
|
|
144
|
+
execMaxDurationMs: nonNegativeIntEnv(ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS),
|
|
145
145
|
});
|
|
146
146
|
const codexSchema = z.object({
|
|
147
147
|
execMaxCaptureChars: positiveIntEnv(ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS),
|
|
@@ -26,6 +26,12 @@ function requirePositiveSafeInteger(value, field) {
|
|
|
26
26
|
}
|
|
27
27
|
return value;
|
|
28
28
|
}
|
|
29
|
+
function requireNonNegativeSafeInteger(value, field) {
|
|
30
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
31
|
+
throw new Error(`generation launch ${field} must be a non-negative safe integer`);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
29
35
|
function parseLaunchInputs(launch) {
|
|
30
36
|
const raw = launch.facts.inputs;
|
|
31
37
|
if (!isObject(raw))
|
|
@@ -58,7 +64,7 @@ function parseLaunchInputs(launch) {
|
|
|
58
64
|
...(context ? { context } : {}),
|
|
59
65
|
launchSnapshot,
|
|
60
66
|
idleTimeoutMs: requirePositiveSafeInteger(raw.idleTimeoutMs, "idleTimeoutMs"),
|
|
61
|
-
executionTimeoutMs:
|
|
67
|
+
executionTimeoutMs: requireNonNegativeSafeInteger(raw.executionTimeoutMs, "executionTimeoutMs"),
|
|
62
68
|
persistProjectionResponse: raw.persistProjectionResponse,
|
|
63
69
|
...(raw.session ? { session: raw.session } : {}),
|
|
64
70
|
...(resumePath ? { resumePath } : {}),
|
|
@@ -211,6 +211,7 @@ export function foldAgentActivity(events) {
|
|
|
211
211
|
settled.sort((left, right) => left.order - right.order);
|
|
212
212
|
pinned.sort((left, right) => left.order - right.order);
|
|
213
213
|
const window = settled.slice(-AGENT_ACTIVITY_WINDOW_SIZE);
|
|
214
|
+
const omittedSettledCount = Math.max(0, settled.length - window.length);
|
|
214
215
|
const visibleOrders = [...window, ...pinned].map((row) => row.order);
|
|
215
216
|
const relevantTurns = visibleOrders.length === 0
|
|
216
217
|
? turns.slice(-1)
|
|
@@ -232,6 +233,7 @@ export function foldAgentActivity(events) {
|
|
|
232
233
|
}
|
|
233
234
|
return {
|
|
234
235
|
window,
|
|
236
|
+
omittedSettledCount,
|
|
235
237
|
pinned,
|
|
236
238
|
timeline,
|
|
237
239
|
ledgerActivities,
|
|
@@ -6,7 +6,7 @@ import { readProjectionAlias } from "./projection-alias.js";
|
|
|
6
6
|
import { ProjectionStateError } from "../atomic-publish.js";
|
|
7
7
|
import { foldPublicProjectionActivity, } from "./projection-activity.js";
|
|
8
8
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
9
|
-
import { readProjectionTellCounts } from "./tell/store.js";
|
|
9
|
+
import { readPendingTellWindow, readProjectionTellCounts } from "./tell/store.js";
|
|
10
10
|
import { ProjectionGenerationStoreError, } from "./generation/store.js";
|
|
11
11
|
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./generation/projection-generation-launcher.js";
|
|
12
12
|
import { observeProjectionLifeSnapshot, } from "./projection-life-observer.js";
|
|
@@ -169,6 +169,7 @@ function readIdentityFacts(projectionDir, diagnostics) {
|
|
|
169
169
|
pid: identity.pid,
|
|
170
170
|
akuma: identity.akuma,
|
|
171
171
|
provider: identity.provider,
|
|
172
|
+
binding: identity.binding,
|
|
172
173
|
mintedAt: identity.mintedAt,
|
|
173
174
|
workspaceRoot: identity.workspaceRoot,
|
|
174
175
|
};
|
|
@@ -176,18 +177,18 @@ function readIdentityFacts(projectionDir, diagnostics) {
|
|
|
176
177
|
catch (error) {
|
|
177
178
|
if (isErrnoException(error) && error.code === "ENOENT") {
|
|
178
179
|
diagnostics.push({ kind: "missing-identity", detail: "heart identity missing" });
|
|
179
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
180
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
180
181
|
}
|
|
181
182
|
if (error instanceof ProjectionGenerationStoreError) {
|
|
182
183
|
diagnostics.push({ kind: "invalid-identity", detail: error.message });
|
|
183
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
184
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
184
185
|
}
|
|
185
186
|
if (error instanceof ProjectionStateError) {
|
|
186
187
|
diagnostics.push({ kind: "invalid-identity", detail: error.message });
|
|
187
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
188
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
188
189
|
}
|
|
189
190
|
diagnostics.push({ kind: "unreadable-identity", detail: `heart identity unreadable: ${String(error)}` });
|
|
190
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
191
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
function readHeartTellCounts(projectionDir, diagnostics) {
|
|
@@ -203,6 +204,22 @@ function readHeartTellCounts(projectionDir, diagnostics) {
|
|
|
203
204
|
return emptyTellCounts();
|
|
204
205
|
}
|
|
205
206
|
}
|
|
207
|
+
function readPendingTells(projectionDir, diagnostics) {
|
|
208
|
+
try {
|
|
209
|
+
// Kanshi is an operator surface: unconsumed tells are actionable facts, not
|
|
210
|
+
// a count to hide behind. This is one heart read and does not enumerate a
|
|
211
|
+
// second projection topology.
|
|
212
|
+
return readPendingTellWindow(projectionDir, Number.MAX_SAFE_INTEGER).window;
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof ProjectionGenerationStoreError || error instanceof ProjectionStateError) {
|
|
216
|
+
diagnostics.push({ kind: "unreadable-tells", detail: error.message });
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
diagnostics.push({ kind: "unreadable-tells", detail: `heart tells unreadable: ${String(error)}` });
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
206
223
|
function readStoredEvents(projectionDir, executionId, diagnostics) {
|
|
207
224
|
let content;
|
|
208
225
|
let truncated = false;
|
|
@@ -322,6 +339,7 @@ function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
322
339
|
if (snapshot.compatibility === "incompatible") {
|
|
323
340
|
return {
|
|
324
341
|
id,
|
|
342
|
+
observedAtMs: nowMs,
|
|
325
343
|
...(alias ? { alias } : {}),
|
|
326
344
|
state: "incompatible",
|
|
327
345
|
observation: snapshot,
|
|
@@ -335,6 +353,7 @@ function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
335
353
|
?? "projection identity could not be observed";
|
|
336
354
|
return {
|
|
337
355
|
id,
|
|
356
|
+
observedAtMs: nowMs,
|
|
338
357
|
...(alias ? { alias } : {}),
|
|
339
358
|
state: "unknown",
|
|
340
359
|
observation: {
|
|
@@ -354,6 +373,9 @@ function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
354
373
|
const tellCounts = readDetails
|
|
355
374
|
? readHeartTellCounts(projectionDir, diagnostics)
|
|
356
375
|
: emptyTellCounts();
|
|
376
|
+
const pendingTells = readDetails
|
|
377
|
+
? readPendingTells(projectionDir, diagnostics)
|
|
378
|
+
: [];
|
|
357
379
|
const activityFacts = readDetails
|
|
358
380
|
? readActivityFacts(projectionDir, life.executionId, nowMs, diagnostics, typeof adoptedAt === "string" && Number.isFinite(adoptedAtMs) ? adoptedAt : identityFacts.mintedAt)
|
|
359
381
|
: {};
|
|
@@ -377,11 +399,13 @@ function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
377
399
|
: undefined;
|
|
378
400
|
return {
|
|
379
401
|
id,
|
|
402
|
+
observedAtMs: nowMs,
|
|
380
403
|
...(alias ? { alias } : {}),
|
|
381
404
|
state,
|
|
382
405
|
observation: { compatibility: "current", lifecycle: life },
|
|
383
406
|
akuma: identityFacts.akuma,
|
|
384
407
|
provider: identityFacts.provider,
|
|
408
|
+
binding: identityFacts.binding,
|
|
385
409
|
pid: identityFacts.pid,
|
|
386
410
|
mintedAt: identityFacts.mintedAt,
|
|
387
411
|
...(terminalAt ? { terminalAt } : {}),
|
|
@@ -391,6 +415,7 @@ function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
391
415
|
...(displayAgeMs !== undefined ? { activityAgeMs: displayAgeMs } : {}),
|
|
392
416
|
...(terminalFailure ? { terminalFailure } : {}),
|
|
393
417
|
tellCounts,
|
|
418
|
+
...(pendingTells.length > 0 ? { pendingTells } : {}),
|
|
394
419
|
diagnostics,
|
|
395
420
|
};
|
|
396
421
|
}
|
|
@@ -433,7 +458,7 @@ function readAkumaProjectionStatusSummaries(root, akuma, aliases, nowMs) {
|
|
|
433
458
|
const akumaDir = path.join(root, akuma);
|
|
434
459
|
const hexes = readProjectionTopologyEntries(akumaDir);
|
|
435
460
|
if (!hexes)
|
|
436
|
-
return
|
|
461
|
+
return null;
|
|
437
462
|
const summaries = [];
|
|
438
463
|
for (const hex of hexes) {
|
|
439
464
|
const id = `${akuma}/${hex}`;
|
|
@@ -465,10 +490,17 @@ export async function readOperationalProjectionStatusBoard(cwd, nowMs) {
|
|
|
465
490
|
for (const akuma of akumas) {
|
|
466
491
|
if (akuma.startsWith("."))
|
|
467
492
|
continue;
|
|
468
|
-
|
|
493
|
+
const scoped = readAkumaProjectionStatusSummaries(root, akuma, aliases, nowMs);
|
|
494
|
+
// Seeing an entry and then being unable to observe its namespace is not an
|
|
495
|
+
// observable zero. Keep the whole aggregate surface unavailable.
|
|
496
|
+
if (scoped === null)
|
|
497
|
+
return null;
|
|
498
|
+
summaries.push(...scoped);
|
|
469
499
|
}
|
|
470
500
|
const rows = summaries.map((summary) => readProjectionRow(summary, nowMs, requiresProjectionStatusDetails(summary.state)));
|
|
471
|
-
|
|
501
|
+
// A published root is an observable surface even when it currently has no
|
|
502
|
+
// rows. The caller must distinguish that fact from an unavailable root.
|
|
503
|
+
return prioritizeProjectionStatusRows(rows);
|
|
472
504
|
}
|
|
473
505
|
export async function readExactProjectionStatus(cwd, nowMs, projectionId) {
|
|
474
506
|
if (!isProjectionId(projectionId))
|
|
@@ -511,7 +543,10 @@ export async function readAkumaNonterminalProjectionStatus(cwd, nowMs, akuma) {
|
|
|
511
543
|
throw error;
|
|
512
544
|
}
|
|
513
545
|
const aliases = await readProjectionStatusAliases(cwd, root);
|
|
514
|
-
const
|
|
546
|
+
const summaries = readAkumaProjectionStatusSummaries(root, akuma, aliases, nowMs);
|
|
547
|
+
if (summaries === null)
|
|
548
|
+
return null;
|
|
549
|
+
const rows = summaries
|
|
515
550
|
.filter(isNonterminalProjectionStatusSummary)
|
|
516
551
|
.map((summary) => readProjectionRow(summary, nowMs, true))
|
|
517
552
|
.sort(compareProjectionStatusRows);
|
|
@@ -26,11 +26,9 @@ function timestampAge(timestamp, now) {
|
|
|
26
26
|
export function deriveTaskStatusSummary(board, now) {
|
|
27
27
|
const eligible = board.tasks.filter((task) => !task.contractId && (task.state === "open" || task.state === "in_progress"));
|
|
28
28
|
const inProgress = eligible.filter((task) => task.state === "in_progress").length;
|
|
29
|
-
const topTasks =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
]
|
|
33
|
-
.slice(0, 5)
|
|
29
|
+
const topTasks = eligible
|
|
30
|
+
.filter((task) => task.state === "in_progress")
|
|
31
|
+
.sort(compareTaskStatusRows)
|
|
34
32
|
.map((task) => {
|
|
35
33
|
const updatedAt = taskUpdatedAt(task);
|
|
36
34
|
return {
|
|
@@ -47,14 +45,12 @@ export function deriveTaskStatusSummary(board, now) {
|
|
|
47
45
|
});
|
|
48
46
|
const ready = eligible.filter((task) => task.state === "open" && !task.blocked).length;
|
|
49
47
|
const blocked = eligible.filter((task) => task.state === "open" && task.blocked).length;
|
|
50
|
-
if (board.tasks.length === 0 && board.diseases.length === 0)
|
|
51
|
-
return undefined;
|
|
52
48
|
return {
|
|
53
|
-
total:
|
|
49
|
+
total: eligible.length,
|
|
54
50
|
inProgress,
|
|
55
51
|
ready,
|
|
56
52
|
blocked,
|
|
57
|
-
omitted:
|
|
53
|
+
omitted: ready + blocked,
|
|
58
54
|
topTasks,
|
|
59
55
|
diseases: board.diseases,
|
|
60
56
|
};
|
|
@@ -199,6 +195,8 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
199
195
|
: await readExactProjectionStatus(cwd, now, opts.projectionId);
|
|
200
196
|
return {
|
|
201
197
|
contracts: [],
|
|
198
|
+
contractsObservable: false,
|
|
199
|
+
commissionPlaces: new Map(),
|
|
202
200
|
projections: opts?.projectionId === undefined
|
|
203
201
|
? await readOperationalProjectionStatusBoard(cwd, now)
|
|
204
202
|
: exactProjection ? { rows: [exactProjection] } : null,
|
|
@@ -206,7 +204,8 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
206
204
|
diseases: loadedSettings.diseases,
|
|
207
205
|
claimReconciliation: null,
|
|
208
206
|
targetFilter,
|
|
209
|
-
|
|
207
|
+
// Task and contract boards are repository organs; a non-repository cwd
|
|
208
|
+
// cannot truthfully turn their absence into a zero count.
|
|
210
209
|
};
|
|
211
210
|
}
|
|
212
211
|
// Status is a pure reader: use the same resolver, but retain its ability to
|
|
@@ -237,6 +236,7 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
237
236
|
})();
|
|
238
237
|
}), defaultBranch);
|
|
239
238
|
const contracts = [];
|
|
239
|
+
const commissionPlaces = new Map();
|
|
240
240
|
// Readable-ledger commission targets retained for post-assembly filter only.
|
|
241
241
|
const derivedTargetById = new Map();
|
|
242
242
|
for (const item of ledgers) {
|
|
@@ -261,6 +261,7 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
261
261
|
continue;
|
|
262
262
|
}
|
|
263
263
|
const bind = findBindEntry(item.entries);
|
|
264
|
+
commissionPlaces.set(item.contractId, bind?.data.place ?? null);
|
|
264
265
|
derivedTargetById.set(item.contractId, commissionTarget(item.entries)?.ref);
|
|
265
266
|
const base = latestBase(item.entries);
|
|
266
267
|
const state = deriveContractState(item.entries);
|
|
@@ -334,6 +335,8 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
334
335
|
: await readExactProjectionStatus(cwd, now, opts.projectionId);
|
|
335
336
|
return {
|
|
336
337
|
contracts: filteredContracts,
|
|
338
|
+
contractsObservable: true,
|
|
339
|
+
commissionPlaces,
|
|
337
340
|
projections: opts?.projectionId === undefined
|
|
338
341
|
? await readOperationalProjectionStatusBoard(cwd, now)
|
|
339
342
|
: exactProjection ? { rows: [exactProjection] } : null,
|
|
@@ -72,7 +72,7 @@ export async function createTaskMutationCommit(input) {
|
|
|
72
72
|
], undefined, env);
|
|
73
73
|
}
|
|
74
74
|
const tree = (await git(input.cwd, ["write-tree"], undefined, env)).trim();
|
|
75
|
-
const parentTree = (await git(input.cwd, ["
|
|
75
|
+
const parentTree = (await git(input.cwd, ["show", "-s", "--format=%T", input.parent])).trim();
|
|
76
76
|
if (tree === parentTree)
|
|
77
77
|
return input.parent;
|
|
78
78
|
return (await git(input.cwd, ["commit-tree", tree, "-p", input.parent, "-m", input.subject])).trim();
|
|
@@ -354,7 +354,7 @@ export async function findAcceptedLandingCommit(input) {
|
|
|
354
354
|
delivery: input.delivery,
|
|
355
355
|
sources,
|
|
356
356
|
});
|
|
357
|
-
const actualTree = (await git(input.cwd, ["
|
|
357
|
+
const actualTree = (await git(input.cwd, ["show", "-s", "--format=%T", commit])).trim();
|
|
358
358
|
if (actualTree === expectedTree)
|
|
359
359
|
return commit;
|
|
360
360
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated into build output by scripts/build.mjs
|
|
2
|
-
export const VERSION = "2.9.
|
|
3
|
-
export const GIT_HASH = "
|
|
2
|
+
export const VERSION = "2.9.9";
|
|
3
|
+
export const GIT_HASH = "79df272";
|