@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":"format.mjs","names":[],"sources":["../../../src/orchestrators/codegen/format.ts"],"sourcesContent":["// TypeScript source rendering for codegen-emitted files.\n//\n// Distilled-doc § \"Hand-rolled TS-object-literal rendering ... drifts\n// subtly between emitters; a small shared renderer would absorb the\n// variation and own the bigint policy in one place.\" This module IS\n// that shared renderer.\n//\n// Output shape (one emitted file):\n//\n// <generated-header>\n// <do-not-commit-banner if sensitive>\n// <imports?>\n// <one `export const <name> = <literal> as const;` per export>\n// <trailing newline>\n//\n// The renderer:\n// - sorts object keys (deterministic re-emit, distilled-doc\n// invariant \"Deterministic re-emit\"),\n// - quotes identifier-unsafe keys with double-quoted strings,\n// - serialises bigints as quoted decimal strings for\n// `BigInt(<string>)` consumers,\n// - refuses functions / symbols / undefined / circular refs with a\n// typed render error,\n// - emits arrays and records as readonly literal forms.\n//\n// The renderer does NOT format with prettier; it aims for\n// prettier-compatible spacing (two-space indent, trailing commas,\n// double-quoted strings, semicolons) so a prettier-on-write user\n// hook is a no-op on emitted bytes — that's load-bearing for the\n// \"no mtime touch on identical content\" idempotency invariant.\n\nimport { isRawExpr } from '../../contracts/codegenable.ts';\n\nimport { CodegenRenderError } from './errors.ts';\n\n// -----------------------------------------------------------------------------\n// Headers\n// -----------------------------------------------------------------------------\n\nconst GENERATED_HEADER = [\n\t'// THIS FILE IS AUTO-GENERATED BY @mysten/devstack.',\n\t'// Do not edit by hand — your changes will be overwritten on the next',\n\t'// `devstack up` cycle. Apps consume codegen output; codegen output never',\n\t'// imports from devstack.',\n].join('\\n');\n\nconst SENSITIVE_HEADER = [\n\t'// !!! DO NOT COMMIT THIS FILE !!!',\n\t'// This file carries sensitive material (wallet pair token, database',\n\t'// credentials, or user extras). The output directory ships a .gitignore',\n\t'// covering it; this banner is a belt-and-braces reminder.',\n].join('\\n');\n\n// -----------------------------------------------------------------------------\n// Public render entry\n// -----------------------------------------------------------------------------\n\nexport interface RenderInput {\n\treadonly emitterName: string;\n\treadonly outputPath: string;\n\treadonly sensitive: boolean;\n\t/** The declarations written by `Codegenable.emit(ctx)`. Each entry\n\t * becomes one `export const <key> = <literal> as const;`. */\n\treadonly exports: { readonly [key: string]: unknown };\n\t/** Optional import lines the emitter wants prepended (e.g. a\n\t * type import from `@mysten/dapp-kit` for the wallet config).\n\t * Each entry is a raw import statement string. */\n\treadonly imports?: ReadonlyArray<string>;\n}\n\n/** Result of a render attempt. Discriminated so callers can dispatch\n * on `ok` without resorting to `instanceof` checks (STYLE_GUIDE §2). */\nexport type RenderResult =\n\t| { readonly ok: true; readonly text: string }\n\t| { readonly ok: false; readonly error: CodegenRenderError };\n\nconst renderErr = (\n\tinput: RenderInput,\n\tdetail: string,\n): { readonly ok: false; readonly error: CodegenRenderError } => ({\n\tok: false,\n\terror: new CodegenRenderError({\n\t\temitterName: input.emitterName,\n\t\toutputPath: input.outputPath,\n\t\tdetail,\n\t}),\n});\n\n/** Render an emitted file to a TS source string. Returns a discriminated\n * `RenderResult` — `{ok: true, text}` on success, `{ok: false, error}`\n * when the value is unserialisable or imports forbidden paths. */\nexport const renderFile = (input: RenderInput): RenderResult => {\n\tconst lines: Array<string> = [];\n\tlines.push(GENERATED_HEADER);\n\tif (input.sensitive) {\n\t\tlines.push('');\n\t\tlines.push(SENSITIVE_HEADER);\n\t}\n\tlines.push('');\n\tif (input.imports && input.imports.length > 0) {\n\t\tfor (const imp of input.imports) {\n\t\t\tif (isForbiddenGeneratedImport(imp)) {\n\t\t\t\treturn renderErr(input, `generated files must not import devstack source: ${imp}`);\n\t\t\t}\n\t\t\tlines.push(imp);\n\t\t}\n\t\tlines.push('');\n\t}\n\t// Stable export order: keys lexicographically sorted.\n\tconst keys = Object.keys(input.exports).sort();\n\tfor (const key of keys) {\n\t\tconst value = input.exports[key];\n\t\tconst rendered = tryRender(value, new Set());\n\t\tif (!rendered.ok) {\n\t\t\treturn renderErr(input, `export '${key}': ${rendered.detail}`);\n\t\t}\n\t\tif (!isIdentifier(key)) {\n\t\t\treturn renderErr(input, `export key '${key}' is not a valid TS identifier`);\n\t\t}\n\t\tlines.push(`export const ${key} = ${rendered.text} as const;`);\n\t\tlines.push('');\n\t}\n\t// Single trailing newline; never two.\n\twhile (lines.length > 1 && lines[lines.length - 1] === '' && lines[lines.length - 2] === '') {\n\t\tlines.pop();\n\t}\n\treturn {\n\t\tok: true,\n\t\ttext: lines.join('\\n') + (lines[lines.length - 1] === '' ? '' : '\\n'),\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Value rendering\n// -----------------------------------------------------------------------------\n\nconst INDENT = '\\t';\n\ntype TryRenderResult =\n\t| { readonly ok: true; readonly text: string }\n\t| { readonly ok: false; readonly detail: string };\n\nconst tryOk = (text: string): TryRenderResult => ({ ok: true, text });\nconst tryErr = (detail: string): TryRenderResult => ({ ok: false, detail });\n\nconst tryRender = (value: unknown, seen: Set<object>, depth = 1): TryRenderResult => {\n\tif (value === null) return tryOk('null');\n\tif (value === undefined) return tryErr('undefined is not serialisable — emit null instead');\n\t// Raw-expression escape hatch: a `RawExpr` is emitted VERBATIM (e.g.\n\t// `resolveId(\"@local/foo\")`) instead of as a quoted literal. The single\n\t// authorized use is id resolution in the emitted `config.ts` — ids are\n\t// LOADED CONFIG DATA injected at app build time, not codegen output, so\n\t// the config calls a runtime resolver rather than embedding a literal id.\n\tif (isRawExpr(value)) return tryOk(value.expr);\n\tconst t = typeof value;\n\tif (t === 'string') return tryOk(JSON.stringify(value));\n\tif (t === 'number') {\n\t\tif (!Number.isFinite(value as number)) return tryErr('non-finite number');\n\t\treturn tryOk(String(value));\n\t}\n\tif (t === 'boolean') return tryOk(String(value));\n\tif (t === 'bigint') return tryOk(JSON.stringify(value.toString()));\n\tif (t === 'function' || t === 'symbol') return tryErr(`${t} is not serialisable`);\n\tif (Array.isArray(value)) {\n\t\tif (seen.has(value)) return tryErr('circular reference');\n\t\tseen.add(value);\n\t\tif (value.length === 0) return tryOk('[]');\n\t\tconst inner: Array<string> = [];\n\t\tfor (const item of value) {\n\t\t\tconst r = tryRender(item, seen, depth + 1);\n\t\t\tif (!r.ok) return r;\n\t\t\tinner.push(INDENT.repeat(depth) + r.text);\n\t\t}\n\t\tseen.delete(value);\n\t\treturn tryOk(`[\\n${inner.join(',\\n')},\\n${INDENT.repeat(depth - 1)}]`);\n\t}\n\tif (t === 'object') {\n\t\tconst obj = value as Record<string, unknown>;\n\t\tif (seen.has(obj)) return tryErr('circular reference');\n\t\tseen.add(obj);\n\t\tconst keys = Object.keys(obj).sort();\n\t\tif (keys.length === 0) return tryOk('{}');\n\t\tconst lines: Array<string> = [];\n\t\tfor (const k of keys) {\n\t\t\tconst v = obj[k];\n\t\t\tif (v === undefined) continue; // drop undefined props (distilled-doc skip-emit-explicit)\n\t\t\tconst r = tryRender(v, seen, depth + 1);\n\t\t\tif (!r.ok) return r;\n\t\t\tconst keyText = isIdentifier(k) ? k : JSON.stringify(k);\n\t\t\tlines.push(`${INDENT.repeat(depth)}${keyText}: ${r.text}`);\n\t\t}\n\t\tseen.delete(obj);\n\t\tif (lines.length === 0) return tryOk('{}');\n\t\treturn tryOk(`{\\n${lines.join(',\\n')},\\n${INDENT.repeat(depth - 1)}}`);\n\t}\n\treturn tryErr(`unsupported value type ${t}`);\n};\n\nconst IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst isIdentifier = (s: string): boolean => IDENT_RE.test(s);\n\nconst isForbiddenGeneratedImport = (line: string): boolean =>\n\t/\\bfrom\\s+[\"']@mysten-incubation\\/devstack(?:-rewrite)?(?:\\/|[\"'])/.test(line) ||\n\t/\\bimport\\s*\\(\\s*[\"']@mysten-incubation\\/devstack(?:-rewrite)?(?:\\/|[\"'])/.test(line) ||\n\t/\\bfrom\\s+[\"'][./][^\"']*\\/src\\//.test(line) ||\n\t/\\bimport\\s*\\(\\s*[\"'][./][^\"']*\\/src\\//.test(line);\n"],"mappings":"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"}
1
+ {"version":3,"file":"format.mjs","names":[],"sources":["../../../src/orchestrators/codegen/format.ts"],"sourcesContent":["// TypeScript source rendering for codegen-emitted files.\n//\n// Distilled-doc § \"Hand-rolled TS-object-literal rendering ... drifts\n// subtly between emitters; a small shared renderer would absorb the\n// variation and own the bigint policy in one place.\" This module IS\n// that shared renderer.\n//\n// Output shape (one emitted file):\n//\n// <generated-header>\n// <do-not-commit-banner if sensitive>\n// <imports?>\n// <one `export const <name> = <literal> as const;` per export>\n// <trailing newline>\n//\n// The renderer:\n// - sorts object keys (deterministic re-emit, distilled-doc\n// invariant \"Deterministic re-emit\"),\n// - quotes identifier-unsafe keys with double-quoted strings,\n// - serialises bigints as quoted decimal strings for\n// `BigInt(<string>)` consumers,\n// - refuses functions / symbols / undefined / circular refs with a\n// typed render error,\n// - emits arrays and records as readonly literal forms.\n//\n// The renderer does NOT format with prettier; it aims for\n// prettier-compatible spacing (two-space indent, trailing commas,\n// double-quoted strings, semicolons) so a prettier-on-write user\n// hook is a no-op on emitted bytes — that's load-bearing for the\n// \"no mtime touch on identical content\" idempotency invariant.\n\nimport { isForNetworkBucket, isRawExpr } from '../../contracts/codegenable.ts';\n\nimport { CodegenRenderError } from './errors.ts';\n\n// -----------------------------------------------------------------------------\n// Headers\n// -----------------------------------------------------------------------------\n\nconst GENERATED_HEADER = [\n\t'// THIS FILE IS AUTO-GENERATED BY @mysten/devstack.',\n\t'// Do not edit by hand — your changes will be overwritten on the next',\n\t'// `devstack up` cycle. Apps consume codegen output; codegen output never',\n\t'// imports from devstack.',\n].join('\\n');\n\nconst SENSITIVE_HEADER = [\n\t'// !!! DO NOT COMMIT THIS FILE !!!',\n\t'// This file carries sensitive material (wallet pair token, database',\n\t'// credentials, or user extras). The output directory ships a .gitignore',\n\t'// covering it; this banner is a belt-and-braces reminder.',\n].join('\\n');\n\n// -----------------------------------------------------------------------------\n// Public render entry\n// -----------------------------------------------------------------------------\n\nexport interface RenderInput {\n\treadonly emitterName: string;\n\treadonly outputPath: string;\n\treadonly sensitive: boolean;\n\t/** The declarations written by `Codegenable.emit(ctx)`. Each entry\n\t * becomes one `export const <key> = <literal> as const;`. */\n\treadonly exports: { readonly [key: string]: unknown };\n\t/** Optional import lines the emitter wants prepended (e.g. a\n\t * type import from `@mysten/dapp-kit` for the wallet config).\n\t * Each entry is a raw import statement string. */\n\treadonly imports?: ReadonlyArray<string>;\n\t/** Optional module-level statements emitted AFTER the imports block and\n\t * BEFORE the exports (e.g. the deployment preamble\n\t * `const __deployment = loadDeployment();` /\n\t * `const dep = __deployment.forNetwork(__deployment.defaultNetwork);` the\n\t * committed `config.ts` + service buckets share). One line per entry,\n\t * followed by a single blank line. Literal-only buckets pass no preamble. */\n\treadonly preamble?: ReadonlyArray<string>;\n}\n\n/** Result of a render attempt. Discriminated so callers can dispatch\n * on `ok` without resorting to `instanceof` checks (STYLE_GUIDE §2). */\nexport type RenderResult =\n\t| { readonly ok: true; readonly text: string }\n\t| { readonly ok: false; readonly error: CodegenRenderError };\n\nconst renderErr = (\n\tinput: RenderInput,\n\tdetail: string,\n): { readonly ok: false; readonly error: CodegenRenderError } => ({\n\tok: false,\n\terror: new CodegenRenderError({\n\t\temitterName: input.emitterName,\n\t\toutputPath: input.outputPath,\n\t\tdetail,\n\t}),\n});\n\n/** Render an emitted file to a TS source string. Returns a discriminated\n * `RenderResult` — `{ok: true, text}` on success, `{ok: false, error}`\n * when the value is unserialisable or imports forbidden paths. */\nexport const renderFile = (input: RenderInput): RenderResult => {\n\tconst lines: Array<string> = [];\n\tlines.push(GENERATED_HEADER);\n\tif (input.sensitive) {\n\t\tlines.push('');\n\t\tlines.push(SENSITIVE_HEADER);\n\t}\n\tlines.push('');\n\tif (input.imports && input.imports.length > 0) {\n\t\tfor (const imp of input.imports) {\n\t\t\tif (isForbiddenGeneratedImport(imp)) {\n\t\t\t\treturn renderErr(input, `generated files must not import devstack source: ${imp}`);\n\t\t\t}\n\t\t\tlines.push(imp);\n\t\t}\n\t\tlines.push('');\n\t}\n\tif (input.preamble && input.preamble.length > 0) {\n\t\tfor (const stmt of input.preamble) {\n\t\t\tlines.push(stmt);\n\t\t}\n\t\tlines.push('');\n\t}\n\t// Stable export order: keys lexicographically sorted.\n\tconst keys = Object.keys(input.exports).sort();\n\tfor (const key of keys) {\n\t\tconst value = input.exports[key];\n\t\tconst rendered = tryRender(value, new Set());\n\t\tif (!rendered.ok) {\n\t\t\treturn renderErr(input, `export '${key}': ${rendered.detail}`);\n\t\t}\n\t\tif (!isIdentifier(key)) {\n\t\t\treturn renderErr(input, `export key '${key}' is not a valid TS identifier`);\n\t\t}\n\t\tlines.push(`export const ${key} = ${rendered.text} as const;`);\n\t\tlines.push('');\n\t}\n\t// Single trailing newline; never two.\n\twhile (lines.length > 1 && lines[lines.length - 1] === '' && lines[lines.length - 2] === '') {\n\t\tlines.pop();\n\t}\n\treturn {\n\t\tok: true,\n\t\ttext: lines.join('\\n') + (lines[lines.length - 1] === '' ? '' : '\\n'),\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Value rendering\n// -----------------------------------------------------------------------------\n\nconst INDENT = '\\t';\n\ntype TryRenderResult =\n\t| { readonly ok: true; readonly text: string }\n\t| { readonly ok: false; readonly detail: string };\n\nconst tryOk = (text: string): TryRenderResult => ({ ok: true, text });\nconst tryErr = (detail: string): TryRenderResult => ({ ok: false, detail });\n\nconst tryRender = (value: unknown, seen: Set<object>, depth = 1): TryRenderResult => {\n\tif (value === null) return tryOk('null');\n\tif (value === undefined) return tryErr('undefined is not serialisable — emit null instead');\n\t// Raw-expression escape hatch: a `RawExpr` is emitted VERBATIM (e.g.\n\t// `resolveId(\"@local/foo\")`) instead of as a quoted literal. The single\n\t// authorized use is id resolution in the emitted `config.ts` — ids are\n\t// LOADED CONFIG DATA injected at app build time, not codegen output, so\n\t// the config calls a runtime resolver rather than embedding a literal id.\n\tif (isRawExpr(value)) return tryOk(value.expr);\n\t// Per-network service bucket: emit a `{ forNetwork(network) { … } }`\n\t// accessor whose body resolves `dep` for the requested network and returns\n\t// the inner bucket object. The inner object carries the SAME literals +\n\t// `requireValue(dep, …)` raw expressions as before; `dep` is now the\n\t// accessor's per-call local rather than a module-level default-network\n\t// constant, so a runtime `switchNetwork` flips service ids in lockstep.\n\tif (isForNetworkBucket(value)) {\n\t\t// Mirror the object-literal indentation convention: the `forNetwork`\n\t\t// method sits at `depth`, its body at `depth + 1`, the closing brace at\n\t\t// `depth - 1`. The inner bucket object renders one level deeper than the\n\t\t// `return` it follows.\n\t\tconst inner = tryRender(value.inner, seen, depth + 2);\n\t\tif (!inner.ok) return inner;\n\t\tconst method = INDENT.repeat(depth);\n\t\tconst body = INDENT.repeat(depth + 1);\n\t\tconst close = INDENT.repeat(depth - 1);\n\t\t// A pure-literal bucket (e.g. a known/live seal, builtin-only coin) does\n\t\t// not reference `dep`; prefix the param with `_` so it reads as\n\t\t// intentionally-unused and omit the `const dep = …` line.\n\t\tconst param = value.needsDep ? 'network' : '_network';\n\t\tconst lines: Array<string> = ['{'];\n\t\tlines.push(`${method}forNetwork(${param}: string) {`);\n\t\tif (value.needsDep) {\n\t\t\tlines.push(`${body}const dep = loadDeployment().forNetwork(network);`);\n\t\t}\n\t\tlines.push(`${body}return ${inner.text} as const;`);\n\t\tlines.push(`${method}},`);\n\t\tlines.push(`${close}}`);\n\t\treturn tryOk(lines.join('\\n'));\n\t}\n\tconst t = typeof value;\n\tif (t === 'string') return tryOk(JSON.stringify(value));\n\tif (t === 'number') {\n\t\tif (!Number.isFinite(value as number)) return tryErr('non-finite number');\n\t\treturn tryOk(String(value));\n\t}\n\tif (t === 'boolean') return tryOk(String(value));\n\tif (t === 'bigint') return tryOk(JSON.stringify(value.toString()));\n\tif (t === 'function' || t === 'symbol') return tryErr(`${t} is not serialisable`);\n\tif (Array.isArray(value)) {\n\t\tif (seen.has(value)) return tryErr('circular reference');\n\t\tseen.add(value);\n\t\tif (value.length === 0) return tryOk('[]');\n\t\tconst inner: Array<string> = [];\n\t\tfor (const item of value) {\n\t\t\tconst r = tryRender(item, seen, depth + 1);\n\t\t\tif (!r.ok) return r;\n\t\t\tinner.push(INDENT.repeat(depth) + r.text);\n\t\t}\n\t\tseen.delete(value);\n\t\treturn tryOk(`[\\n${inner.join(',\\n')},\\n${INDENT.repeat(depth - 1)}]`);\n\t}\n\tif (t === 'object') {\n\t\tconst obj = value as Record<string, unknown>;\n\t\tif (seen.has(obj)) return tryErr('circular reference');\n\t\tseen.add(obj);\n\t\tconst keys = Object.keys(obj).sort();\n\t\tif (keys.length === 0) return tryOk('{}');\n\t\tconst lines: Array<string> = [];\n\t\tfor (const k of keys) {\n\t\t\tconst v = obj[k];\n\t\t\tif (v === undefined) continue; // drop undefined props (distilled-doc skip-emit-explicit)\n\t\t\tconst r = tryRender(v, seen, depth + 1);\n\t\t\tif (!r.ok) return r;\n\t\t\tconst keyText = isIdentifier(k) ? k : JSON.stringify(k);\n\t\t\tlines.push(`${INDENT.repeat(depth)}${keyText}: ${r.text}`);\n\t\t}\n\t\tseen.delete(obj);\n\t\tif (lines.length === 0) return tryOk('{}');\n\t\treturn tryOk(`{\\n${lines.join(',\\n')},\\n${INDENT.repeat(depth - 1)}}`);\n\t}\n\treturn tryErr(`unsupported value type ${t}`);\n};\n\nconst IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst isIdentifier = (s: string): boolean => IDENT_RE.test(s);\n\nconst isForbiddenGeneratedImport = (line: string): boolean =>\n\t/\\bfrom\\s+[\"']@mysten-incubation\\/devstack(?:-rewrite)?(?:\\/|[\"'])/.test(line) ||\n\t/\\bimport\\s*\\(\\s*[\"']@mysten-incubation\\/devstack(?:-rewrite)?(?:\\/|[\"'])/.test(line) ||\n\t/\\bfrom\\s+[\"'][./][^\"']*\\/src\\//.test(line) ||\n\t/\\bimport\\s*\\(\\s*[\"'][./][^\"']*\\/src\\//.test(line);\n"],"mappings":"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"}
@@ -33,12 +33,7 @@ const layerCodegenPaths = Layer.effect(CodegenPathsService, Effect.gen(function*
33
33
  const root = yield* CodegenRoot;
34
34
  const path = yield* Path.Path;
35
35
  const outputDir = root.stackSubdir ? path.join(root.outputDir, root.stackSubdir) : root.outputDir;
36
- const extrasDir = root.extrasDir;
37
- const codegenLockFile = `${extrasDir}.codegen.lock`;
38
- const resolveExtras = (outputPath) => Effect.gen(function* () {
39
- yield* assertRelativeCodegenOutputPath(outputPath);
40
- return path.join(extrasDir, outputPath);
41
- });
36
+ const codegenLockFile = `${outputDir}.codegen.lock`;
42
37
  const buildAt = (atRoot) => {
43
38
  const bindingsDir = path.join(atRoot, "bindings");
44
39
  const resolve = (outputPath) => Effect.gen(function* () {
@@ -51,9 +46,7 @@ const layerCodegenPaths = Layer.effect(CodegenPathsService, Effect.gen(function*
51
46
  gitignoreFile: path.join(atRoot, ".gitignore"),
52
47
  bindingsDir,
53
48
  codegenLockFile,
54
- extrasDir,
55
49
  resolve,
56
- resolveExtras,
57
50
  resolveBindingsPackage,
58
51
  withRoot: (newRoot) => buildAt(newRoot)
59
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"paths.mjs","names":[],"sources":["../../../src/orchestrators/codegen/paths.ts"],"sourcesContent":["// Codegen output-path layout.\n//\n// Distilled-doc § \"All outputs land under a single user-chosen\n// directory (default `./src/generated/`)\" + §\"Stable output paths\".\n// One file owns the layout so emitters never assemble paths by hand.\n//\n// Default root is `<appRoot>/src/generated/`. Tests and parallel\n// stacks pin a per-test root; the substrate's `RuntimeRoot` is for\n// engine-private state (~/.devstack/...), NOT for codegen output.\n// Codegen output lives in the USER's source tree.\n\nimport { Context, Effect, Layer, Path } from 'effect';\n\nimport { CodegenPathConflict } from './errors.ts';\n\n/** Guard plugin-authored `CodegenableDecl.outputPath` against `..`\n * traversal and absolute paths. Fails with a typed\n * `CodegenPathConflict({kind:'non-relative'})` — defense-in-depth\n * for the file-layout invariants. Called once inside `buildAt` so\n * both the root bundle and any `withRoot`-rebased view enforce the\n * same `..`-rejecting `resolve` discipline.\n *\n * POSIX-only: devstack runs on POSIX filesystems (substrate paths\n * are POSIX-shaped throughout), so this check intentionally inspects\n * only `/`-rooted absolutes and the `..` substring. A Windows-style\n * `'foo/bar\\\\..\\\\baz'` would slip past — that's accepted because\n * devstack never executes on a Windows runtime.\n *\n * STYLE_GUIDE §2 rule 5 — orchestrator failures are typed. */\nexport const assertRelativeCodegenOutputPath = (\n\toutputPath: string,\n): Effect.Effect<void, CodegenPathConflict> =>\n\toutputPath.includes('..') || outputPath.startsWith('/')\n\t\t? Effect.fail(\n\t\t\t\tnew CodegenPathConflict({\n\t\t\t\t\tkind: 'non-relative',\n\t\t\t\t\toutputPath,\n\t\t\t\t\temitters: [],\n\t\t\t\t}),\n\t\t\t)\n\t\t: Effect.void;\n\n/**\n * Codegen output root — the directory codegen owns and overwrites.\n * Pinned at boot time from the user's `defineDevstack` options\n * (default `./src/generated/` resolved against the app's cwd).\n *\n * Held as a service so emitters can yield it without a function\n * argument; mirrors the substrate's `RuntimeRoot` pattern.\n */\nexport interface CodegenRootShape {\n\t/** Absolute path to the output directory. The orchestrator\n\t * manages it; the user never writes here. */\n\treadonly outputDir: string;\n\t/** Optional per-stack subdirectory under `outputDir`. When set,\n\t * parallel stacks emit into sibling directories under the same\n\t * output root (distilled-doc §\"per-stack subdirectory\"). */\n\treadonly stackSubdir: string | null;\n\t/** Absolute path to the dev-only + secret `generated-extras` tree\n\t * (`.devstack/stacks/<stack>/generated-extras`). Decls / aggregates\n\t * with `outputLocation: 'generated-extras'` emit here. Outside the\n\t * staging-and-swap tree of `outputDir` — extras are gitignored and\n\t * written in place (no atomic swap), so warm restarts never churn\n\t * the runtime tree's mtimes. */\n\treadonly extrasDir: string;\n}\n\nexport class CodegenRoot extends Context.Service<CodegenRoot, CodegenRootShape>()(\n\t'@devstack/orchestrator/CodegenRoot',\n) {}\n\n/** Build a `CodegenRoot` layer pinned to a literal path. */\nexport const layerCodegenRoot = (root: CodegenRootShape): Layer.Layer<CodegenRoot> =>\n\tLayer.succeed(CodegenRoot)(root);\n\n/** Closed bundle the resolver returns. Mirrors substrate `StackPaths`. */\nexport interface CodegenPaths {\n\t/** The directory the orchestrator emits into (after applying\n\t * per-stack subdirectory if configured). The watcher MUST\n\t * exclude this directory. */\n\treadonly outputDir: string;\n\t/** Path to the `.gitignore` inside `outputDir`. Written every\n\t * emit (the dir is gitignored). */\n\treadonly gitignoreFile: string;\n\t/** Subtree where Move-to-TS bindings land. */\n\treadonly bindingsDir: string;\n\t/** Per-process lock file gating `runEmitCycle`. Sibling to\n\t * `outputDir` so concurrent invocations (e.g. CLI direct-callers\n\t * racing the supervisor) serialize cleanly without blocking the\n\t * short-section substrate `stack.lock`. Codegen cycles can be\n\t * file-system heavy (multi-emitter, Move-bindings compilation);\n\t * the substrate lock is reserved for short sections per the\n\t * cross-process safety protocol. */\n\treadonly codegenLockFile: string;\n\t/** The dev-only + secret `generated-extras` tree. Decls /\n\t * aggregates with `outputLocation: 'generated-extras'` resolve\n\t * against this. Preserved verbatim across `withRoot` — the extras\n\t * tree lives OUTSIDE the staging-and-swap of `outputDir`, so the\n\t * staging rebase must still name the real extras dir. */\n\treadonly extrasDir: string;\n\t/** Helper: resolve an emitter's `outputPath` (e.g. `config.ts`)\n\t * against the output root. Fails with `CodegenPathConflict({kind:\n\t * 'non-relative'})` if the supplied path escapes the root. */\n\treadonly resolve: (outputPath: string) => Effect.Effect<string, CodegenPathConflict>;\n\t/** Helper: resolve an emitter's `outputPath` against the\n\t * `generated-extras` tree (`extrasDir`). Same `..`-rejecting\n\t * discipline as `resolve`. */\n\treadonly resolveExtras: (outputPath: string) => Effect.Effect<string, CodegenPathConflict>;\n\t/** Helper: resolve a per-package bindings subtree path. */\n\treadonly resolveBindingsPackage: (packageName: string) => string;\n\t/** Data-driven rebase: re-root the entire bundle at `newRoot`.\n\t * Preserves the layout (bindings under `<root>/bindings`, gitignore\n\t * at `<root>/.gitignore`) and the `..`-rejecting `resolve`\n\t * discipline; only the prefix changes. Used by the stage-and-swap\n\t * build to redirect the emit pipeline at the staging directory\n\t * WITHOUT string-surgery in the caller.\n\t *\n\t * Note: `codegenLockFile` is preserved verbatim — the lock is\n\t * acquired ONCE outside the staging build, so the rebased view\n\t * must still name the real lock path. */\n\treadonly withRoot: (newRoot: string) => CodegenPaths;\n}\n\nexport class CodegenPathsService extends Context.Service<CodegenPathsService, CodegenPaths>()(\n\t'@devstack/orchestrator/CodegenPaths',\n) {}\n\n/**\n * Materialize the resolver from `CodegenRoot` + Effect's `Path`\n * service. Stack subdir, if present, is appended:\n * `<outputDir>` or `<outputDir>/<stackSubdir>`.\n */\nexport const layerCodegenPaths: Layer.Layer<CodegenPathsService, never, CodegenRoot | Path.Path> =\n\tLayer.effect(\n\t\tCodegenPathsService,\n\t\tEffect.gen(function* () {\n\t\t\tconst root = yield* CodegenRoot;\n\t\t\tconst path = yield* Path.Path;\n\t\t\tconst outputDir = root.stackSubdir\n\t\t\t\t? path.join(root.outputDir, root.stackSubdir)\n\t\t\t\t: root.outputDir;\n\t\t\t// Captured once at boot. Preserved verbatim through `withRoot`\n\t\t\t// (the extras tree is OUTSIDE the staging swap of `outputDir`,\n\t\t\t// so the rebased view must keep naming the real extras dir).\n\t\t\tconst extrasDir = root.extrasDir;\n\t\t\t// Lock the codegen subsystem on a sibling of `extrasDir`, NOT of\n\t\t\t// `outputDir`. At BOOT nothing is ever emitted into the live\n\t\t\t// `outputDir` (`generated`) tree — boot's only codegen write is\n\t\t\t// `emitExtras`, which lands in `extrasDir` — so deriving the lock\n\t\t\t// from `extrasDir` keeps the live `generated` basename entirely\n\t\t\t// out of the boot footprint (no phantom `…/generated.codegen.lock`\n\t\t\t// next to a directory that is never created). The `codegen` verb\n\t\t\t// (the one path that DOES stage into `<outputDir>.staging.<id>`)\n\t\t\t// still gets a stable sibling lock — `<extrasDir>.codegen.lock` —\n\t\t\t// outside both its `outputDir` swap and the `extrasDir` tree.\n\t\t\t// Sibling-NOT-inside is what matters for the stage-and-swap rename\n\t\t\t// of `outputDir`, and an `extrasDir` sibling satisfies that.\n\t\t\t// Captured once at boot — `withRoot` re-roots the rest of the\n\t\t\t// bundle but preserves this lock path verbatim so the rebased\n\t\t\t// staging view names the real cross-process lock (the lock is\n\t\t\t// acquired ONCE outside the staging build).\n\t\t\tconst codegenLockFile = `${extrasDir}.codegen.lock`;\n\t\t\tconst resolveExtras = (outputPath: string): Effect.Effect<string, CodegenPathConflict> =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tyield* assertRelativeCodegenOutputPath(outputPath);\n\t\t\t\t\treturn path.join(extrasDir, outputPath);\n\t\t\t\t});\n\t\t\tconst buildAt = (atRoot: string): CodegenPaths => {\n\t\t\t\tconst bindingsDir = path.join(atRoot, 'bindings');\n\t\t\t\tconst resolve = (outputPath: string): Effect.Effect<string, CodegenPathConflict> =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* assertRelativeCodegenOutputPath(outputPath);\n\t\t\t\t\t\treturn path.join(atRoot, outputPath);\n\t\t\t\t\t});\n\t\t\t\tconst resolveBindingsPackage = (packageName: string): string =>\n\t\t\t\t\tpath.join(bindingsDir, packageName);\n\t\t\t\tconst bundle: CodegenPaths = {\n\t\t\t\t\toutputDir: atRoot,\n\t\t\t\t\tgitignoreFile: path.join(atRoot, '.gitignore'),\n\t\t\t\t\tbindingsDir,\n\t\t\t\t\tcodegenLockFile,\n\t\t\t\t\textrasDir,\n\t\t\t\t\tresolve,\n\t\t\t\t\tresolveExtras,\n\t\t\t\t\tresolveBindingsPackage,\n\t\t\t\t\twithRoot: (newRoot: string) => buildAt(newRoot),\n\t\t\t\t};\n\t\t\t\treturn bundle;\n\t\t\t};\n\t\t\treturn CodegenPathsService.of(buildAt(outputDir));\n\t\t}),\n\t);\n"],"mappings":";;;;;;;;;;;;;;;;;AA6BA,MAAa,mCACZ,eAEA,WAAW,SAAS,IAAI,KAAK,WAAW,WAAW,GAAG,IACnD,OAAO,KACP,IAAI,oBAAoB;CACvB,MAAM;CACN;CACA,UAAU,CAAC;AACZ,CAAC,CACF,IACC,OAAO;AA2BX,IAAa,cAAb,cAAiC,QAAQ,QAAuC,CAAC,CAChF,oCACD,CAAC,CAAC,CAAC;;AAGH,MAAa,oBAAoB,SAChC,MAAM,QAAQ,WAAW,CAAC,CAAC,IAAI;AAkDhC,IAAa,sBAAb,cAAyC,QAAQ,QAA2C,CAAC,CAC5F,qCACD,CAAC,CAAC,CAAC;;;;;;AAOH,MAAa,oBACZ,MAAM,OACL,qBACA,OAAO,IAAI,aAAa;CACvB,MAAM,OAAO,OAAO;CACpB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,YAAY,KAAK,cACpB,KAAK,KAAK,KAAK,WAAW,KAAK,WAAW,IAC1C,KAAK;CAIR,MAAM,YAAY,KAAK;CAiBvB,MAAM,kBAAkB,GAAG,UAAU;CACrC,MAAM,iBAAiB,eACtB,OAAO,IAAI,aAAa;EACvB,OAAO,gCAAgC,UAAU;EACjD,OAAO,KAAK,KAAK,WAAW,UAAU;CACvC,CAAC;CACF,MAAM,WAAW,WAAiC;EACjD,MAAM,cAAc,KAAK,KAAK,QAAQ,UAAU;EAChD,MAAM,WAAW,eAChB,OAAO,IAAI,aAAa;GACvB,OAAO,gCAAgC,UAAU;GACjD,OAAO,KAAK,KAAK,QAAQ,UAAU;EACpC,CAAC;EACF,MAAM,0BAA0B,gBAC/B,KAAK,KAAK,aAAa,WAAW;EAYnC,OAAO;GAVN,WAAW;GACX,eAAe,KAAK,KAAK,QAAQ,YAAY;GAC7C;GACA;GACA;GACA;GACA;GACA;GACA,WAAW,YAAoB,QAAQ,OAAO;EAEnC;CACb;CACA,OAAO,oBAAoB,GAAG,QAAQ,SAAS,CAAC;AACjD,CAAC,CACF"}
1
+ {"version":3,"file":"paths.mjs","names":[],"sources":["../../../src/orchestrators/codegen/paths.ts"],"sourcesContent":["// Codegen output-path layout.\n//\n// Distilled-doc § \"All outputs land under a single user-chosen\n// directory (default `./src/generated/`)\" + §\"Stable output paths\".\n// One file owns the layout so emitters never assemble paths by hand.\n//\n// Default root is `<appRoot>/src/generated/`. Tests and parallel\n// stacks pin a per-test root; the substrate's `RuntimeRoot` is for\n// engine-private state (~/.devstack/...), NOT for codegen output.\n// Codegen output lives in the USER's source tree.\n\nimport { Context, Effect, Layer, Path } from 'effect';\n\nimport { CodegenPathConflict } from './errors.ts';\n\n/** Guard plugin-authored `CodegenableDecl.outputPath` against `..`\n * traversal and absolute paths. Fails with a typed\n * `CodegenPathConflict({kind:'non-relative'})` — defense-in-depth\n * for the file-layout invariants. Called once inside `buildAt` so\n * both the root bundle and any `withRoot`-rebased view enforce the\n * same `..`-rejecting `resolve` discipline.\n *\n * POSIX-only: devstack runs on POSIX filesystems (substrate paths\n * are POSIX-shaped throughout), so this check intentionally inspects\n * only `/`-rooted absolutes and the `..` substring. A Windows-style\n * `'foo/bar\\\\..\\\\baz'` would slip past — that's accepted because\n * devstack never executes on a Windows runtime.\n *\n * STYLE_GUIDE §2 rule 5 — orchestrator failures are typed. */\nexport const assertRelativeCodegenOutputPath = (\n\toutputPath: string,\n): Effect.Effect<void, CodegenPathConflict> =>\n\toutputPath.includes('..') || outputPath.startsWith('/')\n\t\t? Effect.fail(\n\t\t\t\tnew CodegenPathConflict({\n\t\t\t\t\tkind: 'non-relative',\n\t\t\t\t\toutputPath,\n\t\t\t\t\temitters: [],\n\t\t\t\t}),\n\t\t\t)\n\t\t: Effect.void;\n\n/**\n * Codegen output root — the directory codegen owns and overwrites.\n * Pinned at boot time from the user's `defineDevstack` options\n * (default `./src/generated/` resolved against the app's cwd).\n *\n * Held as a service so emitters can yield it without a function\n * argument; mirrors the substrate's `RuntimeRoot` pattern.\n */\nexport interface CodegenRootShape {\n\t/** Absolute path to the output directory. The orchestrator\n\t * manages it; the user never writes here. */\n\treadonly outputDir: string;\n\t/** Optional per-stack subdirectory under `outputDir`. When set,\n\t * parallel stacks emit into sibling directories under the same\n\t * output root (distilled-doc §\"per-stack subdirectory\"). */\n\treadonly stackSubdir: string | null;\n}\n\nexport class CodegenRoot extends Context.Service<CodegenRoot, CodegenRootShape>()(\n\t'@devstack/orchestrator/CodegenRoot',\n) {}\n\n/** Build a `CodegenRoot` layer pinned to a literal path. */\nexport const layerCodegenRoot = (root: CodegenRootShape): Layer.Layer<CodegenRoot> =>\n\tLayer.succeed(CodegenRoot)(root);\n\n/** Closed bundle the resolver returns. Mirrors substrate `StackPaths`. */\nexport interface CodegenPaths {\n\t/** The directory the orchestrator emits into (after applying\n\t * per-stack subdirectory if configured). The watcher MUST\n\t * exclude this directory. */\n\treadonly outputDir: string;\n\t/** Path to the `.gitignore` inside `outputDir`. Written every\n\t * emit (the dir is gitignored). */\n\treadonly gitignoreFile: string;\n\t/** Subtree where Move-to-TS bindings land. */\n\treadonly bindingsDir: string;\n\t/** Per-process lock file gating `runEmitCycle`. Sibling to\n\t * `outputDir` so concurrent invocations (e.g. CLI direct-callers\n\t * racing the supervisor) serialize cleanly without blocking the\n\t * short-section substrate `stack.lock`. Codegen cycles can be\n\t * file-system heavy (multi-emitter, Move-bindings compilation);\n\t * the substrate lock is reserved for short sections per the\n\t * cross-process safety protocol. */\n\treadonly codegenLockFile: string;\n\t/** Helper: resolve an emitter's `outputPath` (e.g. `config.ts`)\n\t * against the output root. Fails with `CodegenPathConflict({kind:\n\t * 'non-relative'})` if the supplied path escapes the root. */\n\treadonly resolve: (outputPath: string) => Effect.Effect<string, CodegenPathConflict>;\n\t/** Helper: resolve a per-package bindings subtree path. */\n\treadonly resolveBindingsPackage: (packageName: string) => string;\n\t/** Data-driven rebase: re-root the entire bundle at `newRoot`.\n\t * Preserves the layout (bindings under `<root>/bindings`, gitignore\n\t * at `<root>/.gitignore`) and the `..`-rejecting `resolve`\n\t * discipline; only the prefix changes. Used by the stage-and-swap\n\t * build to redirect the emit pipeline at the staging directory\n\t * WITHOUT string-surgery in the caller.\n\t *\n\t * Note: `codegenLockFile` is preserved verbatim — the lock is\n\t * acquired ONCE outside the staging build, so the rebased view\n\t * must still name the real lock path. */\n\treadonly withRoot: (newRoot: string) => CodegenPaths;\n}\n\nexport class CodegenPathsService extends Context.Service<CodegenPathsService, CodegenPaths>()(\n\t'@devstack/orchestrator/CodegenPaths',\n) {}\n\n/**\n * Materialize the resolver from `CodegenRoot` + Effect's `Path`\n * service. Stack subdir, if present, is appended:\n * `<outputDir>` or `<outputDir>/<stackSubdir>`.\n */\nexport const layerCodegenPaths: Layer.Layer<CodegenPathsService, never, CodegenRoot | Path.Path> =\n\tLayer.effect(\n\t\tCodegenPathsService,\n\t\tEffect.gen(function* () {\n\t\t\tconst root = yield* CodegenRoot;\n\t\t\tconst path = yield* Path.Path;\n\t\t\tconst outputDir = root.stackSubdir\n\t\t\t\t? path.join(root.outputDir, root.stackSubdir)\n\t\t\t\t: root.outputDir;\n\t\t\t// Lock the codegen subsystem on a stable SIBLING of the canonical\n\t\t\t// `outputDir` — `<outputDir>.codegen.lock`. Sibling-NOT-inside is\n\t\t\t// what matters: the `codegen` verb stages into `<outputDir>.staging.<id>`\n\t\t\t// and renames it over `outputDir`, so a lock inside either would be\n\t\t\t// swapped out mid-cycle. Captured once at boot — `withRoot` re-roots\n\t\t\t// the rest of the bundle but preserves this lock path verbatim so the\n\t\t\t// rebased staging view names the real cross-process lock (the lock is\n\t\t\t// acquired ONCE outside the staging build).\n\t\t\tconst codegenLockFile = `${outputDir}.codegen.lock`;\n\t\t\tconst buildAt = (atRoot: string): CodegenPaths => {\n\t\t\t\tconst bindingsDir = path.join(atRoot, 'bindings');\n\t\t\t\tconst resolve = (outputPath: string): Effect.Effect<string, CodegenPathConflict> =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* assertRelativeCodegenOutputPath(outputPath);\n\t\t\t\t\t\treturn path.join(atRoot, outputPath);\n\t\t\t\t\t});\n\t\t\t\tconst resolveBindingsPackage = (packageName: string): string =>\n\t\t\t\t\tpath.join(bindingsDir, packageName);\n\t\t\t\tconst bundle: CodegenPaths = {\n\t\t\t\t\toutputDir: atRoot,\n\t\t\t\t\tgitignoreFile: path.join(atRoot, '.gitignore'),\n\t\t\t\t\tbindingsDir,\n\t\t\t\t\tcodegenLockFile,\n\t\t\t\t\tresolve,\n\t\t\t\t\tresolveBindingsPackage,\n\t\t\t\t\twithRoot: (newRoot: string) => buildAt(newRoot),\n\t\t\t\t};\n\t\t\t\treturn bundle;\n\t\t\t};\n\t\t\treturn CodegenPathsService.of(buildAt(outputDir));\n\t\t}),\n\t);\n"],"mappings":";;;;;;;;;;;;;;;;;AA6BA,MAAa,mCACZ,eAEA,WAAW,SAAS,IAAI,KAAK,WAAW,WAAW,GAAG,IACnD,OAAO,KACP,IAAI,oBAAoB;CACvB,MAAM;CACN;CACA,UAAU,CAAC;AACZ,CAAC,CACF,IACC,OAAO;AAoBX,IAAa,cAAb,cAAiC,QAAQ,QAAuC,CAAC,CAChF,oCACD,CAAC,CAAC,CAAC;;AAGH,MAAa,oBAAoB,SAChC,MAAM,QAAQ,WAAW,CAAC,CAAC,IAAI;AAwChC,IAAa,sBAAb,cAAyC,QAAQ,QAA2C,CAAC,CAC5F,qCACD,CAAC,CAAC,CAAC;;;;;;AAOH,MAAa,oBACZ,MAAM,OACL,qBACA,OAAO,IAAI,aAAa;CACvB,MAAM,OAAO,OAAO;CACpB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,YAAY,KAAK,cACpB,KAAK,KAAK,KAAK,WAAW,KAAK,WAAW,IAC1C,KAAK;CASR,MAAM,kBAAkB,GAAG,UAAU;CACrC,MAAM,WAAW,WAAiC;EACjD,MAAM,cAAc,KAAK,KAAK,QAAQ,UAAU;EAChD,MAAM,WAAW,eAChB,OAAO,IAAI,aAAa;GACvB,OAAO,gCAAgC,UAAU;GACjD,OAAO,KAAK,KAAK,QAAQ,UAAU;EACpC,CAAC;EACF,MAAM,0BAA0B,gBAC/B,KAAK,KAAK,aAAa,WAAW;EAUnC,OAAO;GARN,WAAW;GACX,eAAe,KAAK,KAAK,QAAQ,YAAY;GAC7C;GACA;GACA;GACA;GACA,WAAW,YAAoB,QAAQ,OAAO;EAEnC;CACb;CACA,OAAO,oBAAoB,GAAG,QAAQ,SAAS,CAAC;AACjD,CAAC,CACF"}