@quolu/lattice 0.79.3 → 0.79.5

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.
Files changed (48) hide show
  1. package/README.md +8 -2
  2. package/bin/lattice-bridge.mjs +31 -24
  3. package/bin/lattice-dashboard-supervisor.mjs +18 -0
  4. package/bin/lattice-dashboard.mjs +37 -14
  5. package/bin/lattice-mcp.mjs +2 -1
  6. package/docs/bridge-setup.md +37 -0
  7. package/package.json +2 -2
  8. package/sensor/dist/bin/lattice-sensor.js +6 -26
  9. package/sensor/dist/bin/node-version-check.d.ts +10 -1
  10. package/sensor/dist/bin/node-version-check.d.ts.map +1 -1
  11. package/sensor/dist/bin/node-version-check.js +43 -1
  12. package/sensor/dist/bin/node-version-check.js.map +1 -1
  13. package/sensor/dist/mcp/daemon-paths.d.ts +4 -0
  14. package/sensor/dist/mcp/daemon-paths.d.ts.map +1 -1
  15. package/sensor/dist/mcp/daemon-paths.js +12 -0
  16. package/sensor/dist/mcp/daemon-paths.js.map +1 -1
  17. package/sensor/dist/mcp/index.d.ts +3 -1
  18. package/sensor/dist/mcp/index.d.ts.map +1 -1
  19. package/sensor/dist/mcp/index.js +59 -30
  20. package/sensor/dist/mcp/index.js.map +1 -1
  21. package/sensor/dist/mcp/proxy.d.ts +2 -0
  22. package/sensor/dist/mcp/proxy.d.ts.map +1 -1
  23. package/sensor/dist/mcp/proxy.js +9 -3
  24. package/sensor/dist/mcp/proxy.js.map +1 -1
  25. package/sensor/dist/mcp/session.d.ts +7 -0
  26. package/sensor/dist/mcp/session.d.ts.map +1 -1
  27. package/sensor/dist/mcp/session.js +4 -1
  28. package/sensor/dist/mcp/session.js.map +1 -1
  29. package/sensor/dist/mcp/transport.d.ts +5 -5
  30. package/sensor/dist/mcp/transport.d.ts.map +1 -1
  31. package/sensor/dist/mcp/transport.js +14 -6
  32. package/sensor/dist/mcp/transport.js.map +1 -1
  33. package/sensor/package.json +1 -1
  34. package/src/bridge-cli.mjs +6 -2
  35. package/src/bridge-config.mjs +8 -0
  36. package/src/bridge-daemon.mjs +30 -2
  37. package/src/dashboard-delivery.mjs +14 -2
  38. package/src/dashboard-lifecycle-ipc.mjs +5 -0
  39. package/src/dashboard-lifecycle-journal.mjs +237 -0
  40. package/src/dashboard-process-control.mjs +74 -0
  41. package/src/dashboard-supervisor.mjs +180 -0
  42. package/src/dashboard-windows-process-control.ps1 +40 -0
  43. package/src/factory-diagnostics.mjs +22 -9
  44. package/src/mcp-startup-receipt.mjs +99 -0
  45. package/src/node-version-guard.mjs +3 -42
  46. package/src/setup-config.mjs +7 -3
  47. package/src/todo-dashboard-registry.mjs +24 -3
  48. package/src/todo-store-cache.mjs +50 -6
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/mcp/transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/mcp/transport.ts"],"names":[],"mappings":"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"}
@@ -51,6 +51,6 @@
51
51
  "vitest": "^2.1.9"
52
52
  },
53
53
  "engines": {
54
- "node": ">=20.0.0 <25.0.0 || >=26.0.0"
54
+ "node": ">=20.0.0 <24.2.0 || >=24.22.0 <25.0.0 || >=26.10.0"
55
55
  }
56
56
  }
@@ -6,7 +6,7 @@ import * as clack from '@clack/prompts';
6
6
  import packageJson from '../package.json' with { type: 'json' };
7
7
  import { resolveBridgeListenAddress } from './bridge-address.mjs';
8
8
  import { registerBridgeUpstream } from './bridge-registrar.mjs';
9
- import { ensureTodoDashboardDaemon } from './todo-dashboard-registry.mjs';
9
+ import { ensureTodoDashboardDaemon, readTodoDashboardLifecycleStatus } from './todo-dashboard-registry.mjs';
10
10
  import { verifyBridgeHubDelivery } from './dashboard-delivery.mjs';
11
11
  import {
12
12
  BridgeConfigError, configureBridge, disableBridge, readBridgeConfig, restoreBridgeConfig,
@@ -472,7 +472,11 @@ export async function runBridgeCli({ argv, stdout, stderr, env = process.env,
472
472
  if (wizard) {
473
473
  stdout.write(`Lattice bridgeを${config.listen.address}:${config.listen.port}で有効にしました。\n`);
474
474
  for (const warning of warnings ?? []) stdout.write(`警告: ${warning.message}\n`);
475
- } else stdout.write(`${JSON.stringify(result(command, config, recovery, liveness, diagnostics, warnings))}\n`);
475
+ } else {
476
+ const output = result(command, config, recovery, liveness, diagnostics, warnings);
477
+ if (command === 'status') output.dashboard_lifecycle = await readTodoDashboardLifecycleStatus({ env });
478
+ stdout.write(`${JSON.stringify(output)}\n`);
479
+ }
476
480
  return 0;
477
481
  } catch (error) {
478
482
  const payload = { schema: 'lattice.cli_error.v2',
@@ -270,6 +270,14 @@ export async function withBridgeOperationLock({ env = process.env } = {}, action
270
270
  return withLock(refs.operationLock, action);
271
271
  }
272
272
 
273
+ /** Serialize request publication with daemon shutdown; never hold this while waiting for a receipt. */
274
+ export async function withBridgeStopTransition({ env = process.env } = {}, action) {
275
+ if (typeof action !== 'function') throw new TypeError('bridge stop action required');
276
+ const refs = bridgeConfigPaths(env);
277
+ await prepareRoot(refs.root);
278
+ return withLock(path.join(refs.root, 'bridge-stop-transition.lock'), action);
279
+ }
280
+
273
281
  function closeServer(server) {
274
282
  return new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
275
283
  }
@@ -9,6 +9,7 @@ import { parseTree } from 'jsonc-parser';
9
9
 
10
10
  import {
11
11
  BRIDGE_PORT_MAX, BRIDGE_PORT_MIN, BridgeConfigError, bridgeConfigPaths, readBridgeConfig,
12
+ withBridgeStopTransition,
12
13
  } from './bridge-config.mjs';
13
14
  import { resolveBridgeListenAddress } from './bridge-address.mjs';
14
15
  import packageJson from '../package.json' with { type: 'json' };
@@ -201,9 +202,24 @@ export async function clearBridgeStopControl({ env = process.env } = {}) {
201
202
  await rm(refs.receipt, { force: true });
202
203
  }
203
204
 
204
- export async function requestBridgeDaemonStop({ env = process.env, listen = null } = {}) {
205
+ /** Close the data plane before acknowledging the latest published request. */
206
+ export async function completeBridgeDaemonStop({ env = process.env, close } = {}) {
207
+ if (typeof close !== 'function') throw new TypeError('bridge close action required');
208
+ return withBridgeStopTransition({ env }, async () => {
209
+ await close();
210
+ const request = await readBridgeStopRequest({ env });
211
+ if (request !== null) await writeBridgeStopReceipt({ nonce: request.nonce, env });
212
+ await removeBridgeDaemonDescriptor({ env });
213
+ await removeBridgeDaemonActiveMarker({ env });
214
+ return { nonce: request?.nonce ?? null };
215
+ });
216
+ }
217
+
218
+ async function publishBridgeStopRequest({ env, listen }) {
205
219
  let descriptor = null;
206
- try { descriptor = await readBridgeDaemonDescriptor({ env }); } catch {}
220
+ try { descriptor = await readBridgeDaemonDescriptor({ env }); } catch (error) {
221
+ if (error?.code !== 'BRIDGE_DAEMON_DESCRIPTOR_INVALID') throw error;
222
+ }
207
223
  let config = null;
208
224
  try { config = await readBridgeConfig({ env }); } catch (error) {
209
225
  if (!['BRIDGE_CONFIG_INVALID', 'BRIDGE_CONFIG_MODE_INVALID'].includes(error?.code)) throw error;
@@ -234,11 +250,23 @@ export async function requestBridgeDaemonStop({ env = process.env, listen = null
234
250
  }
235
251
  }
236
252
  const refs = bridgeStopPaths(env);
253
+ // Concurrent callers join the published request instead of overwriting its nonce.
254
+ const pending = await readBridgeStopRequest({ env });
255
+ if (pending !== null) return { state: 'requested', nonce: pending.nonce };
237
256
  const nonce = randomBytes(32).toString('hex');
238
257
  await rm(refs.receipt, { force: true });
239
258
  await atomicDescriptor(refs.request, {
240
259
  schema: STOP_REQUEST_SCHEMA, nonce, requested_at: new Date().toISOString(),
241
260
  });
261
+ return { state: 'requested', nonce };
262
+ }
263
+
264
+ export async function requestBridgeDaemonStop({ env = process.env, listen = null } = {}) {
265
+ const published = await withBridgeStopTransition({ env }, () => publishBridgeStopRequest({ env, listen }));
266
+ if (published.state === 'not_running') return published;
267
+ const { nonce } = published;
268
+ const refs = bridgeStopPaths(env);
269
+ // Wait outside the transition lock: the daemon needs it to close and acknowledge.
242
270
  const deadline = Date.now() + STOP_TIMEOUT_MS;
243
271
  while (Date.now() < deadline) {
244
272
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -5,6 +5,12 @@ import { createBridgeHubHeartbeatController } from './bridge-hub-heartbeat.mjs';
5
5
 
6
6
  const SCHEMA = 'lattice.dashboard_delivery.v1';
7
7
  const SETUP = 'lattice bridge setup --listen <IP> --dashboard --hub <URL> --json';
8
+ const FAILURE_STAGES = new Map([
9
+ ...['heartbeat_missing', 'heartbeat_invalid', 'unreachable', 'rejected', 'skipped_no_dashboard',
10
+ 'skipped_no_projects', 'project_not_registered'].map((reason) => [reason, 'heartbeat_registration']),
11
+ ...['hub_listing_unavailable', 'project_not_visible'].map((reason) => [reason, 'hub_listing']),
12
+ ...['project_unreachable', 'project_response_invalid'].map((reason) => [reason, 'project_route']),
13
+ ]);
8
14
 
9
15
  function receipt(state, reason, projectIds = [], urls = [], nextAction = null) {
10
16
  return { schema: SCHEMA, state, reason, project_ids: projectIds, urls, next_action: nextAction };
@@ -13,7 +19,8 @@ function receipt(state, reason, projectIds = [], urls = [], nextAction = null) {
13
19
  function unconfirmed(reason, projectIds = []) {
14
20
  return new BridgeConfigError('BRIDGE_HUB_DELIVERY_UNCONFIRMED',
15
21
  '工程の公開配信を確認できません。接続設定は保存済みです。', {
16
- reason, project_ids: projectIds, next_action: 'lattice todo dashboard ensure --json',
22
+ reason, stage: FAILURE_STAGES.get(reason), project_ids: projectIds,
23
+ next_action: 'lattice todo dashboard ensure --json',
17
24
  });
18
25
  }
19
26
 
@@ -29,7 +36,8 @@ export async function verifyBridgeHubDelivery({ config, env = process.env, proje
29
36
  || result?.schema !== 'lattice.bridge_hub_registration_result.v2'
30
37
  || !Array.isArray(registered) || !registered.every((id) => typeof id === 'string')
31
38
  || !Array.isArray(result.rejected)) {
32
- throw unconfirmed(delivered?.state ?? 'heartbeat_missing');
39
+ throw unconfirmed(FAILURE_STAGES.has(delivered?.state) ? delivered.state
40
+ : delivered?.state == null ? 'heartbeat_missing' : 'heartbeat_invalid');
33
41
  }
34
42
  const projectIds = projectId === null ? registered : [projectId];
35
43
  if (projectIds.length === 0 || projectIds.some((id) => !registered.includes(id))
@@ -97,6 +105,10 @@ export async function reportProjectDashboardDelivery({ projectId, env, stderr,
97
105
  if (typeof error?.code !== 'string') throw error;
98
106
  delivery = receipt('failed', error.code, [projectId], [],
99
107
  error.detail?.next_action ?? 'lattice bridge status --json');
108
+ const subreason = error.detail?.reason;
109
+ delivery.failure = error.code === 'BRIDGE_HUB_DELIVERY_UNCONFIRMED' && FAILURE_STAGES.has(subreason)
110
+ ? { stage: FAILURE_STAGES.get(subreason), subreason }
111
+ : { stage: 'unknown', subreason: 'unavailable' };
100
112
  }
101
113
  stderr?.write(`${JSON.stringify(delivery)}\n`);
102
114
  return delivery;
@@ -0,0 +1,5 @@
1
+ /** Only a fixed phase name crosses this channel; no project data or errors. */
2
+ export function dashboardLifecyclePhase(phase) {
3
+ if (!process.connected) return;
4
+ process.send({ type: 'dashboard_phase', phase }, () => {});
5
+ }
@@ -0,0 +1,237 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { lstat, mkdir, open, readdir, readFile, rename, rm } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+
6
+ const SCHEMA = 'lattice.dashboard_lifecycle.v1';
7
+ export const LIFECYCLE_MAX_RUNS = 64;
8
+ export const LIFECYCLE_MAX_BYTES = 16 * 1024;
9
+ const PHASES = new Set(['spawn', 'import', 'registry', 'store', 'listen', 'ready',
10
+ 'periodic_sync', 'empty_shutdown', 'shutdown_request', 'sync_failed', 'store_read_failed',
11
+ 'store_manifest_missing', 'store_root_missing', 'store_access_denied', 'store_io_failed',
12
+ 'store_manifest_invalid', 'store_artifact_missing',
13
+ 'cleanup_failed', 'close_failed', 'close', 'closed']);
14
+ const RUN_ID = /^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/u;
15
+ const WINDOWS_REPLACE_WAIT_MS = 500;
16
+ const REPLACE_MAX_ATTEMPTS = 32;
17
+
18
+ export function lifecycleError(code) {
19
+ return Object.assign(new Error(code), { code,
20
+ detail: { reason: code.toLowerCase(), next_action: 'lattice todo dashboard ensure --json' } });
21
+ }
22
+
23
+ function directory(root) { return path.join(root, 'lifecycle'); }
24
+ function terminationTime(run) {
25
+ return run.exit_observed_at ?? run.observer_loss_observed_at ?? run.started_at;
26
+ }
27
+ function reference(root, id) {
28
+ if (!RUN_ID.test(id)) throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID');
29
+ return path.join(directory(root), `${id}.json`);
30
+ }
31
+
32
+ async function checkOwned(ref, type) {
33
+ const info = await lstat(ref);
34
+ if (info.isSymbolicLink() || (type === 'directory' ? !info.isDirectory() : !info.isFile())
35
+ || (typeof process.getuid === 'function' && info.uid !== process.getuid())
36
+ || (process.platform !== 'win32' && (info.mode & 0o077) !== 0)) {
37
+ throw lifecycleError('DASHBOARD_LIFECYCLE_UNSAFE_PATH');
38
+ }
39
+ return info;
40
+ }
41
+
42
+ export async function prepareLifecycleDirectory(root) {
43
+ // The runtime root is already private and owned by the dashboard registry.
44
+ await checkOwned(root, 'directory');
45
+ await mkdir(directory(root), { mode: 0o700 }).catch((error) => {
46
+ if (error.code !== 'EEXIST') throw error;
47
+ });
48
+ await checkOwned(directory(root), 'directory');
49
+ // Interrupted atomic writes contain no body data either, but must not grow forever.
50
+ const pending = /^(?:[a-f0-9-]{36}\.json|ensure\.json)\.([1-9][0-9]*)\.[a-f0-9-]{36}\.tmp$/u;
51
+ for (const name of await readdir(directory(root))) {
52
+ const match = pending.exec(name);
53
+ if (!match) continue;
54
+ let alive = true;
55
+ try { process.kill(Number(match[1]), 0); } catch (error) {
56
+ if (error.code !== 'ESRCH') throw error;
57
+ alive = false;
58
+ }
59
+ if (!alive) {
60
+ const ref = path.join(directory(root), name);
61
+ await checkOwned(ref, 'file');
62
+ await rm(ref);
63
+ }
64
+ }
65
+ }
66
+
67
+ export async function readLifecycleRuns(root) {
68
+ try { await checkOwned(directory(root), 'directory'); } catch (error) {
69
+ if (error.code === 'ENOENT') return [];
70
+ throw error;
71
+ }
72
+ const runs = [];
73
+ for (const name of (await readdir(directory(root))).sort()) {
74
+ if (!name.endsWith('.json') || !RUN_ID.test(name.slice(0, -5))) continue;
75
+ const ref = path.join(directory(root), name);
76
+ const info = await checkOwned(ref, 'file');
77
+ if (info.size > LIFECYCLE_MAX_BYTES) throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID');
78
+ const handle = await open(ref, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
79
+ let value;
80
+ try { value = JSON.parse(await handle.readFile('utf8')); }
81
+ catch { throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID'); }
82
+ finally { await handle.close(); }
83
+ if (value?.schema !== SCHEMA || value.run_id !== name.slice(0, -5)
84
+ || !['active', 'closed', 'supervisor_lost'].includes(value.state)) {
85
+ throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID');
86
+ }
87
+ runs.push(value);
88
+ }
89
+ return runs.sort((a, b) => a.started_at.localeCompare(b.started_at));
90
+ }
91
+
92
+ /** Publish only after a real atomic replacement; Windows delete-sharing can be transient. */
93
+ async function publishLifecycleJson(ref, bytes) {
94
+ const parent = path.dirname(ref);
95
+ await checkOwned(parent, 'directory');
96
+ // At most 64 live writers can race this check, so even orphaned temporary files
97
+ // have a finite bound. Refuse another write rather than discard an active run.
98
+ if ((await readdir(parent)).length >= 256) throw lifecycleError('DASHBOARD_LIFECYCLE_CAPACITY');
99
+ if (Buffer.byteLength(bytes) > LIFECYCLE_MAX_BYTES) throw lifecycleError('DASHBOARD_LIFECYCLE_CAPACITY');
100
+ try { await checkOwned(ref, 'file'); } catch (error) { if (error.code !== 'ENOENT') throw error; }
101
+ const temporary = `${ref}.${process.pid}.${randomUUID()}.tmp`;
102
+ const handle = await open(temporary, 'wx', 0o600);
103
+ try {
104
+ await handle.writeFile(bytes, 'utf8');
105
+ await handle.sync();
106
+ } finally { await handle.close(); }
107
+ // Failed private temporaries stay bounded for dead-writer cleanup. Never delete
108
+ // the old receipt to make replacement succeed, or let cleanup mask its error.
109
+ const deadline = performance.now() + WINDOWS_REPLACE_WAIT_MS;
110
+ let attempts = 0;
111
+ for (;;) {
112
+ await checkOwned(parent, 'directory');
113
+ await checkOwned(temporary, 'file');
114
+ try { await checkOwned(ref, 'file'); } catch (error) { if (error.code !== 'ENOENT') throw error; }
115
+ attempts++;
116
+ try {
117
+ await rename(temporary, ref);
118
+ return;
119
+ } catch (error) {
120
+ const busy = process.platform === 'win32' && ['EPERM', 'EACCES', 'EBUSY'].includes(error.code);
121
+ if (!busy) throw error;
122
+ if (performance.now() >= deadline || attempts >= REPLACE_MAX_ATTEMPTS) {
123
+ const failure = lifecycleError('DASHBOARD_LIFECYCLE_PUBLISH_FAILED');
124
+ failure.cause = error;
125
+ failure.detail = { ...failure.detail, operation: 'atomic_replace',
126
+ fs_code: error.code, attempts, temporary_retained: true };
127
+ throw failure;
128
+ }
129
+ await new Promise((resolve) => setTimeout(resolve,
130
+ Math.min(10 * 2 ** Math.min(attempts - 1, 3), 50, Math.max(1, deadline - performance.now()))));
131
+ }
132
+ }
133
+ }
134
+
135
+ export async function writeLifecycleRun(root, run) {
136
+ await publishLifecycleJson(reference(root, run.run_id), `${JSON.stringify(run)}\n`);
137
+ }
138
+
139
+ /** Call under the existing dashboard startup lock, before spawning anything. */
140
+ export async function createLifecycleRun(root, version) {
141
+ await prepareLifecycleDirectory(root);
142
+ const runs = await readLifecycleRuns(root);
143
+ while (runs.length >= LIFECYCLE_MAX_RUNS) {
144
+ const oldest = runs.filter((run) => run.state !== 'active'
145
+ && !run.child_at_reconciliation?.startsWith('present'))
146
+ .sort((a, b) => terminationTime(a).localeCompare(terminationTime(b)))[0];
147
+ if (!oldest) throw lifecycleError('DASHBOARD_LIFECYCLE_CAPACITY');
148
+ const index = runs.findIndex((run) => run.run_id === oldest.run_id);
149
+ const [old] = runs.splice(index, 1);
150
+ await rm(reference(root, old.run_id));
151
+ }
152
+ const run = { schema: SCHEMA, run_id: randomUUID(), version, platform: process.platform,
153
+ state: 'active', started_at: new Date().toISOString(), supervisor: null, child: null,
154
+ phase: 'spawn', ready_at: null, exit_observed_at: null,
155
+ observed_exit: { status: 'unknown' }, termination_request: null,
156
+ stderr: { bytes: 0, hashed_bytes: 0, sha256: null, truncated: false }, events: [] };
157
+ await writeLifecycleRun(root, run);
158
+ return run;
159
+ }
160
+
161
+ export function recordLifecyclePhase(run, phase) {
162
+ if (!PHASES.has(phase) || phase === run.phase) return false;
163
+ run.phase = phase;
164
+ if (['empty_shutdown', 'shutdown_request', 'sync_failed', 'cleanup_failed', 'close_failed'].includes(phase)) {
165
+ run.exit_stage = phase;
166
+ }
167
+ const at = new Date().toISOString();
168
+ if (phase === 'ready' && run.ready_at === null) run.ready_at = at;
169
+ if (phase.startsWith('store_') || ['sync_failed', 'cleanup_failed', 'close_failed'].includes(phase)) {
170
+ run.last_failure_observed = { at, phase };
171
+ }
172
+ run.events.push({ at, phase });
173
+ if (run.events.length > 64) run.events.shift();
174
+ return true;
175
+ }
176
+
177
+ /** No fabricated exit time/value when the observer itself disappeared. */
178
+ export async function reconcileLifecycleRuns(root, observeIdentity) {
179
+ const runs = await readLifecycleRuns(root);
180
+ for (const run of runs) {
181
+ if (run.state === 'closed') continue;
182
+ const supervisor = run.supervisor === null ? null : await observeIdentity(run.supervisor.pid);
183
+ if (run.state === 'active' && supervisor !== null && supervisor.birth !== null
184
+ && supervisor.birth === run.supervisor.birth) continue;
185
+ // Unknown birth cannot establish observer loss. Do not overwrite its receipt.
186
+ if (run.state === 'active' && supervisor !== null
187
+ && (supervisor.birth === null || run.supervisor.birth === null)) continue;
188
+ const previousState = run.state;
189
+ const previousPresence = run.child_at_reconciliation;
190
+ run.state = 'supervisor_lost';
191
+ run.observer_loss_observed_at ??= new Date().toISOString();
192
+ const child = run.child === null ? null : await observeIdentity(run.child.pid);
193
+ run.child_at_reconciliation = run.child === null ? 'not_observed' : child === null ? 'absent'
194
+ : child.birth !== null && child.birth === run.child.birth ? 'present_identity_matched'
195
+ : child.birth !== null && run.child.birth !== null ? 'absent_identity_reused'
196
+ : 'present_identity_unconfirmed';
197
+ run.observed_exit = { status: 'unknown', reason: 'supervisor_lost' };
198
+ if (previousState !== run.state || previousPresence !== run.child_at_reconciliation) {
199
+ run.child_presence_observed_at = new Date().toISOString();
200
+ await writeLifecycleRun(root, run);
201
+ }
202
+ }
203
+ return runs;
204
+ }
205
+
206
+ /** One bounded decision receipt, serialized by the registry's existing startup lock. */
207
+ export async function recordDashboardEnsureDecision(root, decision, childPid) {
208
+ if (!['reuse_current', 'adopt_current', 'replace_legacy', 'start_missing',
209
+ 'pid_reused', 'alive_unresponsive'].includes(decision)) throw new TypeError('invalid dashboard decision');
210
+ await prepareLifecycleDirectory(root);
211
+ const matching = (await readLifecycleRuns(root)).filter((run) => run.child?.pid === childPid
212
+ && (run.state === 'active' || run.child_at_reconciliation?.startsWith('present'))).at(-1);
213
+ const supervision = childPid === null ? 'not_started' : matching?.state === 'active' ? 'supervised'
214
+ : matching?.state === 'supervisor_lost' ? 'supervisor_lost' : 'legacy_unsupervised';
215
+ const ref = path.join(directory(root), 'ensure.json');
216
+ await publishLifecycleJson(ref, `${JSON.stringify({ schema: 'lattice.dashboard_ensure.v1',
217
+ observed_at: new Date().toISOString(), decision, child_pid: childPid,
218
+ supervision, run_id: matching?.run_id ?? null })}\n`);
219
+ }
220
+
221
+ export async function readDashboardLifecycleStatus(root) {
222
+ const runs = await readLifecycleRuns(root);
223
+ const terminal = runs.filter((run) => run.state !== 'active').sort((a, b) =>
224
+ terminationTime(a).localeCompare(terminationTime(b)));
225
+ let ensure = null;
226
+ try {
227
+ const ref = path.join(directory(root), 'ensure.json');
228
+ const info = await checkOwned(ref, 'file');
229
+ if (info.size > LIFECYCLE_MAX_BYTES) throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID');
230
+ try { ensure = JSON.parse(await readFile(ref, 'utf8')); }
231
+ catch { throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID'); }
232
+ if (ensure.schema !== 'lattice.dashboard_ensure.v1') throw lifecycleError('DASHBOARD_LIFECYCLE_INVALID');
233
+ } catch (error) { if (error.code !== 'ENOENT') throw error; }
234
+ return { schema: 'lattice.dashboard_lifecycle_status.v1',
235
+ last_ensure: ensure, active: runs.filter((run) => run.state === 'active'),
236
+ last_termination: terminal.at(-1) ?? null };
237
+ }
@@ -0,0 +1,74 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { promisify } from 'node:util';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const execute = promisify(execFile);
7
+
8
+ /** A missing process and an unavailable birth observation are different. */
9
+ export async function observeDashboardProcess(pid) {
10
+ if (!Number.isSafeInteger(pid) || pid < 1) throw new TypeError('invalid dashboard pid');
11
+ try { process.kill(pid, 0); } catch (error) {
12
+ if (error.code === 'ESRCH') return null;
13
+ throw error;
14
+ }
15
+ try {
16
+ if (process.platform === 'linux') {
17
+ const [stat, boot] = await Promise.all([readFile(`/proc/${pid}/stat`, 'utf8'),
18
+ readFile('/proc/sys/kernel/random/boot_id', 'utf8')]);
19
+ const fields = stat.slice(stat.lastIndexOf(')') + 2).split(' ');
20
+ if (fields[0] === 'Z') return null;
21
+ return { pid, birth: `linux:${boot.trim()}:${fields[19]}` };
22
+ }
23
+ const { stdout } = process.platform === 'win32'
24
+ ? await execute('pwsh.exe', ['-NoProfile', '-NonInteractive', '-Command',
25
+ `[System.Diagnostics.Process]::GetProcessById(${pid}).StartTime.ToUniversalTime().ToFileTimeUtc()`],
26
+ { encoding: 'utf8', timeout: 5_000, windowsHide: true })
27
+ : await execute('/bin/ps', ['-o', 'lstart=', '-p', String(pid)],
28
+ { encoding: 'utf8', timeout: 5_000, env: { ...process.env, LC_ALL: 'C' } });
29
+ return { pid, birth: stdout.trim() || null };
30
+ } catch (error) {
31
+ // Recheck death after a racing exit. An observation failure never licenses a kill.
32
+ try { process.kill(pid, 0); } catch (probeError) {
33
+ if (probeError.code === 'ESRCH') return null;
34
+ throw probeError;
35
+ }
36
+ return { pid, birth: null, observation: 'unavailable' };
37
+ }
38
+ }
39
+
40
+ export function observedDashboardExit(code, signal, platform = process.platform) {
41
+ if (platform === 'win32') {
42
+ if (!Number.isInteger(code)) return { status: 'unknown', signal: 'not_applicable' };
43
+ const uint32 = code >>> 0;
44
+ return { status: 'observed', uint32, hex: `0x${uint32.toString(16).padStart(8, '0').toUpperCase()}`,
45
+ signal: 'not_applicable', source: 'node_child_wait', origin: 'unknown' };
46
+ }
47
+ if (Number.isInteger(code)) return { status: 'observed', code, signal: null, source: 'node_child_wait' };
48
+ if (typeof signal === 'string') return { status: 'observed', code: null, signal, source: 'node_child_wait' };
49
+ return { status: 'unknown' };
50
+ }
51
+
52
+ /** Use the same authenticated handle for birth check, termination and exit read. */
53
+ export async function terminateOwnedWindowsDashboard(identity, exitCode = 1) {
54
+ if (!identity || !Number.isSafeInteger(identity.pid) || !/^[0-9]+$/u.test(identity.birth ?? '')) {
55
+ throw Object.assign(new Error('dashboard process birth is unavailable'),
56
+ { code: 'DASHBOARD_CHILD_IDENTITY_UNAVAILABLE' });
57
+ }
58
+ const script = fileURLToPath(new URL('./dashboard-windows-process-control.ps1', import.meta.url));
59
+ const { stdout } = await execute('pwsh.exe', ['-NoProfile', '-NonInteractive', '-File', script,
60
+ '-ChildPid', String(identity.pid), '-BirthFileTime', identity.birth, '-RequestedExitCode', String(exitCode)],
61
+ { encoding: 'utf8', timeout: 12_000, windowsHide: true, maxBuffer: 16_384 });
62
+ const result = JSON.parse(stdout.trim());
63
+ if (result.schema !== 'lattice.dashboard_process_control.v1'
64
+ || result.pid !== identity.pid || result.birth_filetime !== identity.birth
65
+ || typeof result.termination_requested !== 'boolean' || result.requested_exit_code !== exitCode
66
+ || !Number.isInteger(result.actual_exit_code) || result.actual_exit_code < 0
67
+ || result.actual_exit_code > 0xFFFFFFFF
68
+ || result.actual_exit_hex !== `0x${result.actual_exit_code.toString(16).padStart(8, '0').toUpperCase()}`
69
+ || result.source !== 'GetExitCodeProcess') {
70
+ throw Object.assign(new Error('dashboard process control result invalid'),
71
+ { code: 'DASHBOARD_CHILD_CONTROL_INVALID' });
72
+ }
73
+ return result;
74
+ }