@schoolai/shipyard 3.5.0-rc.20260504.0 → 3.5.0
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/{auth-LS3NBD42.js → auth-SS7LV5XK.js} +4 -3
- package/dist/{chunk-GLH3V7NG.js → chunk-2J3WSIAF.js} +5 -3
- package/dist/{chunk-GLH3V7NG.js.map → chunk-2J3WSIAF.js.map} +1 -1
- package/dist/{chunk-YUG27SAR.js → chunk-2UN5AR7V.js} +2 -2
- package/dist/{chunk-ODCN6W33.js → chunk-3CAEALVL.js} +7 -5
- package/dist/{chunk-ODCN6W33.js.map → chunk-3CAEALVL.js.map} +1 -1
- package/dist/chunk-3MNPDCO5.js +1011 -0
- package/dist/chunk-3MNPDCO5.js.map +1 -0
- package/dist/{chunk-JQ7HCEFS.js → chunk-BNEE7ZPW.js} +8 -6
- package/dist/{chunk-JQ7HCEFS.js.map → chunk-BNEE7ZPW.js.map} +1 -1
- package/dist/{chunk-5LIPEC7P.js → chunk-GIFN3IPT.js} +4 -4
- package/dist/{chunk-3TB4VNFG.js → chunk-IISLTKYY.js} +2 -2
- package/dist/chunk-PI77CUEP.js +49 -0
- package/dist/chunk-PI77CUEP.js.map +1 -0
- package/dist/chunk-SNYEQHUK.js +64 -0
- package/dist/chunk-SNYEQHUK.js.map +1 -0
- package/dist/{chunk-XXTIKBCU.js → chunk-VBPHGPBR.js} +2 -2
- package/dist/{chunk-M5M6VC5F.js → chunk-VPMN47TL.js} +31 -72
- package/dist/chunk-VPMN47TL.js.map +1 -0
- package/dist/{git-repo-CNIKBYPB.js → git-repo-364VANDM.js} +5 -4
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/{logger-7XW3I4XN.js → logger-GQCSLSZH.js} +4 -3
- package/dist/{login-RHZDNC74.js → login-D6USDG5M.js} +7 -6
- package/dist/{logout-CUAAF5IK.js → logout-VUNCW5B2.js} +6 -5
- package/dist/{logout-CUAAF5IK.js.map → logout-VUNCW5B2.js.map} +1 -1
- package/dist/mcp-servers-FZV2P2ZO.js +16 -0
- package/dist/{roi-LN7MMRH7.js → roi-Y3MX5UW4.js} +4 -3
- package/dist/{roi-LN7MMRH7.js.map → roi-Y3MX5UW4.js.map} +1 -1
- package/dist/{serve-E7CHPJD4.js → serve-IVUGCBEE.js} +73 -462
- package/dist/{serve-E7CHPJD4.js.map → serve-IVUGCBEE.js.map} +1 -1
- package/dist/services/watcher-worker/worker.d.ts +49 -0
- package/dist/services/watcher-worker/worker.js +157 -0
- package/dist/services/watcher-worker/worker.js.map +1 -0
- package/dist/{skills-OMDIMU7D.js → skills-GPGRNV4R.js} +2 -2
- package/dist/start-I7ZONWK7.js +285 -0
- package/dist/start-I7ZONWK7.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-M5M6VC5F.js.map +0 -1
- package/dist/mcp-servers-3SHS2PEJ.js +0 -15
- package/dist/start-HQ42GOYF.js +0 -36
- package/dist/start-HQ42GOYF.js.map +0 -1
- /package/dist/{auth-LS3NBD42.js.map → auth-SS7LV5XK.js.map} +0 -0
- /package/dist/{chunk-YUG27SAR.js.map → chunk-2UN5AR7V.js.map} +0 -0
- /package/dist/{chunk-5LIPEC7P.js.map → chunk-GIFN3IPT.js.map} +0 -0
- /package/dist/{chunk-3TB4VNFG.js.map → chunk-IISLTKYY.js.map} +0 -0
- /package/dist/{chunk-XXTIKBCU.js.map → chunk-VBPHGPBR.js.map} +0 -0
- /package/dist/{git-repo-CNIKBYPB.js.map → git-repo-364VANDM.js.map} +0 -0
- /package/dist/{logger-7XW3I4XN.js.map → logger-GQCSLSZH.js.map} +0 -0
- /package/dist/{login-RHZDNC74.js.map → login-D6USDG5M.js.map} +0 -0
- /package/dist/{mcp-servers-3SHS2PEJ.js.map → mcp-servers-FZV2P2ZO.js.map} +0 -0
- /package/dist/{skills-OMDIMU7D.js.map → skills-GPGRNV4R.js.map} +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* IPC protocol between the daemon (parent) and the watcher worker subprocess.
|
|
5
|
+
*
|
|
6
|
+
* Wire format: line-delimited JSON over the worker's stdio. Each line is
|
|
7
|
+
* exactly one Command (parent → worker) or one Reply (worker → parent), with
|
|
8
|
+
* no embedded literal newlines — JSON encoding escapes newlines inside string
|
|
9
|
+
* values (e.g. a path containing `\n`) so the line protocol stays intact.
|
|
10
|
+
*
|
|
11
|
+
* Stdout is the IPC channel; structured worker logs go to stderr only.
|
|
12
|
+
*/
|
|
13
|
+
declare const SubscribeOptionsSchema: z.ZodObject<{
|
|
14
|
+
ignore: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
|
+
backend: z.ZodOptional<z.ZodEnum<{
|
|
16
|
+
default: "default";
|
|
17
|
+
"brute-force": "brute-force";
|
|
18
|
+
watchman: "watchman";
|
|
19
|
+
}>>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
type WorkerSubscribeOptions = z.infer<typeof SubscribeOptionsSchema>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Watcher worker entry point — the only place in the daemon that imports
|
|
25
|
+
* `@parcel/watcher` (post-Commit-4). The worker is intentionally minimal:
|
|
26
|
+
* subscribe/unsubscribe/shutdown over stdio, no business logic, no state
|
|
27
|
+
* beyond a Map<id, AsyncSubscription>.
|
|
28
|
+
*
|
|
29
|
+
* Crashes are expected (parcel/watcher SIGABRTs on FSEvents NULL-deref); we
|
|
30
|
+
* keep the blast surface as small as possible so the parent's supervisor
|
|
31
|
+
* can replay the subscription map onto a fresh worker.
|
|
32
|
+
*/
|
|
33
|
+
interface ParcelEventLike {
|
|
34
|
+
type: 'create' | 'update' | 'delete';
|
|
35
|
+
path: string;
|
|
36
|
+
}
|
|
37
|
+
interface ParcelAsyncSubscriptionLike {
|
|
38
|
+
unsubscribe(): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
type WorkerSubscribeFn = (path: string, fn: (err: Error | null, events: ParcelEventLike[]) => unknown, opts?: WorkerSubscribeOptions) => Promise<ParcelAsyncSubscriptionLike>;
|
|
41
|
+
interface RunWorkerDeps {
|
|
42
|
+
subscribe: WorkerSubscribeFn;
|
|
43
|
+
stdin: NodeJS.ReadableStream;
|
|
44
|
+
stdout: NodeJS.WritableStream;
|
|
45
|
+
stderr: NodeJS.WritableStream;
|
|
46
|
+
}
|
|
47
|
+
declare function runWorker(deps: RunWorkerDeps): Promise<void>;
|
|
48
|
+
|
|
49
|
+
export { type RunWorkerDeps, type WorkerSubscribeFn, runWorker };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
assertNever,
|
|
4
|
+
decodeLine,
|
|
5
|
+
encodeLine
|
|
6
|
+
} from "../../chunk-SNYEQHUK.js";
|
|
7
|
+
import "../../chunk-VPMN47TL.js";
|
|
8
|
+
import "../../chunk-2H7UOFLK.js";
|
|
9
|
+
|
|
10
|
+
// src/services/watcher-worker/worker.ts
|
|
11
|
+
async function runWorker(deps) {
|
|
12
|
+
const subs = /* @__PURE__ */ new Map();
|
|
13
|
+
let shuttingDown = false;
|
|
14
|
+
let resolveDone;
|
|
15
|
+
const done = new Promise((resolve) => {
|
|
16
|
+
resolveDone = resolve;
|
|
17
|
+
});
|
|
18
|
+
function logStderr(level, event, extra) {
|
|
19
|
+
const payload = extra ? { level, event, ...extra } : { level, event };
|
|
20
|
+
deps.stderr.write(`${JSON.stringify(payload)}
|
|
21
|
+
`);
|
|
22
|
+
}
|
|
23
|
+
function writeReply(reply) {
|
|
24
|
+
deps.stdout.write(`${encodeLine(reply)}
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
function toWireEvents(events) {
|
|
28
|
+
return events.map((e) => ({ type: e.type, path: e.path }));
|
|
29
|
+
}
|
|
30
|
+
async function handleSubscribe(id, path, opts) {
|
|
31
|
+
const callback = (err, events) => {
|
|
32
|
+
if (err !== null) {
|
|
33
|
+
logStderr("warn", "watcher_callback_error", {
|
|
34
|
+
id,
|
|
35
|
+
path,
|
|
36
|
+
err: err.message
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!subs.has(id)) return;
|
|
41
|
+
writeReply({ type: "events", id, events: toWireEvents(events) });
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const handle = await deps.subscribe(path, callback, opts);
|
|
45
|
+
if (shuttingDown) {
|
|
46
|
+
await handle.unsubscribe().catch(() => {
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
subs.set(id, { handle });
|
|
51
|
+
writeReply({ type: "subscribed", id });
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
+
writeReply({ type: "subscribe_failed", id, error: message });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function handleUnsubscribe(id) {
|
|
58
|
+
const entry = subs.get(id);
|
|
59
|
+
subs.delete(id);
|
|
60
|
+
if (entry) {
|
|
61
|
+
try {
|
|
62
|
+
await entry.handle.unsubscribe();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
logStderr("warn", "watcher_unsubscribe_failed", {
|
|
65
|
+
id,
|
|
66
|
+
err: err instanceof Error ? err.message : String(err)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
writeReply({ type: "unsubscribed", id });
|
|
71
|
+
}
|
|
72
|
+
async function handleShutdown() {
|
|
73
|
+
if (shuttingDown) return;
|
|
74
|
+
shuttingDown = true;
|
|
75
|
+
const entries = Array.from(subs.values());
|
|
76
|
+
subs.clear();
|
|
77
|
+
await Promise.all(
|
|
78
|
+
entries.map(async (entry) => {
|
|
79
|
+
try {
|
|
80
|
+
await entry.handle.unsubscribe();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
logStderr("warn", "watcher_unsubscribe_failed_on_shutdown", {
|
|
83
|
+
err: err instanceof Error ? err.message : String(err)
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
resolveDone();
|
|
89
|
+
}
|
|
90
|
+
function dispatch(cmd) {
|
|
91
|
+
switch (cmd.cmd) {
|
|
92
|
+
case "subscribe":
|
|
93
|
+
void handleSubscribe(cmd.id, cmd.path, cmd.opts);
|
|
94
|
+
return;
|
|
95
|
+
case "unsubscribe":
|
|
96
|
+
void handleUnsubscribe(cmd.id);
|
|
97
|
+
return;
|
|
98
|
+
case "shutdown":
|
|
99
|
+
void handleShutdown();
|
|
100
|
+
return;
|
|
101
|
+
default:
|
|
102
|
+
assertNever(cmd);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let buffer = "";
|
|
106
|
+
deps.stdin.on("data", (chunk) => {
|
|
107
|
+
buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
108
|
+
let nl = buffer.indexOf("\n");
|
|
109
|
+
while (nl !== -1) {
|
|
110
|
+
const line = buffer.slice(0, nl);
|
|
111
|
+
buffer = buffer.slice(nl + 1);
|
|
112
|
+
nl = buffer.indexOf("\n");
|
|
113
|
+
if (line.length === 0) continue;
|
|
114
|
+
const decoded = decodeLine(line);
|
|
115
|
+
if (decoded === null) {
|
|
116
|
+
logStderr("warn", "worker_decode_failed", { line });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if ("type" in decoded) {
|
|
120
|
+
logStderr("warn", "worker_received_unexpected_reply", { type: decoded.type });
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
dispatch(decoded);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
deps.stdin.on("end", () => {
|
|
127
|
+
void handleShutdown();
|
|
128
|
+
});
|
|
129
|
+
deps.stdin.on("close", () => {
|
|
130
|
+
void handleShutdown();
|
|
131
|
+
});
|
|
132
|
+
return done;
|
|
133
|
+
}
|
|
134
|
+
async function main() {
|
|
135
|
+
const parcelWatcher = await import("@parcel/watcher");
|
|
136
|
+
await runWorker({
|
|
137
|
+
subscribe: (path, fn, opts) => parcelWatcher.subscribe(path, fn, toParcelOptions(opts)),
|
|
138
|
+
stdin: process.stdin,
|
|
139
|
+
stdout: process.stdout,
|
|
140
|
+
stderr: process.stderr
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function toParcelOptions(opts) {
|
|
144
|
+
if (!opts) return void 0;
|
|
145
|
+
const out = {};
|
|
146
|
+
if (opts.ignore) out.ignore = opts.ignore;
|
|
147
|
+
if (opts.backend && opts.backend !== "default") out.backend = opts.backend;
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
var entryUrl = process.argv[1] ? `file://${process.argv[1]}` : null;
|
|
151
|
+
if (entryUrl !== null && import.meta.url === entryUrl) {
|
|
152
|
+
void main();
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
runWorker
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/watcher-worker/worker.ts"],"sourcesContent":["import { assertNever } from '../../shared/assert-never.js';\nimport {\n decodeLine,\n encodeLine,\n type WorkerCommand,\n type WorkerParcelEvent,\n type WorkerReply,\n type WorkerSubscribeOptions,\n} from './worker-protocol.js';\n\n/**\n * Watcher worker entry point — the only place in the daemon that imports\n * `@parcel/watcher` (post-Commit-4). The worker is intentionally minimal:\n * subscribe/unsubscribe/shutdown over stdio, no business logic, no state\n * beyond a Map<id, AsyncSubscription>.\n *\n * Crashes are expected (parcel/watcher SIGABRTs on FSEvents NULL-deref); we\n * keep the blast surface as small as possible so the parent's supervisor\n * can replay the subscription map onto a fresh worker.\n */\n\ninterface ParcelEventLike {\n type: 'create' | 'update' | 'delete';\n path: string;\n}\n\ninterface ParcelAsyncSubscriptionLike {\n unsubscribe(): Promise<void>;\n}\n\nexport type WorkerSubscribeFn = (\n path: string,\n fn: (err: Error | null, events: ParcelEventLike[]) => unknown,\n opts?: WorkerSubscribeOptions\n) => Promise<ParcelAsyncSubscriptionLike>;\n\nexport interface RunWorkerDeps {\n subscribe: WorkerSubscribeFn;\n stdin: NodeJS.ReadableStream;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n}\n\ninterface ActiveSubscription {\n handle: ParcelAsyncSubscriptionLike;\n}\n\nexport async function runWorker(deps: RunWorkerDeps): Promise<void> {\n const subs = new Map<string, ActiveSubscription>();\n let shuttingDown = false;\n let resolveDone: () => void;\n const done = new Promise<void>((resolve) => {\n resolveDone = resolve;\n });\n\n function logStderr(\n level: 'info' | 'warn' | 'error',\n event: string,\n extra?: Record<string, unknown>\n ): void {\n const payload = extra ? { level, event, ...extra } : { level, event };\n deps.stderr.write(`${JSON.stringify(payload)}\\n`);\n }\n\n function writeReply(reply: WorkerReply): void {\n deps.stdout.write(`${encodeLine(reply)}\\n`);\n }\n\n /** Coerce a parcel/watcher event into the protocol's strict shape. */\n function toWireEvents(events: ParcelEventLike[]): WorkerParcelEvent[] {\n return events.map((e) => ({ type: e.type, path: e.path }));\n }\n\n async function handleSubscribe(\n id: string,\n path: string,\n opts: WorkerSubscribeOptions\n ): Promise<void> {\n const callback = (err: Error | null, events: ParcelEventLike[]) => {\n if (err !== null) {\n logStderr('warn', 'watcher_callback_error', {\n id,\n path,\n err: err.message,\n });\n return;\n }\n /**\n * Drop events for ids that have been unsubscribed but whose underlying\n * watcher hasn't fully torn down yet.\n */\n if (!subs.has(id)) return;\n writeReply({ type: 'events', id, events: toWireEvents(events) });\n };\n\n try {\n const handle = await deps.subscribe(path, callback, opts);\n /** If the worker began shutdown while subscribe was in flight, undo. */\n if (shuttingDown) {\n await handle.unsubscribe().catch(() => {});\n return;\n }\n subs.set(id, { handle });\n writeReply({ type: 'subscribed', id });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n writeReply({ type: 'subscribe_failed', id, error: message });\n }\n }\n\n async function handleUnsubscribe(id: string): Promise<void> {\n const entry = subs.get(id);\n subs.delete(id);\n if (entry) {\n try {\n await entry.handle.unsubscribe();\n } catch (err) {\n logStderr('warn', 'watcher_unsubscribe_failed', {\n id,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n writeReply({ type: 'unsubscribed', id });\n }\n\n async function handleShutdown(): Promise<void> {\n if (shuttingDown) return;\n shuttingDown = true;\n const entries = Array.from(subs.values());\n subs.clear();\n await Promise.all(\n entries.map(async (entry) => {\n try {\n await entry.handle.unsubscribe();\n } catch (err) {\n logStderr('warn', 'watcher_unsubscribe_failed_on_shutdown', {\n err: err instanceof Error ? err.message : String(err),\n });\n }\n })\n );\n resolveDone();\n }\n\n function dispatch(cmd: WorkerCommand): void {\n switch (cmd.cmd) {\n case 'subscribe':\n void handleSubscribe(cmd.id, cmd.path, cmd.opts);\n return;\n case 'unsubscribe':\n void handleUnsubscribe(cmd.id);\n return;\n case 'shutdown':\n void handleShutdown();\n return;\n default:\n assertNever(cmd);\n }\n }\n\n let buffer = '';\n deps.stdin.on('data', (chunk: Buffer | string) => {\n buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');\n let nl = buffer.indexOf('\\n');\n while (nl !== -1) {\n const line = buffer.slice(0, nl);\n buffer = buffer.slice(nl + 1);\n nl = buffer.indexOf('\\n');\n if (line.length === 0) continue;\n const decoded = decodeLine(line);\n if (decoded === null) {\n logStderr('warn', 'worker_decode_failed', { line });\n continue;\n }\n /** Workers should never see Reply messages; ignore-and-log if they do. */\n if ('type' in decoded) {\n logStderr('warn', 'worker_received_unexpected_reply', { type: decoded.type });\n continue;\n }\n dispatch(decoded);\n }\n });\n\n /** Parent died → unsubscribe everything and exit. */\n deps.stdin.on('end', () => {\n void handleShutdown();\n });\n deps.stdin.on('close', () => {\n void handleShutdown();\n });\n\n return done;\n}\n\n/**\n * Default entry: when this file is run directly via `fork()` from the\n * supervisor, import `@parcel/watcher` and wire it up to runWorker. Tests\n * import `runWorker` directly and skip this branch entirely.\n */\nasync function main(): Promise<void> {\n const parcelWatcher = await import('@parcel/watcher');\n await runWorker({\n subscribe: (path, fn, opts) => parcelWatcher.subscribe(path, fn, toParcelOptions(opts)),\n stdin: process.stdin,\n stdout: process.stdout,\n stderr: process.stderr,\n });\n}\n\n/**\n * Translate the protocol's options shape to `@parcel/watcher`'s. The protocol\n * accepts `backend: 'default'` to mean \"use the platform default\" — parcel's\n * `BackendType` does not include 'default' and instead expects the field to\n * be omitted entirely.\n */\nfunction toParcelOptions(\n opts: WorkerSubscribeOptions | undefined\n): { ignore?: string[]; backend?: 'brute-force' | 'watchman' } | undefined {\n if (!opts) return undefined;\n const out: { ignore?: string[]; backend?: 'brute-force' | 'watchman' } = {};\n if (opts.ignore) out.ignore = opts.ignore;\n if (opts.backend && opts.backend !== 'default') out.backend = opts.backend;\n return out;\n}\n\nconst entryUrl = process.argv[1] ? `file://${process.argv[1]}` : null;\nif (entryUrl !== null && import.meta.url === entryUrl) {\n void main();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
detectSkills
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VBPHGPBR.js";
|
|
5
5
|
import "./chunk-2H7UOFLK.js";
|
|
6
6
|
export {
|
|
7
7
|
detectSkills
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=skills-
|
|
9
|
+
//# sourceMappingURL=skills-GPGRNV4R.js.map
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createMetricsCollector,
|
|
4
|
+
decideAction,
|
|
5
|
+
makeInitialAttemptState
|
|
6
|
+
} from "./chunk-3MNPDCO5.js";
|
|
7
|
+
import {
|
|
8
|
+
assertNever
|
|
9
|
+
} from "./chunk-SNYEQHUK.js";
|
|
10
|
+
import {
|
|
11
|
+
ensureAuthenticated,
|
|
12
|
+
getSignalingUrl
|
|
13
|
+
} from "./chunk-3CAEALVL.js";
|
|
14
|
+
import "./chunk-6TYNQ5KQ.js";
|
|
15
|
+
import "./chunk-EHQITHQX.js";
|
|
16
|
+
import {
|
|
17
|
+
print
|
|
18
|
+
} from "./chunk-IISLTKYY.js";
|
|
19
|
+
import "./chunk-2UN5AR7V.js";
|
|
20
|
+
import {
|
|
21
|
+
loadAuthToken
|
|
22
|
+
} from "./chunk-2J3WSIAF.js";
|
|
23
|
+
import {
|
|
24
|
+
validateEnv
|
|
25
|
+
} from "./chunk-PI77CUEP.js";
|
|
26
|
+
import "./chunk-VPMN47TL.js";
|
|
27
|
+
import "./chunk-2H7UOFLK.js";
|
|
28
|
+
|
|
29
|
+
// src/shared/commands/start.ts
|
|
30
|
+
import { fork as childProcessFork } from "child_process";
|
|
31
|
+
|
|
32
|
+
// src/shared/commands/start-supervisor.ts
|
|
33
|
+
var ABNORMAL_SIGNALS = /* @__PURE__ */ new Set(["SIGABRT", "SIGSEGV", "SIGBUS", "SIGKILL"]);
|
|
34
|
+
var SHUTDOWN_GRACEFUL_MS = 5e3;
|
|
35
|
+
var SHUTDOWN_SIGTERM_MS = 2e3;
|
|
36
|
+
function runStartSupervisor(deps) {
|
|
37
|
+
let child = null;
|
|
38
|
+
let restartState = makeInitialAttemptState();
|
|
39
|
+
let restartTimer = null;
|
|
40
|
+
let circuitLogged = false;
|
|
41
|
+
let shutdownInitiated = false;
|
|
42
|
+
let resolveDone = () => {
|
|
43
|
+
};
|
|
44
|
+
const done = new Promise((resolve) => {
|
|
45
|
+
resolveDone = resolve;
|
|
46
|
+
});
|
|
47
|
+
function captureMetric(eventType, properties) {
|
|
48
|
+
deps.metrics?.capture(eventType, properties);
|
|
49
|
+
}
|
|
50
|
+
function spawnChild(opts) {
|
|
51
|
+
const proc = deps.fork(deps.childModulePath, deps.childArgs, {
|
|
52
|
+
env: { ...process.env, SHIPYARD_DAEMON_CHILD: "1" },
|
|
53
|
+
stdio: "inherit"
|
|
54
|
+
});
|
|
55
|
+
const holder = {
|
|
56
|
+
process: proc,
|
|
57
|
+
spawnedAt: deps.now(),
|
|
58
|
+
exited: false
|
|
59
|
+
};
|
|
60
|
+
child = holder;
|
|
61
|
+
deps.log({
|
|
62
|
+
event: "daemon_supervisor_started",
|
|
63
|
+
pid: proc.pid ?? null,
|
|
64
|
+
deathCount: restartState.failureCount
|
|
65
|
+
});
|
|
66
|
+
if (opts.isRespawn) {
|
|
67
|
+
emitRespawn(proc.pid ?? null);
|
|
68
|
+
}
|
|
69
|
+
proc.on("exit", (code, signal) => {
|
|
70
|
+
handleChildExit(holder, code, signal);
|
|
71
|
+
});
|
|
72
|
+
proc.on("error", (err) => {
|
|
73
|
+
deps.log({
|
|
74
|
+
event: "daemon_supervisor_child_error",
|
|
75
|
+
err: err instanceof Error ? err.message : String(err)
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function handleChildExit(holder, code, signal) {
|
|
80
|
+
holder.exited = true;
|
|
81
|
+
if (child !== holder) return;
|
|
82
|
+
child = null;
|
|
83
|
+
const uptimeMs = deps.now() - holder.spawnedAt;
|
|
84
|
+
if (shutdownInitiated) {
|
|
85
|
+
deps.log({ event: "daemon_supervisor_child_exited_during_shutdown", code, signal, uptimeMs });
|
|
86
|
+
resolveDone({ exitCode: code ?? 0, reason: "graceful" });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!isAbnormalExit(code, signal)) {
|
|
90
|
+
deps.log({ event: "daemon_supervisor_child_exited_clean", code, signal, uptimeMs });
|
|
91
|
+
resolveDone({ exitCode: code ?? 0, reason: "graceful" });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
handleAbnormalChildExit(holder, code, signal, uptimeMs);
|
|
95
|
+
}
|
|
96
|
+
function handleAbnormalChildExit(holder, code, signal, uptimeMs) {
|
|
97
|
+
deps.log({ event: "daemon_supervisor_child_died", code, signal, uptimeMs });
|
|
98
|
+
const failureDecision = decideAction(restartState, { kind: "subscribe_failure" }, deps.now());
|
|
99
|
+
restartState = failureDecision.state;
|
|
100
|
+
emitFailureSignals(failureDecision.signals, holder);
|
|
101
|
+
if (restartState.circuitOpenedAt !== null) {
|
|
102
|
+
resolveDone({ exitCode: 1, reason: "circuit_open" });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
scheduleRespawn();
|
|
106
|
+
}
|
|
107
|
+
function emitFailureSignals(signals, holder) {
|
|
108
|
+
for (const sig of signals) {
|
|
109
|
+
if (sig.kind === "circuit_opened" && !circuitLogged) {
|
|
110
|
+
circuitLogged = true;
|
|
111
|
+
const windowMs = deps.now() - holder.spawnedAt;
|
|
112
|
+
deps.log({
|
|
113
|
+
event: "daemon_supervisor_circuit_open",
|
|
114
|
+
deathCount: restartState.failureCount,
|
|
115
|
+
windowMs
|
|
116
|
+
});
|
|
117
|
+
captureMetric("daemon_supervisor_circuit_open", {
|
|
118
|
+
deathCount: restartState.failureCount,
|
|
119
|
+
windowMs
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function scheduleRespawn() {
|
|
125
|
+
if (shutdownInitiated) return;
|
|
126
|
+
if (restartState.circuitOpenedAt !== null) return;
|
|
127
|
+
const requestDecision = decideAction(
|
|
128
|
+
restartState,
|
|
129
|
+
{ kind: "request_subscribe", reason: "rescan", activeCount: 0 },
|
|
130
|
+
deps.now()
|
|
131
|
+
);
|
|
132
|
+
restartState = requestDecision.state;
|
|
133
|
+
deps.log({
|
|
134
|
+
event: "daemon_supervisor_respawn_scheduled",
|
|
135
|
+
deathCount: restartState.failureCount
|
|
136
|
+
});
|
|
137
|
+
switch (requestDecision.action.kind) {
|
|
138
|
+
case "wait": {
|
|
139
|
+
restartTimer = deps.setTimeout(() => {
|
|
140
|
+
restartTimer = null;
|
|
141
|
+
if (shutdownInitiated) return;
|
|
142
|
+
spawnChild({ isRespawn: true });
|
|
143
|
+
}, requestDecision.action.ms);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
case "subscribe":
|
|
147
|
+
case "evict_and_subscribe":
|
|
148
|
+
spawnChild({ isRespawn: true });
|
|
149
|
+
return;
|
|
150
|
+
case "reject_stub":
|
|
151
|
+
return;
|
|
152
|
+
case "noop":
|
|
153
|
+
return;
|
|
154
|
+
default:
|
|
155
|
+
assertNever(requestDecision.action);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function emitRespawn(newPid) {
|
|
159
|
+
deps.log({ event: "daemon_supervisor_respawned", deathCount: restartState.failureCount });
|
|
160
|
+
captureMetric("daemon_supervisor_respawned", {
|
|
161
|
+
newPid,
|
|
162
|
+
deathCount: restartState.failureCount
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function forwardShutdown() {
|
|
166
|
+
if (shutdownInitiated) return;
|
|
167
|
+
shutdownInitiated = true;
|
|
168
|
+
if (restartTimer !== null) {
|
|
169
|
+
deps.clearTimeout(restartTimer);
|
|
170
|
+
restartTimer = null;
|
|
171
|
+
}
|
|
172
|
+
const holder = child;
|
|
173
|
+
if (!holder) {
|
|
174
|
+
deps.log({ event: "daemon_supervisor_shutdown_no_child" });
|
|
175
|
+
resolveDone({ exitCode: 0, reason: "graceful" });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
deps.log({ event: "daemon_supervisor_shutdown_requested" });
|
|
179
|
+
try {
|
|
180
|
+
holder.process.send?.({ cmd: "shutdown" });
|
|
181
|
+
} catch (err) {
|
|
182
|
+
deps.log({
|
|
183
|
+
event: "daemon_supervisor_shutdown_send_failed",
|
|
184
|
+
err: err instanceof Error ? err.message : String(err)
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
deps.setTimeout(() => onSigtermDeadline(holder), SHUTDOWN_GRACEFUL_MS);
|
|
188
|
+
}
|
|
189
|
+
function onSigtermDeadline(holder) {
|
|
190
|
+
if (holder.exited) return;
|
|
191
|
+
deps.log({ event: "daemon_supervisor_shutdown_sigterm" });
|
|
192
|
+
try {
|
|
193
|
+
holder.process.kill("SIGTERM");
|
|
194
|
+
} catch (err) {
|
|
195
|
+
deps.log({
|
|
196
|
+
event: "daemon_supervisor_kill_failed",
|
|
197
|
+
signal: "SIGTERM",
|
|
198
|
+
err: err instanceof Error ? err.message : String(err)
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
deps.setTimeout(() => onSigkillDeadline(holder), SHUTDOWN_SIGTERM_MS);
|
|
202
|
+
}
|
|
203
|
+
function onSigkillDeadline(holder) {
|
|
204
|
+
if (holder.exited) return;
|
|
205
|
+
deps.log({ event: "daemon_supervisor_shutdown_sigkill" });
|
|
206
|
+
try {
|
|
207
|
+
holder.process.kill("SIGKILL");
|
|
208
|
+
} catch (err) {
|
|
209
|
+
deps.log({
|
|
210
|
+
event: "daemon_supervisor_kill_failed",
|
|
211
|
+
signal: "SIGKILL",
|
|
212
|
+
err: err instanceof Error ? err.message : String(err)
|
|
213
|
+
});
|
|
214
|
+
resolveDone({ exitCode: 1, reason: "graceful" });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
deps.onSignal("SIGTERM", forwardShutdown);
|
|
218
|
+
deps.onSignal("SIGINT", forwardShutdown);
|
|
219
|
+
spawnChild({ isRespawn: false });
|
|
220
|
+
return { done };
|
|
221
|
+
}
|
|
222
|
+
function isAbnormalExit(code, signal) {
|
|
223
|
+
if (signal !== null && ABNORMAL_SIGNALS.has(signal)) return true;
|
|
224
|
+
if (code !== null && code !== 0) return true;
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/shared/commands/start.ts
|
|
229
|
+
async function startCommand() {
|
|
230
|
+
if (process.env.SHIPYARD_DAEMON_CHILD === "1") {
|
|
231
|
+
return runDaemonChild();
|
|
232
|
+
}
|
|
233
|
+
return runSupervisor();
|
|
234
|
+
}
|
|
235
|
+
async function runDaemonChild() {
|
|
236
|
+
const env = validateEnv();
|
|
237
|
+
const signalingUrl = getSignalingUrl();
|
|
238
|
+
const codeIdx = process.argv.indexOf("--code");
|
|
239
|
+
const webCode = codeIdx !== -1 ? process.argv[codeIdx + 1] : void 0;
|
|
240
|
+
print("Starting Shipyard daemon...\n");
|
|
241
|
+
const authResult = await ensureAuthenticated({ signalingUrl, webCode });
|
|
242
|
+
env.SHIPYARD_USER_TOKEN = authResult.token;
|
|
243
|
+
env.SHIPYARD_USER_ID = authResult.userId;
|
|
244
|
+
env.SHIPYARD_USER_DISPLAY_NAME = authResult.displayName;
|
|
245
|
+
env.SHIPYARD_SIGNALING_URL = authResult.signalingUrl;
|
|
246
|
+
const { serve } = await import("./serve-IVUGCBEE.js");
|
|
247
|
+
return serve({ isDev: env.SHIPYARD_DEV, autoOpenBrowser: !authResult.deviceFlowRan });
|
|
248
|
+
}
|
|
249
|
+
async function runSupervisor() {
|
|
250
|
+
const childModulePath = process.argv[1];
|
|
251
|
+
if (!childModulePath) {
|
|
252
|
+
throw new Error("shipyard start: cannot determine childModulePath from process.argv");
|
|
253
|
+
}
|
|
254
|
+
const auth = await loadAuthToken();
|
|
255
|
+
const METRICS_WORKER_URL = process.env.SHIPYARD_METRICS_WORKER_URL || "https://shipyard-metrics.jacob-191.workers.dev";
|
|
256
|
+
const metrics = auth.status === "ok" ? createMetricsCollector(
|
|
257
|
+
METRICS_WORKER_URL,
|
|
258
|
+
auth.token,
|
|
259
|
+
process.env.SHIPYARD_TELEMETRY !== "0"
|
|
260
|
+
) : void 0;
|
|
261
|
+
const { done } = runStartSupervisor({
|
|
262
|
+
fork: childProcessFork,
|
|
263
|
+
childModulePath,
|
|
264
|
+
childArgs: process.argv.slice(2),
|
|
265
|
+
log: (entry) => process.stderr.write(`${JSON.stringify(entry)}
|
|
266
|
+
`),
|
|
267
|
+
metrics,
|
|
268
|
+
now: () => Date.now(),
|
|
269
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
270
|
+
clearTimeout: (timer) => {
|
|
271
|
+
if (timer === null || timer === void 0) return;
|
|
272
|
+
clearTimeout(timer);
|
|
273
|
+
},
|
|
274
|
+
onSignal: (sig, handler) => {
|
|
275
|
+
process.on(sig, handler);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
const result = await done;
|
|
279
|
+
metrics?.dispose();
|
|
280
|
+
process.exit(result.exitCode);
|
|
281
|
+
}
|
|
282
|
+
export {
|
|
283
|
+
startCommand
|
|
284
|
+
};
|
|
285
|
+
//# sourceMappingURL=start-I7ZONWK7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/commands/start.ts","../src/shared/commands/start-supervisor.ts"],"sourcesContent":["import { fork as childProcessFork } from 'node:child_process';\nimport { loadAuthToken } from '../../services/bootstrap/auth.js';\nimport { createMetricsCollector } from '../../services/metrics/metrics-collector.js';\nimport { validateEnv } from '../env.js';\nimport { ensureAuthenticated, getSignalingUrl } from './login.js';\nimport { print } from './output.js';\nimport { runStartSupervisor } from './start-supervisor.js';\n\n/**\n * `shipyard start` -- the primary entry point for running the daemon.\n *\n * Two-layer process model (Commit 3 of the watcher-worker subprocess\n * rollout): the parent CLI process forks itself and supervises a daemon\n * child. The branch is gated on `SHIPYARD_DAEMON_CHILD=1` in the env so the\n * forked child re-enters this same function and runs the existing\n * `serve()` path verbatim. The parent monitors the child's exit and\n * respawns on abnormal exits (SIGABRT/SIGSEGV/SIGBUS/SIGKILL or non-zero\n * exit code), backed by `decideAction`'s pure backoff/circuit core\n * (third use site after `file-watcher-guard.ts`'s per-path circuit and\n * the watcher-worker supervisor's restart circuit).\n */\nexport async function startCommand(): Promise<void> {\n if (process.env.SHIPYARD_DAEMON_CHILD === '1') {\n return runDaemonChild();\n }\n return runSupervisor();\n}\n\nasync function runDaemonChild(): Promise<void> {\n const env = validateEnv();\n const signalingUrl = getSignalingUrl();\n\n const codeIdx = process.argv.indexOf('--code');\n const webCode = codeIdx !== -1 ? process.argv[codeIdx + 1] : undefined;\n\n print('Starting Shipyard daemon...\\n');\n\n const authResult = await ensureAuthenticated({ signalingUrl, webCode });\n\n env.SHIPYARD_USER_TOKEN = authResult.token;\n env.SHIPYARD_USER_ID = authResult.userId;\n env.SHIPYARD_USER_DISPLAY_NAME = authResult.displayName;\n env.SHIPYARD_SIGNALING_URL = authResult.signalingUrl;\n\n const { serve } = await import('../../services/serve.js');\n return serve({ isDev: env.SHIPYARD_DEV, autoOpenBrowser: !authResult.deviceFlowRan });\n}\n\nasync function runSupervisor(): Promise<void> {\n /**\n * Re-fork the same entrypoint that started us. `process.argv[1]` is the\n * Node script (or bundled binary) currently executing; the forked child\n * picks up `SHIPYARD_DAEMON_CHILD=1` and takes the `runDaemonChild()`\n * branch above.\n */\n const childModulePath = process.argv[1];\n if (!childModulePath) {\n throw new Error('shipyard start: cannot determine childModulePath from process.argv');\n }\n\n /**\n * Build the supervisor's own metrics collector. The daemon child constructs\n * a separate one in `serve.ts` once it's authenticated. We use the existing\n * cached auth token here without running the device flow — if the user has\n * never logged in, metrics is just `undefined` (the supervisor still runs).\n * This keeps option (a) of Commit 4's spec: supervisor parent gets its own\n * collector at startup, daemon child gets its own as today.\n */\n const auth = await loadAuthToken();\n const METRICS_WORKER_URL =\n process.env.SHIPYARD_METRICS_WORKER_URL || 'https://shipyard-metrics.jacob-191.workers.dev';\n const metrics =\n auth.status === 'ok'\n ? createMetricsCollector(\n METRICS_WORKER_URL,\n auth.token,\n process.env.SHIPYARD_TELEMETRY !== '0'\n )\n : undefined;\n\n const { done } = runStartSupervisor({\n fork: childProcessFork,\n childModulePath,\n childArgs: process.argv.slice(2),\n log: (entry) => process.stderr.write(`${JSON.stringify(entry)}\\n`),\n metrics,\n now: () => Date.now(),\n setTimeout: (fn, ms) => setTimeout(fn, ms),\n clearTimeout: (timer) => {\n if (timer === null || timer === undefined) return;\n clearTimeout(timer as never);\n },\n onSignal: (sig, handler) => {\n process.on(sig, handler);\n },\n });\n\n const result = await done;\n /** Flush any pending metrics events before the supervisor exits. */\n metrics?.dispose();\n /**\n * Propagate the daemon child's exit code (or `1` for circuit-open) to\n * shell/CI. Exiting here also stops any non-trivial Node teardown that\n * the supervisor's signal handlers might otherwise block.\n */\n process.exit(result.exitCode);\n}\n","import type { ChildProcess } from 'node:child_process';\nimport { assertNever } from '../assert-never.js';\nimport { type AttemptState, decideAction, makeInitialAttemptState } from '../file-watcher-guard.js';\n\n/**\n * Mirrors the shape of `MetricsCapture` from\n * `apps/daemon/src/services/metrics/metrics-collector.ts`. Declared inline\n * (not imported) so the supervisor module stays in `apps/daemon/src/shared/`\n * with no upward dependency on `services/metrics/`. Production wiring in\n * `start.ts` constructs a `MetricsCollector` and passes it through.\n */\nexport interface StartSupervisorMetrics {\n capture(eventType: string, properties: Record<string, unknown>): void;\n}\n\n/**\n * Outer CLI supervisor: the parent `shipyard start` process forks itself and\n * supervises the daemon child. On abnormal exit (SIGABRT/SIGSEGV/SIGBUS/SIGKILL\n * or non-zero exit code) it applies the same backoff + circuit semantics as\n * the watcher worker supervisor (third use of `decideAction`'s pure core) and\n * respawns. On graceful exit it propagates the exit code.\n *\n * On supervisor SIGTERM/SIGINT it forwards `{cmd:'shutdown'}` over the IPC\n * channel that `child_process.fork` sets up automatically, then escalates\n * SIGTERM -> SIGKILL on the same shape as the watcher-worker supervisor.\n */\n\nexport interface StartSupervisorDeps {\n fork: typeof import('node:child_process').fork;\n /** Path to the daemon binary entrypoint (typically `process.argv[1]`). */\n childModulePath: string;\n /** Forwarded to the child verbatim (typically `process.argv.slice(2)`). */\n childArgs: string[];\n log: (entry: { event: string; [key: string]: unknown }) => void;\n /**\n * Optional metrics capture. Production wiring constructs a\n * `MetricsCollector` from `loadAuthToken()` config (the supervisor parent\n * runs before the daemon child constructs its own collector). When the\n * user has no saved auth token, the supervisor still runs — metrics is\n * just `undefined` and supervision events still surface via `log`.\n */\n metrics?: StartSupervisorMetrics;\n now: () => number;\n setTimeout: (fn: () => void, ms: number) => unknown;\n clearTimeout: (timer: unknown) => void;\n /**\n * Process signal subscription. Tests inject a stub so SIGTERM/SIGINT can be\n * driven without touching the real `process` global.\n */\n onSignal: (signal: NodeJS.Signals, handler: () => void) => void;\n}\n\nexport type StartSupervisorReason = 'graceful' | 'circuit_open';\n\nexport interface StartSupervisorResult {\n /**\n * Resolves when the child exits cleanly OR the circuit opens. Callers can\n * await this from the entrypoint to keep the supervisor process alive\n * until the supervised daemon settles.\n */\n done: Promise<{ exitCode: number; reason: StartSupervisorReason }>;\n}\n\n/** Empirically: SIGSEGV -> 139, SIGBUS -> 138, SIGABRT -> 134 on POSIX. */\nconst ABNORMAL_SIGNALS = new Set<NodeJS.Signals>(['SIGABRT', 'SIGSEGV', 'SIGBUS', 'SIGKILL']);\n\nconst SHUTDOWN_GRACEFUL_MS = 5_000;\nconst SHUTDOWN_SIGTERM_MS = 2_000;\n\ninterface ChildHolder {\n process: ChildProcess;\n spawnedAt: number;\n exited: boolean;\n}\n\nexport function runStartSupervisor(deps: StartSupervisorDeps): StartSupervisorResult {\n let child: ChildHolder | null = null;\n let restartState: AttemptState = makeInitialAttemptState();\n let restartTimer: unknown = null;\n let circuitLogged = false;\n let shutdownInitiated = false;\n\n let resolveDone: (value: { exitCode: number; reason: StartSupervisorReason }) => void = () => {};\n const done = new Promise<{ exitCode: number; reason: StartSupervisorReason }>((resolve) => {\n resolveDone = resolve;\n });\n\n function captureMetric(eventType: string, properties: Record<string, unknown>): void {\n deps.metrics?.capture(eventType, properties);\n }\n\n function spawnChild(opts: { isRespawn: boolean }): void {\n const proc = deps.fork(deps.childModulePath, deps.childArgs, {\n env: { ...process.env, SHIPYARD_DAEMON_CHILD: '1' },\n stdio: 'inherit',\n });\n const holder: ChildHolder = {\n process: proc,\n spawnedAt: deps.now(),\n exited: false,\n };\n child = holder;\n deps.log({\n event: 'daemon_supervisor_started',\n pid: proc.pid ?? null,\n deathCount: restartState.failureCount,\n });\n\n if (opts.isRespawn) {\n emitRespawn(proc.pid ?? null);\n }\n\n proc.on('exit', (code, signal) => {\n handleChildExit(holder, code, signal);\n });\n proc.on('error', (err) => {\n deps.log({\n event: 'daemon_supervisor_child_error',\n err: err instanceof Error ? err.message : String(err),\n });\n });\n }\n\n function handleChildExit(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null\n ): void {\n holder.exited = true;\n /** Drop stale exits — only the live child drives state. */\n if (child !== holder) return;\n child = null;\n\n const uptimeMs = deps.now() - holder.spawnedAt;\n\n if (shutdownInitiated) {\n deps.log({ event: 'daemon_supervisor_child_exited_during_shutdown', code, signal, uptimeMs });\n resolveDone({ exitCode: code ?? 0, reason: 'graceful' });\n return;\n }\n\n if (!isAbnormalExit(code, signal)) {\n deps.log({ event: 'daemon_supervisor_child_exited_clean', code, signal, uptimeMs });\n resolveDone({ exitCode: code ?? 0, reason: 'graceful' });\n return;\n }\n\n handleAbnormalChildExit(holder, code, signal, uptimeMs);\n }\n\n function handleAbnormalChildExit(\n holder: ChildHolder,\n code: number | null,\n signal: NodeJS.Signals | null,\n uptimeMs: number\n ): void {\n deps.log({ event: 'daemon_supervisor_child_died', code, signal, uptimeMs });\n\n /**\n * Reuse the guard's pure restart core: 'subscribe_failure' drives the\n * same backoff + circuit logic per-process. Different state instance,\n * same primitive (third use site after guard's per-path circuit and the\n * watcher-worker supervisor's restart circuit).\n */\n const failureDecision = decideAction(restartState, { kind: 'subscribe_failure' }, deps.now());\n restartState = failureDecision.state;\n emitFailureSignals(failureDecision.signals, holder);\n\n if (restartState.circuitOpenedAt !== null) {\n /**\n * Per the spec for this layer: rather than half-open probe like the\n * watcher worker (which lives inside the daemon), the CLI supervisor\n * surfaces the failure to the user so they can investigate. The\n * supervisor terminates rather than continuing to thrash.\n */\n resolveDone({ exitCode: 1, reason: 'circuit_open' });\n return;\n }\n\n scheduleRespawn();\n }\n\n function emitFailureSignals(\n signals: ReturnType<typeof decideAction>['signals'],\n holder: ChildHolder\n ): void {\n for (const sig of signals) {\n if (sig.kind === 'circuit_opened' && !circuitLogged) {\n circuitLogged = true;\n const windowMs = deps.now() - holder.spawnedAt;\n deps.log({\n event: 'daemon_supervisor_circuit_open',\n deathCount: restartState.failureCount,\n windowMs,\n });\n captureMetric('daemon_supervisor_circuit_open', {\n deathCount: restartState.failureCount,\n windowMs,\n });\n }\n }\n }\n\n function scheduleRespawn(): void {\n if (shutdownInitiated) return;\n if (restartState.circuitOpenedAt !== null) return;\n\n const requestDecision = decideAction(\n restartState,\n { kind: 'request_subscribe', reason: 'rescan', activeCount: 0 },\n deps.now()\n );\n restartState = requestDecision.state;\n deps.log({\n event: 'daemon_supervisor_respawn_scheduled',\n deathCount: restartState.failureCount,\n });\n\n switch (requestDecision.action.kind) {\n case 'wait': {\n restartTimer = deps.setTimeout(() => {\n restartTimer = null;\n if (shutdownInitiated) return;\n spawnChild({ isRespawn: true });\n }, requestDecision.action.ms);\n return;\n }\n case 'subscribe':\n case 'evict_and_subscribe':\n /**\n * `evict_and_subscribe` only fires when activeCount >= MAX_ACTIVE_WATCHERS;\n * we always pass activeCount: 0 so the pure core never returns it here.\n * Treating both as \"respawn now\" keeps the switch exhaustive without\n * coupling this layer to guard-internals.\n */\n spawnChild({ isRespawn: true });\n return;\n case 'reject_stub':\n /** Circuit-open path is handled by the caller before scheduleRespawn. */\n return;\n case 'noop':\n /** decideRequest never returns 'noop'. */\n return;\n default:\n assertNever(requestDecision.action);\n }\n }\n\n /**\n * Emit the `daemon_supervisor_respawned` log + metric. The metric carries\n * `newPid` (post-fork) plus `deathCount`. Called inline in `spawnChild` for\n * respawns; the initial spawn does not emit this event.\n */\n function emitRespawn(newPid: number | null): void {\n deps.log({ event: 'daemon_supervisor_respawned', deathCount: restartState.failureCount });\n captureMetric('daemon_supervisor_respawned', {\n newPid,\n deathCount: restartState.failureCount,\n });\n }\n\n function forwardShutdown(): void {\n if (shutdownInitiated) return;\n shutdownInitiated = true;\n\n if (restartTimer !== null) {\n deps.clearTimeout(restartTimer);\n restartTimer = null;\n }\n\n const holder = child;\n if (!holder) {\n /**\n * Either we never spawned, the previous child already exited, or the\n * circuit opened. Resolve with code 0 so the supervisor process exits.\n */\n deps.log({ event: 'daemon_supervisor_shutdown_no_child' });\n resolveDone({ exitCode: 0, reason: 'graceful' });\n return;\n }\n\n deps.log({ event: 'daemon_supervisor_shutdown_requested' });\n\n /**\n * Cooperative shutdown via the IPC channel that `fork()` sets up. The\n * child should listen for `process.on('message', ...)` and tear down\n * gracefully on `{cmd:'shutdown'}`.\n */\n try {\n holder.process.send?.({ cmd: 'shutdown' });\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_shutdown_send_failed',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n\n /** SIGTERM after grace, SIGKILL after that. */\n deps.setTimeout(() => onSigtermDeadline(holder), SHUTDOWN_GRACEFUL_MS);\n }\n\n function onSigtermDeadline(holder: ChildHolder): void {\n if (holder.exited) return;\n deps.log({ event: 'daemon_supervisor_shutdown_sigterm' });\n try {\n holder.process.kill('SIGTERM');\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal: 'SIGTERM',\n err: err instanceof Error ? err.message : String(err),\n });\n }\n deps.setTimeout(() => onSigkillDeadline(holder), SHUTDOWN_SIGTERM_MS);\n }\n\n function onSigkillDeadline(holder: ChildHolder): void {\n if (holder.exited) return;\n deps.log({ event: 'daemon_supervisor_shutdown_sigkill' });\n try {\n holder.process.kill('SIGKILL');\n } catch (err) {\n deps.log({\n event: 'daemon_supervisor_kill_failed',\n signal: 'SIGKILL',\n err: err instanceof Error ? err.message : String(err),\n });\n /**\n * Safety net: SIGKILL throwing AND on-exit not firing is a paranoid\n * combination (zombie process, EPERM on a child we own), but if it\n * happens the `done` promise hangs forever and so does whoever\n * awaits it. Resolve here so the supervisor parent can exit.\n */\n resolveDone({ exitCode: 1, reason: 'graceful' });\n }\n }\n\n /** Wire signal forwarding via injected hook so tests can drive deterministically. */\n deps.onSignal('SIGTERM', forwardShutdown);\n deps.onSignal('SIGINT', forwardShutdown);\n\n /** Spawn the initial child immediately. */\n spawnChild({ isRespawn: false });\n\n return { done };\n}\n\nfunction isAbnormalExit(code: number | null, signal: NodeJS.Signals | null): boolean {\n if (signal !== null && ABNORMAL_SIGNALS.has(signal)) return true;\n if (code !== null && code !== 0) return true;\n return false;\n}\n"],"mappings":"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","names":[]}
|