@astrosheep/keiyaku 1.0.1 → 1.0.2
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 +5 -7
- package/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms_v2.js +103 -0
- package/build/agents/harness/activity-values.js +54 -0
- package/build/agents/harness/event-channel.js +55 -20
- package/build/agents/harness/events.js +47 -1
- package/build/agents/harness/execution-handle.js +292 -61
- package/build/agents/harness/index.js +103 -121
- package/build/agents/harness/pump.js +36 -47
- package/build/agents/harness/runtime.js +3 -0
- package/build/agents/launch-snapshot_v2.js +348 -0
- package/build/agents/opencode-sdk.js +42 -169
- package/build/agents/providers/claude-agent-sdk.js +240 -79
- package/build/agents/providers/codex-app-server.js +280 -72
- package/build/agents/providers/codex-sdk.js +159 -41
- package/build/agents/providers/event-type-tail.js +16 -0
- package/build/agents/providers/opencode-sdk.js +165 -59
- package/build/agents/providers/pi.js +254 -42
- package/build/agents/selector_v2.js +122 -0
- package/build/cli/commands/akuma.js +120 -42
- package/build/cli/completion.js +6 -7
- package/build/cli/flags.js +36 -10
- package/build/cli/help.js +29 -24
- package/build/cli/index.js +225 -93
- package/build/cli/parse.js +194 -75
- package/build/cli/projection-address.js +11 -0
- package/build/cli/render/address.js +88 -0
- package/build/cli/render/arc.js +10 -10
- package/build/cli/render/call.js +59 -0
- package/build/cli/render/compact-text.js +3 -0
- package/build/cli/render/errors.js +4 -2
- package/build/cli/render/format.js +6 -0
- package/build/cli/render/line-width.js +70 -0
- package/build/cli/render/misc.js +7 -4
- package/build/cli/render/petition.js +4 -3
- package/build/cli/render/projection-activity.js +201 -0
- package/build/cli/render/shared.js +46 -12
- package/build/cli/render/status.js +59 -10
- package/build/cli/render/tool-ledger-rollup.js +74 -0
- package/build/cli/render/tool-presentation.js +97 -0
- package/build/cli/render/wait.js +229 -0
- package/build/cli/skills-install.js +42 -24
- package/build/cli/subagent-guard.js +1 -1
- package/build/config/akuma-loader_v2.js +222 -0
- package/build/config/env-keys.js +0 -4
- package/build/config/env.js +0 -6
- package/build/config/settings.js +325 -12
- package/build/core/addressing.js +224 -0
- package/build/core/amend.js +30 -47
- package/build/core/arc.js +68 -60
- package/build/core/bind.js +105 -25
- package/build/core/call-persist.js +69 -0
- package/build/core/call.js +658 -0
- package/build/core/claim.js +72 -44
- package/build/core/command-io.js +19 -19
- package/build/core/context.js +11 -36
- package/build/core/draft.js +2 -3
- package/build/core/entry.js +101 -6
- package/build/core/execution-coordinate.js +62 -0
- package/build/core/execution-pact.js +141 -0
- package/build/core/forfeit.js +2 -3
- package/build/core/hints.js +10 -10
- package/build/core/ids.js +6 -0
- package/build/core/ledger.js +16 -1
- package/build/core/petition-claim-gates.js +14 -12
- package/build/core/petition-claim.js +1 -0
- package/build/core/petition-run.js +6 -2
- package/build/core/petition.js +63 -21
- package/build/core/places.js +106 -13
- package/build/core/projection/generation.js +412 -0
- package/build/core/projection/heart.js +316 -0
- package/build/core/projection/identity.js +81 -0
- package/build/core/projection/leash.js +87 -0
- package/build/core/projection/mint.js +154 -0
- package/build/core/projection-activity.js +219 -0
- package/build/core/projection-coordinate.js +35 -0
- package/build/core/projection-core.js +69 -463
- package/build/core/projection-generation-continuation.js +31 -0
- package/build/core/projection-generation-execution.js +148 -0
- package/build/core/projection-generation-identity.js +17 -0
- package/build/core/projection-generation-launcher.js +90 -0
- package/build/core/projection-generation-process.js +43 -0
- package/build/core/projection-generation-runner.js +144 -0
- package/build/core/projection-generation-runtime.js +15 -0
- package/build/core/projection-generation-store.js +707 -0
- package/build/core/projection-identity.js +11 -0
- package/build/core/projection-life-observer.js +87 -0
- package/build/core/projection-life-protocol.js +95 -0
- package/build/core/projection-mint.js +96 -24
- package/build/core/projection-runner-lock.js +230 -0
- package/build/core/projection-status.js +207 -107
- package/build/core/projection-tells.js +401 -0
- package/build/core/projection-wait.js +155 -0
- package/build/core/projection-wake.js +109 -231
- package/build/core/queue_v2.js +342 -0
- package/build/core/registry.js +6 -3
- package/build/core/render.js +63 -1
- package/build/core/renew.js +80 -53
- package/build/core/scope.js +186 -137
- package/build/core/seal.js +16 -19
- package/build/core/status.js +88 -25
- package/build/core/stored-agent-event.js +101 -0
- package/build/core/transcripts.js +214 -228
- package/build/core/verdict.js +27 -15
- package/build/core/worktree-bootstrap.js +187 -0
- package/build/core/worktree-path.js +72 -18
- package/build/flow-error.js +4 -6
- package/build/generated/version.js +1 -1
- package/build/git/branches.js +6 -1
- package/build/index.js +8 -5
- package/build/keiyaku.js +1 -3
- package/package.json +6 -5
- package/skills/keiyaku/SKILL.md +6 -47
- package/skills/keiyaku-akuma/SKILL.md +75 -0
- package/build/agents/effective-policy.js +0 -32
- package/build/agents/index.js +0 -114
- package/build/agents/selector.js +0 -28
- package/build/cli/render/summon.js +0 -17
- package/build/cli/render/tell.js +0 -11
- package/build/config/akuma-loader.js +0 -268
- package/build/core/queue.js +0 -73
- package/build/core/summon-persist.js +0 -73
- package/build/core/summon.js +0 -377
|
@@ -1,158 +1,259 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { isErrnoException } from "../errno.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
import { executionEventsPath, projectionRoot, } from "./projection-core.js";
|
|
5
|
+
import { ProjectionStateError } from "./atomic-publish.js";
|
|
6
|
+
import { foldAgentActivity, } from "./projection-activity.js";
|
|
7
|
+
import { readProjectionIdentity } from "./projection-identity.js";
|
|
8
|
+
import { readProjectionTellCounts, } from "./projection-tells.js";
|
|
9
|
+
import { ProjectionGenerationStoreError } from "./projection-generation-store.js";
|
|
10
|
+
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./projection-generation-launcher.js";
|
|
11
|
+
import { observeProjectionLifeSnapshot } from "./projection-life-observer.js";
|
|
12
|
+
import { selectCurrentGeneration } from "./projection-life-protocol.js";
|
|
13
|
+
import { invalidActivityEventDiagnostic, selectValidStoredAgentEvents } from "./stored-agent-event.js";
|
|
14
|
+
const MAX_STATUS_FILE_BYTES = 256 * 1024;
|
|
15
|
+
class ProjectionStatusFileError extends Error {
|
|
16
|
+
diagnostic;
|
|
17
|
+
constructor(kind, filePath) {
|
|
18
|
+
const label = path.basename(filePath);
|
|
19
|
+
const detail = kind === "non-regular-projection-file"
|
|
20
|
+
? `${label} is not a regular file`
|
|
21
|
+
: `${label} exceeds status read limit`;
|
|
22
|
+
super(detail);
|
|
23
|
+
this.name = "ProjectionStatusFileError";
|
|
24
|
+
this.diagnostic = { kind, detail };
|
|
15
25
|
}
|
|
16
26
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
27
|
+
function recordProjectionStatusFileError(error, diagnostics) {
|
|
28
|
+
if (!(error instanceof ProjectionStatusFileError))
|
|
29
|
+
return false;
|
|
30
|
+
diagnostics.push(error.diagnostic);
|
|
31
|
+
return true;
|
|
19
32
|
}
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
|
|
33
|
+
function readBoundedRegularFile(filePath) {
|
|
34
|
+
const before = fs.lstatSync(filePath);
|
|
35
|
+
if (!before.isFile())
|
|
36
|
+
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
37
|
+
if (before.size > MAX_STATUS_FILE_BYTES) {
|
|
38
|
+
throw new ProjectionStatusFileError("oversized-projection-file", filePath);
|
|
39
|
+
}
|
|
40
|
+
let fd;
|
|
23
41
|
try {
|
|
24
|
-
|
|
42
|
+
fd = fs.openSync(filePath, fs.constants.O_RDONLY | fs.constants.O_NONBLOCK | fs.constants.O_NOFOLLOW);
|
|
25
43
|
}
|
|
26
44
|
catch (error) {
|
|
27
|
-
if (isErrnoException(error) && error.code === "
|
|
28
|
-
|
|
29
|
-
return 0;
|
|
45
|
+
if (isErrnoException(error) && error.code === "ELOOP") {
|
|
46
|
+
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
30
47
|
}
|
|
31
|
-
|
|
32
|
-
return 0;
|
|
48
|
+
throw error;
|
|
33
49
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
try {
|
|
51
|
+
const opened = fs.fstatSync(fd);
|
|
52
|
+
if (!opened.isFile())
|
|
53
|
+
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
54
|
+
if (opened.size > MAX_STATUS_FILE_BYTES) {
|
|
55
|
+
throw new ProjectionStatusFileError("oversized-projection-file", filePath);
|
|
56
|
+
}
|
|
57
|
+
const chunks = [];
|
|
58
|
+
let total = 0;
|
|
59
|
+
while (total <= MAX_STATUS_FILE_BYTES) {
|
|
60
|
+
const chunk = Buffer.allocUnsafe(Math.min(64 * 1024, MAX_STATUS_FILE_BYTES + 1 - total));
|
|
61
|
+
const bytesRead = fs.readSync(fd, chunk, 0, chunk.length, null);
|
|
62
|
+
if (bytesRead === 0)
|
|
63
|
+
break;
|
|
64
|
+
chunks.push(chunk.subarray(0, bytesRead));
|
|
65
|
+
total += bytesRead;
|
|
41
66
|
}
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
if (total > MAX_STATUS_FILE_BYTES) {
|
|
68
|
+
throw new ProjectionStatusFileError("oversized-projection-file", filePath);
|
|
44
69
|
}
|
|
70
|
+
return Buffer.concat(chunks, total).toString("utf8");
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
fs.closeSync(fd);
|
|
45
74
|
}
|
|
46
|
-
return count;
|
|
47
75
|
}
|
|
48
|
-
function
|
|
76
|
+
function displayedTellCounts(counts) {
|
|
49
77
|
return {
|
|
50
|
-
inbox:
|
|
51
|
-
inflight:
|
|
52
|
-
submitted:
|
|
53
|
-
consumed:
|
|
78
|
+
inbox: counts.inbox,
|
|
79
|
+
inflight: counts.inflight,
|
|
80
|
+
submitted: counts.submitted,
|
|
81
|
+
consumed: counts.consumed,
|
|
54
82
|
};
|
|
55
83
|
}
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
diagnostics.push({ kind: "missing-pact", detail: "pact.json missing" });
|
|
61
|
-
return { pact: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined };
|
|
62
|
-
}
|
|
84
|
+
function emptyTellCounts() {
|
|
85
|
+
return { inbox: 0, inflight: 0, submitted: 0, consumed: 0 };
|
|
86
|
+
}
|
|
87
|
+
function readIdentityFacts(projectionDir, diagnostics) {
|
|
63
88
|
try {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
89
|
+
const identity = readProjectionIdentity(projectionDir);
|
|
90
|
+
return {
|
|
91
|
+
identity,
|
|
92
|
+
pid: identity.pid,
|
|
93
|
+
akuma: identity.akuma,
|
|
94
|
+
provider: identity.provider,
|
|
95
|
+
mintedAt: identity.mintedAt,
|
|
96
|
+
workspaceRoot: identity.workspaceRoot,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (isErrnoException(error) && error.code === "ENOENT") {
|
|
101
|
+
diagnostics.push({ kind: "missing-identity", detail: "heart identity missing" });
|
|
102
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
71
103
|
}
|
|
72
|
-
if (
|
|
73
|
-
diagnostics.push({ kind: "invalid-
|
|
104
|
+
if (error instanceof ProjectionGenerationStoreError) {
|
|
105
|
+
diagnostics.push({ kind: "invalid-identity", detail: error.message });
|
|
106
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
74
107
|
}
|
|
75
|
-
if (
|
|
76
|
-
diagnostics.push({ kind: "invalid-
|
|
108
|
+
if (error instanceof ProjectionStateError) {
|
|
109
|
+
diagnostics.push({ kind: "invalid-identity", detail: error.message });
|
|
110
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
77
111
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
diagnostics.push({ kind: "unreadable-identity", detail: `heart identity unreadable: ${String(error)}` });
|
|
113
|
+
return { identity: null, pid: undefined, akuma: undefined, provider: undefined, mintedAt: undefined, workspaceRoot: undefined };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function readHeartTellCounts(projectionDir, diagnostics) {
|
|
117
|
+
try {
|
|
118
|
+
return displayedTellCounts(readProjectionTellCounts(projectionDir));
|
|
85
119
|
}
|
|
86
120
|
catch (error) {
|
|
87
|
-
|
|
88
|
-
|
|
121
|
+
if (error instanceof ProjectionGenerationStoreError || error instanceof ProjectionStateError) {
|
|
122
|
+
diagnostics.push({ kind: "unreadable-tells", detail: error.message });
|
|
123
|
+
return emptyTellCounts();
|
|
124
|
+
}
|
|
125
|
+
diagnostics.push({ kind: "unreadable-tells", detail: `heart tells unreadable: ${String(error)}` });
|
|
126
|
+
return emptyTellCounts();
|
|
89
127
|
}
|
|
90
128
|
}
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
if (!statOrNull(verdictPath))
|
|
94
|
-
return null;
|
|
129
|
+
function readStoredEvents(projectionDir, executionId, diagnostics) {
|
|
130
|
+
let content;
|
|
95
131
|
try {
|
|
96
|
-
|
|
97
|
-
if (verdict.state === "done" || verdict.state === "dismissed" || verdict.state === "failed")
|
|
98
|
-
return verdict.state;
|
|
99
|
-
diagnostics.push({ kind: "invalid-verdict", detail: "verdict.json state invalid" });
|
|
100
|
-
return null;
|
|
132
|
+
content = readBoundedRegularFile(executionEventsPath(projectionDir, executionId));
|
|
101
133
|
}
|
|
102
134
|
catch (error) {
|
|
103
|
-
|
|
104
|
-
|
|
135
|
+
if (isErrnoException(error) && error.code === "ENOENT")
|
|
136
|
+
return [];
|
|
137
|
+
if (recordProjectionStatusFileError(error, diagnostics))
|
|
138
|
+
return [];
|
|
139
|
+
diagnostics.push({ kind: "unreadable-activity", detail: `activity ledger unreadable: ${String(error)}` });
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
const lines = content.split("\n");
|
|
143
|
+
const terminated = content.endsWith("\n");
|
|
144
|
+
const values = [];
|
|
145
|
+
let malformed = 0;
|
|
146
|
+
for (const line of lines.slice(0, -1)) {
|
|
147
|
+
try {
|
|
148
|
+
values.push(JSON.parse(line));
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
malformed += 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const finalLine = lines.at(-1);
|
|
155
|
+
if (!terminated && finalLine) {
|
|
156
|
+
try {
|
|
157
|
+
values.push(JSON.parse(finalLine));
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// A concurrent append can leave only this final record incomplete.
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (malformed > 0) {
|
|
164
|
+
diagnostics.push({
|
|
165
|
+
kind: "invalid-activity-event",
|
|
166
|
+
detail: `${malformed} persisted activity event${malformed === 1 ? "" : "s"} malformed`,
|
|
167
|
+
});
|
|
105
168
|
}
|
|
169
|
+
return values;
|
|
106
170
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
171
|
+
function latestValidEventAtMs(events) {
|
|
172
|
+
let latest;
|
|
173
|
+
for (const event of events) {
|
|
174
|
+
const atMs = Date.parse(event.at);
|
|
175
|
+
if (!Number.isFinite(atMs))
|
|
176
|
+
continue;
|
|
177
|
+
if (latest === undefined || atMs > latest)
|
|
178
|
+
latest = atMs;
|
|
113
179
|
}
|
|
180
|
+
return latest;
|
|
181
|
+
}
|
|
182
|
+
function readActivityFacts(projectionDir, executionId, nowMs, diagnostics, fallbackAtMs) {
|
|
183
|
+
if (!executionId)
|
|
184
|
+
return {};
|
|
185
|
+
const stored = readStoredEvents(projectionDir, executionId, diagnostics);
|
|
186
|
+
const { events, malformed } = selectValidStoredAgentEvents(stored);
|
|
187
|
+
const invalidActivity = invalidActivityEventDiagnostic(malformed);
|
|
188
|
+
if (invalidActivity)
|
|
189
|
+
diagnostics.push(invalidActivity);
|
|
190
|
+
const activityAtMs = latestValidEventAtMs(events) ?? fallbackAtMs;
|
|
114
191
|
return {
|
|
115
|
-
|
|
116
|
-
|
|
192
|
+
...(events.length > 0 ? { activity: foldAgentActivity(events) } : {}),
|
|
193
|
+
...(activityAtMs !== undefined
|
|
194
|
+
? {
|
|
195
|
+
activityAtMs,
|
|
196
|
+
activityAgeMs: Math.max(0, nowMs - activityAtMs),
|
|
197
|
+
}
|
|
198
|
+
: {}),
|
|
117
199
|
};
|
|
118
200
|
}
|
|
119
|
-
function readProjectionRow(projectionDir, id, nowMs
|
|
201
|
+
function readProjectionRow(projectionDir, id, nowMs) {
|
|
120
202
|
const diagnostics = [];
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
203
|
+
const identityFacts = readIdentityFacts(projectionDir, diagnostics);
|
|
204
|
+
const tellCounts = identityFacts.identity
|
|
205
|
+
? readHeartTellCounts(projectionDir, diagnostics)
|
|
206
|
+
: emptyTellCounts();
|
|
207
|
+
if (!identityFacts.identity) {
|
|
125
208
|
return {
|
|
126
209
|
id,
|
|
127
|
-
state: "
|
|
128
|
-
akuma: pactFacts.akuma,
|
|
129
|
-
provider: pactFacts.provider,
|
|
130
|
-
pid: pactFacts.pid,
|
|
131
|
-
mintedAt: pactFacts.mintedAt,
|
|
210
|
+
state: "unknown",
|
|
132
211
|
tellCounts,
|
|
133
212
|
diagnostics,
|
|
134
213
|
};
|
|
135
214
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
215
|
+
const observation = observeProjectionLifeSnapshot(projectionDir, {
|
|
216
|
+
nowMs,
|
|
217
|
+
startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
|
|
218
|
+
});
|
|
219
|
+
const life = observation.life;
|
|
220
|
+
const current = observation.records
|
|
221
|
+
? selectCurrentGeneration(observation.records)
|
|
222
|
+
: null;
|
|
223
|
+
const adoptedAt = current?.adoption?.facts.adoptedAt;
|
|
224
|
+
const adoptedAtMs = typeof adoptedAt === "string"
|
|
225
|
+
? Date.parse(adoptedAt)
|
|
226
|
+
: Number.NaN;
|
|
227
|
+
const activityFacts = readActivityFacts(projectionDir, life.executionId, nowMs, diagnostics, Number.isFinite(adoptedAtMs) ? adoptedAtMs : undefined);
|
|
228
|
+
if (life.phase === "unknown" && life.diagnostic) {
|
|
229
|
+
diagnostics.push({ kind: "unknown-lifecycle", detail: life.diagnostic });
|
|
230
|
+
}
|
|
231
|
+
const phase = life.phase;
|
|
141
232
|
const state = phase === "active" || phase === "quiescent" ? "out" : phase;
|
|
142
233
|
return {
|
|
143
234
|
id,
|
|
144
235
|
state,
|
|
145
|
-
akuma:
|
|
146
|
-
provider:
|
|
147
|
-
pid:
|
|
148
|
-
mintedAt:
|
|
236
|
+
akuma: identityFacts.akuma,
|
|
237
|
+
provider: identityFacts.provider,
|
|
238
|
+
pid: identityFacts.pid,
|
|
239
|
+
mintedAt: identityFacts.mintedAt,
|
|
240
|
+
...(identityFacts.workspaceRoot ? { workspaceRoot: identityFacts.workspaceRoot } : {}),
|
|
241
|
+
...activityFacts,
|
|
149
242
|
tellCounts,
|
|
150
243
|
diagnostics,
|
|
151
|
-
...heartbeatFacts,
|
|
152
244
|
};
|
|
153
245
|
}
|
|
154
|
-
export function readProjectionStatusBoard(cwd, nowMs
|
|
246
|
+
export function readProjectionStatusBoard(cwd, nowMs) {
|
|
155
247
|
const root = projectionRoot(cwd);
|
|
248
|
+
try {
|
|
249
|
+
if (!fs.lstatSync(root).isDirectory())
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
if (isErrnoException(error) && error.code === "ENOENT")
|
|
254
|
+
return null;
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
156
257
|
let entries;
|
|
157
258
|
try {
|
|
158
259
|
entries = fs.readdirSync(root);
|
|
@@ -162,18 +263,17 @@ export function readProjectionStatusBoard(cwd, nowMs, options = {}) {
|
|
|
162
263
|
return null;
|
|
163
264
|
throw error;
|
|
164
265
|
}
|
|
165
|
-
const probePid = options.probePid ?? ((pid) => process.kill(pid, 0));
|
|
166
266
|
const rows = entries
|
|
167
267
|
.filter((entry) => !entry.startsWith("."))
|
|
168
268
|
.filter((entry) => {
|
|
169
269
|
try {
|
|
170
|
-
return fs.
|
|
270
|
+
return fs.lstatSync(path.join(root, entry)).isDirectory();
|
|
171
271
|
}
|
|
172
272
|
catch {
|
|
173
273
|
return false;
|
|
174
274
|
}
|
|
175
275
|
})
|
|
176
276
|
.sort()
|
|
177
|
-
.map((id) => readProjectionRow(path.join(root, id), id, nowMs
|
|
277
|
+
.map((id) => readProjectionRow(path.join(root, id), id, nowMs));
|
|
178
278
|
return rows.length > 0 ? { rows } : null;
|
|
179
279
|
}
|