@mysten-incubation/devstack 0.2.0 → 0.4.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/README.md +1 -1
- package/dashboard-ui/assets/{grpc-a4usE3Nk.js → grpc-CpkDu4SA.js} +1 -1
- package/dashboard-ui/assets/{index-CRYJ4pru.js → index-jLPRmjst.js} +39 -33
- package/dashboard-ui/index.html +1 -1
- package/dist/api/inference-network.d.mts +5 -5
- package/dist/api/inference-network.mjs +5 -5
- package/dist/api/inference-network.mjs.map +1 -1
- package/dist/api/run-stack-internal.mjs +2 -3
- package/dist/api/run-stack-internal.mjs.map +1 -1
- package/dist/build-integrations/dapp-kit/index.d.mts +12 -0
- package/dist/build-integrations/dapp-kit/index.mjs +14 -1
- package/dist/build-integrations/dapp-kit/index.mjs.map +1 -1
- package/dist/build-integrations/playwright/config.d.mts +2 -1
- package/dist/build-integrations/playwright/config.mjs +1 -1
- package/dist/build-integrations/playwright/config.mjs.map +1 -1
- package/dist/build-integrations/playwright/errors.d.mts +1 -1
- package/dist/build-integrations/playwright/errors.mjs.map +1 -1
- package/dist/build-integrations/playwright/index.d.mts +2 -2
- package/dist/build-integrations/playwright/index.mjs +2 -2
- package/dist/build-integrations/playwright/wallet-context.d.mts +2 -1
- package/dist/build-integrations/playwright/wallet-context.mjs +141 -41
- package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs +1 -1
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
- package/dist/build-integrations/vite/index.d.mts +82 -40
- package/dist/build-integrations/vite/index.mjs +281 -112
- package/dist/build-integrations/vite/index.mjs.map +1 -1
- package/dist/build-integrations/vitest/config.mjs +3 -4
- package/dist/build-integrations/vitest/config.mjs.map +1 -1
- package/dist/build-integrations/vitest/global-setup.mjs +8 -8
- package/dist/build-integrations/vitest/global-setup.mjs.map +1 -1
- package/dist/cli/doctor-probes.mjs +7 -2
- package/dist/cli/doctor-probes.mjs.map +1 -1
- package/dist/cli/main.mjs +5 -4
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/wirings/apply.mjs +0 -1
- package/dist/cli/wirings/apply.mjs.map +1 -1
- package/dist/cli/wirings/codegen.mjs +37 -38
- package/dist/cli/wirings/codegen.mjs.map +1 -1
- package/dist/cli/wirings/dump-deployment.mjs +141 -0
- package/dist/cli/wirings/dump-deployment.mjs.map +1 -0
- package/dist/cli/wirings/snapshot.mjs +0 -1
- package/dist/cli/wirings/snapshot.mjs.map +1 -1
- package/dist/cli/wirings/up.mjs +7 -0
- package/dist/cli/wirings/up.mjs.map +1 -1
- package/dist/contracts/codegenable.d.mts +22 -25
- package/dist/contracts/codegenable.mjs +35 -4
- package/dist/contracts/codegenable.mjs.map +1 -1
- package/dist/contracts/config-bindings.mjs +43 -18
- package/dist/contracts/config-bindings.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/orchestrators/boot.d.mts +0 -10
- package/dist/orchestrators/boot.mjs +24 -54
- package/dist/orchestrators/boot.mjs.map +1 -1
- package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
- package/dist/orchestrators/codegen/config-runtime.mjs +137 -112
- package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -1
- package/dist/orchestrators/codegen/deployment-network-file.mjs +130 -0
- package/dist/orchestrators/codegen/deployment-network-file.mjs.map +1 -0
- package/dist/orchestrators/codegen/deployment-strict.mjs +77 -0
- package/dist/orchestrators/codegen/deployment-strict.mjs.map +1 -0
- package/dist/orchestrators/codegen/deployment.d.mts +63 -0
- package/dist/orchestrators/codegen/deployment.mjs +153 -0
- package/dist/orchestrators/codegen/deployment.mjs.map +1 -0
- package/dist/orchestrators/codegen/errors.mjs +7 -9
- package/dist/orchestrators/codegen/errors.mjs.map +1 -1
- package/dist/orchestrators/codegen/format.mjs +20 -1
- package/dist/orchestrators/codegen/format.mjs.map +1 -1
- package/dist/orchestrators/codegen/paths.mjs +1 -8
- package/dist/orchestrators/codegen/paths.mjs.map +1 -1
- package/dist/orchestrators/codegen/service.mjs +369 -141
- package/dist/orchestrators/codegen/service.mjs.map +1 -1
- package/dist/orchestrators/layers.mjs +0 -1
- package/dist/orchestrators/layers.mjs.map +1 -1
- package/dist/orchestrators/network-options.d.mts +37 -35
- package/dist/orchestrators/network-options.mjs +13 -10
- package/dist/orchestrators/network-options.mjs.map +1 -1
- package/dist/plugins/account/codegen.d.mts +3 -4
- package/dist/plugins/account/codegen.mjs +5 -7
- package/dist/plugins/account/codegen.mjs.map +1 -1
- package/dist/plugins/account/index.mjs +1 -3
- package/dist/plugins/account/index.mjs.map +1 -1
- package/dist/plugins/coin/codegen.mjs +5 -5
- package/dist/plugins/coin/codegen.mjs.map +1 -1
- package/dist/plugins/coin/index.mjs.map +1 -1
- package/dist/plugins/dashboard/domain.mjs +18 -1
- package/dist/plugins/dashboard/domain.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/root.mjs +5 -3
- package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/types.mjs +15 -2
- package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
- package/dist/plugins/deepbook/codegen.mjs +4 -4
- package/dist/plugins/deepbook/codegen.mjs.map +1 -1
- package/dist/plugins/deepbook/index.d.mts +7 -3
- package/dist/plugins/deepbook/index.mjs +3 -3
- package/dist/plugins/deepbook/index.mjs.map +1 -1
- package/dist/plugins/internal/codegen-helpers.mjs +0 -1
- package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
- package/dist/plugins/package/codegen.d.mts +1 -12
- package/dist/plugins/package/codegen.mjs +43 -25
- package/dist/plugins/package/codegen.mjs.map +1 -1
- package/dist/plugins/package/dep-resolution.mjs +1 -1
- package/dist/plugins/package/dep-resolution.mjs.map +1 -1
- package/dist/plugins/package/index.d.mts +14 -11
- package/dist/plugins/package/index.mjs +6 -7
- package/dist/plugins/package/index.mjs.map +1 -1
- package/dist/plugins/seal/codegen.mjs +3 -3
- package/dist/plugins/seal/codegen.mjs.map +1 -1
- package/dist/plugins/seal/index.mjs.map +1 -1
- package/dist/plugins/sui/codegen.mjs +5 -4
- package/dist/plugins/sui/codegen.mjs.map +1 -1
- package/dist/plugins/sui/index.d.mts +10 -10
- package/dist/plugins/sui/index.mjs +1 -2
- package/dist/plugins/sui/index.mjs.map +1 -1
- package/dist/plugins/sui/move-summary-runner.mjs +29 -2
- package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
- package/dist/plugins/wallet/codegen.d.mts +8 -12
- package/dist/plugins/wallet/codegen.mjs +22 -15
- package/dist/plugins/wallet/codegen.mjs.map +1 -1
- package/dist/plugins/wallet/index.d.mts +4 -3
- package/dist/plugins/wallet/index.mjs +1 -1
- package/dist/plugins/wallet/index.mjs.map +1 -1
- package/dist/plugins/wallet/service.d.mts +2 -2
- package/dist/plugins/wallet/service.mjs +2 -3
- package/dist/plugins/wallet/service.mjs.map +1 -1
- package/dist/plugins/walrus/codegen.mjs +4 -4
- package/dist/plugins/walrus/codegen.mjs.map +1 -1
- package/dist/plugins/walrus/index.mjs +1 -1
- package/dist/plugins/walrus/index.mjs.map +1 -1
- package/dist/substrate/manifest.d.mts +17 -22
- package/dist/substrate/manifest.mjs +4 -6
- package/dist/substrate/manifest.mjs.map +1 -1
- package/dist/substrate/plugin-ctx.d.mts +6 -6
- package/dist/substrate/plugin-ctx.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
- package/dist/substrate/runtime/index.mjs +1 -0
- package/dist/substrate/runtime/lifecycle/file-watcher.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/file-watcher.mjs +54 -0
- package/dist/substrate/runtime/lifecycle/file-watcher.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/index.mjs +1 -0
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +76 -6
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
- package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
- package/dist/substrate/runtime/paths.mjs +1 -1
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs +2 -6
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
- package/dist/surfaces/cli/command-tree.mjs +6 -6
- package/dist/surfaces/cli/command-tree.mjs.map +1 -1
- package/dist/surfaces/cli/index.mjs +6 -4
- package/dist/surfaces/cli/index.mjs.map +1 -1
- package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/cli/wirings/dump-ids.mjs +0 -86
- package/dist/cli/wirings/dump-ids.mjs.map +0 -1
- package/dist/orchestrators/codegen/id-config.d.mts +0 -1
- package/dist/orchestrators/codegen/id-config.mjs +0 -107
- package/dist/orchestrators/codegen/id-config.mjs.map +0 -1
- package/dist/orchestrators/codegen/output-location.mjs +0 -32
- package/dist/orchestrators/codegen/output-location.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-attribution.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/watch-attribution.ts"],"sourcesContent":["// Watch-path → owning plugin attribution.\n//\n// Architecture § L3 Watch dispatcher: \"collects all plugin `watch`\n// declarations, receives watcher events from L0 (which already\n// debounced + dedup'd), triggers selective restart through the\n// scheduler's invalidate-with-cascade.\"\n//\n// L0 owns the file watcher (debounce + content-hash dedup). The\n// supervisor's role at watch time is just: given a fired path, which\n// plugin row(s) should be invalidated? This module builds and queries\n// that index. Selective-restart is the supervisor's concern; watch\n// attribution stays pure.\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { DepNode } from './dep-graph.ts';\n\n/** Per-plugin watch entry — a copy of the plugin's declared `watch`\n * decl with the owning key attached. */\nexport interface WatchEntry {\n\treadonly pluginKey: PluginKey;\n\treadonly paths: ReadonlyArray<string>;\n\t/** Whether downstream consumers should cascade-invalidate when this\n\t * fires. Defaults to true (architecture § WatchDecl). */\n\treadonly cascade: boolean;\n}\n\n/** Build the watch index from a resolved dep-graph's nodes. */\nexport const buildWatchIndex = (\n\tnodes: ReadonlyMap<PluginKey, DepNode>,\n): ReadonlyArray<WatchEntry> => {\n\tconst out: WatchEntry[] = [];\n\tfor (const [key, node] of nodes) {\n\t\tconst watch = node.member.watch;\n\t\tif (watch === undefined || watch.paths.length === 0) continue;\n\t\tout.push({\n\t\t\tpluginKey: key,\n\t\t\tpaths: watch.paths,\n\t\t\tcascade: watch.cascade ?? true,\n\t\t});\n\t}\n\treturn out;\n};\n\n/**\n * Given the firing `firedPath` (already debounced + content-hash dedup'd\n * by L0), return the plugin keys whose declared paths match.\n *\n * Matching is glob-aware via minimatch semantics — the substrate-level\n * attribution here delegates to a supplied `match` predicate to keep\n * this module dependency-free. The supervisor wires the matcher in.\n */\nexport const attribute = (\n\tindex: ReadonlyArray<WatchEntry>,\n\tfiredPath: string,\n\tmatch: (pattern: string, path: string) => boolean,\n): ReadonlySet<PluginKey> => {\n\tconst out = new Set<PluginKey>();\n\tfor (const entry of index) {\n\t\tfor (const pattern of entry.paths) {\n\t\t\tif (match(pattern, firedPath)) {\n\t\t\t\tout.add(entry.pluginKey);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n};\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"watch-attribution.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/watch-attribution.ts"],"sourcesContent":["// Watch-path → owning plugin attribution.\n//\n// Architecture § L3 Watch dispatcher: \"collects all plugin `watch`\n// declarations, receives watcher events from L0 (which already\n// debounced + dedup'd), triggers selective restart through the\n// scheduler's invalidate-with-cascade.\"\n//\n// L0 owns the file watcher (debounce + content-hash dedup). The\n// supervisor's role at watch time is just: given a fired path, which\n// plugin row(s) should be invalidated? This module builds and queries\n// that index. Selective-restart is the supervisor's concern; watch\n// attribution stays pure.\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { DepNode } from './dep-graph.ts';\n\n/** Per-plugin watch entry — a copy of the plugin's declared `watch`\n * decl with the owning key attached. */\nexport interface WatchEntry {\n\treadonly pluginKey: PluginKey;\n\treadonly paths: ReadonlyArray<string>;\n\t/** Whether downstream consumers should cascade-invalidate when this\n\t * fires. Defaults to true (architecture § WatchDecl). */\n\treadonly cascade: boolean;\n}\n\n/** Build the watch index from a resolved dep-graph's nodes. */\nexport const buildWatchIndex = (\n\tnodes: ReadonlyMap<PluginKey, DepNode>,\n): ReadonlyArray<WatchEntry> => {\n\tconst out: WatchEntry[] = [];\n\tfor (const [key, node] of nodes) {\n\t\tconst watch = node.member.watch;\n\t\tif (watch === undefined || watch.paths.length === 0) continue;\n\t\tout.push({\n\t\t\tpluginKey: key,\n\t\t\tpaths: watch.paths,\n\t\t\tcascade: watch.cascade ?? true,\n\t\t});\n\t}\n\treturn out;\n};\n\n/**\n * Given the firing `firedPath` (already debounced + content-hash dedup'd\n * by L0), return the plugin keys whose declared paths match.\n *\n * Matching is glob-aware via minimatch semantics — the substrate-level\n * attribution here delegates to a supplied `match` predicate to keep\n * this module dependency-free. The supervisor wires the matcher in.\n */\nexport const attribute = (\n\tindex: ReadonlyArray<WatchEntry>,\n\tfiredPath: string,\n\tmatch: (pattern: string, path: string) => boolean,\n): ReadonlySet<PluginKey> => {\n\tconst out = new Set<PluginKey>();\n\tfor (const entry of index) {\n\t\tfor (const pattern of entry.paths) {\n\t\t\tif (match(pattern, firedPath)) {\n\t\t\t\tout.add(entry.pluginKey);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n};\n\nconst REGEXP_SPECIALS = new Set('.+^${}()|[]\\\\'.split(''));\n\n/**\n * Compile a watch glob to an anchored `RegExp`. Supports the only glob\n * features the package plugin emits (architecture § WatchDecl):\n * - `**\\/` — zero or more path segments (so `root/**\\/*.move` matches both\n * `root/x.move` and `root/sources/x.move`)\n * - `**` — any characters including `/` (trailing-segment form)\n * - `*` — any characters except `/` (within one segment)\n * - `?` — one character except `/`\n * Everything else is matched literally. This is the dependency-free stand-in\n * for the architecture's \"minimatch\" matcher — devstack pulls in no glob\n * library (cf. the hand-rolled `collectHashedSources`).\n */\nconst globToRegExp = (glob: string): RegExp => {\n\tlet body = '';\n\tfor (let i = 0; i < glob.length; i += 1) {\n\t\tconst c = glob[i]!;\n\t\tif (c === '*' && glob[i + 1] === '*') {\n\t\t\tif (glob[i + 2] === '/') {\n\t\t\t\tbody += '(?:.*/)?';\n\t\t\t\ti += 2;\n\t\t\t} else {\n\t\t\t\tbody += '.*';\n\t\t\t\ti += 1;\n\t\t\t}\n\t\t} else if (c === '*') {\n\t\t\tbody += '[^/]*';\n\t\t} else if (c === '?') {\n\t\t\tbody += '[^/]';\n\t\t} else if (REGEXP_SPECIALS.has(c)) {\n\t\t\tbody += `\\\\${c}`;\n\t\t} else {\n\t\t\tbody += c;\n\t\t}\n\t}\n\treturn new RegExp(`^${body}$`);\n};\n\n/** Glob-aware matcher — the production matcher the supervisor wires into\n * `attribute`. Honors `**`, `*`, `?`; everything else is literal. Both\n * sides are normalized to POSIX separators first: the watcher feeds paths\n * from `join(root, filename)`, which is `\\`-separated on Windows, while\n * glob patterns are always `/`-separated. */\nconst toPosix = (p: string): string => p.replace(/\\\\/g, '/');\n\nexport const globMatch = (pattern: string, path: string): boolean =>\n\tglobToRegExp(toPosix(pattern)).test(toPosix(path));\n\n/** Literal directory prefix of a watch glob — the path up to (but not\n * including) the first segment containing a glob metacharacter. Both\n * `root/**\\/*.move` and the exact `root/Move.toml` collapse to `root`,\n * so the L0 watcher places ONE recursive watch per source tree. A\n * pattern whose literal prefix has no directory separator — a bare\n * basename (`Move.toml`), a leading glob (`*.move` ⇒ empty prefix), or a\n * same-segment glob (`src*`) — collapses to `.` (the cwd), never to a\n * bare filename: `fs.watch` must be handed a directory, and `globMatch`\n * still filters the events. */\nconst literalRoot = (pattern: string): string => {\n\tconst metaIdx = pattern.search(/[*?]/);\n\tconst literal = metaIdx === -1 ? pattern : pattern.slice(0, metaIdx);\n\tconst slash = literal.lastIndexOf('/');\n\tif (slash === 0) return '/'; // pattern sits at filesystem root\n\treturn slash > 0 ? literal.slice(0, slash) : '.';\n};\n\n/** Distinct recursive-watch roots for a watch index — the directories the\n * L0 file watcher hands to `fs.watch(root, { recursive: true })`. */\nexport const deriveWatchRoots = (index: ReadonlyArray<WatchEntry>): ReadonlyArray<string> => {\n\tconst roots = new Set<string>();\n\tfor (const entry of index) {\n\t\tfor (const pattern of entry.paths) {\n\t\t\troots.add(literalRoot(pattern));\n\t\t}\n\t}\n\treturn [...roots];\n};\n"],"mappings":";;AA2BA,MAAa,mBACZ,UAC+B;CAC/B,MAAM,MAAoB,CAAC;CAC3B,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO;EAChC,MAAM,QAAQ,KAAK,OAAO;EAC1B,IAAI,UAAU,KAAA,KAAa,MAAM,MAAM,WAAW,GAAG;EACrD,IAAI,KAAK;GACR,WAAW;GACX,OAAO,MAAM;GACb,SAAS,MAAM,WAAW;EAC3B,CAAC;CACF;CACA,OAAO;AACR;;;;;;;;;AAUA,MAAa,aACZ,OACA,WACA,UAC4B;CAC5B,MAAM,sBAAM,IAAI,IAAe;CAC/B,KAAK,MAAM,SAAS,OACnB,KAAK,MAAM,WAAW,MAAM,OAC3B,IAAI,MAAM,SAAS,SAAS,GAAG;EAC9B,IAAI,IAAI,MAAM,SAAS;EACvB;CACD;CAGF,OAAO;AACR;AAEA,MAAM,kBAAkB,IAAI,IAAI,gBAAgB,MAAM,EAAE,CAAC;;;;;;;;;;;;;AAczD,MAAM,gBAAgB,SAAyB;CAC9C,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;EACxC,MAAM,IAAI,KAAK;EACf,IAAI,MAAM,OAAO,KAAK,IAAI,OAAO,KAChC,IAAI,KAAK,IAAI,OAAO,KAAK;GACxB,QAAQ;GACR,KAAK;EACN,OAAO;GACN,QAAQ;GACR,KAAK;EACN;OACM,IAAI,MAAM,KAChB,QAAQ;OACF,IAAI,MAAM,KAChB,QAAQ;OACF,IAAI,gBAAgB,IAAI,CAAC,GAC/B,QAAQ,KAAK;OAEb,QAAQ;CAEV;CACA,OAAO,IAAI,OAAO,IAAI,KAAK,EAAE;AAC9B;;;;;;AAOA,MAAM,WAAW,MAAsB,EAAE,QAAQ,OAAO,GAAG;AAE3D,MAAa,aAAa,SAAiB,SAC1C,aAAa,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC;;;;;;;;;;AAWlD,MAAM,eAAe,YAA4B;CAChD,MAAM,UAAU,QAAQ,OAAO,MAAM;CACrC,MAAM,UAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,GAAG,OAAO;CACnE,MAAM,QAAQ,QAAQ,YAAY,GAAG;CACrC,IAAI,UAAU,GAAG,OAAO;CACxB,OAAO,QAAQ,IAAI,QAAQ,MAAM,GAAG,KAAK,IAAI;AAC9C;;;AAIA,MAAa,oBAAoB,UAA4D;CAC5F,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,SAAS,OACnB,KAAK,MAAM,WAAW,MAAM,OAC3B,MAAM,IAAI,YAAY,OAAO,CAAC;CAGhC,OAAO,CAAC,GAAG,KAAK;AACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.mjs","names":[],"sources":["../../../../src/substrate/runtime/manifest/manifest.ts"],"sourcesContent":["// Manifest emitter — endpoint-keyed envelope, atomic write.\n//\n// Architecture § Manifest data model. The envelope is L0 (`identity`\n// tuple, `manifestVersion`, `endpoints` lookup, `extras`).\n//\n// The emitter:\n// - Walks endpoint entries to build the flat `endpoints` lookup\n// keyed by `endpointKey`. Entries carry the declared endpoint\n// `name` for build-integration lookup.\n// - Writes atomically via tempfile + fsync + rename. The atomic-\n// write primitive lives in L0 (per architecture § Collapsed:\n// \"Three tempfile+rename impls → one atomic-write primitive\").\n// - Validates the envelope against `ManifestEnvelopeSchema` on read.\n// - Pins `manifestVersion` so future-proofing migrations have a\n// compatibility seam. The pinned version is `1`.\n//\n// Discipline: zero service names. The schema validates the envelope\n// shape, not the per-plugin contents.\n\nimport { Effect } from 'effect';\nimport { Data } from 'effect';\nimport { FileSystem } from 'effect';\n\nimport type { EndpointKey, PluginKey } from '../../brand.ts';\nimport {\n\ttype EndpointEntry,\n\ttype ManifestCodegen,\n\ttype ManifestExtras,\n\ttype ManifestEnvelope,\n\tManifestEnvelopeSchema,\n} from '../../manifest.ts';\nimport { atomicWriteFile } from '../atomic-write.ts';\nimport { decodeJsonText } from '../runtime-decode.ts';\n\n// -----------------------------------------------------------------------------\n// Pinned schema version\n// -----------------------------------------------------------------------------\n\n/**\n * Schema version pinned at the envelope level. Bump only on a\n * breaking shape change to the envelope (NOT to a per-plugin service\n * slice — those carry their own version via Codegenable contribution).\n *\n * Reader policy:\n * - Equal version: accept.\n * - Older version: refuse (advise user to re-run `up`).\n * - Newer version: refuse (build integration is out of date).\n */\nexport const CURRENT_MANIFEST_VERSION = 1 as const;\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** One error class for every manifest IO failure. */\nexport class ManifestError extends Data.TaggedError('ManifestError')<{\n\treadonly reason:\n\t\t| 'write-failed'\n\t\t| 'read-failed'\n\t\t| 'decode-failed'\n\t\t| 'version-mismatch'\n\t\t| 'duplicate-endpoint';\n\treadonly path: string;\n\treadonly detail?: string;\n\treadonly cause?: unknown;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Public writer interface\n// -----------------------------------------------------------------------------\n\nexport interface WriteManifestInput {\n\treadonly identity: ManifestEnvelope['identity'];\n\treadonly endpoints?: ReadonlyArray<EndpointEntry>;\n\treadonly extras?: ManifestExtras;\n\t/** Per-stack codegen metadata (the
|
|
1
|
+
{"version":3,"file":"manifest.mjs","names":[],"sources":["../../../../src/substrate/runtime/manifest/manifest.ts"],"sourcesContent":["// Manifest emitter — endpoint-keyed envelope, atomic write.\n//\n// Architecture § Manifest data model. The envelope is L0 (`identity`\n// tuple, `manifestVersion`, `endpoints` lookup, `extras`).\n//\n// The emitter:\n// - Walks endpoint entries to build the flat `endpoints` lookup\n// keyed by `endpointKey`. Entries carry the declared endpoint\n// `name` for build-integration lookup.\n// - Writes atomically via tempfile + fsync + rename. The atomic-\n// write primitive lives in L0 (per architecture § Collapsed:\n// \"Three tempfile+rename impls → one atomic-write primitive\").\n// - Validates the envelope against `ManifestEnvelopeSchema` on read.\n// - Pins `manifestVersion` so future-proofing migrations have a\n// compatibility seam. The pinned version is `1`.\n//\n// Discipline: zero service names. The schema validates the envelope\n// shape, not the per-plugin contents.\n\nimport { Effect } from 'effect';\nimport { Data } from 'effect';\nimport { FileSystem } from 'effect';\n\nimport type { EndpointKey, PluginKey } from '../../brand.ts';\nimport {\n\ttype EndpointEntry,\n\ttype ManifestCodegen,\n\ttype ManifestExtras,\n\ttype ManifestEnvelope,\n\tManifestEnvelopeSchema,\n} from '../../manifest.ts';\nimport { atomicWriteFile } from '../atomic-write.ts';\nimport { decodeJsonText } from '../runtime-decode.ts';\n\n// -----------------------------------------------------------------------------\n// Pinned schema version\n// -----------------------------------------------------------------------------\n\n/**\n * Schema version pinned at the envelope level. Bump only on a\n * breaking shape change to the envelope (NOT to a per-plugin service\n * slice — those carry their own version via Codegenable contribution).\n *\n * Reader policy:\n * - Equal version: accept.\n * - Older version: refuse (advise user to re-run `up`).\n * - Newer version: refuse (build integration is out of date).\n */\nexport const CURRENT_MANIFEST_VERSION = 1 as const;\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** One error class for every manifest IO failure. */\nexport class ManifestError extends Data.TaggedError('ManifestError')<{\n\treadonly reason:\n\t\t| 'write-failed'\n\t\t| 'read-failed'\n\t\t| 'decode-failed'\n\t\t| 'version-mismatch'\n\t\t| 'duplicate-endpoint';\n\treadonly path: string;\n\treadonly detail?: string;\n\treadonly cause?: unknown;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Public writer interface\n// -----------------------------------------------------------------------------\n\nexport interface WriteManifestInput {\n\treadonly identity: ManifestEnvelope['identity'];\n\treadonly endpoints?: ReadonlyArray<EndpointEntry>;\n\treadonly extras?: ManifestExtras;\n\t/** Per-stack codegen metadata (the live `deploymentFile`). Optional +\n\t * additive — omitting it produces an envelope without the `codegen`\n\t * key, identical to a pre-field manifest. */\n\treadonly codegen?: ManifestCodegen;\n}\n\n/**\n * Build the envelope from endpoint entries + extras. Pure; the writer\n * calls this and then atomically writes the JSON.\n *\n * Endpoint-key collisions error: every endpoint has a unique\n * `(pluginKey, dispatchId)` digest by construction; a duplicate means\n * a substrate bug.\n */\nexport const buildEnvelope = (\n\tinput: WriteManifestInput,\n): Effect.Effect<ManifestEnvelope, ManifestError> =>\n\tEffect.gen(function* () {\n\t\tconst endpoints: Record<string, EndpointEntry> = {};\n\t\tconst extras: Record<string, unknown> = { ...input.extras };\n\n\t\tconst addEndpoint = (ep: EndpointEntry): Effect.Effect<void, ManifestError> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ek = ep.endpointKey as string;\n\t\t\t\tif (ek in endpoints) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\t\treason: 'duplicate-endpoint',\n\t\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\t\tdetail: `endpointKey ${ek} contributed twice`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tendpoints[ek] = ep;\n\t\t\t});\n\n\t\tfor (const ep of input.endpoints ?? []) {\n\t\t\tyield* addEndpoint(ep);\n\t\t}\n\n\t\treturn {\n\t\t\tidentity: input.identity,\n\t\t\tmanifestVersion: CURRENT_MANIFEST_VERSION,\n\t\t\tendpoints,\n\t\t\textras,\n\t\t\t// Spread only when present so an omitted `codegen` yields the\n\t\t\t// exact same envelope (and serialized bytes) as a pre-field\n\t\t\t// manifest — additive, no churn for stacks that don't record it.\n\t\t\t...(input.codegen !== undefined ? { codegen: input.codegen } : {}),\n\t\t};\n\t});\n\n// -----------------------------------------------------------------------------\n// Atomic write — delegates to the canonical primitive.\n// -----------------------------------------------------------------------------\n\n/**\n * Serialize and write the envelope at `path` atomically. Routes\n * through the canonical `atomicWriteFile` primitive (mkdir-parent →\n * O_EXCL temp → write → fsync → rename), so the manifest writer\n * shares ONE owner of the tempfile dance with the cache.\n */\nexport const writeManifest = (\n\tenvelope: ManifestEnvelope,\n\tpath: string,\n): Effect.Effect<void, ManifestError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst json = serializeEnvelope(envelope);\n\t\tconst bytes = new TextEncoder().encode(json);\n\t\tyield* atomicWriteFile(path, bytes).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\treason: 'write-failed',\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tdetail: `atomic write failed at stage ${cause.stage}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t});\n\nconst serializeEnvelope = (envelope: ManifestEnvelope): string =>\n\t// Stable key ordering, deterministic re-emit. `JSON.stringify` with\n\t// 2-space indent is reproducible byte-for-byte given the same\n\t// input object.\n\tJSON.stringify(envelope, null, 2);\n\n// -----------------------------------------------------------------------------\n// Read + decode\n// -----------------------------------------------------------------------------\n\n/**\n * Read and decode the manifest at `path`. Validates against\n * `ManifestEnvelopeSchema` and the pinned `CURRENT_MANIFEST_VERSION`.\n *\n * Used by:\n * - Build integrations (Vitest, Playwright, generated app code) — consumes\n * `envelope.endpoints` lookup.\n *\n * The reader is read-only; no mutation, no IO beyond the single read.\n */\nexport const readManifest = (\n\tpath: string,\n): Effect.Effect<ManifestEnvelope, ManifestError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(Effect.mapError((cause) => new ManifestError({ reason: 'read-failed', path, cause })));\n\t\tconst decoded = yield* decodeJsonText(ManifestEnvelopeSchema, text, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew ManifestError({ reason: 'decode-failed', path, cause: issue.cause ?? issue }),\n\t\t});\n\t\tif (decoded.manifestVersion !== CURRENT_MANIFEST_VERSION) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew ManifestError({\n\t\t\t\t\treason: 'version-mismatch',\n\t\t\t\t\tpath,\n\t\t\t\t\tdetail: `expected ${CURRENT_MANIFEST_VERSION}, got ${decoded.manifestVersion}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn decoded as ManifestEnvelope;\n\t});\n\n// -----------------------------------------------------------------------------\n// Re-export the envelope + endpoint types so downstream substrate\n// modules (codegen, build integrations) don't reach into substrate/\n// directly.\n// -----------------------------------------------------------------------------\n\nexport type { EndpointEntry, EndpointKey, ManifestCodegen, ManifestEnvelope, PluginKey };\nexport { ManifestEnvelopeSchema };\n"],"mappings":";;;;;AAuDA,IAAa,gBAAb,cAAmC,KAAK,YAAY,eAAe,CAAC,CAUjE,CAAC;;;;;;;;;AAwBJ,MAAa,iBACZ,UAEA,OAAO,IAAI,aAAa;CACvB,MAAM,YAA2C,CAAC;CAClD,MAAM,SAAkC,EAAE,GAAG,MAAM,OAAO;CAE1D,MAAM,eAAe,OACpB,OAAO,IAAI,aAAa;EACvB,MAAM,KAAK,GAAG;EACd,IAAI,MAAM,WACT,OAAO,OAAO,OAAO,KACpB,IAAI,cAAc;GACjB,QAAQ;GACR,MAAM;GACN,QAAQ,eAAe,GAAG;EAC3B,CAAC,CACF;EAED,UAAU,MAAM;CACjB,CAAC;CAEF,KAAK,MAAM,MAAM,MAAM,aAAa,CAAC,GACpC,OAAO,YAAY,EAAE;CAGtB,OAAO;EACN,UAAU,MAAM;EAChB,iBAAA;EACA;EACA;EAIA,GAAI,MAAM,YAAY,KAAA,IAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;CACjE;AACD,CAAC;;;;;;;AAYF,MAAa,iBACZ,UACA,SAEA,OAAO,IAAI,aAAa;CACvB,MAAM,OAAO,kBAAkB,QAAQ;CAEvC,OAAO,gBAAgB,MADT,IAAI,YAAY,CAAC,CAAC,OAAO,IACN,CAAC,CAAC,CAAC,KACnC,OAAO,UACL,UACA,IAAI,cAAc;EACjB,QAAQ;EACR;EACA,QAAQ,gCAAgC,MAAM;EAC9C;CACD,CAAC,CACH,CACD;AACD,CAAC;AAEF,MAAM,qBAAqB,aAI1B,KAAK,UAAU,UAAU,MAAM,CAAC"}
|
|
@@ -75,6 +75,6 @@ const layerStackPaths = Layer.effect(StackPathsService, Effect.gen(function* ()
|
|
|
75
75
|
});
|
|
76
76
|
}));
|
|
77
77
|
//#endregion
|
|
78
|
-
export { IdentityContext, RuntimeRoot, StackPathsService, layerIdentity, layerRuntimeRoot, layerStackPaths
|
|
78
|
+
export { IdentityContext, RuntimeRoot, StackPathsService, layerIdentity, layerRuntimeRoot, layerStackPaths };
|
|
79
79
|
|
|
80
80
|
//# sourceMappingURL=paths.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SupervisorBootError } from "./errors.mjs";
|
|
2
2
|
import { noopContributionDispatcher } from "./contribution-dispatcher.mjs";
|
|
3
3
|
import { resolveGraph } from "../lifecycle/dep-graph.mjs";
|
|
4
|
-
import { buildWatchIndex,
|
|
4
|
+
import { attribute, buildWatchIndex, globMatch } from "../lifecycle/watch-attribution.mjs";
|
|
5
5
|
import { plan } from "../reconcile/graph.mjs";
|
|
6
6
|
import { installSignalHandler } from "../lifecycle/signals.mjs";
|
|
7
7
|
import "../lifecycle/index.mjs";
|
|
@@ -200,11 +200,7 @@ const startSupervisor = (stack, identity, state, pluginContext = Context.empty()
|
|
|
200
200
|
});
|
|
201
201
|
const watchIndex = buildWatchIndex(graph.nodes);
|
|
202
202
|
const notifyWatchFire = (path) => Effect.gen(function* () {
|
|
203
|
-
const matched =
|
|
204
|
-
for (const entry of watchIndex) for (const pat of entry.paths) if (exactPrefixMatch(pat, path)) {
|
|
205
|
-
matched.add(entry.pluginKey);
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
203
|
+
const matched = attribute(watchIndex, path, globMatch);
|
|
208
204
|
if (matched.size === 0) return;
|
|
209
205
|
for (const key of matched) yield* Queue.offer(commands, {
|
|
210
206
|
tag: "selective-restart.requested",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-supervisor.mjs","names":["Logger"],"sources":["../../../../src/substrate/runtime/supervisor/start-supervisor.ts"],"sourcesContent":["// Top-level supervisor entry — composes every per-concern module.\n//\n// Responsibilities (in order):\n// 1. Seed projection identity + booting slice so early-mounted\n// renderers see a complete baseline.\n// 2. Resolve the dep graph + boot the registry.\n// 3. Build the substrate-wiring bag: logger overlay, runtime root, and\n// the closed contribution dispatcher.\n// 4. Compose the `SupervisorState` record (one bag passed to every\n// module).\n// 5. Build `runInitialAcquire` — the deferred initial-acquire body.\n// 6. Build the watch index + `notifyWatchFire`.\n// 7. Fork the command loop + signal handler.\n// 8. Install the scope-close finalizer (reverse-dep teardown).\n// 9. Return the handle.\n\nimport {\n\tContext,\n\tDeferred,\n\tEffect,\n\tExit,\n\ttype Fiber,\n\tQueue,\n\tRef,\n\tScope,\n\tSubscriptionRef,\n} from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { EngineCommand, EngineEvent } from '../../events.ts';\nimport type { Identity } from '../../identity.ts';\nimport type { LifecycleStatus } from '../../lifecycle.ts';\nimport type { AccountProjection, SubscribableState } from '../../projection.ts';\nimport {\n\tnoopContributionDispatcher,\n\ttype ContributionDispatcher,\n} from './contribution-dispatcher.ts';\nimport {\n\tLogger,\n\tLogStore,\n\tmakeLogStore,\n\ttype LoggerShape,\n\ttype LogStoreConfig,\n} from '../observability/index.ts';\nimport { ControlPlaneService } from '../control-plane/service.ts';\nimport { controlPlaneDomainFromContext } from '../control-plane/domain.ts';\nimport { RuntimeRoot } from '../paths.ts';\nimport { declareAccount, setIdentity } from '../projection/update.ts';\nimport {\n\tbuildWatchIndex,\n\texactPrefixMatch,\n\tinstallSignalHandler,\n\tresolveGraph,\n\ttype PluginRegistry,\n\ttype ResolvedGraph,\n\ttype UnknownDependency,\n\ttype WatchEntry,\n} from '../lifecycle/index.ts';\nimport { acquireFullGraph, buildRegistry } from './acquire-node.ts';\nimport { commandLoop } from './command-loop.ts';\nimport { runPostAcquireHook } from './background-tasks.ts';\nimport {\n\tSupervisorBootError,\n\ttype SupervisorError,\n\ttype SupervisorPostAcquireFailed,\n} from './errors.ts';\nimport {\n\tallReadyOrTerminal,\n\ttype BackgroundTaskSlot,\n\ttype QueuedCommand,\n\ttype SupervisorCommandHandler,\n\ttype SupervisorPostAcquireHook,\n\ttype SupervisorState,\n} from './state.ts';\nimport type { SupervisedStack } from './types.ts';\nimport { teardownKeys } from './teardown.ts';\nimport { plan } from '../reconcile/graph.ts';\nimport {\n\tbuildTransitionEmitter,\n\tnoopLogger,\n\tOptionalService,\n\tsetCyclePhase,\n\twithEventPublishingLogger,\n} from './wiring.ts';\n\nconst loggerAccess = OptionalService(Logger);\nconst runtimeRootAccess = OptionalService(RuntimeRoot);\n\nexport interface SupervisorHandle {\n\treadonly identity: Identity;\n\treadonly graph: ResolvedGraph;\n\treadonly registry: PluginRegistry;\n\treadonly events: Queue.Dequeue<EngineEvent>;\n\treadonly commands: Queue.Enqueue<EngineCommand>;\n\treadonly runCommand: (command: EngineCommand) => Effect.Effect<void, unknown>;\n\treadonly state: SubscriptionRef.SubscriptionRef<SubscribableState>;\n\treadonly watchIndex: ReadonlyArray<WatchEntry>;\n\t/** Fire a watch event for the given path. Substrate-level glue:\n\t * the thick L0 watcher calls this; tests call it directly. */\n\treadonly notifyWatchFire: (path: string) => Effect.Effect<void>;\n\t/** Block until the supervisor's command loop sets the shutdown\n\t * latch. The outer runtime then closes the supervisor scope, which\n\t * tears down every plugin in reverse-dep order. */\n\treadonly awaitShutdown: Effect.Effect<void>;\n}\n\nexport interface SupervisorStartup {\n\treadonly handle: SupervisorHandle;\n\treadonly runInitialAcquire: Effect.Effect<void, SupervisorPostAcquireFailed, never>;\n}\n\nexport interface SupervisorStartupOptions {\n\treadonly commandLoop?: boolean;\n\treadonly devstackVersion?: string;\n\t/** Per-service log-store tuning. Absent fields fall back to the\n\t * `DEVSTACK_DASHBOARD_LOG_*` env vars, then the module defaults\n\t * (2000 records/service, 256 services). Threaded into the\n\t * process-scoped `makeLogStore` below. */\n\treadonly logStore?: LogStoreConfig;\n}\n\nconst pendingAccountProjection = (\n\trowKey: PluginKey,\n\tresourceId: string,\n\tupdatedAt: number,\n): AccountProjection | null => {\n\tif (!resourceId.startsWith('account/')) return null;\n\tconst name = resourceId.slice('account/'.length);\n\tif (name.length === 0) return null;\n\treturn {\n\t\tkey: resourceId as `account/${string}`,\n\t\trowKey,\n\t\tname,\n\t\taddress: null,\n\t\tscheme: null,\n\t\tsource: null,\n\t\tfunding: { status: 'pending', balanceMist: null, requestedMist: null, entries: [] },\n\t\twalletVisible: false,\n\t\tupdatedAt,\n\t};\n};\n\n/**\n * Prepare a supervisor for `stack` without running the initial acquire.\n * The returned `SupervisorHandle` is Scope-managed; the supervisor's\n * lifecycle is the surrounding Scope's lifecycle. Signal handlers,\n * the command loop, and every plugin's scope are children of the\n * supervisor scope. Callers that mount renderers can subscribe to the\n * returned state before invoking `runInitialAcquire`.\n *\n * `pluginContext` carries the substrate-context services available to\n * each plugin's `acquire` body (`IdentityContext`,\n * `ContainerRuntimeService`, `RuntimeRoot`, `StackPathsService`, etc.).\n * Plugins declare what they need by yielding the corresponding\n * `Context.Service` tag from within `Effect.gen`; the supervisor\n * provides this context before running the acquire effect so the\n * plugin's R-channel narrows to `Scope.Scope` (then to `never` after\n * the per-plugin Scope is provided).\n *\n * Contribution dispatch: the supervisor replays each plugin's\n * buffered ctx contributions through the closed `dispatcher`\n * (snapshotable/routable/codegenable/projection/strategy-contributor).\n * Production callers pass `buildProductionContributionDispatcher(...)`;\n * bare smoke tests omit it and get the no-op dispatcher.\n */\nexport const startSupervisor = (\n\tstack: SupervisedStack,\n\tidentity: Identity,\n\tstate: SubscriptionRef.SubscriptionRef<SubscribableState>,\n\tpluginContext: Context.Context<never> = Context.empty(),\n\tdispatcher: ContributionDispatcher = noopContributionDispatcher,\n\tcommandHandler?: SupervisorCommandHandler,\n\tpostAcquireHook?: SupervisorPostAcquireHook,\n\toptions: SupervisorStartupOptions = {},\n): Effect.Effect<SupervisorStartup, SupervisorBootError | UnknownDependency, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\t// Optional Logger service — pull from the plugin context if the\n\t\t// caller layered it in (CLI / e2e do). Bare smoke tests get the\n\t\t// no-op fallback so they remain log-free.\n\t\tconst baseLogger: LoggerShape = loggerAccess.read(pluginContext, noopLogger);\n\n\t\tyield* baseLogger.log('supervisor', null, {\n\t\t\tlevel: 'debug',\n\t\t\tmessage: 'supervisor boot start',\n\t\t\tfields: {\n\t\t\t\tapp: identity.app,\n\t\t\t\tstack: identity.stack,\n\t\t\t\tnetwork: identity.network,\n\t\t\t\tmemberCount: stack.members.length,\n\t\t\t},\n\t\t});\n\n\t\t// Seed the projection's identity and booting slices before\n\t\t// acquire starts so renderers mounting early have a complete\n\t\t// baseline.\n\t\tyield* SubscriptionRef.update(\n\t\t\tstate,\n\t\t\t(s) =>\n\t\t\t\t({\n\t\t\t\t\t...setIdentity(s, {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tnetwork: identity.network,\n\t\t\t\t\t}),\n\t\t\t\t\tcycle: {\n\t\t\t\t\t\t...s.cycle,\n\t\t\t\t\t\tstartedAt: s.cycle.startedAt === 0 ? Date.now() : s.cycle.startedAt,\n\t\t\t\t\t\tphase: 'booting',\n\t\t\t\t\t},\n\t\t\t\t}) satisfies SubscribableState,\n\t\t);\n\n\t\t// Resolve the dep graph.\n\t\tconst graph = yield* resolveGraph(stack.members).pipe(\n\t\t\tEffect.mapError((cause) => new SupervisorBootError({ cause })),\n\t\t);\n\n\t\t// Event hub + command channel.\n\t\tconst hub = yield* Queue.unbounded<EngineEvent>();\n\t\tconst commands = yield* Queue.unbounded<EngineCommand>();\n\t\tconst queuedCommands = yield* Queue.unbounded<QueuedCommand>();\n\t\t// Background-task fiber slot: the live stack-restart fiber (or `null`\n\t\t// when idle). The fiber IS the running state — see `BackgroundTaskSlot`.\n\t\t// Forked into `supervisorScope` (below) via `Effect.forkIn`, interrupted\n\t\t// via `Fiber.interrupt`. (Snapshot capture/restore run inline in the\n\t\t// command loop now — the bounce — so they have no forked slot.)\n\t\tconst stackRestartTask: BackgroundTaskSlot = yield* Ref.make<Fiber.Fiber<void, never> | null>(\n\t\t\tnull,\n\t\t);\n\t\tconst shutdownLatch = yield* Ref.make(false);\n\t\tconst shutdownComplete = yield* Deferred.make<void>();\n\t\tconst initialAcquireStarted = yield* Ref.make(false);\n\n\t\t// Observability store (process-scoped, like `state`/`hub`): a\n\t\t// cross-service queryable log ring fed off the SAME logger path that\n\t\t// feeds the projection's per-row tail. Survives `stack.restart`\n\t\t// because it lives in this closure (only `cycle.id` bumps on restart).\n\t\t// The dashboard reads it via the control-plane `domain`.\n\t\tconst logStore = yield* makeLogStore(options.logStore ?? {});\n\t\tconst logger = withEventPublishingLogger(baseLogger, state, hub, logStore);\n\n\t\t// The control-plane command verbs, both offering onto the SAME\n\t\t// `queuedCommands` seam the single command-loop consumer drains —\n\t\t// distinguished only by the QueuedCommand kind:\n\t\t// - `publishCommand` — fire-and-forget; offers a `fire-and-forget`\n\t\t// QueuedCommand and returns immediately.\n\t\t// - `submitCommand` — offers a `submitted` QueuedCommand carrying a\n\t\t// completion deferred, then AWAITs the real exit. So a destructive\n\t\t// command like `snapshot.restore` (which removes live managed\n\t\t// containers then re-acquires) runs in-band with the loop, never\n\t\t// racing the live supervisor out-of-band. Re-fails with the\n\t\t// handler's cause.\n\t\t// (Both feed `queuedCommands`, NOT the public `commands` queue + bridge —\n\t\t// that queue stays for the signal handler and cross-process callers.)\n\t\tconst publishCommand = (command: EngineCommand): Effect.Effect<void> =>\n\t\t\tEffect.asVoid(Queue.offer(queuedCommands, { kind: 'fire-and-forget', command }));\n\t\tconst submitCommand = (command: EngineCommand): Effect.Effect<void, unknown> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst completion = yield* Deferred.make<Exit.Exit<void, unknown>>();\n\t\t\t\tyield* Queue.offer(queuedCommands, {\n\t\t\t\t\tkind: 'submitted',\n\t\t\t\t\tsubmission: { command, completion },\n\t\t\t\t});\n\t\t\t\tconst exit = yield* Deferred.await(completion);\n\t\t\t\tif (Exit.isFailure(exit)) {\n\t\t\t\t\treturn yield* Effect.failCause(exit.cause);\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Per-plugin scopes parent off the supervisor scope.\n\t\tconst supervisorScope = yield* Effect.scope;\n\n\t\tconst emit = buildTransitionEmitter(state, hub);\n\t\tconst registry = yield* buildRegistry(graph, supervisorScope, emit);\n\n\t\t// Build the control-plane `domain` accessor surface from the data\n\t\t// the supervisor holds at wiring time: the resolved registry +\n\t\t// graph, plus the (optional) snapshot orchestrator / container\n\t\t// runtime / filesystem the caller may have layered into\n\t\t// `pluginContext`. The projection stays CLOSED — `domain` reads\n\t\t// resolved plugin VALUES via the name-blind registry seam, never\n\t\t// the projection. The registry is process-scoped, so the closure\n\t\t// stays valid across `stack.restart` (only `cycle.id` bumps).\n\t\tconst controlPlaneDomain = controlPlaneDomainFromContext({\n\t\t\tpluginContext,\n\t\t\tgraph,\n\t\t\tstackOptions: stack.options,\n\t\t\tdevstackVersion: options.devstackVersion ?? null,\n\t\t\tregistry,\n\t\t\tlogStore,\n\t\t});\n\n\t\tconst pluginRuntimeContext = pluginContext.pipe(\n\t\t\tContext.add(Logger, Logger.of(logger)),\n\t\t\t// Observability store. Exposed so the control-plane `domain` can\n\t\t\t// query the cross-service log ring.\n\t\t\tContext.add(LogStore, LogStore.of(logStore)),\n\t\t\t// Expose the control plane (live projection + fire-and-forget\n\t\t\t// command dispatch + the plugin-domain accessor surface) to\n\t\t\t// in-process surfaces like the dashboard plugin. Reads the same\n\t\t\t// `state` ref and `commands` queue the supervisor itself drives.\n\t\t\tContext.add(\n\t\t\t\tControlPlaneService,\n\t\t\t\tControlPlaneService.of({\n\t\t\t\t\tstate,\n\t\t\t\t\tpublishCommand,\n\t\t\t\t\tsubmitCommand,\n\t\t\t\t\tdomain: controlPlaneDomain,\n\t\t\t\t}),\n\t\t\t),\n\t\t) as Context.Context<never>;\n\n\t\t// Declare a row for every plugin so the projection's\n\t\t// `lifecycle.statusChanged` events have a row to attach to.\n\t\t// `section` is plugin-declared at `definePlugin({ section })`\n\t\t// time; we stamp it onto the row here so the TUI groups rows\n\t\t// without pattern-matching on plugin-name substrings.\n\t\tfor (const [key, node] of graph.nodes) {\n\t\t\tconst declaredAccount = pendingAccountProjection(key, node.member.id, Date.now());\n\t\t\tyield* SubscriptionRef.update(state, (s) => ({\n\t\t\t\t...(declaredAccount === null ? s : declareAccount(s, declaredAccount)),\n\t\t\t\trows: s.rows.some((r) => r.key === key)\n\t\t\t\t\t? s.rows\n\t\t\t\t\t: [\n\t\t\t\t\t\t\t...s.rows,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\t\trole: node.member.role,\n\t\t\t\t\t\t\t\tstatus: 'pending' as LifecycleStatus,\n\t\t\t\t\t\t\t\tphase: null,\n\t\t\t\t\t\t\t\tlastError: null,\n\t\t\t\t\t\t\t\tlogTail: { lines: [], level: 'info' as const, truncated: false },\n\t\t\t\t\t\t\t\tendpoints: [],\n\t\t\t\t\t\t\t\tselectiveRestartHighlight: false,\n\t\t\t\t\t\t\t\tsection: node.member.section,\n\t\t\t\t\t\t\t\tendpointSection: node.member.endpointSection ?? node.member.section,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t}));\n\t\t}\n\n\t\t// Extract `RuntimeRoot` from the plugin context — recorded on\n\t\t// `SupervisorState.runtimeRoot` and read by the post-acquire hook\n\t\t// + background tasks (NOT threaded into the acquire path, which is\n\t\t// name-blind). Fallback to '' for bare smoke tests that don't wire\n\t\t// RuntimeRoot; emit a logWarning when that path fires so\n\t\t// production-style misconfigurations are visible (plugins computing\n\t\t// `${runtimeRoot}/foo` would otherwise silently resolve to\n\t\t// host-filesystem root).\n\t\tconst runtimeRootResolved = runtimeRootAccess.read(pluginContext, { root: '' });\n\t\tif (runtimeRootResolved.root === '') {\n\t\t\tyield* Effect.logWarning(\n\t\t\t\t'supervisor: RuntimeRoot missing from pluginContext; falling back to empty root. ' +\n\t\t\t\t\t'Production wiring must layer `layerRuntimeRoot(...)` into pluginContext.',\n\t\t\t);\n\t\t}\n\t\tconst runtimeRoot = runtimeRootResolved.root;\n\n\t\tconst enableCommandLoop = options.commandLoop !== false;\n\t\tif (enableCommandLoop) {\n\t\t\tyield* Effect.forkScoped(installSignalHandler(commands));\n\t\t\tyield* Effect.forkScoped(\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tconst command = yield* Queue.take(commands);\n\t\t\t\t\t\tyield* Queue.offer(queuedCommands, { kind: 'fire-and-forget', command });\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst supervisorState: SupervisorState = {\n\t\t\tgraph,\n\t\t\tregistry,\n\t\t\tref: state,\n\t\t\thub,\n\t\t\tqueuedCommands,\n\t\t\tsupervisorScope,\n\t\t\tstackRestartTask,\n\t\t\tshutdownLatch,\n\t\t\tshutdownComplete,\n\t\t\tpluginContext: pluginRuntimeContext,\n\t\t\tdispatcher,\n\t\t\tlogger,\n\t\t\tidentity,\n\t\t\truntimeRoot,\n\t\t\tcommandHandler,\n\t\t\tpostAcquireHook,\n\t\t};\n\n\t\tconst runInitialAcquire = Effect.gen(function* () {\n\t\t\tconst alreadyStarted = yield* Ref.modify(initialAcquireStarted, (started) => [started, true]);\n\t\t\tif (alreadyStarted) return;\n\t\t\tif (yield* Ref.get(shutdownLatch)) return;\n\t\t\tyield* acquireFullGraph(\n\t\t\t\tgraph,\n\t\t\t\tregistry,\n\t\t\t\tstate,\n\t\t\t\thub,\n\t\t\t\tpluginRuntimeContext,\n\t\t\t\tdispatcher,\n\t\t\t\tlogger,\n\t\t\t\tidentity,\n\t\t\t\tsupervisorScope,\n\t\t\t);\n\t\t\tif (yield* Ref.get(shutdownLatch)) return;\n\t\t\tconst initialReady = yield* allReadyOrTerminal(graph, registry);\n\t\t\tif (initialReady) {\n\t\t\t\tyield* runPostAcquireHook(supervisorState);\n\t\t\t\tif (!(yield* Ref.get(shutdownLatch))) {\n\t\t\t\t\tyield* setCyclePhase(state, 'running');\n\t\t\t\t}\n\t\t\t} else if (!(yield* Ref.get(shutdownLatch))) {\n\t\t\t\tyield* setCyclePhase(state, 'running');\n\t\t\t}\n\t\t});\n\n\t\t// Build the watch index up front; the supervisor exposes\n\t\t// `notifyWatchFire` so the L0 thick watcher can call into it.\n\t\tconst watchIndex = buildWatchIndex(graph.nodes);\n\n\t\tconst notifyWatchFire = (path: string): Effect.Effect<void> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst matched = new Set<PluginKey>();\n\t\t\t\tfor (const entry of watchIndex) {\n\t\t\t\t\tfor (const pat of entry.paths) {\n\t\t\t\t\t\tif (exactPrefixMatch(pat, path)) {\n\t\t\t\t\t\t\tmatched.add(entry.pluginKey);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (matched.size === 0) return;\n\t\t\t\t// One `selective-restart.requested` per matched plugin, in\n\t\t\t\t// match order. (Previously the head was offered separately\n\t\t\t\t// from the tail — identical behaviour, one fewer branch.)\n\t\t\t\tfor (const key of matched) {\n\t\t\t\t\tyield* Queue.offer(commands, {\n\t\t\t\t\t\ttag: 'selective-restart.requested',\n\t\t\t\t\t\tpluginKey: key,\n\t\t\t\t\t} satisfies EngineCommand);\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Fork the command loop.\n\t\tif (enableCommandLoop) {\n\t\t\tyield* Effect.forkScoped(commandLoop(supervisorState));\n\t\t}\n\n\t\t// Tear-down finalizer: closes every plugin scope in reverse-dep\n\t\t// order. The supervisor scope itself closes when the surrounding\n\t\t// caller closes — `Scope.close` cascades to plugin scopes.\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst fullDrain = plan(graph, {\n\t\t\t\t\tkind: 'graph-keys',\n\t\t\t\t\tkeys: [...graph.nodes.keys()],\n\t\t\t\t});\n\t\t\t\tyield* teardownKeys(graph, registry, fullDrain.teardownOrder).pipe(\n\t\t\t\t\tEffect.catch(() => Effect.void),\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\n\t\tconst awaitShutdown: Effect.Effect<void> = Deferred.await(shutdownComplete);\n\n\t\t// The programmable `runCommand` surface is exactly the submit-and-await\n\t\t// path the control plane uses; share the one implementation.\n\t\tconst runCommand = submitCommand;\n\n\t\tconst handle = {\n\t\t\tidentity,\n\t\t\tgraph,\n\t\t\tregistry,\n\t\t\tevents: hub,\n\t\t\tcommands,\n\t\t\trunCommand,\n\t\t\tstate,\n\t\t\twatchIndex,\n\t\t\tnotifyWatchFire,\n\t\t\tawaitShutdown,\n\t\t} satisfies SupervisorHandle;\n\t\treturn { handle, runInitialAcquire } satisfies SupervisorStartup;\n\t});\n\n/**\n * Boot a supervisor for `stack` and wait for the initial acquire to\n * finish before returning the handle. Existing callers that only need\n * a ready-or-failed handle keep this simpler entry point; live surfaces\n * that need startup display use `startSupervisor`.\n */\nexport const supervise = (\n\tstack: SupervisedStack,\n\tidentity: Identity,\n\tstate: SubscriptionRef.SubscriptionRef<SubscribableState>,\n\tpluginContext: Context.Context<never> = Context.empty(),\n\tdispatcher: ContributionDispatcher = noopContributionDispatcher,\n\tcommandHandler?: SupervisorCommandHandler,\n\tpostAcquireHook?: SupervisorPostAcquireHook,\n): Effect.Effect<SupervisorHandle, SupervisorError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst startup = yield* startSupervisor(\n\t\t\tstack,\n\t\t\tidentity,\n\t\t\tstate,\n\t\t\tpluginContext,\n\t\t\tdispatcher,\n\t\t\tcommandHandler,\n\t\t\tpostAcquireHook,\n\t\t\t{ commandLoop: true },\n\t\t);\n\t\tyield* startup.runInitialAcquire;\n\t\treturn startup.handle;\n\t});\n\n/**\n * Block until the supervisor's shutdown latch fires OR the surrounding\n * scope is interrupted (signal-driven exit). Wraps `awaitShutdown` for\n * the common \"boot then wait\" shape.\n *\n * Returns the final supervisor state so callers (CLI, programmable\n * API) can inspect the projection after shutdown.\n */\nexport const runToShutdown = (\n\thandle: SupervisorHandle,\n): Effect.Effect<SubscribableState, never, never> =>\n\tEffect.gen(function* () {\n\t\tyield* handle.awaitShutdown;\n\t\treturn yield* SubscriptionRef.get(handle.state);\n\t});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"start-supervisor.mjs","names":["Logger"],"sources":["../../../../src/substrate/runtime/supervisor/start-supervisor.ts"],"sourcesContent":["// Top-level supervisor entry — composes every per-concern module.\n//\n// Responsibilities (in order):\n// 1. Seed projection identity + booting slice so early-mounted\n// renderers see a complete baseline.\n// 2. Resolve the dep graph + boot the registry.\n// 3. Build the substrate-wiring bag: logger overlay, runtime root, and\n// the closed contribution dispatcher.\n// 4. Compose the `SupervisorState` record (one bag passed to every\n// module).\n// 5. Build `runInitialAcquire` — the deferred initial-acquire body.\n// 6. Build the watch index + `notifyWatchFire`.\n// 7. Fork the command loop + signal handler.\n// 8. Install the scope-close finalizer (reverse-dep teardown).\n// 9. Return the handle.\n\nimport {\n\tContext,\n\tDeferred,\n\tEffect,\n\tExit,\n\ttype Fiber,\n\tQueue,\n\tRef,\n\tScope,\n\tSubscriptionRef,\n} from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { EngineCommand, EngineEvent } from '../../events.ts';\nimport type { Identity } from '../../identity.ts';\nimport type { LifecycleStatus } from '../../lifecycle.ts';\nimport type { AccountProjection, SubscribableState } from '../../projection.ts';\nimport {\n\tnoopContributionDispatcher,\n\ttype ContributionDispatcher,\n} from './contribution-dispatcher.ts';\nimport {\n\tLogger,\n\tLogStore,\n\tmakeLogStore,\n\ttype LoggerShape,\n\ttype LogStoreConfig,\n} from '../observability/index.ts';\nimport { ControlPlaneService } from '../control-plane/service.ts';\nimport { controlPlaneDomainFromContext } from '../control-plane/domain.ts';\nimport { RuntimeRoot } from '../paths.ts';\nimport { declareAccount, setIdentity } from '../projection/update.ts';\nimport {\n\tattribute,\n\tbuildWatchIndex,\n\tglobMatch,\n\tinstallSignalHandler,\n\tresolveGraph,\n\ttype PluginRegistry,\n\ttype ResolvedGraph,\n\ttype UnknownDependency,\n\ttype WatchEntry,\n} from '../lifecycle/index.ts';\nimport { acquireFullGraph, buildRegistry } from './acquire-node.ts';\nimport { commandLoop } from './command-loop.ts';\nimport { runPostAcquireHook } from './background-tasks.ts';\nimport {\n\tSupervisorBootError,\n\ttype SupervisorError,\n\ttype SupervisorPostAcquireFailed,\n} from './errors.ts';\nimport {\n\tallReadyOrTerminal,\n\ttype BackgroundTaskSlot,\n\ttype QueuedCommand,\n\ttype SupervisorCommandHandler,\n\ttype SupervisorPostAcquireHook,\n\ttype SupervisorState,\n} from './state.ts';\nimport type { SupervisedStack } from './types.ts';\nimport { teardownKeys } from './teardown.ts';\nimport { plan } from '../reconcile/graph.ts';\nimport {\n\tbuildTransitionEmitter,\n\tnoopLogger,\n\tOptionalService,\n\tsetCyclePhase,\n\twithEventPublishingLogger,\n} from './wiring.ts';\n\nconst loggerAccess = OptionalService(Logger);\nconst runtimeRootAccess = OptionalService(RuntimeRoot);\n\nexport interface SupervisorHandle {\n\treadonly identity: Identity;\n\treadonly graph: ResolvedGraph;\n\treadonly registry: PluginRegistry;\n\treadonly events: Queue.Dequeue<EngineEvent>;\n\treadonly commands: Queue.Enqueue<EngineCommand>;\n\treadonly runCommand: (command: EngineCommand) => Effect.Effect<void, unknown>;\n\treadonly state: SubscriptionRef.SubscriptionRef<SubscribableState>;\n\treadonly watchIndex: ReadonlyArray<WatchEntry>;\n\t/** Fire a watch event for the given path. Substrate-level glue:\n\t * the thick L0 watcher calls this; tests call it directly. */\n\treadonly notifyWatchFire: (path: string) => Effect.Effect<void>;\n\t/** Block until the supervisor's command loop sets the shutdown\n\t * latch. The outer runtime then closes the supervisor scope, which\n\t * tears down every plugin in reverse-dep order. */\n\treadonly awaitShutdown: Effect.Effect<void>;\n}\n\nexport interface SupervisorStartup {\n\treadonly handle: SupervisorHandle;\n\treadonly runInitialAcquire: Effect.Effect<void, SupervisorPostAcquireFailed, never>;\n}\n\nexport interface SupervisorStartupOptions {\n\treadonly commandLoop?: boolean;\n\treadonly devstackVersion?: string;\n\t/** Per-service log-store tuning. Absent fields fall back to the\n\t * `DEVSTACK_DASHBOARD_LOG_*` env vars, then the module defaults\n\t * (2000 records/service, 256 services). Threaded into the\n\t * process-scoped `makeLogStore` below. */\n\treadonly logStore?: LogStoreConfig;\n}\n\nconst pendingAccountProjection = (\n\trowKey: PluginKey,\n\tresourceId: string,\n\tupdatedAt: number,\n): AccountProjection | null => {\n\tif (!resourceId.startsWith('account/')) return null;\n\tconst name = resourceId.slice('account/'.length);\n\tif (name.length === 0) return null;\n\treturn {\n\t\tkey: resourceId as `account/${string}`,\n\t\trowKey,\n\t\tname,\n\t\taddress: null,\n\t\tscheme: null,\n\t\tsource: null,\n\t\tfunding: { status: 'pending', balanceMist: null, requestedMist: null, entries: [] },\n\t\twalletVisible: false,\n\t\tupdatedAt,\n\t};\n};\n\n/**\n * Prepare a supervisor for `stack` without running the initial acquire.\n * The returned `SupervisorHandle` is Scope-managed; the supervisor's\n * lifecycle is the surrounding Scope's lifecycle. Signal handlers,\n * the command loop, and every plugin's scope are children of the\n * supervisor scope. Callers that mount renderers can subscribe to the\n * returned state before invoking `runInitialAcquire`.\n *\n * `pluginContext` carries the substrate-context services available to\n * each plugin's `acquire` body (`IdentityContext`,\n * `ContainerRuntimeService`, `RuntimeRoot`, `StackPathsService`, etc.).\n * Plugins declare what they need by yielding the corresponding\n * `Context.Service` tag from within `Effect.gen`; the supervisor\n * provides this context before running the acquire effect so the\n * plugin's R-channel narrows to `Scope.Scope` (then to `never` after\n * the per-plugin Scope is provided).\n *\n * Contribution dispatch: the supervisor replays each plugin's\n * buffered ctx contributions through the closed `dispatcher`\n * (snapshotable/routable/codegenable/projection/strategy-contributor).\n * Production callers pass `buildProductionContributionDispatcher(...)`;\n * bare smoke tests omit it and get the no-op dispatcher.\n */\nexport const startSupervisor = (\n\tstack: SupervisedStack,\n\tidentity: Identity,\n\tstate: SubscriptionRef.SubscriptionRef<SubscribableState>,\n\tpluginContext: Context.Context<never> = Context.empty(),\n\tdispatcher: ContributionDispatcher = noopContributionDispatcher,\n\tcommandHandler?: SupervisorCommandHandler,\n\tpostAcquireHook?: SupervisorPostAcquireHook,\n\toptions: SupervisorStartupOptions = {},\n): Effect.Effect<SupervisorStartup, SupervisorBootError | UnknownDependency, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\t// Optional Logger service — pull from the plugin context if the\n\t\t// caller layered it in (CLI / e2e do). Bare smoke tests get the\n\t\t// no-op fallback so they remain log-free.\n\t\tconst baseLogger: LoggerShape = loggerAccess.read(pluginContext, noopLogger);\n\n\t\tyield* baseLogger.log('supervisor', null, {\n\t\t\tlevel: 'debug',\n\t\t\tmessage: 'supervisor boot start',\n\t\t\tfields: {\n\t\t\t\tapp: identity.app,\n\t\t\t\tstack: identity.stack,\n\t\t\t\tnetwork: identity.network,\n\t\t\t\tmemberCount: stack.members.length,\n\t\t\t},\n\t\t});\n\n\t\t// Seed the projection's identity and booting slices before\n\t\t// acquire starts so renderers mounting early have a complete\n\t\t// baseline.\n\t\tyield* SubscriptionRef.update(\n\t\t\tstate,\n\t\t\t(s) =>\n\t\t\t\t({\n\t\t\t\t\t...setIdentity(s, {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tnetwork: identity.network,\n\t\t\t\t\t}),\n\t\t\t\t\tcycle: {\n\t\t\t\t\t\t...s.cycle,\n\t\t\t\t\t\tstartedAt: s.cycle.startedAt === 0 ? Date.now() : s.cycle.startedAt,\n\t\t\t\t\t\tphase: 'booting',\n\t\t\t\t\t},\n\t\t\t\t}) satisfies SubscribableState,\n\t\t);\n\n\t\t// Resolve the dep graph.\n\t\tconst graph = yield* resolveGraph(stack.members).pipe(\n\t\t\tEffect.mapError((cause) => new SupervisorBootError({ cause })),\n\t\t);\n\n\t\t// Event hub + command channel.\n\t\tconst hub = yield* Queue.unbounded<EngineEvent>();\n\t\tconst commands = yield* Queue.unbounded<EngineCommand>();\n\t\tconst queuedCommands = yield* Queue.unbounded<QueuedCommand>();\n\t\t// Background-task fiber slot: the live stack-restart fiber (or `null`\n\t\t// when idle). The fiber IS the running state — see `BackgroundTaskSlot`.\n\t\t// Forked into `supervisorScope` (below) via `Effect.forkIn`, interrupted\n\t\t// via `Fiber.interrupt`. (Snapshot capture/restore run inline in the\n\t\t// command loop now — the bounce — so they have no forked slot.)\n\t\tconst stackRestartTask: BackgroundTaskSlot = yield* Ref.make<Fiber.Fiber<void, never> | null>(\n\t\t\tnull,\n\t\t);\n\t\tconst shutdownLatch = yield* Ref.make(false);\n\t\tconst shutdownComplete = yield* Deferred.make<void>();\n\t\tconst initialAcquireStarted = yield* Ref.make(false);\n\n\t\t// Observability store (process-scoped, like `state`/`hub`): a\n\t\t// cross-service queryable log ring fed off the SAME logger path that\n\t\t// feeds the projection's per-row tail. Survives `stack.restart`\n\t\t// because it lives in this closure (only `cycle.id` bumps on restart).\n\t\t// The dashboard reads it via the control-plane `domain`.\n\t\tconst logStore = yield* makeLogStore(options.logStore ?? {});\n\t\tconst logger = withEventPublishingLogger(baseLogger, state, hub, logStore);\n\n\t\t// The control-plane command verbs, both offering onto the SAME\n\t\t// `queuedCommands` seam the single command-loop consumer drains —\n\t\t// distinguished only by the QueuedCommand kind:\n\t\t// - `publishCommand` — fire-and-forget; offers a `fire-and-forget`\n\t\t// QueuedCommand and returns immediately.\n\t\t// - `submitCommand` — offers a `submitted` QueuedCommand carrying a\n\t\t// completion deferred, then AWAITs the real exit. So a destructive\n\t\t// command like `snapshot.restore` (which removes live managed\n\t\t// containers then re-acquires) runs in-band with the loop, never\n\t\t// racing the live supervisor out-of-band. Re-fails with the\n\t\t// handler's cause.\n\t\t// (Both feed `queuedCommands`, NOT the public `commands` queue + bridge —\n\t\t// that queue stays for the signal handler and cross-process callers.)\n\t\tconst publishCommand = (command: EngineCommand): Effect.Effect<void> =>\n\t\t\tEffect.asVoid(Queue.offer(queuedCommands, { kind: 'fire-and-forget', command }));\n\t\tconst submitCommand = (command: EngineCommand): Effect.Effect<void, unknown> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst completion = yield* Deferred.make<Exit.Exit<void, unknown>>();\n\t\t\t\tyield* Queue.offer(queuedCommands, {\n\t\t\t\t\tkind: 'submitted',\n\t\t\t\t\tsubmission: { command, completion },\n\t\t\t\t});\n\t\t\t\tconst exit = yield* Deferred.await(completion);\n\t\t\t\tif (Exit.isFailure(exit)) {\n\t\t\t\t\treturn yield* Effect.failCause(exit.cause);\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Per-plugin scopes parent off the supervisor scope.\n\t\tconst supervisorScope = yield* Effect.scope;\n\n\t\tconst emit = buildTransitionEmitter(state, hub);\n\t\tconst registry = yield* buildRegistry(graph, supervisorScope, emit);\n\n\t\t// Build the control-plane `domain` accessor surface from the data\n\t\t// the supervisor holds at wiring time: the resolved registry +\n\t\t// graph, plus the (optional) snapshot orchestrator / container\n\t\t// runtime / filesystem the caller may have layered into\n\t\t// `pluginContext`. The projection stays CLOSED — `domain` reads\n\t\t// resolved plugin VALUES via the name-blind registry seam, never\n\t\t// the projection. The registry is process-scoped, so the closure\n\t\t// stays valid across `stack.restart` (only `cycle.id` bumps).\n\t\tconst controlPlaneDomain = controlPlaneDomainFromContext({\n\t\t\tpluginContext,\n\t\t\tgraph,\n\t\t\tstackOptions: stack.options,\n\t\t\tdevstackVersion: options.devstackVersion ?? null,\n\t\t\tregistry,\n\t\t\tlogStore,\n\t\t});\n\n\t\tconst pluginRuntimeContext = pluginContext.pipe(\n\t\t\tContext.add(Logger, Logger.of(logger)),\n\t\t\t// Observability store. Exposed so the control-plane `domain` can\n\t\t\t// query the cross-service log ring.\n\t\t\tContext.add(LogStore, LogStore.of(logStore)),\n\t\t\t// Expose the control plane (live projection + fire-and-forget\n\t\t\t// command dispatch + the plugin-domain accessor surface) to\n\t\t\t// in-process surfaces like the dashboard plugin. Reads the same\n\t\t\t// `state` ref and `commands` queue the supervisor itself drives.\n\t\t\tContext.add(\n\t\t\t\tControlPlaneService,\n\t\t\t\tControlPlaneService.of({\n\t\t\t\t\tstate,\n\t\t\t\t\tpublishCommand,\n\t\t\t\t\tsubmitCommand,\n\t\t\t\t\tdomain: controlPlaneDomain,\n\t\t\t\t}),\n\t\t\t),\n\t\t) as Context.Context<never>;\n\n\t\t// Declare a row for every plugin so the projection's\n\t\t// `lifecycle.statusChanged` events have a row to attach to.\n\t\t// `section` is plugin-declared at `definePlugin({ section })`\n\t\t// time; we stamp it onto the row here so the TUI groups rows\n\t\t// without pattern-matching on plugin-name substrings.\n\t\tfor (const [key, node] of graph.nodes) {\n\t\t\tconst declaredAccount = pendingAccountProjection(key, node.member.id, Date.now());\n\t\t\tyield* SubscriptionRef.update(state, (s) => ({\n\t\t\t\t...(declaredAccount === null ? s : declareAccount(s, declaredAccount)),\n\t\t\t\trows: s.rows.some((r) => r.key === key)\n\t\t\t\t\t? s.rows\n\t\t\t\t\t: [\n\t\t\t\t\t\t\t...s.rows,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\t\trole: node.member.role,\n\t\t\t\t\t\t\t\tstatus: 'pending' as LifecycleStatus,\n\t\t\t\t\t\t\t\tphase: null,\n\t\t\t\t\t\t\t\tlastError: null,\n\t\t\t\t\t\t\t\tlogTail: { lines: [], level: 'info' as const, truncated: false },\n\t\t\t\t\t\t\t\tendpoints: [],\n\t\t\t\t\t\t\t\tselectiveRestartHighlight: false,\n\t\t\t\t\t\t\t\tsection: node.member.section,\n\t\t\t\t\t\t\t\tendpointSection: node.member.endpointSection ?? node.member.section,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t}));\n\t\t}\n\n\t\t// Extract `RuntimeRoot` from the plugin context — recorded on\n\t\t// `SupervisorState.runtimeRoot` and read by the post-acquire hook\n\t\t// + background tasks (NOT threaded into the acquire path, which is\n\t\t// name-blind). Fallback to '' for bare smoke tests that don't wire\n\t\t// RuntimeRoot; emit a logWarning when that path fires so\n\t\t// production-style misconfigurations are visible (plugins computing\n\t\t// `${runtimeRoot}/foo` would otherwise silently resolve to\n\t\t// host-filesystem root).\n\t\tconst runtimeRootResolved = runtimeRootAccess.read(pluginContext, { root: '' });\n\t\tif (runtimeRootResolved.root === '') {\n\t\t\tyield* Effect.logWarning(\n\t\t\t\t'supervisor: RuntimeRoot missing from pluginContext; falling back to empty root. ' +\n\t\t\t\t\t'Production wiring must layer `layerRuntimeRoot(...)` into pluginContext.',\n\t\t\t);\n\t\t}\n\t\tconst runtimeRoot = runtimeRootResolved.root;\n\n\t\tconst enableCommandLoop = options.commandLoop !== false;\n\t\tif (enableCommandLoop) {\n\t\t\tyield* Effect.forkScoped(installSignalHandler(commands));\n\t\t\tyield* Effect.forkScoped(\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tconst command = yield* Queue.take(commands);\n\t\t\t\t\t\tyield* Queue.offer(queuedCommands, { kind: 'fire-and-forget', command });\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst supervisorState: SupervisorState = {\n\t\t\tgraph,\n\t\t\tregistry,\n\t\t\tref: state,\n\t\t\thub,\n\t\t\tqueuedCommands,\n\t\t\tsupervisorScope,\n\t\t\tstackRestartTask,\n\t\t\tshutdownLatch,\n\t\t\tshutdownComplete,\n\t\t\tpluginContext: pluginRuntimeContext,\n\t\t\tdispatcher,\n\t\t\tlogger,\n\t\t\tidentity,\n\t\t\truntimeRoot,\n\t\t\tcommandHandler,\n\t\t\tpostAcquireHook,\n\t\t};\n\n\t\tconst runInitialAcquire = Effect.gen(function* () {\n\t\t\tconst alreadyStarted = yield* Ref.modify(initialAcquireStarted, (started) => [started, true]);\n\t\t\tif (alreadyStarted) return;\n\t\t\tif (yield* Ref.get(shutdownLatch)) return;\n\t\t\tyield* acquireFullGraph(\n\t\t\t\tgraph,\n\t\t\t\tregistry,\n\t\t\t\tstate,\n\t\t\t\thub,\n\t\t\t\tpluginRuntimeContext,\n\t\t\t\tdispatcher,\n\t\t\t\tlogger,\n\t\t\t\tidentity,\n\t\t\t\tsupervisorScope,\n\t\t\t);\n\t\t\tif (yield* Ref.get(shutdownLatch)) return;\n\t\t\tconst initialReady = yield* allReadyOrTerminal(graph, registry);\n\t\t\tif (initialReady) {\n\t\t\t\tyield* runPostAcquireHook(supervisorState);\n\t\t\t\tif (!(yield* Ref.get(shutdownLatch))) {\n\t\t\t\t\tyield* setCyclePhase(state, 'running');\n\t\t\t\t}\n\t\t\t} else if (!(yield* Ref.get(shutdownLatch))) {\n\t\t\t\tyield* setCyclePhase(state, 'running');\n\t\t\t}\n\t\t});\n\n\t\t// Build the watch index up front; the supervisor exposes\n\t\t// `notifyWatchFire` so the L0 thick watcher can call into it.\n\t\tconst watchIndex = buildWatchIndex(graph.nodes);\n\n\t\tconst notifyWatchFire = (path: string): Effect.Effect<void> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Glob-aware attribution: the declared paths are globs\n\t\t\t\t// (`<src>/**/*.move`), so a literal prefix test would never\n\t\t\t\t// match a fired file path. `globMatch` honors `**`/`*`/`?`.\n\t\t\t\tconst matched = attribute(watchIndex, path, globMatch);\n\t\t\t\tif (matched.size === 0) return;\n\t\t\t\t// One `selective-restart.requested` per matched plugin, in\n\t\t\t\t// match order. (Previously the head was offered separately\n\t\t\t\t// from the tail — identical behaviour, one fewer branch.)\n\t\t\t\tfor (const key of matched) {\n\t\t\t\t\tyield* Queue.offer(commands, {\n\t\t\t\t\t\ttag: 'selective-restart.requested',\n\t\t\t\t\t\tpluginKey: key,\n\t\t\t\t\t} satisfies EngineCommand);\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Fork the command loop.\n\t\tif (enableCommandLoop) {\n\t\t\tyield* Effect.forkScoped(commandLoop(supervisorState));\n\t\t}\n\n\t\t// Tear-down finalizer: closes every plugin scope in reverse-dep\n\t\t// order. The supervisor scope itself closes when the surrounding\n\t\t// caller closes — `Scope.close` cascades to plugin scopes.\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst fullDrain = plan(graph, {\n\t\t\t\t\tkind: 'graph-keys',\n\t\t\t\t\tkeys: [...graph.nodes.keys()],\n\t\t\t\t});\n\t\t\t\tyield* teardownKeys(graph, registry, fullDrain.teardownOrder).pipe(\n\t\t\t\t\tEffect.catch(() => Effect.void),\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\n\t\tconst awaitShutdown: Effect.Effect<void> = Deferred.await(shutdownComplete);\n\n\t\t// The programmable `runCommand` surface is exactly the submit-and-await\n\t\t// path the control plane uses; share the one implementation.\n\t\tconst runCommand = submitCommand;\n\n\t\tconst handle = {\n\t\t\tidentity,\n\t\t\tgraph,\n\t\t\tregistry,\n\t\t\tevents: hub,\n\t\t\tcommands,\n\t\t\trunCommand,\n\t\t\tstate,\n\t\t\twatchIndex,\n\t\t\tnotifyWatchFire,\n\t\t\tawaitShutdown,\n\t\t} satisfies SupervisorHandle;\n\t\treturn { handle, runInitialAcquire } satisfies SupervisorStartup;\n\t});\n\n/**\n * Boot a supervisor for `stack` and wait for the initial acquire to\n * finish before returning the handle. Existing callers that only need\n * a ready-or-failed handle keep this simpler entry point; live surfaces\n * that need startup display use `startSupervisor`.\n */\nexport const supervise = (\n\tstack: SupervisedStack,\n\tidentity: Identity,\n\tstate: SubscriptionRef.SubscriptionRef<SubscribableState>,\n\tpluginContext: Context.Context<never> = Context.empty(),\n\tdispatcher: ContributionDispatcher = noopContributionDispatcher,\n\tcommandHandler?: SupervisorCommandHandler,\n\tpostAcquireHook?: SupervisorPostAcquireHook,\n): Effect.Effect<SupervisorHandle, SupervisorError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst startup = yield* startSupervisor(\n\t\t\tstack,\n\t\t\tidentity,\n\t\t\tstate,\n\t\t\tpluginContext,\n\t\t\tdispatcher,\n\t\t\tcommandHandler,\n\t\t\tpostAcquireHook,\n\t\t\t{ commandLoop: true },\n\t\t);\n\t\tyield* startup.runInitialAcquire;\n\t\treturn startup.handle;\n\t});\n\n/**\n * Block until the supervisor's shutdown latch fires OR the surrounding\n * scope is interrupted (signal-driven exit). Wraps `awaitShutdown` for\n * the common \"boot then wait\" shape.\n *\n * Returns the final supervisor state so callers (CLI, programmable\n * API) can inspect the projection after shutdown.\n */\nexport const runToShutdown = (\n\thandle: SupervisorHandle,\n): Effect.Effect<SubscribableState, never, never> =>\n\tEffect.gen(function* () {\n\t\tyield* handle.awaitShutdown;\n\t\treturn yield* SubscriptionRef.get(handle.state);\n\t});\n"],"mappings":"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"}
|
|
@@ -100,7 +100,7 @@ const commands = [
|
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
name: "apply",
|
|
103
|
-
summary: "Re-emit the per-stack
|
|
103
|
+
summary: "Re-emit the per-stack deployment file from a live or one-shot stack.",
|
|
104
104
|
usage: "devstack apply [options]",
|
|
105
105
|
lifecycle: "live-aware",
|
|
106
106
|
sideEffects: "write",
|
|
@@ -118,17 +118,17 @@ const commands = [
|
|
|
118
118
|
options: configOptions
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
|
-
name: "dump-
|
|
122
|
-
summary: "Emit the stack
|
|
123
|
-
usage: "devstack dump-
|
|
121
|
+
name: "dump-deployment",
|
|
122
|
+
summary: "Emit the stack deployment for a real-network deploy.",
|
|
123
|
+
usage: "devstack dump-deployment [options]",
|
|
124
124
|
lifecycle: "live-aware",
|
|
125
125
|
sideEffects: "write",
|
|
126
126
|
requiresDocker: true,
|
|
127
|
-
description: "Emits the stack
|
|
127
|
+
description: "Emits the stack deployment.json deployment to --out (or stdout). Reads the existing file when a supervisor is live; otherwise runs a one-shot boot to produce it, then tears down. With --network <net>, instead emits a typed deployments/<net>.ts (satisfies AppNetworkDeployment) from that network entry. The supported way to obtain a committed deployment file for a real-network deploy.",
|
|
128
128
|
options: [...configOptions, {
|
|
129
129
|
name: "out",
|
|
130
130
|
value: "path",
|
|
131
|
-
description: "Write the
|
|
131
|
+
description: "Write the deployment JSON to this file instead of stdout."
|
|
132
132
|
}]
|
|
133
133
|
},
|
|
134
134
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-tree.mjs","names":[],"sources":["../../../src/surfaces/cli/command-tree.ts"],"sourcesContent":["import { ENV_VARS } from './flags.ts';\nimport { exitCodeTable } from './sysexits.ts';\n\nexport type CommandLifecycle = 'attached' | 'live-aware' | 'one-shot' | 'offline';\n\nexport interface CommandOption {\n\treadonly name: string;\n\treadonly value?: string;\n\treadonly description: string;\n}\n\nexport interface CommandNode {\n\treadonly name: string;\n\treadonly summary: string;\n\treadonly usage: string;\n\treadonly lifecycle: CommandLifecycle;\n\treadonly sideEffects: 'none' | 'read' | 'write' | 'destructive';\n\treadonly requiresDocker: boolean;\n\treadonly description?: string;\n\treadonly arguments?: ReadonlyArray<string>;\n\treadonly options?: ReadonlyArray<CommandOption>;\n\treadonly subcommands?: ReadonlyArray<CommandNode>;\n}\n\nconst identityOptions = [\n\t{ name: 'json', description: 'Emit JSON envelope output.' },\n\t{ name: 'app', value: 'name', description: 'Override app name.' },\n\t{ name: 'stack', value: 'name', description: 'Override stack name.' },\n\t{ name: 'state-dir', value: 'path', description: 'Override state directory.' },\n\t{ name: 'verbose', description: 'Enable more verbose logging.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst configOptions = [\n\t...identityOptions,\n\t{ name: 'config', value: 'path', description: 'Override devstack.config.ts path.' },\n\t{ name: 'network', value: 'name', description: 'Override network before config import.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst confirmOptions = [\n\t...identityOptions,\n\t{ name: 'yes', description: 'Assume yes on prompts.' },\n\t{ name: 'no-input', description: 'Forbid prompts.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst globalMaintenanceOptions = [\n\t{ name: 'json', description: 'Emit JSON envelope output.' },\n\t{ name: 'state-dir', value: 'path', description: 'Override state directory.' },\n\t{ name: 'verbose', description: 'Enable more verbose logging.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst commands = [\n\t{\n\t\tname: 'up',\n\t\tsummary: 'Boot a stack and stay attached until interrupted.',\n\t\tusage: 'devstack up [options]',\n\t\tlifecycle: 'attached',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\tdescription: 'Starts the supervisor and renders the attached operator surface.',\n\t\toptions: [\n\t\t\t...configOptions,\n\t\t\t{\n\t\t\t\tname: 'renderer',\n\t\t\t\tvalue: 'tui|plain|silent',\n\t\t\t\tdescription: 'Select the attached renderer.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'from-snapshot',\n\t\t\t\tvalue: 'name-or-id',\n\t\t\t\tdescription: 'Start by restoring a snapshot before the initial acquire.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'snapshot-cache',\n\t\t\t\tvalue: 'name',\n\t\t\t\tdescription: 'Use a named snapshot as a startup cache and refresh it when stale.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'snapshot-stale',\n\t\t\t\tvalue: 'warn|block|clean-start',\n\t\t\t\tdescription: 'Policy when --from-snapshot inputs differ from the current stack.',\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'apply',\n\t\tsummary: 'Re-emit the per-stack ids file and dev extras from a live or one-shot stack.',\n\t\tusage: 'devstack apply [options]',\n\t\tlifecycle: 'live-aware',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\toptions: configOptions,\n\t},\n\t{\n\t\tname: 'codegen',\n\t\tsummary: 'Regenerate committed bindings from Move source (no stack boot).',\n\t\tusage: 'devstack codegen [options]',\n\t\tlifecycle: 'one-shot',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: false,\n\t\tdescription:\n\t\t\t'Move-compiles local package sources and emits the committed src/generated tree (type bindings + sentinel-id config stubs) without booting a stack.',\n\t\toptions: configOptions,\n\t},\n\t{\n\t\tname: 'dump-ids',\n\t\tsummary: 'Emit the stack id-config (devstack-ids.json) for a real-network deploy.',\n\t\tusage: 'devstack dump-ids [options]',\n\t\tlifecycle: 'live-aware',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\tdescription:\n\t\t\t'Emits the stack devstack-ids.json id-config to --out (or stdout). Reads the existing file when a supervisor is live; otherwise runs a one-shot boot to produce it, then tears down. The supported way to obtain a committed id-config file for a real-network deploy.',\n\t\toptions: [\n\t\t\t...configOptions,\n\t\t\t{\n\t\t\t\tname: 'out',\n\t\t\t\tvalue: 'path',\n\t\t\t\tdescription: 'Write the id-config JSON to this file instead of stdout.',\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'status',\n\t\tsummary: 'Show the current stack projection (offline: from the manifest).',\n\t\tusage: 'devstack status [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'read',\n\t\trequiresDocker: false,\n\t\toptions: identityOptions,\n\t},\n\t{\n\t\tname: 'doctor',\n\t\tsummary: 'Run host and stack preflight checks.',\n\t\tusage: 'devstack doctor [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'read',\n\t\trequiresDocker: true,\n\t\toptions: identityOptions,\n\t},\n\t{\n\t\tname: 'config',\n\t\tsummary: 'Print resolved config inputs.',\n\t\tusage: 'devstack config [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'read',\n\t\trequiresDocker: false,\n\t\toptions: configOptions,\n\t},\n\t{\n\t\tname: 'schema',\n\t\tsummary: 'Emit the CLI schema.',\n\t\tusage: 'devstack schema --json',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'none',\n\t\trequiresDocker: false,\n\t\toptions: [{ name: 'json', description: 'Emit JSON schema output.' }],\n\t},\n\t{\n\t\tname: 'snapshot',\n\t\tsummary: 'Capture, restore, list, or delete stack snapshots.',\n\t\tusage: 'devstack snapshot <command> [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\tsubcommands: [\n\t\t\t{\n\t\t\t\tname: 'save',\n\t\t\t\tsummary: 'Capture a snapshot through a one-shot stack boot.',\n\t\t\t\tusage: 'devstack snapshot save [name] [options]',\n\t\t\t\tlifecycle: 'one-shot',\n\t\t\t\tsideEffects: 'write',\n\t\t\t\trequiresDocker: true,\n\t\t\t\targuments: ['name'],\n\t\t\t\toptions: [\n\t\t\t\t\t...configOptions,\n\t\t\t\t\t{ name: 'name', value: 'name', description: 'Human-readable snapshot name.' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'restore',\n\t\t\t\tsummary: 'Restore a snapshot by name or id.',\n\t\t\t\tusage: 'devstack snapshot restore <name-or-id> [options]',\n\t\t\t\tlifecycle: 'offline',\n\t\t\t\tsideEffects: 'destructive',\n\t\t\t\trequiresDocker: true,\n\t\t\t\targuments: ['name-or-id'],\n\t\t\t\toptions: confirmOptions,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'list',\n\t\t\t\tsummary: 'List snapshots for the selected stack.',\n\t\t\t\tusage: 'devstack snapshot list [options]',\n\t\t\t\tlifecycle: 'offline',\n\t\t\t\tsideEffects: 'read',\n\t\t\t\trequiresDocker: false,\n\t\t\t\toptions: identityOptions,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'delete',\n\t\t\t\tsummary: 'Delete a snapshot by name or id.',\n\t\t\t\tusage: 'devstack snapshot delete <name-or-id> [options]',\n\t\t\t\tlifecycle: 'offline',\n\t\t\t\tsideEffects: 'destructive',\n\t\t\t\trequiresDocker: false,\n\t\t\t\targuments: ['name-or-id'],\n\t\t\t\toptions: confirmOptions,\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'prune',\n\t\tsummary: 'Inventory and prune devstack-labelled Docker resources.',\n\t\tusage: 'devstack prune [--list | --dry-run | --all --yes] [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'destructive',\n\t\trequiresDocker: true,\n\t\toptions: [\n\t\t\t...globalMaintenanceOptions,\n\t\t\t{ name: 'list', description: 'List resource groups without pruning.' },\n\t\t\t{ name: 'all', description: 'Prune every idle non-shared resource group.' },\n\t\t\t{ name: 'no-containers', description: 'Do not remove containers.' },\n\t\t\t{ name: 'no-networks', description: 'Do not remove networks.' },\n\t\t\t{ name: 'no-volumes', description: 'Do not remove volumes.' },\n\t\t\t{ name: 'include-images', description: 'Also remove devstack-labelled images.' },\n\t\t\t{ name: 'dry-run', description: 'Skip mutating effects.' },\n\t\t\t{ name: 'yes', description: 'Assume yes on prompts.' },\n\t\t\t{ name: 'no-input', description: 'Forbid prompts.' },\n\t\t],\n\t},\n\t{\n\t\tname: 'wipe',\n\t\tsummary: 'Destroy all state for the selected stack.',\n\t\tusage: 'devstack wipe [--dry-run] [--yes] [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'destructive',\n\t\trequiresDocker: true,\n\t\toptions: [\n\t\t\t...identityOptions,\n\t\t\t{ name: 'dry-run', description: 'Skip mutating effects.' },\n\t\t\t{ name: 'yes', description: 'Assume yes on prompts.' },\n\t\t\t{ name: 'no-input', description: 'Forbid prompts.' },\n\t\t],\n\t},\n] as const satisfies ReadonlyArray<CommandNode>;\n\nexport const COMMAND_TREE: CommandNode = {\n\tname: 'devstack',\n\tsummary: 'Sui development stack CLI.',\n\tusage: 'devstack <command> [options]',\n\tlifecycle: 'offline',\n\tsideEffects: 'none',\n\trequiresDocker: false,\n\tdescription: 'Boot, inspect, snapshot, and manage local Sui development stacks.',\n\tsubcommands: commands,\n};\n\nexport type Verb = (typeof commands)[number]['name'];\n\nexport const VERBS: ReadonlyArray<Verb> = commands.map((command) => command.name);\n\nexport const commandSchema = () => ({\n\tschemaVersion: 1,\n\tverbs: VERBS,\n\tcommands: COMMAND_TREE,\n\texitCodes: exitCodeTable,\n\tenvVars: Object.values(ENV_VARS),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-tree.mjs","names":[],"sources":["../../../src/surfaces/cli/command-tree.ts"],"sourcesContent":["import { ENV_VARS } from './flags.ts';\nimport { exitCodeTable } from './sysexits.ts';\n\nexport type CommandLifecycle = 'attached' | 'live-aware' | 'one-shot' | 'offline';\n\nexport interface CommandOption {\n\treadonly name: string;\n\treadonly value?: string;\n\treadonly description: string;\n}\n\nexport interface CommandNode {\n\treadonly name: string;\n\treadonly summary: string;\n\treadonly usage: string;\n\treadonly lifecycle: CommandLifecycle;\n\treadonly sideEffects: 'none' | 'read' | 'write' | 'destructive';\n\treadonly requiresDocker: boolean;\n\treadonly description?: string;\n\treadonly arguments?: ReadonlyArray<string>;\n\treadonly options?: ReadonlyArray<CommandOption>;\n\treadonly subcommands?: ReadonlyArray<CommandNode>;\n}\n\nconst identityOptions = [\n\t{ name: 'json', description: 'Emit JSON envelope output.' },\n\t{ name: 'app', value: 'name', description: 'Override app name.' },\n\t{ name: 'stack', value: 'name', description: 'Override stack name.' },\n\t{ name: 'state-dir', value: 'path', description: 'Override state directory.' },\n\t{ name: 'verbose', description: 'Enable more verbose logging.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst configOptions = [\n\t...identityOptions,\n\t{ name: 'config', value: 'path', description: 'Override devstack.config.ts path.' },\n\t{ name: 'network', value: 'name', description: 'Override network before config import.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst confirmOptions = [\n\t...identityOptions,\n\t{ name: 'yes', description: 'Assume yes on prompts.' },\n\t{ name: 'no-input', description: 'Forbid prompts.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst globalMaintenanceOptions = [\n\t{ name: 'json', description: 'Emit JSON envelope output.' },\n\t{ name: 'state-dir', value: 'path', description: 'Override state directory.' },\n\t{ name: 'verbose', description: 'Enable more verbose logging.' },\n] as const satisfies ReadonlyArray<CommandOption>;\n\nconst commands = [\n\t{\n\t\tname: 'up',\n\t\tsummary: 'Boot a stack and stay attached until interrupted.',\n\t\tusage: 'devstack up [options]',\n\t\tlifecycle: 'attached',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\tdescription: 'Starts the supervisor and renders the attached operator surface.',\n\t\toptions: [\n\t\t\t...configOptions,\n\t\t\t{\n\t\t\t\tname: 'renderer',\n\t\t\t\tvalue: 'tui|plain|silent',\n\t\t\t\tdescription: 'Select the attached renderer.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'from-snapshot',\n\t\t\t\tvalue: 'name-or-id',\n\t\t\t\tdescription: 'Start by restoring a snapshot before the initial acquire.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'snapshot-cache',\n\t\t\t\tvalue: 'name',\n\t\t\t\tdescription: 'Use a named snapshot as a startup cache and refresh it when stale.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'snapshot-stale',\n\t\t\t\tvalue: 'warn|block|clean-start',\n\t\t\t\tdescription: 'Policy when --from-snapshot inputs differ from the current stack.',\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'apply',\n\t\tsummary: 'Re-emit the per-stack deployment file from a live or one-shot stack.',\n\t\tusage: 'devstack apply [options]',\n\t\tlifecycle: 'live-aware',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\toptions: configOptions,\n\t},\n\t{\n\t\tname: 'codegen',\n\t\tsummary: 'Regenerate committed bindings from Move source (no stack boot).',\n\t\tusage: 'devstack codegen [options]',\n\t\tlifecycle: 'one-shot',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: false,\n\t\tdescription:\n\t\t\t'Move-compiles local package sources and emits the committed src/generated tree (type bindings + sentinel-id config stubs) without booting a stack.',\n\t\toptions: configOptions,\n\t},\n\t{\n\t\tname: 'dump-deployment',\n\t\tsummary: 'Emit the stack deployment for a real-network deploy.',\n\t\tusage: 'devstack dump-deployment [options]',\n\t\tlifecycle: 'live-aware',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\tdescription:\n\t\t\t'Emits the stack deployment.json deployment to --out (or stdout). Reads the existing file when a supervisor is live; otherwise runs a one-shot boot to produce it, then tears down. With --network <net>, instead emits a typed deployments/<net>.ts (satisfies AppNetworkDeployment) from that network entry. The supported way to obtain a committed deployment file for a real-network deploy.',\n\t\toptions: [\n\t\t\t...configOptions,\n\t\t\t{\n\t\t\t\tname: 'out',\n\t\t\t\tvalue: 'path',\n\t\t\t\tdescription: 'Write the deployment JSON to this file instead of stdout.',\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'status',\n\t\tsummary: 'Show the current stack projection (offline: from the manifest).',\n\t\tusage: 'devstack status [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'read',\n\t\trequiresDocker: false,\n\t\toptions: identityOptions,\n\t},\n\t{\n\t\tname: 'doctor',\n\t\tsummary: 'Run host and stack preflight checks.',\n\t\tusage: 'devstack doctor [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'read',\n\t\trequiresDocker: true,\n\t\toptions: identityOptions,\n\t},\n\t{\n\t\tname: 'config',\n\t\tsummary: 'Print resolved config inputs.',\n\t\tusage: 'devstack config [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'read',\n\t\trequiresDocker: false,\n\t\toptions: configOptions,\n\t},\n\t{\n\t\tname: 'schema',\n\t\tsummary: 'Emit the CLI schema.',\n\t\tusage: 'devstack schema --json',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'none',\n\t\trequiresDocker: false,\n\t\toptions: [{ name: 'json', description: 'Emit JSON schema output.' }],\n\t},\n\t{\n\t\tname: 'snapshot',\n\t\tsummary: 'Capture, restore, list, or delete stack snapshots.',\n\t\tusage: 'devstack snapshot <command> [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'write',\n\t\trequiresDocker: true,\n\t\tsubcommands: [\n\t\t\t{\n\t\t\t\tname: 'save',\n\t\t\t\tsummary: 'Capture a snapshot through a one-shot stack boot.',\n\t\t\t\tusage: 'devstack snapshot save [name] [options]',\n\t\t\t\tlifecycle: 'one-shot',\n\t\t\t\tsideEffects: 'write',\n\t\t\t\trequiresDocker: true,\n\t\t\t\targuments: ['name'],\n\t\t\t\toptions: [\n\t\t\t\t\t...configOptions,\n\t\t\t\t\t{ name: 'name', value: 'name', description: 'Human-readable snapshot name.' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'restore',\n\t\t\t\tsummary: 'Restore a snapshot by name or id.',\n\t\t\t\tusage: 'devstack snapshot restore <name-or-id> [options]',\n\t\t\t\tlifecycle: 'offline',\n\t\t\t\tsideEffects: 'destructive',\n\t\t\t\trequiresDocker: true,\n\t\t\t\targuments: ['name-or-id'],\n\t\t\t\toptions: confirmOptions,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'list',\n\t\t\t\tsummary: 'List snapshots for the selected stack.',\n\t\t\t\tusage: 'devstack snapshot list [options]',\n\t\t\t\tlifecycle: 'offline',\n\t\t\t\tsideEffects: 'read',\n\t\t\t\trequiresDocker: false,\n\t\t\t\toptions: identityOptions,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'delete',\n\t\t\t\tsummary: 'Delete a snapshot by name or id.',\n\t\t\t\tusage: 'devstack snapshot delete <name-or-id> [options]',\n\t\t\t\tlifecycle: 'offline',\n\t\t\t\tsideEffects: 'destructive',\n\t\t\t\trequiresDocker: false,\n\t\t\t\targuments: ['name-or-id'],\n\t\t\t\toptions: confirmOptions,\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'prune',\n\t\tsummary: 'Inventory and prune devstack-labelled Docker resources.',\n\t\tusage: 'devstack prune [--list | --dry-run | --all --yes] [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'destructive',\n\t\trequiresDocker: true,\n\t\toptions: [\n\t\t\t...globalMaintenanceOptions,\n\t\t\t{ name: 'list', description: 'List resource groups without pruning.' },\n\t\t\t{ name: 'all', description: 'Prune every idle non-shared resource group.' },\n\t\t\t{ name: 'no-containers', description: 'Do not remove containers.' },\n\t\t\t{ name: 'no-networks', description: 'Do not remove networks.' },\n\t\t\t{ name: 'no-volumes', description: 'Do not remove volumes.' },\n\t\t\t{ name: 'include-images', description: 'Also remove devstack-labelled images.' },\n\t\t\t{ name: 'dry-run', description: 'Skip mutating effects.' },\n\t\t\t{ name: 'yes', description: 'Assume yes on prompts.' },\n\t\t\t{ name: 'no-input', description: 'Forbid prompts.' },\n\t\t],\n\t},\n\t{\n\t\tname: 'wipe',\n\t\tsummary: 'Destroy all state for the selected stack.',\n\t\tusage: 'devstack wipe [--dry-run] [--yes] [options]',\n\t\tlifecycle: 'offline',\n\t\tsideEffects: 'destructive',\n\t\trequiresDocker: true,\n\t\toptions: [\n\t\t\t...identityOptions,\n\t\t\t{ name: 'dry-run', description: 'Skip mutating effects.' },\n\t\t\t{ name: 'yes', description: 'Assume yes on prompts.' },\n\t\t\t{ name: 'no-input', description: 'Forbid prompts.' },\n\t\t],\n\t},\n] as const satisfies ReadonlyArray<CommandNode>;\n\nexport const COMMAND_TREE: CommandNode = {\n\tname: 'devstack',\n\tsummary: 'Sui development stack CLI.',\n\tusage: 'devstack <command> [options]',\n\tlifecycle: 'offline',\n\tsideEffects: 'none',\n\trequiresDocker: false,\n\tdescription: 'Boot, inspect, snapshot, and manage local Sui development stacks.',\n\tsubcommands: commands,\n};\n\nexport type Verb = (typeof commands)[number]['name'];\n\nexport const VERBS: ReadonlyArray<Verb> = commands.map((command) => command.name);\n\nexport const commandSchema = () => ({\n\tschemaVersion: 1,\n\tverbs: VERBS,\n\tcommands: COMMAND_TREE,\n\texitCodes: exitCodeTable,\n\tenvVars: Object.values(ENV_VARS),\n});\n"],"mappings":"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"}
|
|
@@ -271,16 +271,18 @@ const app = buildApplication(buildRouteMap({
|
|
|
271
271
|
return runWithFlags(this, "codegen", flags, [], (global) => this.deps.codegen.run({ configPath: global.configPath }));
|
|
272
272
|
}
|
|
273
273
|
}),
|
|
274
|
-
|
|
274
|
+
dumpDeployment: buildCommand({
|
|
275
275
|
parameters: { flags: {
|
|
276
276
|
...configFlagParams,
|
|
277
|
-
out: stringFlag("Write the
|
|
277
|
+
out: stringFlag("Write the deployment JSON to this file instead of stdout", "path"),
|
|
278
|
+
network: stringFlag("Emit a typed deployments/<network>.ts (satisfies AppNetworkDeployment) instead of the raw envelope", "name")
|
|
278
279
|
} },
|
|
279
|
-
docs: { brief: "Emit the stack
|
|
280
|
+
docs: { brief: "Emit the stack deployment (deployment.json) for a real-network deploy" },
|
|
280
281
|
func: function(flags) {
|
|
281
|
-
return runWithFlags(this, "dump-
|
|
282
|
+
return runWithFlags(this, "dump-deployment", flags, [], (global) => this.deps.dumpDeployment.run({
|
|
282
283
|
configPath: global.configPath,
|
|
283
284
|
out: flags.out,
|
|
285
|
+
network: flags.network,
|
|
284
286
|
io: this.io,
|
|
285
287
|
outputMode: global.outputMode
|
|
286
288
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["runStricli"],"sources":["../../../src/surfaces/cli/index.ts"],"sourcesContent":["// CLI surface — top-level entry point.\n//\n// The public CLI is intentionally small: `up` is the attached operator\n// surface, `apply` is live-aware reconcile (publish to `up` when it is\n// running, one-shot otherwise), and every other command is offline/direct.\n\nimport {\n\tbuildApplication,\n\tbuildChoiceParser,\n\tbuildCommand,\n\tbuildRouteMap,\n\trun as runStricli,\n\ttext_en,\n\ttype CommandContext as StricliCommandContext,\n\ttype StricliProcess,\n} from '@stricli/core';\nimport { Effect, type Scope } from 'effect';\n\nimport { commandSchema } from './command-tree.ts';\nimport { type CliError, CliInternalError, CliUsageError, exitCodeFor } from './errors.ts';\nimport {\n\ttype CliRendererMode,\n\tENV_VARS,\n\ttype GlobalFlags,\n\ttype OutputMode,\n\ttype SnapshotStalePolicy,\n} from './flags.ts';\nimport { ExitCode } from './sysexits.ts';\nimport { parseDevstackNetworkName } from '../../api/inference-network.ts';\nimport { type CliIO, emitFailure, emitSuccess, nodeProcessIO } from './output.ts';\nimport {\n\ttype CommandResult,\n\ttype ConfigDeps,\n\ttype DoctorDeps,\n\ttype PruneDeps,\n\ttype PruneResourceScope,\n\ttype SnapshotDeps,\n\ttype StatusDeps,\n\ttype WipeDeps,\n\trunConfig,\n\trunDoctor,\n\trunPrune,\n\trunSnapshot,\n\trunStatus,\n\trunWipe,\n} from './commands/index.ts';\nimport { readDevstackVersion } from '../../cli/wirings/read-devstack-version.ts';\n\n// -----------------------------------------------------------------------------\n// Deps bundle\n// -----------------------------------------------------------------------------\n\nexport interface LifecycleCommandDeps {\n\treadonly run: (flags: GlobalFlags) => Effect.Effect<CommandResult, CliError>;\n}\n\n/** The stack-free `codegen` verb takes only a config path — it boots no\n * stack, so it needs no renderer/snapshot/identity flags. */\nexport interface CodegenCommandDeps {\n\treadonly run: (flags: {\n\t\treadonly configPath: string | undefined;\n\t}) => Effect.Effect<CommandResult, CliError>;\n}\n\n/** `dump-ids` emits the stack's `devstack-ids.json` id-config. It owns\n * its own output (file via `--out`, else stdout), so it receives `io`\n * and the resolved `outputMode` alongside the config path + destination. */\nexport interface DumpIdsCommandDeps {\n\treadonly run: (flags: {\n\t\treadonly configPath: string | undefined;\n\t\treadonly out: string | undefined;\n\t\treadonly io: CliIO;\n\t\treadonly outputMode: OutputMode;\n\t}) => Effect.Effect<CommandResult, CliError>;\n}\n\nexport interface CliDeps {\n\treadonly up: LifecycleCommandDeps;\n\treadonly apply: LifecycleCommandDeps;\n\treadonly codegen: CodegenCommandDeps;\n\treadonly dumpIds: DumpIdsCommandDeps;\n\treadonly status: StatusDeps;\n\treadonly snapshot: SnapshotDeps;\n\treadonly prune: PruneDeps;\n\treadonly doctor: DoctorDeps;\n\treadonly config: ConfigDeps;\n\treadonly wipe: WipeDeps;\n}\n\nexport interface DispatchEnv {\n\treadonly argv: ReadonlyArray<string>;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly stdinIsTty: boolean;\n\treadonly io?: CliIO;\n}\n\n// -----------------------------------------------------------------------------\n// Stricli context + buffered process\n// -----------------------------------------------------------------------------\n\ninterface BufferedProcess extends StricliProcess {\n\treadonly stdoutBuffer: Array<string>;\n\treadonly stderrBuffer: Array<string>;\n\texitCode?: number | string | null;\n}\n\ninterface TrackedIO extends CliIO {\n\treadonly touched: () => boolean;\n\treadonly lastExitCode: () => number | null;\n}\n\ninterface DevstackCliContext extends StricliCommandContext {\n\treadonly deps: CliDeps;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly stdinIsTty: boolean;\n\treadonly io: TrackedIO;\n\treadonly process: BufferedProcess;\n}\n\nconst makeBufferedProcess = (\n\tenv: Readonly<Record<string, string | undefined>>,\n): BufferedProcess => {\n\tconst stdoutBuffer: Array<string> = [];\n\tconst stderrBuffer: Array<string> = [];\n\treturn {\n\t\tstdoutBuffer,\n\t\tstderrBuffer,\n\t\tenv,\n\t\tstdout: {\n\t\t\twrite: (str) => {\n\t\t\t\tstdoutBuffer.push(str);\n\t\t\t},\n\t\t},\n\t\tstderr: {\n\t\t\twrite: (str) => {\n\t\t\t\tstderrBuffer.push(str);\n\t\t\t},\n\t\t},\n\t};\n};\n\nconst trackIO = (io: CliIO): TrackedIO => {\n\tlet touched = false;\n\tlet lastExitCode: number | null = null;\n\treturn {\n\t\ttouched: () => touched,\n\t\tlastExitCode: () => lastExitCode,\n\t\twriteStdout: (line) =>\n\t\t\tio.writeStdout(line).pipe(\n\t\t\t\tEffect.tap(() =>\n\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\twriteStderr: (line) =>\n\t\t\tio.writeStderr(line).pipe(\n\t\t\t\tEffect.tap(() =>\n\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\tsetExitCode: (code) =>\n\t\t\tio.setExitCode(code).pipe(\n\t\t\t\tEffect.tap(() =>\n\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t\tlastExitCode = code;\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Flag models\n// -----------------------------------------------------------------------------\n\ninterface IdentityFlags {\n\treadonly json?: boolean;\n\treadonly app?: string;\n\treadonly stack?: string;\n\treadonly stateDir?: string;\n\treadonly verbose?: boolean;\n}\n\ninterface ConfigFlags extends IdentityFlags {\n\treadonly config?: string;\n\treadonly network?: string;\n}\n\ninterface UpFlags extends ConfigFlags {\n\treadonly renderer?: CliRendererMode;\n\treadonly fromSnapshot?: string;\n\treadonly snapshotCache?: string;\n\treadonly snapshotStale?: SnapshotStalePolicy;\n}\n\ninterface DumpIdsFlags extends ConfigFlags {\n\treadonly out?: string;\n}\n\ninterface DestructiveFlags extends IdentityFlags {\n\treadonly dryRun?: boolean;\n\treadonly yes?: boolean;\n\treadonly noInput?: boolean;\n}\n\ninterface ConfirmFlags extends IdentityFlags {\n\treadonly yes?: boolean;\n\treadonly noInput?: boolean;\n}\n\ninterface PruneFlags {\n\treadonly json?: boolean;\n\treadonly stateDir?: string;\n\treadonly verbose?: boolean;\n\treadonly dryRun?: boolean;\n\treadonly yes?: boolean;\n\treadonly noInput?: boolean;\n\treadonly list?: boolean;\n\treadonly all?: boolean;\n\treadonly noContainers?: boolean;\n\treadonly noNetworks?: boolean;\n\treadonly noVolumes?: boolean;\n\treadonly includeImages?: boolean;\n}\n\ninterface SnapshotSaveFlags extends ConfigFlags {\n\treadonly name?: string;\n}\n\nconst textParser = (input: string): string => input;\n\nconst stringFlag = (brief: string, placeholder: string) =>\n\t({\n\t\tkind: 'parsed',\n\t\tparse: textParser,\n\t\toptional: true,\n\t\tplaceholder,\n\t\tbrief,\n\t}) as const;\n\nconst boolFlag = (brief: string) =>\n\t({\n\t\tkind: 'boolean',\n\t\toptional: true,\n\t\tbrief,\n\t}) as const;\n\nconst identityFlagParams = {\n\tjson: boolFlag('Emit JSON envelope output'),\n\tapp: stringFlag('Override app name', 'name'),\n\tstack: stringFlag('Override stack name', 'name'),\n\tstateDir: stringFlag('Override state directory', 'path'),\n\tverbose: boolFlag('Enable more verbose logging'),\n} as const;\n\nconst configFlagParams = {\n\t...identityFlagParams,\n\tconfig: stringFlag('Override devstack.config.ts path', 'path'),\n\tnetwork: stringFlag('Override network before config import', 'name'),\n} as const;\n\nconst destructiveFlagParams = {\n\t...identityFlagParams,\n\tdryRun: boolFlag('Skip mutating effects'),\n\tyes: boolFlag('Assume yes on prompts'),\n\tnoInput: boolFlag('Forbid prompts'),\n} as const;\n\nconst globalMaintenanceFlagParams = {\n\tjson: identityFlagParams.json,\n\tstateDir: identityFlagParams.stateDir,\n\tverbose: identityFlagParams.verbose,\n} as const;\n\nconst confirmFlagParams = {\n\t...identityFlagParams,\n\tyes: boolFlag('Assume yes on prompts'),\n\tnoInput: boolFlag('Forbid prompts'),\n} as const;\n\nconst pruneFlagParams = {\n\t...globalMaintenanceFlagParams,\n\tdryRun: destructiveFlagParams.dryRun,\n\tyes: destructiveFlagParams.yes,\n\tnoInput: destructiveFlagParams.noInput,\n\tlist: boolFlag('List devstack-labelled Docker resources without pruning'),\n\tall: boolFlag('Prune every idle non-shared resource group'),\n\tnoContainers: boolFlag('Do not remove containers'),\n\tnoNetworks: boolFlag('Do not remove networks'),\n\tnoVolumes: boolFlag('Do not remove volumes'),\n\tincludeImages: boolFlag('Also remove devstack-labelled images for selected groups'),\n} as const;\n\nconst rendererParser = buildChoiceParser(['tui', 'plain', 'silent'] as const);\nconst snapshotStaleParser = buildChoiceParser(['warn', 'block', 'clean-start'] as const);\n\nconst outputModeFrom = (\n\tflags: Pick<IdentityFlags, 'json'>,\n\tenv: Readonly<Record<string, string | undefined>>,\n): OutputMode => (flags.json === true || env[ENV_VARS.JSON] === '1' ? 'json' : 'human');\n\nconst pruneResourcesFromFlags = (flags: PruneFlags): PruneResourceScope => ({\n\tcontainers: flags.noContainers !== true,\n\tnetworks: flags.noNetworks !== true,\n\tvolumes: flags.noVolumes !== true,\n\timages: flags.includeImages === true,\n});\n\nconst optionalEnv = (\n\tvalue: string | undefined,\n\tenv: Readonly<Record<string, string | undefined>>,\n\tkey: string,\n): string | undefined => value ?? env[key];\n\nconst makeGlobalFlags = (\n\tctx: DevstackCliContext,\n\tflags: IdentityFlags & Partial<ConfigFlags & UpFlags & DestructiveFlags>,\n\trest: ReadonlyArray<string>,\n): GlobalFlags => {\n\tconst networkRaw = optionalEnv(flags.network, ctx.env, ENV_VARS.NETWORK);\n\tlet network: string | undefined;\n\tif (networkRaw !== undefined) {\n\t\ttry {\n\t\t\tnetwork = parseDevstackNetworkName(\n\t\t\t\tnetworkRaw,\n\t\t\t\tflags.network === undefined ? ENV_VARS.NETWORK : '--network',\n\t\t\t);\n\t\t} catch (cause) {\n\t\t\tthrow cause instanceof Error\n\t\t\t\t? new CliUsageError({ message: cause.message })\n\t\t\t\t: new CliInternalError({ message: 'failed to parse network flag', cause });\n\t\t}\n\t}\n\treturn {\n\t\toutputMode: outputModeFrom(flags, ctx.env),\n\t\tapp: optionalEnv(flags.app, ctx.env, ENV_VARS.APP),\n\t\tstack: optionalEnv(flags.stack, ctx.env, ENV_VARS.STACK),\n\t\tstateDir: optionalEnv(flags.stateDir, ctx.env, ENV_VARS.STATE_DIR),\n\t\tconfigPath: optionalEnv(flags.config, ctx.env, ENV_VARS.CONFIG_PATH),\n\t\tnetwork,\n\t\trenderer: flags.renderer,\n\t\tfromSnapshot: flags.fromSnapshot,\n\t\tsnapshotCache: flags.snapshotCache,\n\t\tsnapshotStalePolicy: flags.snapshotStale,\n\t\tdryRun: flags.dryRun === true,\n\t\tconfirm: {\n\t\t\tassumeYes: flags.yes === true,\n\t\t\tforbidPrompt: flags.noInput === true || ctx.env[ENV_VARS.NO_INPUT] === '1',\n\t\t\tstdinIsTty: ctx.stdinIsTty,\n\t\t},\n\t\tverbose: flags.verbose === true,\n\t\trest,\n\t};\n};\n\n/**\n * Bridge the CLI `--network` flag through `process.env` so config-load-time\n * factory reads pick it up. This indirection is deliberate, not a leak.\n *\n * Why the mutation exists:\n * The `deepbook()` factory (`plugins/deepbook/index.ts`) defaults its mode\n * by reading `process.env.DEVSTACK_NETWORK` at config import time — before\n * any flag value has reached the orchestrator. To make `--network` affect\n * the same default, we must mutate the env BEFORE the user's\n * `devstack.config.ts` is loaded. The chain is:\n * `--network=<net>` flag → setNetworkEnv → `process.env.DEVSTACK_NETWORK`\n * → `deepbook()` factory's env read at import.\n *\n * Why save/restore (and a scoped finalizer) matters:\n * The CLI is also invoked from tests and embedded harnesses inside a single\n * process. An unscoped mutation leaks across invocations: a test that runs\n * `dispatch(['up','--network=testnet'])` followed by `dispatch(['up'])`\n * would see the second call inherit `testnet` from the first. The\n * finalizer restores the prior value (or deletes the key if it was unset)\n * on success, failure, AND interrupt — `Effect.addFinalizer` guarantees\n * the cleanup runs regardless of how the scope closes.\n */\nconst setNetworkEnv = (flags: GlobalFlags): Effect.Effect<void, never, Scope.Scope> => {\n\tif (flags.network === undefined) return Effect.void;\n\tconst next = flags.network;\n\treturn Effect.gen(function* () {\n\t\tconst prior = process.env[ENV_VARS.NETWORK];\n\t\tprocess.env[ENV_VARS.NETWORK] = next;\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tif (prior === undefined) {\n\t\t\t\t\tdelete process.env[ENV_VARS.NETWORK];\n\t\t\t\t} else {\n\t\t\t\t\tprocess.env[ENV_VARS.NETWORK] = prior;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t});\n};\n\n// -----------------------------------------------------------------------------\n// Command execution helpers\n// -----------------------------------------------------------------------------\n\nconst runCommandEffect = async (\n\tctx: DevstackCliContext,\n\tcommand: string,\n\tflags: GlobalFlags,\n\teffect: Effect.Effect<CommandResult, CliError>,\n): Promise<void> => {\n\t// `setNetworkEnv` registers a `process.env[ENV_VARS.NETWORK]` restore as a\n\t// scope finalizer; the outer `Effect.scoped` closes that scope after the\n\t// command completes (success, failure, or interrupt), preventing env leaks\n\t// between concurrent CLI invocations in the same process.\n\tconst program = Effect.scoped(\n\t\tsetNetworkEnv(flags).pipe(\n\t\t\tEffect.andThen(effect),\n\t\t\tEffect.catch((error: CliError) =>\n\t\t\t\temitFailure(ctx.io, flags.outputMode, {\n\t\t\t\t\tcommand,\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\terror,\n\t\t\t\t}).pipe(Effect.as({ exitCode: exitCodeFor(error) })),\n\t\t\t),\n\t\t\tEffect.catchCause((cause) =>\n\t\t\t\temitFailure(ctx.io, flags.outputMode, {\n\t\t\t\t\tcommand,\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\terror: new CliInternalError({ message: 'unexpected internal failure' }),\n\t\t\t\t\tcause,\n\t\t\t\t}).pipe(Effect.as({ exitCode: ExitCode.SOFTWARE })),\n\t\t\t),\n\t\t),\n\t);\n\tconst result = await Effect.runPromise(program);\n\tif (ctx.io.lastExitCode() === null) {\n\t\tawait Effect.runPromise(ctx.io.setExitCode(result.exitCode));\n\t}\n};\n\nconst runWithFlags = async (\n\tctx: DevstackCliContext,\n\tcommand: string,\n\trawFlags: IdentityFlags & Partial<ConfigFlags & UpFlags & DestructiveFlags>,\n\trest: ReadonlyArray<string>,\n\teffect: (flags: GlobalFlags) => Effect.Effect<CommandResult, CliError>,\n): Promise<void> => {\n\tlet flags: GlobalFlags;\n\ttry {\n\t\tflags = makeGlobalFlags(ctx, rawFlags, rest);\n\t} catch (cause) {\n\t\tconst error =\n\t\t\tcause instanceof CliUsageError\n\t\t\t\t? cause\n\t\t\t\t: new CliInternalError({ message: 'failed to resolve CLI flags', cause });\n\t\tconst mode = outputModeFrom(rawFlags, ctx.env);\n\t\tawait Effect.runPromise(\n\t\t\temitFailure(ctx.io, mode, {\n\t\t\t\tcommand,\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\tawait runCommandEffect(ctx, command, flags, effect(flags));\n};\n\nconst requiredPositional = (placeholder: string, brief: string) =>\n\t({\n\t\tparse: textParser,\n\t\tplaceholder,\n\t\tbrief,\n\t}) as const;\n\nconst optionalPositional = (placeholder: string, brief: string) =>\n\t({\n\t\tparse: textParser,\n\t\tplaceholder,\n\t\tbrief,\n\t\toptional: true as const,\n\t}) as const;\n\n// -----------------------------------------------------------------------------\n// Commands\n// -----------------------------------------------------------------------------\n\nconst upCommand = buildCommand<UpFlags, [], DevstackCliContext>({\n\tparameters: {\n\t\tflags: {\n\t\t\t...configFlagParams,\n\t\t\trenderer: {\n\t\t\t\tkind: 'parsed',\n\t\t\t\tparse: rendererParser,\n\t\t\t\toptional: true,\n\t\t\t\tplaceholder: 'tui|plain|silent',\n\t\t\t\tbrief: 'Select the attached renderer',\n\t\t\t},\n\t\t\tfromSnapshot: stringFlag('Start by restoring a named snapshot before acquire', 'name-or-id'),\n\t\t\tsnapshotCache: stringFlag(\n\t\t\t\t'Use a named snapshot as a startup cache and refresh it when stale',\n\t\t\t\t'name',\n\t\t\t),\n\t\t\tsnapshotStale: {\n\t\t\t\tkind: 'parsed',\n\t\t\t\tparse: snapshotStaleParser,\n\t\t\t\toptional: true,\n\t\t\t\tplaceholder: 'warn|block|clean-start',\n\t\t\t\tbrief: 'Policy when --from-snapshot inputs differ from the current stack',\n\t\t\t},\n\t\t},\n\t},\n\tdocs: {\n\t\tbrief: 'Boot a stack and stay attached until interrupted',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'up', flags, [], (global) => this.deps.up.run(global));\n\t},\n});\n\nconst applyCommand = buildCommand<ConfigFlags, [], DevstackCliContext>({\n\tparameters: { flags: configFlagParams },\n\tdocs: {\n\t\tbrief: 'Reconcile a live stack or run one-shot setup',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'apply', flags, [], (global) => this.deps.apply.run(global));\n\t},\n});\n\nconst codegenCommand = buildCommand<ConfigFlags, [], DevstackCliContext>({\n\tparameters: { flags: configFlagParams },\n\tdocs: {\n\t\tbrief: 'Regenerate committed bindings from Move source (no stack boot)',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'codegen', flags, [], (global) =>\n\t\t\tthis.deps.codegen.run({ configPath: global.configPath }),\n\t\t);\n\t},\n});\n\nconst dumpIdsCommand = buildCommand<DumpIdsFlags, [], DevstackCliContext>({\n\tparameters: {\n\t\tflags: {\n\t\t\t...configFlagParams,\n\t\t\tout: stringFlag('Write the id-config JSON to this file instead of stdout', 'path'),\n\t\t},\n\t},\n\tdocs: {\n\t\tbrief: 'Emit the stack id-config (devstack-ids.json) for a real-network deploy',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'dump-ids', flags, [], (global) =>\n\t\t\tthis.deps.dumpIds.run({\n\t\t\t\tconfigPath: global.configPath,\n\t\t\t\tout: flags.out,\n\t\t\t\tio: this.io,\n\t\t\t\toutputMode: global.outputMode,\n\t\t\t}),\n\t\t);\n\t},\n});\n\nconst statusCommand = buildCommand<IdentityFlags, [], DevstackCliContext>({\n\tparameters: { flags: identityFlagParams },\n\tdocs: { brief: 'Show the current stack projection (offline: from the manifest)' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'status', flags, [], (global) =>\n\t\t\trunStatus(this.deps.status, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst doctorCommand = buildCommand<IdentityFlags, [], DevstackCliContext>({\n\tparameters: { flags: identityFlagParams },\n\tdocs: { brief: 'Run host and stack preflight checks' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'doctor', flags, [], (global) =>\n\t\t\trunDoctor(this.deps.doctor, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst configCommand = buildCommand<ConfigFlags, [], DevstackCliContext>({\n\tparameters: { flags: configFlagParams },\n\tdocs: { brief: 'Print resolved config inputs' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'config', flags, [], (global) =>\n\t\t\trunConfig(this.deps.config, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst schemaCommand = buildCommand<Pick<IdentityFlags, 'json'>, [], DevstackCliContext>({\n\tparameters: { flags: { json: identityFlagParams.json } },\n\tdocs: { brief: 'Emit the CLI schema' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'schema', flags, [], (global) => {\n\t\t\tconst data = { ...commandSchema(), outputMode: global.outputMode };\n\t\t\treturn emitSuccess(this.io, global.outputMode, {\n\t\t\t\tcommand: 'schema',\n\t\t\t\telapsedMs: 0,\n\t\t\t\tdata,\n\t\t\t\thumanLines: [JSON.stringify(data, null, 2)],\n\t\t\t}).pipe(Effect.as({ exitCode: 0 }));\n\t\t});\n\t},\n});\n\nconst snapshotSaveCommand = buildCommand<\n\tSnapshotSaveFlags,\n\t[string | undefined],\n\tDevstackCliContext\n>({\n\tparameters: {\n\t\tflags: {\n\t\t\t...configFlagParams,\n\t\t\tname: stringFlag('Human-readable snapshot name', 'name'),\n\t\t},\n\t\tpositional: { kind: 'tuple', parameters: [optionalPositional('name', 'snapshot name')] },\n\t},\n\tdocs: { brief: 'Capture a snapshot' },\n\tfunc: function (flags, snapshotName) {\n\t\tconst rest = [\n\t\t\t'save',\n\t\t\t...(snapshotName === undefined ? [] : [snapshotName]),\n\t\t\t...(flags.name === undefined ? [] : ['--name', flags.name]),\n\t\t];\n\t\treturn runWithFlags(this, 'snapshot save', flags, rest, (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotRestoreCommand = buildCommand<ConfirmFlags, [string], DevstackCliContext>({\n\tparameters: {\n\t\tflags: confirmFlagParams,\n\t\tpositional: {\n\t\t\tkind: 'tuple',\n\t\t\tparameters: [requiredPositional('name-or-id', 'snapshot name or id')],\n\t\t},\n\t},\n\tdocs: { brief: 'Restore a snapshot' },\n\tfunc: function (flags, snapshotRef) {\n\t\treturn runWithFlags(this, 'snapshot restore', flags, ['restore', snapshotRef], (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotListCommand = buildCommand<IdentityFlags, [], DevstackCliContext>({\n\tparameters: { flags: identityFlagParams },\n\tdocs: { brief: 'List snapshots' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'snapshot list', flags, ['list'], (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotDeleteCommand = buildCommand<ConfirmFlags, [string], DevstackCliContext>({\n\tparameters: {\n\t\tflags: confirmFlagParams,\n\t\tpositional: {\n\t\t\tkind: 'tuple',\n\t\t\tparameters: [requiredPositional('name-or-id', 'snapshot name or id')],\n\t\t},\n\t},\n\tdocs: { brief: 'Delete a snapshot' },\n\tfunc: function (flags, snapshotRef) {\n\t\treturn runWithFlags(this, 'snapshot delete', flags, ['delete', snapshotRef], (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotCommands = buildRouteMap({\n\troutes: {\n\t\tsave: snapshotSaveCommand,\n\t\trestore: snapshotRestoreCommand,\n\t\tlist: snapshotListCommand,\n\t\tdelete: snapshotDeleteCommand,\n\t},\n\tdocs: { brief: 'Capture, restore, list, or delete stack snapshots' },\n});\n\nconst pruneCommand = buildCommand<PruneFlags, [], DevstackCliContext>({\n\tparameters: { flags: pruneFlagParams },\n\tdocs: { brief: 'Inventory and prune devstack-labelled Docker resources' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'prune', flags, [], (global) =>\n\t\t\trunPrune(\n\t\t\t\tthis.deps.prune,\n\t\t\t\t{ flags: global, io: this.io },\n\t\t\t\t{\n\t\t\t\t\tmode: flags.list === true ? 'list' : flags.all === true ? 'all' : 'auto',\n\t\t\t\t\tresources: pruneResourcesFromFlags(flags),\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\t},\n});\n\nconst wipeCommand = buildCommand<DestructiveFlags, [], DevstackCliContext>({\n\tparameters: { flags: destructiveFlagParams },\n\tdocs: { brief: 'Destroy all state for the selected stack' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'wipe', flags, [], (global) =>\n\t\t\trunWipe(this.deps.wipe, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst root = buildRouteMap({\n\troutes: {\n\t\tup: upCommand,\n\t\tapply: applyCommand,\n\t\tcodegen: codegenCommand,\n\t\tdumpIds: dumpIdsCommand,\n\t\tstatus: statusCommand,\n\t\tdoctor: doctorCommand,\n\t\tconfig: configCommand,\n\t\tschema: schemaCommand,\n\t\tsnapshot: snapshotCommands,\n\t\tprune: pruneCommand,\n\t\twipe: wipeCommand,\n\t},\n\tdocs: {\n\t\tbrief: 'Sui development stack CLI',\n\t},\n});\n\nconst app = buildApplication(root, {\n\tname: 'devstack',\n\tversionInfo: { currentVersion: readDevstackVersion() },\n\tscanner: { caseStyle: 'allow-kebab-for-camel' },\n\tdocumentation: {\n\t\tcaseStyle: 'convert-camel-to-kebab',\n\t\tdisableAnsiColor: true,\n\t\tonlyRequiredInUsageLine: true,\n\t},\n\tlocalization: {\n\t\tloadText: () => ({\n\t\t\t...text_en,\n\t\t\texceptionWhileParsingArguments: (error) =>\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t}),\n\t},\n});\n\nconst jsonRequested = (\n\targv: ReadonlyArray<string>,\n\tenv: Readonly<Record<string, string | undefined>>,\n): boolean => env[ENV_VARS.JSON] === '1' || argv.includes('--json');\n\n/**\n * Project a `BufferedProcess.exitCode` to a sysexit code AT THE\n * STRICLI-PARSE BOUNDARY ONLY.\n *\n * Contract: `BufferedProcess.exitCode` is mutated ONLY by Stricli's\n * argv-parser when an argv parse step fails (unknown subcommand,\n * malformed flag value, missing required positional). Verbs route\n * their own outcomes through `ctx.io.setExitCode`, which marks\n * `io.touched()` and short-circuits this projection in `dispatch`\n * before `flushBufferedProcess` is reached.\n *\n * A non-zero value here means Stricli rejected argv before any verb\n * ran, so mapping to `USAGE` holds by construction. Kept as a named\n * function so the invariant is documented at the call site.\n */\nconst normalizeStricliExitCode = (code: number | string | null | undefined): number => {\n\tif (typeof code === 'number' && code !== 0) return ExitCode.USAGE;\n\treturn ExitCode.OK;\n};\n\n/**\n * Bridge Stricli's synchronous `StricliProcess.{stdout,stderr}.write`\n * shape to our async (Effect-based) `CliIO` surface.\n *\n * The indirection is load-bearing for the JSON-envelope contract:\n * Stricli writes argv-parse errors to stderr the moment the parser\n * trips, but `--json` mode demands the failure be EMITTED as a\n * structured envelope on stdout (not raw text on stderr) with exit\n * code `EX_USAGE`. We can't wire Stricli's `stderr.write` directly to\n * `nodeProcessIO.writeStderr` because:\n *\n * 1. The stderr bytes are the raw parser error text; in `--json`\n * mode we need to transform them into a failure envelope.\n * 2. We don't know whether the verb handler \"touched\" the IO\n * (rendered its own envelope) until after Stricli returns.\n *\n * Buffering lets us delay the decision until both signals are\n * available. Tests substitute a `BufferedProcess` whose buffers are\n * later inspected, mirroring the prod flush behavior.\n */\nconst flushBufferedProcess = (\n\tprocess: BufferedProcess,\n\tio: CliIO,\n\targv: ReadonlyArray<string>,\n\tenv: Readonly<Record<string, string | undefined>>,\n): Effect.Effect<void> =>\n\tEffect.gen(function* () {\n\t\tconst exitCode = normalizeStricliExitCode(process.exitCode);\n\t\tconst stdout = process.stdoutBuffer.join('');\n\t\tconst stderr = process.stderrBuffer.join('').trim();\n\t\tif (exitCode !== 0 && jsonRequested(argv, env)) {\n\t\t\tyield* emitFailure(io, 'json', {\n\t\t\t\tcommand: '(parse)',\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror: new CliUsageError({\n\t\t\t\t\tmessage: stderr.length > 0 ? stderr : 'invalid command line',\n\t\t\t\t}),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (stdout.length > 0)\n\t\t\tyield* io.writeStdout(stdout.endsWith('\\n') ? stdout.slice(0, -1) : stdout);\n\t\tif (stderr.length > 0) yield* io.writeStderr(stderr);\n\t\tyield* io.setExitCode(exitCode);\n\t});\n\nexport const dispatch = (deps: CliDeps, dispatchEnv: DispatchEnv): Effect.Effect<void> =>\n\tEffect.gen(function* () {\n\t\tconst io = trackIO(dispatchEnv.io ?? nodeProcessIO);\n\t\tconst process = makeBufferedProcess(dispatchEnv.env);\n\t\tconst ctx: DevstackCliContext = {\n\t\t\tprocess,\n\t\t\tdeps,\n\t\t\tenv: dispatchEnv.env,\n\t\t\tstdinIsTty: dispatchEnv.stdinIsTty,\n\t\t\tio,\n\t\t};\n\t\tyield* Effect.tryPromise({\n\t\t\ttry: () => runStricli(app, dispatchEnv.argv, ctx),\n\t\t\tcatch: (cause) => new CliInternalError({ message: 'CLI dispatcher failed', cause }),\n\t\t}).pipe(\n\t\t\tEffect.catch((error: CliError) =>\n\t\t\t\temitFailure(io, jsonRequested(dispatchEnv.argv, dispatchEnv.env) ? 'json' : 'human', {\n\t\t\t\t\tcommand: '(dispatch)',\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\terror,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tif (!io.touched()) {\n\t\t\tyield* flushBufferedProcess(process, io, dispatchEnv.argv, dispatchEnv.env);\n\t\t}\n\t});\n\n// -----------------------------------------------------------------------------\n// Re-exports\n// -----------------------------------------------------------------------------\n\nexport type { CliIO } from './output.ts';\nexport type { GlobalFlags } from './flags.ts';\nexport { COMMAND_TREE, commandSchema, VERBS, type Verb } from './command-tree.ts';\nexport type { Envelope, EnvelopeError } from './envelope.ts';\nexport {\n\tENVELOPE_SCHEMA_VERSION,\n\tfailureEnvelope,\n\tstreamingEvent,\n\tsuccessEnvelope,\n\ttype StreamingEvent,\n} from './envelope.ts';\nexport { ExitCode, exitCodeName } from './sysexits.ts';\nexport {\n\ttype CliError,\n\tCliAlreadyReportedError,\n\tCliConfigInvalidError,\n\tCliConfigNotFoundError,\n\tCliConfirmDeclinedError,\n\tCliConfirmRequiredError,\n\tCliInternalError,\n\tCliSnapshotNotFoundError,\n\tCliSupervisorLiveError,\n\tCliUnavailableError,\n\tCliUsageError,\n} from './errors.ts';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["runStricli"],"sources":["../../../src/surfaces/cli/index.ts"],"sourcesContent":["// CLI surface — top-level entry point.\n//\n// The public CLI is intentionally small: `up` is the attached operator\n// surface, `apply` is live-aware reconcile (publish to `up` when it is\n// running, one-shot otherwise), and every other command is offline/direct.\n\nimport {\n\tbuildApplication,\n\tbuildChoiceParser,\n\tbuildCommand,\n\tbuildRouteMap,\n\trun as runStricli,\n\ttext_en,\n\ttype CommandContext as StricliCommandContext,\n\ttype StricliProcess,\n} from '@stricli/core';\nimport { Effect, type Scope } from 'effect';\n\nimport { commandSchema } from './command-tree.ts';\nimport { type CliError, CliInternalError, CliUsageError, exitCodeFor } from './errors.ts';\nimport {\n\ttype CliRendererMode,\n\tENV_VARS,\n\ttype GlobalFlags,\n\ttype OutputMode,\n\ttype SnapshotStalePolicy,\n} from './flags.ts';\nimport { ExitCode } from './sysexits.ts';\nimport { parseDevstackNetworkName } from '../../api/inference-network.ts';\nimport { type CliIO, emitFailure, emitSuccess, nodeProcessIO } from './output.ts';\nimport {\n\ttype CommandResult,\n\ttype ConfigDeps,\n\ttype DoctorDeps,\n\ttype PruneDeps,\n\ttype PruneResourceScope,\n\ttype SnapshotDeps,\n\ttype StatusDeps,\n\ttype WipeDeps,\n\trunConfig,\n\trunDoctor,\n\trunPrune,\n\trunSnapshot,\n\trunStatus,\n\trunWipe,\n} from './commands/index.ts';\nimport { readDevstackVersion } from '../../cli/wirings/read-devstack-version.ts';\n\n// -----------------------------------------------------------------------------\n// Deps bundle\n// -----------------------------------------------------------------------------\n\nexport interface LifecycleCommandDeps {\n\treadonly run: (flags: GlobalFlags) => Effect.Effect<CommandResult, CliError>;\n}\n\n/** The stack-free `codegen` verb takes only a config path — it boots no\n * stack, so it needs no renderer/snapshot/identity flags. */\nexport interface CodegenCommandDeps {\n\treadonly run: (flags: {\n\t\treadonly configPath: string | undefined;\n\t}) => Effect.Effect<CommandResult, CliError>;\n}\n\n/** `dump-deployment` emits the stack's `deployment.json` deployment. It owns\n * its own output (file via `--out`, else stdout), so it receives `io`\n * and the resolved `outputMode` alongside the config path + destination. */\nexport interface DumpDeploymentCommandDeps {\n\treadonly run: (flags: {\n\t\treadonly configPath: string | undefined;\n\t\treadonly out: string | undefined;\n\t\treadonly network: string | undefined;\n\t\treadonly io: CliIO;\n\t\treadonly outputMode: OutputMode;\n\t}) => Effect.Effect<CommandResult, CliError>;\n}\n\nexport interface CliDeps {\n\treadonly up: LifecycleCommandDeps;\n\treadonly apply: LifecycleCommandDeps;\n\treadonly codegen: CodegenCommandDeps;\n\treadonly dumpDeployment: DumpDeploymentCommandDeps;\n\treadonly status: StatusDeps;\n\treadonly snapshot: SnapshotDeps;\n\treadonly prune: PruneDeps;\n\treadonly doctor: DoctorDeps;\n\treadonly config: ConfigDeps;\n\treadonly wipe: WipeDeps;\n}\n\nexport interface DispatchEnv {\n\treadonly argv: ReadonlyArray<string>;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly stdinIsTty: boolean;\n\treadonly io?: CliIO;\n}\n\n// -----------------------------------------------------------------------------\n// Stricli context + buffered process\n// -----------------------------------------------------------------------------\n\ninterface BufferedProcess extends StricliProcess {\n\treadonly stdoutBuffer: Array<string>;\n\treadonly stderrBuffer: Array<string>;\n\texitCode?: number | string | null;\n}\n\ninterface TrackedIO extends CliIO {\n\treadonly touched: () => boolean;\n\treadonly lastExitCode: () => number | null;\n}\n\ninterface DevstackCliContext extends StricliCommandContext {\n\treadonly deps: CliDeps;\n\treadonly env: Readonly<Record<string, string | undefined>>;\n\treadonly stdinIsTty: boolean;\n\treadonly io: TrackedIO;\n\treadonly process: BufferedProcess;\n}\n\nconst makeBufferedProcess = (\n\tenv: Readonly<Record<string, string | undefined>>,\n): BufferedProcess => {\n\tconst stdoutBuffer: Array<string> = [];\n\tconst stderrBuffer: Array<string> = [];\n\treturn {\n\t\tstdoutBuffer,\n\t\tstderrBuffer,\n\t\tenv,\n\t\tstdout: {\n\t\t\twrite: (str) => {\n\t\t\t\tstdoutBuffer.push(str);\n\t\t\t},\n\t\t},\n\t\tstderr: {\n\t\t\twrite: (str) => {\n\t\t\t\tstderrBuffer.push(str);\n\t\t\t},\n\t\t},\n\t};\n};\n\nconst trackIO = (io: CliIO): TrackedIO => {\n\tlet touched = false;\n\tlet lastExitCode: number | null = null;\n\treturn {\n\t\ttouched: () => touched,\n\t\tlastExitCode: () => lastExitCode,\n\t\twriteStdout: (line) =>\n\t\t\tio.writeStdout(line).pipe(\n\t\t\t\tEffect.tap(() =>\n\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\twriteStderr: (line) =>\n\t\t\tio.writeStderr(line).pipe(\n\t\t\t\tEffect.tap(() =>\n\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\tsetExitCode: (code) =>\n\t\t\tio.setExitCode(code).pipe(\n\t\t\t\tEffect.tap(() =>\n\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t\tlastExitCode = code;\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Flag models\n// -----------------------------------------------------------------------------\n\ninterface IdentityFlags {\n\treadonly json?: boolean;\n\treadonly app?: string;\n\treadonly stack?: string;\n\treadonly stateDir?: string;\n\treadonly verbose?: boolean;\n}\n\ninterface ConfigFlags extends IdentityFlags {\n\treadonly config?: string;\n\treadonly network?: string;\n}\n\ninterface UpFlags extends ConfigFlags {\n\treadonly renderer?: CliRendererMode;\n\treadonly fromSnapshot?: string;\n\treadonly snapshotCache?: string;\n\treadonly snapshotStale?: SnapshotStalePolicy;\n}\n\ninterface DumpDeploymentFlags extends ConfigFlags {\n\treadonly out?: string;\n}\n\ninterface DestructiveFlags extends IdentityFlags {\n\treadonly dryRun?: boolean;\n\treadonly yes?: boolean;\n\treadonly noInput?: boolean;\n}\n\ninterface ConfirmFlags extends IdentityFlags {\n\treadonly yes?: boolean;\n\treadonly noInput?: boolean;\n}\n\ninterface PruneFlags {\n\treadonly json?: boolean;\n\treadonly stateDir?: string;\n\treadonly verbose?: boolean;\n\treadonly dryRun?: boolean;\n\treadonly yes?: boolean;\n\treadonly noInput?: boolean;\n\treadonly list?: boolean;\n\treadonly all?: boolean;\n\treadonly noContainers?: boolean;\n\treadonly noNetworks?: boolean;\n\treadonly noVolumes?: boolean;\n\treadonly includeImages?: boolean;\n}\n\ninterface SnapshotSaveFlags extends ConfigFlags {\n\treadonly name?: string;\n}\n\nconst textParser = (input: string): string => input;\n\nconst stringFlag = (brief: string, placeholder: string) =>\n\t({\n\t\tkind: 'parsed',\n\t\tparse: textParser,\n\t\toptional: true,\n\t\tplaceholder,\n\t\tbrief,\n\t}) as const;\n\nconst boolFlag = (brief: string) =>\n\t({\n\t\tkind: 'boolean',\n\t\toptional: true,\n\t\tbrief,\n\t}) as const;\n\nconst identityFlagParams = {\n\tjson: boolFlag('Emit JSON envelope output'),\n\tapp: stringFlag('Override app name', 'name'),\n\tstack: stringFlag('Override stack name', 'name'),\n\tstateDir: stringFlag('Override state directory', 'path'),\n\tverbose: boolFlag('Enable more verbose logging'),\n} as const;\n\nconst configFlagParams = {\n\t...identityFlagParams,\n\tconfig: stringFlag('Override devstack.config.ts path', 'path'),\n\tnetwork: stringFlag('Override network before config import', 'name'),\n} as const;\n\nconst destructiveFlagParams = {\n\t...identityFlagParams,\n\tdryRun: boolFlag('Skip mutating effects'),\n\tyes: boolFlag('Assume yes on prompts'),\n\tnoInput: boolFlag('Forbid prompts'),\n} as const;\n\nconst globalMaintenanceFlagParams = {\n\tjson: identityFlagParams.json,\n\tstateDir: identityFlagParams.stateDir,\n\tverbose: identityFlagParams.verbose,\n} as const;\n\nconst confirmFlagParams = {\n\t...identityFlagParams,\n\tyes: boolFlag('Assume yes on prompts'),\n\tnoInput: boolFlag('Forbid prompts'),\n} as const;\n\nconst pruneFlagParams = {\n\t...globalMaintenanceFlagParams,\n\tdryRun: destructiveFlagParams.dryRun,\n\tyes: destructiveFlagParams.yes,\n\tnoInput: destructiveFlagParams.noInput,\n\tlist: boolFlag('List devstack-labelled Docker resources without pruning'),\n\tall: boolFlag('Prune every idle non-shared resource group'),\n\tnoContainers: boolFlag('Do not remove containers'),\n\tnoNetworks: boolFlag('Do not remove networks'),\n\tnoVolumes: boolFlag('Do not remove volumes'),\n\tincludeImages: boolFlag('Also remove devstack-labelled images for selected groups'),\n} as const;\n\nconst rendererParser = buildChoiceParser(['tui', 'plain', 'silent'] as const);\nconst snapshotStaleParser = buildChoiceParser(['warn', 'block', 'clean-start'] as const);\n\nconst outputModeFrom = (\n\tflags: Pick<IdentityFlags, 'json'>,\n\tenv: Readonly<Record<string, string | undefined>>,\n): OutputMode => (flags.json === true || env[ENV_VARS.JSON] === '1' ? 'json' : 'human');\n\nconst pruneResourcesFromFlags = (flags: PruneFlags): PruneResourceScope => ({\n\tcontainers: flags.noContainers !== true,\n\tnetworks: flags.noNetworks !== true,\n\tvolumes: flags.noVolumes !== true,\n\timages: flags.includeImages === true,\n});\n\nconst optionalEnv = (\n\tvalue: string | undefined,\n\tenv: Readonly<Record<string, string | undefined>>,\n\tkey: string,\n): string | undefined => value ?? env[key];\n\nconst makeGlobalFlags = (\n\tctx: DevstackCliContext,\n\tflags: IdentityFlags & Partial<ConfigFlags & UpFlags & DestructiveFlags>,\n\trest: ReadonlyArray<string>,\n): GlobalFlags => {\n\tconst networkRaw = optionalEnv(flags.network, ctx.env, ENV_VARS.NETWORK);\n\tlet network: string | undefined;\n\tif (networkRaw !== undefined) {\n\t\ttry {\n\t\t\tnetwork = parseDevstackNetworkName(\n\t\t\t\tnetworkRaw,\n\t\t\t\tflags.network === undefined ? ENV_VARS.NETWORK : '--network',\n\t\t\t);\n\t\t} catch (cause) {\n\t\t\tthrow cause instanceof Error\n\t\t\t\t? new CliUsageError({ message: cause.message })\n\t\t\t\t: new CliInternalError({ message: 'failed to parse network flag', cause });\n\t\t}\n\t}\n\treturn {\n\t\toutputMode: outputModeFrom(flags, ctx.env),\n\t\tapp: optionalEnv(flags.app, ctx.env, ENV_VARS.APP),\n\t\tstack: optionalEnv(flags.stack, ctx.env, ENV_VARS.STACK),\n\t\tstateDir: optionalEnv(flags.stateDir, ctx.env, ENV_VARS.STATE_DIR),\n\t\tconfigPath: optionalEnv(flags.config, ctx.env, ENV_VARS.CONFIG_PATH),\n\t\tnetwork,\n\t\trenderer: flags.renderer,\n\t\tfromSnapshot: flags.fromSnapshot,\n\t\tsnapshotCache: flags.snapshotCache,\n\t\tsnapshotStalePolicy: flags.snapshotStale,\n\t\tdryRun: flags.dryRun === true,\n\t\tconfirm: {\n\t\t\tassumeYes: flags.yes === true,\n\t\t\tforbidPrompt: flags.noInput === true || ctx.env[ENV_VARS.NO_INPUT] === '1',\n\t\t\tstdinIsTty: ctx.stdinIsTty,\n\t\t},\n\t\tverbose: flags.verbose === true,\n\t\trest,\n\t};\n};\n\n/**\n * Bridge the CLI `--network` flag through `process.env` so config-load-time\n * factory reads pick it up. This indirection is deliberate, not a leak.\n *\n * Why the mutation exists:\n * The `deepbook()` factory (`plugins/deepbook/index.ts`) defaults its mode\n * by reading `process.env.DEVSTACK_NETWORK` at config import time — before\n * any flag value has reached the orchestrator. To make `--network` affect\n * the same default, we must mutate the env BEFORE the user's\n * `devstack.config.ts` is loaded. The chain is:\n * `--network=<net>` flag → setNetworkEnv → `process.env.DEVSTACK_NETWORK`\n * → `deepbook()` factory's env read at import.\n *\n * Why save/restore (and a scoped finalizer) matters:\n * The CLI is also invoked from tests and embedded harnesses inside a single\n * process. An unscoped mutation leaks across invocations: a test that runs\n * `dispatch(['up','--network=testnet'])` followed by `dispatch(['up'])`\n * would see the second call inherit `testnet` from the first. The\n * finalizer restores the prior value (or deletes the key if it was unset)\n * on success, failure, AND interrupt — `Effect.addFinalizer` guarantees\n * the cleanup runs regardless of how the scope closes.\n */\nconst setNetworkEnv = (flags: GlobalFlags): Effect.Effect<void, never, Scope.Scope> => {\n\tif (flags.network === undefined) return Effect.void;\n\tconst next = flags.network;\n\treturn Effect.gen(function* () {\n\t\tconst prior = process.env[ENV_VARS.NETWORK];\n\t\tprocess.env[ENV_VARS.NETWORK] = next;\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tif (prior === undefined) {\n\t\t\t\t\tdelete process.env[ENV_VARS.NETWORK];\n\t\t\t\t} else {\n\t\t\t\t\tprocess.env[ENV_VARS.NETWORK] = prior;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t});\n};\n\n// -----------------------------------------------------------------------------\n// Command execution helpers\n// -----------------------------------------------------------------------------\n\nconst runCommandEffect = async (\n\tctx: DevstackCliContext,\n\tcommand: string,\n\tflags: GlobalFlags,\n\teffect: Effect.Effect<CommandResult, CliError>,\n): Promise<void> => {\n\t// `setNetworkEnv` registers a `process.env[ENV_VARS.NETWORK]` restore as a\n\t// scope finalizer; the outer `Effect.scoped` closes that scope after the\n\t// command completes (success, failure, or interrupt), preventing env leaks\n\t// between concurrent CLI invocations in the same process.\n\tconst program = Effect.scoped(\n\t\tsetNetworkEnv(flags).pipe(\n\t\t\tEffect.andThen(effect),\n\t\t\tEffect.catch((error: CliError) =>\n\t\t\t\temitFailure(ctx.io, flags.outputMode, {\n\t\t\t\t\tcommand,\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\terror,\n\t\t\t\t}).pipe(Effect.as({ exitCode: exitCodeFor(error) })),\n\t\t\t),\n\t\t\tEffect.catchCause((cause) =>\n\t\t\t\temitFailure(ctx.io, flags.outputMode, {\n\t\t\t\t\tcommand,\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\terror: new CliInternalError({ message: 'unexpected internal failure' }),\n\t\t\t\t\tcause,\n\t\t\t\t}).pipe(Effect.as({ exitCode: ExitCode.SOFTWARE })),\n\t\t\t),\n\t\t),\n\t);\n\tconst result = await Effect.runPromise(program);\n\tif (ctx.io.lastExitCode() === null) {\n\t\tawait Effect.runPromise(ctx.io.setExitCode(result.exitCode));\n\t}\n};\n\nconst runWithFlags = async (\n\tctx: DevstackCliContext,\n\tcommand: string,\n\trawFlags: IdentityFlags & Partial<ConfigFlags & UpFlags & DestructiveFlags>,\n\trest: ReadonlyArray<string>,\n\teffect: (flags: GlobalFlags) => Effect.Effect<CommandResult, CliError>,\n): Promise<void> => {\n\tlet flags: GlobalFlags;\n\ttry {\n\t\tflags = makeGlobalFlags(ctx, rawFlags, rest);\n\t} catch (cause) {\n\t\tconst error =\n\t\t\tcause instanceof CliUsageError\n\t\t\t\t? cause\n\t\t\t\t: new CliInternalError({ message: 'failed to resolve CLI flags', cause });\n\t\tconst mode = outputModeFrom(rawFlags, ctx.env);\n\t\tawait Effect.runPromise(\n\t\t\temitFailure(ctx.io, mode, {\n\t\t\t\tcommand,\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\tawait runCommandEffect(ctx, command, flags, effect(flags));\n};\n\nconst requiredPositional = (placeholder: string, brief: string) =>\n\t({\n\t\tparse: textParser,\n\t\tplaceholder,\n\t\tbrief,\n\t}) as const;\n\nconst optionalPositional = (placeholder: string, brief: string) =>\n\t({\n\t\tparse: textParser,\n\t\tplaceholder,\n\t\tbrief,\n\t\toptional: true as const,\n\t}) as const;\n\n// -----------------------------------------------------------------------------\n// Commands\n// -----------------------------------------------------------------------------\n\nconst upCommand = buildCommand<UpFlags, [], DevstackCliContext>({\n\tparameters: {\n\t\tflags: {\n\t\t\t...configFlagParams,\n\t\t\trenderer: {\n\t\t\t\tkind: 'parsed',\n\t\t\t\tparse: rendererParser,\n\t\t\t\toptional: true,\n\t\t\t\tplaceholder: 'tui|plain|silent',\n\t\t\t\tbrief: 'Select the attached renderer',\n\t\t\t},\n\t\t\tfromSnapshot: stringFlag('Start by restoring a named snapshot before acquire', 'name-or-id'),\n\t\t\tsnapshotCache: stringFlag(\n\t\t\t\t'Use a named snapshot as a startup cache and refresh it when stale',\n\t\t\t\t'name',\n\t\t\t),\n\t\t\tsnapshotStale: {\n\t\t\t\tkind: 'parsed',\n\t\t\t\tparse: snapshotStaleParser,\n\t\t\t\toptional: true,\n\t\t\t\tplaceholder: 'warn|block|clean-start',\n\t\t\t\tbrief: 'Policy when --from-snapshot inputs differ from the current stack',\n\t\t\t},\n\t\t},\n\t},\n\tdocs: {\n\t\tbrief: 'Boot a stack and stay attached until interrupted',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'up', flags, [], (global) => this.deps.up.run(global));\n\t},\n});\n\nconst applyCommand = buildCommand<ConfigFlags, [], DevstackCliContext>({\n\tparameters: { flags: configFlagParams },\n\tdocs: {\n\t\tbrief: 'Reconcile a live stack or run one-shot setup',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'apply', flags, [], (global) => this.deps.apply.run(global));\n\t},\n});\n\nconst codegenCommand = buildCommand<ConfigFlags, [], DevstackCliContext>({\n\tparameters: { flags: configFlagParams },\n\tdocs: {\n\t\tbrief: 'Regenerate committed bindings from Move source (no stack boot)',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'codegen', flags, [], (global) =>\n\t\t\tthis.deps.codegen.run({ configPath: global.configPath }),\n\t\t);\n\t},\n});\n\nconst dumpDeploymentCommand = buildCommand<DumpDeploymentFlags, [], DevstackCliContext>({\n\tparameters: {\n\t\tflags: {\n\t\t\t...configFlagParams,\n\t\t\tout: stringFlag('Write the deployment JSON to this file instead of stdout', 'path'),\n\t\t\tnetwork: stringFlag(\n\t\t\t\t'Emit a typed deployments/<network>.ts (satisfies AppNetworkDeployment) instead of the raw envelope',\n\t\t\t\t'name',\n\t\t\t),\n\t\t},\n\t},\n\tdocs: {\n\t\tbrief: 'Emit the stack deployment (deployment.json) for a real-network deploy',\n\t},\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'dump-deployment', flags, [], (global) =>\n\t\t\tthis.deps.dumpDeployment.run({\n\t\t\t\tconfigPath: global.configPath,\n\t\t\t\tout: flags.out,\n\t\t\t\tnetwork: flags.network,\n\t\t\t\tio: this.io,\n\t\t\t\toutputMode: global.outputMode,\n\t\t\t}),\n\t\t);\n\t},\n});\n\nconst statusCommand = buildCommand<IdentityFlags, [], DevstackCliContext>({\n\tparameters: { flags: identityFlagParams },\n\tdocs: { brief: 'Show the current stack projection (offline: from the manifest)' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'status', flags, [], (global) =>\n\t\t\trunStatus(this.deps.status, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst doctorCommand = buildCommand<IdentityFlags, [], DevstackCliContext>({\n\tparameters: { flags: identityFlagParams },\n\tdocs: { brief: 'Run host and stack preflight checks' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'doctor', flags, [], (global) =>\n\t\t\trunDoctor(this.deps.doctor, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst configCommand = buildCommand<ConfigFlags, [], DevstackCliContext>({\n\tparameters: { flags: configFlagParams },\n\tdocs: { brief: 'Print resolved config inputs' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'config', flags, [], (global) =>\n\t\t\trunConfig(this.deps.config, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst schemaCommand = buildCommand<Pick<IdentityFlags, 'json'>, [], DevstackCliContext>({\n\tparameters: { flags: { json: identityFlagParams.json } },\n\tdocs: { brief: 'Emit the CLI schema' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'schema', flags, [], (global) => {\n\t\t\tconst data = { ...commandSchema(), outputMode: global.outputMode };\n\t\t\treturn emitSuccess(this.io, global.outputMode, {\n\t\t\t\tcommand: 'schema',\n\t\t\t\telapsedMs: 0,\n\t\t\t\tdata,\n\t\t\t\thumanLines: [JSON.stringify(data, null, 2)],\n\t\t\t}).pipe(Effect.as({ exitCode: 0 }));\n\t\t});\n\t},\n});\n\nconst snapshotSaveCommand = buildCommand<\n\tSnapshotSaveFlags,\n\t[string | undefined],\n\tDevstackCliContext\n>({\n\tparameters: {\n\t\tflags: {\n\t\t\t...configFlagParams,\n\t\t\tname: stringFlag('Human-readable snapshot name', 'name'),\n\t\t},\n\t\tpositional: { kind: 'tuple', parameters: [optionalPositional('name', 'snapshot name')] },\n\t},\n\tdocs: { brief: 'Capture a snapshot' },\n\tfunc: function (flags, snapshotName) {\n\t\tconst rest = [\n\t\t\t'save',\n\t\t\t...(snapshotName === undefined ? [] : [snapshotName]),\n\t\t\t...(flags.name === undefined ? [] : ['--name', flags.name]),\n\t\t];\n\t\treturn runWithFlags(this, 'snapshot save', flags, rest, (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotRestoreCommand = buildCommand<ConfirmFlags, [string], DevstackCliContext>({\n\tparameters: {\n\t\tflags: confirmFlagParams,\n\t\tpositional: {\n\t\t\tkind: 'tuple',\n\t\t\tparameters: [requiredPositional('name-or-id', 'snapshot name or id')],\n\t\t},\n\t},\n\tdocs: { brief: 'Restore a snapshot' },\n\tfunc: function (flags, snapshotRef) {\n\t\treturn runWithFlags(this, 'snapshot restore', flags, ['restore', snapshotRef], (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotListCommand = buildCommand<IdentityFlags, [], DevstackCliContext>({\n\tparameters: { flags: identityFlagParams },\n\tdocs: { brief: 'List snapshots' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'snapshot list', flags, ['list'], (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotDeleteCommand = buildCommand<ConfirmFlags, [string], DevstackCliContext>({\n\tparameters: {\n\t\tflags: confirmFlagParams,\n\t\tpositional: {\n\t\t\tkind: 'tuple',\n\t\t\tparameters: [requiredPositional('name-or-id', 'snapshot name or id')],\n\t\t},\n\t},\n\tdocs: { brief: 'Delete a snapshot' },\n\tfunc: function (flags, snapshotRef) {\n\t\treturn runWithFlags(this, 'snapshot delete', flags, ['delete', snapshotRef], (global) =>\n\t\t\trunSnapshot(this.deps.snapshot, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst snapshotCommands = buildRouteMap({\n\troutes: {\n\t\tsave: snapshotSaveCommand,\n\t\trestore: snapshotRestoreCommand,\n\t\tlist: snapshotListCommand,\n\t\tdelete: snapshotDeleteCommand,\n\t},\n\tdocs: { brief: 'Capture, restore, list, or delete stack snapshots' },\n});\n\nconst pruneCommand = buildCommand<PruneFlags, [], DevstackCliContext>({\n\tparameters: { flags: pruneFlagParams },\n\tdocs: { brief: 'Inventory and prune devstack-labelled Docker resources' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'prune', flags, [], (global) =>\n\t\t\trunPrune(\n\t\t\t\tthis.deps.prune,\n\t\t\t\t{ flags: global, io: this.io },\n\t\t\t\t{\n\t\t\t\t\tmode: flags.list === true ? 'list' : flags.all === true ? 'all' : 'auto',\n\t\t\t\t\tresources: pruneResourcesFromFlags(flags),\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\t},\n});\n\nconst wipeCommand = buildCommand<DestructiveFlags, [], DevstackCliContext>({\n\tparameters: { flags: destructiveFlagParams },\n\tdocs: { brief: 'Destroy all state for the selected stack' },\n\tfunc: function (flags) {\n\t\treturn runWithFlags(this, 'wipe', flags, [], (global) =>\n\t\t\trunWipe(this.deps.wipe, { flags: global, io: this.io }),\n\t\t);\n\t},\n});\n\nconst root = buildRouteMap({\n\troutes: {\n\t\tup: upCommand,\n\t\tapply: applyCommand,\n\t\tcodegen: codegenCommand,\n\t\tdumpDeployment: dumpDeploymentCommand,\n\t\tstatus: statusCommand,\n\t\tdoctor: doctorCommand,\n\t\tconfig: configCommand,\n\t\tschema: schemaCommand,\n\t\tsnapshot: snapshotCommands,\n\t\tprune: pruneCommand,\n\t\twipe: wipeCommand,\n\t},\n\tdocs: {\n\t\tbrief: 'Sui development stack CLI',\n\t},\n});\n\nconst app = buildApplication(root, {\n\tname: 'devstack',\n\tversionInfo: { currentVersion: readDevstackVersion() },\n\tscanner: { caseStyle: 'allow-kebab-for-camel' },\n\tdocumentation: {\n\t\tcaseStyle: 'convert-camel-to-kebab',\n\t\tdisableAnsiColor: true,\n\t\tonlyRequiredInUsageLine: true,\n\t},\n\tlocalization: {\n\t\tloadText: () => ({\n\t\t\t...text_en,\n\t\t\texceptionWhileParsingArguments: (error) =>\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t}),\n\t},\n});\n\nconst jsonRequested = (\n\targv: ReadonlyArray<string>,\n\tenv: Readonly<Record<string, string | undefined>>,\n): boolean => env[ENV_VARS.JSON] === '1' || argv.includes('--json');\n\n/**\n * Project a `BufferedProcess.exitCode` to a sysexit code AT THE\n * STRICLI-PARSE BOUNDARY ONLY.\n *\n * Contract: `BufferedProcess.exitCode` is mutated ONLY by Stricli's\n * argv-parser when an argv parse step fails (unknown subcommand,\n * malformed flag value, missing required positional). Verbs route\n * their own outcomes through `ctx.io.setExitCode`, which marks\n * `io.touched()` and short-circuits this projection in `dispatch`\n * before `flushBufferedProcess` is reached.\n *\n * A non-zero value here means Stricli rejected argv before any verb\n * ran, so mapping to `USAGE` holds by construction. Kept as a named\n * function so the invariant is documented at the call site.\n */\nconst normalizeStricliExitCode = (code: number | string | null | undefined): number => {\n\tif (typeof code === 'number' && code !== 0) return ExitCode.USAGE;\n\treturn ExitCode.OK;\n};\n\n/**\n * Bridge Stricli's synchronous `StricliProcess.{stdout,stderr}.write`\n * shape to our async (Effect-based) `CliIO` surface.\n *\n * The indirection is load-bearing for the JSON-envelope contract:\n * Stricli writes argv-parse errors to stderr the moment the parser\n * trips, but `--json` mode demands the failure be EMITTED as a\n * structured envelope on stdout (not raw text on stderr) with exit\n * code `EX_USAGE`. We can't wire Stricli's `stderr.write` directly to\n * `nodeProcessIO.writeStderr` because:\n *\n * 1. The stderr bytes are the raw parser error text; in `--json`\n * mode we need to transform them into a failure envelope.\n * 2. We don't know whether the verb handler \"touched\" the IO\n * (rendered its own envelope) until after Stricli returns.\n *\n * Buffering lets us delay the decision until both signals are\n * available. Tests substitute a `BufferedProcess` whose buffers are\n * later inspected, mirroring the prod flush behavior.\n */\nconst flushBufferedProcess = (\n\tprocess: BufferedProcess,\n\tio: CliIO,\n\targv: ReadonlyArray<string>,\n\tenv: Readonly<Record<string, string | undefined>>,\n): Effect.Effect<void> =>\n\tEffect.gen(function* () {\n\t\tconst exitCode = normalizeStricliExitCode(process.exitCode);\n\t\tconst stdout = process.stdoutBuffer.join('');\n\t\tconst stderr = process.stderrBuffer.join('').trim();\n\t\tif (exitCode !== 0 && jsonRequested(argv, env)) {\n\t\t\tyield* emitFailure(io, 'json', {\n\t\t\t\tcommand: '(parse)',\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror: new CliUsageError({\n\t\t\t\t\tmessage: stderr.length > 0 ? stderr : 'invalid command line',\n\t\t\t\t}),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (stdout.length > 0)\n\t\t\tyield* io.writeStdout(stdout.endsWith('\\n') ? stdout.slice(0, -1) : stdout);\n\t\tif (stderr.length > 0) yield* io.writeStderr(stderr);\n\t\tyield* io.setExitCode(exitCode);\n\t});\n\nexport const dispatch = (deps: CliDeps, dispatchEnv: DispatchEnv): Effect.Effect<void> =>\n\tEffect.gen(function* () {\n\t\tconst io = trackIO(dispatchEnv.io ?? nodeProcessIO);\n\t\tconst process = makeBufferedProcess(dispatchEnv.env);\n\t\tconst ctx: DevstackCliContext = {\n\t\t\tprocess,\n\t\t\tdeps,\n\t\t\tenv: dispatchEnv.env,\n\t\t\tstdinIsTty: dispatchEnv.stdinIsTty,\n\t\t\tio,\n\t\t};\n\t\tyield* Effect.tryPromise({\n\t\t\ttry: () => runStricli(app, dispatchEnv.argv, ctx),\n\t\t\tcatch: (cause) => new CliInternalError({ message: 'CLI dispatcher failed', cause }),\n\t\t}).pipe(\n\t\t\tEffect.catch((error: CliError) =>\n\t\t\t\temitFailure(io, jsonRequested(dispatchEnv.argv, dispatchEnv.env) ? 'json' : 'human', {\n\t\t\t\t\tcommand: '(dispatch)',\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\terror,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tif (!io.touched()) {\n\t\t\tyield* flushBufferedProcess(process, io, dispatchEnv.argv, dispatchEnv.env);\n\t\t}\n\t});\n\n// -----------------------------------------------------------------------------\n// Re-exports\n// -----------------------------------------------------------------------------\n\nexport type { CliIO } from './output.ts';\nexport type { GlobalFlags } from './flags.ts';\nexport { COMMAND_TREE, commandSchema, VERBS, type Verb } from './command-tree.ts';\nexport type { Envelope, EnvelopeError } from './envelope.ts';\nexport {\n\tENVELOPE_SCHEMA_VERSION,\n\tfailureEnvelope,\n\tstreamingEvent,\n\tsuccessEnvelope,\n\ttype StreamingEvent,\n} from './envelope.ts';\nexport { ExitCode, exitCodeName } from './sysexits.ts';\nexport {\n\ttype CliError,\n\tCliAlreadyReportedError,\n\tCliConfigInvalidError,\n\tCliConfigNotFoundError,\n\tCliConfirmDeclinedError,\n\tCliConfirmRequiredError,\n\tCliInternalError,\n\tCliSnapshotNotFoundError,\n\tCliSupervisorLiveError,\n\tCliUnavailableError,\n\tCliUsageError,\n} from './errors.ts';\n"],"mappings":"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"}
|