@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
@@ -0,0 +1,104 @@
1
+ export declare const TREESEED_RECONCILE_RUN_MODEL: readonly ["refresh", "plan", "validate", "apply", "refresh", "verify", "persist"];
2
+ export declare const TREESEED_RECONCILE_ACTION_KINDS: readonly ["noop", "create", "update", "replace", "delete", "adopt", "rename", "reattach", "retain", "taint", "blocked"];
3
+ export type TreeseedCanonicalReconcilePhase = typeof TREESEED_RECONCILE_RUN_MODEL[number];
4
+ export type TreeseedCanonicalReconcileActionKind = typeof TREESEED_RECONCILE_ACTION_KINDS[number];
5
+ export interface TreeseedCanonicalGraphNode {
6
+ id: string;
7
+ provider?: string | null;
8
+ type?: string | null;
9
+ owner?: string | null;
10
+ environment?: string | null;
11
+ spec?: unknown;
12
+ state?: unknown;
13
+ locators?: Record<string, unknown>;
14
+ metadata?: Record<string, unknown>;
15
+ }
16
+ export interface TreeseedCanonicalDrift {
17
+ id: string;
18
+ resourceId?: string | null;
19
+ severity?: 'info' | 'warning' | 'blocking';
20
+ reason: string;
21
+ expected?: unknown;
22
+ observed?: unknown;
23
+ provider?: string | null;
24
+ type?: string | null;
25
+ }
26
+ export interface TreeseedCanonicalAction {
27
+ id: string;
28
+ kind: TreeseedCanonicalReconcileActionKind;
29
+ resourceId: string;
30
+ reason: string;
31
+ provider?: string | null;
32
+ type?: string | null;
33
+ before?: unknown;
34
+ after?: unknown;
35
+ }
36
+ export interface TreeseedCanonicalPostcondition {
37
+ id: string;
38
+ resourceId: string;
39
+ description: string;
40
+ source?: 'api' | 'cli' | 'sdk' | 'http' | 'local' | 'derived';
41
+ required?: boolean;
42
+ ok: boolean;
43
+ issues: string[];
44
+ expected?: unknown;
45
+ observed?: unknown;
46
+ }
47
+ export interface TreeseedCanonicalLiveVerification {
48
+ ok: boolean;
49
+ source?: string;
50
+ checkedAt?: string | null;
51
+ issues: string[];
52
+ checks?: unknown[];
53
+ }
54
+ export interface TreeseedCanonicalReconcileReport {
55
+ desiredGraph: TreeseedCanonicalGraphNode[];
56
+ observedGraph: TreeseedCanonicalGraphNode[];
57
+ stateGraph: TreeseedCanonicalGraphNode[];
58
+ diff: TreeseedCanonicalDrift[];
59
+ actions: TreeseedCanonicalAction[];
60
+ postconditions: TreeseedCanonicalPostcondition[];
61
+ selectedResources: string[];
62
+ skippedResources: Array<{
63
+ id: string;
64
+ reason: string;
65
+ }>;
66
+ blockedDrift: TreeseedCanonicalDrift[];
67
+ providerLimitations: TreeseedCanonicalDrift[];
68
+ retainedResources: TreeseedCanonicalGraphNode[];
69
+ destroyedResources: TreeseedCanonicalGraphNode[];
70
+ liveVerification: TreeseedCanonicalLiveVerification;
71
+ ok: boolean;
72
+ }
73
+ export interface CreateTreeseedCanonicalReconcileReportInput {
74
+ desiredGraph?: TreeseedCanonicalGraphNode[];
75
+ observedGraph?: TreeseedCanonicalGraphNode[];
76
+ stateGraph?: TreeseedCanonicalGraphNode[];
77
+ diff?: TreeseedCanonicalDrift[];
78
+ actions?: TreeseedCanonicalAction[];
79
+ postconditions?: TreeseedCanonicalPostcondition[];
80
+ selectedResources?: string[];
81
+ skippedResources?: Array<{
82
+ id: string;
83
+ reason: string;
84
+ }>;
85
+ blockedDrift?: TreeseedCanonicalDrift[];
86
+ providerLimitations?: TreeseedCanonicalDrift[];
87
+ retainedResources?: TreeseedCanonicalGraphNode[];
88
+ destroyedResources?: TreeseedCanonicalGraphNode[];
89
+ liveVerification?: Partial<TreeseedCanonicalLiveVerification>;
90
+ }
91
+ export declare function createTreeseedCanonicalReconcileReport(input?: CreateTreeseedCanonicalReconcileReportInput): TreeseedCanonicalReconcileReport;
92
+ export declare function assertTreeseedCanonicalReconcileSuccess(report: TreeseedCanonicalReconcileReport): void;
93
+ export declare function summarizeTreeseedCanonicalReconcileReport(report: TreeseedCanonicalReconcileReport): {
94
+ ok: boolean;
95
+ desired: number;
96
+ observed: number;
97
+ actions: number;
98
+ postconditions: number;
99
+ blockedDrift: number;
100
+ providerLimitations: number;
101
+ retainedResources: number;
102
+ destroyedResources: number;
103
+ liveVerificationOk: boolean;
104
+ };
@@ -0,0 +1,100 @@
1
+ const TREESEED_RECONCILE_RUN_MODEL = [
2
+ "refresh",
3
+ "plan",
4
+ "validate",
5
+ "apply",
6
+ "refresh",
7
+ "verify",
8
+ "persist"
9
+ ];
10
+ const TREESEED_RECONCILE_ACTION_KINDS = [
11
+ "noop",
12
+ "create",
13
+ "update",
14
+ "replace",
15
+ "delete",
16
+ "adopt",
17
+ "rename",
18
+ "reattach",
19
+ "retain",
20
+ "taint",
21
+ "blocked"
22
+ ];
23
+ function hasBlockingAction(actions) {
24
+ return actions.some((action) => action.kind === "blocked");
25
+ }
26
+ function liveVerificationOk(input, postconditions) {
27
+ if (input?.ok === false) return false;
28
+ if ((input?.issues ?? []).length > 0) return false;
29
+ return postconditions.every((postcondition) => postcondition.required === false || postcondition.ok);
30
+ }
31
+ function createTreeseedCanonicalReconcileReport(input = {}) {
32
+ const desiredGraph = input.desiredGraph ?? [];
33
+ const observedGraph = input.observedGraph ?? [];
34
+ const stateGraph = input.stateGraph ?? [];
35
+ const diff = input.diff ?? [];
36
+ const actions = input.actions ?? [];
37
+ const postconditions = input.postconditions ?? [];
38
+ const selectedResources = input.selectedResources ?? desiredGraph.map((node) => node.id);
39
+ const skippedResources = input.skippedResources ?? [];
40
+ const blockedDrift = input.blockedDrift ?? diff.filter((entry) => entry.severity === "blocking");
41
+ const providerLimitations = input.providerLimitations ?? [];
42
+ const retainedResources = input.retainedResources ?? [];
43
+ const destroyedResources = input.destroyedResources ?? [];
44
+ const liveVerification = {
45
+ ok: input.liveVerification?.ok ?? liveVerificationOk(input.liveVerification, postconditions),
46
+ source: input.liveVerification?.source ?? "sdk",
47
+ checkedAt: input.liveVerification?.checkedAt ?? null,
48
+ issues: input.liveVerification?.issues ?? [],
49
+ checks: input.liveVerification?.checks ?? []
50
+ };
51
+ const ok = liveVerification.ok && blockedDrift.length === 0 && providerLimitations.length === 0 && !hasBlockingAction(actions) && postconditions.every((postcondition) => postcondition.required === false || postcondition.ok);
52
+ return {
53
+ desiredGraph,
54
+ observedGraph,
55
+ stateGraph,
56
+ diff,
57
+ actions,
58
+ postconditions,
59
+ selectedResources,
60
+ skippedResources,
61
+ blockedDrift,
62
+ providerLimitations,
63
+ retainedResources,
64
+ destroyedResources,
65
+ liveVerification,
66
+ ok
67
+ };
68
+ }
69
+ function assertTreeseedCanonicalReconcileSuccess(report) {
70
+ if (report.ok) return;
71
+ const reasons = [
72
+ ...report.blockedDrift.map((entry) => `blocked drift ${entry.id}: ${entry.reason}`),
73
+ ...report.providerLimitations.map((entry) => `provider limitation ${entry.id}: ${entry.reason}`),
74
+ ...report.actions.filter((action) => action.kind === "blocked").map((action) => `blocked action ${action.id}: ${action.reason}`),
75
+ ...report.postconditions.filter((postcondition) => postcondition.required !== false && !postcondition.ok).map((postcondition) => `postcondition ${postcondition.id}: ${postcondition.issues.join("; ") || "failed"}`),
76
+ ...report.liveVerification.issues.map((issue) => `live verification: ${issue}`)
77
+ ];
78
+ throw new Error(`Treeseed reconciliation did not converge: ${reasons.join(" | ") || "unknown drift remained"}`);
79
+ }
80
+ function summarizeTreeseedCanonicalReconcileReport(report) {
81
+ return {
82
+ ok: report.ok,
83
+ desired: report.desiredGraph.length,
84
+ observed: report.observedGraph.length,
85
+ actions: report.actions.length,
86
+ postconditions: report.postconditions.length,
87
+ blockedDrift: report.blockedDrift.length,
88
+ providerLimitations: report.providerLimitations.length,
89
+ retainedResources: report.retainedResources.length,
90
+ destroyedResources: report.destroyedResources.length,
91
+ liveVerificationOk: report.liveVerification.ok
92
+ };
93
+ }
94
+ export {
95
+ TREESEED_RECONCILE_ACTION_KINDS,
96
+ TREESEED_RECONCILE_RUN_MODEL,
97
+ assertTreeseedCanonicalReconcileSuccess,
98
+ createTreeseedCanonicalReconcileReport,
99
+ summarizeTreeseedCanonicalReconcileReport
100
+ };
@@ -6,8 +6,8 @@ function stableHash(value) {
6
6
  return createHash("sha256").update(JSON.stringify(value)).digest("hex");
7
7
  }
8
8
  function railwayUnitTypeForServiceKey(serviceKey) {
9
- if (serviceKey === "marketOperationsRunner") {
10
- return "railway-service:market-operations-runner";
9
+ if (serviceKey === "operationsRunner") {
10
+ return "railway-service:operations-runner";
11
11
  }
12
12
  if (serviceKey === "workdayManager") {
13
13
  return "railway-service:workday-manager";
@@ -271,7 +271,7 @@ function loadTreeseedReconcileState(tenantRoot, target) {
271
271
  return {
272
272
  version: 1,
273
273
  target,
274
- dependencyGraphVersion: legacyState.reconcile?.dependencyGraphVersion ?? 1,
274
+ dependencyGraphVersion: legacyState.reconciliation?.dependencyGraphVersion ?? 1,
275
275
  units: { ...persistedUnits }
276
276
  };
277
277
  }
@@ -280,7 +280,7 @@ function writeTreeseedReconcileState(tenantRoot, reconcileState) {
280
280
  const legacyState = loadDeployState(tenantRoot, deployConfig, { target: reconcileState.target });
281
281
  writeDeployState(tenantRoot, {
282
282
  ...legacyState,
283
- reconcile: {
283
+ reconciliation: {
284
284
  version: reconcileState.version,
285
285
  dependencyGraphVersion: reconcileState.dependencyGraphVersion,
286
286
  targetKey: targetKey(reconcileState.target)
@@ -1,7 +1,7 @@
1
1
  const TRESEED_RECONCILE_UNIT_TYPES = [
2
2
  "web-ui",
3
3
  "api-runtime",
4
- "market-operations-runner-runtime",
4
+ "operations-runner-runtime",
5
5
  "workday-manager-runtime",
6
6
  "worker-runner-runtime",
7
7
  "edge-worker",
@@ -15,7 +15,7 @@ const TRESEED_RECONCILE_UNIT_TYPES = [
15
15
  "custom-domain:api",
16
16
  "dns-record",
17
17
  "railway-service:api",
18
- "railway-service:market-operations-runner",
18
+ "railway-service:operations-runner",
19
19
  "railway-service:workday-manager",
20
20
  "railway-service:worker-runner"
21
21
  ];
@@ -0,0 +1,20 @@
1
+ import { collectTreeseedDeploymentReadiness, formatTreeseedReadinessReport } from '../operations/services/deployment-readiness.js';
2
+ function arg(name) {
3
+ const index = process.argv.indexOf(name);
4
+ return index >= 0 ? process.argv[index + 1] : null;
5
+ }
6
+ const environment = (arg('--environment') ?? 'staging');
7
+ const strict = process.argv.includes('--strict');
8
+ const report = collectTreeseedDeploymentReadiness({
9
+ tenantRoot: process.cwd(),
10
+ environment,
11
+ });
12
+ if (process.argv.includes('--json')) {
13
+ console.log(JSON.stringify(report, null, 2));
14
+ }
15
+ else {
16
+ console.log(formatTreeseedReadinessReport(report));
17
+ }
18
+ if (strict && !report.ok) {
19
+ process.exitCode = 1;
20
+ }
@@ -0,0 +1,186 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, relative, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { parse, stringify } from 'yaml';
5
+ const check = process.argv.includes('--check');
6
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
7
+ const workspaceRoot = resolve(packageRoot, '../..');
8
+ const workspaceOpenApiPath = resolve(workspaceRoot, 'docs/api/openapi.yaml');
9
+ const packageOpenApiPath = resolve(packageRoot, 'docs/api/openapi.yaml');
10
+ const openApiPath = existsSync(workspaceOpenApiPath) ? workspaceOpenApiPath : packageOpenApiPath;
11
+ const workspaceOpenApiJsonPath = resolve(workspaceRoot, 'docs/api/openapi.json');
12
+ const packageOpenApiJsonPath = resolve(packageRoot, 'docs/api/openapi.json');
13
+ const outPath = resolve(packageRoot, 'src/treedx/generated/openapi-types.ts');
14
+ const openApi = parse(readFileSync(openApiPath, 'utf8'));
15
+ function refName(ref) {
16
+ return ref.split('/').pop() ?? ref;
17
+ }
18
+ function schemaRefType(ref) {
19
+ return `components['schemas']['${refName(ref)}']`;
20
+ }
21
+ function literal(value) {
22
+ return JSON.stringify(value);
23
+ }
24
+ function key(name) {
25
+ return /^[A-Za-z_$][\w$]*$/u.test(name) ? name : JSON.stringify(name);
26
+ }
27
+ function typeForSchema(schema) {
28
+ if (!schema || typeof schema !== 'object')
29
+ return 'unknown';
30
+ const s = schema;
31
+ if (typeof s.$ref === 'string')
32
+ return schemaRefType(s.$ref);
33
+ if ('const' in s)
34
+ return literal(s.const);
35
+ if (Array.isArray(s.enum))
36
+ return s.enum.map(literal).join(' | ') || 'never';
37
+ if (Array.isArray(s.oneOf))
38
+ return s.oneOf.map(typeForSchema).join(' | ') || 'unknown';
39
+ if (Array.isArray(s.anyOf))
40
+ return s.anyOf.map(typeForSchema).join(' | ') || 'unknown';
41
+ if (Array.isArray(s.allOf))
42
+ return s.allOf.map(typeForSchema).join(' & ') || 'unknown';
43
+ if (s.nullable === true)
44
+ return `${typeForSchema({ ...s, nullable: undefined })} | null`;
45
+ if (s.type === 'string')
46
+ return 'string';
47
+ if (s.type === 'integer' || s.type === 'number')
48
+ return 'number';
49
+ if (s.type === 'boolean')
50
+ return 'boolean';
51
+ if (s.type === 'null')
52
+ return 'null';
53
+ if (s.type === 'array')
54
+ return `${typeForSchema(s.items)}[]`;
55
+ if (s.type === 'object' || s.properties || s.additionalProperties !== undefined) {
56
+ const properties = (s.properties ?? {});
57
+ const required = new Set(Array.isArray(s.required) ? s.required.map(String) : []);
58
+ const parts = Object.entries(properties).map(([name, prop]) => {
59
+ const optional = required.has(name) ? '' : '?';
60
+ return `${key(name)}${optional}: ${typeForSchema(prop)};`;
61
+ });
62
+ if (s.additionalProperties === true) {
63
+ parts.push('[key: string]: unknown;');
64
+ }
65
+ else if (s.additionalProperties && typeof s.additionalProperties === 'object') {
66
+ parts.push(`[key: string]: ${typeForSchema(s.additionalProperties)};`);
67
+ }
68
+ return parts.length > 0 ? `{ ${parts.join(' ')} }` : 'Record<string, never>';
69
+ }
70
+ return 'unknown';
71
+ }
72
+ function parametersFor(operation, location) {
73
+ const params = Array.isArray(operation.parameters) ? operation.parameters : [];
74
+ const entries = params
75
+ .filter((param) => typeof param === 'object' && param !== null && param.in === location)
76
+ .map((param) => {
77
+ const name = String(param.name);
78
+ const optional = param.required === true ? '' : '?';
79
+ return `${key(name)}${optional}: ${typeForSchema(param.schema)};`;
80
+ });
81
+ return entries.length > 0 ? `{ ${entries.join(' ')} }` : 'never';
82
+ }
83
+ function requestBodyFor(operation) {
84
+ const body = operation.requestBody;
85
+ const content = body?.content ?? {};
86
+ const json = content['application/json']?.schema;
87
+ if (json)
88
+ return typeForSchema(json);
89
+ const octets = content['application/octet-stream']?.schema;
90
+ if (octets)
91
+ return 'ArrayBuffer | Uint8Array | Blob';
92
+ return 'never';
93
+ }
94
+ function responseFor(response) {
95
+ if (!response || typeof response !== 'object')
96
+ return 'unknown';
97
+ if (typeof response.$ref === 'string') {
98
+ const name = refName(response.$ref);
99
+ if (name === 'Error')
100
+ return "components['schemas']['TreeDxErrorEnvelope']";
101
+ if (name === 'Ok')
102
+ return "components['schemas']['TreeDxOkEnvelope']";
103
+ }
104
+ const r = response;
105
+ const content = r.content ?? {};
106
+ const json = content['application/json']?.schema;
107
+ if (json)
108
+ return typeForSchema(json);
109
+ const octets = content['application/octet-stream']?.schema;
110
+ if (octets)
111
+ return 'ArrayBuffer';
112
+ return 'unknown';
113
+ }
114
+ function operationType(operation) {
115
+ const responses = operation.responses ?? {};
116
+ const responseEntries = Object.entries(responses).map(([status, response]) => `${JSON.stringify(status)}: ${responseFor(response)};`);
117
+ return [
118
+ '{',
119
+ `parameters: { path: ${parametersFor(operation, 'path')}; query: ${parametersFor(operation, 'query')}; header: ${parametersFor(operation, 'header')}; };`,
120
+ `requestBody: ${requestBodyFor(operation)};`,
121
+ `responses: { ${responseEntries.join(' ')} };`,
122
+ '}',
123
+ ].join(' ');
124
+ }
125
+ const schemas = openApi.components?.schemas ?? {};
126
+ const schemaLines = Object.entries(schemas)
127
+ .sort(([a], [b]) => a.localeCompare(b))
128
+ .map(([name, schema]) => `${key(name)}: ${typeForSchema(schema)};`);
129
+ const operationEntries = [];
130
+ const pathLines = [];
131
+ for (const [path, methods] of Object.entries(openApi.paths ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
132
+ const methodLines = [];
133
+ for (const [method, operation] of Object.entries(methods).sort(([a], [b]) => a.localeCompare(b))) {
134
+ if (!operation?.operationId)
135
+ continue;
136
+ operationEntries.push([operation.operationId, operation]);
137
+ methodLines.push(`${method}: operations['${operation.operationId}'];`);
138
+ }
139
+ pathLines.push(`${JSON.stringify(path)}: { ${methodLines.join(' ')} };`);
140
+ }
141
+ const operationLines = operationEntries
142
+ .sort(([a], [b]) => a.localeCompare(b))
143
+ .map(([id, operation]) => `${key(id)}: ${operationType(operation)};`);
144
+ const generated = `// Generated from docs/api/openapi.yaml. Do not edit by hand.
145
+
146
+ export interface paths {
147
+ ${pathLines.map((line) => `\t${line}`).join('\n')}
148
+ }
149
+
150
+ export interface components {
151
+ \tschemas: {
152
+ ${schemaLines.map((line) => `\t\t${line}`).join('\n')}
153
+ \t};
154
+ }
155
+
156
+ export interface operations {
157
+ ${operationLines.map((line) => `\t${line}`).join('\n')}
158
+ }
159
+ `;
160
+ const current = (() => {
161
+ try {
162
+ return readFileSync(outPath, 'utf8');
163
+ }
164
+ catch {
165
+ return null;
166
+ }
167
+ })();
168
+ if (check && current !== generated) {
169
+ console.error(`${relative(process.cwd(), outPath)} is not up to date. Run npm run treedx:generate-types.`);
170
+ process.exit(1);
171
+ }
172
+ if (!check) {
173
+ mkdirSync(dirname(outPath), { recursive: true });
174
+ writeFileSync(outPath, generated, 'utf8');
175
+ for (const target of [workspaceOpenApiJsonPath, packageOpenApiJsonPath]) {
176
+ mkdirSync(dirname(target), { recursive: true });
177
+ writeFileSync(target, `${JSON.stringify(openApi, null, 2)}\n`, 'utf8');
178
+ }
179
+ if (openApiPath === workspaceOpenApiPath) {
180
+ mkdirSync(dirname(packageOpenApiPath), { recursive: true });
181
+ writeFileSync(packageOpenApiPath, stringify(openApi), 'utf8');
182
+ }
183
+ console.log(`Wrote ${relative(process.cwd(), outPath)}`);
184
+ console.log(`Wrote ${relative(process.cwd(), workspaceOpenApiJsonPath)}`);
185
+ console.log(`Wrote ${relative(process.cwd(), packageOpenApiJsonPath)}`);
186
+ }
@@ -0,0 +1,16 @@
1
+ import { runTreeseedOperationsRunnerSmoke } from '../operations/services/operations-runner-smoke.js';
2
+ function arg(name) {
3
+ const index = process.argv.indexOf(name);
4
+ return index >= 0 ? process.argv[index + 1] : null;
5
+ }
6
+ const environment = (arg('--environment') ?? 'staging') === 'prod' ? 'prod' : 'staging';
7
+ const report = await runTreeseedOperationsRunnerSmoke({
8
+ tenantRoot: process.cwd(),
9
+ environment,
10
+ baseUrl: arg('--base-url'),
11
+ timeoutMs: arg('--timeout-ms') ? Number(arg('--timeout-ms')) : undefined,
12
+ });
13
+ console.log(JSON.stringify(report, null, 2));
14
+ if (!report.ok) {
15
+ process.exitCode = 1;
16
+ }
@@ -101,5 +101,8 @@ assertNoLocalDependencyLinks();
101
101
  run('npm', ['run', 'lint']);
102
102
  scanDirectory(resolve(packageRoot, 'dist'));
103
103
  assertCleanDistArtifacts();
104
- run('npm', ['run', 'test:unit']);
104
+ run('npm', ['run', 'test:release']);
105
+ if (process.env.TREESEED_SDK_VERIFY_WORKFLOW_LIFECYCLE === '1') {
106
+ run('npm', ['run', 'test:workflow:lifecycle']);
107
+ }
105
108
  run('npm', ['run', 'test:smoke']);
@@ -36,8 +36,8 @@ function writeCatalogCache(root, endpoint, items) {
36
36
  }
37
37
 
38
38
  const starterTemplate = {
39
- id: 'starter-basic',
40
- displayName: 'TreeSeed Basic',
39
+ id: 'fixture-template',
40
+ displayName: 'Fixture Template',
41
41
  description: 'Starter',
42
42
  summary: 'Starter summary',
43
43
  status: 'live',
@@ -53,7 +53,7 @@ const starterTemplate = {
53
53
  fulfillment: {
54
54
  source: {
55
55
  repoUrl: 'https://example.com/repo.git',
56
- directory: 'templates/starter-basic',
56
+ directory: 'templates/fixture-template',
57
57
  ref: 'main',
58
58
  },
59
59
  hooksPolicy: 'builtin_only',
@@ -69,7 +69,7 @@ test('template registry reads the remote catalog from a configured file endpoint
69
69
 
70
70
  const remoteProducts = await listTemplateProducts({ cwd, env: {} });
71
71
  assert.equal(remoteProducts.length, 1);
72
- assert.equal(remoteProducts[0]?.id, 'starter-basic');
72
+ assert.equal(remoteProducts[0]?.id, 'fixture-template');
73
73
 
74
74
  writeCatalogCache(cwd, fallbackEndpoint, [starterTemplate]);
75
75
 
@@ -83,7 +83,7 @@ test('template registry reads the remote catalog from a configured file endpoint
83
83
  });
84
84
 
85
85
  assert.equal(cachedProducts.length, 1);
86
- assert.equal(cachedProducts[0]?.id, 'starter-basic');
86
+ assert.equal(cachedProducts[0]?.id, 'fixture-template');
87
87
  assert.equal(warnings.length, 1);
88
88
  assert.match(warnings[0], /Using cached template catalog/);
89
89
  });
@@ -94,7 +94,7 @@ test('template definition resolution rejects templates missing from the remote c
94
94
  const cwd = makeMachineConfigRoot(`file:${fixturePath}`);
95
95
 
96
96
  await assert.rejects(
97
- () => resolveTemplateDefinition('starter-basic', { cwd, env: {} }),
98
- /Unable to resolve remote template product "starter-basic"\./,
97
+ () => resolveTemplateDefinition('fixture-template', { cwd, env: {} }),
98
+ /Unable to resolve remote template product "fixture-template"\./,
99
99
  );
100
100
  });
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { pathToFileURL } from 'node:url';
3
- import { resolveScope, runProjectPlatformAction, } from '../operations/services/project-platform.js';
4
3
  const tenantRoot = process.cwd();
4
+ function writeStatus(message) {
5
+ process.stderr.write(`[tenant-workflow-action] ${message}\n`);
6
+ }
5
7
  function parseArgs(argv) {
6
8
  const parsed = {
7
9
  action: 'deploy_web',
@@ -65,17 +67,24 @@ async function main() {
65
67
  const options = parseArgs(process.argv.slice(2));
66
68
  process.env.TREESEED_WORKFLOW_ACTION = options.action;
67
69
  process.env.TREESEED_WORKFLOW_PLANE ||= 'web';
70
+ writeStatus(`start action=${options.action} environment=${options.environment ?? '(auto)'}`);
71
+ writeStatus('loading project platform module...');
72
+ const { resolveScope, runProjectPlatformAction } = await import('../operations/services/project-platform.js');
73
+ writeStatus('project platform module loaded.');
68
74
  const scope = resolveScope(options.environment);
75
+ writeStatus(`resolved scope=${scope}; running action...`);
69
76
  const result = await runProjectPlatformAction(options.action, {
70
77
  tenantRoot,
71
78
  scope,
72
79
  projectId: options.projectId ?? process.env.TREESEED_PROJECT_ID ?? null,
73
80
  previewId: options.previewId,
74
81
  dryRun: options.dryRun,
82
+ write: (line) => writeStatus(line),
75
83
  });
76
84
  if (result !== undefined) {
77
85
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
78
86
  }
87
+ writeStatus('complete.');
79
88
  }
80
89
  function isCliEntrypoint() {
81
90
  if (!process.argv[1]) {