@sentropic/h2a-runtime 0.98.4 → 0.98.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.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/llm-mesh-accounts.d.ts +15 -2
- package/dist/llm-mesh-accounts.d.ts.map +1 -1
- package/dist/llm-mesh-accounts.js +13 -3
- package/dist/llm-mesh-accounts.js.map +1 -1
- package/dist/native-terminal/crash-safe-log.d.ts +17 -0
- package/dist/native-terminal/crash-safe-log.d.ts.map +1 -0
- package/dist/native-terminal/crash-safe-log.js +79 -0
- package/dist/native-terminal/crash-safe-log.js.map +1 -0
- package/dist/native-terminal/fault-counters.d.ts +38 -0
- package/dist/native-terminal/fault-counters.d.ts.map +1 -0
- package/dist/native-terminal/fault-counters.js +46 -0
- package/dist/native-terminal/fault-counters.js.map +1 -0
- package/dist/native-terminal/host.d.ts.map +1 -1
- package/dist/native-terminal/host.js +98 -37
- package/dist/native-terminal/host.js.map +1 -1
- package/dist/native-terminal/journal.d.ts +5 -1
- package/dist/native-terminal/journal.d.ts.map +1 -1
- package/dist/native-terminal/journal.js +4 -1
- package/dist/native-terminal/journal.js.map +1 -1
- package/dist/native-terminal/process.d.ts.map +1 -1
- package/dist/native-terminal/process.js +38 -11
- package/dist/native-terminal/process.js.map +1 -1
- package/dist/native-terminal/server.d.ts +31 -0
- package/dist/native-terminal/server.d.ts.map +1 -1
- package/dist/native-terminal/server.js +196 -45
- package/dist/native-terminal/server.js.map +1 -1
- package/dist/native-terminal/socket-path.d.ts +1 -0
- package/dist/native-terminal/socket-path.d.ts.map +1 -1
- package/dist/native-terminal/socket-path.js +3 -3
- package/dist/native-terminal/socket-path.js.map +1 -1
- package/dist/native-terminal/supervisor.d.ts.map +1 -1
- package/dist/native-terminal/supervisor.js +60 -1
- package/dist/native-terminal/supervisor.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { type LlmMeshAdministrativeFacade, type LlmMeshFacade } from "@sentropic
|
|
|
2
2
|
import type { AccountPublic } from "@sentropic/cluster-mesh/llm-mesh/enrollment";
|
|
3
3
|
export interface LlmMeshEnrollmentAccount {
|
|
4
4
|
accountId: string;
|
|
5
|
-
provider: "cloud-code" | "codex" | "muse" | "
|
|
5
|
+
provider: "cloud-code" | "codex" | "muse" | "mistral-vibe";
|
|
6
6
|
label: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
@@ -26,6 +26,14 @@ export interface FacadeEnrollmentOptions {
|
|
|
26
26
|
configRef?: string;
|
|
27
27
|
ownerScope?: string;
|
|
28
28
|
redirectUri?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Select the provider's local CLI-store import instead of the OAuth flow.
|
|
31
|
+
* Owner decision 2026-10-10: OAuth is the default enrollment for every
|
|
32
|
+
* provider; importing credentials from an already-logged-in CLI is an
|
|
33
|
+
* explicit opt-in (`h2a llm-mesh account enroll <provider> --cli`) and only
|
|
34
|
+
* exists for providers that actually keep a local CLI store (muse today).
|
|
35
|
+
*/
|
|
36
|
+
cliImport?: boolean;
|
|
29
37
|
/** Injection seam for CLI tests; production uses the opaque facade. */
|
|
30
38
|
facade?: LlmMeshFacade;
|
|
31
39
|
/** Injection seam that keeps enrollment tests from opening a real browser. */
|
|
@@ -43,8 +51,13 @@ export declare function llmMeshOwnerScopeRef(): string;
|
|
|
43
51
|
* Enroll through the sentropic-owned OAuth state machine. H2A never receives
|
|
44
52
|
* an authorization code or a provider token. Account records remain owned by
|
|
45
53
|
* the facade/keyring and are not copied into h2a config.
|
|
54
|
+
*
|
|
55
|
+
* Provider semantics (owner decision 2026-10-10): "muse" enrolls via the
|
|
56
|
+
* native Meta OAuth device flow by default; passing cliImport selects the
|
|
57
|
+
* Muse CLI-store import instead. "muse-code" is no longer a user entry — it
|
|
58
|
+
* survives only as the mesh-side provider id for the device flow.
|
|
46
59
|
*/
|
|
47
|
-
export declare function enrollViaFacade(provider: "cloud-code" | "codex" | "muse" | "
|
|
60
|
+
export declare function enrollViaFacade(provider: "cloud-code" | "codex" | "muse" | "mistral-vibe", options?: FacadeEnrollmentOptions): Promise<LlmMeshEnrollmentAccount>;
|
|
48
61
|
export declare function listAccountsViaFacade(options?: FacadeAccountOptions): Promise<readonly AccountPublic[]>;
|
|
49
62
|
export declare function removeAccountViaFacade(accountId: string, options?: FacadeAccountOptions): Promise<{
|
|
50
63
|
accountId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-mesh-accounts.d.ts","sourceRoot":"","sources":["../src/llm-mesh-accounts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,2BAA2B,EAAE,KAAK,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACpI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAEjF,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"llm-mesh-accounts.d.ts","sourceRoot":"","sources":["../src/llm-mesh-accounts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,2BAA2B,EAAE,KAAK,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACpI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAEjF,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,cAAc,CAAC;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IAChE,kBAAkB,CAChB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,wBAAwB,CACtB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uEAAuE;IACvE,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,MAAM,CAAC,EAAE,IAAI,CAAC,2BAA2B,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC;CAC9E;AAoBD,wBAAgB,sBAAsB,IAAI,2BAA2B,CAMpE;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAiBD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,cAAc,EAC1D,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,wBAAwB,CAAC,CAqInC;AAED,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAKnC;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,CAK/C;AAaD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,IAAI,EAAE,OAAO,GACZ,MAAM,CAsBR;AAID,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,+BAA+B,GAAG,wBAAwB,GACnE,MAAM,CAGR"}
|
|
@@ -51,21 +51,31 @@ function openEnrollmentBrowser(url) {
|
|
|
51
51
|
* Enroll through the sentropic-owned OAuth state machine. H2A never receives
|
|
52
52
|
* an authorization code or a provider token. Account records remain owned by
|
|
53
53
|
* the facade/keyring and are not copied into h2a config.
|
|
54
|
+
*
|
|
55
|
+
* Provider semantics (owner decision 2026-10-10): "muse" enrolls via the
|
|
56
|
+
* native Meta OAuth device flow by default; passing cliImport selects the
|
|
57
|
+
* Muse CLI-store import instead. "muse-code" is no longer a user entry — it
|
|
58
|
+
* survives only as the mesh-side provider id for the device flow.
|
|
54
59
|
*/
|
|
55
60
|
export async function enrollViaFacade(provider, options = {}) {
|
|
56
61
|
const facade = options.facade ?? createCliLlmMeshFacade();
|
|
57
62
|
const ownerScope = options.ownerScope ?? llmMeshOwnerScopeRef();
|
|
63
|
+
if (options.cliImport && provider !== "muse") {
|
|
64
|
+
throw new Error(`provider "${provider}" has no CLI-store import; --cli is only valid for providers with a local CLI import (muse)`);
|
|
65
|
+
}
|
|
66
|
+
// The facade knows the device flow under its historical mesh-side id.
|
|
67
|
+
const facadeProvider = provider === "muse" && !options.cliImport ? "muse-code" : provider;
|
|
58
68
|
// The installed @sentropic/cluster-mesh/llm-mesh types predate the muse provider, but
|
|
59
69
|
// enroll passes the id through opaquely — a muse-capable facade resolves
|
|
60
70
|
// it, an older one fails with its own unknown-provider error. Cast is
|
|
61
71
|
// load-bearing until the dep bump, not a lie about the contract.
|
|
62
|
-
const session = await facade.enroll(
|
|
72
|
+
const session = await facade.enroll(facadeProvider, {
|
|
63
73
|
configRef: options.configRef ?? process.env.H2A_LLM_MESH_CONFIG_REF ?? "default",
|
|
64
74
|
mode: "cli",
|
|
65
75
|
redirectUri: options.redirectUri ?? "http://127.0.0.1",
|
|
66
76
|
ownerScope,
|
|
67
77
|
});
|
|
68
|
-
if (provider === "muse") {
|
|
78
|
+
if (provider === "muse" && options.cliImport) {
|
|
69
79
|
// Muse CLI-store import (BR75): no browser or device round-trip — the
|
|
70
80
|
// owner act was the muse login itself. The ownerScope binds the enrolling
|
|
71
81
|
// owner explicitly (never inferred); it doubles as the completion code
|
|
@@ -85,7 +95,7 @@ export async function enrollViaFacade(provider, options = {}) {
|
|
|
85
95
|
const completed = await completeMuseImport.call(facade, museSession.enrollmentId, ownerScope, ownerScope);
|
|
86
96
|
return { accountId: completed.accountId, provider, label: completed.label };
|
|
87
97
|
}
|
|
88
|
-
if (provider === "muse
|
|
98
|
+
if (provider === "muse") {
|
|
89
99
|
// Native Meta device flow (RFC 8628, MuseCodeEnrollmentProvider
|
|
90
100
|
// mesh-side): print the user code + verification URL, then complete via
|
|
91
101
|
// the muse-specific device import — the muse-code key mint is its own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-mesh-accounts.js","sourceRoot":"","sources":["../src/llm-mesh-accounts.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAwD,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"llm-mesh-accounts.js","sourceRoot":"","sources":["../src/llm-mesh-accounts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append one host log line, tolerating a stderr that throws or has died.
|
|
3
|
+
* Returns whether the line was delivered to a live stderr stream: a false
|
|
4
|
+
* return means the line only reached the bounded post-mortem buffer, and the
|
|
5
|
+
* CALLER (each contained site owns its named counter) reports that for
|
|
6
|
+
* supervision.
|
|
7
|
+
*/
|
|
8
|
+
export declare function writeHostLogLine(line: string): boolean;
|
|
9
|
+
/** Test-only: restore the sink to its initial, healthy state. */
|
|
10
|
+
export declare function resetHostLogSinkForTests(): void;
|
|
11
|
+
/** Test and debugger view of the sink: stderr status and buffered lines. */
|
|
12
|
+
export declare function hostLogSinkDiagnostics(): Readonly<{
|
|
13
|
+
stderrUsable: boolean;
|
|
14
|
+
bufferedLines: ReadonlyArray<string>;
|
|
15
|
+
faultCounters: Readonly<Record<string, number>>;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=crash-safe-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-safe-log.d.ts","sourceRoot":"","sources":["../../src/native-terminal/crash-safe-log.ts"],"names":[],"mappings":"AAgDA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAetD;AAED,iEAAiE;AACjE,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,IAAI,QAAQ,CAAC;IACjD,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD,CAAC,CAED"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash-safe host log sink: the one channel the native terminal host may use
|
|
3
|
+
* to reach an operator.
|
|
4
|
+
*
|
|
5
|
+
* A bare `process.stderr.write` is fatal to the host. The supervisor spawns
|
|
6
|
+
* the host with stderr as a pipe it never reads and unrefs (`stdio: ["ignore",
|
|
7
|
+
* "ignore", "pipe"]`), so when the supervisor process dies the pipe's read end
|
|
8
|
+
* closes and the host's NEXT log line — typically the deferred durable-row
|
|
9
|
+
* prune of `#schedulePruneOfExitedSession` — fails. Node reports that failure
|
|
10
|
+
* ASYNCHRONOUSLY, as an `error` event on the stderr stream: `write()` sits
|
|
11
|
+
* inside a try/catch and returns, then EPIPE surfaces on the host's event
|
|
12
|
+
* loop where no listener exists, and the unhandled `error` event throws
|
|
13
|
+
* `uncaughtException` (exit 1, supervisor restart: the 2026-10-10/11
|
|
14
|
+
* crash-loop, host.js:590:36 via 1425:26 and 1454:62). The mechanism is
|
|
15
|
+
* reproduced; attribution to that incident remains probable because its
|
|
16
|
+
* journal redacts the error code.
|
|
17
|
+
*
|
|
18
|
+
* Rules this sink enforces:
|
|
19
|
+
* - a durable `error` listener on `process.stderr` turns asynchronous stream
|
|
20
|
+
* failures (EPIPE, ...) into observations instead of uncaught exceptions;
|
|
21
|
+
* - a synchronous write throw OR the first async `error` marks stderr
|
|
22
|
+
* unusable forever: no line is ever written to that stream again;
|
|
23
|
+
* - the logger's own failure is never reported into the failing stream;
|
|
24
|
+
* - lines emitted while stderr is unusable are kept in a bounded most-recent
|
|
25
|
+
* buffer (diagnostic for an attached debugger), never unbounded memory.
|
|
26
|
+
*/
|
|
27
|
+
import { HOST_FAULT_COUNTERS, hostFaultCounters, recordHostFault } from "./fault-counters.js";
|
|
28
|
+
const HOST_LOG_PREFIX = "[h2a-pty-host]";
|
|
29
|
+
const MAX_BUFFERED_HOST_LOG_LINES = 256;
|
|
30
|
+
let stderrUsable = true;
|
|
31
|
+
const bufferedLines = [];
|
|
32
|
+
function markStderrUnusable() {
|
|
33
|
+
stderrUsable = false;
|
|
34
|
+
}
|
|
35
|
+
// Attached at module load, for the process lifetime: from the moment this
|
|
36
|
+
// sink is imported, an `error` arriving on process.stderr — including
|
|
37
|
+
// between two log lines — never finds the stream unhandled. Each observed
|
|
38
|
+
// death of the stream counts ONCE, on the transition.
|
|
39
|
+
process.stderr.on("error", () => {
|
|
40
|
+
if (!stderrUsable)
|
|
41
|
+
return;
|
|
42
|
+
recordHostFault(HOST_FAULT_COUNTERS.hostLogStderrStreamError);
|
|
43
|
+
markStderrUnusable();
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Append one host log line, tolerating a stderr that throws or has died.
|
|
47
|
+
* Returns whether the line was delivered to a live stderr stream: a false
|
|
48
|
+
* return means the line only reached the bounded post-mortem buffer, and the
|
|
49
|
+
* CALLER (each contained site owns its named counter) reports that for
|
|
50
|
+
* supervision.
|
|
51
|
+
*/
|
|
52
|
+
export function writeHostLogLine(line) {
|
|
53
|
+
const text = `${HOST_LOG_PREFIX} ${line}\n`;
|
|
54
|
+
if (stderrUsable) {
|
|
55
|
+
try {
|
|
56
|
+
process.stderr.write(text);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Synchronous write failure: stop touching the stream.
|
|
61
|
+
recordHostFault(HOST_FAULT_COUNTERS.hostLogStderrSyncWriteFailed);
|
|
62
|
+
markStderrUnusable();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (bufferedLines.length >= MAX_BUFFERED_HOST_LOG_LINES)
|
|
66
|
+
bufferedLines.shift();
|
|
67
|
+
bufferedLines.push(text);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
/** Test-only: restore the sink to its initial, healthy state. */
|
|
71
|
+
export function resetHostLogSinkForTests() {
|
|
72
|
+
stderrUsable = true;
|
|
73
|
+
bufferedLines.length = 0;
|
|
74
|
+
}
|
|
75
|
+
/** Test and debugger view of the sink: stderr status and buffered lines. */
|
|
76
|
+
export function hostLogSinkDiagnostics() {
|
|
77
|
+
return { stderrUsable, bufferedLines: [...bufferedLines], faultCounters: hostFaultCounters() };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=crash-safe-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-safe-log.js","sourceRoot":"","sources":["../../src/native-terminal/crash-safe-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE9F,MAAM,eAAe,GAAG,gBAAgB,CAAC;AACzC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAExC,IAAI,YAAY,GAAG,IAAI,CAAC;AACxB,MAAM,aAAa,GAAa,EAAE,CAAC;AAEnC,SAAS,kBAAkB;IACzB,YAAY,GAAG,KAAK,CAAC;AACvB,CAAC;AAED,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAC1E,sDAAsD;AACtD,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;IAC9B,IAAI,CAAC,YAAY;QAAE,OAAO;IAC1B,eAAe,CAAC,mBAAmB,CAAC,wBAAwB,CAAC,CAAC;IAC9D,kBAAkB,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAG,GAAG,eAAe,IAAI,IAAI,IAAI,CAAC;IAC5C,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;YACvD,eAAe,CAAC,mBAAmB,CAAC,4BAA4B,CAAC,CAAC;YAClE,kBAAkB,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,IAAI,2BAA2B;QAAE,aAAa,CAAC,KAAK,EAAE,CAAC;IAC/E,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,wBAAwB;IACtC,YAAY,GAAG,IAAI,CAAC;IACpB,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3B,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,sBAAsB;IAKpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,aAAa,EAAE,iBAAiB,EAAE,EAAE,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named fault counters for supervision. Every fault-tolerant site in the
|
|
3
|
+
* native terminal host bumps its own named counter so an operator can see
|
|
4
|
+
* WHAT is being absorbed and how often — fault containment must never be
|
|
5
|
+
* silent. The contained sites are:
|
|
6
|
+
*
|
|
7
|
+
* - the host log sink (`crash-safe-log.ts`): stderr write failures;
|
|
8
|
+
* - the pty `onData` guard (`host.ts`);
|
|
9
|
+
* - the pty `onExit` guard (`host.ts`);
|
|
10
|
+
* - the pty DSR reply write (`host.ts`);
|
|
11
|
+
* - socket connection errors and client frame destroys (`server.ts`);
|
|
12
|
+
* - the net.Server listener handler (`server.ts`), per classification;
|
|
13
|
+
* - bounded respawn abandonment (`supervisor.ts`);
|
|
14
|
+
* - the process-level diagnostic writes (`process.ts`).
|
|
15
|
+
*
|
|
16
|
+
* Counters are per-process; supervision reads them through
|
|
17
|
+
* `hostFaultCounters()` (tests, an attached debugger, a future ping op).
|
|
18
|
+
*/
|
|
19
|
+
export declare const HOST_FAULT_COUNTERS: {
|
|
20
|
+
readonly hostSocketConnectionErrors: "h2a_host_socket_conn_errors";
|
|
21
|
+
readonly hostClientFrameDestroys: "h2a_host_client_frame_destroys";
|
|
22
|
+
readonly hostPtyWriteBreaks: "h2a_host_pty_write_breaks";
|
|
23
|
+
readonly hostPtyCallbackFailures: "h2a_host_pty_callback_failures";
|
|
24
|
+
readonly hostLogStderrSyncWriteFailed: "host-log.stderr-sync-write-failed";
|
|
25
|
+
readonly hostLogStderrStreamError: "host-log.stderr-stream-error";
|
|
26
|
+
readonly ptyDataCallbackContained: "pty.data-callback-contained";
|
|
27
|
+
readonly ptyExitCallbackContained: "pty.exit-callback-contained";
|
|
28
|
+
readonly serverListenerErrorRecoverable: "server.listener-error-recoverable";
|
|
29
|
+
readonly serverListenerErrorExhausted: "server.listener-error-exhausted";
|
|
30
|
+
readonly serverListenerErrorUnusable: "server.listener-error-unusable";
|
|
31
|
+
readonly serverListenerErrorUnknown: "server.listener-error-unknown";
|
|
32
|
+
readonly supervisorRespawnAbandoned: "supervisor.respawn-abandoned";
|
|
33
|
+
readonly processShutdownWriteFailed: "process.shutdown-write-failed";
|
|
34
|
+
readonly processFatalWriteFailed: "process.fatal-write-failed";
|
|
35
|
+
};
|
|
36
|
+
export declare function recordHostFault(counter: string): void;
|
|
37
|
+
export declare function hostFaultCounters(): Readonly<Record<string, number>>;
|
|
38
|
+
//# sourceMappingURL=fault-counters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fault-counters.d.ts","sourceRoot":"","sources":["../../src/native-terminal/fault-counters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;CAmBtB,CAAC;AAIX,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAErD;AAED,wBAAgB,iBAAiB,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEpE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named fault counters for supervision. Every fault-tolerant site in the
|
|
3
|
+
* native terminal host bumps its own named counter so an operator can see
|
|
4
|
+
* WHAT is being absorbed and how often — fault containment must never be
|
|
5
|
+
* silent. The contained sites are:
|
|
6
|
+
*
|
|
7
|
+
* - the host log sink (`crash-safe-log.ts`): stderr write failures;
|
|
8
|
+
* - the pty `onData` guard (`host.ts`);
|
|
9
|
+
* - the pty `onExit` guard (`host.ts`);
|
|
10
|
+
* - the pty DSR reply write (`host.ts`);
|
|
11
|
+
* - socket connection errors and client frame destroys (`server.ts`);
|
|
12
|
+
* - the net.Server listener handler (`server.ts`), per classification;
|
|
13
|
+
* - bounded respawn abandonment (`supervisor.ts`);
|
|
14
|
+
* - the process-level diagnostic writes (`process.ts`).
|
|
15
|
+
*
|
|
16
|
+
* Counters are per-process; supervision reads them through
|
|
17
|
+
* `hostFaultCounters()` (tests, an attached debugger, a future ping op).
|
|
18
|
+
*/
|
|
19
|
+
export const HOST_FAULT_COUNTERS = {
|
|
20
|
+
// The four contractual R7.5 supervision counters (h2a_host_*), one per
|
|
21
|
+
// NAMED fault site of the spec.
|
|
22
|
+
hostSocketConnectionErrors: "h2a_host_socket_conn_errors",
|
|
23
|
+
hostClientFrameDestroys: "h2a_host_client_frame_destroys",
|
|
24
|
+
hostPtyWriteBreaks: "h2a_host_pty_write_breaks",
|
|
25
|
+
hostPtyCallbackFailures: "h2a_host_pty_callback_failures",
|
|
26
|
+
// Per-site distinct counters kept for finer supervision.
|
|
27
|
+
hostLogStderrSyncWriteFailed: "host-log.stderr-sync-write-failed",
|
|
28
|
+
hostLogStderrStreamError: "host-log.stderr-stream-error",
|
|
29
|
+
ptyDataCallbackContained: "pty.data-callback-contained",
|
|
30
|
+
ptyExitCallbackContained: "pty.exit-callback-contained",
|
|
31
|
+
serverListenerErrorRecoverable: "server.listener-error-recoverable",
|
|
32
|
+
serverListenerErrorExhausted: "server.listener-error-exhausted",
|
|
33
|
+
serverListenerErrorUnusable: "server.listener-error-unusable",
|
|
34
|
+
serverListenerErrorUnknown: "server.listener-error-unknown",
|
|
35
|
+
supervisorRespawnAbandoned: "supervisor.respawn-abandoned",
|
|
36
|
+
processShutdownWriteFailed: "process.shutdown-write-failed",
|
|
37
|
+
processFatalWriteFailed: "process.fatal-write-failed",
|
|
38
|
+
};
|
|
39
|
+
const counts = new Map();
|
|
40
|
+
export function recordHostFault(counter) {
|
|
41
|
+
counts.set(counter, (counts.get(counter) ?? 0) + 1);
|
|
42
|
+
}
|
|
43
|
+
export function hostFaultCounters() {
|
|
44
|
+
return Object.fromEntries(counts);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=fault-counters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fault-counters.js","sourceRoot":"","sources":["../../src/native-terminal/fault-counters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,uEAAuE;IACvE,gCAAgC;IAChC,0BAA0B,EAAE,6BAA6B;IACzD,uBAAuB,EAAE,gCAAgC;IACzD,kBAAkB,EAAE,2BAA2B;IAC/C,uBAAuB,EAAE,gCAAgC;IACzD,yDAAyD;IACzD,4BAA4B,EAAE,mCAAmC;IACjE,wBAAwB,EAAE,8BAA8B;IACxD,wBAAwB,EAAE,6BAA6B;IACvD,wBAAwB,EAAE,6BAA6B;IACvD,8BAA8B,EAAE,mCAAmC;IACnE,4BAA4B,EAAE,iCAAiC;IAC/D,2BAA2B,EAAE,gCAAgC;IAC7D,0BAA0B,EAAE,+BAA+B;IAC3D,0BAA0B,EAAE,8BAA8B;IAC1D,0BAA0B,EAAE,+BAA+B;IAC3D,uBAAuB,EAAE,4BAA4B;CAC7C,CAAC;AAEX,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEzC,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/native-terminal/host.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/native-terminal/host.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { readFileSync, readdirSync } from "node:fs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
+
import { writeHostLogLine } from "./crash-safe-log.js";
|
|
5
|
+
import { HOST_FAULT_COUNTERS, recordHostFault } from "./fault-counters.js";
|
|
4
6
|
// Durable session identity (incl. pgid) lives in the single registry store by
|
|
5
7
|
// design — one local store per the owner's durable-state direction (see the
|
|
6
8
|
// longer rationale on `persistNativeTerminalPgid`/`readNativeTerminalPgid` in
|
|
@@ -587,7 +589,10 @@ export class NativeTerminalHost {
|
|
|
587
589
|
this.#log =
|
|
588
590
|
options.log ??
|
|
589
591
|
((line) => {
|
|
590
|
-
process.stderr.write
|
|
592
|
+
// The default sink must be crash-safe: a plain `process.stderr.write`
|
|
593
|
+
// here reproduces the suspected mechanism of the 2026-10-10/11
|
|
594
|
+
// crash-loop (async EPIPE, unhandled `error`, uncaughtException).
|
|
595
|
+
writeHostLogLine(line);
|
|
591
596
|
});
|
|
592
597
|
this.#forceKillTimeoutMs =
|
|
593
598
|
options.forceKillTimeoutMs ?? NATIVE_TERMINAL_FORCE_KILL_TIMEOUT_MS;
|
|
@@ -728,48 +733,88 @@ export class NativeTerminalHost {
|
|
|
728
733
|
let dsrTail = "";
|
|
729
734
|
const resetRelay = new TerminalResetRelay((data) => { record.replay.append(data); }, () => record.replay.resetSequence());
|
|
730
735
|
record.dataSubscription = record.pty.onData((data) => {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
736
|
+
try {
|
|
737
|
+
if (record.exit !== null || data.length === 0)
|
|
738
|
+
return;
|
|
739
|
+
resetRelay.feed(data);
|
|
740
|
+
// Answer Device Status Report cursor queries (ESC[6n) like a real
|
|
741
|
+
// terminal/tmux: TUIs that require a cursor-position report (muse
|
|
742
|
+
// aborts with "cursor position could not be read" without it).
|
|
743
|
+
const window = dsrTail + data;
|
|
744
|
+
dsrTail = window.slice(-3);
|
|
745
|
+
const queries = window.split("\x1b[6n").length - 1;
|
|
746
|
+
for (let i = 0; i < queries; i++) {
|
|
747
|
+
try {
|
|
748
|
+
record.pty.write("\x1b[1;1R");
|
|
749
|
+
}
|
|
750
|
+
catch {
|
|
751
|
+
// R7.5 named exemption: expected transport failure, potentially
|
|
752
|
+
// high volume. Count it instead of logging every failed reply.
|
|
753
|
+
recordHostFault(HOST_FAULT_COUNTERS.hostPtyWriteBreaks);
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
catch (error) {
|
|
759
|
+
// node-pty delivers this callback on the event loop shared with every
|
|
760
|
+
// other session; a faulty one must cost at most this session's output
|
|
761
|
+
// relay, never the host. Dispose the subscription so the faulty
|
|
762
|
+
// callback stops firing on every chunk.
|
|
763
|
+
recordHostFault(HOST_FAULT_COUNTERS.ptyDataCallbackContained);
|
|
764
|
+
record.dataSubscription?.dispose();
|
|
765
|
+
this.#reportSessionCallbackFailure("data", record, error);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
record.exitSubscription = record.pty.onExit((event) => {
|
|
769
|
+
try {
|
|
770
|
+
if (record.exit !== null)
|
|
771
|
+
return;
|
|
772
|
+
resetRelay.flush();
|
|
773
|
+
// A durable row exists to make this session reapable after THIS host
|
|
774
|
+
// dies. Once the group is confirmed empty the row can no longer make
|
|
775
|
+
// anything reapable — it is a stale record that a later host death would
|
|
776
|
+
// re-examine against whatever holds that pgid NUMBER by then. Drop it
|
|
777
|
+
// on POSITIVE proof only (see `#pruneDurableRowIfGroupEmpty`), and OFF
|
|
778
|
+
// this callback: this is node-pty's own synchronous exit callback on the
|
|
779
|
+
// host's event loop (see `#schedulePruneOfExitedSession`).
|
|
780
|
+
this.#schedulePruneOfExitedSession(record, "its pty exited");
|
|
781
|
+
const exit = {
|
|
782
|
+
exitCode: event.exitCode,
|
|
783
|
+
};
|
|
784
|
+
if (event.signal !== undefined)
|
|
785
|
+
exit.signal = event.signal;
|
|
786
|
+
record.exit = Object.freeze(exit);
|
|
787
|
+
record.status = "exited";
|
|
788
|
+
this.#invalidateController(record);
|
|
789
|
+
record.dataSubscription?.dispose();
|
|
790
|
+
record.exitSubscription?.dispose();
|
|
791
|
+
}
|
|
792
|
+
catch (error) {
|
|
793
|
+
// Same shared event loop as the data callback; a faulty exit callback
|
|
794
|
+
// must not take the host down. Settle the record from the parts of
|
|
795
|
+
// the event that remain readable so the session cannot linger as
|
|
796
|
+
// "running" with a dead pty, then dispose both subscriptions.
|
|
797
|
+
const exit = { exitCode: -1 };
|
|
741
798
|
try {
|
|
742
|
-
|
|
799
|
+
exit.exitCode = event.exitCode;
|
|
800
|
+
if (event.signal !== undefined)
|
|
801
|
+
exit.signal = event.signal;
|
|
743
802
|
}
|
|
744
803
|
catch {
|
|
745
|
-
//
|
|
746
|
-
|
|
804
|
+
// The event's own fields are unreadable; -1 records that the exit
|
|
805
|
+
// was observed but its code was not.
|
|
806
|
+
}
|
|
807
|
+
if (record.exit === null) {
|
|
808
|
+
record.exit = Object.freeze(exit);
|
|
809
|
+
record.status = "exited";
|
|
810
|
+
this.#invalidateController(record);
|
|
747
811
|
}
|
|
812
|
+
record.dataSubscription?.dispose();
|
|
813
|
+
record.exitSubscription?.dispose();
|
|
814
|
+
recordHostFault(HOST_FAULT_COUNTERS.ptyExitCallbackContained);
|
|
815
|
+
this.#reportSessionCallbackFailure("exit", record, error);
|
|
748
816
|
}
|
|
749
817
|
});
|
|
750
|
-
record.exitSubscription = record.pty.onExit((event) => {
|
|
751
|
-
if (record.exit !== null)
|
|
752
|
-
return;
|
|
753
|
-
resetRelay.flush();
|
|
754
|
-
// A durable row exists to make this session reapable after THIS host
|
|
755
|
-
// dies. Once the group is confirmed empty the row can no longer make
|
|
756
|
-
// anything reapable — it is a stale record that a later host death would
|
|
757
|
-
// re-examine against whatever holds that pgid NUMBER by then. Drop it
|
|
758
|
-
// on POSITIVE proof only (see `#pruneDurableRowIfGroupEmpty`), and OFF
|
|
759
|
-
// this callback: this is node-pty's own synchronous exit callback on the
|
|
760
|
-
// host's event loop (see `#schedulePruneOfExitedSession`).
|
|
761
|
-
this.#schedulePruneOfExitedSession(record, "its pty exited");
|
|
762
|
-
const exit = {
|
|
763
|
-
exitCode: event.exitCode,
|
|
764
|
-
};
|
|
765
|
-
if (event.signal !== undefined)
|
|
766
|
-
exit.signal = event.signal;
|
|
767
|
-
record.exit = Object.freeze(exit);
|
|
768
|
-
record.status = "exited";
|
|
769
|
-
this.#invalidateController(record);
|
|
770
|
-
record.dataSubscription?.dispose();
|
|
771
|
-
record.exitSubscription?.dispose();
|
|
772
|
-
});
|
|
773
818
|
return this.#snapshot(record);
|
|
774
819
|
}
|
|
775
820
|
list() {
|
|
@@ -1520,6 +1565,22 @@ export class NativeTerminalHost {
|
|
|
1520
1565
|
record.controllerActivity = null;
|
|
1521
1566
|
record.controllerEpoch += 1;
|
|
1522
1567
|
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Report a contained pty-callback failure WITHOUT being able to throw: the
|
|
1570
|
+
* caller is the catch block that keeps the host alive, and a failing log
|
|
1571
|
+
* sink must not re-arm the very crash the guard just contained. The default
|
|
1572
|
+
* sink is itself crash-safe (`crash-safe-log.ts`); an injected sink that
|
|
1573
|
+
* throws is swallowed here for the same reason.
|
|
1574
|
+
*/
|
|
1575
|
+
#reportSessionCallbackFailure(kind, record, error) {
|
|
1576
|
+
recordHostFault(HOST_FAULT_COUNTERS.hostPtyCallbackFailures);
|
|
1577
|
+
try {
|
|
1578
|
+
this.#log(`contained a faulty pty ${kind} callback for terminal session ${record.id} (pgid=${record.pty.pgid}): ${String(error)}`);
|
|
1579
|
+
}
|
|
1580
|
+
catch {
|
|
1581
|
+
// The log sink itself is failing; containment is the priority.
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1523
1584
|
#snapshot(record) {
|
|
1524
1585
|
return Object.freeze({
|
|
1525
1586
|
id: record.id,
|