@north-light/crouter 0.3.167 → 0.3.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clients/attach/viewer.js +254 -254
- package/dist/core/__tests__/broker-fork-seam.test.js +1 -2
- package/dist/core/__tests__/broker-sdk-wiring.test.js +4 -4
- package/dist/core/canvas/pid.d.ts +5 -14
- package/dist/core/canvas/pid.js +21 -35
- package/dist/web-client/assets/index-U_NZ66VE.js +79 -0
- package/dist/web-client/assets/{index-BgLGlZ3D.css → index-aaeu4adv.css} +1 -1
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/package.json +1 -1
- package/runtime.lock.json +6 -6
- package/dist/web-client/assets/index-CmoNqcCv.js +0 -79
|
@@ -34,7 +34,6 @@ import { tmpdir } from 'node:os';
|
|
|
34
34
|
import { dirname, join } from 'node:path';
|
|
35
35
|
import { fileURLToPath } from 'node:url';
|
|
36
36
|
import { createAgentSessionServices, createAgentSessionFromServices, SessionManager, VERSION, } from '../runtime/broker-sdk.js';
|
|
37
|
-
import { CANVAS_EXTENSIONS } from '../runtime/launch.js';
|
|
38
37
|
import { buildBrokerSession } from '../runtime/broker.js';
|
|
39
38
|
// M-9 (broker.ts fault-and-die model gate): buildBrokerSession with no cfg.model
|
|
40
39
|
// now calls the REAL SDK's modelRegistry.getAvailable() and faults if it's empty
|
|
@@ -83,7 +82,7 @@ test('D2 broker fork branch: buildBrokerSession(cfg.forkFrom) yields a NEW id +
|
|
|
83
82
|
// if broker.ts:~1106 reverts to that throw, this rejects and the test goes RED.
|
|
84
83
|
const cfg = {
|
|
85
84
|
cwd: dir,
|
|
86
|
-
extensionPaths: [
|
|
85
|
+
extensionPaths: [C3_EXT],
|
|
87
86
|
forkFrom: srcFile,
|
|
88
87
|
model: 'c3prov/c3model',
|
|
89
88
|
};
|
|
@@ -84,7 +84,7 @@ function cfg(cwd, extra = {}) {
|
|
|
84
84
|
test('C3 — services path registers an extension model provider; the broker session gets it', async () => {
|
|
85
85
|
const cwd = mkdtempSync(join(tmpdir(), 'crtr-c3-'));
|
|
86
86
|
try {
|
|
87
|
-
const { session, services } = await buildBrokerSession(realEngine, cfg(cwd, { model: 'c3prov/c3model' }));
|
|
87
|
+
const { session, services } = await buildBrokerSession(realEngine, cfg(cwd, { extensionPaths: [C3_EXT], model: 'c3prov/c3model' }));
|
|
88
88
|
try {
|
|
89
89
|
// The extension's provider was registered into the SERVICES model runtime (this
|
|
90
90
|
// is the registerProvider step plain createAgentSession skips).
|
|
@@ -107,7 +107,7 @@ test('C3 — services path registers an extension model provider; the broker ses
|
|
|
107
107
|
test('C3b — broker splits model thinking suffix before SDK registry lookup', async () => {
|
|
108
108
|
const cwd = mkdtempSync(join(tmpdir(), 'crtr-c3b-'));
|
|
109
109
|
try {
|
|
110
|
-
const { session } = await buildBrokerSession(realEngine, cfg(cwd, { model: 'c3prov/c3model:high' }));
|
|
110
|
+
const { session } = await buildBrokerSession(realEngine, cfg(cwd, { extensionPaths: [C3_EXT], model: 'c3prov/c3model:high' }));
|
|
111
111
|
try {
|
|
112
112
|
assert.equal(session.model?.id, 'c3model', 'C3b: suffixed model specs resolve by model id instead of falling back to SDK default');
|
|
113
113
|
}
|
|
@@ -420,7 +420,7 @@ test('C5 — isLeadingEngineCommand against a REAL session (registered extension
|
|
|
420
420
|
// proven against a plain object shaped like the real accessors.
|
|
421
421
|
const cwd = mkdtempSync(join(tmpdir(), 'crtr-c5-cmd-'));
|
|
422
422
|
try {
|
|
423
|
-
const { session } = await buildBrokerSession(realEngine, cfg(cwd, { extensionPaths: [
|
|
423
|
+
const { session } = await buildBrokerSession(realEngine, cfg(cwd, { extensionPaths: [C3_EXT, C5_EXT], model: 'c3prov/c3model' }));
|
|
424
424
|
try {
|
|
425
425
|
assert.equal(isLeadingEngineCommand('/devcmd', session), true, 'a real registered extension command matches');
|
|
426
426
|
assert.equal(isLeadingEngineCommand('/devcmd extra args', session), true, 'space-separated still matches against a real session');
|
|
@@ -744,7 +744,7 @@ test('Major 6 (broker half) — engineLeadingCommandTokens degrades to empty per
|
|
|
744
744
|
test('Major 6 (broker half) — engineLeadingCommandTokens against a REAL session enumerates the real registered extension command', async () => {
|
|
745
745
|
const cwd = mkdtempSync(join(tmpdir(), 'crtr-m6-cmd-'));
|
|
746
746
|
try {
|
|
747
|
-
const { session } = await buildBrokerSession(realEngine, cfg(cwd, { extensionPaths: [
|
|
747
|
+
const { session } = await buildBrokerSession(realEngine, cfg(cwd, { extensionPaths: [C3_EXT, C5_EXT], model: 'c3prov/c3model' }));
|
|
748
748
|
try {
|
|
749
749
|
const tokens = engineLeadingCommandTokens(session);
|
|
750
750
|
assert.ok(tokens.includes('devcmd'), 'the real registered extension command name is present in the enumeration');
|
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
/** True if a process with `pid` is currently alive (
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* null/undefined pid
|
|
6
|
-
*
|
|
7
|
-
* The zombie check matters because EVERY broker this module supervises is
|
|
8
|
-
* spawned `detached: true` by crtr itself (`headlessBrokerHost.launch`) — a
|
|
9
|
-
* dead broker whose spawning process hasn't reaped it yet is a zombie, and
|
|
10
|
-
* `kill(pid, 0)` alone reports it as alive, wedging the daemon's revive guard
|
|
11
|
-
* (`isPidAlive(pi_pid)`, `revive.ts`) forever: the daemon never revives an
|
|
12
|
-
* already-live-looking row, so a refreshed/crashed node whose broker zombied
|
|
13
|
-
* out under a long-lived spawning process (see `isZombie`'s doc) never comes
|
|
14
|
-
* back on its own. */
|
|
1
|
+
/** True if a process with `pid` is currently alive. `kill(pid, 0)` provides the
|
|
2
|
+
* initial existence check; EPERM means the foreign process exists. For our
|
|
3
|
+
* processes, the later `ps` read is authoritative because it also distinguishes
|
|
4
|
+
* zombies and processes reaped between the two probes. Only an unavailable
|
|
5
|
+
* `ps` probe fails open to alive. A null/undefined pid reads dead. */
|
|
15
6
|
export declare function isPidAlive(pid: number | null | undefined): boolean;
|
|
16
7
|
/** THE single precision-aware identity compare, used EVERYWHERE two
|
|
17
8
|
* `composeIdentity` fingerprints are compared (this module's own
|
package/dist/core/canvas/pid.js
CHANGED
|
@@ -10,46 +10,31 @@
|
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
11
|
import { readFileSync } from 'node:fs';
|
|
12
12
|
import { readKernelBootId } from './boot-id.js';
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
* front door's foreground attach session parks its OWN event loop for the
|
|
19
|
-
* whole session — see `bootRoot` in runtime/boot-root.ts — so it can't process
|
|
20
|
-
* the SIGCHLD that would otherwise reap its detached broker child in real
|
|
21
|
-
* time). `ps -o stat=` reports a leading `Z` for a zombie on BOTH BSD ps
|
|
22
|
-
* (macOS) and procps-ng (Linux), so one portable probe covers both platforms
|
|
23
|
-
* without a Linux-only `/proc` special case. Best-effort: any probe failure
|
|
24
|
-
* (spawn error, no matching row, non-zero exit) reads as NOT a zombie —
|
|
25
|
-
* fail-open, matching this module's other guards; a probe failure must never
|
|
26
|
-
* be misread as proof of death (a live pid IS alive; only a positive `Z`
|
|
27
|
-
* read says otherwise). */
|
|
28
|
-
function isZombie(pid) {
|
|
13
|
+
/** Classify the current `ps` row for a pid. BSD ps and procps-ng both report a
|
|
14
|
+
* leading `Z` for zombies and exit silently with empty output when no process
|
|
15
|
+
* matches. Only a probe that could not run is unknown; that is the sole
|
|
16
|
+
* fail-open result. */
|
|
17
|
+
function psProcessState(pid) {
|
|
29
18
|
try {
|
|
30
19
|
const r = spawnSync('ps', ['-o', 'stat=', '-p', String(pid)], { encoding: 'utf8', timeout: 2000 });
|
|
31
|
-
if (r.
|
|
32
|
-
return
|
|
33
|
-
|
|
20
|
+
if (r.error != null || r.signal != null || typeof r.stdout !== 'string')
|
|
21
|
+
return 'unknown';
|
|
22
|
+
if (typeof r.stderr === 'string' && r.stderr.trim() !== '')
|
|
23
|
+
return 'unknown';
|
|
24
|
+
const stat = r.stdout.trim();
|
|
25
|
+
if (stat === '')
|
|
26
|
+
return 'gone';
|
|
27
|
+
return stat.charAt(0) === 'Z' ? 'zombie' : 'live';
|
|
34
28
|
}
|
|
35
29
|
catch {
|
|
36
|
-
return
|
|
30
|
+
return 'unknown';
|
|
37
31
|
}
|
|
38
32
|
}
|
|
39
|
-
/** True if a process with `pid` is currently alive (
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* null/undefined pid
|
|
44
|
-
*
|
|
45
|
-
* The zombie check matters because EVERY broker this module supervises is
|
|
46
|
-
* spawned `detached: true` by crtr itself (`headlessBrokerHost.launch`) — a
|
|
47
|
-
* dead broker whose spawning process hasn't reaped it yet is a zombie, and
|
|
48
|
-
* `kill(pid, 0)` alone reports it as alive, wedging the daemon's revive guard
|
|
49
|
-
* (`isPidAlive(pi_pid)`, `revive.ts`) forever: the daemon never revives an
|
|
50
|
-
* already-live-looking row, so a refreshed/crashed node whose broker zombied
|
|
51
|
-
* out under a long-lived spawning process (see `isZombie`'s doc) never comes
|
|
52
|
-
* back on its own. */
|
|
33
|
+
/** True if a process with `pid` is currently alive. `kill(pid, 0)` provides the
|
|
34
|
+
* initial existence check; EPERM means the foreign process exists. For our
|
|
35
|
+
* processes, the later `ps` read is authoritative because it also distinguishes
|
|
36
|
+
* zombies and processes reaped between the two probes. Only an unavailable
|
|
37
|
+
* `ps` probe fails open to alive. A null/undefined pid reads dead. */
|
|
53
38
|
export function isPidAlive(pid) {
|
|
54
39
|
if (pid == null)
|
|
55
40
|
return false;
|
|
@@ -59,7 +44,8 @@ export function isPidAlive(pid) {
|
|
|
59
44
|
catch (e) {
|
|
60
45
|
return e.code === 'EPERM';
|
|
61
46
|
}
|
|
62
|
-
|
|
47
|
+
const state = psProcessState(pid);
|
|
48
|
+
return state !== 'zombie' && state !== 'gone';
|
|
63
49
|
}
|
|
64
50
|
/** Matches the kernel `boot_id` UUID shape (`/proc/sys/kernel/random/boot_id`),
|
|
65
51
|
* used to tell a NEW-format identity base (a per-boot UUID) apart from a
|