@treeseed/sdk 0.10.27 → 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 (168) 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 +11 -4
  20. package/dist/index.js +71 -7
  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/template-registry.js +14 -7
  67. package/dist/operations/services/verification-cache.d.ts +25 -0
  68. package/dist/operations/services/verification-cache.js +71 -0
  69. package/dist/operations/services/workspace-dependency-mode.js +9 -1
  70. package/dist/operations/services/workspace-save.js +1 -1
  71. package/dist/operations/services/workspace-tools.js +2 -1
  72. package/dist/platform/contracts.d.ts +32 -1
  73. package/dist/platform/deploy-config.js +73 -8
  74. package/dist/platform/env.yaml +163 -35
  75. package/dist/platform/environment.d.ts +1 -0
  76. package/dist/platform/environment.js +74 -5
  77. package/dist/platform/plugin.d.ts +9 -0
  78. package/dist/platform-operation-store.js +2 -2
  79. package/dist/platform-operations.js +1 -1
  80. package/dist/reconcile/bootstrap-systems.js +2 -2
  81. package/dist/reconcile/builtin-adapters.js +372 -189
  82. package/dist/reconcile/contracts.d.ts +9 -5
  83. package/dist/reconcile/desired-state.d.ts +1 -0
  84. package/dist/reconcile/desired-state.js +5 -5
  85. package/dist/reconcile/engine.d.ts +5 -2
  86. package/dist/reconcile/engine.js +53 -32
  87. package/dist/reconcile/index.d.ts +2 -0
  88. package/dist/reconcile/index.js +2 -0
  89. package/dist/reconcile/live-acceptance.d.ts +79 -0
  90. package/dist/reconcile/live-acceptance.js +1615 -0
  91. package/dist/reconcile/platform.d.ts +104 -0
  92. package/dist/reconcile/platform.js +100 -0
  93. package/dist/reconcile/state.js +4 -4
  94. package/dist/reconcile/units.js +2 -2
  95. package/dist/scripts/deployment-readiness.js +20 -0
  96. package/dist/scripts/generate-treedx-openapi-types.js +186 -0
  97. package/dist/scripts/operations-runner-smoke.js +16 -0
  98. package/dist/scripts/release-verify.js +4 -1
  99. package/dist/scripts/template-catalog.test.js +7 -7
  100. package/dist/scripts/tenant-workflow-action.js +10 -1
  101. package/dist/sdk-types.d.ts +172 -5
  102. package/dist/sdk-types.js +28 -3
  103. package/dist/sdk.d.ts +35 -24
  104. package/dist/sdk.js +186 -17
  105. package/dist/template-launch-requirements.js +9 -0
  106. package/dist/treedx/adapters.d.ts +6 -0
  107. package/dist/treedx/adapters.js +36 -0
  108. package/dist/treedx/client.d.ts +222 -0
  109. package/dist/treedx/client.js +871 -0
  110. package/dist/treedx/errors.d.ts +13 -0
  111. package/dist/treedx/errors.js +17 -0
  112. package/dist/treedx/federated-client.d.ts +27 -0
  113. package/dist/treedx/federated-client.js +158 -0
  114. package/dist/treedx/generated/openapi-types.d.ts +3558 -0
  115. package/dist/treedx/generated/openapi-types.js +0 -0
  116. package/dist/treedx/graph-adapter.d.ts +33 -0
  117. package/dist/treedx/graph-adapter.js +156 -0
  118. package/dist/treedx/index.d.ts +14 -0
  119. package/dist/treedx/index.js +48 -0
  120. package/dist/treedx/market-integration.d.ts +27 -0
  121. package/dist/treedx/market-integration.js +131 -0
  122. package/dist/treedx/ports.d.ts +166 -0
  123. package/dist/treedx/ports.js +231 -0
  124. package/dist/treedx/query-adapter.d.ts +19 -0
  125. package/dist/treedx/query-adapter.js +62 -0
  126. package/dist/treedx/registry-client.d.ts +11 -0
  127. package/dist/treedx/registry-client.js +19 -0
  128. package/dist/treedx/repository-adapter.d.ts +45 -0
  129. package/dist/treedx/repository-adapter.js +308 -0
  130. package/dist/treedx/sdk-integration.d.ts +27 -0
  131. package/dist/treedx/sdk-integration.js +63 -0
  132. package/dist/treedx/types.d.ts +1084 -0
  133. package/dist/treedx/types.js +8 -0
  134. package/dist/treedx/workspace-adapter.d.ts +27 -0
  135. package/dist/treedx/workspace-adapter.js +65 -0
  136. package/dist/treedx-backends.d.ts +218 -0
  137. package/dist/treedx-backends.js +632 -0
  138. package/dist/treedx-client.d.ts +86 -0
  139. package/dist/treedx-client.js +175 -0
  140. package/dist/treeseed/template-catalog/catalog.fixture.json +497 -138
  141. package/dist/workflow/operations.d.ts +119 -13
  142. package/dist/workflow/operations.js +309 -53
  143. package/dist/workflow-state.d.ts +13 -0
  144. package/dist/workflow-state.js +43 -26
  145. package/dist/workflow-support.d.ts +11 -3
  146. package/dist/workflow-support.js +67 -3
  147. package/dist/workflow.d.ts +5 -0
  148. package/drizzle/market/0004_treedx_market_integration.sql +99 -0
  149. package/package.json +34 -3
  150. package/templates/github/deploy-web.workflow.yml +39 -6
  151. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +0 -3
  152. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +0 -6
  153. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +0 -35
  154. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +0 -4
  155. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +0 -65
  156. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +0 -22
  157. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +0 -1
  158. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +0 -11
  159. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +0 -11
  160. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +0 -11
  161. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +0 -17
  162. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +0 -1
  163. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +0 -3
  164. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +0 -1
  165. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +0 -26
  166. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +0 -74
  167. package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +0 -9
  168. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +0 -103
@@ -53,7 +53,7 @@ const TREESEED_DEFAULT_PROVIDER_SELECTIONS = {
53
53
  },
54
54
  site: "default"
55
55
  };
56
- const TRESEED_MANAGED_SERVICE_KEYS = ["marketDatabase", "api", "marketOperationsRunner"];
56
+ const TRESEED_MANAGED_SERVICE_KEYS = ["treeseedDatabase", "api", "operationsRunner"];
57
57
  const TRESEED_WORKSPACE_PACKAGE_DIRS = ["sdk", "core", "cli"];
58
58
  const CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER = "replace-with-cloudflare-account-id";
59
59
  function normalizePlanesFromLegacyHosting(hosting) {
@@ -63,12 +63,12 @@ function normalizePlanesFromLegacyHosting(hosting) {
63
63
  runtime: { mode: "none", registration: "none" }
64
64
  };
65
65
  }
66
- if (hosting.kind === "market_control_plane" || hosting.kind === "hosted_project") {
66
+ if (hosting.kind === "treeseed_control_plane" || hosting.kind === "hosted_project") {
67
67
  return {
68
68
  hub: { mode: "treeseed_hosted" },
69
69
  runtime: {
70
70
  mode: "treeseed_managed",
71
- registration: hosting.kind === "market_control_plane" ? "none" : hosting.registration ?? "none",
71
+ registration: hosting.kind === "treeseed_control_plane" ? "none" : hosting.registration ?? "none",
72
72
  marketBaseUrl: hosting.marketBaseUrl,
73
73
  teamId: hosting.teamId,
74
74
  projectId: hosting.projectId
@@ -484,12 +484,12 @@ function parseFallbackDeployConfig(configPath) {
484
484
  const hosting = optionalRecord(record.hosting, "hosting") ?? {};
485
485
  const parsedHosting = Object.keys(hosting).length === 0 ? void 0 : {
486
486
  kind: optionalEnum(hosting.kind, "hosting.kind", [
487
- "market_control_plane",
487
+ "treeseed_control_plane",
488
488
  "hosted_project",
489
489
  "self_hosted_project"
490
490
  ]) ?? "self_hosted_project",
491
491
  registration: optionalEnum(hosting.registration, "hosting.registration", ["optional", "none"]) ?? "none",
492
- marketBaseUrl: optionalString(process.env.TREESEED_MARKET_API_BASE_URL) ?? optionalString(hosting.marketBaseUrl),
492
+ marketBaseUrl: optionalString(process.env.TREESEED_API_BASE_URL) ?? optionalString(hosting.marketBaseUrl),
493
493
  teamId: optionalString(process.env.TREESEED_HOSTING_TEAM_ID) ?? optionalString(hosting.teamId),
494
494
  projectId: optionalString(process.env.TREESEED_PROJECT_ID) ?? optionalString(hosting.projectId)
495
495
  };
@@ -507,7 +507,7 @@ function parseFallbackDeployConfig(configPath) {
507
507
  const runtime = {
508
508
  mode: optionalEnum(runtimeRecord.mode, "runtime.mode", ["none", "byo_attached", "treeseed_managed"]) ?? inferredPlanes.runtime.mode,
509
509
  registration: optionalEnum(runtimeRecord.registration, "runtime.registration", ["optional", "required", "none"]) ?? inferredPlanes.runtime.registration ?? "none",
510
- marketBaseUrl: optionalString(process.env.TREESEED_MARKET_API_BASE_URL) ?? optionalString(runtimeRecord.marketBaseUrl) ?? inferredPlanes.runtime.marketBaseUrl,
510
+ marketBaseUrl: optionalString(process.env.TREESEED_API_BASE_URL) ?? optionalString(runtimeRecord.marketBaseUrl) ?? inferredPlanes.runtime.marketBaseUrl,
511
511
  teamId: optionalString(process.env.TREESEED_HOSTING_TEAM_ID) ?? optionalString(runtimeRecord.teamId) ?? inferredPlanes.runtime.teamId,
512
512
  projectId: optionalString(process.env.TREESEED_PROJECT_ID) ?? optionalString(runtimeRecord.projectId) ?? inferredPlanes.runtime.projectId
513
513
  };
@@ -520,7 +520,7 @@ function parseFallbackDeployConfig(configPath) {
520
520
  slug: expectString(record.slug, "slug"),
521
521
  siteUrl: expectString(record.siteUrl, "siteUrl"),
522
522
  contactEmail: expectString(record.contactEmail, "contactEmail"),
523
- hosting: parsedHosting?.kind === "market_control_plane" ? { ...parsedHosting, registration: "none" } : parsedHosting && record.hub === void 0 && record.runtime === void 0 ? parsedHosting : normalizeLegacyHostingFromPlanes(hub, runtime),
523
+ hosting: parsedHosting?.kind === "treeseed_control_plane" ? { ...parsedHosting, registration: "none" } : parsedHosting && record.hub === void 0 && record.runtime === void 0 ? parsedHosting : normalizeLegacyHostingFromPlanes(hub, runtime),
524
524
  hub,
525
525
  runtime,
526
526
  cloudflare: {
@@ -532,10 +532,11 @@ function parseFallbackDeployConfig(configPath) {
532
532
  d1Binding: optionalString(cloudflare.d1Binding),
533
533
  queueBinding: optionalString(cloudflare.queueBinding),
534
534
  pages: cloudflare.pages === void 0 ? void 0 : {
535
- projectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME) ?? optionalString(cloudflarePages.projectName),
536
- previewProjectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME) ?? optionalString(cloudflarePages.previewProjectName),
535
+ projectName: optionalString(cloudflarePages.projectName) ?? optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME),
536
+ previewProjectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME) ?? optionalString(cloudflarePages.previewProjectName) ?? optionalString(cloudflarePages.projectName) ?? optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME),
537
537
  productionBranch: optionalString(cloudflarePages.productionBranch) ?? "main",
538
538
  stagingBranch: optionalString(cloudflarePages.stagingBranch) ?? "staging",
539
+ buildCommand: optionalString(cloudflarePages.buildCommand),
539
540
  buildOutputDir: optionalString(cloudflarePages.buildOutputDir)
540
541
  },
541
542
  r2: cloudflare.r2 === void 0 ? void 0 : {
@@ -1,6 +1,9 @@
1
1
  import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { spawnSync } from "node:child_process";
3
3
  import { basename, dirname, relative, resolve } from "node:path";
4
+ import {
5
+ normalizeTreeseedTemplateId
6
+ } from "../../sdk-types.js";
4
7
  import { RemoteTemplateCatalogClient } from "../../template-catalog.js";
5
8
  import {
6
9
  normalizeTemplateLaunchRequirements
@@ -47,15 +50,15 @@ function listTemplateArtifactIds() {
47
50
  return [.../* @__PURE__ */ new Set([...packagedIds, ...localStarterIds])].sort((left, right) => left.localeCompare(right, void 0, { sensitivity: "base" }));
48
51
  }
49
52
  const LOCAL_STARTER_ID_TO_DIRECTORY = {
50
- "starter-research": "research",
51
- "starter-engineering": "engineering",
52
- "starter-information-hub": "information-hub"
53
+ "research": "research",
54
+ "engineering": "engineering",
55
+ "information-hub": "information-hub"
53
56
  };
54
57
  function localStartersRoot() {
55
58
  return resolve(cliPackageRoot, "..", "..", "starters");
56
59
  }
57
60
  function resolveLocalStarterArtifactRoot(id) {
58
- const directory = LOCAL_STARTER_ID_TO_DIRECTORY[id];
61
+ const directory = LOCAL_STARTER_ID_TO_DIRECTORY[normalizeTreeseedTemplateId(id)];
59
62
  if (!directory) {
60
63
  return null;
61
64
  }
@@ -124,11 +127,13 @@ function validateTemplatePlaceholders(definition) {
124
127
  }
125
128
  }
126
129
  function normalizeTemplateProduct(remoteProduct) {
127
- const artifactRoot = resolve(localTemplateArtifactsRoot, remoteProduct.id);
130
+ const id = normalizeTreeseedTemplateId(remoteProduct.id);
131
+ const artifactRoot = resolve(localTemplateArtifactsRoot, id);
128
132
  const source = remoteProduct.fulfillment.source;
129
133
  return {
130
134
  ...remoteProduct,
131
- contentPath: source.kind === "git" ? `${source.repoUrl}#${remoteProduct.id}` : `r2://${source.bucket ?? "bucket"}/${source.objectKey}#${remoteProduct.id}`,
135
+ id,
136
+ contentPath: source.kind === "git" ? `${source.repoUrl}#${id}` : `r2://${source.bucket ?? "bucket"}/${source.objectKey}#${id}`,
132
137
  artifactRoot,
133
138
  artifactManifestPath: resolve(artifactRoot, "template.config.json"),
134
139
  templateRoot: resolve(artifactRoot, "template"),
@@ -364,7 +369,8 @@ async function listTemplateProducts(options = {}) {
364
369
  });
365
370
  }
366
371
  async function resolveTemplateProduct(id, options = {}) {
367
- const product = (await listTemplateProducts(options)).find((entry) => entry.id === id);
372
+ const normalizedId = normalizeTreeseedTemplateId(id);
373
+ const product = (await listTemplateProducts(options)).find((entry) => entry.id === normalizedId);
368
374
  if (!product) {
369
375
  throw new Error(`Unable to resolve remote template product "${id}".`);
370
376
  }
@@ -524,6 +530,7 @@ async function syncTemplateProject(siteRoot, options = {}) {
524
530
  if (!check) {
525
531
  writeTemplateState(siteRoot, {
526
532
  ...state,
533
+ templateId: definition.product.id,
527
534
  templateVersion: definition.product.templateVersion,
528
535
  sourceRef: definition.product.fulfillment.source.ref,
529
536
  lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -0,0 +1,25 @@
1
+ export interface TreeseedVerificationCacheEntry {
2
+ key: string;
3
+ repoName: string;
4
+ repoPath: string;
5
+ headSha: string;
6
+ command: string;
7
+ status: 'passed' | 'failed';
8
+ createdAt: string;
9
+ durationMs: number;
10
+ logsPath?: string | null;
11
+ }
12
+ export interface TreeseedVerificationCacheInput {
13
+ workspaceRoot: string;
14
+ repoName: string;
15
+ repoPath: string;
16
+ command: string;
17
+ verifyMode: string;
18
+ env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
19
+ }
20
+ export declare function treeseedVerificationCacheKey(input: TreeseedVerificationCacheInput): {
21
+ key: string;
22
+ headSha: string;
23
+ };
24
+ export declare function readTreeseedVerificationCache(input: TreeseedVerificationCacheInput): TreeseedVerificationCacheEntry | null;
25
+ export declare function writeTreeseedVerificationCache(input: TreeseedVerificationCacheInput, durationMs: number): TreeseedVerificationCacheEntry | null;
@@ -0,0 +1,71 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { headCommit } from "./git-workflow.js";
5
+ function sha256(value) {
6
+ return createHash("sha256").update(value).digest("hex");
7
+ }
8
+ function fileHash(path) {
9
+ if (!existsSync(path)) return null;
10
+ return sha256(readFileSync(path));
11
+ }
12
+ function cacheEnabled(env = process.env) {
13
+ const value = String(env.TREESEED_VERIFY_CACHE ?? "").trim().toLowerCase();
14
+ if (value === "0" || value === "false" || value === "off") return false;
15
+ if (env.GITHUB_ACTIONS === "true") return value === "1" || value === "true" || value === "on";
16
+ return true;
17
+ }
18
+ function treeseedVerificationCacheKey(input) {
19
+ const headSha = headCommit(input.repoPath);
20
+ const payload = {
21
+ repoPath: resolve(input.repoPath),
22
+ headSha,
23
+ packageJson: fileHash(resolve(input.repoPath, "package.json")),
24
+ packageLock: fileHash(resolve(input.repoPath, "package-lock.json")),
25
+ command: input.command,
26
+ nodeMajor: process.versions.node.split(".")[0],
27
+ verifyMode: input.verifyMode
28
+ };
29
+ return { key: sha256(JSON.stringify(payload)), headSha };
30
+ }
31
+ function cachePath(input, key) {
32
+ return resolve(input.workspaceRoot, ".treeseed", "cache", "verification", `${key}.json`);
33
+ }
34
+ function readTreeseedVerificationCache(input) {
35
+ if (!cacheEnabled(input.env)) return null;
36
+ const { key, headSha } = treeseedVerificationCacheKey(input);
37
+ const path = cachePath(input, key);
38
+ if (!existsSync(path)) return null;
39
+ try {
40
+ const entry = JSON.parse(readFileSync(path, "utf8"));
41
+ if (entry.key !== key || entry.headSha !== headSha || entry.status !== "passed") return null;
42
+ return entry;
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
47
+ function writeTreeseedVerificationCache(input, durationMs) {
48
+ if (!cacheEnabled(input.env)) return null;
49
+ const { key, headSha } = treeseedVerificationCacheKey(input);
50
+ const path = cachePath(input, key);
51
+ const entry = {
52
+ key,
53
+ repoName: input.repoName,
54
+ repoPath: resolve(input.repoPath),
55
+ headSha,
56
+ command: input.command,
57
+ status: "passed",
58
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
59
+ durationMs,
60
+ logsPath: null
61
+ };
62
+ mkdirSync(dirname(path), { recursive: true });
63
+ writeFileSync(path, `${JSON.stringify(entry, null, 2)}
64
+ `, "utf8");
65
+ return entry;
66
+ }
67
+ export {
68
+ readTreeseedVerificationCache,
69
+ treeseedVerificationCacheKey,
70
+ writeTreeseedVerificationCache
71
+ };
@@ -128,6 +128,14 @@ function dependencySpec(packageJson, field, packageName) {
128
128
  const value = deps[packageName];
129
129
  return typeof value === "string" ? value : null;
130
130
  }
131
+ function dependencySpecsMatch(manifestSpec, lockSpec) {
132
+ if (lockSpec === manifestSpec) return true;
133
+ const manifestVersion = manifestSpec.replace(/^[~^]/u, "");
134
+ const lockRef = lockSpec.includes("#") ? lockSpec.slice(lockSpec.lastIndexOf("#") + 1) : null;
135
+ return Boolean(
136
+ lockRef && manifestVersion.includes("-dev.") && lockRef === manifestVersion && /^(?:github:|git\+https:\/\/github\.com\/|git\+ssh:\/\/git@github\.com[:/])/u.test(lockSpec)
137
+ );
138
+ }
131
139
  function normalizedPathValue(value) {
132
140
  return value.replaceAll("\\", "/").replace(/^\.\//u, "").replace(/\/$/u, "");
133
141
  }
@@ -175,7 +183,7 @@ function collectPackageLockConsistencyIssues(filePath, packageJson, packages, wo
175
183
  const manifestSpec = dependencySpec(packageJson, field, packageName);
176
184
  if (!manifestSpec) continue;
177
185
  const lockSpec = dependencySpec(rootLockEntry ?? {}, field, packageName);
178
- if (lockSpec !== manifestSpec) {
186
+ if (!lockSpec || !dependencySpecsMatch(manifestSpec, lockSpec)) {
179
187
  issues.push({
180
188
  filePath,
181
189
  packageName,
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { changedWorkspacePackages, publishableWorkspacePackages, run, sortWorkspacePackages, workspacePackages, workspaceRoot } from "./workspace-tools.js";
4
4
  const MERGE_CONFLICT_EXIT_CODE = 12;
5
- const TREESEED_PUBLIC_RELEASE_PACKAGE_NAMES = ["@treeseed/sdk", "@treeseed/core", "@treeseed/cli", "@treeseed/agent"];
5
+ const TREESEED_PUBLIC_RELEASE_PACKAGE_NAMES = ["@treeseed/sdk", "@treeseed/ui", "@treeseed/core", "@treeseed/admin", "@treeseed/cli", "@treeseed/agent"];
6
6
  function parseSemver(version) {
7
7
  const match = String(version).trim().match(/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/);
8
8
  if (!match) {
@@ -177,7 +177,8 @@ function run(command, args, options = {}) {
177
177
  env: { ...process.env, ...options.env ?? {} },
178
178
  stdio: options.capture ? "pipe" : "inherit",
179
179
  encoding: "utf8",
180
- timeout: options.timeoutMs
180
+ timeout: options.timeoutMs,
181
+ maxBuffer: options.maxBuffer ?? 1024 * 1024 * 32
181
182
  });
182
183
  if (result.status !== 0) {
183
184
  const message = (result.error?.message ? `${result.error.message}
@@ -177,9 +177,10 @@ export interface TreeseedCloudflarePagesConfig {
177
177
  previewProjectName?: string;
178
178
  productionBranch?: string;
179
179
  stagingBranch?: string;
180
+ buildCommand?: string;
180
181
  buildOutputDir?: string;
181
182
  }
182
- export type TreeseedHostingKind = 'market_control_plane' | 'hosted_project' | 'self_hosted_project';
183
+ export type TreeseedHostingKind = 'treeseed_control_plane' | 'hosted_project' | 'self_hosted_project';
183
184
  export type TreeseedHostingRegistration = 'optional' | 'none';
184
185
  export type TreeseedHubMode = 'treeseed_hosted' | 'customer_hosted';
185
186
  export type TreeseedRuntimeMode = 'none' | 'byo_attached' | 'treeseed_managed';
@@ -232,6 +233,15 @@ export interface TreeseedManagedServiceRailwayConfig {
232
233
  healthcheckIntervalSeconds?: number;
233
234
  restartPolicy?: string;
234
235
  runtimeMode?: string;
236
+ resourceType?: string;
237
+ environmentVariable?: string;
238
+ serviceTargets?: string[];
239
+ volumeMountPath?: string;
240
+ runnerPool?: {
241
+ bootstrapCount?: number;
242
+ maxRunners?: number;
243
+ volumeMountPath?: string;
244
+ };
235
245
  schedule?: string | string[];
236
246
  }
237
247
  export interface TreeseedManagedServiceConfig {
@@ -248,6 +258,14 @@ export interface TreeseedManagedServicesConfig {
248
258
  api?: TreeseedManagedServiceConfig;
249
259
  [key: string]: TreeseedManagedServiceConfig | undefined;
250
260
  }
261
+ export interface TreeseedPublicTreeDxFederationConfig {
262
+ railway?: {
263
+ nodePool?: {
264
+ bootstrapCount?: number;
265
+ maxNodes?: number;
266
+ };
267
+ };
268
+ }
251
269
  export interface TreeseedPlatformSurfacesConfig {
252
270
  web?: TreeseedPlatformSurfaceConfig;
253
271
  api?: TreeseedPlatformSurfaceConfig;
@@ -278,6 +296,14 @@ export interface TreeseedExportConfig {
278
296
  ignore?: string[];
279
297
  bundledPaths?: string[];
280
298
  }
299
+ export interface TreeseedApiConnectionConfig {
300
+ proxyPrefix?: string;
301
+ localBaseUrl?: string;
302
+ environments?: Partial<Record<'local' | 'staging' | 'prod', {
303
+ baseUrl?: string;
304
+ domain?: string;
305
+ }>>;
306
+ }
281
307
  export interface TreeseedDeployConfig {
282
308
  name: string;
283
309
  slug: string;
@@ -302,6 +328,11 @@ export interface TreeseedDeployConfig {
302
328
  providers: TreeseedProviderSelections;
303
329
  surfaces?: TreeseedPlatformSurfacesConfig;
304
330
  services?: TreeseedManagedServicesConfig;
331
+ publicTreeDxFederation?: TreeseedPublicTreeDxFederationConfig;
332
+ connections?: {
333
+ api?: TreeseedApiConnectionConfig;
334
+ [key: string]: unknown;
335
+ };
305
336
  processing?: TreeseedProcessingConfig;
306
337
  capacityProviders?: Record<string, CapacityProviderRegistrationRequest>;
307
338
  smtp?: {
@@ -181,12 +181,12 @@ function parseHostingConfig(value) {
181
181
  }
182
182
  return {
183
183
  kind: optionalEnum(record.kind, "hosting.kind", [
184
- "market_control_plane",
184
+ "treeseed_control_plane",
185
185
  "hosted_project",
186
186
  "self_hosted_project"
187
187
  ]) ?? "self_hosted_project",
188
188
  registration: optionalEnum(record.registration, "hosting.registration", ["optional", "none"]) ?? "none",
189
- marketBaseUrl: optionalString(process.env.TREESEED_MARKET_API_BASE_URL) ?? optionalString(record.marketBaseUrl),
189
+ marketBaseUrl: optionalString(process.env.TREESEED_API_BASE_URL) ?? optionalString(record.marketBaseUrl),
190
190
  teamId: optionalString(process.env.TREESEED_HOSTING_TEAM_ID) ?? optionalString(record.teamId),
191
191
  projectId: optionalString(process.env.TREESEED_PROJECT_ID) ?? optionalString(record.projectId)
192
192
  };
@@ -198,12 +198,12 @@ function normalizePlanesFromLegacyHosting(hosting) {
198
198
  runtime: { mode: "none", registration: "none" }
199
199
  };
200
200
  }
201
- if (hosting.kind === "market_control_plane" || hosting.kind === "hosted_project") {
201
+ if (hosting.kind === "treeseed_control_plane" || hosting.kind === "hosted_project") {
202
202
  return {
203
203
  hub: { mode: "treeseed_hosted" },
204
204
  runtime: {
205
205
  mode: "treeseed_managed",
206
- registration: hosting.kind === "market_control_plane" ? "none" : hosting.registration ?? "none",
206
+ registration: hosting.kind === "treeseed_control_plane" ? "none" : hosting.registration ?? "none",
207
207
  marketBaseUrl: hosting.marketBaseUrl,
208
208
  teamId: hosting.teamId,
209
209
  projectId: hosting.projectId
@@ -262,7 +262,7 @@ function parseRuntimeConfig(value, fallback) {
262
262
  return {
263
263
  mode: optionalEnum(record.mode, "runtime.mode", ["none", "byo_attached", "treeseed_managed"]) ?? fallback.mode,
264
264
  registration: optionalEnum(record.registration, "runtime.registration", ["optional", "required", "none"]) ?? fallback.registration ?? "none",
265
- marketBaseUrl: optionalString(process.env.TREESEED_MARKET_API_BASE_URL) ?? fallback.marketBaseUrl,
265
+ marketBaseUrl: optionalString(process.env.TREESEED_API_BASE_URL) ?? fallback.marketBaseUrl,
266
266
  teamId: optionalString(process.env.TREESEED_HOSTING_TEAM_ID) ?? fallback.teamId,
267
267
  projectId: optionalString(process.env.TREESEED_PROJECT_ID) ?? fallback.projectId
268
268
  };
@@ -378,6 +378,21 @@ function parseManagedServiceConfig(value, label) {
378
378
  ),
379
379
  restartPolicy: optionalString(railway.restartPolicy),
380
380
  runtimeMode: optionalString(railway.runtimeMode),
381
+ resourceType: optionalString(railway.resourceType),
382
+ environmentVariable: optionalString(railway.environmentVariable),
383
+ serviceTargets: optionalStringArray(railway.serviceTargets, `${label}.railway.serviceTargets`),
384
+ volumeMountPath: optionalString(railway.volumeMountPath),
385
+ runnerPool: optionalRecord(railway.runnerPool, `${label}.railway.runnerPool`) ? {
386
+ bootstrapCount: optionalPositiveNumber(
387
+ optionalRecord(railway.runnerPool, `${label}.railway.runnerPool`)?.bootstrapCount,
388
+ `${label}.railway.runnerPool.bootstrapCount`
389
+ ),
390
+ maxRunners: optionalPositiveNumber(
391
+ optionalRecord(railway.runnerPool, `${label}.railway.runnerPool`)?.maxRunners,
392
+ `${label}.railway.runnerPool.maxRunners`
393
+ ),
394
+ volumeMountPath: optionalString(optionalRecord(railway.runnerPool, `${label}.railway.runnerPool`)?.volumeMountPath)
395
+ } : void 0,
381
396
  schedule: Array.isArray(railway.schedule) ? railway.schedule.map((entry) => optionalString(entry)).filter(Boolean) : optionalString(railway.schedule)
382
397
  },
383
398
  local: parseLocalRuntimeConfig(record.local, `${label}.local`),
@@ -388,6 +403,28 @@ function parseManagedServiceConfig(value, label) {
388
403
  }
389
404
  };
390
405
  }
406
+ function parsePublicTreeDxFederationConfig(value) {
407
+ const record = optionalRecord(value, "publicTreeDxFederation");
408
+ if (!record) {
409
+ return void 0;
410
+ }
411
+ const railway = optionalRecord(record.railway, "publicTreeDxFederation.railway") ?? {};
412
+ const nodePool = optionalRecord(railway.nodePool, "publicTreeDxFederation.railway.nodePool") ?? {};
413
+ return {
414
+ railway: {
415
+ nodePool: {
416
+ bootstrapCount: optionalPositiveNumber(
417
+ nodePool.bootstrapCount,
418
+ "publicTreeDxFederation.railway.nodePool.bootstrapCount"
419
+ ),
420
+ maxNodes: optionalPositiveNumber(
421
+ nodePool.maxNodes,
422
+ "publicTreeDxFederation.railway.nodePool.maxNodes"
423
+ )
424
+ }
425
+ }
426
+ };
427
+ }
391
428
  function parseManagedServicesConfig(value) {
392
429
  const record = optionalRecord(value, "services");
393
430
  if (!record) {
@@ -420,6 +457,31 @@ function parseProcessingConfig(value, services) {
420
457
  requiredCapabilities: optionalStringArray(record.requiredCapabilities, "processing.requiredCapabilities")
421
458
  };
422
459
  }
460
+ function parseConnectionsConfig(value) {
461
+ const record = optionalRecord(value, "connections") ?? {};
462
+ const api = optionalRecord(record.api, "connections.api");
463
+ if (!api) {
464
+ return Object.keys(record).length > 0 ? record : void 0;
465
+ }
466
+ const environmentsRaw = optionalRecord(api.environments, "connections.api.environments") ?? {};
467
+ const environments = Object.fromEntries(
468
+ ["local", "staging", "prod"].map((scope) => {
469
+ const environment = optionalRecord(environmentsRaw[scope], `connections.api.environments.${scope}`);
470
+ return [scope, environment ? {
471
+ baseUrl: optionalString(environment.baseUrl),
472
+ domain: optionalString(environment.domain)
473
+ } : void 0];
474
+ }).filter(([, environment]) => environment)
475
+ );
476
+ return {
477
+ ...record,
478
+ api: {
479
+ proxyPrefix: optionalString(api.proxyPrefix),
480
+ localBaseUrl: optionalString(api.localBaseUrl),
481
+ environments
482
+ }
483
+ };
484
+ }
423
485
  function inferManagedRuntimeFromServices(services) {
424
486
  return Object.values(services ?? {}).some(
425
487
  (service) => service && service.enabled !== false && (service.provider ?? "railway") === "railway"
@@ -542,7 +604,7 @@ function parseDeployConfig(raw) {
542
604
  const turnstile = optionalRecord(parsed.turnstile, "turnstile") ?? {};
543
605
  optionalBoolean(turnstile.enabled, "turnstile.enabled");
544
606
  const normalizedHosting = normalizeLegacyHostingFromPlanes(hub, runtime);
545
- const compatibilityHosting = hosting?.kind === "market_control_plane" ? { ...hosting, registration: "none" } : hosting && !parsed.hub && !parsed.runtime ? hosting : normalizedHosting;
607
+ const compatibilityHosting = hosting?.kind === "treeseed_control_plane" ? { ...hosting, registration: "none" } : hosting && !parsed.hub && !parsed.runtime ? hosting : normalizedHosting;
546
608
  return {
547
609
  name: expectString(parsed.name, "name"),
548
610
  slug: expectString(parsed.slug, "slug"),
@@ -561,10 +623,11 @@ function parseDeployConfig(raw) {
561
623
  d1Binding: optionalString(cloudflare.d1Binding),
562
624
  queueBinding: optionalString(cloudflare.queueBinding),
563
625
  pages: cloudflare.pages === void 0 ? void 0 : {
564
- projectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME) ?? optionalString(cloudflarePages.projectName),
565
- previewProjectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME) ?? optionalString(cloudflarePages.previewProjectName),
626
+ projectName: optionalString(cloudflarePages.projectName) ?? optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME),
627
+ previewProjectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME) ?? optionalString(cloudflarePages.previewProjectName) ?? optionalString(cloudflarePages.projectName) ?? optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME),
566
628
  productionBranch: optionalString(cloudflarePages.productionBranch) ?? "main",
567
629
  stagingBranch: optionalString(cloudflarePages.stagingBranch) ?? "staging",
630
+ buildCommand: optionalString(cloudflarePages.buildCommand),
568
631
  buildOutputDir: optionalString(cloudflarePages.buildOutputDir)
569
632
  },
570
633
  r2: cloudflare.r2 === void 0 ? void 0 : {
@@ -580,6 +643,8 @@ function parseDeployConfig(raw) {
580
643
  providers: parseProviderSelections(parsed.providers),
581
644
  surfaces: parsePlatformSurfacesConfig(parsed.surfaces),
582
645
  services,
646
+ publicTreeDxFederation: parsePublicTreeDxFederationConfig(parsed.publicTreeDxFederation),
647
+ connections: parseConnectionsConfig(parsed.connections),
583
648
  processing,
584
649
  capacityProviders: optionalRecord(parsed.capacityProviders, "capacityProviders"),
585
650
  smtp: {