@astrosheep/keiyaku 2.9.9 → 2.9.10
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/README.md +50 -182
- package/build/.tsbuildinfo +1 -1
- package/build/agents/harness/control-types.js +18 -1
- package/build/agents/harness/index.js +2 -0
- package/build/agents/harness/outcome-error.js +81 -0
- package/build/agents/harness/projection.js +2 -1
- package/build/agents/harness/router.js +5 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
- package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
- package/build/agents/providers/claude-agent-sdk/session.js +19 -5
- package/build/agents/providers/codex-app-server/adapter.js +11 -6
- package/build/agents/providers/codex-app-server/events.js +67 -6
- package/build/agents/providers/codex-app-server/registration.js +11 -1
- package/build/agents/providers/opencode-sdk/adapter.js +8 -1
- package/build/agents/providers/opencode-sdk/events.js +24 -2
- package/build/agents/providers/opencode-sdk/registration.js +11 -1
- package/build/agents/providers/pi/checkpoint.js +9 -1
- package/build/agents/providers/pi/events.js +2 -0
- package/build/agents/providers/pi/registration.js +14 -1
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +3 -3
- package/build/cli/commands/akuma/catalog.js +2 -2
- package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
- package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +5 -4
- package/build/cli/commands/contract/arc/handler.js +5 -4
- package/build/cli/commands/contract/audit/handler.js +2 -2
- package/build/cli/commands/contract/bind/handler.js +12 -3
- package/build/cli/commands/contract/bind/meta.js +45 -15
- package/build/cli/commands/contract/forfeit/handler.js +9 -5
- package/build/cli/commands/contract/log/handler.js +2 -2
- package/build/cli/commands/contract/petition/handler.js +34 -7
- package/build/cli/commands/contract/renew/handler.js +7 -7
- package/build/cli/commands/contract/renew/meta.js +3 -3
- package/build/cli/commands/metadata.js +10 -6
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -0
- package/build/cli/commands/projection/history/handler.js +21 -0
- package/build/cli/commands/projection/history/meta.js +9 -0
- package/build/cli/commands/projection/shared.js +3 -4
- package/build/cli/commands/projection/status/handler.js +3 -3
- package/build/cli/commands/projection/wait/handler.js +20 -11
- package/build/cli/commands/task/add/handler.js +14 -5
- package/build/cli/commands/task/add/meta.js +2 -2
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/done/handler.js +1 -4
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/hold/handler.js +3 -0
- package/build/cli/commands/task/hold/meta.js +8 -0
- package/build/cli/commands/task/log/handler.js +1 -1
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/resume/handler.js +3 -0
- package/build/cli/commands/task/resume/meta.js +8 -0
- package/build/cli/commands/task/shared.js +39 -14
- package/build/cli/commands/task/show/handler.js +1 -1
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +1 -4
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +11 -3
- package/build/cli/commands/task/update/meta.js +3 -3
- package/build/cli/completion.js +3 -2
- package/build/cli/flags.js +51 -14
- package/build/cli/help.js +4 -1
- package/build/cli/index.js +40 -25
- package/build/cli/parse-flags.js +40 -7
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +2 -3
- package/build/cli/parse.js +40 -6
- package/build/cli/projection-address.js +12 -10
- package/build/cli/render/amendment-warning.js +8 -0
- package/build/cli/render/arc.js +6 -2
- package/build/cli/render/audit.js +400 -81
- package/build/cli/render/kanshi.js +6 -1
- package/build/cli/render/lifecycle.js +56 -0
- package/build/cli/render/misc.js +24 -28
- package/build/cli/render/petition.js +5 -0
- package/build/cli/render/projection-activity.js +3 -2
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +9 -16
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +3 -5
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +2 -0
- package/build/config/env.js +23 -0
- package/build/config/settings/schema.js +3 -1
- package/build/core/address-carrier.js +89 -0
- package/build/core/addressing.js +255 -196
- package/build/core/amend.js +115 -38
- package/build/core/amendment-criteria.js +17 -0
- package/build/core/amendment-warning.js +10 -0
- package/build/core/arc.js +184 -83
- package/build/core/audit/candidate.js +110 -9
- package/build/core/audit/coordinates.js +120 -65
- package/build/core/audit/evidence.js +19 -23
- package/build/core/audit/facade.js +34 -11
- package/build/core/audit/report.js +5 -5
- package/build/core/bind-reconciliation.js +390 -0
- package/build/core/bind-workspace.js +12 -20
- package/build/core/bind.js +242 -273
- package/build/core/call/call.js +1 -0
- package/build/core/call/context.js +46 -71
- package/build/core/call/prompt.js +6 -3
- package/build/core/context.js +49 -35
- package/build/core/contract-carrier-runtime.js +408 -0
- package/build/core/contract-carrier.js +270 -0
- package/build/core/contract-view.js +33 -27
- package/build/core/contract.js +5 -1
- package/build/core/derived-replay.js +207 -0
- package/build/core/draft.js +125 -57
- package/build/core/forfeit.js +113 -56
- package/build/core/identifier-slug.js +63 -13
- package/build/core/ids.js +4 -4
- package/build/core/lifecycle-history.js +35 -0
- package/build/core/lifecycle-recovery.js +117 -0
- package/build/core/lifecycle-runner.js +377 -0
- package/build/core/log.js +37 -11
- package/build/core/outcome-base.js +181 -0
- package/build/core/process-group.js +139 -0
- package/build/core/projection/generation/database.js +82 -7
- package/build/core/projection/generation/model.js +9 -36
- package/build/core/projection/generation/projection-generation-continuation.js +10 -22
- package/build/core/projection/generation/projection-generation-execution.js +6 -5
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +27 -8
- package/build/core/projection/projection-alias.js +23 -10
- package/build/core/projection/projection-core.js +21 -7
- package/build/core/projection/projection-execution-observer.js +91 -39
- package/build/core/projection/projection-history.js +474 -0
- package/build/core/projection/projection-runner-lock.js +12 -0
- package/build/core/projection/projection-status-observation.js +365 -0
- package/build/core/projection/projection-status.js +21 -358
- package/build/core/projection/projection-terminal-failure.js +13 -8
- package/build/core/projection/projection-wait.js +7 -2
- package/build/core/projection/tell/launch-store.js +244 -0
- package/build/core/projection/tell/model.js +3 -3
- package/build/core/projection/tell/store.js +70 -118
- package/build/core/registry.js +22 -87
- package/build/core/renew-build.js +424 -0
- package/build/core/renew-plan.js +239 -0
- package/build/core/renew-rewrite.js +77 -0
- package/build/core/renew.js +295 -520
- package/build/core/repository-ledger/accepted-fold-read.js +19 -0
- package/build/core/repository-ledger/accepted-tail.js +116 -0
- package/build/core/repository-ledger/admission.js +38 -0
- package/build/core/repository-ledger/authoritative-transaction.js +1 -0
- package/build/core/repository-ledger/claim-evidence.js +147 -0
- package/build/core/repository-ledger/codec.js +297 -0
- package/build/core/repository-ledger/current-state-store.js +853 -0
- package/build/core/repository-ledger/fold-repository.js +375 -0
- package/build/core/repository-ledger/fold.js +248 -0
- package/build/core/repository-ledger/git-object-store.js +243 -0
- package/build/core/repository-ledger/history-read.js +15 -0
- package/build/core/repository-ledger/incremental-read.js +153 -0
- package/build/core/repository-ledger/index.js +15 -0
- package/build/core/repository-ledger/inventory-plan.js +75 -0
- package/build/core/repository-ledger/inventory.js +310 -0
- package/build/core/repository-ledger/publication-admission.js +125 -0
- package/build/core/repository-ledger/publication.js +353 -0
- package/build/core/repository-ledger/read-model.js +469 -0
- package/build/core/repository-ledger/transaction-membership.js +78 -0
- package/build/core/repository-ledger/traversal.js +404 -0
- package/build/core/repository-ledger/write-transaction.js +339 -0
- package/build/core/seal.js +168 -161
- package/build/core/settlement/claim-delivery.js +42 -215
- package/build/core/settlement/claim.js +235 -153
- package/build/core/settlement/index.js +4 -4
- package/build/core/settlement/petition-claim-gates.js +52 -33
- package/build/core/settlement/petition-forfeit.js +12 -5
- package/build/core/settlement/petition-head-guard.js +8 -5
- package/build/core/settlement/petition-preview.js +68 -56
- package/build/core/settlement/petition-window.js +50 -0
- package/build/core/settlement/petition.js +252 -131
- package/build/core/settlement/queue-read-model.js +72 -95
- package/build/core/settlement/queue-seat-allocation.js +35 -126
- package/build/core/settlement/queue.js +1 -1
- package/build/core/settlement/settlement.js +172 -80
- package/build/core/settlement/verdict.js +112 -66
- package/build/core/settlement/verification-coordination.js +305 -0
- package/build/core/settlement/verification-supervisor.js +275 -0
- package/build/core/settlement/verification.js +398 -31
- package/build/core/status/board.js +114 -119
- package/build/core/status/lifecycle.js +7 -80
- package/build/core/structured-query.js +23 -0
- package/build/core/target-ref.js +1 -1
- package/build/core/task/board.js +59 -24
- package/build/core/task/commands.js +181 -33
- package/build/core/task/coordinate.js +56 -0
- package/build/core/task/document.js +25 -9
- package/build/core/task/index.js +7 -4
- package/build/core/task/query.js +17 -27
- package/build/core/task/settlement-git.js +164 -179
- package/build/core/task/settlement-policy.js +15 -11
- package/build/core/task/source-board.js +31 -13
- package/build/core/task/task-bind-preparation.js +193 -0
- package/build/core/task/task-contract.js +102 -193
- package/build/core/task/task-file-transaction.js +171 -0
- package/build/core/task/task-git-runtime.js +76 -14
- package/build/core/task/task-git-store.js +68 -169
- package/build/core/task/task-store-repository.js +13 -6
- package/build/core/task/task-worktree.js +6 -33
- package/build/core/task/task.js +1 -1
- package/build/core/task/tree.js +3 -3
- package/build/core/task/validation.js +4 -3
- package/build/core/transcripts.js +93 -1
- package/build/core/worktree-bootstrap.js +44 -36
- package/build/core/worktree-path.js +210 -77
- package/build/flow-error.js +7 -7
- package/build/generated/version.js +2 -2
- package/build/git/core.js +76 -13
- package/build/git/refs.js +168 -46
- package/build/git/streaming-batch.js +73 -13
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +3 -3
- package/skills/keiyaku-task/SKILL.md +4 -2
- package/skills/keiyaku-workflow/SKILL.md +88 -203
- package/build/core/entry.js +0 -305
- package/build/core/ledger-batch.js +0 -194
- package/build/core/ledger.js +0 -84
- package/build/core/projection/leash.js +0 -87
- package/build/core/ref-log.js +0 -119
- package/build/core/renew-session.js +0 -128
- package/build/core/status/ledger-batch.js +0 -1
- package/build/core/status/reconciliation.js +0 -137
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { isErrnoException } from "../../errno.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { foldPublicProjectionActivity, } from "./projection-activity.js";
|
|
4
|
+
import { isProjectionId, projectionRoot, projectionRootAtCoordinate } from "./projection-core.js";
|
|
5
|
+
import { projectionAliasRootAtCoordinate, readProjectionAliasAtRoot, } from "./projection-alias.js";
|
|
6
|
+
import { resolveProjectionCoordinate } from "./projection-coordinate.js";
|
|
8
7
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
9
|
-
import { readPendingTellWindow, readProjectionTellCounts } from "./tell/store.js";
|
|
10
|
-
import { ProjectionGenerationStoreError, } from "./generation/store.js";
|
|
11
8
|
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./generation/projection-generation-launcher.js";
|
|
12
9
|
import { observeProjectionLifeSnapshot, } from "./projection-life-observer.js";
|
|
13
|
-
import { selectCurrentGeneration, } from "./projection-life-protocol.js";
|
|
14
|
-
import { invalidActivityEventDiagnostic, selectValidStoredAgentEvents } from "../stored-agent-event.js";
|
|
15
10
|
import { worktreeContainsCoordinate } from "../worktree-path.js";
|
|
16
|
-
import {
|
|
17
|
-
import { extractTerminalTimestamp } from "./generation/model.js";
|
|
11
|
+
import { readProjectionRow, readProjectionSummary } from "./projection-status-observation.js";
|
|
18
12
|
const MAX_STATUS_FILE_BYTES = 256 * 1024;
|
|
19
13
|
const STATUS_GROUP = {
|
|
20
14
|
"startup-timeout": 0,
|
|
@@ -84,349 +78,13 @@ export function prioritizeProjectionStatusRows(rows) {
|
|
|
84
78
|
export function requiresProjectionStatusDetails(state) {
|
|
85
79
|
return !isOmissibleProjectionStatusState(state);
|
|
86
80
|
}
|
|
87
|
-
|
|
88
|
-
diagnostic;
|
|
89
|
-
constructor(kind, filePath) {
|
|
90
|
-
const label = path.basename(filePath);
|
|
91
|
-
const detail = `${label} is not a regular file`;
|
|
92
|
-
super(detail);
|
|
93
|
-
this.name = "ProjectionStatusFileError";
|
|
94
|
-
this.diagnostic = { kind, detail };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function oversizedProjectionFileDiagnostic(filePath) {
|
|
98
|
-
return {
|
|
99
|
-
kind: "oversized-projection-file",
|
|
100
|
-
fileName: path.basename(filePath),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
function recordProjectionStatusFileError(error, diagnostics) {
|
|
104
|
-
if (!(error instanceof ProjectionStatusFileError))
|
|
105
|
-
return false;
|
|
106
|
-
diagnostics.push(error.diagnostic);
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
function readBoundedRegularFileTail(filePath) {
|
|
110
|
-
const before = fs.lstatSync(filePath);
|
|
111
|
-
if (!before.isFile())
|
|
112
|
-
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
113
|
-
let fd;
|
|
114
|
-
try {
|
|
115
|
-
fd = fs.openSync(filePath, fs.constants.O_RDONLY | fs.constants.O_NONBLOCK | fs.constants.O_NOFOLLOW);
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
if (isErrnoException(error) && error.code === "ELOOP") {
|
|
119
|
-
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
120
|
-
}
|
|
121
|
-
throw error;
|
|
122
|
-
}
|
|
123
|
-
try {
|
|
124
|
-
const opened = fs.fstatSync(fd);
|
|
125
|
-
if (!opened.isFile())
|
|
126
|
-
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
127
|
-
const snapshotSize = opened.size;
|
|
128
|
-
const truncated = snapshotSize > MAX_STATUS_FILE_BYTES;
|
|
129
|
-
const readLength = Math.min(snapshotSize, MAX_STATUS_FILE_BYTES);
|
|
130
|
-
const readOffset = Math.max(0, snapshotSize - MAX_STATUS_FILE_BYTES);
|
|
131
|
-
const buffer = Buffer.allocUnsafe(readLength);
|
|
132
|
-
let total = 0;
|
|
133
|
-
while (total < readLength) {
|
|
134
|
-
const bytesRead = fs.readSync(fd, buffer, total, readLength - total, readOffset + total);
|
|
135
|
-
if (bytesRead === 0)
|
|
136
|
-
break;
|
|
137
|
-
total += bytesRead;
|
|
138
|
-
}
|
|
139
|
-
let tail = buffer.subarray(0, total);
|
|
140
|
-
if (truncated) {
|
|
141
|
-
const firstLf = tail.indexOf(0x0a);
|
|
142
|
-
if (firstLf < 0) {
|
|
143
|
-
return { content: "", truncated: true };
|
|
144
|
-
}
|
|
145
|
-
tail = tail.subarray(firstLf + 1);
|
|
146
|
-
}
|
|
147
|
-
return { content: tail.toString("utf8"), truncated };
|
|
148
|
-
}
|
|
149
|
-
finally {
|
|
150
|
-
fs.closeSync(fd);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
function displayedTellCounts(counts) {
|
|
154
|
-
return {
|
|
155
|
-
inbox: counts.inbox,
|
|
156
|
-
inflight: counts.inflight,
|
|
157
|
-
submitted: counts.submitted,
|
|
158
|
-
consumed: counts.consumed,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
function emptyTellCounts() {
|
|
162
|
-
return { inbox: 0, inflight: 0, submitted: 0, consumed: 0 };
|
|
163
|
-
}
|
|
164
|
-
function readIdentityFacts(projectionDir, diagnostics) {
|
|
165
|
-
try {
|
|
166
|
-
const identity = readProjectionIdentity(projectionDir);
|
|
167
|
-
return {
|
|
168
|
-
identity,
|
|
169
|
-
pid: identity.pid,
|
|
170
|
-
akuma: identity.akuma,
|
|
171
|
-
provider: identity.provider,
|
|
172
|
-
binding: identity.binding,
|
|
173
|
-
mintedAt: identity.mintedAt,
|
|
174
|
-
workspaceRoot: identity.workspaceRoot,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
if (isErrnoException(error) && error.code === "ENOENT") {
|
|
179
|
-
diagnostics.push({ kind: "missing-identity", detail: "heart identity missing" });
|
|
180
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
181
|
-
}
|
|
182
|
-
if (error instanceof ProjectionGenerationStoreError) {
|
|
183
|
-
diagnostics.push({ kind: "invalid-identity", detail: error.message });
|
|
184
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
185
|
-
}
|
|
186
|
-
if (error instanceof ProjectionStateError) {
|
|
187
|
-
diagnostics.push({ kind: "invalid-identity", detail: error.message });
|
|
188
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
189
|
-
}
|
|
190
|
-
diagnostics.push({ kind: "unreadable-identity", detail: `heart identity unreadable: ${String(error)}` });
|
|
191
|
-
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, binding: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function readHeartTellCounts(projectionDir, diagnostics) {
|
|
195
|
-
try {
|
|
196
|
-
return displayedTellCounts(readProjectionTellCounts(projectionDir));
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
if (error instanceof ProjectionGenerationStoreError || error instanceof ProjectionStateError) {
|
|
200
|
-
diagnostics.push({ kind: "unreadable-tells", detail: error.message });
|
|
201
|
-
return emptyTellCounts();
|
|
202
|
-
}
|
|
203
|
-
diagnostics.push({ kind: "unreadable-tells", detail: `heart tells unreadable: ${String(error)}` });
|
|
204
|
-
return emptyTellCounts();
|
|
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
|
-
}
|
|
223
|
-
function readStoredEvents(projectionDir, executionId, diagnostics) {
|
|
224
|
-
let content;
|
|
225
|
-
let truncated = false;
|
|
226
|
-
const eventsPath = executionEventsPath(projectionDir, executionId);
|
|
227
|
-
try {
|
|
228
|
-
const read = readBoundedRegularFileTail(eventsPath);
|
|
229
|
-
content = read.content;
|
|
230
|
-
truncated = read.truncated;
|
|
231
|
-
}
|
|
232
|
-
catch (error) {
|
|
233
|
-
if (isErrnoException(error) && error.code === "ENOENT")
|
|
234
|
-
return [];
|
|
235
|
-
if (recordProjectionStatusFileError(error, diagnostics))
|
|
236
|
-
return [];
|
|
237
|
-
diagnostics.push({ kind: "unreadable-activity", detail: `activity ledger unreadable: ${String(error)}` });
|
|
238
|
-
return [];
|
|
239
|
-
}
|
|
240
|
-
if (truncated) {
|
|
241
|
-
diagnostics.push(oversizedProjectionFileDiagnostic(eventsPath));
|
|
242
|
-
}
|
|
243
|
-
// Parse only LF-terminated records. An unterminated final line is ignored even
|
|
244
|
-
// when it happens to parse: it may be a concurrent append fragment.
|
|
245
|
-
const lines = content.split("\n");
|
|
246
|
-
const values = [];
|
|
247
|
-
let malformed = 0;
|
|
248
|
-
for (const line of lines.slice(0, -1)) {
|
|
249
|
-
try {
|
|
250
|
-
values.push(JSON.parse(line));
|
|
251
|
-
}
|
|
252
|
-
catch {
|
|
253
|
-
malformed += 1;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
if (malformed > 0) {
|
|
257
|
-
diagnostics.push({
|
|
258
|
-
kind: "invalid-activity-event",
|
|
259
|
-
detail: `${malformed} persisted activity event${malformed === 1 ? "" : "s"} malformed`,
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
return values;
|
|
263
|
-
}
|
|
264
|
-
function latestValidEvent(events) {
|
|
265
|
-
let latest;
|
|
266
|
-
for (const event of events) {
|
|
267
|
-
const atMs = Date.parse(event.at);
|
|
268
|
-
if (!Number.isFinite(atMs))
|
|
269
|
-
continue;
|
|
270
|
-
if (latest === undefined || atMs > latest.atMs)
|
|
271
|
-
latest = { at: event.at, atMs };
|
|
272
|
-
}
|
|
273
|
-
return latest;
|
|
274
|
-
}
|
|
275
|
-
function readActivityFacts(projectionDir, executionId, nowMs, diagnostics, fallbackAt) {
|
|
276
|
-
const fallbackAtMs = fallbackAt === undefined ? undefined : Date.parse(fallbackAt);
|
|
277
|
-
const validFallback = fallbackAt !== undefined && Number.isFinite(fallbackAtMs)
|
|
278
|
-
? { at: fallbackAt, atMs: fallbackAtMs }
|
|
279
|
-
: undefined;
|
|
280
|
-
if (!executionId) {
|
|
281
|
-
return validFallback
|
|
282
|
-
? { activityAt: validFallback.at, activityAtMs: validFallback.atMs, activityAgeMs: Math.max(0, nowMs - validFallback.atMs) }
|
|
283
|
-
: {};
|
|
284
|
-
}
|
|
285
|
-
const stored = readStoredEvents(projectionDir, executionId, diagnostics);
|
|
286
|
-
const { events, malformed } = selectValidStoredAgentEvents(stored);
|
|
287
|
-
const invalidActivity = invalidActivityEventDiagnostic(malformed);
|
|
288
|
-
if (invalidActivity)
|
|
289
|
-
diagnostics.push(invalidActivity);
|
|
290
|
-
const latest = latestValidEvent(events) ?? validFallback;
|
|
291
|
-
return {
|
|
292
|
-
...(events.length > 0 ? { activity: foldPublicProjectionActivity(events) } : {}),
|
|
293
|
-
...(latest !== undefined
|
|
294
|
-
? {
|
|
295
|
-
activityAt: latest.at,
|
|
296
|
-
activityAtMs: latest.atMs,
|
|
297
|
-
activityAgeMs: Math.max(0, nowMs - latest.atMs),
|
|
298
|
-
}
|
|
299
|
-
: {}),
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
function terminalTimestamp(current) {
|
|
303
|
-
return extractTerminalTimestamp(current?.verdict?.facts);
|
|
304
|
-
}
|
|
305
|
-
function readProjectionSummary(projectionDir, id, alias, nowMs) {
|
|
306
|
-
const diagnostics = [];
|
|
307
|
-
const snapshot = observeProjectionLifeSnapshot(projectionDir, {
|
|
308
|
-
nowMs,
|
|
309
|
-
startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
|
|
310
|
-
});
|
|
311
|
-
if (snapshot.compatibility === "incompatible") {
|
|
312
|
-
return {
|
|
313
|
-
id,
|
|
314
|
-
...(alias ? { alias } : {}),
|
|
315
|
-
projectionDir,
|
|
316
|
-
snapshot,
|
|
317
|
-
identityFacts: null,
|
|
318
|
-
diagnostics,
|
|
319
|
-
state: "incompatible",
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
const identityFacts = readIdentityFacts(projectionDir, diagnostics);
|
|
323
|
-
const life = snapshot.life;
|
|
324
|
-
const phase = life.phase;
|
|
325
|
-
const state = phase === "active" || phase === "quiescent" ? "out" : phase;
|
|
326
|
-
return {
|
|
327
|
-
id,
|
|
328
|
-
...(alias ? { alias } : {}),
|
|
329
|
-
projectionDir,
|
|
330
|
-
snapshot,
|
|
331
|
-
identityFacts,
|
|
332
|
-
diagnostics,
|
|
333
|
-
state,
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
function readProjectionRow(summary, nowMs, readDetails) {
|
|
337
|
-
const { id, alias, projectionDir, snapshot } = summary;
|
|
338
|
-
const diagnostics = [...summary.diagnostics];
|
|
339
|
-
if (snapshot.compatibility === "incompatible") {
|
|
340
|
-
return {
|
|
341
|
-
id,
|
|
342
|
-
observedAtMs: nowMs,
|
|
343
|
-
...(alias ? { alias } : {}),
|
|
344
|
-
state: "incompatible",
|
|
345
|
-
observation: snapshot,
|
|
346
|
-
tellCounts: emptyTellCounts(),
|
|
347
|
-
diagnostics,
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
const identityFacts = summary.identityFacts;
|
|
351
|
-
if (!identityFacts.identity) {
|
|
352
|
-
const diagnostic = diagnostics.map((entry) => entry.detail).find((detail) => detail !== undefined)
|
|
353
|
-
?? "projection identity could not be observed";
|
|
354
|
-
return {
|
|
355
|
-
id,
|
|
356
|
-
observedAtMs: nowMs,
|
|
357
|
-
...(alias ? { alias } : {}),
|
|
358
|
-
state: "unknown",
|
|
359
|
-
observation: {
|
|
360
|
-
compatibility: "current",
|
|
361
|
-
lifecycle: { phase: "unknown", diagnostic },
|
|
362
|
-
},
|
|
363
|
-
tellCounts: emptyTellCounts(),
|
|
364
|
-
diagnostics,
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
const life = snapshot.life;
|
|
368
|
-
const current = snapshot.records ? selectCurrentGeneration(snapshot.records) : null;
|
|
369
|
-
const adoptedAt = current?.adoption?.facts.adoptedAt;
|
|
370
|
-
const adoptedAtMs = typeof adoptedAt === "string"
|
|
371
|
-
? Date.parse(adoptedAt)
|
|
372
|
-
: Number.NaN;
|
|
373
|
-
const tellCounts = readDetails
|
|
374
|
-
? readHeartTellCounts(projectionDir, diagnostics)
|
|
375
|
-
: emptyTellCounts();
|
|
376
|
-
const pendingTells = readDetails
|
|
377
|
-
? readPendingTells(projectionDir, diagnostics)
|
|
378
|
-
: [];
|
|
379
|
-
const activityFacts = readDetails
|
|
380
|
-
? readActivityFacts(projectionDir, life.executionId, nowMs, diagnostics, typeof adoptedAt === "string" && Number.isFinite(adoptedAtMs) ? adoptedAt : identityFacts.mintedAt)
|
|
381
|
-
: {};
|
|
382
|
-
const mintedAtMs = Date.parse(identityFacts.mintedAt ?? "");
|
|
383
|
-
const terminalAt = terminalTimestamp(current);
|
|
384
|
-
const durationAnchorMs = current?.verdict
|
|
385
|
-
? (terminalAt === undefined ? Number.NaN : Date.parse(terminalAt))
|
|
386
|
-
: nowMs;
|
|
387
|
-
const durationMs = Number.isFinite(mintedAtMs) && Number.isFinite(durationAnchorMs)
|
|
388
|
-
? Math.max(0, durationAnchorMs - mintedAtMs)
|
|
389
|
-
: undefined;
|
|
390
|
-
const displayAgeMs = activityFacts.activityAgeMs
|
|
391
|
-
?? (Number.isFinite(mintedAtMs) ? Math.max(0, nowMs - mintedAtMs) : undefined);
|
|
392
|
-
if (life.phase === "unknown" && life.diagnostic) {
|
|
393
|
-
diagnostics.push({ kind: "unknown-lifecycle", detail: life.diagnostic });
|
|
394
|
-
}
|
|
395
|
-
const phase = life.phase;
|
|
396
|
-
const state = phase === "active" || phase === "quiescent" ? "out" : phase;
|
|
397
|
-
const terminalFailure = current?.verdict
|
|
398
|
-
? projectTerminalFailure(current.verdict.facts.state, current.verdict.facts)
|
|
399
|
-
: undefined;
|
|
400
|
-
return {
|
|
401
|
-
id,
|
|
402
|
-
observedAtMs: nowMs,
|
|
403
|
-
...(alias ? { alias } : {}),
|
|
404
|
-
state,
|
|
405
|
-
observation: { compatibility: "current", lifecycle: life },
|
|
406
|
-
akuma: identityFacts.akuma,
|
|
407
|
-
provider: identityFacts.provider,
|
|
408
|
-
binding: identityFacts.binding,
|
|
409
|
-
pid: identityFacts.pid,
|
|
410
|
-
mintedAt: identityFacts.mintedAt,
|
|
411
|
-
...(terminalAt ? { terminalAt } : {}),
|
|
412
|
-
...(durationMs !== undefined ? { durationMs } : {}),
|
|
413
|
-
...(identityFacts.workspaceRoot ? { workspaceRoot: identityFacts.workspaceRoot } : {}),
|
|
414
|
-
...activityFacts,
|
|
415
|
-
...(displayAgeMs !== undefined ? { activityAgeMs: displayAgeMs } : {}),
|
|
416
|
-
...(terminalFailure ? { terminalFailure } : {}),
|
|
417
|
-
tellCounts,
|
|
418
|
-
...(pendingTells.length > 0 ? { pendingTells } : {}),
|
|
419
|
-
diagnostics,
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
async function readProjectionStatusAliases(cwd, root) {
|
|
81
|
+
async function readProjectionStatusAliases(root) {
|
|
423
82
|
const aliases = new Map();
|
|
424
|
-
const aliasRoot = path.join(path.dirname(path.dirname(root)), ".keiyaku", "projection-alias");
|
|
425
83
|
try {
|
|
426
|
-
for (const alias of fs.readdirSync(
|
|
84
|
+
for (const alias of fs.readdirSync(root).sort()) {
|
|
427
85
|
if (alias.startsWith("."))
|
|
428
86
|
continue;
|
|
429
|
-
const id = await
|
|
87
|
+
const id = await readProjectionAliasAtRoot(root, alias);
|
|
430
88
|
if (id)
|
|
431
89
|
aliases.set(id, alias);
|
|
432
90
|
}
|
|
@@ -449,8 +107,8 @@ function readProjectionTopologyEntries(directory) {
|
|
|
449
107
|
throw error;
|
|
450
108
|
}
|
|
451
109
|
}
|
|
452
|
-
|
|
453
|
-
const root =
|
|
110
|
+
function readProjectionRootTopology(coordinate) {
|
|
111
|
+
const root = projectionRootAtCoordinate(coordinate);
|
|
454
112
|
const akumas = readProjectionTopologyEntries(root);
|
|
455
113
|
return akumas ? { root, akumas } : null;
|
|
456
114
|
}
|
|
@@ -472,7 +130,9 @@ function readAkumaProjectionStatusSummaries(root, akuma, aliases, nowMs) {
|
|
|
472
130
|
catch {
|
|
473
131
|
continue;
|
|
474
132
|
}
|
|
475
|
-
summaries.push(readProjectionSummary(dir, id, aliases.get(id), nowMs
|
|
133
|
+
summaries.push(readProjectionSummary(dir, id, aliases.get(id), nowMs, {
|
|
134
|
+
requiresIdentity: requiresProjectionStatusDetails,
|
|
135
|
+
}));
|
|
476
136
|
}
|
|
477
137
|
return summaries;
|
|
478
138
|
}
|
|
@@ -481,11 +141,12 @@ function isNonterminalProjectionStatusSummary(summary) {
|
|
|
481
141
|
&& requiresProjectionStatusDetails(summary.state);
|
|
482
142
|
}
|
|
483
143
|
export async function readOperationalProjectionStatusBoard(cwd, nowMs) {
|
|
484
|
-
const
|
|
144
|
+
const coordinate = await resolveProjectionCoordinate(cwd);
|
|
145
|
+
const topology = readProjectionRootTopology(coordinate);
|
|
485
146
|
if (!topology)
|
|
486
147
|
return null;
|
|
487
148
|
const { root, akumas } = topology;
|
|
488
|
-
const aliases = await readProjectionStatusAliases(
|
|
149
|
+
const aliases = await readProjectionStatusAliases(projectionAliasRootAtCoordinate(coordinate));
|
|
489
150
|
const summaries = [];
|
|
490
151
|
for (const akuma of akumas) {
|
|
491
152
|
if (akuma.startsWith("."))
|
|
@@ -505,7 +166,8 @@ export async function readOperationalProjectionStatusBoard(cwd, nowMs) {
|
|
|
505
166
|
export async function readExactProjectionStatus(cwd, nowMs, projectionId) {
|
|
506
167
|
if (!isProjectionId(projectionId))
|
|
507
168
|
return null;
|
|
508
|
-
const
|
|
169
|
+
const coordinate = await resolveProjectionCoordinate(cwd);
|
|
170
|
+
const root = projectionRootAtCoordinate(coordinate);
|
|
509
171
|
try {
|
|
510
172
|
if (!fs.lstatSync(root).isDirectory())
|
|
511
173
|
return null;
|
|
@@ -526,13 +188,14 @@ export async function readExactProjectionStatus(cwd, nowMs, projectionId) {
|
|
|
526
188
|
return null;
|
|
527
189
|
throw error;
|
|
528
190
|
}
|
|
529
|
-
const aliases = await readProjectionStatusAliases(
|
|
191
|
+
const aliases = await readProjectionStatusAliases(projectionAliasRootAtCoordinate(coordinate));
|
|
530
192
|
return readProjectionRow(readProjectionSummary(dir, projectionId, aliases.get(projectionId), nowMs), nowMs, true);
|
|
531
193
|
}
|
|
532
194
|
export async function readAkumaNonterminalProjectionStatus(cwd, nowMs, akuma) {
|
|
533
195
|
if (!isProjectionId(`${akuma}/00000000`))
|
|
534
196
|
return null;
|
|
535
|
-
const
|
|
197
|
+
const coordinate = await resolveProjectionCoordinate(cwd);
|
|
198
|
+
const root = projectionRootAtCoordinate(coordinate);
|
|
536
199
|
try {
|
|
537
200
|
if (!fs.lstatSync(root).isDirectory())
|
|
538
201
|
return null;
|
|
@@ -542,7 +205,7 @@ export async function readAkumaNonterminalProjectionStatus(cwd, nowMs, akuma) {
|
|
|
542
205
|
return null;
|
|
543
206
|
throw error;
|
|
544
207
|
}
|
|
545
|
-
const aliases = await readProjectionStatusAliases(
|
|
208
|
+
const aliases = await readProjectionStatusAliases(projectionAliasRootAtCoordinate(coordinate));
|
|
546
209
|
const summaries = readAkumaProjectionStatusSummaries(root, akuma, aliases, nowMs);
|
|
547
210
|
if (summaries === null)
|
|
548
211
|
return null;
|
|
@@ -43,15 +43,19 @@ function artifactId(source) {
|
|
|
43
43
|
}
|
|
44
44
|
function providerFailureCause(value) {
|
|
45
45
|
const source = objectValue(value);
|
|
46
|
-
return source
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
return source && isHarnessFailureValue(source) ? source : undefined;
|
|
47
|
+
}
|
|
48
|
+
function isHarnessFailureValue(value) {
|
|
49
|
+
if (value === null || typeof value === "boolean" || typeof value === "string")
|
|
50
|
+
return true;
|
|
51
|
+
if (typeof value === "number")
|
|
52
|
+
return Number.isFinite(value);
|
|
53
|
+
if (Array.isArray(value))
|
|
54
|
+
return value.every(isHarnessFailureValue);
|
|
55
|
+
const object = objectValue(value);
|
|
56
|
+
return object !== undefined && Object.values(object).every(isHarnessFailureValue);
|
|
49
57
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Convert artifact-rich verdict facts into the strict public allowlist. Raw
|
|
52
|
-
* messages, output, diagnostics, sessions, provider payloads, and unknown
|
|
53
|
-
* strings have no path through this function.
|
|
54
|
-
*/
|
|
58
|
+
/** Convert the public harness terminal failure into the shared projection face. */
|
|
55
59
|
export function projectTerminalFailure(state, facts) {
|
|
56
60
|
if (state !== "failed" && state !== "lost-runner" && state !== "launch-failed")
|
|
57
61
|
return undefined;
|
|
@@ -97,6 +101,7 @@ export function projectTerminalFailure(state, facts) {
|
|
|
97
101
|
class: "harness",
|
|
98
102
|
code,
|
|
99
103
|
phase: source.phase === "adoption" ? "adoption" : "runtime",
|
|
104
|
+
...(typeof error.message === "string" ? { message: error.message } : {}),
|
|
100
105
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
101
106
|
...(publicExitCode !== undefined ? { exitCode: publicExitCode } : {}),
|
|
102
107
|
...(publicSignal ? { signal: publicSignal } : {}),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { foldPublicProjectionActivity } from "./projection-activity.js";
|
|
4
|
-
import { readGenerationEvents, isProjectionId,
|
|
4
|
+
import { readGenerationEvents, isProjectionId, projectionRootAtCoordinate, } from "./projection-core.js";
|
|
5
|
+
import { resolveProjectionCoordinate } from "./projection-coordinate.js";
|
|
5
6
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
6
7
|
import { RESPONSE_ARTIFACT_ID_RE } from "../response-artifact-id.js";
|
|
7
8
|
import { extractTerminalTimestamp } from "./generation/model.js";
|
|
@@ -15,7 +16,11 @@ import { tellProjection } from "./projection-wake.js";
|
|
|
15
16
|
import { FlowError } from "../../flow-error.js";
|
|
16
17
|
/** Return the commission-bound projection IDs visible at one admission instant. */
|
|
17
18
|
export async function snapshotCommissionProjectionIds(cwd, commissionId) {
|
|
18
|
-
|
|
19
|
+
return snapshotCommissionProjectionIdsAtCoordinate(await resolveProjectionCoordinate(cwd), commissionId);
|
|
20
|
+
}
|
|
21
|
+
/** Scan one already-resolved projection coordinate for commission-bound IDs. */
|
|
22
|
+
export async function snapshotCommissionProjectionIdsAtCoordinate(coordinate, commissionId) {
|
|
23
|
+
const root = projectionRootAtCoordinate(coordinate);
|
|
19
24
|
let akumas;
|
|
20
25
|
try {
|
|
21
26
|
akumas = fs.readdirSync(root).sort();
|