@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.
Files changed (159) hide show
  1. package/README.md +1 -1
  2. package/dashboard-ui/assets/{grpc-a4usE3Nk.js → grpc-CpkDu4SA.js} +1 -1
  3. package/dashboard-ui/assets/{index-CRYJ4pru.js → index-jLPRmjst.js} +39 -33
  4. package/dashboard-ui/index.html +1 -1
  5. package/dist/api/inference-network.d.mts +5 -5
  6. package/dist/api/inference-network.mjs +5 -5
  7. package/dist/api/inference-network.mjs.map +1 -1
  8. package/dist/api/run-stack-internal.mjs +2 -3
  9. package/dist/api/run-stack-internal.mjs.map +1 -1
  10. package/dist/build-integrations/dapp-kit/index.d.mts +12 -0
  11. package/dist/build-integrations/dapp-kit/index.mjs +14 -1
  12. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -1
  13. package/dist/build-integrations/playwright/config.d.mts +2 -1
  14. package/dist/build-integrations/playwright/config.mjs +1 -1
  15. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  16. package/dist/build-integrations/playwright/errors.d.mts +1 -1
  17. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  18. package/dist/build-integrations/playwright/index.d.mts +2 -2
  19. package/dist/build-integrations/playwright/index.mjs +2 -2
  20. package/dist/build-integrations/playwright/wallet-context.d.mts +2 -1
  21. package/dist/build-integrations/playwright/wallet-context.mjs +141 -41
  22. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  23. package/dist/build-integrations/runtime/dapp-kit-slot.mjs +1 -1
  24. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  25. package/dist/build-integrations/vite/index.d.mts +82 -40
  26. package/dist/build-integrations/vite/index.mjs +281 -112
  27. package/dist/build-integrations/vite/index.mjs.map +1 -1
  28. package/dist/build-integrations/vitest/config.mjs +3 -4
  29. package/dist/build-integrations/vitest/config.mjs.map +1 -1
  30. package/dist/build-integrations/vitest/global-setup.mjs +8 -8
  31. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -1
  32. package/dist/cli/doctor-probes.mjs +7 -2
  33. package/dist/cli/doctor-probes.mjs.map +1 -1
  34. package/dist/cli/main.mjs +5 -4
  35. package/dist/cli/main.mjs.map +1 -1
  36. package/dist/cli/wirings/apply.mjs +0 -1
  37. package/dist/cli/wirings/apply.mjs.map +1 -1
  38. package/dist/cli/wirings/codegen.mjs +37 -38
  39. package/dist/cli/wirings/codegen.mjs.map +1 -1
  40. package/dist/cli/wirings/dump-deployment.mjs +141 -0
  41. package/dist/cli/wirings/dump-deployment.mjs.map +1 -0
  42. package/dist/cli/wirings/snapshot.mjs +0 -1
  43. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  44. package/dist/cli/wirings/up.mjs +7 -0
  45. package/dist/cli/wirings/up.mjs.map +1 -1
  46. package/dist/contracts/codegenable.d.mts +22 -25
  47. package/dist/contracts/codegenable.mjs +35 -4
  48. package/dist/contracts/codegenable.mjs.map +1 -1
  49. package/dist/contracts/config-bindings.mjs +43 -18
  50. package/dist/contracts/config-bindings.mjs.map +1 -1
  51. package/dist/index.mjs +1 -1
  52. package/dist/orchestrators/boot.d.mts +0 -10
  53. package/dist/orchestrators/boot.mjs +24 -54
  54. package/dist/orchestrators/boot.mjs.map +1 -1
  55. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  56. package/dist/orchestrators/codegen/config-runtime.mjs +137 -112
  57. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -1
  58. package/dist/orchestrators/codegen/deployment-network-file.mjs +130 -0
  59. package/dist/orchestrators/codegen/deployment-network-file.mjs.map +1 -0
  60. package/dist/orchestrators/codegen/deployment-strict.mjs +77 -0
  61. package/dist/orchestrators/codegen/deployment-strict.mjs.map +1 -0
  62. package/dist/orchestrators/codegen/deployment.d.mts +63 -0
  63. package/dist/orchestrators/codegen/deployment.mjs +153 -0
  64. package/dist/orchestrators/codegen/deployment.mjs.map +1 -0
  65. package/dist/orchestrators/codegen/errors.mjs +7 -9
  66. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  67. package/dist/orchestrators/codegen/format.mjs +20 -1
  68. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  69. package/dist/orchestrators/codegen/paths.mjs +1 -8
  70. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  71. package/dist/orchestrators/codegen/service.mjs +369 -141
  72. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  73. package/dist/orchestrators/layers.mjs +0 -1
  74. package/dist/orchestrators/layers.mjs.map +1 -1
  75. package/dist/orchestrators/network-options.d.mts +37 -35
  76. package/dist/orchestrators/network-options.mjs +13 -10
  77. package/dist/orchestrators/network-options.mjs.map +1 -1
  78. package/dist/plugins/account/codegen.d.mts +3 -4
  79. package/dist/plugins/account/codegen.mjs +5 -7
  80. package/dist/plugins/account/codegen.mjs.map +1 -1
  81. package/dist/plugins/account/index.mjs +1 -3
  82. package/dist/plugins/account/index.mjs.map +1 -1
  83. package/dist/plugins/coin/codegen.mjs +5 -5
  84. package/dist/plugins/coin/codegen.mjs.map +1 -1
  85. package/dist/plugins/coin/index.mjs.map +1 -1
  86. package/dist/plugins/dashboard/domain.mjs +18 -1
  87. package/dist/plugins/dashboard/domain.mjs.map +1 -1
  88. package/dist/plugins/dashboard/schema/root.mjs +5 -3
  89. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  90. package/dist/plugins/dashboard/schema/types.mjs +15 -2
  91. package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
  92. package/dist/plugins/deepbook/codegen.mjs +4 -4
  93. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  94. package/dist/plugins/deepbook/index.d.mts +7 -3
  95. package/dist/plugins/deepbook/index.mjs +3 -3
  96. package/dist/plugins/deepbook/index.mjs.map +1 -1
  97. package/dist/plugins/internal/codegen-helpers.mjs +0 -1
  98. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  99. package/dist/plugins/package/codegen.d.mts +1 -12
  100. package/dist/plugins/package/codegen.mjs +43 -25
  101. package/dist/plugins/package/codegen.mjs.map +1 -1
  102. package/dist/plugins/package/dep-resolution.mjs +1 -1
  103. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  104. package/dist/plugins/package/index.d.mts +14 -11
  105. package/dist/plugins/package/index.mjs +6 -7
  106. package/dist/plugins/package/index.mjs.map +1 -1
  107. package/dist/plugins/seal/codegen.mjs +3 -3
  108. package/dist/plugins/seal/codegen.mjs.map +1 -1
  109. package/dist/plugins/seal/index.mjs.map +1 -1
  110. package/dist/plugins/sui/codegen.mjs +5 -4
  111. package/dist/plugins/sui/codegen.mjs.map +1 -1
  112. package/dist/plugins/sui/index.d.mts +10 -10
  113. package/dist/plugins/sui/index.mjs +1 -2
  114. package/dist/plugins/sui/index.mjs.map +1 -1
  115. package/dist/plugins/sui/move-summary-runner.mjs +29 -2
  116. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
  117. package/dist/plugins/wallet/codegen.d.mts +8 -12
  118. package/dist/plugins/wallet/codegen.mjs +22 -15
  119. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  120. package/dist/plugins/wallet/index.d.mts +4 -3
  121. package/dist/plugins/wallet/index.mjs +1 -1
  122. package/dist/plugins/wallet/index.mjs.map +1 -1
  123. package/dist/plugins/wallet/service.d.mts +2 -2
  124. package/dist/plugins/wallet/service.mjs +2 -3
  125. package/dist/plugins/wallet/service.mjs.map +1 -1
  126. package/dist/plugins/walrus/codegen.mjs +4 -4
  127. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  128. package/dist/plugins/walrus/index.mjs +1 -1
  129. package/dist/plugins/walrus/index.mjs.map +1 -1
  130. package/dist/substrate/manifest.d.mts +17 -22
  131. package/dist/substrate/manifest.mjs +4 -6
  132. package/dist/substrate/manifest.mjs.map +1 -1
  133. package/dist/substrate/plugin-ctx.d.mts +6 -6
  134. package/dist/substrate/plugin-ctx.mjs.map +1 -1
  135. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  136. package/dist/substrate/runtime/index.mjs +1 -0
  137. package/dist/substrate/runtime/lifecycle/file-watcher.d.mts +1 -0
  138. package/dist/substrate/runtime/lifecycle/file-watcher.mjs +54 -0
  139. package/dist/substrate/runtime/lifecycle/file-watcher.mjs.map +1 -0
  140. package/dist/substrate/runtime/lifecycle/index.mjs +1 -0
  141. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +76 -6
  142. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
  143. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  144. package/dist/substrate/runtime/paths.mjs +1 -1
  145. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +2 -6
  146. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
  147. package/dist/surfaces/cli/command-tree.mjs +6 -6
  148. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  149. package/dist/surfaces/cli/index.mjs +6 -4
  150. package/dist/surfaces/cli/index.mjs.map +1 -1
  151. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  152. package/package.json +1 -1
  153. package/dist/cli/wirings/dump-ids.mjs +0 -86
  154. package/dist/cli/wirings/dump-ids.mjs.map +0 -1
  155. package/dist/orchestrators/codegen/id-config.d.mts +0 -1
  156. package/dist/orchestrators/codegen/id-config.mjs +0 -107
  157. package/dist/orchestrators/codegen/id-config.mjs.map +0 -1
  158. package/dist/orchestrators/codegen/output-location.mjs +0 -32
  159. package/dist/orchestrators/codegen/output-location.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"service.mjs","names":[],"sources":["../../../src/orchestrators/codegen/service.ts"],"sourcesContent":["// Codegen orchestrator — main service.\n//\n// Architecture §6 (Codegenable):\n// \"Codegen is a surface (L4) that walks the plugin-emitted\n// `Codegenable` capability decls.\"\n//\n// Hard boundary (distilled-doc §\"Hard boundary\"):\n// \"Apps consume codegen output, NOT devstack.\" Every runtime value\n// the app needs flows through codegen-emitted TS files. The\n// orchestrator owns the only legitimate channel from stack state\n// to app code.\n//\n// Lifecycle (distilled-doc §\"Lifecycle states\"):\n// - at-up: per supervisor cycle, run all emitters serially,\n// with per-file atomic/idempotent writes inside a\n// cycle-level stage-and-swap (rollback on any\n// per-file failure leaves the user-visible tree\n// unchanged).\n// - on-change: re-run as part of the new cycle when the\n// supervisor restarts.\n// - on-demand: same emit pipeline for snapshot resume.\n// - idempotency: per-file no-touch on unchanged content.\n//\n// Pipeline (one cycle):\n// 1. Collect `Codegenable` contributions from the active stack\n// members (the supervisor walks `member.capabilities`).\n// 2. Validate uniqueness: emitter name (literal) is globally\n// unique; output path is globally unique.\n// 3. Run each emitter serially (distilled-doc § \"Serial within a\n// cycle\"). Each emit writes exports through a per-file context.\n// 4. Render each collected file emission to a TS source string.\n// 5. Emit each file with an atomic write + per-file no-touch\n// idempotency.\n// 6. Run the Move-bindings emitter against the collected\n// `package`-emitted contributions.\n// 7. Write the `.gitignore`.\n//\n// What this module does NOT do:\n// - Construct plugin-level resolved blobs (plugins pass them at\n// factory-build time).\n// - Decode the manifest envelope (plugins pass resolved blobs at\n// factory-build time; the orchestrator never re-reads the envelope).\n// - Watch files. Re-emit is driven by the supervisor cycle (and\n// on-demand by the CLI); the app's own toolchain (Vite/HMR)\n// watches the emitted output tree.\n// - Walk the user's Move-source mtimes (see `bindings.ts`).\n\nimport { Context, Effect, FileSystem, Layer, Order, Ref, Scope } from 'effect';\nimport { dirname } from 'node:path';\n\nimport {\n\tisRawExpr,\n\ttype CodegenableDecl,\n\ttype CodegenEmitDone,\n\ttype CodegenEmitContext,\n\ttype OutputLocation,\n} from '../../contracts/codegenable.ts';\nimport { CONFIG_RUNTIME_OUTPUT_PATH, CONFIG_RUNTIME_SOURCE } from './config-runtime.ts';\nimport { acquireStackLock } from '../../substrate/runtime/cross-process/stack-lock.ts';\nimport { mintRandomSuffix } from '../../substrate/runtime/random-suffix.ts';\nimport { stageAndSwap, StageAndSwapError } from '../../substrate/runtime/stage-and-swap/index.ts';\n\nimport {\n\temitBindings,\n\ttype EmitBindingsResult,\n\tisPackageBindings,\n\tMoveCodegenService,\n\tMoveSummaryRunnerService,\n\ttype PackageBindings,\n} from './bindings.ts';\nimport { emitOne } from './emit.ts';\nimport {\n\tCodegenAggregateConflict,\n\tCodegenEmitFailed,\n\tCodegenEmitterCollision,\n\tCodegenPathConflict,\n\tCodegenWriteFailed,\n\ttype CodegenError,\n} from './errors.ts';\nimport { renderFile } from './format.ts';\nimport { writeGitignore } from './gitignore.ts';\nimport { UNRESOLVED_ID } from './id-config.ts';\nimport type { IdConfig, IdConfigNetwork, IdConfigPackage, IdConfigValues } from './id-config.ts';\nimport { CodegenPathsService, type CodegenPaths } from './paths.ts';\nimport { dirModeFor, modeFor, NON_SENSITIVE_DIR_MODE } from './permissions.ts';\n\n// -----------------------------------------------------------------------------\n// Public types\n// -----------------------------------------------------------------------------\n\n/** A type alias the orchestrator uses internally to avoid restating\n * the wide-erased `CodegenableDecl` generic in every signature. */\nexport type Codegenable = CodegenableDecl<string>;\n\nexport interface RunEmitCycleInput {\n\t/** All Codegenable contributions, as collected from the active\n\t * stack members' `capabilities` tuples. The orchestrator does\n\t * not look at plugins — only at the decl set. */\n\treadonly contributions: ReadonlyArray<Codegenable>;\n\t/** Optional: import-extension for bindings emission. Default `.ts`. */\n\treadonly bindingsImportExtension?: '.ts' | '.js' | '';\n\t/** When `true`, this is the COMMITTED projection tree (`src/generated`,\n\t * written by the stack-free `codegen` verb): the `.gitignore` TRACKS\n\t * the stubs (bindings, config, config-runtime) so `tsc`/`vite build`\n\t * work on a fresh clone, ignoring only `sensitivePaths`. When\n\t * `false`/omitted, the ephemeral tree is blanket-ignored. */\n\treadonly trackTree?: boolean;\n}\n\nexport interface RunEmitCycleResult {\n\treadonly filesWritten: ReadonlyArray<string>;\n\treadonly filesUnchanged: ReadonlyArray<string>;\n\treadonly filesChmod: ReadonlyArray<string>;\n\treadonly bindings: EmitBindingsResult | null;\n}\n\n/** Resolve a decl/aggregate's absolute output path against the tree\n * selected by its `outputLocation`. `'generated-extras'` routes\n * through `paths.resolveExtras` (the gitignored dev tree); everything\n * else through `paths.resolve` (the staging-and-swapped runtime tree). */\nconst resolveAt = (\n\tpaths: CodegenPaths,\n\tlocation: OutputLocation,\n\toutputPath: string,\n): Effect.Effect<string, CodegenPathConflict> =>\n\tlocation === 'generated-extras' ? paths.resolveExtras(outputPath) : paths.resolve(outputPath);\n\nconst declLocation = (decl: Pick<Codegenable, 'outputLocation'>): OutputLocation =>\n\tdecl.outputLocation ?? 'generated';\n\n/** A decl belongs to the `emitExtras` flush IFF it writes ONLY into the\n * dev-only `generated-extras` tree. INVARIANT: `emitExtras` must NEVER\n * touch the committed `src/generated` tree (it runs without stage-and-swap),\n * so a decl that would emit any file into `generated` is excluded.\n *\n * - `aggregateOnly` decls write only their aggregate file: include iff the\n * aggregate's location is `generated-extras` (e.g. each account folding\n * into the gitignored `accounts.ts`).\n * - standalone decls write a per-decl file (and possibly an aggregate):\n * include iff that standalone file lands in `generated-extras` (e.g. the\n * wallet's `dev-wallet.ts`). A standalone-in-`generated` decl is excluded\n * even if its aggregate targets `generated-extras`. */\nconst isExtrasDecl = (decl: Codegenable): boolean =>\n\tdecl.aggregateOnly === true\n\t\t? (decl.aggregate?.outputLocation ?? 'generated') === 'generated-extras'\n\t\t: declLocation(decl) === 'generated-extras';\n\nconst buildParentModeResolver = (\n\tpaths: CodegenPaths,\n\tentries: ReadonlyArray<{\n\t\treadonly outputPath: string;\n\t\treadonly location: OutputLocation;\n\t\treadonly sensitive: boolean;\n\t}>,\n): Effect.Effect<(absolutePath: string) => number, CodegenPathConflict> =>\n\tEffect.gen(function* () {\n\t\tconst byParent = new Map<string, Array<{ readonly sensitive?: boolean }>>();\n\t\tfor (const entry of entries) {\n\t\t\tconst parent = dirname(yield* resolveAt(paths, entry.location, entry.outputPath));\n\t\t\tconst current = byParent.get(parent);\n\t\t\tif (current === undefined) {\n\t\t\t\tbyParent.set(parent, [{ sensitive: entry.sensitive }]);\n\t\t\t} else {\n\t\t\t\tcurrent.push({ sensitive: entry.sensitive });\n\t\t\t}\n\t\t}\n\t\tconst modes = new Map<string, number>();\n\t\tfor (const [parent, parentDecls] of byParent) {\n\t\t\tmodes.set(parent, dirModeFor(parentDecls));\n\t\t}\n\t\treturn (absolutePath: string) => modes.get(dirname(absolutePath)) ?? NON_SENSITIVE_DIR_MODE;\n\t});\n\n// -----------------------------------------------------------------------------\n// Main entry — one cycle of the codegen pipeline\n// -----------------------------------------------------------------------------\n\n/**\n * Per-cycle lock acquire timeout. Codegen cycles can be file-system\n * heavy (multi-emitter, Move-bindings compilation), so we allow more\n * than the substrate's default 5s for `stack.lock` — a custom CLI\n * caller that hits a supervisor mid-cycle should wait, not error.\n * Mirrors `MOVE_BUILD_LOCK_TIMEOUT_MS` (5 minutes).\n */\nconst CODEGEN_CYCLE_LOCK_TIMEOUT_MS = 5 * 60_000;\n\nexport const runEmitCycle = (\n\tinput: RunEmitCycleInput,\n): Effect.Effect<\n\tRunEmitCycleResult,\n\tCodegenError,\n\tFileSystem.FileSystem | CodegenPathsService | MoveSummaryRunnerService | MoveCodegenService\n> =>\n\t// Per-process lock. The supervisor's serialized post-acquire path\n\t// is fine for the normal lifecycle, but custom callers (CLI direct\n\t// invocations, future watcher hooks) can call `runEmitCycle`\n\t// concurrently. With `stageAndSwap` writing under shared\n\t// `<outputDir>.staging.<cycleId>` and `<outputDir>.bak.<cycleId>`\n\t// siblings — and with the pre-seed `fs.copy` reading from the\n\t// shared `outputDir` — two overlapping cycles can stage from a\n\t// half-published tree of the other. The lock serializes them.\n\t//\n\t// Dedicated `codegenLockFile` (NOT the substrate `stack.lock`):\n\t// codegen cycles can run for many seconds when Move bindings\n\t// compile, and the substrate's `stack.lock` is reserved for short\n\t// critical sections (roster mutations, the snapshot bounce). A\n\t// dedicated lock isolates codegen contention from those subsystems.\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tconst paths = yield* CodegenPathsService;\n\t\t\tyield* acquireStackLock(paths.codegenLockFile, CODEGEN_CYCLE_LOCK_TIMEOUT_MS).pipe(\n\t\t\t\tEffect.mapError(\n\t\t\t\t\t(cause) =>\n\t\t\t\t\t\tnew CodegenWriteFailed({\n\t\t\t\t\t\t\toutputPath: paths.codegenLockFile,\n\t\t\t\t\t\t\tstage: 'write',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn yield* runEmitCycleLocked(input);\n\t\t}),\n\t);\n\nconst runEmitCycleLocked = (\n\tinput: RunEmitCycleInput,\n): Effect.Effect<\n\tRunEmitCycleResult,\n\tCodegenError,\n\tFileSystem.FileSystem | CodegenPathsService | MoveSummaryRunnerService | MoveCodegenService\n> =>\n\tEffect.gen(function* () {\n\t\tconst paths = yield* CodegenPathsService;\n\t\t// Yield the Move-codegen services here (outside the\n\t\t// stage-and-swap build) so the build's R-channel collapses to\n\t\t// just `FileSystem.FileSystem` — the substrate `stageAndSwap`\n\t\t// primitive constrains `build`'s requirements to\n\t\t// `FileSystem.FileSystem`.\n\t\tconst moveRunner = yield* MoveSummaryRunnerService;\n\t\tconst moveCodegen = yield* MoveCodegenService;\n\n\t\t// Pre-flight contribution-set validation. Detected BEFORE the\n\t\t// stage-and-swap so a programming-bug rejection (duplicate\n\t\t// emitterName / outputPath collision) never opens an empty\n\t\t// staging dir on disk. `package` is the one exception:\n\t\t// multiple instances (one per Package) legitimately share the\n\t\t// `emitterName` literal by design.\n\t\tyield* validateUniqueness(input.contributions);\n\t\tyield* validateAggregatePathAvailability(input.contributions);\n\n\t\t// Cycle-level atomicity: substrate stage-and-swap. The build\n\t\t// populates `<outputDir>.staging.<cycleId>/`; on success the\n\t\t// substrate renames it into place; on any failure the previous\n\t\t// tree (if any) is restored byte-for-byte. Without this wrapper\n\t\t// a mid-cycle emit failure would leave `src/generated/`\n\t\t// half-rewritten — see STYLE_GUIDE §19.\n\t\t//\n\t\t// `preserveOnPreseed: true` — substrate clones the current\n\t\t// target into staging before `build` runs so the per-file\n\t\t// no-touch idempotency (and gitignore user-block preservation)\n\t\t// sees the right baseline. Files this cycle rewrites are\n\t\t// overwritten in staging; files this cycle does NOT touch\n\t\t// survive into the next target verbatim with their original\n\t\t// mtimes (HMR watchers stay quiet for unchanged outputs).\n\t\t//\n\t\t// Cycle id is a random suffix. STYLE_GUIDE §17 mandates 8\n\t\t// hex chars for external-facing identifiers; this is a\n\t\t// deliberate 16-char carve-out because the value only\n\t\t// appears in transient staging-directory names\n\t\t// (`.staging.<id>` / `.bak.<id>`) that the substrate rm's\n\t\t// after publish. The extra entropy is defense-in-depth for\n\t\t// the race-window where two concurrent emit cycles under a\n\t\t// custom-CLI caller could mint overlapping staging dirs\n\t\t// against the same shared `outputDir`; a collision there\n\t\t// would corrupt a half-built tree, not just clash an\n\t\t// operator-visible name.\n\t\tconst cycleId = mintRandomSuffix(16);\n\t\tconst stagingPaths = paths.withRoot(`${paths.outputDir}.staging.${cycleId}`);\n\n\t\treturn yield* stageAndSwap({\n\t\t\ttargetPath: paths.outputDir,\n\t\t\tidSuffix: cycleId,\n\t\t\tpreserveOnPreseed: true,\n\t\t\tbuild: Effect.gen(function* () {\n\t\t\t\tconst inner = yield* runEmitCycleInner(input, stagingPaths).pipe(\n\t\t\t\t\tEffect.provideService(MoveSummaryRunnerService, moveRunner),\n\t\t\t\t\tEffect.provideService(MoveCodegenService, moveCodegen),\n\t\t\t\t);\n\t\t\t\t// Rewrite paths so callers see the final user-visible\n\t\t\t\t// `outputDir` location, not the staging directory that\n\t\t\t\t// only exists for the duration of the build.\n\t\t\t\treturn rewriteResultPaths(inner, stagingPaths.outputDir, paths.outputDir);\n\t\t\t}),\n\t\t}).pipe(\n\t\t\tEffect.mapError((e): CodegenError => {\n\t\t\t\tif (e instanceof StageAndSwapError) {\n\t\t\t\t\treturn new CodegenWriteFailed({\n\t\t\t\t\t\toutputPath: paths.outputDir,\n\t\t\t\t\t\tstage: 'rename',\n\t\t\t\t\t\tcause: e,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn e;\n\t\t\t}),\n\t\t);\n\t});\n\n/**\n * Project a staging-rooted `RunEmitCycleResult` back into the user-\n * visible `outputDir` namespace. The build effect writes through\n * `stagingDir` paths; callers (and tests) expect to see the final\n * post-rename locations.\n */\nconst rewriteResultPaths = (\n\tresult: RunEmitCycleResult,\n\tstagingDir: string,\n\toutputDir: string,\n): RunEmitCycleResult => {\n\tconst stripped = stagingDir.replace(/\\/+$/, '');\n\tconst target = outputDir.replace(/\\/+$/, '');\n\tconst rewrite = (p: string): string =>\n\t\tp.startsWith(stripped) ? `${target}${p.slice(stripped.length)}` : p;\n\treturn {\n\t\tfilesWritten: result.filesWritten.map(rewrite),\n\t\tfilesUnchanged: result.filesUnchanged.map(rewrite),\n\t\tfilesChmod: result.filesChmod.map(rewrite),\n\t\tbindings:\n\t\t\tresult.bindings === null\n\t\t\t\t? null\n\t\t\t\t: {\n\t\t\t\t\t\t...result.bindings,\n\t\t\t\t\t\tfilesWritten: result.bindings.filesWritten.map(rewrite),\n\t\t\t\t\t},\n\t};\n};\n\n/**\n * The body of one emit cycle. Pulled out of `runEmitCycle` so the\n * stage-and-swap wrapper can drive it against a redirected\n * `CodegenPathsService` (the staging tree). Validation runs BEFORE\n * this function so callers know the contribution set is well-formed.\n */\nconst runEmitCycleInner = (\n\tinput: RunEmitCycleInput,\n\tpaths: CodegenPaths,\n): Effect.Effect<\n\tRunEmitCycleResult,\n\tCodegenError,\n\tFileSystem.FileSystem | MoveSummaryRunnerService | MoveCodegenService\n> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.logInfo(`codegen: emitting projection (trackTree=${input.trackTree === true}).`);\n\t\tconst fileEmitters: Array<Codegenable> = [...input.contributions];\n\n\t\tconst filesWritten: Array<string> = [];\n\t\tconst filesUnchanged: Array<string> = [];\n\t\tconst filesChmod: Array<string> = [];\n\t\t// Aggregate buckets keyed by plugin-supplied bucket name. The\n\t\t// orchestrator treats bucket names as opaque tags chosen by\n\t\t// the contributor; it never branches on plugin identity. See\n\t\t// `CodegenableDecl.aggregate` (contracts/codegenable.ts).\n\t\tconst aggregates = new Map<string, Record<string, unknown>>();\n\t\t// Per-bucket location + sensitivity, read from the first decl\n\t\t// the orchestrator sees contributing to the bucket. Drives where\n\t\t// the synthesized aggregate file lands and its file mode. Every\n\t\t// later contributor to the same bucket MUST agree (enforced\n\t\t// below) — a silent disagreement could misroute a sensitive\n\t\t// aggregate into the committed `generated` tree.\n\t\tconst aggregateMeta = new Map<string, AggregateMeta>();\n\t\tconst packageContribs: Array<PackageBindings> = [];\n\t\tconst sortedDecls = [...fileEmitters].sort(\n\t\t\tOrder.mapInput(Order.String, (d: Codegenable) => d.outputPath),\n\t\t);\n\t\t// Parent-mode resolver must see every path that will be written —\n\t\t// standalone decls AND synthesized aggregates — across BOTH trees.\n\t\t// Aggregate-only decls do not write a standalone file, so they are\n\t\t// excluded from the standalone-path set here.\n\t\tconst parentModeFor = yield* buildParentModeResolver(\n\t\t\tpaths,\n\t\t\tfileEmitters\n\t\t\t\t.filter((d) => d.aggregateOnly !== true)\n\t\t\t\t.map((d) => ({\n\t\t\t\t\toutputPath: d.outputPath,\n\t\t\t\t\tlocation: declLocation(d),\n\t\t\t\t\tsensitive: d.sensitive === true,\n\t\t\t\t})),\n\t\t);\n\t\tfor (const decl of sortedDecls) {\n\t\t\tconst emission = yield* runEmitter(decl);\n\t\t\tconst exported = emission.exports;\n\t\t\tif (decl.aggregate !== undefined) {\n\t\t\t\tconst projected = decl.aggregate.project(exported);\n\t\t\t\tif (projected !== null) {\n\t\t\t\t\tconst bucket = aggregates.get(decl.aggregate.bucket) ?? {};\n\t\t\t\t\tdeepMerge(bucket, projected);\n\t\t\t\t\taggregates.set(decl.aggregate.bucket, bucket);\n\t\t\t\t\t// First-contributor-wins for routing/sensitivity, but a\n\t\t\t\t\t// LATER contributor that disagrees is a hard error — the\n\t\t\t\t\t// `AggregateContribution` contract requires all\n\t\t\t\t\t// contributors to a bucket to agree, and a silent\n\t\t\t\t\t// mismatch could misroute a sensitive aggregate into the\n\t\t\t\t\t// committed `generated` tree (secret leak).\n\t\t\t\t\tconst declLoc = decl.aggregate.outputLocation ?? 'generated';\n\t\t\t\t\tconst declSensitive = decl.aggregate.sensitive === true;\n\t\t\t\t\tconst established = aggregateMeta.get(decl.aggregate.bucket);\n\t\t\t\t\tif (established === undefined) {\n\t\t\t\t\t\taggregateMeta.set(decl.aggregate.bucket, {\n\t\t\t\t\t\t\tlocation: declLoc,\n\t\t\t\t\t\t\tsensitive: declSensitive,\n\t\t\t\t\t\t\testablishedBy: decl.emitterName,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (established.location !== declLoc) {\n\t\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\t\tnew CodegenAggregateConflict({\n\t\t\t\t\t\t\t\t\tbucket: decl.aggregate.bucket,\n\t\t\t\t\t\t\t\t\tfield: 'outputLocation',\n\t\t\t\t\t\t\t\t\testablished: established.location,\n\t\t\t\t\t\t\t\t\tconflicting: declLoc,\n\t\t\t\t\t\t\t\t\temitters: [established.establishedBy, decl.emitterName],\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (established.sensitive !== declSensitive) {\n\t\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\t\tnew CodegenAggregateConflict({\n\t\t\t\t\t\t\t\t\tbucket: decl.aggregate.bucket,\n\t\t\t\t\t\t\t\t\tfield: 'sensitive',\n\t\t\t\t\t\t\t\t\testablished: String(established.sensitive),\n\t\t\t\t\t\t\t\t\tconflicting: String(declSensitive),\n\t\t\t\t\t\t\t\t\temitters: [established.establishedBy, decl.emitterName],\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Move-bindings collection: any export whose shape matches\n\t\t\t// the orchestrator's `PackageBindings` consumer contract is\n\t\t\t// forwarded to `emitBindings`. Runs against the raw `exported`\n\t\t\t// map (not via `aggregate.project`) so direct `codegenable(...)`\n\t\t\t// contributions — which carry no `aggregate` — are picked up\n\t\t\t// too. The orchestrator validates the shape it consumes; it\n\t\t\t// does NOT name the plugin that produced it.\n\t\t\tfor (const value of Object.values(exported)) {\n\t\t\t\tif (isPackageBindings(value)) {\n\t\t\t\t\tpackageContribs.push(value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Aggregate-only decls contribute solely to their bucket; the\n\t\t\t// standalone per-decl file is skipped (the combined aggregate\n\t\t\t// is the only app-facing surface).\n\t\t\tif (decl.aggregateOnly === true) continue;\n\t\t\tconst rendered = renderFile({\n\t\t\t\temitterName: decl.emitterName,\n\t\t\t\toutputPath: decl.outputPath,\n\t\t\t\tsensitive: decl.sensitive === true,\n\t\t\t\texports: exported,\n\t\t\t\timports: emission.imports,\n\t\t\t});\n\t\t\tif (!rendered.ok) {\n\t\t\t\treturn yield* Effect.fail(rendered.error);\n\t\t\t}\n\t\t\tconst abs = yield* resolveAt(paths, declLocation(decl), decl.outputPath);\n\t\t\tconst outcome = yield* emitOne({\n\t\t\t\tpath: abs,\n\t\t\t\tcontent: rendered.text,\n\t\t\t\tmode: modeFor(decl),\n\t\t\t\tparentMode: parentModeFor(abs),\n\t\t\t});\n\t\t\tswitch (outcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst aggregateFiles = buildAggregateFiles(aggregates, aggregateMeta);\n\t\t// True once any aggregate references a `config-runtime.ts` resolver\n\t\t// (the committed `config.ts`): then we ALSO emit the fixed\n\t\t// `config-runtime.ts` resolver and import the referenced resolvers into\n\t\t// that file.\n\t\tlet needsConfigRuntime = false;\n\t\tfor (const aggregate of aggregateFiles) {\n\t\t\tconst resolvers = resolversUsedBy(aggregate.exports);\n\t\t\tif (resolvers.length > 0) needsConfigRuntime = true;\n\t\t\tconst rendered = renderFile({\n\t\t\t\temitterName: aggregate.emitterName,\n\t\t\t\toutputPath: aggregate.outputPath,\n\t\t\t\tsensitive: aggregate.sensitive,\n\t\t\t\texports: aggregate.exports,\n\t\t\t\t// The committed `config.ts` resolves ids/network at runtime —\n\t\t\t\t// import exactly the resolvers it references (no unused imports;\n\t\t\t\t// oxlint is pinned and flags them). `.js` specifier (ESM/TS-\n\t\t\t\t// resolved) mirrors the bindings' import style.\n\t\t\t\t...(resolvers.length > 0\n\t\t\t\t\t? { imports: [`import { ${resolvers.join(', ')} } from './config-runtime.js';`] }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t\tif (!rendered.ok) {\n\t\t\t\treturn yield* Effect.fail(rendered.error);\n\t\t\t}\n\t\t\tconst abs = yield* resolveAt(paths, aggregate.location, aggregate.outputPath);\n\t\t\tconst outcome = yield* emitOne({\n\t\t\t\tpath: abs,\n\t\t\t\tcontent: rendered.text,\n\t\t\t\tmode: aggregate.sensitive ? 0o600 : 0o644,\n\t\t\t\tparentMode: parentModeFor(abs),\n\t\t\t});\n\t\t\tswitch (outcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Emit the FIXED `config-runtime.ts` resolver (a constant string, NOT\n\t\t// routed through the literal renderer) when `config.ts` resolves ids\n\t\t// at runtime. It reads the injected `__DEVSTACK_IDS__` global and\n\t\t// THROWS `DevstackConfigMissingError` on an unresolved id.\n\t\tif (needsConfigRuntime) {\n\t\t\tconst abs = yield* paths.resolve(CONFIG_RUNTIME_OUTPUT_PATH);\n\t\t\tconst outcome = yield* emitOne({\n\t\t\t\tpath: abs,\n\t\t\t\tcontent: CONFIG_RUNTIME_SOURCE,\n\t\t\t\tmode: 0o644,\n\t\t\t\tparentMode: parentModeFor(abs),\n\t\t\t});\n\t\t\tswitch (outcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tlet bindings: EmitBindingsResult | null = null;\n\t\tif (packageContribs.length > 0) {\n\t\t\tbindings = yield* emitBindings({\n\t\t\t\tbindingsDir: paths.bindingsDir,\n\t\t\t\tpackages: packageContribs,\n\t\t\t\timportExtension: input.bindingsImportExtension,\n\t\t\t});\n\t\t} else {\n\t\t\tyield* Effect.logInfo(\n\t\t\t\t'codegen: no package contributions; skipping Move-to-TS bindings step.',\n\t\t\t);\n\t\t}\n\n\t\t// `.gitignore` covers the runtime `generated/` tree only. Decls\n\t\t// routed to `generated-extras` live outside `outputDir` (that\n\t\t// whole tree is gitignored at the `.devstack/` level), and\n\t\t// aggregate-only decls never write a standalone file — both are\n\t\t// excluded here so the managed `.gitignore` only lists real\n\t\t// sensitive files in `outputDir`.\n\t\t//\n\t\t// Synthesized aggregate files are a SEPARATE source of sensitive\n\t\t// runtime paths: a sensitive bucket routed to `generated` writes a\n\t\t// real secret-bearing file in `outputDir` that the standalone-decl\n\t\t// scan above never sees (its contributors may all be\n\t\t// `aggregateOnly`). Without an explicit ignore line such a file\n\t\t// would rely solely on the blanket `*` rule — and a user `!<file>`\n\t\t// override in the preserved user block would then start tracking\n\t\t// the secret. Include them so each gets an explicit re-ignore line.\n\t\tconst sensitivePaths = [\n\t\t\t...fileEmitters\n\t\t\t\t.filter(\n\t\t\t\t\t(d) =>\n\t\t\t\t\t\td.sensitive === true && d.aggregateOnly !== true && declLocation(d) === 'generated',\n\t\t\t\t)\n\t\t\t\t.map((d) => d.outputPath),\n\t\t\t...aggregateFiles\n\t\t\t\t.filter((a) => a.sensitive && a.location === 'generated')\n\t\t\t\t.map((a) => a.outputPath),\n\t\t];\n\t\t// A committed projection (written by the stack-free `codegen` verb\n\t\t// into `src/generated`) is TRACKED: the stubs are committed so\n\t\t// `tsc`/`vite build` work on a fresh clone. Any ephemeral tree keeps\n\t\t// the blanket ignore.\n\t\tyield* writeGitignore({\n\t\t\tpath: paths.gitignoreFile,\n\t\t\tsensitivePaths,\n\t\t\tparentMode: parentModeFor(paths.gitignoreFile),\n\t\t\ttrackTree: input.trackTree === true,\n\t\t});\n\n\t\treturn {\n\t\t\tfilesWritten,\n\t\t\tfilesUnchanged,\n\t\t\tfilesChmod,\n\t\t\tbindings,\n\t\t};\n\t});\n\n// -----------------------------------------------------------------------------\n// Internals\n// -----------------------------------------------------------------------------\n\ninterface CodegenEmission {\n\treadonly exports: { readonly [key: string]: unknown };\n\treadonly imports: ReadonlyArray<string>;\n}\n\nconst runEmitter = (decl: Codegenable): Effect.Effect<CodegenEmission, CodegenEmitFailed> =>\n\tEffect.gen(function* () {\n\t\t// Annotate the emit span with the contributor's plugin-supplied\n\t\t// `kind` tag (declared on the decl's `aggregate`). The orchestrator\n\t\t// stays name-blind — it never reads the tag's VALUE or branches on it\n\t\t// (per the `AggregateContribution` contract); wiring it here makes the\n\t\t// otherwise-dead field observable so a trace attributes each emit to\n\t\t// the plugin family that produced it. `annotateCurrentSpan` only lands\n\t\t// inside an enclosing `withSpan` — the `codegen.emit` span this body is\n\t\t// wrapped in below.\n\t\tconst kind = decl.aggregate?.kind;\n\t\tif (kind !== undefined) {\n\t\t\tyield* Effect.annotateCurrentSpan('codegen.kind', kind);\n\t\t}\n\t\tconst exports: Record<string, unknown> = {};\n\t\tconst imports: Array<string> = [];\n\t\tconst done: CodegenEmitDone = { _tag: 'CodegenEmitDone' };\n\t\tconst ctx: CodegenEmitContext = {\n\t\t\texportConst: (name, value) => {\n\t\t\t\texports[name] = value;\n\t\t\t},\n\t\t\timportStatement: (statement) => {\n\t\t\t\timports.push(statement);\n\t\t\t},\n\t\t\tdone: () => done,\n\t\t};\n\t\tyield* decl.emit(ctx).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew CodegenEmitFailed({\n\t\t\t\t\t\temitterName: decl.emitterName,\n\t\t\t\t\t\toutputPath: decl.outputPath,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\treturn { exports, imports };\n\t}).pipe(Effect.withSpan('codegen.emit', { attributes: { 'codegen.emitter': decl.emitterName } }));\n\n/**\n * Uniqueness check: emitter name (literal) must be unique unless\n * the decl opts into repetition via `allowEmitterNameRepetition`\n * (used by per-item plugins like Package, which emit one decl per\n * published package under a shared emitter name). Output paths\n * must be unique across ALL emitters.\n */\nconst validateUniqueness = (\n\tdecls: ReadonlyArray<Codegenable>,\n): Effect.Effect<void, CodegenPathConflict | CodegenEmitterCollision> =>\n\tEffect.gen(function* () {\n\t\tconst byPath = new Map<string, Array<string>>();\n\t\tconst byName = new Map<string, Array<string>>();\n\t\tfor (const d of decls) {\n\t\t\t// Aggregate-only decls write no standalone file, so their\n\t\t\t// `outputPath` is a dead value — exclude them from the\n\t\t\t// path-uniqueness check (many `package` decls legitimately\n\t\t\t// share `config.ts`'s bucket but carry distinct dead\n\t\t\t// `package/<name>.ts` outputPaths that never hit disk).\n\t\t\tif (d.aggregateOnly !== true) {\n\t\t\t\t// Key by (location, path): the same relative path in the\n\t\t\t\t// `generated` vs `generated-extras` trees is two distinct\n\t\t\t\t// files, so `accounts.ts` may exist in both without a\n\t\t\t\t// false collision.\n\t\t\t\tconst pathKey = `${declLocation(d)} ${d.outputPath}`;\n\t\t\t\tconst ps = byPath.get(pathKey) ?? [];\n\t\t\t\tps.push(d.emitterName);\n\t\t\t\tbyPath.set(pathKey, ps);\n\t\t\t}\n\t\t\tif (d.allowEmitterNameRepetition === true) continue;\n\t\t\tconst ns = byName.get(d.emitterName) ?? [];\n\t\t\tns.push(d.outputPath);\n\t\t\tbyName.set(d.emitterName, ns);\n\t\t}\n\t\tfor (const [pathKey, emitters] of byPath) {\n\t\t\tif (emitters.length > 1) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CodegenPathConflict({\n\t\t\t\t\t\tkind: 'duplicate',\n\t\t\t\t\t\t// Strip the `<location> ` prefix from the dedup key so\n\t\t\t\t\t\t// the error names the relative path the plugin declared.\n\t\t\t\t\t\toutputPath: pathKey.slice(pathKey.indexOf(' ') + 1),\n\t\t\t\t\t\temitters,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, outputPaths] of byName) {\n\t\t\tif (outputPaths.length > 1) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CodegenEmitterCollision({\n\t\t\t\t\t\temitterName: name,\n\t\t\t\t\t\toutputPaths,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n/**\n * Reject contribution sets that would have an aggregate bucket\n * collide with a per-decl `outputPath`. The orchestrator only knows\n * bucket names because plugins declared them via `aggregate.bucket`;\n * it does not enumerate or recognize plugin identities here.\n */\nconst validateAggregatePathAvailability = (\n\tdecls: ReadonlyArray<Codegenable>,\n): Effect.Effect<void, CodegenPathConflict> =>\n\tEffect.gen(function* () {\n\t\t// Aggregate buckets keyed by (location, bucket). A standalone\n\t\t// decl in the SAME tree that writes the bucket path would clash\n\t\t// with the synthesized aggregate; a decl in the OTHER tree (or\n\t\t// an aggregate-only decl, which writes no standalone file) does\n\t\t// not.\n\t\tconst aggregatePaths = new Map<string, string>();\n\t\tfor (const decl of decls) {\n\t\t\tif (decl.aggregate !== undefined) {\n\t\t\t\tconst location = decl.aggregate.outputLocation ?? 'generated';\n\t\t\t\taggregatePaths.set(`${location} ${decl.aggregate.bucket}`, decl.aggregate.bucket);\n\t\t\t}\n\t\t}\n\t\tfor (const [key, bucket] of aggregatePaths) {\n\t\t\tconst location = key.slice(0, key.indexOf(' '));\n\t\t\tconst colliding = decls.filter(\n\t\t\t\t(decl) =>\n\t\t\t\t\tdecl.aggregateOnly !== true &&\n\t\t\t\t\tdeclLocation(decl) === location &&\n\t\t\t\t\tdecl.outputPath === bucket,\n\t\t\t);\n\t\t\tif (colliding.length > 0) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CodegenPathConflict({\n\t\t\t\t\t\tkind: 'duplicate',\n\t\t\t\t\t\toutputPath: bucket,\n\t\t\t\t\t\temitters: [...colliding.map((decl) => decl.emitterName), `aggregate/${bucket}`],\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n/** Per-bucket location + sensitivity, captured from the first decl\n * the orchestrator sees contributing to a bucket. The orchestrator\n * stays name-blind; the plugin owns these on its\n * `AggregateContribution`. `establishedBy` records the emitter name\n * of that first contributor so a later disagreement can quote both\n * sides in `CodegenAggregateConflict`. */\ninterface AggregateMeta {\n\treadonly location: OutputLocation;\n\treadonly sensitive: boolean;\n\treadonly establishedBy: string;\n}\n\ninterface AggregateFile {\n\treadonly emitterName: string;\n\treadonly outputPath: string;\n\treadonly exports: { readonly [key: string]: unknown };\n\treadonly location: OutputLocation;\n\treadonly sensitive: boolean;\n}\n\n/**\n * Recursively merge `source` into `target`. Distinct buckets are\n * shallow records keyed by name, but a single bucket (e.g. `config.ts`)\n * accumulates contributions from MANY plugins into nested sub-records\n * (`networks.localnet` from sui, `packages.<name>` / `objects.<name>`\n * from each package). A shallow `Object.assign` would have the last\n * package's `{packages:{...}}` clobber the prior ones. Deep-merge so\n * sibling keys at every level coexist.\n *\n * Arrays and non-plain values overwrite (no element-wise merge — a\n * plugin that re-emits a bucket key owns its full value). Only plain\n * objects recurse.\n */\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n\ttypeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst deepMerge = (\n\ttarget: Record<string, unknown>,\n\tsource: Readonly<Record<string, unknown>>,\n): void => {\n\tfor (const [key, value] of Object.entries(source)) {\n\t\tconst existing = target[key];\n\t\tif (isPlainObject(existing) && isPlainObject(value)) {\n\t\t\tdeepMerge(existing, value);\n\t\t} else {\n\t\t\t// `value` may be a decl-owned cached projection object (or array).\n\t\t\t// Storing it by reference would let a sibling decl that later\n\t\t\t// recurses into the same nested key mutate this decl's cache in\n\t\t\t// place, leaking state across emit cycles. Deep-clone any plain\n\t\t\t// object / array so the shared bucket never aliases decl state.\n\t\t\ttarget[key] = isPlainObject(value) || Array.isArray(value) ? structuredClone(value) : value;\n\t\t}\n\t}\n};\n\n/**\n * Synthesize one `AggregateFile` per non-empty bucket. The exports\n * map is keyed by the bucket's stem (e.g. `accounts.ts` → `accounts`)\n * so the rendered file exports `export const <stem> = { ... }`. The\n * orchestrator picks the export key from the bucket filename; the\n * stem itself is not a plugin identifier — it is the filename\n * without the `.ts` extension, derived mechanically. The bucket's\n * `location`/`sensitive` (from the first contributing decl) drive\n * which tree the file lands in and its mode.\n */\nconst buildAggregateFiles = (\n\tbuckets: ReadonlyMap<string, Record<string, unknown>>,\n\tmeta: ReadonlyMap<string, AggregateMeta>,\n): ReadonlyArray<AggregateFile> => {\n\tconst files: Array<AggregateFile> = [];\n\tconst sortedEntries = [...buckets.entries()].sort(([a], [b]) => a.localeCompare(b));\n\tfor (const [bucket, contents] of sortedEntries) {\n\t\tif (Object.keys(contents).length === 0) continue;\n\t\tconst stem = bucketStem(bucket);\n\t\tconst bucketMeta = meta.get(bucket) ?? {\n\t\t\tlocation: 'generated' as const,\n\t\t\tsensitive: false,\n\t\t\testablishedBy: `aggregate/${stem}`,\n\t\t};\n\t\tfiles.push({\n\t\t\temitterName: `aggregate/${stem}`,\n\t\t\toutputPath: bucket,\n\t\t\texports: { [stem]: contents },\n\t\t\tlocation: bucketMeta.location,\n\t\t\tsensitive: bucketMeta.sensitive,\n\t\t});\n\t}\n\treturn files;\n};\n\nconst bucketStem = (bucket: string): string => bucket.replace(/\\.ts$/, '').replace(/^.*\\//, '');\n\n/** The config-runtime resolver names a committed `config.ts` aggregate may\n * reference as raw expressions. Each is imported from `./config-runtime.js`\n * only when the aggregate actually calls it (oxlint flags unused imports). */\nconst CONFIG_RUNTIME_RESOLVERS = [\n\t'resolveId',\n\t'resolveNetwork',\n\t'resolveNetworks',\n\t'resolveValue',\n] as const;\ntype ConfigRuntimeResolver = (typeof CONFIG_RUNTIME_RESOLVERS)[number];\n\n/** Recursively collect which `config-runtime.ts` resolvers an exports map\n * references via raw expressions — i.e. the committed `config.ts` needs each\n * imported + the fixed `config-runtime.ts` emitted alongside it. */\nconst collectResolversInValue = (value: unknown, found: Set<ConfigRuntimeResolver>): void => {\n\tif (isRawExpr(value)) {\n\t\tfor (const name of CONFIG_RUNTIME_RESOLVERS) {\n\t\t\tif (value.expr.includes(`${name}(`)) found.add(name);\n\t\t}\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const v of value) collectResolversInValue(v, found);\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tfor (const v of Object.values(value)) collectResolversInValue(v, found);\n\t}\n};\n\n/** The ordered set of config-runtime resolvers an aggregate's exports use\n * (empty when none — the aggregate needs no resolver import). */\nconst resolversUsedBy = (exports: {\n\treadonly [key: string]: unknown;\n}): ReadonlyArray<ConfigRuntimeResolver> => {\n\tconst found = new Set<ConfigRuntimeResolver>();\n\tfor (const v of Object.values(exports)) collectResolversInValue(v, found);\n\treturn CONFIG_RUNTIME_RESOLVERS.filter((name) => found.has(name));\n};\n\n// -----------------------------------------------------------------------------\n// Service surface — registration API + emit-cycle trigger\n// -----------------------------------------------------------------------------\n\n/**\n * The codegen orchestrator's Context-bound service. The substrate's\n * supervisor calls `registerContribution(pluginKey, decl)` once per\n * `CodegenableDecl` on each plugin's `capabilities` tuple, scope-bound\n * to that plugin's acquire scope.\n *\n * Boot no longer runs codegen — the emit pipeline is the stack-free\n * `devstack codegen` verb (which calls `runEmitCycle` directly off the\n * config-derived `staticCodegen` decls). This service keeps the dispatcher\n * seam closed: every `codegenable` contribution still has a handler, so\n * plugins emit decls uniformly even though boot writes the id-config (not\n * the committed tree).\n */\nexport interface CodegenOrchestrator {\n\t/** Register a `CodegenableDecl` from a plugin. Scope-bound — when\n\t * the caller's scope (the plugin's acquire scope) closes, the\n\t * registration is reaped. */\n\treadonly registerContribution: (\n\t\tpluginKey: string,\n\t\tdecl: Codegenable,\n\t) => Effect.Effect<void, never, Scope.Scope>;\n\n\t/** Assemble the id-config from the currently-registered (live-resolved)\n\t * contributions. Boot calls this in its post-acquire hook to WRITE the\n\t * id-config file (the same `networks` / `packages` / `mvrOverrides`\n\t * data that fed `config.ts`, but as loadable JSON the Vite plugin\n\t * injects). `network` is the active network name (`ctx.identity.network`).\n\t * Pure projection over the registered decls — no I/O, no chain. */\n\treadonly assembleIdConfig: (network: string) => Effect.Effect<IdConfig, CodegenEmitFailed>;\n\n\t/** Flush ONLY the `generated-extras` contributions (the dev wallet's\n\t * `dev-wallet.ts` + the account plugin's `accounts.ts`) to the\n\t * gitignored `.devstack/stacks/<stack>/generated-extras` tree. These\n\t * are acquire-resolved (can't be statically derived by the `codegen`\n\t * verb), so boot writes them — but ONLY when the resolved network's\n\t * `devWallet` flag is on. The committed `src/generated` tree is NEVER\n\t * touched (no `generated`-located decl is emitted). Reuses the emit\n\t * renderer + aggregate logic; skips the stage-and-swap of the runtime\n\t * tree (extras live outside it). No-op (empty result) when nothing is\n\t * routed to `generated-extras`. */\n\treadonly emitExtras: () => Effect.Effect<\n\t\tRunEmitCycleResult,\n\t\tCodegenError,\n\t\tFileSystem.FileSystem | CodegenPathsService | MoveSummaryRunnerService | MoveCodegenService\n\t>;\n}\n\nexport class CodegenOrchestratorService extends Context.Service<\n\tCodegenOrchestratorService,\n\tCodegenOrchestrator\n>()('@devstack/orchestrators/Codegen') {}\n\n/**\n * Slice the deep-merged `config.ts` aggregate bucket into the loadable\n * `IdConfig` interchange shape. The bucket is the live codegen\n * accumulation (sui `networks`, per-package `packages`/`objects`/\n * `mvrOverrides`, account `accounts`); this picks the id-bearing fields\n * the Vite plugin injects. Reads are defensive — any missing slice\n * collapses to an empty record so a partial stack still writes a valid\n * (if sparse) id-config.\n */\nconst idConfigFromBucket = (\n\tbucket: Record<string, unknown>,\n\tnetwork: string,\n\tvalues: IdConfigValues,\n): IdConfig => {\n\tconst asRecord = (v: unknown): Record<string, unknown> => (isPlainObject(v) ? v : {});\n\tconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n\n\tconst networks: Record<string, IdConfigNetwork> = {};\n\tfor (const [name, raw] of Object.entries(asRecord(bucket['networks']))) {\n\t\tconst entry = asRecord(raw);\n\t\tconst rpc = asString(entry['rpc']);\n\t\tif (rpc === undefined) continue;\n\t\tnetworks[name] = {\n\t\t\trpc,\n\t\t\t...(asString(entry['chainId']) !== undefined ? { chainId: asString(entry['chainId']) } : {}),\n\t\t\t...(entry['faucet'] !== undefined ? { faucet: asString(entry['faucet']) ?? null } : {}),\n\t\t\t...(entry['graphql'] !== undefined ? { graphql: asString(entry['graphql']) ?? null } : {}),\n\t\t};\n\t}\n\n\tconst packages: Record<string, IdConfigPackage> = {};\n\tfor (const [name, raw] of Object.entries(asRecord(bucket['packages']))) {\n\t\tconst entry = asRecord(raw);\n\t\t// The active-network id is `packageId` (convenience field the package\n\t\t// projection sets = `byNetwork[activeNetwork]`). An empty/missing\n\t\t// packageId maps to the UNRESOLVED_ID sentinel — an empty string would\n\t\t// slip past `isUnresolvedId` and ship as a real, resolved id.\n\t\tconst rawId = asString(entry['packageId']);\n\t\tconst id = rawId === undefined || rawId === '' ? UNRESOLVED_ID : rawId;\n\t\tconst objectsRaw = asRecord(entry['objects']);\n\t\tconst objects: Record<string, string> = {};\n\t\tfor (const [k, v] of Object.entries(objectsRaw)) {\n\t\t\tconst s = asString(v);\n\t\t\tif (s !== undefined) objects[k] = s;\n\t\t}\n\t\tpackages[name] = {\n\t\t\tid,\n\t\t\t...(Object.keys(objects).length > 0 ? { objects } : {}),\n\t\t};\n\t}\n\n\tconst accounts: Record<string, string> = {};\n\tfor (const [name, v] of Object.entries(asRecord(bucket['accounts']))) {\n\t\t// Account bindings are an object keyed by name; the injectable id is\n\t\t// the `address`. Tolerate a bare string too (a pinned known-config).\n\t\tconst address = asString(v) ?? asString(asRecord(v)['address']);\n\t\tif (address !== undefined) accounts[name] = address;\n\t}\n\n\tconst mvrOverrides: Record<string, string> = {};\n\tfor (const [mvr, v] of Object.entries(asRecord(bucket['mvrOverrides']))) {\n\t\tconst s = asString(v);\n\t\tif (s !== undefined) mvrOverrides[mvr] = s;\n\t}\n\n\t// The active `network` field MUST be a key present in `networks` — the\n\t// committed `config-runtime.ts` `resolveActiveNetwork()` does\n\t// `resolveNetworks()[network]`, and the Vite dev-wallet injection reads\n\t// `networks[network].rpc`. The `network` PARAM is the identity's network\n\t// name (e.g. `\"testnet-fork\"`), but the sui binding keys the `networks`\n\t// map by what it emitted (`\"localnet\"` for every mode). So PREFER the\n\t// network the binding stamped into the bucket (`bucket['network']`, which\n\t// matches the `networks` key); fall back to the param, then — if neither\n\t// is a known key but exactly one network exists — that sole key. This\n\t// keeps `network` in agreement with `networks` so resolution never\n\t// dereferences `undefined`.\n\tconst networkKeys = Object.keys(networks);\n\tconst bucketNetwork = asString(bucket['network']);\n\tconst activeNetwork =\n\t\tbucketNetwork !== undefined && networkKeys.includes(bucketNetwork)\n\t\t\t? bucketNetwork\n\t\t\t: networkKeys.includes(network)\n\t\t\t\t? network\n\t\t\t\t: networkKeys.length === 1\n\t\t\t\t\t? networkKeys[0]!\n\t\t\t\t\t: (bucketNetwork ?? network);\n\n\treturn {\n\t\tnetwork: activeNetwork,\n\t\tnetworks,\n\t\tpackages,\n\t\taccounts,\n\t\tmvrOverrides,\n\t\t...(Object.keys(values).length > 0 ? { values } : {}),\n\t};\n};\n\ninterface RegisteredCodegenEntry {\n\treadonly pluginKey: string;\n\treadonly decl: Codegenable;\n\treadonly seq: number;\n}\n\n/** Layer-wired codegen orchestrator. No upstream requirements at boot\n * time — the per-cycle effect carries the `FileSystem` + Move-codegen\n * service requirements through to the caller. */\nexport const layerCodegenOrchestrator: Layer.Layer<CodegenOrchestratorService> = Layer.effect(\n\tCodegenOrchestratorService,\n\tEffect.gen(function* () {\n\t\tconst contributionsRef = yield* Ref.make<ReadonlyArray<RegisteredCodegenEntry>>([]);\n\t\tconst seqRef = yield* Ref.make(0);\n\n\t\tconst registerContribution: CodegenOrchestrator['registerContribution'] = (pluginKey, decl) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst seq = yield* Ref.updateAndGet(seqRef, (n) => n + 1);\n\t\t\t\tconst entry: RegisteredCodegenEntry = { pluginKey, decl, seq };\n\t\t\t\tyield* Ref.update(contributionsRef, (xs) => [...xs, entry]);\n\t\t\t\tyield* Effect.addFinalizer(() =>\n\t\t\t\t\tRef.update(contributionsRef, (xs) => xs.filter((e) => e.seq !== seq)),\n\t\t\t\t);\n\t\t\t}) as Effect.Effect<void, never, Scope.Scope>;\n\n\t\tconst assembleIdConfig: CodegenOrchestrator['assembleIdConfig'] = (network) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst registered = (yield* Ref.get(contributionsRef)).map((e) => e.decl);\n\t\t\t\t// Deep-merge every contribution's `config.ts` aggregate\n\t\t\t\t// projection into ONE bucket — the SAME accumulation the live\n\t\t\t\t// codegen cycle performed (sui's `networks.<net>` + each\n\t\t\t\t// package's `packages.<name>` / `objects` / `mvrOverrides`,\n\t\t\t\t// the account plugin's `accounts`). The merged bucket carries\n\t\t\t\t// real (live-`acquire`-resolved) ids; we then slice it into the\n\t\t\t\t// loadable `IdConfig` shape.\n\t\t\t\tconst bucket: Record<string, unknown> = {};\n\t\t\t\t// `accounts.ts` is a SEPARATE aggregate bucket (the account\n\t\t\t\t// plugin routes it to `generated-extras`); fold its projection\n\t\t\t\t// under an `accounts` key so the id-config carries account\n\t\t\t\t// addresses alongside the `config.ts`-derived ids.\n\t\t\t\tconst accounts: Record<string, unknown> = {};\n\t\t\t\t// The generic resolver channel — `values[namespace][key]` —\n\t\t\t\t// accumulated from any LIVE config-binding aggregate that\n\t\t\t\t// declared `idConfigValues` (the plugin live JSON the typed\n\t\t\t\t// fields can't carry). Deep-merged so sibling namespaces /\n\t\t\t\t// keys from distinct plugins coexist.\n\t\t\t\tconst values: Record<string, unknown> = {};\n\t\t\t\tfor (const decl of registered) {\n\t\t\t\t\tif (decl.aggregate === undefined) continue;\n\t\t\t\t\t// The generic `values` channel is BUCKET-BLIND: any LIVE\n\t\t\t\t\t// config-binding aggregate (config.ts, coins.ts, deepbook.ts,\n\t\t\t\t\t// walrus.ts, seal.ts, ...) may declare `idConfigValues`. Fold\n\t\t\t\t\t// every contributor's so the committed-tree `resolveValue` calls\n\t\t\t\t\t// those buckets emit resolve at app build/dev time -- not just the\n\t\t\t\t\t// `config.ts` plugins'. Slicing the TYPED id-config fields\n\t\t\t\t\t// (`networks` / `packages` / `mvrOverrides`) stays scoped to the\n\t\t\t\t\t// `config.ts` bucket below.\n\t\t\t\t\tif (decl.aggregate.idConfigValues !== undefined) {\n\t\t\t\t\t\tdeepMerge(values, decl.aggregate.idConfigValues);\n\t\t\t\t\t}\n\t\t\t\t\tif (decl.aggregate.bucket === 'config.ts') {\n\t\t\t\t\t\tconst emission = yield* runEmitter(decl);\n\t\t\t\t\t\tconst projected = decl.aggregate.project(emission.exports);\n\t\t\t\t\t\tif (projected !== null) deepMerge(bucket, projected);\n\t\t\t\t\t} else if (decl.aggregate.bucket === 'accounts.ts') {\n\t\t\t\t\t\tconst emission = yield* runEmitter(decl);\n\t\t\t\t\t\tconst projected = decl.aggregate.project(emission.exports);\n\t\t\t\t\t\tif (projected !== null) deepMerge(accounts, projected);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbucket['accounts'] = accounts;\n\t\t\t\treturn idConfigFromBucket(bucket, network, values as IdConfigValues);\n\t\t\t});\n\n\t\tconst emitExtras: CodegenOrchestrator['emitExtras'] = () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst registered = (yield* Ref.get(contributionsRef)).map((e) => e.decl);\n\t\t\t\tconst extras = registered.filter(isExtrasDecl);\n\t\t\t\tif (extras.length === 0) {\n\t\t\t\t\t// Nothing routed to the dev tree (no wallet/accounts mounted).\n\t\t\t\t\treturn { filesWritten: [], filesUnchanged: [], filesChmod: [], bindings: null };\n\t\t\t\t}\n\t\t\t\t// Validate the extras-only set up front (mirrors `runEmitCycle`'s\n\t\t\t\t// pre-flight), then emit DIRECTLY against the real paths — no\n\t\t\t\t// stage-and-swap, since the extras tree lives outside the runtime\n\t\t\t\t// `outputDir`. Every `generated-extras` decl routes through\n\t\t\t\t// `paths.resolveExtras`; no `generated`-located decl is present,\n\t\t\t\t// so the committed `src/generated` tree is untouched.\n\t\t\t\tyield* validateUniqueness(extras);\n\t\t\t\tyield* validateAggregatePathAvailability(extras);\n\t\t\t\tconst paths = yield* CodegenPathsService;\n\t\t\t\t// Acquire the dedicated `codegenLockFile` for symmetry with\n\t\t\t\t// `runEmitCycle` — the extras emit writes into the shared stack\n\t\t\t\t// tree (`generated-extras`) and a concurrent codegen cycle could\n\t\t\t\t// otherwise interleave. Scoped so the lock releases when the emit\n\t\t\t\t// completes (or fails).\n\t\t\t\treturn yield* Effect.scoped(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* acquireStackLock(paths.codegenLockFile, CODEGEN_CYCLE_LOCK_TIMEOUT_MS).pipe(\n\t\t\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\t\tnew CodegenWriteFailed({\n\t\t\t\t\t\t\t\t\t\toutputPath: paths.codegenLockFile,\n\t\t\t\t\t\t\t\t\t\tstage: 'write',\n\t\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn yield* runEmitCycleInner({ contributions: extras, trackTree: false }, paths);\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t});\n\n\t\treturn CodegenOrchestratorService.of({\n\t\t\tregisterContribution,\n\t\t\tassembleIdConfig,\n\t\t\temitExtras,\n\t\t});\n\t}),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"service.mjs","names":[],"sources":["../../../src/orchestrators/codegen/service.ts"],"sourcesContent":["// Codegen orchestrator — main service.\n//\n// Architecture §6 (Codegenable):\n// \"Codegen is a surface (L4) that walks the plugin-emitted\n// `Codegenable` capability decls.\"\n//\n// Hard boundary (distilled-doc §\"Hard boundary\"):\n// \"Apps consume codegen output, NOT devstack.\" Every runtime value\n// the app needs flows through codegen-emitted TS files. The\n// orchestrator owns the only legitimate channel from stack state\n// to app code.\n//\n// Lifecycle (distilled-doc §\"Lifecycle states\"):\n// - at-up: per supervisor cycle, run all emitters serially,\n// with per-file atomic/idempotent writes inside a\n// cycle-level stage-and-swap (rollback on any\n// per-file failure leaves the user-visible tree\n// unchanged).\n// - on-change: re-run as part of the new cycle when the\n// supervisor restarts.\n// - on-demand: same emit pipeline for snapshot resume.\n// - idempotency: per-file no-touch on unchanged content.\n//\n// Pipeline (one cycle):\n// 1. Collect `Codegenable` contributions from the active stack\n// members (the supervisor walks `member.capabilities`).\n// 2. Validate uniqueness: emitter name (literal) is globally\n// unique; output path is globally unique.\n// 3. Run each emitter serially (distilled-doc § \"Serial within a\n// cycle\"). Each emit writes exports through a per-file context.\n// 4. Render each collected file emission to a TS source string.\n// 5. Emit each file with an atomic write + per-file no-touch\n// idempotency.\n// 6. Run the Move-bindings emitter against the collected\n// `package`-emitted contributions.\n// 7. Write the `.gitignore`.\n//\n// What this module does NOT do:\n// - Construct plugin-level resolved blobs (plugins pass them at\n// factory-build time).\n// - Decode the manifest envelope (plugins pass resolved blobs at\n// factory-build time; the orchestrator never re-reads the envelope).\n// - Watch files. Re-emit is driven by the supervisor cycle (and\n// on-demand by the CLI); the app's own toolchain (Vite/HMR)\n// watches the emitted output tree.\n// - Walk the user's Move-source mtimes (see `bindings.ts`).\n\nimport { Context, Effect, FileSystem, Layer, Order, Ref, Scope } from 'effect';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport {\n\tForNetworkBucket,\n\tisForNetworkBucket,\n\tisRawExpr,\n\trawExpr,\n\ttype CodegenableDecl,\n\ttype CodegenEmitDone,\n\ttype CodegenEmitContext,\n} from '../../contracts/codegenable.ts';\nimport { CONFIG_RUNTIME_OUTPUT_PATH, CONFIG_RUNTIME_SOURCE } from './config-runtime.ts';\nimport { DEPLOYMENT_STRICT_OUTPUT_PATH, renderDeploymentStrict } from './deployment-strict.ts';\nimport { LOCAL_NETWORK_NAME } from '../../api/inference-network.ts';\nimport { acquireStackLock } from '../../substrate/runtime/cross-process/stack-lock.ts';\nimport { mintRandomSuffix } from '../../substrate/runtime/random-suffix.ts';\nimport { stageAndSwap, StageAndSwapError } from '../../substrate/runtime/stage-and-swap/index.ts';\n\nimport {\n\temitBindings,\n\ttype EmitBindingsResult,\n\tisPackageBindings,\n\tMoveCodegenService,\n\tMoveSummaryRunnerService,\n\ttype PackageBindings,\n} from './bindings.ts';\nimport { emitOne } from './emit.ts';\nimport {\n\tCodegenAggregateConflict,\n\tCodegenEmitFailed,\n\tCodegenEmitterCollision,\n\tCodegenPathConflict,\n\tCodegenWriteFailed,\n\ttype CodegenError,\n} from './errors.ts';\nimport { renderFile } from './format.ts';\nimport { writeGitignore } from './gitignore.ts';\nimport { UNRESOLVED_ID } from './deployment.ts';\nimport type {\n\tDevstackDeployment,\n\tNetworkDeployment,\n\tDeploymentPackage,\n\tDeploymentValues,\n} from './deployment.ts';\nimport { CodegenPathsService, type CodegenPaths } from './paths.ts';\nimport { dirModeFor, modeFor, NON_SENSITIVE_DIR_MODE } from './permissions.ts';\n\n// -----------------------------------------------------------------------------\n// Public types\n// -----------------------------------------------------------------------------\n\n/** A type alias the orchestrator uses internally to avoid restating\n * the wide-erased `CodegenableDecl` generic in every signature. */\nexport type Codegenable = CodegenableDecl<string>;\n\nexport interface RunEmitCycleInput {\n\t/** All Codegenable contributions, as collected from the active\n\t * stack members' `capabilities` tuples. The orchestrator does\n\t * not look at plugins — only at the decl set. */\n\treadonly contributions: ReadonlyArray<Codegenable>;\n\t/** Optional: import-extension for bindings emission. Default `.ts`. */\n\treadonly bindingsImportExtension?: '.ts' | '.js' | '';\n\t/** When `true`, this is the COMMITTED projection tree (`src/generated`,\n\t * written by the stack-free `codegen` verb): the `.gitignore` TRACKS\n\t * the stubs (bindings, config, config-runtime) so `tsc`/`vite build`\n\t * work on a fresh clone, ignoring only `sensitivePaths`. When\n\t * `false`/omitted, the ephemeral tree is blanket-ignored. */\n\treadonly trackTree?: boolean;\n\t/** The LIVE network names — the app's `deployments/*.ts` filenames (sans\n\t * `.ts`, local excluded) — used to render the strict `deployment.ts`\n\t * type's `ProvidedNetwork` union + `NETWORK_NAMES` tuple. Omitted ⇒ the\n\t * outer {@link runEmitCycle} discovers them by globbing\n\t * `<projectRoot>/deployments/*.ts` (the canonical, non-staging output\n\t * dir's grandparent). Empty / no dir ⇒ `ProvidedNetwork = never`. */\n\treadonly providedNetworks?: ReadonlyArray<string>;\n}\n\nexport interface RunEmitCycleResult {\n\treadonly filesWritten: ReadonlyArray<string>;\n\treadonly filesUnchanged: ReadonlyArray<string>;\n\treadonly filesChmod: ReadonlyArray<string>;\n\treadonly bindings: EmitBindingsResult | null;\n}\n\n/** Discover the app's LIVE network names by globbing `<projectRoot>/deployments/*.ts`\n * (D7 — the network set is the `deployments/` directory, by FILENAME; the\n * file CONTENTS are never read — ids load at app build via Vite). The\n * project root is the grandparent of the canonical (non-staging) codegen\n * `outputDir` (`<projectRoot>/src/generated`). Returns the filenames sans\n * `.ts`, sorted; empty when there is no `deployments/` dir (a clean clone /\n * template — `ProvidedNetwork = never`, `NETWORK_NAMES = [<local>]`). Never\n * throws — a read failure degrades to empty (no live networks). */\nconst discoverProvidedNetworks = (canonicalOutputDir: string): ReadonlyArray<string> => {\n\ttry {\n\t\t// `<projectRoot>/src/generated` → `<projectRoot>`. `deployments/` is a\n\t\t// sibling of `src/`.\n\t\tconst projectRoot = dirname(dirname(canonicalOutputDir));\n\t\tconst deploymentsDir = join(projectRoot, 'deployments');\n\t\tif (!existsSync(deploymentsDir)) return [];\n\t\treturn (\n\t\t\treaddirSync(deploymentsDir)\n\t\t\t\t.filter((f) => f.endsWith('.ts') && !f.endsWith('.d.ts'))\n\t\t\t\t.map((f) => f.slice(0, -'.ts'.length))\n\t\t\t\t.filter((n) => n.length > 0)\n\t\t\t\t// The local network is never a COMMITTED/provided network — it is the\n\t\t\t\t// live dev stack, added as the head of `NETWORK_NAMES` separately. A\n\t\t\t\t// stray committed `deployments/localnet.ts` must NOT pollute the\n\t\t\t\t// `ProvidedNetwork` union / `NETWORK_NAMES` tuple with a duplicate\n\t\t\t\t// `localnet`; the documented \"local excluded\" contract is enforced here\n\t\t\t\t// at the source so every consumer of `providedNetworks` sees it honored.\n\t\t\t\t.filter((n) => n !== LOCAL_NETWORK_NAME)\n\t\t\t\t.sort()\n\t\t);\n\t} catch {\n\t\treturn [];\n\t}\n};\n\nconst buildParentModeResolver = (\n\tpaths: CodegenPaths,\n\tentries: ReadonlyArray<{\n\t\treadonly outputPath: string;\n\t\treadonly sensitive: boolean;\n\t}>,\n): Effect.Effect<(absolutePath: string) => number, CodegenPathConflict> =>\n\tEffect.gen(function* () {\n\t\tconst byParent = new Map<string, Array<{ readonly sensitive?: boolean }>>();\n\t\tfor (const entry of entries) {\n\t\t\tconst parent = dirname(yield* paths.resolve(entry.outputPath));\n\t\t\tconst current = byParent.get(parent);\n\t\t\tif (current === undefined) {\n\t\t\t\tbyParent.set(parent, [{ sensitive: entry.sensitive }]);\n\t\t\t} else {\n\t\t\t\tcurrent.push({ sensitive: entry.sensitive });\n\t\t\t}\n\t\t}\n\t\tconst modes = new Map<string, number>();\n\t\tfor (const [parent, parentDecls] of byParent) {\n\t\t\tmodes.set(parent, dirModeFor(parentDecls));\n\t\t}\n\t\treturn (absolutePath: string) => modes.get(dirname(absolutePath)) ?? NON_SENSITIVE_DIR_MODE;\n\t});\n\n// -----------------------------------------------------------------------------\n// Main entry — one cycle of the codegen pipeline\n// -----------------------------------------------------------------------------\n\n/**\n * Per-cycle lock acquire timeout. Codegen cycles can be file-system\n * heavy (multi-emitter, Move-bindings compilation), so we allow more\n * than the substrate's default 5s for `stack.lock` — a custom CLI\n * caller that hits a supervisor mid-cycle should wait, not error.\n * Mirrors `MOVE_BUILD_LOCK_TIMEOUT_MS` (5 minutes).\n */\nconst CODEGEN_CYCLE_LOCK_TIMEOUT_MS = 5 * 60_000;\n\nexport const runEmitCycle = (\n\tinput: RunEmitCycleInput,\n): Effect.Effect<\n\tRunEmitCycleResult,\n\tCodegenError,\n\tFileSystem.FileSystem | CodegenPathsService | MoveSummaryRunnerService | MoveCodegenService\n> =>\n\t// Per-process lock. The supervisor's serialized post-acquire path\n\t// is fine for the normal lifecycle, but custom callers (CLI direct\n\t// invocations, future watcher hooks) can call `runEmitCycle`\n\t// concurrently. With `stageAndSwap` writing under shared\n\t// `<outputDir>.staging.<cycleId>` and `<outputDir>.bak.<cycleId>`\n\t// siblings — and with the pre-seed `fs.copy` reading from the\n\t// shared `outputDir` — two overlapping cycles can stage from a\n\t// half-published tree of the other. The lock serializes them.\n\t//\n\t// Dedicated `codegenLockFile` (NOT the substrate `stack.lock`):\n\t// codegen cycles can run for many seconds when Move bindings\n\t// compile, and the substrate's `stack.lock` is reserved for short\n\t// critical sections (roster mutations, the snapshot bounce). A\n\t// dedicated lock isolates codegen contention from those subsystems.\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tconst paths = yield* CodegenPathsService;\n\t\t\tyield* acquireStackLock(paths.codegenLockFile, CODEGEN_CYCLE_LOCK_TIMEOUT_MS).pipe(\n\t\t\t\tEffect.mapError(\n\t\t\t\t\t(cause) =>\n\t\t\t\t\t\tnew CodegenWriteFailed({\n\t\t\t\t\t\t\toutputPath: paths.codegenLockFile,\n\t\t\t\t\t\t\tstage: 'write',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn yield* runEmitCycleLocked(input);\n\t\t}),\n\t);\n\nconst runEmitCycleLocked = (\n\tinput: RunEmitCycleInput,\n): Effect.Effect<\n\tRunEmitCycleResult,\n\tCodegenError,\n\tFileSystem.FileSystem | CodegenPathsService | MoveSummaryRunnerService | MoveCodegenService\n> =>\n\tEffect.gen(function* () {\n\t\tconst paths = yield* CodegenPathsService;\n\t\t// Yield the Move-codegen services here (outside the\n\t\t// stage-and-swap build) so the build's R-channel collapses to\n\t\t// just `FileSystem.FileSystem` — the substrate `stageAndSwap`\n\t\t// primitive constrains `build`'s requirements to\n\t\t// `FileSystem.FileSystem`.\n\t\tconst moveRunner = yield* MoveSummaryRunnerService;\n\t\tconst moveCodegen = yield* MoveCodegenService;\n\n\t\t// Discover the app's LIVE network set ONCE from the canonical (non-\n\t\t// staging) `outputDir` — globbing `<projectRoot>/deployments/*.ts` by\n\t\t// FILENAME (D7). Done here (not inside the staging build, whose\n\t\t// `outputDir` is the throwaway `.staging.<id>` dir) so the project root\n\t\t// resolves against the real tree. The caller may override (e.g. a test\n\t\t// pinning a fixed set). Empty when no `deployments/` dir.\n\t\tconst providedNetworks = input.providedNetworks ?? discoverProvidedNetworks(paths.outputDir);\n\t\tconst innerInput: RunEmitCycleInput = { ...input, providedNetworks };\n\n\t\t// Pre-flight contribution-set validation. Detected BEFORE the\n\t\t// stage-and-swap so a programming-bug rejection (duplicate\n\t\t// emitterName / outputPath collision) never opens an empty\n\t\t// staging dir on disk. `package` is the one exception:\n\t\t// multiple instances (one per Package) legitimately share the\n\t\t// `emitterName` literal by design.\n\t\tyield* validateUniqueness(input.contributions);\n\t\tyield* validateAggregatePathAvailability(input.contributions);\n\n\t\t// Cycle-level atomicity: substrate stage-and-swap. The build\n\t\t// populates `<outputDir>.staging.<cycleId>/`; on success the\n\t\t// substrate renames it into place; on any failure the previous\n\t\t// tree (if any) is restored byte-for-byte. Without this wrapper\n\t\t// a mid-cycle emit failure would leave `src/generated/`\n\t\t// half-rewritten — see STYLE_GUIDE §19.\n\t\t//\n\t\t// `preserveOnPreseed: true` — substrate clones the current\n\t\t// target into staging before `build` runs so the per-file\n\t\t// no-touch idempotency (and gitignore user-block preservation)\n\t\t// sees the right baseline. Files this cycle rewrites are\n\t\t// overwritten in staging; files this cycle does NOT touch\n\t\t// survive into the next target verbatim with their original\n\t\t// mtimes (HMR watchers stay quiet for unchanged outputs).\n\t\t//\n\t\t// Cycle id is a random suffix. STYLE_GUIDE §17 mandates 8\n\t\t// hex chars for external-facing identifiers; this is a\n\t\t// deliberate 16-char carve-out because the value only\n\t\t// appears in transient staging-directory names\n\t\t// (`.staging.<id>` / `.bak.<id>`) that the substrate rm's\n\t\t// after publish. The extra entropy is defense-in-depth for\n\t\t// the race-window where two concurrent emit cycles under a\n\t\t// custom-CLI caller could mint overlapping staging dirs\n\t\t// against the same shared `outputDir`; a collision there\n\t\t// would corrupt a half-built tree, not just clash an\n\t\t// operator-visible name.\n\t\tconst cycleId = mintRandomSuffix(16);\n\t\tconst stagingPaths = paths.withRoot(`${paths.outputDir}.staging.${cycleId}`);\n\n\t\treturn yield* stageAndSwap({\n\t\t\ttargetPath: paths.outputDir,\n\t\t\tidSuffix: cycleId,\n\t\t\tpreserveOnPreseed: true,\n\t\t\tbuild: Effect.gen(function* () {\n\t\t\t\tconst inner = yield* runEmitCycleInner(innerInput, stagingPaths).pipe(\n\t\t\t\t\tEffect.provideService(MoveSummaryRunnerService, moveRunner),\n\t\t\t\t\tEffect.provideService(MoveCodegenService, moveCodegen),\n\t\t\t\t);\n\t\t\t\t// Rewrite paths so callers see the final user-visible\n\t\t\t\t// `outputDir` location, not the staging directory that\n\t\t\t\t// only exists for the duration of the build.\n\t\t\t\treturn rewriteResultPaths(inner, stagingPaths.outputDir, paths.outputDir);\n\t\t\t}),\n\t\t}).pipe(\n\t\t\tEffect.mapError((e): CodegenError => {\n\t\t\t\tif (e instanceof StageAndSwapError) {\n\t\t\t\t\treturn new CodegenWriteFailed({\n\t\t\t\t\t\toutputPath: paths.outputDir,\n\t\t\t\t\t\tstage: 'rename',\n\t\t\t\t\t\tcause: e,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn e;\n\t\t\t}),\n\t\t);\n\t});\n\n/**\n * Project a staging-rooted `RunEmitCycleResult` back into the user-\n * visible `outputDir` namespace. The build effect writes through\n * `stagingDir` paths; callers (and tests) expect to see the final\n * post-rename locations.\n */\nconst rewriteResultPaths = (\n\tresult: RunEmitCycleResult,\n\tstagingDir: string,\n\toutputDir: string,\n): RunEmitCycleResult => {\n\tconst stripped = stagingDir.replace(/\\/+$/, '');\n\tconst target = outputDir.replace(/\\/+$/, '');\n\tconst rewrite = (p: string): string =>\n\t\tp.startsWith(stripped) ? `${target}${p.slice(stripped.length)}` : p;\n\treturn {\n\t\tfilesWritten: result.filesWritten.map(rewrite),\n\t\tfilesUnchanged: result.filesUnchanged.map(rewrite),\n\t\tfilesChmod: result.filesChmod.map(rewrite),\n\t\tbindings:\n\t\t\tresult.bindings === null\n\t\t\t\t? null\n\t\t\t\t: {\n\t\t\t\t\t\t...result.bindings,\n\t\t\t\t\t\tfilesWritten: result.bindings.filesWritten.map(rewrite),\n\t\t\t\t\t},\n\t};\n};\n\n/**\n * The body of one emit cycle. Pulled out of `runEmitCycle` so the\n * stage-and-swap wrapper can drive it against a redirected\n * `CodegenPathsService` (the staging tree). Validation runs BEFORE\n * this function so callers know the contribution set is well-formed.\n */\nconst runEmitCycleInner = (\n\tinput: RunEmitCycleInput,\n\tpaths: CodegenPaths,\n): Effect.Effect<\n\tRunEmitCycleResult,\n\tCodegenError,\n\tFileSystem.FileSystem | MoveSummaryRunnerService | MoveCodegenService\n> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.logInfo(`codegen: emitting projection (trackTree=${input.trackTree === true}).`);\n\t\tconst fileEmitters: Array<Codegenable> = [...input.contributions];\n\n\t\tconst filesWritten: Array<string> = [];\n\t\tconst filesUnchanged: Array<string> = [];\n\t\tconst filesChmod: Array<string> = [];\n\t\t// Aggregate buckets keyed by plugin-supplied bucket name. The\n\t\t// orchestrator treats bucket names as opaque tags chosen by\n\t\t// the contributor; it never branches on plugin identity. See\n\t\t// `CodegenableDecl.aggregate` (contracts/codegenable.ts).\n\t\tconst aggregates = new Map<string, Record<string, unknown>>();\n\t\t// Per-bucket location + sensitivity, read from the first decl\n\t\t// the orchestrator sees contributing to the bucket. Drives where\n\t\t// the synthesized aggregate file lands and its file mode. Every\n\t\t// later contributor to the same bucket MUST agree (enforced\n\t\t// below) — a silent disagreement could misroute a sensitive\n\t\t// aggregate into the committed `generated` tree.\n\t\tconst aggregateMeta = new Map<string, AggregateMeta>();\n\t\tconst packageContribs: Array<PackageBindings> = [];\n\t\tconst sortedDecls = [...fileEmitters].sort(\n\t\t\tOrder.mapInput(Order.String, (d: Codegenable) => d.outputPath),\n\t\t);\n\t\t// Parent-mode resolver must see every path that will be written —\n\t\t// standalone decls AND synthesized aggregates — across BOTH trees.\n\t\t// Aggregate-only decls do not write a standalone file, so they are\n\t\t// excluded from the standalone-path set here.\n\t\tconst parentModeFor = yield* buildParentModeResolver(\n\t\t\tpaths,\n\t\t\tfileEmitters\n\t\t\t\t.filter((d) => d.aggregateOnly !== true)\n\t\t\t\t.map((d) => ({\n\t\t\t\t\toutputPath: d.outputPath,\n\t\t\t\t\tsensitive: d.sensitive === true,\n\t\t\t\t})),\n\t\t);\n\t\tfor (const decl of sortedDecls) {\n\t\t\tconst emission = yield* runEmitter(decl);\n\t\t\tconst exported = emission.exports;\n\t\t\tif (decl.aggregate !== undefined) {\n\t\t\t\tconst projected = decl.aggregate.project(exported);\n\t\t\t\tif (projected !== null) {\n\t\t\t\t\tconst bucket = aggregates.get(decl.aggregate.bucket) ?? {};\n\t\t\t\t\tdeepMerge(bucket, projected);\n\t\t\t\t\taggregates.set(decl.aggregate.bucket, bucket);\n\t\t\t\t\t// First-contributor-wins for sensitivity, but a LATER\n\t\t\t\t\t// contributor that disagrees is a hard error — the\n\t\t\t\t\t// `AggregateContribution` contract requires all\n\t\t\t\t\t// contributors to a bucket to agree, and a silent\n\t\t\t\t\t// mismatch could misroute a sensitive aggregate's\n\t\t\t\t\t// permissions (secret leak).\n\t\t\t\t\tconst declSensitive = decl.aggregate.sensitive === true;\n\t\t\t\t\tconst established = aggregateMeta.get(decl.aggregate.bucket);\n\t\t\t\t\tif (established === undefined) {\n\t\t\t\t\t\taggregateMeta.set(decl.aggregate.bucket, {\n\t\t\t\t\t\t\tsensitive: declSensitive,\n\t\t\t\t\t\t\testablishedBy: decl.emitterName,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (established.sensitive !== declSensitive) {\n\t\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\t\tnew CodegenAggregateConflict({\n\t\t\t\t\t\t\t\t\tbucket: decl.aggregate.bucket,\n\t\t\t\t\t\t\t\t\tfield: 'sensitive',\n\t\t\t\t\t\t\t\t\testablished: String(established.sensitive),\n\t\t\t\t\t\t\t\t\tconflicting: String(declSensitive),\n\t\t\t\t\t\t\t\t\temitters: [established.establishedBy, decl.emitterName],\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Move-bindings collection: any export whose shape matches\n\t\t\t// the orchestrator's `PackageBindings` consumer contract is\n\t\t\t// forwarded to `emitBindings`. Runs against the raw `exported`\n\t\t\t// map (not via `aggregate.project`) so direct `codegenable(...)`\n\t\t\t// contributions — which carry no `aggregate` — are picked up\n\t\t\t// too. The orchestrator validates the shape it consumes; it\n\t\t\t// does NOT name the plugin that produced it.\n\t\t\tfor (const value of Object.values(exported)) {\n\t\t\t\tif (isPackageBindings(value)) {\n\t\t\t\t\tpackageContribs.push(value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Aggregate-only decls contribute solely to their bucket; the\n\t\t\t// standalone per-decl file is skipped (the combined aggregate\n\t\t\t// is the only app-facing surface).\n\t\t\tif (decl.aggregateOnly === true) continue;\n\t\t\tconst rendered = renderFile({\n\t\t\t\temitterName: decl.emitterName,\n\t\t\t\toutputPath: decl.outputPath,\n\t\t\t\tsensitive: decl.sensitive === true,\n\t\t\t\texports: exported,\n\t\t\t\timports: emission.imports,\n\t\t\t});\n\t\t\tif (!rendered.ok) {\n\t\t\t\treturn yield* Effect.fail(rendered.error);\n\t\t\t}\n\t\t\tconst abs = yield* paths.resolve(decl.outputPath);\n\t\t\tconst outcome = yield* emitOne({\n\t\t\t\tpath: abs,\n\t\t\t\tcontent: rendered.text,\n\t\t\t\tmode: modeFor(decl),\n\t\t\t\tparentMode: parentModeFor(abs),\n\t\t\t});\n\t\t\tswitch (outcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Inject the static-only DEPLOYMENT envelope accessors into the\n\t\t// committed `config.ts` aggregate and wrap each SERVICE bucket\n\t\t// (coins/deepbook/seal/walrus) in its per-network `forNetwork(network)`\n\t\t// accessor — BEFORE usage scanning, so the resulting `__deployment` /\n\t\t// `dep` references drive the import + preamble below. The MVR `types`\n\t\t// overrides are NOT folded here: they are OPT-IN and come from the\n\t\t// package's own config bindings (each declared `mvrOverrides.types.<tag>`\n\t\t// already projected into the `config.ts` aggregate), so no bindings-derived\n\t\t// post-transform — and no dependency on the bindings having run first.\n\t\tconst aggregateFiles = buildAggregateFiles(aggregates, aggregateMeta)\n\t\t\t.map(withConfigEnvelopeAccessors)\n\t\t\t.map(withForNetworkAccessor);\n\t\t// True once any aggregate references a `config-runtime.ts` deployment\n\t\t// symbol (the committed `config.ts` + service buckets): then we ALSO emit\n\t\t// the fixed `config-runtime.ts` and import + preamble exactly what each\n\t\t// file references.\n\t\tlet needsConfigRuntime = false;\n\t\tfor (const aggregate of aggregateFiles) {\n\t\t\tconst usage = deploymentUsageOf(aggregate.exports);\n\t\t\tif (!deploymentUsageEmpty(usage)) needsConfigRuntime = true;\n\t\t\tconst imports = deploymentImportsFor(usage);\n\t\t\t// A SERVICE bucket carries its `dep` inside the `forNetwork(network)`\n\t\t\t// accessor (a per-call `loadDeployment().forNetwork(network)` local),\n\t\t\t// so it imports `loadDeployment` but emits NO module-level `dep` /\n\t\t\t// `__deployment` preamble. Non-service buckets (config.ts) keep the\n\t\t\t// module-level preamble.\n\t\t\tconst preamble = isServiceBucket(aggregate.outputPath) ? [] : deploymentPreambleFor(usage);\n\t\t\t// `config.ts` references the app-specific `NETWORK_NAMES` tuple (D2)\n\t\t\t// for `defaultNetwork`/`networkNames`; import it from the strict\n\t\t\t// `deployment.ts` we emit alongside `config-runtime.ts`. Scan for the\n\t\t\t// identifier so only files that use it carry the import (oxlint flags\n\t\t\t// unused). `import type` is wrong — `NETWORK_NAMES` is a runtime value\n\t\t\t// (used both as a value AND in the `typeof` cast).\n\t\t\tconst usesNetworkNames = referencesNetworkNames(aggregate.exports);\n\t\t\tconst importLines: Array<string> = [];\n\t\t\tif (imports.length > 0) {\n\t\t\t\timportLines.push(`import { ${imports.join(', ')} } from './config-runtime.js';`);\n\t\t\t}\n\t\t\tif (usesNetworkNames) {\n\t\t\t\timportLines.push(`import { NETWORK_NAMES } from './deployment.js';`);\n\t\t\t}\n\t\t\tconst rendered = renderFile({\n\t\t\t\temitterName: aggregate.emitterName,\n\t\t\t\toutputPath: aggregate.outputPath,\n\t\t\t\tsensitive: aggregate.sensitive,\n\t\t\t\texports: aggregate.exports,\n\t\t\t\t// The committed `config.ts` + service buckets read off the injected\n\t\t\t\t// deployment at runtime — import exactly the symbols referenced (no\n\t\t\t\t// unused imports; oxlint is pinned and flags them) and emit the\n\t\t\t\t// `loadDeployment()` / `dep` preamble. `.js` specifier (ESM/TS-\n\t\t\t\t// resolved) mirrors the bindings' import style.\n\t\t\t\t...(importLines.length > 0 ? { imports: importLines } : {}),\n\t\t\t\t...(preamble.length > 0 ? { preamble } : {}),\n\t\t\t});\n\t\t\tif (!rendered.ok) {\n\t\t\t\treturn yield* Effect.fail(rendered.error);\n\t\t\t}\n\t\t\tconst abs = yield* paths.resolve(aggregate.outputPath);\n\t\t\tconst outcome = yield* emitOne({\n\t\t\t\tpath: abs,\n\t\t\t\tcontent: rendered.text,\n\t\t\t\tmode: aggregate.sensitive ? 0o600 : 0o644,\n\t\t\t\tparentMode: parentModeFor(abs),\n\t\t\t});\n\t\t\tswitch (outcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Emit the FIXED `config-runtime.ts` resolver (a constant string, NOT\n\t\t// routed through the literal renderer) when `config.ts` resolves ids\n\t\t// at runtime. It reads the injected `__DEVSTACK_DEPLOYMENT__` global and\n\t\t// THROWS `DevstackConfigMissingError` on an unresolved id.\n\t\tif (needsConfigRuntime) {\n\t\t\tconst abs = yield* paths.resolve(CONFIG_RUNTIME_OUTPUT_PATH);\n\t\t\tconst outcome = yield* emitOne({\n\t\t\t\tpath: abs,\n\t\t\t\tcontent: CONFIG_RUNTIME_SOURCE,\n\t\t\t\tmode: 0o644,\n\t\t\t\tparentMode: parentModeFor(abs),\n\t\t\t});\n\t\t\tswitch (outcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(abs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Emit the APP-SPECIFIC strict `deployment.ts` type alongside the\n\t\t\t// fixed `config-runtime.ts` (it imports `NetworkDeployment` from\n\t\t\t// it). RENDERED FROM DATA: `AppPackages` is exhaustive over the\n\t\t\t// declared package names, `AppNetworkDeployment.mvrOverrides`\n\t\t\t// requires the declared `@local/*` placeholders, and\n\t\t\t// `ProvidedNetwork` / `NETWORK_NAMES` enumerate the live networks\n\t\t\t// from the `deployments/*.ts` filenames (D7, passed in\n\t\t\t// `providedNetworks`). Types-only + zero runtime (bar the\n\t\t\t// `NETWORK_NAMES` tuple) so a clean clone (no `deployments/` dir →\n\t\t\t// empty `providedNetworks`) stays `tsc`-green.\n\t\t\tconst strictInput = strictTypeInputFrom(aggregateFiles);\n\t\t\tconst deploymentStrict = renderDeploymentStrict({\n\t\t\t\tlocalNetworkName: LOCAL_NETWORK_NAME,\n\t\t\t\tpackageNames: strictInput.packageNames,\n\t\t\t\tmvrPlaceholders: strictInput.mvrPlaceholders,\n\t\t\t\tmvrTypeTags: strictInput.mvrTypeTags,\n\t\t\t\tprovidedNetworks: input.providedNetworks ?? [],\n\t\t\t\tserviceValues: serviceValuesFrom(input.contributions),\n\t\t\t});\n\t\t\tconst strictAbs = yield* paths.resolve(DEPLOYMENT_STRICT_OUTPUT_PATH);\n\t\t\tconst strictOutcome = yield* emitOne({\n\t\t\t\tpath: strictAbs,\n\t\t\t\tcontent: deploymentStrict,\n\t\t\t\tmode: 0o644,\n\t\t\t\tparentMode: parentModeFor(strictAbs),\n\t\t\t});\n\t\t\tswitch (strictOutcome.outcome) {\n\t\t\t\tcase 'wrote':\n\t\t\t\t\tfilesWritten.push(strictAbs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'unchanged':\n\t\t\t\t\tfilesUnchanged.push(strictAbs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'chmod-only':\n\t\t\t\t\tfilesChmod.push(strictAbs);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Run the Move-to-TS bindings step — render each local package's typed\n\t\t// client modules into `generated/bindings/`. Order-independent of the\n\t\t// aggregate emission above: the MVR `types` overrides are opt-in and come\n\t\t// from the package's config bindings, not from the rendered bindings, so\n\t\t// nothing downstream of this step depends on its result beyond the emitted\n\t\t// files + the returned summary.\n\t\tlet bindings: EmitBindingsResult | null = null;\n\t\tif (packageContribs.length > 0) {\n\t\t\tbindings = yield* emitBindings({\n\t\t\t\tbindingsDir: paths.bindingsDir,\n\t\t\t\tpackages: packageContribs,\n\t\t\t\timportExtension: input.bindingsImportExtension,\n\t\t\t});\n\t\t} else {\n\t\t\tyield* Effect.logInfo(\n\t\t\t\t'codegen: no package contributions; skipping Move-to-TS bindings step.',\n\t\t\t);\n\t\t}\n\n\t\t// `.gitignore` covers the runtime `generated/` tree only.\n\t\t// Aggregate-only decls never write a standalone file, so they are\n\t\t// excluded here — the managed `.gitignore` only lists real sensitive\n\t\t// files in `outputDir`.\n\t\t//\n\t\t// Synthesized aggregate files are a SEPARATE source of sensitive\n\t\t// runtime paths: a sensitive aggregate bucket writes a real\n\t\t// secret-bearing file in `outputDir` that the standalone-decl scan\n\t\t// above never sees (its contributors may all be `aggregateOnly`).\n\t\t// Without an explicit ignore line such a file would rely solely on\n\t\t// the blanket `*` rule — and a user `!<file>` override in the\n\t\t// preserved user block would then start tracking the secret. Include\n\t\t// them so each gets an explicit re-ignore line. The managed\n\t\t// `.gitignore` belongs to the committed/live `generated` tree at\n\t\t// `<outputDir>/.gitignore`. Write it ONLY when this emit actually\n\t\t// produces output: a metadata-only cycle (no standalone files, no\n\t\t// aggregate files — e.g. boot's values-only deployment assembly,\n\t\t// which writes no committed file) must NOT clobber the committed\n\t\t// tree's TRACKED policy with the blanket ignore-all, which would\n\t\t// break `tsc`/`vite build` on a fresh clone.\n\t\tconst hasGeneratedOutput =\n\t\t\tfileEmitters.some((d) => d.aggregateOnly !== true) || aggregateFiles.length > 0;\n\t\tif (hasGeneratedOutput) {\n\t\t\tconst sensitivePaths = [\n\t\t\t\t...fileEmitters\n\t\t\t\t\t.filter((d) => d.sensitive === true && d.aggregateOnly !== true)\n\t\t\t\t\t.map((d) => d.outputPath),\n\t\t\t\t...aggregateFiles.filter((a) => a.sensitive).map((a) => a.outputPath),\n\t\t\t];\n\t\t\tyield* writeGitignore({\n\t\t\t\tpath: paths.gitignoreFile,\n\t\t\t\tsensitivePaths,\n\t\t\t\tparentMode: parentModeFor(paths.gitignoreFile),\n\t\t\t\ttrackTree: input.trackTree === true,\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tfilesWritten,\n\t\t\tfilesUnchanged,\n\t\t\tfilesChmod,\n\t\t\tbindings,\n\t\t};\n\t});\n\n// -----------------------------------------------------------------------------\n// Internals\n// -----------------------------------------------------------------------------\n\ninterface CodegenEmission {\n\treadonly exports: { readonly [key: string]: unknown };\n\treadonly imports: ReadonlyArray<string>;\n}\n\nconst runEmitter = (decl: Codegenable): Effect.Effect<CodegenEmission, CodegenEmitFailed> =>\n\tEffect.gen(function* () {\n\t\t// Annotate the emit span with the contributor's plugin-supplied\n\t\t// `kind` tag (declared on the decl's `aggregate`). The orchestrator\n\t\t// stays name-blind — it never reads the tag's VALUE or branches on it\n\t\t// (per the `AggregateContribution` contract); wiring it here makes the\n\t\t// otherwise-dead field observable so a trace attributes each emit to\n\t\t// the plugin family that produced it. `annotateCurrentSpan` only lands\n\t\t// inside an enclosing `withSpan` — the `codegen.emit` span this body is\n\t\t// wrapped in below.\n\t\tconst kind = decl.aggregate?.kind;\n\t\tif (kind !== undefined) {\n\t\t\tyield* Effect.annotateCurrentSpan('codegen.kind', kind);\n\t\t}\n\t\tconst exports: Record<string, unknown> = {};\n\t\tconst imports: Array<string> = [];\n\t\tconst done: CodegenEmitDone = { _tag: 'CodegenEmitDone' };\n\t\tconst ctx: CodegenEmitContext = {\n\t\t\texportConst: (name, value) => {\n\t\t\t\texports[name] = value;\n\t\t\t},\n\t\t\timportStatement: (statement) => {\n\t\t\t\timports.push(statement);\n\t\t\t},\n\t\t\tdone: () => done,\n\t\t};\n\t\tyield* decl.emit(ctx).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew CodegenEmitFailed({\n\t\t\t\t\t\temitterName: decl.emitterName,\n\t\t\t\t\t\toutputPath: decl.outputPath,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\treturn { exports, imports };\n\t}).pipe(Effect.withSpan('codegen.emit', { attributes: { 'codegen.emitter': decl.emitterName } }));\n\n/**\n * Uniqueness check: emitter name (literal) must be unique unless\n * the decl opts into repetition via `allowEmitterNameRepetition`\n * (used by per-item plugins like Package, which emit one decl per\n * published package under a shared emitter name). Output paths\n * must be unique across ALL emitters.\n */\nconst validateUniqueness = (\n\tdecls: ReadonlyArray<Codegenable>,\n): Effect.Effect<void, CodegenPathConflict | CodegenEmitterCollision> =>\n\tEffect.gen(function* () {\n\t\tconst byPath = new Map<string, Array<string>>();\n\t\tconst byName = new Map<string, Array<string>>();\n\t\tfor (const d of decls) {\n\t\t\t// Aggregate-only decls write no standalone file, so their\n\t\t\t// `outputPath` is a dead value — exclude them from the\n\t\t\t// path-uniqueness check (many `package` decls legitimately\n\t\t\t// share `config.ts`'s bucket but carry distinct dead\n\t\t\t// `package/<name>.ts` outputPaths that never hit disk).\n\t\t\tif (d.aggregateOnly !== true) {\n\t\t\t\tconst ps = byPath.get(d.outputPath) ?? [];\n\t\t\t\tps.push(d.emitterName);\n\t\t\t\tbyPath.set(d.outputPath, ps);\n\t\t\t}\n\t\t\tif (d.allowEmitterNameRepetition === true) continue;\n\t\t\tconst ns = byName.get(d.emitterName) ?? [];\n\t\t\tns.push(d.outputPath);\n\t\t\tbyName.set(d.emitterName, ns);\n\t\t}\n\t\tfor (const [outputPath, emitters] of byPath) {\n\t\t\tif (emitters.length > 1) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CodegenPathConflict({\n\t\t\t\t\t\tkind: 'duplicate',\n\t\t\t\t\t\toutputPath,\n\t\t\t\t\t\temitters,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tfor (const [name, outputPaths] of byName) {\n\t\t\tif (outputPaths.length > 1) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CodegenEmitterCollision({\n\t\t\t\t\t\temitterName: name,\n\t\t\t\t\t\toutputPaths,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n/**\n * Reject contribution sets that would have an aggregate bucket\n * collide with a per-decl `outputPath`. The orchestrator only knows\n * bucket names because plugins declared them via `aggregate.bucket`;\n * it does not enumerate or recognize plugin identities here.\n */\nconst validateAggregatePathAvailability = (\n\tdecls: ReadonlyArray<Codegenable>,\n): Effect.Effect<void, CodegenPathConflict> =>\n\tEffect.gen(function* () {\n\t\t// A standalone decl that writes a synthesized aggregate bucket's\n\t\t// path would clash with the aggregate; an aggregate-only decl\n\t\t// (which writes no standalone file) does not.\n\t\tconst aggregateBuckets = new Set<string>();\n\t\tfor (const decl of decls) {\n\t\t\tif (decl.aggregate !== undefined) {\n\t\t\t\taggregateBuckets.add(decl.aggregate.bucket);\n\t\t\t}\n\t\t}\n\t\tfor (const bucket of aggregateBuckets) {\n\t\t\tconst colliding = decls.filter(\n\t\t\t\t(decl) => decl.aggregateOnly !== true && decl.outputPath === bucket,\n\t\t\t);\n\t\t\tif (colliding.length > 0) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CodegenPathConflict({\n\t\t\t\t\t\tkind: 'duplicate',\n\t\t\t\t\t\toutputPath: bucket,\n\t\t\t\t\t\temitters: [...colliding.map((decl) => decl.emitterName), `aggregate/${bucket}`],\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n/** Per-bucket sensitivity, captured from the first decl the\n * orchestrator sees contributing to a bucket. The orchestrator stays\n * name-blind; the plugin owns this on its `AggregateContribution`.\n * `establishedBy` records the emitter name of that first contributor so\n * a later disagreement can quote both sides in\n * `CodegenAggregateConflict`. */\ninterface AggregateMeta {\n\treadonly sensitive: boolean;\n\treadonly establishedBy: string;\n}\n\ninterface AggregateFile {\n\treadonly emitterName: string;\n\treadonly outputPath: string;\n\treadonly exports: { readonly [key: string]: unknown };\n\treadonly sensitive: boolean;\n}\n\n/**\n * Recursively merge `source` into `target`. Distinct buckets are\n * shallow records keyed by name, but a single bucket (e.g. `config.ts`)\n * accumulates contributions from MANY plugins into nested sub-records\n * (`networks.localnet` from sui, `packages.<name>` / `objects.<name>`\n * from each package). A shallow `Object.assign` would have the last\n * package's `{packages:{...}}` clobber the prior ones. Deep-merge so\n * sibling keys at every level coexist.\n *\n * Arrays and non-plain values overwrite (no element-wise merge — a\n * plugin that re-emits a bucket key owns its full value). Only plain\n * objects recurse.\n */\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n\ttypeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst deepMerge = (\n\ttarget: Record<string, unknown>,\n\tsource: Readonly<Record<string, unknown>>,\n): void => {\n\tfor (const [key, value] of Object.entries(source)) {\n\t\tconst existing = target[key];\n\t\tif (isPlainObject(existing) && isPlainObject(value)) {\n\t\t\tdeepMerge(existing, value);\n\t\t} else {\n\t\t\t// `value` may be a decl-owned cached projection object (or array).\n\t\t\t// Storing it by reference would let a sibling decl that later\n\t\t\t// recurses into the same nested key mutate this decl's cache in\n\t\t\t// place, leaking state across emit cycles. Deep-clone any plain\n\t\t\t// object / array so the shared bucket never aliases decl state.\n\t\t\ttarget[key] = isPlainObject(value) || Array.isArray(value) ? structuredClone(value) : value;\n\t\t}\n\t}\n};\n\n/**\n * Synthesize one `AggregateFile` per non-empty bucket. The exports\n * map is keyed by the bucket's stem (e.g. `accounts.ts` → `accounts`)\n * so the rendered file exports `export const <stem> = { ... }`. The\n * orchestrator picks the export key from the bucket filename; the\n * stem itself is not a plugin identifier — it is the filename\n * without the `.ts` extension, derived mechanically. The bucket's\n * `sensitive` flag (from the first contributing decl) drives its mode.\n */\nconst buildAggregateFiles = (\n\tbuckets: ReadonlyMap<string, Record<string, unknown>>,\n\tmeta: ReadonlyMap<string, AggregateMeta>,\n): ReadonlyArray<AggregateFile> => {\n\tconst files: Array<AggregateFile> = [];\n\tconst sortedEntries = [...buckets.entries()].sort(([a], [b]) => a.localeCompare(b));\n\tfor (const [bucket, contents] of sortedEntries) {\n\t\tif (Object.keys(contents).length === 0) continue;\n\t\tconst stem = bucketStem(bucket);\n\t\tconst bucketMeta = meta.get(bucket) ?? {\n\t\t\tsensitive: false,\n\t\t\testablishedBy: `aggregate/${stem}`,\n\t\t};\n\t\tfiles.push({\n\t\t\temitterName: `aggregate/${stem}`,\n\t\t\toutputPath: bucket,\n\t\t\texports: { [stem]: contents },\n\t\t\tsensitive: bucketMeta.sensitive,\n\t\t});\n\t}\n\treturn files;\n};\n\nconst bucketStem = (bucket: string): string => bucket.replace(/\\.ts$/, '').replace(/^.*\\//, '');\n\n/** The committed `config.ts` bucket. The orchestrator already encodes\n * `config.ts` semantics by name elsewhere (the live `assembleDeployment`\n * slices it by this exact bucket); the static envelope-accessor injection\n * below is the matching static-render-only branch. */\nconst CONFIG_BUCKET = 'config.ts';\n\n/** The network-agnostic `accounts.ts` bucket. Like `config.ts`, this is a\n * bucket the orchestrator special-cases STRUCTURALLY (not by plugin identity):\n * the live `assembleDeployment` folds it into the deployment envelope's\n * network-AGNOSTIC `accounts` map (name → address) rather than any per-network\n * unit, so it must NOT receive the per-network `forNetwork(network)` wrapper. */\nconst ACCOUNTS_BUCKET = 'accounts.ts';\n\n/** The network-agnostic `packages.ts` MVR-pointer bucket. Unlike the service\n * buckets, its per-network package ids do NOT live in this module — they\n * resolve through `config.forNetwork(net).packages.<name>.id`; the standalone\n * `packages.ts` export is only the network-agnostic MVR placeholder plus the\n * default-network convenience id. It therefore must NOT receive the per-network\n * `forNetwork(network)` wrapper (doing so reshapes `packages.<name>` into a\n * network accessor and breaks `packages.<name>.mvrPlaceholder`). It is absent\n * from `assembleDeployment`'s name branches because the envelope's `packages`\n * field is sliced out of `config.ts`, not this aggregate. */\nconst PACKAGES_BUCKET = 'packages.ts';\n\n/** The buckets that are NOT per-network service buckets — the ones the\n * orchestrator special-cases structurally:\n * - `config.ts`: carries the TYPED deployment channel and its own\n * per-network `forNetwork` field (injected by {@link withConfigEnvelopeAccessors});\n * `assembleDeployment` slices it into `network`/`networks`/`packages`/`mvrOverrides`.\n * - `accounts.ts`: network-agnostic (name → address), folded into the\n * envelope's `accounts` map by `assembleDeployment`.\n * - `packages.ts`: network-agnostic MVR pointers (see {@link PACKAGES_BUCKET}).\n * config/accounts mirror the two bucket arms `assembleDeployment` branches on;\n * `packages.ts` is the additional structurally-network-agnostic aggregate whose\n * per-network story is owned by `config.forNetwork`. Keeping this set to the\n * genuinely network-agnostic buckets is what lets the STATIC `forNetwork` gate\n * auto-wrap any NEW per-network service bucket by default. */\nconst NON_SERVICE_BUCKETS: ReadonlySet<string> = new Set([\n\tCONFIG_BUCKET,\n\tACCOUNTS_BUCKET,\n\tPACKAGES_BUCKET,\n]);\n\n/** True when a bucket is a per-network SERVICE bucket (coins / deepbook / seal /\n * walrus today; a NEW plugin's `pyth.ts` automatically) — i.e. any aggregate\n * bucket that is NOT one of the orchestrator's structurally-special buckets.\n *\n * Derived from a DECLARED structural fact (the bucket is not config / not\n * accounts) rather than a hard-coded service-name allowlist: a per-network\n * service plugin emitting a new bucket is wrapped in its `forNetwork(network)`\n * accessor by default, so its ids resolve for the dapp-kit-selected network\n * instead of silently baking the DEFAULT network's ids at module load. */\nconst isServiceBucket = (bucket: string): boolean => !NON_SERVICE_BUCKETS.has(bucket);\n\n/**\n * Inject the DEPLOYMENT envelope-accessor fields into the committed\n * `config.ts` aggregate's `config` object literal as raw expressions:\n * - `defaultNetwork: __deployment.defaultNetwork`\n * - `networkNames: __deployment.networkNames`\n * - `forNetwork: __deployment.forNetwork`\n *\n * There is deliberately NO `activeNetwork` field: the genuinely active network\n * is whatever dapp-kit currently has selected (it can `switchNetwork` at\n * runtime), so a statically-resolved \"active\" entry would lie the moment the\n * user switches. Apps resolve per-network data through\n * `config.forNetwork(<dapp-kit-selected network>)` — e.g.\n * `createClient(network) => config.forNetwork(network)` — so nothing drifts out\n * of sync with the selected network.\n *\n * STATIC-render-only: these are wired into the emitted committed tree so apps\n * can enumerate / look up networks off `config`, but they are NOT part of the\n * live deployment path (`assembleDeployment` / `deploymentFromBucket` slice the raw\n * `network`/`networks`/`packages`/`mvrOverrides` fields, never these). The\n * aggregate file's `exports` is `{ config: {...} }`; mutate the inner object.\n */\nconst withConfigEnvelopeAccessors = (file: AggregateFile): AggregateFile => {\n\tif (file.outputPath !== CONFIG_BUCKET) return file;\n\tconst stem = bucketStem(file.outputPath); // 'config'\n\tconst inner = file.exports[stem];\n\tif (!isPlainObject(inner)) return file;\n\tconst augmented: Record<string, unknown> = {\n\t\t...inner,\n\t\t// Typed against the app-specific `NETWORK_NAMES` tuple (D2) so dapp-kit's\n\t\t// `switchNetwork(name)` is literal-checked: `defaultNetwork` narrows to\n\t\t// the tuple's element union, and `networkNames` IS the literal tuple\n\t\t// (the app's declared network set: local + committed `deployments/*.ts`).\n\t\tdefaultNetwork: rawExpr('__deployment.defaultNetwork as (typeof NETWORK_NAMES)[number]'),\n\t\tnetworkNames: rawExpr('NETWORK_NAMES'),\n\t\tforNetwork: rawExpr('__deployment.forNetwork'),\n\t};\n\treturn { ...file, exports: { ...file.exports, [stem]: augmented } };\n};\n\n/**\n * Wrap a SERVICE bucket's inner object in a `forNetwork(network)` accessor.\n *\n * A per-network service bucket (coin → `coins.ts`, deepbook → `deepbook.ts`,\n * seal → `seal.ts`, walrus → `walrus.ts`, and any NEW plugin's bucket) gets its\n * ids wrapped so they resolve for the dapp-kit-selected network rather than the\n * default network baked at module load. Which buckets qualify is derived from\n * {@link isServiceBucket} (every bucket that is not the structurally-special\n * `config.ts` / `accounts.ts`) — see its note for why a declared denylist beats\n * a hard-coded service-name allowlist.\n *\n * The aggregate file's `exports` is `{ <stem>: <merged bucket object> }`. We\n * replace the merged object with a {@link ForNetworkBucket} marker the renderer\n * emits as `{ forNetwork(network) { const dep = …; return <object> as const; } }`.\n * `needsDep` is true when the merged object actually references `dep` (a\n * pure-literal bucket — known/live seal, builtin-only coin — does not, so the\n * accessor omits the `const dep` line and ignores its `network` param).\n *\n * Non-service buckets pass through unchanged.\n */\nconst withForNetworkAccessor = (file: AggregateFile): AggregateFile => {\n\tif (!isServiceBucket(file.outputPath)) return file;\n\tconst stem = bucketStem(file.outputPath);\n\tconst inner = file.exports[stem];\n\tif (!isPlainObject(inner)) return file;\n\tconst usage = { ...EMPTY_DEPLOYMENT_USAGE };\n\tscanDeploymentUsage(inner, usage);\n\tconst marker = new ForNetworkBucket(inner, usage.usesDep);\n\treturn { ...file, exports: { ...file.exports, [stem]: marker } };\n};\n\n/** Pull the app's declared package names + MVR placeholders out of the\n * committed `config.ts` aggregate's inner `config` object — the SAME data\n * the strict `deployment.ts` type narrows over. `config.packages.<name>`\n * gives the package names; `config.mvrOverrides.<mvr>` gives the placeholder\n * keys. Both come from the deep-merged bucket (no chain / no live data), so\n * this stays a pure projection over already-collected exports. Returns empty\n * arrays when there is no `config.ts` aggregate. */\nconst strictTypeInputFrom = (\n\taggregateFiles: ReadonlyArray<AggregateFile>,\n): {\n\tpackageNames: ReadonlyArray<string>;\n\tmvrPlaceholders: ReadonlyArray<string>;\n\tmvrTypeTags: ReadonlyArray<string>;\n} => {\n\tconst empty = { packageNames: [], mvrPlaceholders: [], mvrTypeTags: [] };\n\tconst configFile = aggregateFiles.find((f) => f.outputPath === CONFIG_BUCKET);\n\tif (configFile === undefined) return empty;\n\tconst inner = configFile.exports[bucketStem(CONFIG_BUCKET)];\n\tif (!isPlainObject(inner)) return empty;\n\tconst packagesNode = inner['packages'];\n\t// `mvrOverrides` is now the @mysten override shape `{ packages, types }`\n\t// (the package plugin's `mvrOverrides.packages.<mvr>` + the orchestrator-\n\t// folded `mvrOverrides.types.<tag>`). Read each sub-map's keys.\n\tconst mvrNode = isPlainObject(inner['mvrOverrides']) ? inner['mvrOverrides'] : {};\n\tconst mvrPackagesNode = mvrNode['packages'];\n\tconst mvrTypesNode = mvrNode['types'];\n\tconst packageNames = isPlainObject(packagesNode) ? Object.keys(packagesNode).sort() : [];\n\tconst mvrPlaceholders = isPlainObject(mvrPackagesNode) ? Object.keys(mvrPackagesNode).sort() : [];\n\tconst mvrTypeTags = isPlainObject(mvrTypesNode) ? Object.keys(mvrTypesNode).sort() : [];\n\treturn { packageNames, mvrPlaceholders, mvrTypeTags };\n};\n\n/**\n * Derive the structured SERVICE-VALUE channel `values[namespace][key] = <tsType>`\n * for the strict `deployment.ts` — every generic (non-sugar) RESOLVED\n * config-binding the contributions declare. Computed from the SAME contribution\n * decls the cycle emits: a binding lands here exactly when it would land in the\n * live deployment's generic `values` channel (a `resolved` binding with NO\n * `sugar`), so the required `AppNetworkDeployment.values` shape matches what a\n * resolved deployment actually carries. The tsType is read off each contribution's\n * `aggregate.valueTypes` (added in config-bindings); a binding with no declared\n * tsType contributes `'unknown'`. Empty for a service-less app.\n */\nconst serviceValuesFrom = (\n\tcontributions: ReadonlyArray<Codegenable>,\n): Record<string, Record<string, string>> => {\n\tconst out: Record<string, Record<string, string>> = {};\n\tfor (const decl of contributions) {\n\t\tconst valueTypes = decl.aggregate?.valueTypes;\n\t\tif (valueTypes === undefined) continue;\n\t\tfor (const [ns, keys] of Object.entries(valueTypes)) {\n\t\t\tconst nsOut = (out[ns] ??= {});\n\t\t\tfor (const [key, tsType] of Object.entries(keys)) {\n\t\t\t\tnsOut[key] = tsType;\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n};\n\n/** Which `config-runtime.ts` deployment symbols an aggregate's emitted raw\n * expressions reference. Drives BOTH the `./config-runtime.js` import line\n * (oxlint is pinned and flags unused imports — emit only what's used) AND the\n * module-level preamble the emitted file needs:\n * `const __deployment = loadDeployment();`\n * `const dep = __deployment.forNetwork(__deployment.defaultNetwork);`\n *\n * - `usesDep`: any expr references the `dep` identifier\n * (`requireId(dep, …)`, `requireValue(dep, …)`, `dep.network`, …) — needs\n * the `dep` preamble line (and therefore `__deployment` + `loadDeployment`).\n * - `usesDeployment`: any expr references `__deployment` (the `networks`\n * sugar's `Object.fromEntries(__deployment.networkNames.map(...))`) — needs\n * the `__deployment` preamble line (and `loadDeployment`).\n * - `requireId` / `requireValue` / `optionalValue`: the named helper appears\n * in some expr — import it. */\ninterface DeploymentUsage {\n\treadonly usesDep: boolean;\n\treadonly usesDeployment: boolean;\n\treadonly requireId: boolean;\n\treadonly requireValue: boolean;\n\treadonly optionalValue: boolean;\n}\n\nconst EMPTY_DEPLOYMENT_USAGE: DeploymentUsage = {\n\tusesDep: false,\n\tusesDeployment: false,\n\trequireId: false,\n\trequireValue: false,\n\toptionalValue: false,\n};\n\nconst deploymentUsageEmpty = (u: DeploymentUsage): boolean =>\n\t!u.usesDep && !u.usesDeployment && !u.requireId && !u.requireValue && !u.optionalValue;\n\n/** Recursively scan an exports value's raw expressions, OR-ing in the\n * deployment symbols each references. */\nconst scanDeploymentUsage = (\n\tvalue: unknown,\n\tacc: { -readonly [K in keyof DeploymentUsage]: boolean },\n): void => {\n\tif (isRawExpr(value)) {\n\t\tconst e = value.expr;\n\t\t// `dep` as a standalone identifier (not a substring of e.g. `__deployment`).\n\t\tif (/\\bdep\\b/.test(e)) acc.usesDep = true;\n\t\tif (e.includes('__deployment')) acc.usesDeployment = true;\n\t\tif (e.includes('requireId(')) acc.requireId = true;\n\t\tif (e.includes('requireValue')) acc.requireValue = true;\n\t\tif (e.includes('optionalValue(')) acc.optionalValue = true;\n\t\treturn;\n\t}\n\t// A per-network service bucket carries its `dep` references inside the\n\t// `forNetwork` accessor's `inner` object — recurse so the import scan sees\n\t// the `requireValue` / `loadDeployment` symbols (the accessor's body calls\n\t// `loadDeployment().forNetwork(network)`, so a bucket with resolved fields\n\t// always needs `loadDeployment`).\n\tif (isForNetworkBucket(value)) {\n\t\tscanDeploymentUsage(value.inner, acc);\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const v of value) scanDeploymentUsage(v, acc);\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tfor (const v of Object.values(value)) scanDeploymentUsage(v, acc);\n\t}\n};\n\n/** True when any raw expression in the exports references the `NETWORK_NAMES`\n * identifier (the strict `deployment.ts` tuple `config.ts` types against).\n * Drives the `./deployment.js` import injection. */\nconst referencesNetworkNames = (value: unknown): boolean => {\n\tif (isRawExpr(value)) return /\\bNETWORK_NAMES\\b/.test(value.expr);\n\tif (Array.isArray(value)) return value.some(referencesNetworkNames);\n\tif (isPlainObject(value)) return Object.values(value).some(referencesNetworkNames);\n\treturn false;\n};\n\n/** The deployment symbols an aggregate's exports use (all-false when the\n * aggregate carries no deployment expressions — pure literals). */\nconst deploymentUsageOf = (exports: { readonly [key: string]: unknown }): DeploymentUsage => {\n\tconst acc = { ...EMPTY_DEPLOYMENT_USAGE };\n\tfor (const v of Object.values(exports)) scanDeploymentUsage(v, acc);\n\treturn acc;\n};\n\n/** The `./config-runtime.js` named imports the usage requires, in a stable\n * order. Only symbols actually used are imported (oxlint flags unused). */\nconst deploymentImportsFor = (u: DeploymentUsage): ReadonlyArray<string> => {\n\tconst names: Array<string> = [];\n\tif (u.usesDep || u.usesDeployment) names.push('loadDeployment');\n\tif (u.requireId) names.push('requireId');\n\tif (u.requireValue) names.push('requireValue');\n\tif (u.optionalValue) names.push('optionalValue');\n\treturn names;\n};\n\n/** The module-level preamble lines the usage requires (`loadDeployment()`\n * once, then the active-network `dep`). */\nconst deploymentPreambleFor = (u: DeploymentUsage): ReadonlyArray<string> => {\n\tconst lines: Array<string> = [];\n\tif (u.usesDep || u.usesDeployment) lines.push('const __deployment = loadDeployment();');\n\tif (u.usesDep) lines.push('const dep = __deployment.forNetwork(__deployment.defaultNetwork);');\n\treturn lines;\n};\n\n// -----------------------------------------------------------------------------\n// Service surface — registration API + emit-cycle trigger\n// -----------------------------------------------------------------------------\n\n/**\n * The codegen orchestrator's Context-bound service. The substrate's\n * supervisor calls `registerContribution(pluginKey, decl)` once per\n * `CodegenableDecl` on each plugin's `capabilities` tuple, scope-bound\n * to that plugin's acquire scope.\n *\n * Boot no longer runs codegen — the emit pipeline is the stack-free\n * `devstack codegen` verb (which calls `runEmitCycle` directly off the\n * config-derived `staticCodegen` decls). This service keeps the dispatcher\n * seam closed: every `codegenable` contribution still has a handler, so\n * plugins emit decls uniformly even though boot writes the deployment (not\n * the committed tree).\n */\nexport interface CodegenOrchestrator {\n\t/** Register a `CodegenableDecl` from a plugin. Scope-bound — when\n\t * the caller's scope (the plugin's acquire scope) closes, the\n\t * registration is reaped. */\n\treadonly registerContribution: (\n\t\tpluginKey: string,\n\t\tdecl: Codegenable,\n\t) => Effect.Effect<void, never, Scope.Scope>;\n\n\t/** Assemble the deployment ENVELOPE from the currently-registered\n\t * (live-resolved) contributions. Boot calls this in its post-acquire hook\n\t * to WRITE the deployment file (the same `networks` / `packages` /\n\t * `mvrOverrides` data that fed `config.ts`, but as loadable JSON the Vite\n\t * plugin injects). A single-network dev stack yields a one-entry envelope\n\t * `{ defaultNetwork: <net>, networks: { <net>: <NetworkDeployment, local:true> } }`\n\t * — the live LOCAL network the Vite plugin overlays in dev. `network` is the\n\t * active network name (`ctx.identity.network`). Pure projection over the\n\t * registered decls — no I/O, no chain. */\n\treadonly assembleDeployment: (\n\t\tnetwork: string,\n\t) => Effect.Effect<DevstackDeployment, CodegenEmitFailed>;\n\n\t/** Emit the COMMITTED `src/generated` tree (config.ts + Move bindings +\n\t * coins/deepbook/… ) from the caller-supplied STATIC contributions — the\n\t * SAME id-free decls the stack-free `codegen` verb derives via each\n\t * member's `staticCodegen()` hook, NOT the live registered ones. This is\n\t * load-bearing: the live decls bake the resolved on-chain ids into\n\t * `config.ts`, but the committed tree MUST stay id-free (ids resolve at\n\t * app build time via `__DEVSTACK_DEPLOYMENT__`) — baking a live id breaks a fresh\n\t * clone and any OTHER stack reading the tree. Runs the canonical\n\t * {@link runEmitCycle} (per-process lock + content-addressed\n\t * stage-and-swap), so config.ts re-emits to its unchanged id-free form\n\t * (no-touch) while an edited package's Move bindings refresh. Dev-`up`\n\t * only: the post-acquire hook calls this when a Move-source edit\n\t * (re)acquires the package. `apply` / `runStack` never call it (the\n\t * committed tree is the build's input there, not its output). */\n\treadonly emitBindings: (\n\t\tcontributions: ReadonlyArray<CodegenableDecl>,\n\t) => Effect.Effect<\n\t\tRunEmitCycleResult,\n\t\tCodegenError,\n\t\tFileSystem.FileSystem | CodegenPathsService | MoveSummaryRunnerService | MoveCodegenService\n\t>;\n}\n\nexport class CodegenOrchestratorService extends Context.Service<\n\tCodegenOrchestratorService,\n\tCodegenOrchestrator\n>()('@devstack/orchestrators/Codegen') {}\n\n/**\n * Slice the deep-merged `config.ts` aggregate bucket into a single\n * loadable `NetworkDeployment` (the LIVE LOCAL network unit). The bucket is\n * the live codegen accumulation (sui `networks`, per-package `packages`/\n * `objects`/`mvrOverrides`); this picks the id-bearing\n * fields the Vite plugin injects and FLATTENS the chosen network's\n * connection coordinates (rpc/chainId/faucet/graphql) inline. Reads are\n * defensive — any missing slice collapses to an empty record so a partial\n * stack still writes a valid (if sparse) network deployment. Single-network\n * only here: `assembleDeployment` keys the envelope under this unit's network.\n * Per-network package ids for live networks come from the committed\n * `deployments/<net>.ts` files merged into the envelope at app build/dev time.\n */\nconst deploymentFromBucket = (\n\tbucket: Record<string, unknown>,\n\tnetwork: string,\n\tvalues: DeploymentValues,\n): NetworkDeployment => {\n\tconst asRecord = (v: unknown): Record<string, unknown> => (isPlainObject(v) ? v : {});\n\tconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n\n\t// The bucket's `networks` map is keyed by what the sui binding emitted\n\t// (`\"localnet\"` for every local mode); each entry carries the connection\n\t// coordinates. We flatten ONE entry's coordinates into the per-network\n\t// unit. Collect them first so we can pick the active network.\n\tinterface Conn {\n\t\treadonly rpc: string;\n\t\treadonly chainId?: string;\n\t\treadonly faucet?: string | null;\n\t\treadonly graphql?: string | null;\n\t}\n\tconst conns: Record<string, Conn> = {};\n\tfor (const [name, raw] of Object.entries(asRecord(bucket['networks']))) {\n\t\tconst entry = asRecord(raw);\n\t\tconst rpc = asString(entry['rpc']);\n\t\tif (rpc === undefined) continue;\n\t\tconns[name] = {\n\t\t\trpc,\n\t\t\t...(asString(entry['chainId']) !== undefined ? { chainId: asString(entry['chainId']) } : {}),\n\t\t\t...(entry['faucet'] !== undefined ? { faucet: asString(entry['faucet']) ?? null } : {}),\n\t\t\t...(entry['graphql'] !== undefined ? { graphql: asString(entry['graphql']) ?? null } : {}),\n\t\t};\n\t}\n\n\tconst packages: Record<string, DeploymentPackage> = {};\n\tfor (const [name, raw] of Object.entries(asRecord(bucket['packages']))) {\n\t\tconst entry = asRecord(raw);\n\t\t// The local network's id is `packageId` (the convenience field the\n\t\t// package projection sets). An empty/missing packageId maps to the\n\t\t// UNRESOLVED_ID sentinel — an empty string would slip past\n\t\t// `isUnresolvedId` and ship as a real, resolved id.\n\t\tconst rawId = asString(entry['packageId']);\n\t\tconst id = rawId === undefined || rawId === '' ? UNRESOLVED_ID : rawId;\n\t\tconst objectsRaw = asRecord(entry['objects']);\n\t\tconst objects: Record<string, string> = {};\n\t\tfor (const [k, v] of Object.entries(objectsRaw)) {\n\t\t\tconst s = asString(v);\n\t\t\tif (s !== undefined) objects[k] = s;\n\t\t}\n\t\tpackages[name] = {\n\t\t\tid,\n\t\t\t...(Object.keys(objects).length > 0 ? { objects } : {}),\n\t\t};\n\t}\n\n\t// `mvrOverrides` is the @mysten override shape `{ packages, types }`. The\n\t// live bucket carries `mvrOverrides.packages.<mvr>` (each package plugin's\n\t// resolved active-network id). `types` is OPT-IN and lives ONLY in the\n\t// COMMITTED `config.ts` (each developer-declared `mvrTypes` entry projects a\n\t// `requireId(dep, \"<mvr>\")`-resolved tag there); the live deployment slice\n\t// ships `types: {}`, since the generated `config.ts` rebuilds the full\n\t// `{ packages, types }` override at runtime over `mvrOverrides.packages`.\n\tconst mvrPackages: Record<string, string> = {};\n\tconst mvrNode = asRecord(bucket['mvrOverrides']);\n\tfor (const [mvr, v] of Object.entries(asRecord(mvrNode['packages']))) {\n\t\tconst s = asString(v);\n\t\tif (s !== undefined) mvrPackages[mvr] = s;\n\t}\n\tconst mvrOverrides = { packages: mvrPackages, types: {} as Record<string, string> };\n\n\t// The unit's `network` field MUST be a key present in the bucket's\n\t// connection map — the Vite dev-wallet injection reads\n\t// `networks[network].rpc` off the envelope. The `network` PARAM is the\n\t// identity's network name (e.g. `\"testnet-fork\"`), but the sui binding\n\t// keys the connection map by what it emitted (`\"localnet\"` for every\n\t// mode). A single-network local stack contributes exactly ONE connection,\n\t// so PREFER the network the binding stamped into the bucket\n\t// (`bucket['network']`, which matches the connection key); fall back to\n\t// that sole connection key, then the param. This keeps `network` in\n\t// agreement with the connection map so resolution never dereferences\n\t// `undefined`.\n\t//\n\t// Consumer note: the resulting envelope is keyed by the BINDING's connection\n\t// key (`\"localnet\"` for every local mode — fork modes included), NOT the\n\t// identity's network name. Callers resolving per-network data off the\n\t// envelope must key by this connection name and must NOT assume the identity\n\t// network name appears as a key (a `\"testnet-fork\"` identity still keys its\n\t// connection under `\"localnet\"`). This keying is intentional — do not change.\n\tconst connKeys = Object.keys(conns);\n\tconst bucketNetwork = asString(bucket['network']);\n\tconst activeNetwork =\n\t\tbucketNetwork !== undefined && connKeys.includes(bucketNetwork)\n\t\t\t? bucketNetwork\n\t\t\t: connKeys.length === 1\n\t\t\t\t? connKeys[0]!\n\t\t\t\t: (bucketNetwork ?? network);\n\n\t// Flatten the active network's connection coordinates inline. A bucket\n\t// with no connection at all (network-only / partial stack) still yields a\n\t// well-formed unit with an empty `rpc` — the resolvers throw their\n\t// actionable error rather than a raw TypeError.\n\tconst conn = conns[activeNetwork] ?? { rpc: '' };\n\n\treturn {\n\t\tnetwork: activeNetwork,\n\t\trpc: conn.rpc,\n\t\t...(conn.chainId !== undefined ? { chainId: conn.chainId } : {}),\n\t\t...(conn.faucet !== undefined ? { faucet: conn.faucet } : {}),\n\t\t...(conn.graphql !== undefined ? { graphql: conn.graphql } : {}),\n\t\t// Live LOCAL network — the deploy filter (`command === 'build'`)\n\t\t// drops it; dev overlays it as the default network.\n\t\tlocal: true,\n\t\tpackages,\n\t\tmvrOverrides,\n\t\t...(Object.keys(values).length > 0 ? { values } : {}),\n\t};\n};\n\ninterface RegisteredCodegenEntry {\n\treadonly pluginKey: string;\n\treadonly decl: Codegenable;\n\treadonly seq: number;\n}\n\n/** Layer-wired codegen orchestrator. No upstream requirements at boot\n * time — the per-cycle effect carries the `FileSystem` + Move-codegen\n * service requirements through to the caller. */\nexport const layerCodegenOrchestrator: Layer.Layer<CodegenOrchestratorService> = Layer.effect(\n\tCodegenOrchestratorService,\n\tEffect.gen(function* () {\n\t\tconst contributionsRef = yield* Ref.make<ReadonlyArray<RegisteredCodegenEntry>>([]);\n\t\tconst seqRef = yield* Ref.make(0);\n\n\t\tconst registerContribution: CodegenOrchestrator['registerContribution'] = (pluginKey, decl) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst seq = yield* Ref.updateAndGet(seqRef, (n) => n + 1);\n\t\t\t\tconst entry: RegisteredCodegenEntry = { pluginKey, decl, seq };\n\t\t\t\tyield* Ref.update(contributionsRef, (xs) => [...xs, entry]);\n\t\t\t\tyield* Effect.addFinalizer(() =>\n\t\t\t\t\tRef.update(contributionsRef, (xs) => xs.filter((e) => e.seq !== seq)),\n\t\t\t\t);\n\t\t\t}) as Effect.Effect<void, never, Scope.Scope>;\n\n\t\tconst assembleDeployment: CodegenOrchestrator['assembleDeployment'] = (network) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst registered = (yield* Ref.get(contributionsRef)).map((e) => e.decl);\n\t\t\t\t// Deep-merge every contribution's `config.ts` aggregate\n\t\t\t\t// projection into ONE bucket — the SAME accumulation the live\n\t\t\t\t// codegen cycle performed (sui's `networks.<net>` + each\n\t\t\t\t// package's `packages.<name>` / `objects` / `mvrOverrides`,\n\t\t\t\t// the account plugin's `accounts`). The merged bucket carries\n\t\t\t\t// real (live-`acquire`-resolved) ids; we then slice it into the\n\t\t\t\t// loadable `Deployment` shape.\n\t\t\t\tconst bucket: Record<string, unknown> = {};\n\t\t\t\t// `accounts.ts` is a SEPARATE aggregate bucket (the values-only\n\t\t\t\t// account decl); fold its projection into the ENVELOPE-level\n\t\t\t\t// `accounts` map. Accounts are a network-AGNOSTIC dev concept, so\n\t\t\t\t// they ride the envelope, NOT any per-network unit (the\n\t\t\t\t// per-network shape a prod author writes has no accounts at all).\n\t\t\t\tconst accounts: Record<string, unknown> = {};\n\t\t\t\t// The generic resolver channel — `values[namespace][key]` —\n\t\t\t\t// accumulated from any LIVE config-binding aggregate that\n\t\t\t\t// declared `idConfigValues` (the plugin live JSON the typed\n\t\t\t\t// fields can't carry). Deep-merged so sibling namespaces /\n\t\t\t\t// keys from distinct plugins coexist.\n\t\t\t\tconst values: Record<string, unknown> = {};\n\t\t\t\tfor (const decl of registered) {\n\t\t\t\t\tif (decl.aggregate === undefined) continue;\n\t\t\t\t\t// The generic `values` channel is BUCKET-BLIND: any LIVE\n\t\t\t\t\t// config-binding aggregate (config.ts, coins.ts, deepbook.ts,\n\t\t\t\t\t// walrus.ts, seal.ts, ...) may declare `idConfigValues`. Fold\n\t\t\t\t\t// every contributor's so the committed-tree `resolveValue` calls\n\t\t\t\t\t// those buckets emit resolve at app build/dev time -- not just the\n\t\t\t\t\t// `config.ts` plugins'. Slicing the TYPED deployment fields\n\t\t\t\t\t// (`networks` / `packages` / `mvrOverrides`) stays scoped to the\n\t\t\t\t\t// `config.ts` bucket below.\n\t\t\t\t\tif (decl.aggregate.idConfigValues !== undefined) {\n\t\t\t\t\t\tdeepMerge(values, decl.aggregate.idConfigValues);\n\t\t\t\t\t}\n\t\t\t\t\tif (decl.aggregate.bucket === CONFIG_BUCKET) {\n\t\t\t\t\t\tconst emission = yield* runEmitter(decl);\n\t\t\t\t\t\tconst projected = decl.aggregate.project(emission.exports);\n\t\t\t\t\t\tif (projected !== null) deepMerge(bucket, projected);\n\t\t\t\t\t} else if (decl.aggregate.bucket === ACCOUNTS_BUCKET) {\n\t\t\t\t\t\tconst emission = yield* runEmitter(decl);\n\t\t\t\t\t\tconst projected = decl.aggregate.project(emission.exports);\n\t\t\t\t\t\tif (projected !== null) deepMerge(accounts, projected);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Normalize the account-bucket projection (`{ <name>:\n\t\t\t\t// { address } }`, tolerating a bare string) into the\n\t\t\t\t// envelope-level name → address map.\n\t\t\t\tconst envelopeAccounts: Record<string, string> = {};\n\t\t\t\tfor (const [name, v] of Object.entries(accounts)) {\n\t\t\t\t\tconst address =\n\t\t\t\t\t\ttypeof v === 'string'\n\t\t\t\t\t\t\t? v\n\t\t\t\t\t\t\t: isPlainObject(v) && typeof v['address'] === 'string'\n\t\t\t\t\t\t\t\t? v['address']\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\tif (address !== undefined) envelopeAccounts[name] = address;\n\t\t\t\t}\n\t\t\t\t// The single-network slice — the live LOCAL network unit.\n\t\t\t\tconst unit = deploymentFromBucket(bucket, network, values as DeploymentValues);\n\t\t\t\t// Wrap it in the multi-network envelope keyed by the unit's own\n\t\t\t\t// (bucket-derived) network, so the on-disk shape is uniform with a\n\t\t\t\t// multi-network deployment. A single-network dev stack ⇒ one entry.\n\t\t\t\t// `accounts` ride the ENVELOPE (network-agnostic dev identities).\n\t\t\t\tconst unitNetwork = unit.network ?? network;\n\t\t\t\treturn {\n\t\t\t\t\tdefaultNetwork: unitNetwork,\n\t\t\t\t\tnetworks: { [unitNetwork]: unit },\n\t\t\t\t\taccounts: envelopeAccounts,\n\t\t\t\t} satisfies DevstackDeployment;\n\t\t\t});\n\n\t\tconst emitBindings: CodegenOrchestrator['emitBindings'] = (contributions) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Emit from the caller's STATIC (id-free) contributions, NOT the\n\t\t\t\t// live registered ones — the latter bake real on-chain ids into\n\t\t\t\t// `config.ts`, breaking the committed tree's id-free invariant.\n\t\t\t\t// `runEmitCycle` owns the lock + content-addressed stage-and-swap,\n\t\t\t\t// so config.ts re-emits to its unchanged id-free form (no-touch)\n\t\t\t\t// while an edited package's Move bindings refresh (HMR stays quiet).\n\t\t\t\tif (contributions.length === 0) {\n\t\t\t\t\treturn { filesWritten: [], filesUnchanged: [], filesChmod: [], bindings: null };\n\t\t\t\t}\n\t\t\t\treturn yield* runEmitCycle({ contributions, trackTree: true });\n\t\t\t});\n\n\t\treturn CodegenOrchestratorService.of({\n\t\t\tregisterContribution,\n\t\t\tassembleDeployment,\n\t\t\temitBindings,\n\t\t});\n\t}),\n);\n"],"mappings":"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"}
@@ -19,7 +19,6 @@ import { Layer } from "effect";
19
19
  * a literal, minimal blast radius. */
20
20
  const buildVerbLayers = (params) => layerProductionOrchestrators({ codegen: resolveProductionCodegenOptions({
21
21
  appRoot: params.appRoot,
22
- effectiveStack: String(params.identity.stack),
23
22
  codegen: params.stack.options.codegen
24
23
  }) }).pipe(Layer.provideMerge(buildSubstrateLayers(params.identity, params.runtimeRoot)));
25
24
  /** Substrate + (default-codegen) orchestrator Layers for verbs that
@@ -1 +1 @@
1
- {"version":3,"file":"layers.mjs","names":[],"sources":["../../src/orchestrators/layers.ts"],"sourcesContent":["// Shared substrate + orchestrator Layer composition for stack boot seams.\n//\n// The seams that boot a substrate (CLI `up`, `apply --direct`, snapshot\n// capture --direct; and `api/run-stack.ts`) all build the same composition:\n// - `layerProductionOrchestrators({ codegen })` on top of\n// - `buildSubstrateLayers(identity, runtimeRoot)`.\n//\n// One helper each seam references, instead of rebuilding the composition\n// inline at every call site. Lives in `orchestrators/` so BOTH `api/` and\n// `cli/` can import it by going *down* the layering (neither can import the\n// other). This module imports only from `orchestrators/boot.ts` and\n// `substrate/` — never from `api/` or `cli/`, so there is no import cycle.\n\nimport { Layer } from 'effect';\n\nimport type { Identity } from '../substrate/identity.ts';\nimport {\n\tbuildSubstrateLayers,\n\tlayerProductionOrchestrators,\n\tresolveProductionCodegenOptions,\n} from './boot.ts';\nimport type { SupervisedStack } from '../substrate/runtime/index.ts';\n\n/** Compose substrate + orchestrator Layers for a verb that knows its\n * stack-config (i.e. has a `loaded` config and can pass codegen\n * options). Use `buildDirectSnapshotLayers` when the verb does NOT\n * load a config (e.g. restore/delete/wipe).\n *\n * Resolves the per-stack LIVE codegen output location HERE — the one\n * boot seam where the EFFECTIVE stack (`String(identity.stack)`, already\n * run through the explicit-`--stack` > `config.stackName` > inferred\n * precedence ladder by `resolvedIdentityForStack`/`identityValueFor`\n * upstream) is in scope. EVERY live run emits into\n * `.devstack/stacks/<stack>/generated/` (gitignored) so the id-bearing\n * tree never lands in committed source and two stacks never clobber; the\n * committed `src/generated` tree is owned by the stack-free `codegen`\n * verb. The resolved literal `outputDir`/`stackSubdir` flow into\n * `layerProductionOrchestrators` unchanged — `paths.ts` keeps consuming\n * a literal, minimal blast radius. */\nexport const buildVerbLayers = (params: {\n\treadonly identity: Identity;\n\treadonly stack: SupervisedStack;\n\treadonly appRoot: string;\n\treadonly runtimeRoot: string;\n}) =>\n\tlayerProductionOrchestrators({\n\t\tcodegen: resolveProductionCodegenOptions({\n\t\t\tappRoot: params.appRoot,\n\t\t\teffectiveStack: String(params.identity.stack),\n\t\t\tcodegen: params.stack.options.codegen,\n\t\t}),\n\t}).pipe(Layer.provideMerge(buildSubstrateLayers(params.identity, params.runtimeRoot)));\n\n/** Substrate + (default-codegen) orchestrator Layers for verbs that\n * don't load a config. */\nexport const buildDirectSnapshotLayers = (params: {\n\treadonly identity: Identity;\n\treadonly runtimeRoot: string;\n}) =>\n\tlayerProductionOrchestrators().pipe(\n\t\tLayer.provideMerge(buildSubstrateLayers(params.identity, params.runtimeRoot)),\n\t);\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,MAAa,mBAAmB,WAM/B,6BAA6B,EAC5B,SAAS,gCAAgC;CACxC,SAAS,OAAO;CAChB,gBAAgB,OAAO,OAAO,SAAS,KAAK;CAC5C,SAAS,OAAO,MAAM,QAAQ;AAC/B,CAAC,EACF,CAAC,CAAC,CAAC,KAAK,MAAM,aAAa,qBAAqB,OAAO,UAAU,OAAO,WAAW,CAAC,CAAC;;;AAItF,MAAa,6BAA6B,WAIzC,6BAA6B,CAAC,CAAC,KAC9B,MAAM,aAAa,qBAAqB,OAAO,UAAU,OAAO,WAAW,CAAC,CAC7E"}
1
+ {"version":3,"file":"layers.mjs","names":[],"sources":["../../src/orchestrators/layers.ts"],"sourcesContent":["// Shared substrate + orchestrator Layer composition for stack boot seams.\n//\n// The seams that boot a substrate (CLI `up`, `apply --direct`, snapshot\n// capture --direct; and `api/run-stack.ts`) all build the same composition:\n// - `layerProductionOrchestrators({ codegen })` on top of\n// - `buildSubstrateLayers(identity, runtimeRoot)`.\n//\n// One helper each seam references, instead of rebuilding the composition\n// inline at every call site. Lives in `orchestrators/` so BOTH `api/` and\n// `cli/` can import it by going *down* the layering (neither can import the\n// other). This module imports only from `orchestrators/boot.ts` and\n// `substrate/` — never from `api/` or `cli/`, so there is no import cycle.\n\nimport { Layer } from 'effect';\n\nimport type { Identity } from '../substrate/identity.ts';\nimport {\n\tbuildSubstrateLayers,\n\tlayerProductionOrchestrators,\n\tresolveProductionCodegenOptions,\n} from './boot.ts';\nimport type { SupervisedStack } from '../substrate/runtime/index.ts';\n\n/** Compose substrate + orchestrator Layers for a verb that knows its\n * stack-config (i.e. has a `loaded` config and can pass codegen\n * options). Use `buildDirectSnapshotLayers` when the verb does NOT\n * load a config (e.g. restore/delete/wipe).\n *\n * Resolves the per-stack LIVE codegen output location HERE — the one\n * boot seam where the EFFECTIVE stack (`String(identity.stack)`, already\n * run through the explicit-`--stack` > `config.stackName` > inferred\n * precedence ladder by `resolvedIdentityForStack`/`identityValueFor`\n * upstream) is in scope. EVERY live run emits into\n * `.devstack/stacks/<stack>/generated/` (gitignored) so the id-bearing\n * tree never lands in committed source and two stacks never clobber; the\n * committed `src/generated` tree is owned by the stack-free `codegen`\n * verb. The resolved literal `outputDir`/`stackSubdir` flow into\n * `layerProductionOrchestrators` unchanged — `paths.ts` keeps consuming\n * a literal, minimal blast radius. */\nexport const buildVerbLayers = (params: {\n\treadonly identity: Identity;\n\treadonly stack: SupervisedStack;\n\treadonly appRoot: string;\n\treadonly runtimeRoot: string;\n}) =>\n\tlayerProductionOrchestrators({\n\t\tcodegen: resolveProductionCodegenOptions({\n\t\t\tappRoot: params.appRoot,\n\t\t\tcodegen: params.stack.options.codegen,\n\t\t}),\n\t}).pipe(Layer.provideMerge(buildSubstrateLayers(params.identity, params.runtimeRoot)));\n\n/** Substrate + (default-codegen) orchestrator Layers for verbs that\n * don't load a config. */\nexport const buildDirectSnapshotLayers = (params: {\n\treadonly identity: Identity;\n\treadonly runtimeRoot: string;\n}) =>\n\tlayerProductionOrchestrators().pipe(\n\t\tLayer.provideMerge(buildSubstrateLayers(params.identity, params.runtimeRoot)),\n\t);\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,MAAa,mBAAmB,WAM/B,6BAA6B,EAC5B,SAAS,gCAAgC;CACxC,SAAS,OAAO;CAChB,SAAS,OAAO,MAAM,QAAQ;AAC/B,CAAC,EACF,CAAC,CAAC,CAAC,KAAK,MAAM,aAAa,qBAAqB,OAAO,UAAU,OAAO,WAAW,CAAC,CAAC;;;AAItF,MAAa,6BAA6B,WAIzC,6BAA6B,CAAC,CAAC,KAC9B,MAAM,aAAa,qBAAqB,OAAO,UAAU,OAAO,WAAW,CAAC,CAC7E"}
@@ -1,50 +1,52 @@
1
1
  //#region src/orchestrators/network-options.d.ts
2
2
  /**
3
3
  * Per-network dev-convenience toggles. All optional — an unset field
4
- * defers to the default policy (on for every network EXCEPT live
5
- * `mainnet`). A CONSISTENT mechanism: declare these once per network in
6
- * the config instead of scattering one-off flags.
4
+ * defers to the default policy: the dev wallet is on for every network
5
+ * EXCEPT live `mainnet`, while `autoApproveSigning` defaults off everywhere
6
+ * (opt in for headless tests / fast local iteration). A CONSISTENT
7
+ * mechanism: declare these once per network in the config instead of
8
+ * scattering one-off flags.
7
9
  *
8
- * - `devWallet` — per-network override is FORWARDED. Gates the
9
- * dev-wallet `generated-extras` flush at boot (`orchestrators/boot.ts`,
10
- * which resolves these options against the substrate-forwarded
11
- * `networkOptions` record), which the Vite plugin injects.
10
+ * - `devWallet` — documents per-network intent to mount the dev wallet.
11
+ * The dev-wallet connection now rides the deployment envelope's
12
+ * `values['dev-wallet']` channel unconditionally (when `wallet()` is
13
+ * mounted); the Vite plugin gates injection on a live stack's token
14
+ * file existing, and a prod `build` never injects regardless. So this
15
+ * flag carries no active boot gate today — it remains as the documented
16
+ * per-network knob.
12
17
  * - `autoApproveSigning` — per-network override is FORWARDED. Gates the
13
18
  * dev-wallet auto-approve policy the Vite plugin emits into the
14
19
  * injected dev-wallet (`build-integrations/vite/index.ts`) — on
15
20
  * `mainnet` signing is never silently auto-approved.
16
- * - `faucet` — per-network override is NOT forwarded to the sui plugin
17
- * (see the field doc below). The plugin honours only the policy
18
- * default, which already carries the load-bearing `mainnet`
19
- * hard-clamp, so a non-faucet `mainnet` never registers
20
- * `faucet:request:<chainId>`.
21
+ *
22
+ * NOTE there is deliberately NO per-network `faucet` toggle here. The
23
+ * funding-faucet strategy gate (`faucet:request:<chainId>`) lives in the
24
+ * sui plugin and follows a fixed policy: ON for every non-`mainnet`
25
+ * network, hard-clamped OFF on live `mainnet`. The name-blind substrate
26
+ * does not thread `networkOptions` into plugins (the sui plugin only
27
+ * receives the closed `IdentityContext` tuple), so a per-network `faucet`
28
+ * override could never reach the gate — exposing the field would advertise
29
+ * a silent no-op. If a per-network faucet override is ever genuinely
30
+ * needed it must first be threaded into plugin scope (grow `Identity` or
31
+ * stamp it onto the resolved mode opts in the orchestrator that builds
32
+ * them), THEN re-added here.
21
33
  */
22
34
  interface NetworkScopedOptions {
23
- /** ENFORCED. Mount the test-only dev wallet and flush its
24
- * `generated-extras` tree (`dev-wallet.ts` + `accounts.ts`) at boot so
25
- * the Vite plugin's `@devstack-dev` injection has files to load. Off →
26
- * no flush, and the Vite `load` hook gracefully no-ops. */
35
+ /** Documents per-network intent to mount the test-only dev wallet. The
36
+ * dev-wallet connection rides the deployment envelope's
37
+ * `values['dev-wallet']` channel (folded by `assembleDeployment` when
38
+ * `wallet()` is mounted), and the Vite plugin gates injection on a live
39
+ * stack's `0o600` token file existing — a prod `build` injects nothing
40
+ * regardless. No active boot gate consumes this today. */
27
41
  readonly devWallet?: boolean;
28
- /** Funding-faucet strategy gate (`faucet:request:<chainId>`) in the sui
29
- * plugin. The plugin follows the POLICY DEFAULT only — on for every
30
- * non-`mainnet` network, hard-clamped off on live `mainnet` (so a
31
- * non-faucet network never registers the strategy and account funding
32
- * surfaces the actionable "no faucet strategy" error instead of
33
- * faucet-funding). A per-network `faucet` OVERRIDE here is NOT currently
34
- * forwarded to the plugin (unlike `devWallet` / `autoApproveSigning`,
35
- * which boot resolves against the substrate-forwarded `networkOptions`):
36
- * the name-blind substrate does not thread `networkOptions` into plugins,
37
- * and the sui plugin only receives `IdentityContext`. The sui mode still
38
- * decides HOW a faucet is provisioned (local container / fork whale /
39
- * live endpoint); the policy default decides WHETHER the resolved
40
- * strategy is exposed. */
41
- readonly faucet?: boolean;
42
42
  /** ENFORCED. Default the injected dev-wallet's auto-approve policy for
43
- * this network (`build-integrations/vite/index.ts`). On dev-wallet
44
- * signing requests auto-approve (headless Playwright / in-app "Open as"
45
- * ergonomics) unless an explicit `autoApprove` / `DEVSTACK_AUTO_APPROVE`
46
- * overrides. Hard-clamped off on live `mainnet`, so a real-funds
47
- * signature is never granted without a human in the loop. */
43
+ * this network (`build-integrations/vite/index.ts`). Defaults OFF on every
44
+ * network so a normal `pnpm dev` exercises the real connect + approve UX;
45
+ * set `true` to auto-approve signing requests for this network (headless
46
+ * Playwright / in-app "Open as" ergonomics). An explicit `autoApprove` /
47
+ * `DEVSTACK_AUTO_APPROVE` in the Vite plugin overrides this either way.
48
+ * Hard-clamped off on live `mainnet`, so a real-funds signature is never
49
+ * granted without a human in the loop. */
48
50
  readonly autoApproveSigning?: boolean;
49
51
  }
50
52
  //#endregion
@@ -1,16 +1,21 @@
1
1
  //#region src/orchestrators/network-options.ts
2
2
  /**
3
- * The default per-network policy: dev conveniences are ON for every
4
- * network EXCEPT live `mainnet`. Fork networks (`mainnet-fork`, …) are
5
- * local dev stacks, so they stay ON — only the real `mainnet` name opts
6
- * out.
3
+ * The default per-network policy: the dev wallet is ON for every network
4
+ * EXCEPT live `mainnet`. Fork networks (`mainnet-fork`, …) are local dev
5
+ * stacks, so they stay ON — only the real `mainnet` name opts out.
6
+ *
7
+ * `autoApproveSigning` defaults OFF on every network. A real app should
8
+ * exercise the actual connect + approve UX, so `pnpm dev` shows the wallet
9
+ * prompts rather than silently signing. Headless e2e opts back in via
10
+ * `DEVSTACK_AUTO_APPROVE=1` (read in the Vite plugin ahead of this policy), and
11
+ * an author can re-enable it for a specific network with a per-network
12
+ * `autoApproveSigning: true` override. Live `mainnet` stays hard-clamped off in
13
+ * {@link resolveNetworkOptions} regardless.
7
14
  */
8
15
  const defaultNetworkOptions = (network) => {
9
- const on = network !== "mainnet";
10
16
  return {
11
- devWallet: on,
12
- faucet: on,
13
- autoApproveSigning: on
17
+ devWallet: network !== "mainnet",
18
+ autoApproveSigning: false
14
19
  };
15
20
  };
16
21
  const asBool = (v) => typeof v === "boolean" ? v : void 0;
@@ -28,12 +33,10 @@ const resolveNetworkOptions = (network, overrides) => {
28
33
  const o = raw;
29
34
  if (network === "mainnet") return {
30
35
  devWallet: false,
31
- faucet: false,
32
36
  autoApproveSigning: false
33
37
  };
34
38
  return {
35
39
  devWallet: asBool(o["devWallet"]) ?? base.devWallet,
36
- faucet: asBool(o["faucet"]) ?? base.faucet,
37
40
  autoApproveSigning: asBool(o["autoApproveSigning"]) ?? base.autoApproveSigning
38
41
  };
39
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"network-options.mjs","names":[],"sources":["../../src/orchestrators/network-options.ts"],"sourcesContent":["// Per-network options: the plugin-aware interpretation of the opaque\n// `DevstackOptions.networkOptions` the name-blind substrate forwards\n// verbatim. This module lives OUTSIDE substrate precisely because it\n// names dev conveniences (dev wallet, faucet, signing) — substrate stays\n// name-blind; the orchestrator reads the policy.\n\n/**\n * Per-network dev-convenience toggles. All optional — an unset field\n * defers to the default policy (on for every network EXCEPT live\n * `mainnet`). A CONSISTENT mechanism: declare these once per network in\n * the config instead of scattering one-off flags.\n *\n * - `devWallet` — per-network override is FORWARDED. Gates the\n * dev-wallet `generated-extras` flush at boot (`orchestrators/boot.ts`,\n * which resolves these options against the substrate-forwarded\n * `networkOptions` record), which the Vite plugin injects.\n * - `autoApproveSigning` — per-network override is FORWARDED. Gates the\n * dev-wallet auto-approve policy the Vite plugin emits into the\n * injected dev-wallet (`build-integrations/vite/index.ts`) — on\n * `mainnet` signing is never silently auto-approved.\n * - `faucet`per-network override is NOT forwarded to the sui plugin\n * (see the field doc below). The plugin honours only the policy\n * default, which already carries the load-bearing `mainnet`\n * hard-clamp, so a non-faucet `mainnet` never registers\n * `faucet:request:<chainId>`.\n */\nexport interface NetworkScopedOptions {\n\t/** ENFORCED. Mount the test-only dev wallet and flush its\n\t * `generated-extras` tree (`dev-wallet.ts` + `accounts.ts`) at boot so\n\t * the Vite plugin's `@devstack-dev` injection has files to load. Off →\n\t * no flush, and the Vite `load` hook gracefully no-ops. */\n\treadonly devWallet?: boolean;\n\t/** Funding-faucet strategy gate (`faucet:request:<chainId>`) in the sui\n\t * plugin. The plugin follows the POLICY DEFAULT only on for every\n\t * non-`mainnet` network, hard-clamped off on live `mainnet` (so a\n\t * non-faucet network never registers the strategy and account funding\n\t * surfaces the actionable \"no faucet strategy\" error instead of\n\t * faucet-funding). A per-network `faucet` OVERRIDE here is NOT currently\n\t * forwarded to the plugin (unlike `devWallet` / `autoApproveSigning`,\n\t * which boot resolves against the substrate-forwarded `networkOptions`):\n\t * the name-blind substrate does not thread `networkOptions` into plugins,\n\t * and the sui plugin only receives `IdentityContext`. The sui mode still\n\t * decides HOW a faucet is provisioned (local container / fork whale /\n\t * live endpoint); the policy default decides WHETHER the resolved\n\t * strategy is exposed. */\n\treadonly faucet?: boolean;\n\t/** ENFORCED. Default the injected dev-wallet's auto-approve policy for\n\t * this network (`build-integrations/vite/index.ts`). On dev-wallet\n\t * signing requests auto-approve (headless Playwright / in-app \"Open as\"\n\t * ergonomics) unless an explicit `autoApprove` / `DEVSTACK_AUTO_APPROVE`\n\t * overrides. Hard-clamped off on live `mainnet`, so a real-funds\n\t * signature is never granted without a human in the loop. */\n\treadonly autoApproveSigning?: boolean;\n}\n\n/** Every field resolved to a concrete boolean (no `undefined`). */\nexport type ResolvedNetworkOptions = Required<NetworkScopedOptions>;\n\n/**\n * The default per-network policy: dev conveniences are ON for every\n * network EXCEPT live `mainnet`. Fork networks (`mainnet-fork`, …) are\n * local dev stacks, so they stay ON — only the real `mainnet` name opts\n * out.\n */\nexport const defaultNetworkOptions = (network: string): ResolvedNetworkOptions => {\n\tconst on = network !== 'mainnet';\n\treturn { devWallet: on, faucet: on, autoApproveSigning: on };\n};\n\nconst asBool = (v: unknown): boolean | undefined => (typeof v === 'boolean' ? v : undefined);\n\n/**\n * Resolve the effective options for the active network: the default\n * policy ({@link defaultNetworkOptions}) with the author's per-network\n * overrides merged on top, field by field (an unset/non-boolean override\n * field keeps the policy default). `overrides` is the opaque\n * substrate-forwarded record — fields are read defensively.\n */\nexport const resolveNetworkOptions = (\n\tnetwork: string,\n\toverrides?: Readonly<Record<string, unknown>>,\n): ResolvedNetworkOptions => {\n\tconst base = defaultNetworkOptions(network);\n\tconst raw = overrides?.[network];\n\tif (raw === null || typeof raw !== 'object') return base;\n\tconst o = raw as Record<string, unknown>;\n\t// HARD-CLAMP: every dev convenience is forced OFF on real `mainnet`,\n\t// regardless of an explicit `{ mainnet: { … : true } }` override. The\n\t// default policy is already off for `mainnet`; the clamp ALSO blocks a\n\t// silent explicit opt-in. Each clamp guards a distinct production-safety\n\t// failure mode:\n\t// - `devWallet` — flushing the secret `generated-extras` tree and\n\t// injecting a test-only signer into a production build.\n\t// - `faucet` — exposing a funding-faucet strategy against a real\n\t// network (there is no mainnet faucet to begin with).\n\t// - `autoApproveSigning` auto-approving a real-funds signature with\n\t// no human in the loop.\n\tif (network === 'mainnet') {\n\t\treturn { devWallet: false, faucet: false, autoApproveSigning: false };\n\t}\n\treturn {\n\t\tdevWallet: asBool(o['devWallet']) ?? base.devWallet,\n\t\tfaucet: asBool(o['faucet']) ?? base.faucet,\n\t\tautoApproveSigning: asBool(o['autoApproveSigning']) ?? base.autoApproveSigning,\n\t};\n};\n"],"mappings":";;;;;;;AAgEA,MAAa,yBAAyB,YAA4C;CACjF,MAAM,KAAK,YAAY;CACvB,OAAO;EAAE,WAAW;EAAI,QAAQ;EAAI,oBAAoB;CAAG;AAC5D;AAEA,MAAM,UAAU,MAAqC,OAAO,MAAM,YAAY,IAAI,KAAA;;;;;;;;AASlF,MAAa,yBACZ,SACA,cAC4B;CAC5B,MAAM,OAAO,sBAAsB,OAAO;CAC1C,MAAM,MAAM,YAAY;CACxB,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO;CACpD,MAAM,IAAI;CAYV,IAAI,YAAY,WACf,OAAO;EAAE,WAAW;EAAO,QAAQ;EAAO,oBAAoB;CAAM;CAErE,OAAO;EACN,WAAW,OAAO,EAAE,YAAY,KAAK,KAAK;EAC1C,QAAQ,OAAO,EAAE,SAAS,KAAK,KAAK;EACpC,oBAAoB,OAAO,EAAE,qBAAqB,KAAK,KAAK;CAC7D;AACD"}
1
+ {"version":3,"file":"network-options.mjs","names":[],"sources":["../../src/orchestrators/network-options.ts"],"sourcesContent":["// Per-network options: the plugin-aware interpretation of the opaque\n// `DevstackOptions.networkOptions` the name-blind substrate forwards\n// verbatim. This module lives OUTSIDE substrate precisely because it\n// names dev conveniences (dev wallet, signing) — substrate stays\n// name-blind; the orchestrator reads the policy.\n\n/**\n * Per-network dev-convenience toggles. All optional — an unset field\n * defers to the default policy: the dev wallet is on for every network\n * EXCEPT live `mainnet`, while `autoApproveSigning` defaults off everywhere\n * (opt in for headless tests / fast local iteration). A CONSISTENT\n * mechanism: declare these once per network in the config instead of\n * scattering one-off flags.\n *\n * - `devWallet` — documents per-network intent to mount the dev wallet.\n * The dev-wallet connection now rides the deployment envelope's\n * `values['dev-wallet']` channel unconditionally (when `wallet()` is\n * mounted); the Vite plugin gates injection on a live stack's token\n * file existing, and a prod `build` never injects regardless. So this\n * flag carries no active boot gate today — it remains as the documented\n * per-network knob.\n * - `autoApproveSigning` — per-network override is FORWARDED. Gates the\n * dev-wallet auto-approve policy the Vite plugin emits into the\n * injected dev-wallet (`build-integrations/vite/index.ts`) — on\n * `mainnet` signing is never silently auto-approved.\n *\n * NOTEthere is deliberately NO per-network `faucet` toggle here. The\n * funding-faucet strategy gate (`faucet:request:<chainId>`) lives in the\n * sui plugin and follows a fixed policy: ON for every non-`mainnet`\n * network, hard-clamped OFF on live `mainnet`. The name-blind substrate\n * does not thread `networkOptions` into plugins (the sui plugin only\n * receives the closed `IdentityContext` tuple), so a per-network `faucet`\n * override could never reach the gate exposing the field would advertise\n * a silent no-op. If a per-network faucet override is ever genuinely\n * needed it must first be threaded into plugin scope (grow `Identity` or\n * stamp it onto the resolved mode opts in the orchestrator that builds\n * them), THEN re-added here.\n */\nexport interface NetworkScopedOptions {\n\t/** Documents per-network intent to mount the test-only dev wallet. The\n\t * dev-wallet connection rides the deployment envelope's\n\t * `values['dev-wallet']` channel (folded by `assembleDeployment` when\n\t * `wallet()` is mounted), and the Vite plugin gates injection on a live\n\t * stack's `0o600` token file existing a prod `build` injects nothing\n\t * regardless. No active boot gate consumes this today. */\n\treadonly devWallet?: boolean;\n\t/** ENFORCED. Default the injected dev-wallet's auto-approve policy for\n\t * this network (`build-integrations/vite/index.ts`). Defaults OFF on every\n\t * network so a normal `pnpm dev` exercises the real connect + approve UX;\n\t * set `true` to auto-approve signing requests for this network (headless\n\t * Playwright / in-app \"Open as\" ergonomics). An explicit `autoApprove` /\n\t * `DEVSTACK_AUTO_APPROVE` in the Vite plugin overrides this either way.\n\t * Hard-clamped off on live `mainnet`, so a real-funds signature is never\n\t * granted without a human in the loop. */\n\treadonly autoApproveSigning?: boolean;\n}\n\n/** Every field resolved to a concrete boolean (no `undefined`). */\nexport type ResolvedNetworkOptions = Required<NetworkScopedOptions>;\n\n/**\n * The default per-network policy: the dev wallet is ON for every network\n * EXCEPT live `mainnet`. Fork networks (`mainnet-fork`, …) are local dev\n * stacks, so they stay ON — only the real `mainnet` name opts out.\n *\n * `autoApproveSigning` defaults OFF on every network. A real app should\n * exercise the actual connect + approve UX, so `pnpm dev` shows the wallet\n * prompts rather than silently signing. Headless e2e opts back in via\n * `DEVSTACK_AUTO_APPROVE=1` (read in the Vite plugin ahead of this policy), and\n * an author can re-enable it for a specific network with a per-network\n * `autoApproveSigning: true` override. Live `mainnet` stays hard-clamped off in\n * {@link resolveNetworkOptions} regardless.\n */\nexport const defaultNetworkOptions = (network: string): ResolvedNetworkOptions => {\n\tconst on = network !== 'mainnet';\n\treturn { devWallet: on, autoApproveSigning: false };\n};\n\nconst asBool = (v: unknown): boolean | undefined => (typeof v === 'boolean' ? v : undefined);\n\n/**\n * Resolve the effective options for the active network: the default\n * policy ({@link defaultNetworkOptions}) with the author's per-network\n * overrides merged on top, field by field (an unset/non-boolean override\n * field keeps the policy default). `overrides` is the opaque\n * substrate-forwarded record — fields are read defensively.\n */\nexport const resolveNetworkOptions = (\n\tnetwork: string,\n\toverrides?: Readonly<Record<string, unknown>>,\n): ResolvedNetworkOptions => {\n\tconst base = defaultNetworkOptions(network);\n\tconst raw = overrides?.[network];\n\tif (raw === null || typeof raw !== 'object') return base;\n\tconst o = raw as Record<string, unknown>;\n\t// HARD-CLAMP: every dev convenience is forced OFF on real `mainnet`,\n\t// regardless of an explicit `{ mainnet: { … : true } }` override. The\n\t// default policy is already off for `mainnet`; the clamp ALSO blocks a\n\t// silent explicit opt-in. Each clamp guards a distinct production-safety\n\t// failure mode:\n\t// - `devWallet` — documenting intent to inject a test-only signer\n\t// against a real network.\n\t// - `autoApproveSigning` — auto-approving a real-funds signature with\n\t// no human in the loop.\n\t// (The funding-faucet gate is NOT routed through here it is a fixed\n\t// `network !== 'mainnet'` policy in the sui plugin, with no per-network\n\t// override surface; see the {@link NetworkScopedOptions} note.)\n\tif (network === 'mainnet') {\n\t\treturn { devWallet: false, autoApproveSigning: false };\n\t}\n\treturn {\n\t\tdevWallet: asBool(o['devWallet']) ?? base.devWallet,\n\t\tautoApproveSigning: asBool(o['autoApproveSigning']) ?? base.autoApproveSigning,\n\t};\n};\n"],"mappings":";;;;;;;;;;;;;;AAyEA,MAAa,yBAAyB,YAA4C;CAEjF,OAAO;EAAE,WADE,YAAY;EACC,oBAAoB;CAAM;AACnD;AAEA,MAAM,UAAU,MAAqC,OAAO,MAAM,YAAY,IAAI,KAAA;;;;;;;;AASlF,MAAa,yBACZ,SACA,cAC4B;CAC5B,MAAM,OAAO,sBAAsB,OAAO;CAC1C,MAAM,MAAM,YAAY;CACxB,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO;CACpD,MAAM,IAAI;CAaV,IAAI,YAAY,WACf,OAAO;EAAE,WAAW;EAAO,oBAAoB;CAAM;CAEtD,OAAO;EACN,WAAW,OAAO,EAAE,YAAY,KAAK,KAAK;EAC1C,oBAAoB,OAAO,EAAE,qBAAqB,KAAK,KAAK;CAC7D;AACD"}
@@ -1,11 +1,10 @@
1
1
  //#region src/plugins/account/codegen.d.ts
2
- /** The typed shape the emitted file exports. Per-account record keyed
3
- * by name. */
2
+ /** The typed shape the account decl projects. Per-account record keyed
3
+ * by name → address. (No `scheme`/`source` — those had no consumer and
4
+ * the address is the only field the envelope-level `accounts` map carries.) */
4
5
  interface AccountBindings {
5
6
  readonly name: string;
6
7
  readonly address: string;
7
- readonly scheme: 'ed25519' | 'secp256k1' | 'secp256r1';
8
- readonly source: 'real' | 'impersonate';
9
8
  }
10
9
  //#endregion
11
10
  export { AccountBindings };