@stigmer/cli 3.15.0 → 3.15.2-dev.20260913223433
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/commands/internal-daemon.d.ts.map +1 -1
- package/commands/internal-daemon.js +2 -9
- package/commands/internal-daemon.js.map +1 -1
- package/commands/up.d.ts.map +1 -1
- package/commands/up.js +37 -8
- package/commands/up.js.map +1 -1
- package/local/artifact.d.ts +13 -3
- package/local/artifact.d.ts.map +1 -1
- package/local/artifact.js +31 -10
- package/local/artifact.js.map +1 -1
- package/local/daemon/components.d.ts.map +1 -1
- package/local/daemon/components.js +2 -0
- package/local/daemon/components.js.map +1 -1
- package/local/daemon/host.d.ts +8 -0
- package/local/daemon/host.d.ts.map +1 -1
- package/local/daemon/host.js +42 -1
- package/local/daemon/host.js.map +1 -1
- package/local/daemon/index.d.ts +3 -3
- package/local/daemon/index.d.ts.map +1 -1
- package/local/daemon/index.js +2 -2
- package/local/daemon/index.js.map +1 -1
- package/local/daemon/launch.d.ts +29 -1
- package/local/daemon/launch.d.ts.map +1 -1
- package/local/daemon/launch.js +73 -23
- package/local/daemon/launch.js.map +1 -1
- package/local/daemon/process.d.ts +16 -2
- package/local/daemon/process.d.ts.map +1 -1
- package/local/daemon/process.js +16 -2
- package/local/daemon/process.js.map +1 -1
- package/local/daemon/types.d.ts +2 -0
- package/local/daemon/types.d.ts.map +1 -1
- package/local/paths.d.ts +14 -4
- package/local/paths.d.ts.map +1 -1
- package/local/paths.js +17 -4
- package/local/paths.js.map +1 -1
- package/local/runtime/runner.d.ts +4 -0
- package/local/runtime/runner.d.ts.map +1 -1
- package/local/runtime/runner.js +10 -6
- package/local/runtime/runner.js.map +1 -1
- package/local/runtime/server.d.ts +5 -0
- package/local/runtime/server.d.ts.map +1 -1
- package/local/runtime/server.js +13 -8
- package/local/runtime/server.js.map +1 -1
- package/local/seedpack/content.d.ts +4 -0
- package/local/seedpack/content.d.ts.map +1 -1
- package/local/seedpack/content.js +11 -11
- package/local/seedpack/content.js.map +1 -1
- package/local/state/lock.d.ts +3 -2
- package/local/state/lock.d.ts.map +1 -1
- package/local/state/lock.js +23 -9
- package/local/state/lock.js.map +1 -1
- package/local/state/proc.d.ts +13 -0
- package/local/state/proc.d.ts.map +1 -1
- package/local/state/proc.js +15 -0
- package/local/state/proc.js.map +1 -1
- package/local/temporal/download.d.ts +7 -1
- package/local/temporal/download.d.ts.map +1 -1
- package/local/temporal/download.js +21 -11
- package/local/temporal/download.js.map +1 -1
- package/local/temporal/index.d.ts +3 -3
- package/local/temporal/index.d.ts.map +1 -1
- package/local/temporal/index.js +2 -2
- package/local/temporal/index.js.map +1 -1
- package/local/temporal/inspect.d.ts +10 -3
- package/local/temporal/inspect.d.ts.map +1 -1
- package/local/temporal/inspect.js +52 -13
- package/local/temporal/inspect.js.map +1 -1
- package/local/temporal/manager.d.ts +16 -4
- package/local/temporal/manager.d.ts.map +1 -1
- package/local/temporal/manager.js +19 -6
- package/local/temporal/manager.js.map +1 -1
- package/package.json +5 -5
- package/src/commands/internal-daemon.ts +2 -10
- package/src/commands/up.ts +52 -8
- package/src/local/artifact.test.ts +27 -1
- package/src/local/artifact.ts +35 -13
- package/src/local/daemon/components.ts +2 -0
- package/src/local/daemon/daemon.integration.test.ts +33 -0
- package/src/local/daemon/host.ts +50 -1
- package/src/local/daemon/index.ts +3 -3
- package/src/local/daemon/launch.test.ts +136 -0
- package/src/local/daemon/launch.ts +108 -27
- package/src/local/daemon/process.ts +31 -4
- package/src/local/daemon/supervisor.test.ts +1 -1
- package/src/local/daemon/types.ts +2 -0
- package/src/local/paths.ts +17 -4
- package/src/local/runtime/runner.ts +10 -6
- package/src/local/runtime/runtime.test.ts +15 -0
- package/src/local/runtime/server.test.ts +37 -0
- package/src/local/runtime/server.ts +17 -12
- package/src/local/seedpack/content.test.ts +21 -0
- package/src/local/seedpack/content.ts +15 -16
- package/src/local/state/lock.ts +24 -9
- package/src/local/state/proc.ts +16 -0
- package/src/local/state/state.test.ts +25 -1
- package/src/local/temporal/download.test.ts +79 -11
- package/src/local/temporal/download.ts +24 -11
- package/src/local/temporal/index.ts +11 -3
- package/src/local/temporal/inspect.test.ts +83 -0
- package/src/local/temporal/inspect.ts +60 -12
- package/src/local/temporal/manager.test.ts +34 -1
- package/src/local/temporal/manager.ts +22 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/local/temporal/manager.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,0EAA0E;AAE1E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAiB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/local/temporal/manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/cli",
|
|
3
|
-
"version": "3.15.
|
|
3
|
+
"version": "3.15.2-dev.20260913223433",
|
|
4
4
|
"description": "Stigmer command-line interface — manage agents, workflows, MCP servers, skills, and executions from the terminal",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"@connectrpc/connect": "^2.0.0",
|
|
36
36
|
"@connectrpc/connect-node": "^2.1.1",
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
38
|
-
"@stigmer/ink": "3.15.
|
|
39
|
-
"@stigmer/mcp-server": "3.15.
|
|
40
|
-
"@stigmer/protos": "3.15.
|
|
41
|
-
"@stigmer/sdk": "3.15.
|
|
38
|
+
"@stigmer/ink": "3.15.2-dev.20260913223433",
|
|
39
|
+
"@stigmer/mcp-server": "3.15.2-dev.20260913223433",
|
|
40
|
+
"@stigmer/protos": "3.15.2-dev.20260913223433",
|
|
41
|
+
"@stigmer/sdk": "3.15.2-dev.20260913223433",
|
|
42
42
|
"commander": "^12.1.0",
|
|
43
43
|
"fflate": "^0.8.3",
|
|
44
44
|
"ink": "^7.0.0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// `stigmer internal-daemon` (hidden) — the long-lived supervised daemon process
|
|
2
2
|
// that `up` re-execs. It is not meant to be invoked directly; it runs the local
|
|
3
3
|
// stack until it receives SIGTERM/SIGINT, then exits with the daemon's code.
|
|
4
|
+
// (`stigmer up --foreground` runs the same body in the launching process.)
|
|
4
5
|
|
|
5
6
|
import type { Command } from "commander";
|
|
6
7
|
|
|
@@ -9,17 +10,8 @@ export function registerInternalDaemon(program: Command): void {
|
|
|
9
10
|
.command("internal-daemon", { hidden: true })
|
|
10
11
|
.description("internal: run the supervised local-stack daemon (do not invoke directly)")
|
|
11
12
|
.action(async () => {
|
|
12
|
-
const { runInternalDaemon } = await import("../local/daemon/process.js");
|
|
13
|
+
const { runInternalDaemon, waitForShutdownSignal } = await import("../local/daemon/process.js");
|
|
13
14
|
const code = await runInternalDaemon({ waitForShutdown: waitForShutdownSignal });
|
|
14
15
|
process.exit(code);
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
// Resolve when the first SIGTERM/SIGINT arrives — the daemon's shutdown trigger.
|
|
19
|
-
function waitForShutdownSignal(): Promise<void> {
|
|
20
|
-
return new Promise((resolve) => {
|
|
21
|
-
const onSignal = (): void => resolve();
|
|
22
|
-
process.once("SIGTERM", onSignal);
|
|
23
|
-
process.once("SIGINT", onSignal);
|
|
24
|
-
});
|
|
25
|
-
}
|
package/src/commands/up.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// `stigmer up [server]` — start the local Stigmer stack (managed Temporal, the
|
|
2
2
|
// control-plane server, and the unified runner) as a supervised background
|
|
3
|
-
// daemon. `up server` brings up
|
|
3
|
+
// daemon, or with `--foreground` as this very process. `up server` brings up
|
|
4
|
+
// only the control plane.
|
|
4
5
|
//
|
|
5
6
|
// Thin handler: parse flags, delegate to the local daemon launcher, render the
|
|
6
7
|
// outcome. The launcher (and the heavy resolvers it pulls in) load lazily so
|
|
@@ -9,6 +10,8 @@
|
|
|
9
10
|
import { homedir } from "node:os";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
import type { Command } from "commander";
|
|
13
|
+
import { CliExitError } from "../errors/cli-exit-error.js";
|
|
14
|
+
import { ExitCode } from "../errors/exit-codes.js";
|
|
12
15
|
import { CommandResult, type OutputFlags, renderResult } from "../output/index.js";
|
|
13
16
|
import { HEALTH_STATE_FILE, SERVER_PORT } from "../local/constants.js";
|
|
14
17
|
import { addResultFlags, resultFormat } from "./shared.js";
|
|
@@ -16,6 +19,13 @@ import { addResultFlags, resultFormat } from "./shared.js";
|
|
|
16
19
|
interface UpFlags extends OutputFlags {
|
|
17
20
|
serverOnly?: boolean;
|
|
18
21
|
web?: boolean; // false when --no-web is passed
|
|
22
|
+
foreground?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface UpRun {
|
|
26
|
+
serverOnly: boolean;
|
|
27
|
+
noWeb: boolean;
|
|
28
|
+
foreground: boolean;
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
// The server serves the web console from its unified port (DD-012); the
|
|
@@ -23,14 +33,23 @@ interface UpFlags extends OutputFlags {
|
|
|
23
33
|
// process, one origin — there is no separate console to not-start).
|
|
24
34
|
const NO_WEB_HELP = "don't report the web console URL";
|
|
25
35
|
|
|
36
|
+
// Foreground is the shape a supervisor wants — a container entrypoint, a
|
|
37
|
+
// systemd unit, a tmux pane: one process to watch, signals delivered to it,
|
|
38
|
+
// the stack's output on its stdio — instead of a detached daemon to poll.
|
|
39
|
+
const FOREGROUND_HELP = "run the stack in this process until Ctrl-C or SIGTERM (for containers and service managers)";
|
|
40
|
+
|
|
26
41
|
export function registerUp(program: Command): void {
|
|
27
42
|
const up = program
|
|
28
43
|
.command("up")
|
|
29
44
|
.description("start the local Stigmer stack (server, runner, Temporal)")
|
|
30
45
|
.option("--server-only", "start only the control plane (no runners)")
|
|
31
46
|
.option("--no-web", NO_WEB_HELP)
|
|
47
|
+
.option("--foreground", FOREGROUND_HELP)
|
|
32
48
|
.action((options: UpFlags) =>
|
|
33
|
-
runUp(
|
|
49
|
+
runUp(
|
|
50
|
+
{ serverOnly: options.serverOnly === true, noWeb: options.web === false, foreground: options.foreground === true },
|
|
51
|
+
options,
|
|
52
|
+
),
|
|
34
53
|
);
|
|
35
54
|
addResultFlags(up);
|
|
36
55
|
|
|
@@ -38,16 +57,40 @@ export function registerUp(program: Command): void {
|
|
|
38
57
|
.command("server")
|
|
39
58
|
.description("start only the control plane (no runners)")
|
|
40
59
|
.option("--no-web", NO_WEB_HELP)
|
|
41
|
-
.
|
|
60
|
+
.option("--foreground", FOREGROUND_HELP)
|
|
61
|
+
.action((options: UpFlags) =>
|
|
62
|
+
runUp({ serverOnly: true, noWeb: options.web === false, foreground: options.foreground === true }, options),
|
|
63
|
+
);
|
|
42
64
|
addResultFlags(server);
|
|
43
65
|
}
|
|
44
66
|
|
|
45
|
-
async function runUp(
|
|
67
|
+
async function runUp(run: UpRun, flags: OutputFlags): Promise<void> {
|
|
46
68
|
process.stderr.write("Starting Stigmer local stack… (first run may take a moment)\n");
|
|
47
|
-
const
|
|
48
|
-
|
|
69
|
+
const launch = await import("../local/daemon/launch.js");
|
|
70
|
+
|
|
71
|
+
if (!run.foreground) {
|
|
72
|
+
await launch.up(run);
|
|
73
|
+
await renderUpCard(run, flags);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The card renders when the stack is serving and seeded — the moment the
|
|
78
|
+
// detached shape would have returned — and the process then stays up,
|
|
79
|
+
// mirroring the server's and runner's output, until a shutdown signal.
|
|
80
|
+
const code = await launch.upForeground(run, homedir(), {
|
|
81
|
+
onReady: () => renderUpCard(run, flags),
|
|
82
|
+
});
|
|
83
|
+
if (code !== 0) {
|
|
84
|
+
// The daemon body has already logged which component failed and why.
|
|
85
|
+
const { logDir } = await import("../local/paths.js");
|
|
86
|
+
throw new CliExitError("the local stack did not start", ExitCode.General, [
|
|
87
|
+
`Check the component logs under ${logDir(homedir())}.`,
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
49
91
|
|
|
50
|
-
|
|
92
|
+
async function renderUpCard(run: UpRun, flags: OutputFlags): Promise<void> {
|
|
93
|
+
const result = CommandResult.success(run.serverOnly ? "Stigmer control plane is up" : "Stigmer local stack is up");
|
|
51
94
|
const section = result.addSection("Endpoints");
|
|
52
95
|
section.field("server", `http://localhost:${SERVER_PORT}`);
|
|
53
96
|
if (await consoleReported()) {
|
|
@@ -56,7 +99,8 @@ async function runUp(opts: { serverOnly: boolean; noWeb: boolean }, flags: Outpu
|
|
|
56
99
|
// server without one must not advertise a dead URL.
|
|
57
100
|
section.field("console", `http://localhost:${SERVER_PORT}`);
|
|
58
101
|
}
|
|
59
|
-
result.hint("Check status with: stigmer status")
|
|
102
|
+
result.hint("Check status with: stigmer status");
|
|
103
|
+
result.hint(run.foreground ? "Stop it with: Ctrl-C (or stigmer down from another shell)" : "Stop it with: stigmer down");
|
|
60
104
|
renderResult(result, resultFormat(flags));
|
|
61
105
|
}
|
|
62
106
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { mapReleaseArch, mapReleaseOs, sha256Hex } from "./artifact.js";
|
|
3
|
+
import { mapReleaseArch, mapReleaseOs, parseShasum, sha256Hex } from "./artifact.js";
|
|
4
4
|
|
|
5
5
|
describe("mapReleaseOs", () => {
|
|
6
6
|
it("maps Node platforms to release OS tokens", () => {
|
|
@@ -26,3 +26,29 @@ describe("sha256Hex", () => {
|
|
|
26
26
|
expect(sha256Hex(bytes)).toBe(expected);
|
|
27
27
|
});
|
|
28
28
|
});
|
|
29
|
+
|
|
30
|
+
// A release-wide `sha256sum` file is matched by filename, never by position,
|
|
31
|
+
// and the binary-mode "*" prefix is not part of a name.
|
|
32
|
+
describe("parseShasum", () => {
|
|
33
|
+
const A = "a".repeat(64);
|
|
34
|
+
const B = "b".repeat(64);
|
|
35
|
+
|
|
36
|
+
it("returns the digest on the line naming the file, wherever the line is", () => {
|
|
37
|
+
const file = `${A} first.tar.gz\n${B} second.tar.gz\n`;
|
|
38
|
+
expect(parseShasum(file, "second.tar.gz")).toBe(B);
|
|
39
|
+
expect(parseShasum(file, "first.tar.gz")).toBe(A);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("returns an empty string when no line names the file", () => {
|
|
43
|
+
expect(parseShasum(`${A} first.tar.gz\n`, "missing.tar.gz")).toBe("");
|
|
44
|
+
expect(parseShasum("", "missing.tar.gz")).toBe("");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("accepts sha256sum's binary-mode marker and normalises the hex to lowercase", () => {
|
|
48
|
+
expect(parseShasum(`${A.toUpperCase()} *first.tar.gz\n`, "first.tar.gz")).toBe(A);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("ignores blank and malformed lines", () => {
|
|
52
|
+
expect(parseShasum(`\n\nnot-a-digest\n${B} x.tar.gz\n`, "x.tar.gz")).toBe(B);
|
|
53
|
+
});
|
|
54
|
+
});
|
package/src/local/artifact.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// `.tar.gz`: release platform/arch mapping, a fetch + gunzip + minimal tar
|
|
3
3
|
// reader, optional sha256 verification, and an executable write.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
5
|
+
// The Temporal CLI downloader (`temporal/download.ts`) builds on this, and any
|
|
6
|
+
// future release-binary downloader should too, so the fetch/verify/extract
|
|
7
|
+
// contract lives in exactly one place. (The `stigmer-server` Go binary was its
|
|
8
|
+
// second consumer until the server became an npm artifact.) The tar reader is a
|
|
9
|
+
// tiny POSIX/ustar implementation: no native `tar` dependency, which keeps the
|
|
10
|
+
// base install lean (DD-002).
|
|
10
11
|
|
|
11
12
|
import { createHash } from "node:crypto";
|
|
12
13
|
import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -43,9 +44,11 @@ export interface TarballBinarySource {
|
|
|
43
44
|
/** URL of the `.tar.gz` archive. */
|
|
44
45
|
url: string;
|
|
45
46
|
/**
|
|
46
|
-
* URL of a `shasum -a 256`-format checksum file
|
|
47
|
-
*
|
|
48
|
-
*
|
|
47
|
+
* URL of a `shasum -a 256`-format checksum file covering {@link url}. The
|
|
48
|
+
* file may list many assets (a release's `checksums.txt`); the line whose
|
|
49
|
+
* filename is the archive's basename is the one that counts. When set, the
|
|
50
|
+
* downloaded archive's sha256 is verified against it before extraction and
|
|
51
|
+
* any mismatch — or a file with no entry for the archive — aborts the install.
|
|
49
52
|
*/
|
|
50
53
|
checksumUrl?: string;
|
|
51
54
|
/** Basename of the entry to extract from the archive. */
|
|
@@ -69,11 +72,12 @@ export async function fetchTarballBinary(src: TarballBinarySource): Promise<void
|
|
|
69
72
|
const archive = await fetchBytes(doFetch, src.url, src.label);
|
|
70
73
|
|
|
71
74
|
if (src.checksumUrl !== undefined) {
|
|
72
|
-
const
|
|
75
|
+
const archiveName = archiveBasename(src.url);
|
|
76
|
+
const expected = parseShasum(await fetchText(doFetch, src.checksumUrl, `${src.label} checksum`), archiveName);
|
|
73
77
|
const actual = sha256Hex(archive);
|
|
74
78
|
if (expected === "" || expected !== actual) {
|
|
75
79
|
throw new CliExitError(`${src.label} checksum mismatch — refusing to use the download`, ExitCode.General, [
|
|
76
|
-
`expected: ${expected ||
|
|
80
|
+
`expected: ${expected || `(no entry for ${archiveName} in ${src.checksumUrl})`}`,
|
|
77
81
|
`actual: ${actual}`,
|
|
78
82
|
`archive: ${src.url}`,
|
|
79
83
|
]);
|
|
@@ -121,9 +125,27 @@ async function doFetchOrThrow(doFetch: typeof fetch, url: string, label: string)
|
|
|
121
125
|
return res;
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
/**
|
|
129
|
+
* The sha256 a `shasum`/`sha256sum`-format file records for `filename`, lowercase
|
|
130
|
+
* hex, or "" when the file has no entry for it. Each line is "<hex> <filename>";
|
|
131
|
+
* `sha256sum -b` writes the filename with a leading "*" (binary mode), which is
|
|
132
|
+
* not part of the name. A release-wide file lists every asset, so the match is
|
|
133
|
+
* by filename, never by position.
|
|
134
|
+
*/
|
|
135
|
+
export function parseShasum(content: string, filename: string): string {
|
|
136
|
+
for (const line of content.split("\n")) {
|
|
137
|
+
const [hex, name] = line.trim().split(/\s+/, 2);
|
|
138
|
+
if (hex === undefined || name === undefined) continue;
|
|
139
|
+
if (name.replace(/^\*/, "") === filename) return hex.toLowerCase();
|
|
140
|
+
}
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// The archive's basename as the checksum file names it: the last path segment
|
|
145
|
+
// of the URL, with any query string already excluded by URL parsing.
|
|
146
|
+
function archiveBasename(url: string): string {
|
|
147
|
+
const segments = new URL(url).pathname.split("/");
|
|
148
|
+
return segments[segments.length - 1] ?? "";
|
|
127
149
|
}
|
|
128
150
|
|
|
129
151
|
/**
|
|
@@ -94,6 +94,7 @@ export function buildComponents(config: DaemonConfig, base: NodeJS.ProcessEnv =
|
|
|
94
94
|
// The server is `node <entry>` — the runner's launch shape, one child
|
|
95
95
|
// contract for both components.
|
|
96
96
|
resolve: () => ({
|
|
97
|
+
name: "stigmer-server",
|
|
97
98
|
command: config.server.nodeBin,
|
|
98
99
|
args: [config.server.entryPath],
|
|
99
100
|
env: buildServerEnv(config, base),
|
|
@@ -113,6 +114,7 @@ export function buildComponents(config: DaemonConfig, base: NodeJS.ProcessEnv =
|
|
|
113
114
|
pidFile: join(config.dataDir, RUNNER_PID_FILE),
|
|
114
115
|
critical: false,
|
|
115
116
|
resolve: () => ({
|
|
117
|
+
name: "runner",
|
|
116
118
|
command: runner.nodeBin,
|
|
117
119
|
args: [runner.entryPath],
|
|
118
120
|
cwd: join(config.dataDir, "workspace"),
|
|
@@ -35,6 +35,7 @@ describe("NodeProcessHost (real spawn)", () => {
|
|
|
35
35
|
|
|
36
36
|
const host = new NodeProcessHost();
|
|
37
37
|
const request: SpawnRequest = {
|
|
38
|
+
name: "runner",
|
|
38
39
|
command: process.execPath,
|
|
39
40
|
args: [script],
|
|
40
41
|
env: process.env,
|
|
@@ -57,6 +58,38 @@ describe("NodeProcessHost (real spawn)", () => {
|
|
|
57
58
|
await exited;
|
|
58
59
|
expect(handle.hasExited()).toBe(true);
|
|
59
60
|
});
|
|
61
|
+
|
|
62
|
+
// The foreground launcher's window into the children: every complete line,
|
|
63
|
+
// tagged with the component, in order within a stream; a partial trailing
|
|
64
|
+
// line is delivered at exit; the log file still receives the same bytes.
|
|
65
|
+
it("mirrors complete lines tagged with the component, flushing the tail at exit", async () => {
|
|
66
|
+
const dir = tempDir();
|
|
67
|
+
const script = join(dir, "chatty-child.cjs");
|
|
68
|
+
writeFileSync(
|
|
69
|
+
script,
|
|
70
|
+
// Two writes that split a line across chunks, one stderr line, and a
|
|
71
|
+
// final line with no newline.
|
|
72
|
+
`process.stdout.write("first li");\n` +
|
|
73
|
+
`process.stdout.write("ne\\nsecond line\\n");\n` +
|
|
74
|
+
`process.stderr.write("a warning\\n");\n` +
|
|
75
|
+
`process.stdout.write("tail without newline");\n` +
|
|
76
|
+
`setTimeout(() => process.exit(0), 50);\n`,
|
|
77
|
+
);
|
|
78
|
+
const logFile = join(dir, "child.log");
|
|
79
|
+
const mirrored: string[] = [];
|
|
80
|
+
const host = new NodeProcessHost({ mirror: (component, line) => mirrored.push(`${component}|${line}`) });
|
|
81
|
+
|
|
82
|
+
const handle = host.spawn({ name: "stigmer-server", command: process.execPath, args: [script], env: process.env, logFile });
|
|
83
|
+
await new Promise<void>((resolve) => handle.onExit(() => resolve()));
|
|
84
|
+
|
|
85
|
+
expect(mirrored.filter((l) => l !== "stigmer-server|a warning")).toEqual([
|
|
86
|
+
"stigmer-server|first line",
|
|
87
|
+
"stigmer-server|second line",
|
|
88
|
+
"stigmer-server|tail without newline",
|
|
89
|
+
]);
|
|
90
|
+
expect(mirrored).toContain("stigmer-server|a warning");
|
|
91
|
+
await expect.poll(() => readFileSync(logFile, "utf8")).toContain("first line\nsecond line\n");
|
|
92
|
+
});
|
|
60
93
|
});
|
|
61
94
|
|
|
62
95
|
// ---- Integration 2: the full daemon body, with a fake process host + fake
|
package/src/local/daemon/host.ts
CHANGED
|
@@ -7,13 +7,32 @@
|
|
|
7
7
|
// which is what lets `status` report "runner actually polling" instead of mere
|
|
8
8
|
// liveness. Logs survive normally because the daemon outlives its children; an
|
|
9
9
|
// abnormal daemon death is handled by orphan cleanup on the next `up`.
|
|
10
|
+
//
|
|
11
|
+
// An optional mirror receives every complete line a child writes, tagged with
|
|
12
|
+
// the component's name. The foreground launcher (`stigmer up --foreground`)
|
|
13
|
+
// uses it to show the stack's output in the terminal — or in `docker logs` —
|
|
14
|
+
// while the log files keep receiving the same bytes. The detached daemon
|
|
15
|
+
// installs no mirror: its own stdout is already redirected to daemon.log.
|
|
10
16
|
|
|
11
17
|
import { spawn } from "node:child_process";
|
|
12
18
|
import { createWriteStream } from "node:fs";
|
|
13
19
|
import { killProcessGroup } from "../state/proc.js";
|
|
14
20
|
import type { ChildHandle, Clock, ExitInfo, ProcessHost, SpawnRequest } from "./types.js";
|
|
15
21
|
|
|
22
|
+
/** Receives one complete output line from a child, with the component that wrote it. */
|
|
23
|
+
export type OutputMirror = (component: string, line: string) => void;
|
|
24
|
+
|
|
25
|
+
export interface NodeProcessHostOptions {
|
|
26
|
+
mirror?: OutputMirror;
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
export class NodeProcessHost implements ProcessHost {
|
|
30
|
+
private readonly mirror: OutputMirror | undefined;
|
|
31
|
+
|
|
32
|
+
constructor(options: NodeProcessHostOptions = {}) {
|
|
33
|
+
this.mirror = options.mirror;
|
|
34
|
+
}
|
|
35
|
+
|
|
17
36
|
spawn(request: SpawnRequest): ChildHandle {
|
|
18
37
|
const out = createWriteStream(request.logFile, { flags: "a" });
|
|
19
38
|
const child = spawn(request.command, request.args, {
|
|
@@ -31,8 +50,14 @@ export class NodeProcessHost implements ProcessHost {
|
|
|
31
50
|
// Keep a small rolling tail so a marker split across chunks is still found.
|
|
32
51
|
let tail = "";
|
|
33
52
|
const marker = request.readinessMarker;
|
|
53
|
+
// One line assembler per stream: a chunk can end mid-line, and the two
|
|
54
|
+
// streams interleave, so each keeps its own partial line.
|
|
55
|
+
const mirrorStdout = this.lineMirror(request.name);
|
|
56
|
+
const mirrorStderr = this.lineMirror(request.name);
|
|
57
|
+
|
|
34
58
|
child.stdout?.on("data", (chunk: Buffer) => {
|
|
35
59
|
out.write(chunk);
|
|
60
|
+
mirrorStdout(chunk);
|
|
36
61
|
if (marker !== undefined && !ready) {
|
|
37
62
|
tail = (tail + chunk.toString("utf8")).slice(-Math.max(marker.length * 2, 256));
|
|
38
63
|
if (tail.includes(marker)) {
|
|
@@ -41,10 +66,15 @@ export class NodeProcessHost implements ProcessHost {
|
|
|
41
66
|
}
|
|
42
67
|
}
|
|
43
68
|
});
|
|
44
|
-
child.stderr?.on("data", (chunk: Buffer) =>
|
|
69
|
+
child.stderr?.on("data", (chunk: Buffer) => {
|
|
70
|
+
out.write(chunk);
|
|
71
|
+
mirrorStderr(chunk);
|
|
72
|
+
});
|
|
45
73
|
|
|
46
74
|
child.on("exit", (code, signal) => {
|
|
47
75
|
exited = true;
|
|
76
|
+
mirrorStdout(null);
|
|
77
|
+
mirrorStderr(null);
|
|
48
78
|
out.end();
|
|
49
79
|
exitCb?.({ code, signal });
|
|
50
80
|
});
|
|
@@ -70,6 +100,25 @@ export class NodeProcessHost implements ProcessHost {
|
|
|
70
100
|
},
|
|
71
101
|
};
|
|
72
102
|
}
|
|
103
|
+
|
|
104
|
+
// Assemble complete lines from a byte stream and hand each to the mirror. A
|
|
105
|
+
// `null` chunk flushes the trailing partial line at exit. Without a mirror
|
|
106
|
+
// this is a no-op closure, so the hot path pays nothing in the detached daemon.
|
|
107
|
+
private lineMirror(component: string): (chunk: Buffer | null) => void {
|
|
108
|
+
const mirror = this.mirror;
|
|
109
|
+
if (mirror === undefined) return () => {};
|
|
110
|
+
let partial = "";
|
|
111
|
+
return (chunk) => {
|
|
112
|
+
if (chunk === null) {
|
|
113
|
+
if (partial !== "") mirror(component, partial);
|
|
114
|
+
partial = "";
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const lines = (partial + chunk.toString("utf8")).split("\n");
|
|
118
|
+
partial = lines.pop() ?? "";
|
|
119
|
+
for (const line of lines) mirror(component, line);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
73
122
|
}
|
|
74
123
|
|
|
75
124
|
/** Real wall-clock implementation of Clock. */
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
export { buildComponents, buildRunnerEnv, buildServerEnv } from "./components.js";
|
|
4
4
|
export { type DaemonConfig, type DaemonEnvInputs, DaemonEnvVar, buildDaemonEnv, readDaemonConfig } from "./env.js";
|
|
5
|
-
export { NodeProcessHost, systemClock } from "./host.js";
|
|
6
|
-
export { down, isRunning, type UpOptions, up } from "./launch.js";
|
|
7
|
-
export { type InternalDaemonDeps, type TemporalControl, runInternalDaemon } from "./process.js";
|
|
5
|
+
export { NodeProcessHost, type NodeProcessHostOptions, type OutputMirror, systemClock } from "./host.js";
|
|
6
|
+
export { down, isRunning, type UpForegroundDeps, type UpOptions, up, upForeground } from "./launch.js";
|
|
7
|
+
export { type InternalDaemonDeps, type TemporalControl, runInternalDaemon, waitForShutdownSignal } from "./process.js";
|
|
8
8
|
export {
|
|
9
9
|
HEALTH_CHECK_INTERVAL_MS,
|
|
10
10
|
MAX_RESTARTS,
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// Pins the foreground launcher's contract with the daemon body: the config it
|
|
2
|
+
// hands over is the detached shape's, encoded through the same env contract;
|
|
3
|
+
// the children inherit that built environment; the post-readiness work (the
|
|
4
|
+
// bootstrap, the startup record, the caller's onReady) runs from onStarted;
|
|
5
|
+
// the daemon's exit code is the launcher's. Resolution is driven through the
|
|
6
|
+
// same overrides a container sets (STIGMER_SERVER_DIR, STIGMER_RUNNER_DIR,
|
|
7
|
+
// STIGMER_TEMPORAL_BIN), so nothing is downloaded or installed.
|
|
8
|
+
|
|
9
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
13
|
+
import { SERVER_PORT } from "../constants.js";
|
|
14
|
+
import { tcpConnects } from "../net/tcp.js";
|
|
15
|
+
import { loadStartupConfig } from "../state/startup-config.js";
|
|
16
|
+
import { DaemonEnvVar } from "./env.js";
|
|
17
|
+
import { upForeground } from "./launch.js";
|
|
18
|
+
import type { InternalDaemonDeps } from "./process.js";
|
|
19
|
+
|
|
20
|
+
// The launcher refuses to start beside a stack already serving on the server
|
|
21
|
+
// port — including a developer's own `stigmer up`. Report SKIPPED rather than
|
|
22
|
+
// a false failure in that case.
|
|
23
|
+
const serverPortBusy = await tcpConnects(SERVER_PORT, "127.0.0.1", 300);
|
|
24
|
+
|
|
25
|
+
function tempDir(prefix: string): string {
|
|
26
|
+
return mkdtempSync(join(tmpdir(), prefix));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// A built package in the shape the resolvers accept: package.json + dist/main.js.
|
|
30
|
+
function builtPackage(prefix: string): string {
|
|
31
|
+
const dir = tempDir(prefix);
|
|
32
|
+
writeFileSync(join(dir, "package.json"), "{}");
|
|
33
|
+
mkdirSync(join(dir, "dist"));
|
|
34
|
+
writeFileSync(join(dir, "dist", "main.js"), "//");
|
|
35
|
+
return dir;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const TOUCHED = ["STIGMER_SERVER_DIR", "STIGMER_RUNNER_DIR", "STIGMER_TEMPORAL_BIN", "STIGMER_NODE_BIN", "ANTHROPIC_API_KEY"] as const;
|
|
39
|
+
let saved: Record<string, string | undefined>;
|
|
40
|
+
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
saved = {};
|
|
43
|
+
for (const key of TOUCHED) {
|
|
44
|
+
saved[key] = process.env[key];
|
|
45
|
+
delete process.env[key];
|
|
46
|
+
}
|
|
47
|
+
process.env.STIGMER_SERVER_DIR = builtPackage("stigmer-fg-server-");
|
|
48
|
+
process.env.STIGMER_RUNNER_DIR = builtPackage("stigmer-fg-runner-");
|
|
49
|
+
const temporalBin = join(tempDir("stigmer-fg-temporal-"), "temporal");
|
|
50
|
+
writeFileSync(temporalBin, "#!/bin/sh\n");
|
|
51
|
+
process.env.STIGMER_TEMPORAL_BIN = temporalBin;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
for (const key of TOUCHED) {
|
|
56
|
+
if (saved[key] === undefined) delete process.env[key];
|
|
57
|
+
else process.env[key] = saved[key];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe.skipIf(serverPortBusy)("upForeground", () => {
|
|
62
|
+
it("runs the daemon body in-process with the detached shape's config and env, bootstrapping from onStarted", async () => {
|
|
63
|
+
const home = tempDir("stigmer-fg-home-");
|
|
64
|
+
process.env.ANTHROPIC_API_KEY = "sk-test";
|
|
65
|
+
const order: string[] = [];
|
|
66
|
+
let captured: InternalDaemonDeps | null = null;
|
|
67
|
+
|
|
68
|
+
const code = await upForeground({ noWeb: true }, home, {
|
|
69
|
+
runDaemon: async (deps) => {
|
|
70
|
+
captured = deps;
|
|
71
|
+
order.push("daemon:started");
|
|
72
|
+
await deps.onStarted?.();
|
|
73
|
+
order.push("daemon:waiting");
|
|
74
|
+
return 0;
|
|
75
|
+
},
|
|
76
|
+
bootstrap: async () => {
|
|
77
|
+
order.push("bootstrap");
|
|
78
|
+
},
|
|
79
|
+
onReady: () => {
|
|
80
|
+
order.push("onReady");
|
|
81
|
+
},
|
|
82
|
+
waitForShutdown: () => Promise.resolve(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(code).toBe(0);
|
|
86
|
+
expect(order).toEqual(["daemon:started", "bootstrap", "onReady", "daemon:waiting"]);
|
|
87
|
+
|
|
88
|
+
const deps = captured as unknown as InternalDaemonDeps;
|
|
89
|
+
// The config is the env contract read back — the detached daemon's view.
|
|
90
|
+
expect(deps.config?.dataDir).toBe(join(home, ".stigmer", "data"));
|
|
91
|
+
expect(deps.config?.temporalManaged).toBe(true);
|
|
92
|
+
expect(deps.config?.noWeb).toBe(true);
|
|
93
|
+
expect(deps.config?.server.entryPath).toBe(join(process.env.STIGMER_SERVER_DIR!, "dist", "main.js"));
|
|
94
|
+
expect(deps.config?.runner?.entryPath).toBe(join(process.env.STIGMER_RUNNER_DIR!, "dist", "main.js"));
|
|
95
|
+
expect(deps.config?.anthropicApiKey).toBe("sk-test");
|
|
96
|
+
// The children inherit the built environment, contract variables included.
|
|
97
|
+
expect(deps.env?.[DaemonEnvVar.DataDir]).toBe(join(home, ".stigmer", "data"));
|
|
98
|
+
expect(deps.env?.[DaemonEnvVar.ServerEntry]).toBe(deps.config?.server.entryPath);
|
|
99
|
+
// The startup record names this process as the daemon.
|
|
100
|
+
expect(loadStartupConfig(join(home, ".stigmer", "data"))?.stigmer_server_pid).toBe(process.pid);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("propagates the daemon's failure exit code without bootstrapping", async () => {
|
|
104
|
+
const home = tempDir("stigmer-fg-home-");
|
|
105
|
+
const bootstrap = vi.fn(async () => {});
|
|
106
|
+
|
|
107
|
+
const code = await upForeground({}, home, {
|
|
108
|
+
// A critical component failed to start: the body returns 1 before onStarted.
|
|
109
|
+
runDaemon: async () => 1,
|
|
110
|
+
bootstrap,
|
|
111
|
+
waitForShutdown: () => Promise.resolve(),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(code).toBe(1);
|
|
115
|
+
expect(bootstrap).not.toHaveBeenCalled();
|
|
116
|
+
expect(loadStartupConfig(join(home, ".stigmer", "data"))).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("omits the runner from the contract in server-only mode", async () => {
|
|
120
|
+
const home = tempDir("stigmer-fg-home-");
|
|
121
|
+
let captured: InternalDaemonDeps | null = null;
|
|
122
|
+
|
|
123
|
+
await upForeground({ serverOnly: true }, home, {
|
|
124
|
+
runDaemon: async (deps) => {
|
|
125
|
+
captured = deps;
|
|
126
|
+
return 0;
|
|
127
|
+
},
|
|
128
|
+
bootstrap: async () => {},
|
|
129
|
+
waitForShutdown: () => Promise.resolve(),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const deps = captured as unknown as InternalDaemonDeps;
|
|
133
|
+
expect(deps.config?.serverOnly).toBe(true);
|
|
134
|
+
expect(deps.config?.runner).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
});
|