@treeseed/sdk 0.10.28 → 0.11.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 (148) hide show
  1. package/README.md +207 -6
  2. package/dist/capacity-provider.d.ts +3 -1
  3. package/dist/capacity-provider.js +25 -5
  4. package/dist/control-plane.d.ts +1 -0
  5. package/dist/control-plane.js +38 -13
  6. package/dist/db/market-schema.d.ts +8860 -6172
  7. package/dist/db/market-schema.js +108 -0
  8. package/dist/db/node-sqlite.js +7 -2
  9. package/dist/hosting/apps.d.ts +12 -0
  10. package/dist/hosting/apps.js +107 -0
  11. package/dist/hosting/builtins.d.ts +25 -0
  12. package/dist/hosting/builtins.js +791 -0
  13. package/dist/hosting/contracts.d.ts +207 -0
  14. package/dist/hosting/contracts.js +0 -0
  15. package/dist/hosting/graph.d.ts +192 -0
  16. package/dist/hosting/graph.js +1106 -0
  17. package/dist/hosting/index.d.ts +4 -0
  18. package/dist/hosting/index.js +4 -0
  19. package/dist/index.d.ts +10 -3
  20. package/dist/index.js +63 -6
  21. package/dist/managed-dependencies.js +1 -2
  22. package/dist/market-client.d.ts +63 -3
  23. package/dist/market-client.js +83 -11
  24. package/dist/operations/services/bootstrap-runner.d.ts +3 -1
  25. package/dist/operations/services/bootstrap-runner.js +22 -2
  26. package/dist/operations/services/config-runtime.d.ts +10 -5
  27. package/dist/operations/services/config-runtime.js +209 -66
  28. package/dist/operations/services/deploy.d.ts +70 -7
  29. package/dist/operations/services/deploy.js +579 -64
  30. package/dist/operations/services/deployment-readiness.d.ts +30 -0
  31. package/dist/operations/services/deployment-readiness.js +175 -0
  32. package/dist/operations/services/git-workflow.d.ts +2 -1
  33. package/dist/operations/services/git-workflow.js +9 -3
  34. package/dist/operations/services/github-actions-verification.d.ts +1 -0
  35. package/dist/operations/services/github-actions-verification.js +1 -0
  36. package/dist/operations/services/github-api.js +1 -1
  37. package/dist/operations/services/github-automation.d.ts +1 -1
  38. package/dist/operations/services/github-automation.js +4 -3
  39. package/dist/operations/services/github-credentials.d.ts +13 -0
  40. package/dist/operations/services/github-credentials.js +58 -0
  41. package/dist/operations/services/hosted-service-checks.d.ts +63 -0
  42. package/dist/operations/services/hosted-service-checks.js +327 -0
  43. package/dist/operations/services/hub-provider-launch.js +3 -3
  44. package/dist/operations/services/live-hosted-service-checks.d.ts +25 -0
  45. package/dist/operations/services/live-hosted-service-checks.js +350 -0
  46. package/dist/operations/services/managed-host-security.js +1 -1
  47. package/dist/operations/services/operations-runner-smoke.d.ts +30 -0
  48. package/dist/operations/services/operations-runner-smoke.js +180 -0
  49. package/dist/operations/services/package-adapters.d.ts +95 -0
  50. package/dist/operations/services/package-adapters.js +288 -0
  51. package/dist/operations/services/package-reference-policy.d.ts +1 -0
  52. package/dist/operations/services/package-reference-policy.js +15 -2
  53. package/dist/operations/services/project-platform.d.ts +80 -22
  54. package/dist/operations/services/project-platform.js +49 -8
  55. package/dist/operations/services/project-web-monitor.js +26 -4
  56. package/dist/operations/services/railway-api.d.ts +88 -5
  57. package/dist/operations/services/railway-api.js +626 -35
  58. package/dist/operations/services/railway-deploy.d.ts +46 -40
  59. package/dist/operations/services/railway-deploy.js +261 -293
  60. package/dist/operations/services/release-candidate.d.ts +19 -0
  61. package/dist/operations/services/release-candidate.js +375 -38
  62. package/dist/operations/services/repository-save-orchestrator.d.ts +3 -1
  63. package/dist/operations/services/repository-save-orchestrator.js +279 -66
  64. package/dist/operations/services/runtime-tools.d.ts +1 -0
  65. package/dist/operations/services/runtime-tools.js +10 -9
  66. package/dist/operations/services/verification-cache.d.ts +25 -0
  67. package/dist/operations/services/verification-cache.js +71 -0
  68. package/dist/operations/services/workspace-dependency-mode.js +9 -1
  69. package/dist/operations/services/workspace-save.js +1 -1
  70. package/dist/operations/services/workspace-tools.js +2 -1
  71. package/dist/platform/contracts.d.ts +32 -1
  72. package/dist/platform/deploy-config.js +73 -8
  73. package/dist/platform/env.yaml +163 -35
  74. package/dist/platform/environment.d.ts +1 -0
  75. package/dist/platform/environment.js +74 -5
  76. package/dist/platform/plugin.d.ts +9 -0
  77. package/dist/platform-operation-store.js +2 -2
  78. package/dist/platform-operations.js +1 -1
  79. package/dist/reconcile/bootstrap-systems.js +2 -2
  80. package/dist/reconcile/builtin-adapters.js +372 -189
  81. package/dist/reconcile/contracts.d.ts +9 -5
  82. package/dist/reconcile/desired-state.d.ts +1 -0
  83. package/dist/reconcile/desired-state.js +5 -5
  84. package/dist/reconcile/engine.d.ts +5 -2
  85. package/dist/reconcile/engine.js +53 -32
  86. package/dist/reconcile/index.d.ts +2 -0
  87. package/dist/reconcile/index.js +2 -0
  88. package/dist/reconcile/live-acceptance.d.ts +79 -0
  89. package/dist/reconcile/live-acceptance.js +1615 -0
  90. package/dist/reconcile/platform.d.ts +104 -0
  91. package/dist/reconcile/platform.js +100 -0
  92. package/dist/reconcile/state.js +4 -4
  93. package/dist/reconcile/units.js +2 -2
  94. package/dist/scripts/deployment-readiness.js +20 -0
  95. package/dist/scripts/generate-treedx-openapi-types.js +186 -0
  96. package/dist/scripts/operations-runner-smoke.js +16 -0
  97. package/dist/scripts/release-verify.js +4 -1
  98. package/dist/scripts/tenant-workflow-action.js +10 -1
  99. package/dist/sdk-types.d.ts +169 -4
  100. package/dist/sdk-types.js +20 -2
  101. package/dist/sdk.d.ts +35 -24
  102. package/dist/sdk.js +186 -17
  103. package/dist/template-launch-requirements.js +9 -0
  104. package/dist/treedx/adapters.d.ts +6 -0
  105. package/dist/treedx/adapters.js +36 -0
  106. package/dist/treedx/client.d.ts +222 -0
  107. package/dist/treedx/client.js +871 -0
  108. package/dist/treedx/errors.d.ts +13 -0
  109. package/dist/treedx/errors.js +17 -0
  110. package/dist/treedx/federated-client.d.ts +27 -0
  111. package/dist/treedx/federated-client.js +158 -0
  112. package/dist/treedx/generated/openapi-types.d.ts +3558 -0
  113. package/dist/treedx/generated/openapi-types.js +0 -0
  114. package/dist/treedx/graph-adapter.d.ts +33 -0
  115. package/dist/treedx/graph-adapter.js +156 -0
  116. package/dist/treedx/index.d.ts +14 -0
  117. package/dist/treedx/index.js +48 -0
  118. package/dist/treedx/market-integration.d.ts +27 -0
  119. package/dist/treedx/market-integration.js +131 -0
  120. package/dist/treedx/ports.d.ts +166 -0
  121. package/dist/treedx/ports.js +231 -0
  122. package/dist/treedx/query-adapter.d.ts +19 -0
  123. package/dist/treedx/query-adapter.js +62 -0
  124. package/dist/treedx/registry-client.d.ts +11 -0
  125. package/dist/treedx/registry-client.js +19 -0
  126. package/dist/treedx/repository-adapter.d.ts +45 -0
  127. package/dist/treedx/repository-adapter.js +308 -0
  128. package/dist/treedx/sdk-integration.d.ts +27 -0
  129. package/dist/treedx/sdk-integration.js +63 -0
  130. package/dist/treedx/types.d.ts +1084 -0
  131. package/dist/treedx/types.js +8 -0
  132. package/dist/treedx/workspace-adapter.d.ts +27 -0
  133. package/dist/treedx/workspace-adapter.js +65 -0
  134. package/dist/treedx-backends.d.ts +218 -0
  135. package/dist/treedx-backends.js +632 -0
  136. package/dist/treedx-client.d.ts +86 -0
  137. package/dist/treedx-client.js +175 -0
  138. package/dist/treeseed/template-catalog/catalog.fixture.json +23 -23
  139. package/dist/workflow/operations.d.ts +119 -13
  140. package/dist/workflow/operations.js +309 -53
  141. package/dist/workflow-state.d.ts +13 -0
  142. package/dist/workflow-state.js +43 -26
  143. package/dist/workflow-support.d.ts +11 -3
  144. package/dist/workflow-support.js +67 -3
  145. package/dist/workflow.d.ts +5 -0
  146. package/drizzle/market/0004_treedx_market_integration.sql +99 -0
  147. package/package.json +34 -3
  148. package/templates/github/deploy-web.workflow.yml +39 -6
@@ -0,0 +1,288 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { relative, resolve } from "node:path";
4
+ import { parse as parseYaml } from "yaml";
5
+ import { workspacePackages, workspaceRoot } from "./workspace-tools.js";
6
+ function readJsonFile(filePath) {
7
+ try {
8
+ return JSON.parse(readFileSync(filePath, "utf8"));
9
+ } catch {
10
+ return null;
11
+ }
12
+ }
13
+ function readStructuredFile(filePath) {
14
+ try {
15
+ const raw = readFileSync(filePath, "utf8");
16
+ return filePath.endsWith(".yaml") || filePath.endsWith(".yml") ? parseYaml(raw) : JSON.parse(raw);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+ function readPackageJsonVersion(filePath) {
22
+ const packageJson = readJsonFile(filePath);
23
+ return typeof packageJson?.version === "string" ? packageJson.version : null;
24
+ }
25
+ function normalizeGitHubRepositorySlug(value) {
26
+ const raw = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) ? value.url : null;
27
+ if (typeof raw !== "string" || !raw.trim()) return null;
28
+ const normalized = raw.trim().replace(/^git\+/u, "").replace(/^ssh:\/\/git@github\.com[:/]/u, "").replace(/^git@github\.com:/u, "").replace(/^https:\/\/github\.com\//u, "").replace(/\.git$/u, "").replace(/\/$/u, "");
29
+ return /^[^/\s]+\/[^/\s]+$/u.test(normalized) ? normalized : null;
30
+ }
31
+ function readMixProjectVersion(filePath) {
32
+ if (!existsSync(filePath)) return null;
33
+ const source = readFileSync(filePath, "utf8");
34
+ const match = source.match(/\bversion:\s*"([^"]+)"/u);
35
+ return match?.[1] ?? null;
36
+ }
37
+ function commandFromScript(dir, script, label) {
38
+ if (typeof script !== "string" || !script.trim()) return null;
39
+ const trimmed = script.trim();
40
+ if (trimmed.startsWith("scripts/")) {
41
+ return { label, command: "bash", args: [trimmed], cwd: dir };
42
+ }
43
+ return { label, command: "bash", args: ["-lc", trimmed], cwd: dir };
44
+ }
45
+ function nodeTypeScriptAdapter(pkg) {
46
+ const manifest = readTreeseedPackageManifest(pkg.dir);
47
+ const scripts = pkg.packageJson?.scripts && typeof pkg.packageJson.scripts === "object" && !Array.isArray(pkg.packageJson.scripts) ? pkg.packageJson.scripts : {};
48
+ const manifestVerify = manifest?.verify && typeof manifest.verify === "object" && !Array.isArray(manifest.verify) ? manifest.verify : {};
49
+ const repository = stringValue(manifest?.repository) ?? normalizeGitHubRepositorySlug(pkg.packageJson?.repository);
50
+ const id = stringValue(manifest?.id) ?? String(pkg.name);
51
+ const name = stringValue(manifest?.name) ?? String(pkg.name);
52
+ const publishTarget = stringValue(manifest?.publishTarget) ?? "npm";
53
+ const hostedVerifyWorkflow = stringValue(stringRecord(manifest?.releaseGate).workflow) ?? (existsSync(resolve(pkg.dir, ".github/workflows/deploy.yml")) ? "deploy.yml" : null);
54
+ const verifyLocal = typeof scripts["verify:local"] === "string" ? "verify:local" : typeof scripts.verify === "string" ? "verify" : typeof scripts["verify:action"] === "string" ? "verify:action" : null;
55
+ return {
56
+ id,
57
+ name,
58
+ kind: "node-typescript",
59
+ dir: pkg.dir,
60
+ relativeDir: pkg.relativeDir,
61
+ version: typeof pkg.packageJson?.version === "string" ? pkg.packageJson.version : null,
62
+ publishTarget,
63
+ manifestPath: treeseedPackageManifestPath(pkg.dir) ?? resolve(pkg.dir, "package.json"),
64
+ versionSource: resolve(pkg.dir, "package.json"),
65
+ verifyCommands: {
66
+ fast: commandFromScript(pkg.dir, manifestVerify.fast, "fast") ?? (typeof scripts.verify === "string" ? { label: "verify", command: "npm", args: ["run", "verify"], cwd: pkg.dir } : null),
67
+ local: commandFromScript(pkg.dir, manifestVerify.local, "local") ?? (verifyLocal ? { label: verifyLocal, command: "npm", args: ["run", verifyLocal], cwd: pkg.dir } : null),
68
+ release: commandFromScript(pkg.dir, manifestVerify.release, "release") ?? (typeof scripts["release:publish"] === "string" ? { label: "release:publish", command: "npm", args: ["run", "release:publish"], cwd: pkg.dir } : null)
69
+ },
70
+ artifacts: [{ provider: "npm", name: String(pkg.name) }],
71
+ releaseChecks: [
72
+ { kind: "github-workflow", name: "publish workflow", detail: ".github/workflows/publish.yml" },
73
+ { kind: "npm-pack-dry-run", name: "npm pack", detail: "npm pack --dry-run" }
74
+ ],
75
+ metadata: {
76
+ ...repository ? { repository } : {},
77
+ ...hostedVerifyWorkflow ? {
78
+ hostedVerifyWorkflow: hostedVerifyWorkflow.startsWith(".github/workflows/") ? hostedVerifyWorkflow : `.github/workflows/${hostedVerifyWorkflow}`
79
+ } : {},
80
+ scripts
81
+ }
82
+ };
83
+ }
84
+ function treeseedPackageManifestPath(dir) {
85
+ for (const fileName of ["treeseed.package.yaml", "treeseed.package.yml", "treeseed.package.json", ".treeseed-package.json"]) {
86
+ const filePath = resolve(dir, fileName);
87
+ if (existsSync(filePath)) return filePath;
88
+ }
89
+ return null;
90
+ }
91
+ function readTreeseedPackageManifest(dir) {
92
+ const filePath = treeseedPackageManifestPath(dir);
93
+ return filePath ? readStructuredFile(filePath) : null;
94
+ }
95
+ function stringRecord(value) {
96
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
97
+ }
98
+ function stringValue(value) {
99
+ return typeof value === "string" && value.trim() ? value.trim() : null;
100
+ }
101
+ function stringArray(value) {
102
+ return Array.isArray(value) ? value.map((entry) => stringValue(entry)).filter((entry) => Boolean(entry)) : [];
103
+ }
104
+ function beamPackageAdapter(root, dir) {
105
+ const manifest = readTreeseedPackageManifest(dir);
106
+ const hasMixProject = existsSync(resolve(dir, "apps/api/mix.exs")) || existsSync(resolve(dir, "mix.exs"));
107
+ if (!manifest && !hasMixProject) return null;
108
+ const kind = typeof manifest?.kind === "string" ? manifest.kind : "beam-elixir-rust";
109
+ if (kind !== "beam-elixir-rust") return null;
110
+ const id = typeof manifest?.id === "string" && manifest.id.trim() ? manifest.id.trim() : relative(resolve(root, "packages"), dir).replaceAll("\\", "/");
111
+ const name = typeof manifest?.name === "string" && manifest.name.trim() ? manifest.name.trim() : id;
112
+ const versionSourceRel = typeof manifest?.versionSource === "string" && manifest.versionSource.trim() ? manifest.versionSource.trim() : existsSync(resolve(dir, "apps/api/mix.exs")) ? "apps/api/mix.exs" : "mix.exs";
113
+ const versionSource = resolve(dir, versionSourceRel);
114
+ const image = typeof manifest?.image === "string" && manifest.image.trim() ? manifest.image.trim() : id === "treedx" ? "treeseed/treedx" : null;
115
+ const repository = stringValue(manifest?.repository) ?? (id === "treedx" ? "treeseed-ai/treedx" : null);
116
+ const developmentImages = stringRecord(manifest?.developmentImages);
117
+ const developmentImageHosting = stringRecord(developmentImages.hosting);
118
+ const developmentImageWorkflow = image ? stringValue(developmentImages.workflow) ?? (id === "treedx" ? "dev-image.yml" : null) : null;
119
+ const hostedVerifyWorkflow = stringValue(stringRecord(manifest?.releaseGate).workflow) ?? (existsSync(resolve(dir, ".github/workflows/release-gate.yml")) ? "release-gate.yml" : null);
120
+ const developmentImageDefaultBranch = stringValue(developmentImages.defaultBranch) ?? "staging";
121
+ const developmentImageTagPrefix = stringValue(developmentImages.tagPrefix) ?? "dev";
122
+ const developmentImageMovingTag = developmentImages.movingTag === false ? false : true;
123
+ const developmentImageArchitectures = stringArray(developmentImages.architectures);
124
+ const verify = manifest?.verify && typeof manifest.verify === "object" && !Array.isArray(manifest.verify) ? manifest.verify : {};
125
+ const fast = verify.fast ?? (existsSync(resolve(dir, "scripts/test-treedx-fast.sh")) ? "scripts/test-treedx-fast.sh" : null);
126
+ const local = verify.local ?? (existsSync(resolve(dir, "scripts/test-all.sh")) ? "scripts/test-all.sh" : null);
127
+ const releaseGate = manifest?.releaseGate ?? verify.release ?? (existsSync(resolve(dir, "scripts/release-gate.sh")) ? "scripts/release-gate.sh" : null);
128
+ const version = readMixProjectVersion(versionSource);
129
+ const shaTag = "sha-<short-sha>";
130
+ return {
131
+ id,
132
+ name,
133
+ kind: "beam-elixir-rust",
134
+ dir,
135
+ relativeDir: relative(root, dir).replaceAll("\\", "/"),
136
+ version,
137
+ publishTarget: image,
138
+ manifestPath: treeseedPackageManifestPath(dir),
139
+ versionSource,
140
+ verifyCommands: {
141
+ fast: commandFromScript(dir, fast, "fast"),
142
+ local: commandFromScript(dir, local, "local"),
143
+ release: commandFromScript(dir, releaseGate, "release")
144
+ },
145
+ artifacts: image ? [{ provider: "docker", name: image, tags: version ? [version, shaTag] : [shaTag] }] : [],
146
+ releaseChecks: image ? [{ kind: "docker-manifest", name: "Docker image manifest", detail: `${image}:${version ?? "<version>"}` }] : [],
147
+ metadata: {
148
+ hasCargo: existsSync(resolve(dir, "Cargo.toml")),
149
+ hasDockerfile: existsSync(resolve(dir, "Dockerfile")),
150
+ repository,
151
+ versionSource: versionSourceRel,
152
+ ...developmentImageWorkflow ? {
153
+ developmentImageWorkflow: developmentImageWorkflow.startsWith(".github/workflows/") ? developmentImageWorkflow : `.github/workflows/${developmentImageWorkflow}`,
154
+ developmentImageDefaultBranch,
155
+ developmentImageTagPrefix,
156
+ developmentImageMovingTag,
157
+ developmentImageArchitectures,
158
+ developmentImageTagPattern: `${image}:${developmentImageTagPrefix}-<branch-slug>-<short-sha>`,
159
+ developmentImageMovingTagPattern: developmentImageMovingTag ? `${image}:${developmentImageTagPrefix}-<branch-slug>` : null,
160
+ developmentImageHosting: Object.keys(developmentImageHosting).length > 0 ? developmentImageHosting : null
161
+ } : {},
162
+ ...hostedVerifyWorkflow ? {
163
+ hostedVerifyWorkflow: hostedVerifyWorkflow.startsWith(".github/workflows/") ? hostedVerifyWorkflow : `.github/workflows/${hostedVerifyWorkflow}`
164
+ } : {}
165
+ }
166
+ };
167
+ }
168
+ function gitOutput(cwd, args) {
169
+ const result = spawnSync("git", args, { cwd, encoding: "utf8", stdio: "pipe" });
170
+ if (result.status !== 0) {
171
+ const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
172
+ throw new Error(stderr || `git ${args.join(" ")} failed in ${cwd}.`);
173
+ }
174
+ return result.stdout.trim();
175
+ }
176
+ function branchSlug(value) {
177
+ const normalized = value.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 40);
178
+ return normalized || "branch";
179
+ }
180
+ function planTreeseedPackageDevelopmentImage(root = workspaceRoot(), idOrName, { branch } = {}) {
181
+ const adapter = findTreeseedPackageAdapter(root, idOrName);
182
+ if (!adapter) {
183
+ throw new Error(`Treeseed package adapter ${idOrName} was not discovered.`);
184
+ }
185
+ const imageName = typeof adapter.publishTarget === "string" && adapter.publishTarget.trim() ? adapter.publishTarget.trim() : null;
186
+ if (!imageName) {
187
+ throw new Error(`${adapter.id} does not declare a publish image target.`);
188
+ }
189
+ const metadata = adapter.metadata;
190
+ const workflow = stringValue(metadata.developmentImageWorkflow)?.replace(/^\.github\/workflows\//u, "") ?? null;
191
+ if (!workflow) {
192
+ throw new Error(`${adapter.id} does not declare a development image workflow.`);
193
+ }
194
+ const selectedBranch = branch ?? stringValue(metadata.developmentImageDefaultBranch) ?? "staging";
195
+ const sha = gitOutput(adapter.dir, ["rev-parse", selectedBranch]);
196
+ const slug = branchSlug(selectedBranch);
197
+ const shortSha = sha.slice(0, 12);
198
+ const tagPrefix = stringValue(metadata.developmentImageTagPrefix) ?? "dev";
199
+ const immutableTag = `${tagPrefix}-${slug}-${shortSha}`;
200
+ const movingTag = metadata.developmentImageMovingTag === false ? null : `${tagPrefix}-${slug}`;
201
+ const architectures = stringArray(metadata.developmentImageArchitectures);
202
+ const hosting = stringRecord(metadata.developmentImageHosting);
203
+ const app = stringValue(hosting.app);
204
+ const environment = stringValue(hosting.environment) ?? selectedBranch;
205
+ const overrideEnvVar = stringValue(hosting.envVar);
206
+ const imageRef = `${imageName}:${immutableTag}`;
207
+ const movingImageRef = movingTag ? `${imageName}:${movingTag}` : null;
208
+ const hostingImageRef = movingImageRef ?? imageRef;
209
+ return {
210
+ package: {
211
+ id: adapter.id,
212
+ name: adapter.name,
213
+ path: adapter.relativeDir,
214
+ kind: adapter.kind,
215
+ version: adapter.version,
216
+ publishTarget: adapter.publishTarget,
217
+ metadata: adapter.metadata
218
+ },
219
+ repository: stringValue(metadata.repository) ?? `${adapter.id}`,
220
+ workflow,
221
+ branch: selectedBranch,
222
+ refs: {
223
+ imageName,
224
+ branch: selectedBranch,
225
+ branchSlug: slug,
226
+ sha,
227
+ shortSha,
228
+ immutableTag,
229
+ movingTag,
230
+ imageRef,
231
+ movingImageRef,
232
+ archImageRefs: architectures.map((arch) => `${imageName}:${immutableTag}-${arch}`)
233
+ },
234
+ hosting: app && overrideEnvVar ? {
235
+ app,
236
+ environment,
237
+ overrideEnvVar,
238
+ override: { [overrideEnvVar]: hostingImageRef },
239
+ command: `${overrideEnvVar}=${hostingImageRef} npx trsd hosting apply --environment ${environment} --app ${app} --execute --json`
240
+ } : null
241
+ };
242
+ }
243
+ function discoverTreeseedPackageAdapters(root = workspaceRoot()) {
244
+ const adapters = /* @__PURE__ */ new Map();
245
+ for (const pkg of workspacePackages(root)) {
246
+ if (typeof pkg.name === "string" && pkg.name.startsWith("@treeseed/")) {
247
+ adapters.set(pkg.name, nodeTypeScriptAdapter(pkg));
248
+ }
249
+ }
250
+ const packagesDir = resolve(root, "packages");
251
+ const packageDirs = existsSync(packagesDir) ? readdirSync(packagesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve(packagesDir, entry.name)) : [];
252
+ for (const dir of packageDirs) {
253
+ if (!existsSync(dir)) continue;
254
+ const adapter = beamPackageAdapter(root, dir);
255
+ if (adapter) adapters.set(adapter.id, adapter);
256
+ }
257
+ return [...adapters.values()].sort((left, right) => {
258
+ if (left.kind !== right.kind) return left.kind === "node-typescript" ? -1 : 1;
259
+ return left.id.localeCompare(right.id);
260
+ });
261
+ }
262
+ function findTreeseedPackageAdapter(root, idOrName) {
263
+ return discoverTreeseedPackageAdapters(root).find((adapter) => adapter.id === idOrName || adapter.name === idOrName) ?? null;
264
+ }
265
+ function packageAdapterPlanSummary(root = workspaceRoot()) {
266
+ return discoverTreeseedPackageAdapters(root).map((adapter) => ({
267
+ id: adapter.id,
268
+ name: adapter.name,
269
+ kind: adapter.kind,
270
+ path: adapter.relativeDir,
271
+ version: adapter.version,
272
+ publishTarget: adapter.publishTarget,
273
+ verify: Object.fromEntries(Object.entries(adapter.verifyCommands).map(([key, command]) => [
274
+ key,
275
+ command ? `${command.command} ${command.args.join(" ")}` : null
276
+ ])),
277
+ artifacts: adapter.artifacts,
278
+ releaseChecks: adapter.releaseChecks,
279
+ metadata: adapter.metadata
280
+ }));
281
+ }
282
+ export {
283
+ discoverTreeseedPackageAdapters,
284
+ findTreeseedPackageAdapter,
285
+ packageAdapterPlanSummary,
286
+ planTreeseedPackageDevelopmentImage,
287
+ readMixProjectVersion
288
+ };
@@ -52,6 +52,7 @@ export declare function createPackageDependencyReference(input: {
52
52
  gitDependencyProtocol?: GitDependencyProtocol;
53
53
  }): PackageDependencyReference;
54
54
  export declare function updateInternalDependencySpecs(packageJson: Record<string, unknown> | null, references: Map<string, PackageDependencyReference>): RewrittenDevReference[];
55
+ export declare function installableInternalDependencyVersions(root: any, versions: Map<string, string>): Map<string, string>;
55
56
  export declare function rewriteInternalDependenciesToStableVersions(root: any, versions: Map<string, string>): (RewrittenDevReference & {
56
57
  repoName: string;
57
58
  packageJsonPath: string;
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
+ import { discoverTreeseedPackageAdapters } from "./package-adapters.js";
4
5
  import { run, workspacePackages, workspaceRoot } from "./workspace-tools.js";
5
6
  const INTERNAL_DEPENDENCY_FIELDS = ["dependencies", "optionalDependencies", "peerDependencies", "devDependencies"];
6
7
  function readJson(filePath) {
@@ -155,14 +156,24 @@ function updateInternalDependencySpecs(packageJson, references) {
155
156
  }
156
157
  return changed;
157
158
  }
159
+ function installableInternalDependencyVersions(root = workspaceRoot(), versions) {
160
+ const publishTargets = /* @__PURE__ */ new Map();
161
+ for (const adapter of discoverTreeseedPackageAdapters(root)) {
162
+ const publishTarget = adapter.publishTarget ?? "npm";
163
+ publishTargets.set(adapter.id, publishTarget);
164
+ publishTargets.set(adapter.name, publishTarget);
165
+ }
166
+ return new Map([...versions.entries()].filter(([packageName]) => (publishTargets.get(packageName) ?? "npm") === "npm"));
167
+ }
158
168
  function rewriteInternalDependenciesToStableVersions(root = workspaceRoot(), versions) {
159
169
  const rewrites = [];
170
+ const installableVersions = installableInternalDependencyVersions(root, versions);
160
171
  for (const pkg of workspacePackages(root)) {
161
172
  const packageJsonPath = resolve(pkg.dir, "package.json");
162
173
  const packageJson = readJson(packageJsonPath);
163
174
  const changed = updateInternalDependencySpecs(
164
175
  packageJson,
165
- new Map([...versions.entries()].map(([packageName, version]) => [packageName, {
176
+ new Map([...installableVersions.entries()].map(([packageName, version]) => [packageName, {
166
177
  packageName,
167
178
  version,
168
179
  spec: version,
@@ -185,6 +196,7 @@ function rewriteInternalDependenciesToStableVersions(root = workspaceRoot(), ver
185
196
  }
186
197
  function rewriteProjectInternalDependenciesToStableVersions(root = workspaceRoot(), versions) {
187
198
  const rewrites = [];
199
+ const installableVersions = installableInternalDependencyVersions(root, versions);
188
200
  const targets = [
189
201
  { name: "@treeseed/market", dir: root },
190
202
  ...workspacePackages(root).map((pkg) => ({ name: pkg.name, dir: pkg.dir }))
@@ -195,7 +207,7 @@ function rewriteProjectInternalDependenciesToStableVersions(root = workspaceRoot
195
207
  const packageJson = readJson(packageJsonPath);
196
208
  const changed = updateInternalDependencySpecs(
197
209
  packageJson,
198
- new Map([...versions.entries()].map(([packageName, version]) => [packageName, {
210
+ new Map([...installableVersions.entries()].map(([packageName, version]) => [packageName, {
199
211
  packageName,
200
212
  version,
201
213
  spec: version,
@@ -458,6 +470,7 @@ export {
458
470
  createPackageDependencyReference,
459
471
  devTagFromDependencySpec,
460
472
  gitTagMessage,
473
+ installableInternalDependencyVersions,
461
474
  internalDependencyFields,
462
475
  isGitDependencySpec,
463
476
  isPrereleaseVersion,
@@ -273,6 +273,13 @@ export declare function deployProjectPlatform(options: ProjectPlatformActionOpti
273
273
  cwd: any;
274
274
  publicBaseUrl: any;
275
275
  timings: TreeseedTimingEntry[];
276
+ transport: {
277
+ railway: {
278
+ reconcile: string;
279
+ deploy: string;
280
+ };
281
+ };
282
+ deploymentId?: undefined;
276
283
  runtimeConfiguration?: undefined;
277
284
  } | {
278
285
  service: any;
@@ -281,19 +288,41 @@ export declare function deployProjectPlatform(options: ProjectPlatformActionOpti
281
288
  cwd: any;
282
289
  publicBaseUrl: any;
283
290
  timings: TreeseedTimingEntry[];
291
+ deploymentId: any;
292
+ transport: {
293
+ railway: {
294
+ reconcile: string;
295
+ deploy: string;
296
+ };
297
+ };
298
+ runtimeConfiguration: {
299
+ updated: any;
300
+ healthcheckPath: any;
301
+ healthcheckTimeoutSeconds: any;
302
+ runtimeMode: any;
303
+ volume: any;
304
+ } | null;
305
+ } | {
306
+ service: any;
307
+ status: string;
308
+ command: string;
309
+ cwd: any;
310
+ publicBaseUrl: any;
311
+ timings: TreeseedTimingEntry[];
312
+ transport: {
313
+ railway: {
314
+ reconcile: string;
315
+ deploy: string;
316
+ };
317
+ };
284
318
  runtimeConfiguration: {
285
- updated: boolean;
286
- healthcheckPath: string | null;
287
- healthcheckTimeoutSeconds: number | null;
288
- runtimeMode: string | null;
289
- volume: {
290
- id: any;
291
- name: any;
292
- mountPath: any;
293
- created: boolean;
294
- updated: boolean;
295
- } | null;
319
+ updated: any;
320
+ healthcheckPath: any;
321
+ healthcheckTimeoutSeconds: any;
322
+ runtimeMode: any;
323
+ volume: any;
296
324
  } | null;
325
+ deploymentId?: undefined;
297
326
  } | undefined)[];
298
327
  timings: TreeseedTimingEntry[];
299
328
  }>;
@@ -816,6 +845,13 @@ export declare function runProjectPlatformAction(action: ProjectPlatformAction,
816
845
  cwd: any;
817
846
  publicBaseUrl: any;
818
847
  timings: TreeseedTimingEntry[];
848
+ transport: {
849
+ railway: {
850
+ reconcile: string;
851
+ deploy: string;
852
+ };
853
+ };
854
+ deploymentId?: undefined;
819
855
  runtimeConfiguration?: undefined;
820
856
  } | {
821
857
  service: any;
@@ -824,19 +860,41 @@ export declare function runProjectPlatformAction(action: ProjectPlatformAction,
824
860
  cwd: any;
825
861
  publicBaseUrl: any;
826
862
  timings: TreeseedTimingEntry[];
863
+ deploymentId: any;
864
+ transport: {
865
+ railway: {
866
+ reconcile: string;
867
+ deploy: string;
868
+ };
869
+ };
870
+ runtimeConfiguration: {
871
+ updated: any;
872
+ healthcheckPath: any;
873
+ healthcheckTimeoutSeconds: any;
874
+ runtimeMode: any;
875
+ volume: any;
876
+ } | null;
877
+ } | {
878
+ service: any;
879
+ status: string;
880
+ command: string;
881
+ cwd: any;
882
+ publicBaseUrl: any;
883
+ timings: TreeseedTimingEntry[];
884
+ transport: {
885
+ railway: {
886
+ reconcile: string;
887
+ deploy: string;
888
+ };
889
+ };
827
890
  runtimeConfiguration: {
828
- updated: boolean;
829
- healthcheckPath: string | null;
830
- healthcheckTimeoutSeconds: number | null;
831
- runtimeMode: string | null;
832
- volume: {
833
- id: any;
834
- name: any;
835
- mountPath: any;
836
- created: boolean;
837
- updated: boolean;
838
- } | null;
891
+ updated: any;
892
+ healthcheckPath: any;
893
+ healthcheckTimeoutSeconds: any;
894
+ runtimeMode: any;
895
+ volume: any;
839
896
  } | null;
897
+ deploymentId?: undefined;
840
898
  } | undefined)[];
841
899
  timings: TreeseedTimingEntry[];
842
900
  }>;
@@ -48,7 +48,7 @@ import { CloudflareQueuePullClient, CloudflareQueuePushClient } from "../../remo
48
48
  import { runPrefixedCommand, runTreeseedBootstrapDag, sleep, writeTreeseedBootstrapLine } from "./bootstrap-runner.js";
49
49
  import { runTenantDeployPreflight } from "./save-deploy-preflight.js";
50
50
  const PROJECT_PLATFORM_BOOTSTRAP_SYSTEMS = ["data", "web", "api", "agents"];
51
- const WEB_PLATFORM_BOOTSTRAP_SYSTEMS = PROJECT_PLATFORM_BOOTSTRAP_SYSTEMS;
51
+ const WEB_PLATFORM_BOOTSTRAP_SYSTEMS = ["data", "web"];
52
52
  const PROCESSING_PLATFORM_BOOTSTRAP_SYSTEMS = ["api", "agents"];
53
53
  function stableHash(value) {
54
54
  return createHash("sha256").update(value).digest("hex");
@@ -63,6 +63,13 @@ function recordTiming(timings, name, startMs, status = "success", metadata) {
63
63
  timings.push(entry);
64
64
  return entry;
65
65
  }
66
+ function writeWorkflowStatus(message) {
67
+ if (!process.env.TREESEED_WORKFLOW_ACTION && !process.env.TREESEED_WORKFLOW_DEBUG) {
68
+ return;
69
+ }
70
+ process.stderr.write(`[project-platform] ${message}
71
+ `);
72
+ }
66
73
  async function timedPhase(timings, name, run, metadata) {
67
74
  const startMs = performance.now();
68
75
  try {
@@ -658,10 +665,14 @@ function findFirstMatchingString(value, matcher, seen = /* @__PURE__ */ new Set(
658
665
  return null;
659
666
  }
660
667
  function resolveImmediatePagesProbeUrl(siteConfig, state, target) {
668
+ const configuredUrl = resolveConfiguredSurfaceBaseUrl(siteConfig, target, "web");
669
+ if (configuredUrl) {
670
+ return configuredUrl;
671
+ }
661
672
  if (target.kind === "persistent" && target.scope === "staging" && state.pages?.projectName) {
662
673
  return `https://${state.pages?.stagingBranch ?? "staging"}.${state.pages.projectName}.pages.dev`;
663
674
  }
664
- return state.pages?.url ?? resolveConfiguredSurfaceBaseUrl(siteConfig, target, "web") ?? siteConfig.siteUrl;
675
+ return state.pages?.url ?? siteConfig.siteUrl;
665
676
  }
666
677
  function resolveImmediateApiProbeUrl(siteConfig, state, target) {
667
678
  const configuredUrl = resolveConfiguredSurfaceBaseUrl(siteConfig, target, "api") ?? siteConfig.services?.api?.environments?.[target.kind === "persistent" ? target.scope : "prod"]?.baseUrl ?? siteConfig.services?.api?.publicBaseUrl ?? process.env.TREESEED_API_BASE_URL ?? state.services?.api?.lastDeployedUrl ?? null;
@@ -801,8 +812,8 @@ function probeR2(tenantRoot, siteConfig, state, target) {
801
812
  function probeScaleConfiguration(siteConfig, state) {
802
813
  const worker = state.services?.workerRunner ?? state.services?.worker ?? {};
803
814
  const workerConfig = siteConfig.services?.workerRunner ?? siteConfig.services?.worker ?? {};
804
- const marketRunner = state.services?.marketOperationsRunner ?? {};
805
- const marketRunnerConfig = siteConfig.services?.marketOperationsRunner ?? {};
815
+ const marketRunner = state.services?.operationsRunner ?? {};
816
+ const marketRunnerConfig = siteConfig.services?.operationsRunner ?? {};
806
817
  const scalerKind = String(process.env.TREESEED_WORKER_POOL_SCALER ?? "").trim();
807
818
  if (marketRunnerConfig.provider === "railway" && workerConfig.provider !== "railway") {
808
819
  const runnerServiceId = marketRunner.serviceId ?? null;
@@ -1058,30 +1069,46 @@ async function publishContent(options, reporter, publishOptions = {}) {
1058
1069
  }
1059
1070
  }
1060
1071
  async function provisionProjectPlatform(options) {
1072
+ writeWorkflowStatus(`provision:start scope=${options.scope}`);
1061
1073
  const timings = [];
1074
+ writeWorkflowStatus("provision:resolve-reporter");
1062
1075
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1076
+ writeWorkflowStatus(`provision:reporter kind=${reporter.kind} enabled=${reporter.enabled ? "true" : "false"}`);
1063
1077
  const target = createPersistentDeployTarget(options.scope === "local" ? "staging" : options.scope);
1078
+ writeWorkflowStatus(`provision:target ${deployTargetLabel(target)}`);
1064
1079
  const siteConfig = loadCliDeployConfig(options.tenantRoot);
1080
+ writeWorkflowStatus("provision:resolve-bootstrap-systems");
1065
1081
  const bootstrapSystems = resolveProjectPlatformBootstrapSystems(options, siteConfig);
1066
1082
  const selectedSystems = new Set(bootstrapSystems);
1067
1083
  const env = { ...process.env, ...options.env ?? {} };
1084
+ writeWorkflowStatus(`provision:reconcile:start systems=${bootstrapSystems.join(",") || "(none)"}`);
1068
1085
  const summary = await timedPhase(timings, "provision:reconcile", () => reconcileTreeseedTarget({
1069
1086
  tenantRoot: options.tenantRoot,
1070
1087
  target,
1071
1088
  env,
1072
1089
  systems: bootstrapSystems,
1073
- write: options.write
1090
+ write: options.write,
1091
+ dryRun: options.dryRun
1074
1092
  }));
1093
+ writeWorkflowStatus("provision:reconcile:done");
1075
1094
  timings.push(...summary.timings ?? []);
1095
+ writeWorkflowStatus("provision:collect-reconcile-status:start");
1076
1096
  const verification = await timedPhase(timings, "provision:collect-reconcile-status", () => collectTreeseedReconcileStatus({
1077
1097
  tenantRoot: options.tenantRoot,
1078
1098
  target,
1079
1099
  env,
1080
1100
  systems: bootstrapSystems
1081
1101
  }));
1082
- await timedPhase(timings, "provision:ensure-wrangler-config", () => {
1083
- ensureGeneratedWranglerConfig(options.tenantRoot, { target });
1084
- });
1102
+ writeWorkflowStatus("provision:collect-reconcile-status:done");
1103
+ if (selectedSystems.has("data") || selectedSystems.has("web")) {
1104
+ writeWorkflowStatus("provision:ensure-wrangler-config:start");
1105
+ await timedPhase(timings, "provision:ensure-wrangler-config", () => {
1106
+ ensureGeneratedWranglerConfig(options.tenantRoot, { target });
1107
+ });
1108
+ writeWorkflowStatus("provision:ensure-wrangler-config:done");
1109
+ } else {
1110
+ writeWorkflowStatus("provision:ensure-wrangler-config:skipped");
1111
+ }
1085
1112
  const shouldValidateRailway = selectedSystems.has("api") || selectedSystems.has("agents");
1086
1113
  const railwayValidation = shouldValidateRailway ? options.scope === "local" ? validateRailwayServiceConfiguration(options.tenantRoot, options.scope) : validateRailwayDeployPrerequisites(options.tenantRoot, options.scope, { env }) : { services: [] };
1087
1114
  const railwaySchedules = [];
@@ -1239,16 +1266,22 @@ async function provisionProjectPlatform(options) {
1239
1266
  };
1240
1267
  }
1241
1268
  async function deployProjectPlatform(options) {
1269
+ writeWorkflowStatus(`deploy:start scope=${options.scope} dryRun=${options.dryRun ? "true" : "false"}`);
1242
1270
  const timings = [];
1243
1271
  const deployStartMs = performance.now();
1272
+ writeWorkflowStatus("deploy:resolve-reporter");
1244
1273
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1274
+ writeWorkflowStatus(`deploy:reporter kind=${reporter.kind} enabled=${reporter.enabled ? "true" : "false"}`);
1245
1275
  const commitSha = currentCommit(options.tenantRoot);
1246
1276
  const branchName = currentRef(options.tenantRoot);
1277
+ writeWorkflowStatus("deploy:resolve-bootstrap-systems");
1247
1278
  const bootstrapSystems = resolveProjectPlatformBootstrapSystems(options);
1248
1279
  const selectedSystems = new Set(bootstrapSystems);
1249
1280
  const execution = options.bootstrapExecution ?? "parallel";
1250
1281
  const write = options.write;
1251
1282
  const env = { ...process.env, ...options.env ?? {} };
1283
+ writeWorkflowStatus(`deploy:bootstrap-systems ${bootstrapSystems.join(",") || "(none)"}`);
1284
+ writeWorkflowStatus("deploy:report-running");
1252
1285
  await reportDeployment(reporter, {
1253
1286
  environment: options.scope,
1254
1287
  deploymentKind: "code",
@@ -1258,9 +1291,12 @@ async function deployProjectPlatform(options) {
1258
1291
  triggeredByType: "project_runner",
1259
1292
  metadata: { scope: options.scope }
1260
1293
  });
1294
+ writeWorkflowStatus("deploy:reported-running");
1261
1295
  if (!options.skipProvision) {
1296
+ writeWorkflowStatus("deploy:provision:start");
1262
1297
  const provision = await timedPhase(timings, "deploy:provision", () => provisionProjectPlatform({ ...options, reporter, bootstrapSystems }));
1263
1298
  timings.push(...provision.timings ?? []);
1299
+ writeWorkflowStatus("deploy:provision:done");
1264
1300
  }
1265
1301
  const nodes = [];
1266
1302
  let cloudflareContext = null;
@@ -1565,8 +1601,13 @@ async function runProjectPlatformAction(action, options) {
1565
1601
  const previousWorkflowPlane = process.env.TREESEED_WORKFLOW_PLANE;
1566
1602
  process.env.TREESEED_WORKFLOW_ACTION = action;
1567
1603
  process.env.TREESEED_WORKFLOW_PLANE = previousWorkflowPlane ?? "all";
1604
+ writeWorkflowStatus(`action:start ${action} scope=${options.scope}`);
1605
+ writeWorkflowStatus("action:apply-environment:start");
1568
1606
  applyTreeseedEnvironmentToProcess({ tenantRoot: options.tenantRoot, scope: options.scope, override: true });
1607
+ writeWorkflowStatus("action:apply-environment:done");
1608
+ writeWorkflowStatus("action:resolve-reporter:start");
1569
1609
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1610
+ writeWorkflowStatus(`action:resolve-reporter:done kind=${reporter.kind} enabled=${reporter.enabled ? "true" : "false"}`);
1570
1611
  try {
1571
1612
  switch (action) {
1572
1613
  case "deploy_web":