@stigmer/cli 3.12.9 → 3.14.0-dev.20260910084630

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/auth/login.d.ts.map +1 -1
  2. package/auth/login.js +30 -5
  3. package/auth/login.js.map +1 -1
  4. package/auth/token.d.ts +10 -5
  5. package/auth/token.d.ts.map +1 -1
  6. package/auth/token.js +30 -21
  7. package/auth/token.js.map +1 -1
  8. package/commands/apikey/index.d.ts.map +1 -1
  9. package/commands/apikey/index.js +11 -5
  10. package/commands/apikey/index.js.map +1 -1
  11. package/commands/auth/index.d.ts.map +1 -1
  12. package/commands/auth/index.js +19 -8
  13. package/commands/auth/index.js.map +1 -1
  14. package/commands/config/backend.d.ts.map +1 -1
  15. package/commands/config/backend.js +134 -12
  16. package/commands/config/backend.js.map +1 -1
  17. package/commands/connect.d.ts.map +1 -1
  18. package/commands/connect.js +6 -3
  19. package/commands/connect.js.map +1 -1
  20. package/commands/share.d.ts.map +1 -1
  21. package/commands/share.js +8 -6
  22. package/commands/share.js.map +1 -1
  23. package/commands/up.d.ts.map +1 -1
  24. package/commands/up.js +22 -6
  25. package/commands/up.js.map +1 -1
  26. package/config/config.d.ts +56 -7
  27. package/config/config.d.ts.map +1 -1
  28. package/config/config.js +115 -16
  29. package/config/config.js.map +1 -1
  30. package/config/index.d.ts +1 -1
  31. package/config/index.d.ts.map +1 -1
  32. package/config/index.js +1 -1
  33. package/config/index.js.map +1 -1
  34. package/config/keys.d.ts +1 -1
  35. package/config/keys.d.ts.map +1 -1
  36. package/config/keys.js +29 -6
  37. package/config/keys.js.map +1 -1
  38. package/config/resolve.d.ts +32 -21
  39. package/config/resolve.d.ts.map +1 -1
  40. package/config/resolve.js +80 -39
  41. package/config/resolve.js.map +1 -1
  42. package/local/constants.d.ts +8 -3
  43. package/local/constants.d.ts.map +1 -1
  44. package/local/constants.js +8 -3
  45. package/local/constants.js.map +1 -1
  46. package/local/daemon/components.d.ts.map +1 -1
  47. package/local/daemon/components.js +4 -2
  48. package/local/daemon/components.js.map +1 -1
  49. package/local/daemon/env.d.ts +16 -3
  50. package/local/daemon/env.d.ts.map +1 -1
  51. package/local/daemon/env.js +16 -3
  52. package/local/daemon/env.js.map +1 -1
  53. package/local/daemon/launch.d.ts.map +1 -1
  54. package/local/daemon/launch.js +5 -4
  55. package/local/daemon/launch.js.map +1 -1
  56. package/local/daemon/process.d.ts.map +1 -1
  57. package/local/daemon/process.js +8 -5
  58. package/local/daemon/process.js.map +1 -1
  59. package/local/runtime/index.d.ts +2 -2
  60. package/local/runtime/index.d.ts.map +1 -1
  61. package/local/runtime/index.js +4 -2
  62. package/local/runtime/index.js.map +1 -1
  63. package/local/runtime/node.d.ts +8 -0
  64. package/local/runtime/node.d.ts.map +1 -1
  65. package/local/runtime/node.js +74 -23
  66. package/local/runtime/node.js.map +1 -1
  67. package/local/runtime/runner.d.ts +2 -1
  68. package/local/runtime/runner.d.ts.map +1 -1
  69. package/local/runtime/runner.js +4 -31
  70. package/local/runtime/runner.js.map +1 -1
  71. package/local/runtime/runtimes-install.d.ts +13 -0
  72. package/local/runtime/runtimes-install.d.ts.map +1 -0
  73. package/local/runtime/runtimes-install.js +60 -0
  74. package/local/runtime/runtimes-install.js.map +1 -0
  75. package/local/runtime/server.d.ts +26 -30
  76. package/local/runtime/server.d.ts.map +1 -1
  77. package/local/runtime/server.js +106 -108
  78. package/local/runtime/server.js.map +1 -1
  79. package/local/seedpack/content.d.ts +3 -3
  80. package/local/seedpack/content.d.ts.map +1 -1
  81. package/local/seedpack/content.js +19 -13
  82. package/local/seedpack/content.js.map +1 -1
  83. package/local/status.d.ts.map +1 -1
  84. package/local/status.js +4 -2
  85. package/local/status.js.map +1 -1
  86. package/local/webconsole/index.d.ts +2 -3
  87. package/local/webconsole/index.d.ts.map +1 -1
  88. package/local/webconsole/index.js +24 -10
  89. package/local/webconsole/index.js.map +1 -1
  90. package/package.json +5 -5
  91. package/resources/connect/connect.d.ts +4 -3
  92. package/resources/connect/connect.d.ts.map +1 -1
  93. package/resources/connect/connect.js +17 -5
  94. package/resources/connect/connect.js.map +1 -1
  95. package/resources/connect/oauth.d.ts +5 -2
  96. package/resources/connect/oauth.d.ts.map +1 -1
  97. package/resources/connect/oauth.js +5 -4
  98. package/resources/connect/oauth.js.map +1 -1
  99. package/src/auth/login.ts +54 -9
  100. package/src/auth/token.test.ts +69 -13
  101. package/src/auth/token.ts +46 -22
  102. package/src/client/client.test.ts +10 -2
  103. package/src/commands/apikey/index.ts +42 -11
  104. package/src/commands/auth/index.ts +52 -14
  105. package/src/commands/config/backend.test.ts +122 -0
  106. package/src/commands/config/backend.ts +195 -14
  107. package/src/commands/connect.test.ts +22 -4
  108. package/src/commands/connect.ts +37 -13
  109. package/src/commands/share.ts +36 -16
  110. package/src/commands/up.ts +24 -6
  111. package/src/config/config.test.ts +62 -6
  112. package/src/config/config.ts +165 -24
  113. package/src/config/index.ts +6 -0
  114. package/src/config/keys.test.ts +27 -4
  115. package/src/config/keys.ts +46 -9
  116. package/src/config/resolve.test.ts +135 -34
  117. package/src/config/resolve.ts +88 -38
  118. package/src/local/constants.ts +8 -4
  119. package/src/local/daemon/components.test.ts +9 -1
  120. package/src/local/daemon/components.ts +4 -2
  121. package/src/local/daemon/daemon.integration.test.ts +1 -1
  122. package/src/local/daemon/env.test.ts +15 -4
  123. package/src/local/daemon/env.ts +33 -5
  124. package/src/local/daemon/launch.ts +5 -4
  125. package/src/local/daemon/process.ts +7 -4
  126. package/src/local/runtime/index.ts +6 -5
  127. package/src/local/runtime/node.ts +99 -23
  128. package/src/local/runtime/runner.ts +5 -36
  129. package/src/local/runtime/runtime.test.ts +58 -14
  130. package/src/local/runtime/runtimes-install.test.ts +56 -0
  131. package/src/local/runtime/runtimes-install.ts +72 -0
  132. package/src/local/runtime/server.test.ts +178 -114
  133. package/src/local/runtime/server.ts +149 -129
  134. package/src/local/seedpack/content.ts +52 -21
  135. package/src/local/status.ts +4 -2
  136. package/src/local/webconsole/index.ts +27 -10
  137. package/src/resources/connect/connect.integration.test.ts +79 -26
  138. package/src/resources/connect/connect.ts +72 -19
  139. package/src/resources/connect/oauth.test.ts +38 -12
  140. package/src/resources/connect/oauth.ts +27 -11
  141. package/src/resources/share.test.ts +2 -2
@@ -1,20 +1,20 @@
1
- // Resolution and on-demand acquisition of the `stigmer-server` control plane.
1
+ // Resolution and on-demand acquisition of the stigmer server — the
2
+ // TypeScript implementation serving since the DD-006 cutover (D4 #24; the Go
3
+ // binary ladder that backed rollback retired with #25).
2
4
  //
3
- // DD-003: a TypeScript CLI cannot `go:embed` a Go binary, so it resolves an
4
- // existing `stigmer-server` (dev build / Homebrew / a prior download) and, when
5
- // none is present, downloads the standalone release asset into ~/.stigmer/bin and
6
- // verifies its sha256 before first use. The fetch/extract mechanics are shared
7
- // with the Temporal downloader (`../artifact.ts`); the one deliberate difference
8
- // is the checksum step — this is our own executable, and DD-003 makes integrity
9
- // non-negotiable.
5
+ // The server is launched exactly like the runner: a compiled `node main.js`,
6
+ // never `tsx src/main.ts` (the workers bundle Temporal workflows on boot in
7
+ // dev shape, and the slim artifact ships pre-built bundles — either way the
8
+ // entry must be compiled; see the server package's workflow-source.ts).
10
9
  //
11
- // Resolution order (first existing hit wins; download is the last resort):
12
- // 1. STIGMER_SERVER_BIN — explicit override (tests, custom installs)
13
- // 2. repo `bin/stigmer-server` — the dev build (`make build`)
14
- // 3. ~/bin/stigmer-server — a common local install location
15
- // 4. ~/.stigmer/bin/stigmer-server — a previously-downloaded release asset
16
- // 5. PATH — `stigmer-server`
17
- // 6. download the pinned release asset into ~/.stigmer/bin (checksum-verified)
10
+ // Resolution order (the D2 §6 switch semantics):
11
+ // 1. STIGMER_SERVER_DIR — an explicit server package dir (dist/main.js
12
+ // required), the STIGMER_RUNNER_DIR mirror.
13
+ // 2. The repo-tree server package (dev; build required).
14
+ // 3. The published `@stigmer/server-slim`, installed on demand into
15
+ // ~/.stigmer/runtimes/<version>/ alongside the runner's package — one
16
+ // CJS main.js, pre-built workflow bundles, and the per-platform
17
+ // Temporal native bridge selected by npm via optionalDependencies.
18
18
 
19
19
  import { existsSync } from "node:fs";
20
20
  import { homedir } from "node:os";
@@ -22,148 +22,168 @@ import { dirname, join } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import { CliExitError } from "../../errors/cli-exit-error.js";
24
24
  import { ExitCode } from "../../errors/exit-codes.js";
25
+ import { log } from "../../logger.js";
25
26
  import { VERSION } from "../../version.js";
26
- import { fetchTarballBinary, mapReleaseArch, mapReleaseOs } from "../artifact.js";
27
- import { binDir } from "../paths.js";
28
- import { which } from "./which.js";
29
-
30
- const SERVER_BINARY = "stigmer-server";
31
- const GITHUB_REPO = "stigmer/stigmer";
32
-
33
- // Platform/arch combos for which `release.cli.yaml` publishes a stigmer-server
34
- // asset. The npm CLI installs on more platforms than this (e.g. linux-arm64,
35
- // Windows), so an unsupported `stigmer up` must fail with clear guidance rather
36
- // than a confusing 404.
37
- const SUPPORTED_PLATFORMS = new Set(["darwin-arm64", "darwin-amd64", "linux-amd64"]);
38
-
39
- /**
40
- * Find an already-present `stigmer-server` binary, or null. Pure: never
41
- * downloads. `home` is injectable for tests.
42
- */
43
- export function resolveServerBinary(home: string = homedir()): string | null {
44
- for (const candidate of serverCandidates(home)) {
45
- if (existsSync(candidate)) return candidate;
46
- }
47
- return which(SERVER_BINARY);
48
- }
27
+ import { runtimesDir } from "../paths.js";
28
+ import type { ServerLaunch } from "../daemon/env.js";
29
+ import { resolveServerNode } from "./node.js";
30
+ import {
31
+ ensureRuntimesRoot,
32
+ isAcquirableRelease,
33
+ npmInstallIntoRuntimes,
34
+ type NpmInstall,
35
+ } from "./runtimes-install.js";
36
+
37
+ const SLIM_PACKAGE = "@stigmer/server-slim";
49
38
 
50
39
  export interface EnsureServerOptions {
51
40
  home?: string;
52
- /** Release version to download if needed (defaults to the CLI's own version). */
41
+ /** Release version of the slim server to acquire (defaults to the CLI version). */
53
42
  version?: string;
54
- /** Override the fetch implementation (tests). */
55
- fetchImpl?: typeof fetch;
43
+ /** Node resolver (injectable for tests). */
44
+ node?: () => string;
45
+ /** npm install implementation (injectable for tests). */
46
+ install?: NpmInstall;
56
47
  }
57
48
 
58
49
  /**
59
- * Ensure a `stigmer-server` binary is available, returning its path. Reuses an
60
- * existing binary if found; otherwise downloads the pinned release asset into
61
- * ~/.stigmer/bin (checksum-verified). Throws actionable guidance when no binary
62
- * exists and a download is not possible (a source/dev build, or an unsupported
63
- * platform).
50
+ * Resolve what the daemon launches as `stigmer-server`: the explicit
51
+ * STIGMER_SERVER_DIR override, then the repo tree, then acquiring the
52
+ * published slim package. Throws actionable guidance on a missing build, an
53
+ * invalid override, or a non-release CLI build with nothing local.
64
54
  */
65
- export async function ensureServerBinary(opts: EnsureServerOptions = {}): Promise<string> {
66
- const home = opts.home ?? homedir();
67
- const existing = resolveServerBinary(home);
68
- if (existing !== null) return existing;
69
-
70
- const version = opts.version ?? VERSION;
71
- if (!isDownloadableRelease(version)) {
72
- throw notFoundError();
73
- }
74
-
75
- const binPath = join(binDir(home), SERVER_BINARY);
76
- await downloadServerBinary({ version, binPath, fetchImpl: opts.fetchImpl });
77
- return binPath;
78
- }
79
-
80
- export interface ServerDownloadTarget {
81
- /** Release version, e.g. "0.5.0" or "0.5.0-rc.1" (with or without a leading "v"). */
82
- version: string;
83
- /** Absolute path to write the extracted `stigmer-server` binary to. */
84
- binPath: string;
85
- /** Node platform (defaults to process.platform). */
86
- platform?: NodeJS.Platform;
87
- /** Node arch (defaults to process.arch). */
88
- arch?: string;
89
- /** Override the fetch implementation (tests). */
90
- fetchImpl?: typeof fetch;
55
+ export function ensureServer(opts: EnsureServerOptions = {}): ServerLaunch {
56
+ const node = opts.node ?? resolveServerNode;
57
+ const local = resolveServerTs(node);
58
+ if (local !== null) return local;
59
+ return acquireServer({ ...opts, node });
91
60
  }
92
61
 
93
62
  /**
94
- * Download, checksum-verify, and install the standalone `stigmer-server` release
95
- * asset. Throws a {@link CliExitError} on an unsupported platform or any
96
- * network/checksum/extraction failure.
63
+ * Resolve a repo-tree TS server (dev) or an explicit STIGMER_SERVER_DIR, or
64
+ * null when neither is present (the caller then acquires the slim package).
65
+ * Throws when an override is set but invalid, or when a found server is not
66
+ * built — both are actionable user-facing conditions, not a reason to
67
+ * silently download. `node` is injectable for tests.
97
68
  */
98
- export async function downloadServerBinary(target: ServerDownloadTarget): Promise<void> {
99
- const os = mapReleaseOs(target.platform ?? process.platform);
100
- const arch = mapReleaseArch(target.arch ?? process.arch);
101
- const platformKey = `${os}-${arch}`;
102
- if (!SUPPORTED_PLATFORMS.has(platformKey)) {
103
- throw unsupportedPlatformError(platformKey);
69
+ export function resolveServerTs(
70
+ node: () => string = resolveServerNode,
71
+ ): ServerLaunch | null {
72
+ const override = process.env.STIGMER_SERVER_DIR;
73
+ if (override !== undefined && override !== "") {
74
+ if (!hasPackageJson(override)) {
75
+ throw new CliExitError(
76
+ `STIGMER_SERVER_DIR is not a server package: ${override}`,
77
+ ExitCode.General,
78
+ [
79
+ "Point STIGMER_SERVER_DIR at the @stigmer/server package directory (the one with package.json).",
80
+ ],
81
+ );
82
+ }
83
+ return resolveBuiltServer(override, node);
104
84
  }
105
85
 
106
- const tag = releaseTag(target.version);
107
- const archive = `${SERVER_BINARY}-${tag}-${platformKey}.tar.gz`;
108
- const url = `https://github.com/${GITHUB_REPO}/releases/download/${tag}/${archive}`;
109
-
110
- await fetchTarballBinary({
111
- url,
112
- checksumUrl: `${url}.sha256`,
113
- entryName: SERVER_BINARY,
114
- binPath: target.binPath,
115
- label: SERVER_BINARY,
116
- fetchImpl: target.fetchImpl,
117
- });
86
+ const root = repoRoot();
87
+ if (root !== null) {
88
+ const candidate = join(root, "backend", "services", "stigmer-server");
89
+ if (hasPackageJson(candidate)) return resolveBuiltServer(candidate, node);
90
+ }
91
+ return null;
118
92
  }
119
93
 
120
- function serverCandidates(home: string): string[] {
121
- const candidates: string[] = [];
122
- const override = process.env.STIGMER_SERVER_BIN;
123
- if (override !== undefined && override !== "") candidates.push(override);
94
+ /**
95
+ * Acquire the published `@stigmer/server-slim@<version>` into
96
+ * ~/.stigmer/runtimes/<version>/ (idempotent: reuses a prior install; shares
97
+ * the install root with the runner's package) and resolve its `main.js`
98
+ * entry. The version is pinned to the CLI's own version so the server's
99
+ * protos and behavior stay in lockstep with the CLI and the runner.
100
+ */
101
+ export function acquireServer(opts: EnsureServerOptions = {}): ServerLaunch {
102
+ const home = opts.home ?? homedir();
103
+ const version = opts.version ?? VERSION;
104
+ if (!isAcquirableRelease(version)) {
105
+ throw new CliExitError(
106
+ `cannot acquire ${SLIM_PACKAGE} for a non-release build (${version})`,
107
+ ExitCode.General,
108
+ [
109
+ "Run from the repo with a built server (make build-server), or set",
110
+ "STIGMER_SERVER_DIR to a built server package.",
111
+ "On-demand acquisition is only available for published releases.",
112
+ ],
113
+ );
114
+ }
124
115
 
125
- const root = repoRoot();
126
- if (root !== null) candidates.push(join(root, "bin", SERVER_BINARY));
127
- candidates.push(join(home, "bin", SERVER_BINARY));
128
- candidates.push(join(binDir(home), SERVER_BINARY)); // a previously-downloaded asset
129
- return candidates;
130
- }
116
+ // Probe the Node capability BEFORE the download: a user on an FTS5-less
117
+ // Node must not fetch the full slim artifact only to be rejected after.
118
+ const node = opts.node ?? resolveServerNode;
119
+ const nodeBin = node();
120
+ const installDir = join(runtimesDir(home), version);
121
+ const entryPath = join(
122
+ installDir,
123
+ "node_modules",
124
+ "@stigmer",
125
+ "server-slim",
126
+ "main.js",
127
+ );
128
+
129
+ if (!existsSync(entryPath)) {
130
+ log.info(`acquiring ${SLIM_PACKAGE}`, { version, dir: installDir });
131
+ ensureRuntimesRoot(installDir);
132
+ const install = opts.install ?? npmInstallIntoRuntimes;
133
+ install(installDir, `${SLIM_PACKAGE}@${version}`);
134
+ }
131
135
 
132
- // Only tagged releases publish a downloadable asset. A source build reports the
133
- // "0.0.0-dev" sentinel and the dev npm channel stamps "<v>-dev.<stamp>" versions
134
- // (release.dev.yaml) that never cut a GitHub release — neither is downloadable.
135
- function isDownloadableRelease(version: string): boolean {
136
- return !version.includes("-dev");
137
- }
136
+ if (!existsSync(entryPath)) {
137
+ throw new CliExitError(
138
+ `${SLIM_PACKAGE} install did not produce ${entryPath}`,
139
+ ExitCode.General,
140
+ [
141
+ "The install may have skipped the platform-native package for this OS/arch.",
142
+ `Remove ${installDir} and retry, or set STIGMER_SERVER_DIR to a built server.`,
143
+ ],
144
+ );
145
+ }
138
146
 
139
- // The npm package version maps to the GitHub release tag by prefixing "v"
140
- // (npm 0.5.0 -> tag v0.5.0; npm 0.5.0-rc.1 -> tag v0.5.0-rc.1).
141
- function releaseTag(version: string): string {
142
- return version.startsWith("v") ? version : `v${version}`;
147
+ return {
148
+ nodeBin,
149
+ entryPath,
150
+ appDir: dirname(entryPath),
151
+ };
143
152
  }
144
153
 
145
- function notFoundError(): CliExitError {
146
- return new CliExitError(`${SERVER_BINARY} binary not found`, ExitCode.General, [
147
- "Build it from the repo with `make build` (produces ./bin/stigmer-server),",
148
- "or set STIGMER_SERVER_BIN to an existing binary.",
149
- "Automatic download is only available for tagged releases.",
150
- ]);
154
+ function resolveBuiltServer(appDir: string, node: () => string): ServerLaunch {
155
+ const entryPath = join(appDir, "dist", "main.js");
156
+ if (!existsSync(entryPath)) {
157
+ throw new CliExitError(
158
+ `TS server not built: ${entryPath} is missing`,
159
+ ExitCode.General,
160
+ [
161
+ "Build it with: make build-server",
162
+ "The server must be compiled — it cannot run from source via tsx (its",
163
+ "Temporal workers bundle workflow code from the compiled dist).",
164
+ "STIGMER_SERVER_DIR expects the source package (dist/main.js); to run an",
165
+ "acquired @stigmer/server-slim install, unset it — the CLI resolves that",
166
+ "shape itself.",
167
+ ],
168
+ );
169
+ }
170
+ return { nodeBin: node(), entryPath, appDir };
151
171
  }
152
172
 
153
- function unsupportedPlatformError(platformKey: string): CliExitError {
154
- return new CliExitError(`the local stack does not support this platform (${platformKey})`, ExitCode.General, [
155
- "`stigmer up` needs a stigmer-server release asset, which is published for",
156
- "macOS (arm64/amd64) and Linux (amd64) only.",
157
- "Point STIGMER_SERVER_BIN at a server binary you built yourself to proceed.",
158
- ]);
173
+ function hasPackageJson(dir: string): boolean {
174
+ return existsSync(join(dir, "package.json"));
159
175
  }
160
176
 
161
- // Walk up from this module to the repo root (the directory containing
162
- // `bin/stigmer-server` in a dev checkout). Returns null outside a checkout.
177
+ // Walk up from this module to a repo root containing the TS server package.
163
178
  function repoRoot(): string | null {
164
179
  let dir = dirname(fileURLToPath(import.meta.url));
165
- for (let i = 0; i < 8; i += 1) {
166
- if (existsSync(join(dir, "bin", SERVER_BINARY))) return dir;
180
+ for (let i = 0; i < 10; i += 1) {
181
+ if (
182
+ existsSync(
183
+ join(dir, "backend", "services", "stigmer-server", "package.json"),
184
+ )
185
+ )
186
+ return dir;
167
187
  const parent = dirname(dir);
168
188
  if (parent === dir) break;
169
189
  dir = parent;
@@ -1,7 +1,7 @@
1
1
  // Resolution and on-demand acquisition of the seedpack content.
2
2
  //
3
3
  // The seedpack (system agents, skills, MCP servers, workflows under the
4
- // "stigmer" org) is the TS equivalent of the Go CLI's `go:embed`-ed bundle.
4
+ // "stigmer" org) is the system content every backend is bootstrapped with.
5
5
  // A lean `npx @stigmer/cli` must not carry ~300 content files (DD-002), so the
6
6
  // content ships as `@stigmer/seedpack` and is acquired on demand — the same
7
7
  // pattern as `@stigmer/runner-slim` and the managed Temporal binary.
@@ -12,14 +12,22 @@
12
12
  // ~/.stigmer/runtimes/<version>/ and read from
13
13
  // node_modules/@stigmer/seedpack.
14
14
  //
15
- // The content-hash and extract logic mirror `@stigmer/seedpack` exactly (which
16
- // in turn mirrors the Go `seedpack` package); the CLI reimplements them over a
17
- // resolved directory so it stays decoupled from the package in the lean install
18
- // (where the package is not a dependency, only an on-demand artifact).
15
+ // The content-hash and extract logic mirror `@stigmer/seedpack` exactly; the CLI
16
+ // reimplements them over a resolved directory so it stays decoupled from the
17
+ // package in the lean install (where the package is not a dependency, only an
18
+ // on-demand artifact). `seedpack/src/index.ts` is the one definition both follow.
19
19
 
20
20
  import { execFileSync } from "node:child_process";
21
21
  import { createHash } from "node:crypto";
22
- import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
22
+ import {
23
+ cpSync,
24
+ existsSync,
25
+ mkdirSync,
26
+ readdirSync,
27
+ readFileSync,
28
+ statSync,
29
+ writeFileSync,
30
+ } from "node:fs";
23
31
  import { homedir } from "node:os";
24
32
  import { dirname, join, posix, relative, sep } from "node:path";
25
33
  import { fileURLToPath } from "node:url";
@@ -33,9 +41,9 @@ const SEEDPACK_PACKAGE = "@stigmer/seedpack";
33
41
 
34
42
  /**
35
43
  * The canonical seedpack entries, in apply-safe order. Kept in sync with
36
- * `SEEDPACK_ENTRIES` in `@stigmer/seedpack` and the `//go:embed` set in
37
- * `seedpack/embed.go` — `tools/`, `icons/`, and `canary/` (CI canary metadata,
38
- * not a resource) are deliberately excluded so the content set (and thus the
44
+ * `SEEDPACK_ENTRIES` in `@stigmer/seedpack` (`seedpack/src/index.ts`, the one
45
+ * definition) — `tools/`, `icons/`, and `canary/` (CI canary metadata, not a
46
+ * resource) are deliberately excluded so the content set (and thus the
39
47
  * idempotency hash) is identical across delivery paths.
40
48
  */
41
49
  export const SEEDPACK_ENTRIES = [
@@ -70,7 +78,9 @@ export interface ResolveSeedpackOptions {
70
78
  * on-demand-acquired `@stigmer/seedpack` package. Throws actionable guidance when
71
79
  * acquisition is not possible (non-release build, or a failed/incomplete install).
72
80
  */
73
- export function resolveSeedpackContent(opts: ResolveSeedpackOptions = {}): SeedpackContent {
81
+ export function resolveSeedpackContent(
82
+ opts: ResolveSeedpackOptions = {},
83
+ ): SeedpackContent {
74
84
  const repo = repoSeedpackDir();
75
85
  if (repo !== null) return { dir: repo, source: "repo" };
76
86
  return { dir: acquireSeedpack(opts), source: "package" };
@@ -86,10 +96,14 @@ export function acquireSeedpack(opts: ResolveSeedpackOptions = {}): string {
86
96
  const home = opts.home ?? homedir();
87
97
  const version = opts.version ?? VERSION;
88
98
  if (!isAcquirableRelease(version)) {
89
- throw new CliExitError(`cannot acquire ${SEEDPACK_PACKAGE} for a non-release build (${version})`, ExitCode.General, [
90
- "Run from the repo (the seedpack/ tree is used directly in dev).",
91
- "On-demand acquisition is only available for published releases.",
92
- ]);
99
+ throw new CliExitError(
100
+ `cannot acquire ${SEEDPACK_PACKAGE} for a non-release build (${version})`,
101
+ ExitCode.General,
102
+ [
103
+ "Run from the repo (the seedpack/ tree is used directly in dev).",
104
+ "On-demand acquisition is only available for published releases.",
105
+ ],
106
+ );
93
107
  }
94
108
 
95
109
  const installDir = join(runtimesDir(home), version);
@@ -103,16 +117,21 @@ export function acquireSeedpack(opts: ResolveSeedpackOptions = {}): string {
103
117
  // additive and non-pruning, so this prefix is safely shared with the runner.
104
118
  const rootPkg = join(installDir, "package.json");
105
119
  if (!existsSync(rootPkg)) {
106
- writeFileSync(rootPkg, `${JSON.stringify({ name: "stigmer-runtime", private: true, version: "0.0.0" }, null, 2)}\n`);
120
+ writeFileSync(
121
+ rootPkg,
122
+ `${JSON.stringify({ name: "stigmer-runtime", private: true, version: "0.0.0" }, null, 2)}\n`,
123
+ );
107
124
  }
108
125
  const install = opts.install ?? installSeedpack;
109
126
  install(installDir, `${SEEDPACK_PACKAGE}@${version}`);
110
127
  }
111
128
 
112
129
  if (!existsSync(marker)) {
113
- throw new CliExitError(`${SEEDPACK_PACKAGE} install did not produce ${marker}`, ExitCode.General, [
114
- `Remove ${installDir} and retry.`,
115
- ]);
130
+ throw new CliExitError(
131
+ `${SEEDPACK_PACKAGE} install did not produce ${marker}`,
132
+ ExitCode.General,
133
+ [`Remove ${installDir} and retry.`],
134
+ );
116
135
  }
117
136
  return pkgDir;
118
137
  }
@@ -121,9 +140,21 @@ export function acquireSeedpack(opts: ResolveSeedpackOptions = {}): string {
121
140
  // the user sees the one-time download progress.
122
141
  function installSeedpack(installDir: string, spec: string): void {
123
142
  try {
124
- execFileSync("npm", ["install", spec, "--prefix", installDir, "--omit=dev", "--no-audit", "--no-fund"], {
125
- stdio: "inherit",
126
- });
143
+ execFileSync(
144
+ "npm",
145
+ [
146
+ "install",
147
+ spec,
148
+ "--prefix",
149
+ installDir,
150
+ "--omit=dev",
151
+ "--no-audit",
152
+ "--no-fund",
153
+ ],
154
+ {
155
+ stdio: "inherit",
156
+ },
157
+ );
127
158
  } catch (err) {
128
159
  throw new CliExitError(`failed to install ${spec}`, ExitCode.General, [
129
160
  `Command: npm install ${spec} --prefix ${installDir}`,
@@ -12,7 +12,7 @@ import { join } from "node:path";
12
12
  import { load as loadConfig } from "../config/config.js";
13
13
  import { configPath } from "../config/paths.js";
14
14
  import { CommandResult } from "../output/command-result.js";
15
- import { SERVER_PORT, TEMPORAL_UI_PORT, WEB_CONSOLE_PORT } from "./constants.js";
15
+ import { SERVER_PORT, TEMPORAL_UI_PORT } from "./constants.js";
16
16
  import { resolveApiKey, resolveProvider } from "./llm-config.js";
17
17
  import { tcpConnects } from "./net/tcp.js";
18
18
  import { dataDir } from "./paths.js";
@@ -144,7 +144,9 @@ function addWebUiSection(result: CommandResult, health: HealthState): void {
144
144
  if (!temporalRunning && !webRunning) return;
145
145
 
146
146
  const section = result.addSection("Web UI");
147
- if (webRunning) section.field("Console", `http://localhost:${WEB_CONSOLE_PORT}`);
147
+ // The console shares the server's unified port (DD-012) — same origin as
148
+ // the API, served by the server itself.
149
+ if (webRunning) section.field("Console", `http://localhost:${SERVER_PORT}`);
148
150
  if (temporalRunning) section.field("Temporal", `http://localhost:${TEMPORAL_UI_PORT}`);
149
151
  }
150
152
 
@@ -1,13 +1,30 @@
1
- // Embedded web-console availability.
1
+ // Web-console availability against the server's unified port.
2
2
  //
3
- // The Go CLI embeds the console's static assets via go:embed and serves them on
4
- // :8234. There is no TS equivalent bundled in T05, so the daemon detects the
5
- // console as unavailable and skips it cleanly (recording a "stopped" state),
6
- // exactly as the Go daemon does when built without assets. Real serving — and
7
- // the asset-bundling decision behind it — is deferred to T06.
3
+ // Since DD-012 (oss sub-project console-serving) the SERVER serves the
4
+ // console: the static export ships inside @stigmer/server-slim and the
5
+ // unified port's lane 4 serves it, synthesizing /config.json in-process.
6
+ // The CLI therefore PROBES rather than serves — /config.json answers 200
7
+ // exactly when a console export is bundled with the running server (a
8
+ // dev-tree server without the export falls through to the RPC adapter's
9
+ // 404), so the daemon's component state reports what a browser would
10
+ // actually find. The Go-era embedded console (go:embed on :8234) and the
11
+ // T05/T06 stub this file used to be are both retired by that design.
8
12
 
9
- /** Whether an embedded web console is available to serve. Always false until
10
- * T06 wires asset bundling + an HTTP handler. */
11
- export function isWebConsoleAvailable(): boolean {
12
- return false;
13
+ import { SERVER_PORT } from "../constants.js";
14
+
15
+ /** Keep the daemon's settle path snappy: a hung probe must not stall `stigmer up`. */
16
+ const PROBE_TIMEOUT_MS = 3000;
17
+
18
+ /** Whether the running server serves a bundled web console. */
19
+ export async function isWebConsoleAvailable(
20
+ serverPort: number = SERVER_PORT,
21
+ ): Promise<boolean> {
22
+ try {
23
+ const response = await fetch(`http://127.0.0.1:${serverPort}/config.json`, {
24
+ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
25
+ });
26
+ return response.ok;
27
+ } catch {
28
+ return false;
29
+ }
13
30
  }