@treeseed/sdk 0.6.6 → 0.6.8

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 (48) hide show
  1. package/dist/copilot.d.ts +15 -0
  2. package/dist/copilot.js +75 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +18 -0
  5. package/dist/managed-dependencies.d.ts +56 -0
  6. package/dist/managed-dependencies.js +668 -0
  7. package/dist/operations/providers/default.js +30 -1
  8. package/dist/operations/services/commit-message-provider.d.ts +33 -0
  9. package/dist/operations/services/commit-message-provider.js +319 -0
  10. package/dist/operations/services/config-runtime.js +41 -20
  11. package/dist/operations/services/git-remote-policy.d.ts +9 -0
  12. package/dist/operations/services/git-remote-policy.js +55 -0
  13. package/dist/operations/services/git-workflow.js +22 -3
  14. package/dist/operations/services/github-api.js +9 -4
  15. package/dist/operations/services/knowledge-coop-launch.js +4 -0
  16. package/dist/operations/services/local-dev.js +7 -2
  17. package/dist/operations/services/package-reference-policy.d.ts +70 -0
  18. package/dist/operations/services/package-reference-policy.js +314 -0
  19. package/dist/operations/services/project-platform.d.ts +4 -0
  20. package/dist/operations/services/project-platform.js +30 -4
  21. package/dist/operations/services/railway-deploy.d.ts +4 -1
  22. package/dist/operations/services/railway-deploy.js +76 -38
  23. package/dist/operations/services/repository-save-orchestrator.d.ts +172 -0
  24. package/dist/operations/services/repository-save-orchestrator.js +1462 -0
  25. package/dist/operations/services/workspace-dependency-mode.d.ts +70 -0
  26. package/dist/operations/services/workspace-dependency-mode.js +404 -0
  27. package/dist/operations/services/workspace-preflight.js +5 -0
  28. package/dist/operations/services/workspace-save.js +10 -6
  29. package/dist/operations-registry.js +5 -0
  30. package/dist/operations-types.d.ts +1 -0
  31. package/dist/platform/books-data.js +4 -1
  32. package/dist/platform/env.yaml +6 -3
  33. package/dist/reconcile/builtin-adapters.js +37 -7
  34. package/dist/scripts/cleanup-markdown.js +4 -0
  35. package/dist/scripts/publish-package.js +5 -0
  36. package/dist/scripts/tenant-workflow-action.js +11 -2
  37. package/dist/verification.js +24 -12
  38. package/dist/workflow/operations.d.ts +381 -55
  39. package/dist/workflow/operations.js +718 -258
  40. package/dist/workflow-state.d.ts +40 -1
  41. package/dist/workflow-state.js +220 -17
  42. package/dist/workflow-support.d.ts +3 -0
  43. package/dist/workflow-support.js +34 -0
  44. package/dist/workflow.d.ts +19 -3
  45. package/dist/workflow.js +3 -3
  46. package/dist/wrangler-d1.js +6 -1
  47. package/package.json +17 -1
  48. package/templates/github/deploy.workflow.yml +28 -13
@@ -4,6 +4,7 @@ import { spawnSync } from "node:child_process";
4
4
  import { loadCliDeployConfig } from "./runtime-tools.js";
5
5
  import { createPersistentDeployTarget, resolveTreeseedResourceIdentity } from "./deploy.js";
6
6
  import { runPrefixedCommand, sleep } from "./bootstrap-runner.js";
7
+ import { resolveTreeseedToolCommand } from "../../managed-dependencies.js";
7
8
  import {
8
9
  ensureRailwayEnvironment,
9
10
  ensureRailwayProject,
@@ -148,7 +149,7 @@ function isRailwayAlreadyExistsMessage(result) {
148
149
  return /already exists|already taken|duplicate|has already been taken/iu.test(railwayMessage(result));
149
150
  }
150
151
  function isRailwayTransientFailure(result) {
151
- return /timed out|failed to fetch|temporarily unavailable|econnreset|etimedout/iu.test(railwayMessage(result));
152
+ return /timed out|failed to fetch|temporarily unavailable|econnreset|etimedout|failed to stream build logs|failed to retrieve build log/iu.test(railwayMessage(result));
152
153
  }
153
154
  function sleepSync(milliseconds) {
154
155
  if (!Number.isFinite(milliseconds) || milliseconds <= 0) {
@@ -230,7 +231,11 @@ mutation TreeseedScheduleUpdate($id: String!, $name: String!, $schedule: String!
230
231
  }
231
232
  function runRailway(args, { cwd, capture = false, allowFailure = false, input, env } = {}) {
232
233
  const effectiveEnv = buildRailwayCommandEnv({ ...process.env, ...env ?? {} });
233
- const runWithEnv = (spawnEnv) => spawnSync("railway", args, {
234
+ const railway = resolveTreeseedToolCommand("railway", { env: effectiveEnv });
235
+ if (!railway) {
236
+ throw new Error("Railway CLI is unavailable.");
237
+ }
238
+ const runWithEnv = (spawnEnv) => spawnSync(railway.command, [...railway.argsPrefix, ...args], {
234
239
  cwd,
235
240
  stdio: input !== void 0 ? ["pipe", capture ? "pipe" : "inherit", capture ? "pipe" : "inherit"] : capture ? "pipe" : "inherit",
236
241
  encoding: "utf8",
@@ -243,34 +248,35 @@ function runRailway(args, { cwd, capture = false, allowFailure = false, input, e
243
248
  }
244
249
  return result;
245
250
  }
246
- function shellEscape(value) {
247
- return `'${String(value).replace(/'/gu, `'\\''`)}'`;
248
- }
249
251
  function setRailwaySecretVariable({ cwd, service, environment, key, value, env = process.env, capture = false, allowFailure = false }) {
250
252
  const effectiveEnv = buildRailwayCommandEnv({
251
253
  ...process.env,
252
- ...env ?? {},
253
- TREESEED_RAILWAY_SECRET_VALUE: value
254
+ ...env ?? {}
254
255
  });
255
- const command = [
256
- 'printf %s\\\\n "$TREESEED_RAILWAY_SECRET_VALUE"',
257
- "|",
258
- "railway variable set",
259
- "--service",
260
- shellEscape(service),
261
- "--environment",
262
- shellEscape(environment),
263
- "--stdin",
264
- "--skip-deploys",
265
- shellEscape(key)
266
- ].join(" ");
267
256
  let result = null;
268
257
  for (let attempt = 0; attempt < 3; attempt += 1) {
269
- result = spawnSync("bash", ["-lc", command], {
258
+ const railway = resolveTreeseedToolCommand("railway", { env: effectiveEnv });
259
+ if (!railway) {
260
+ throw new Error("Railway CLI is unavailable.");
261
+ }
262
+ result = spawnSync(railway.command, [
263
+ ...railway.argsPrefix,
264
+ "variable",
265
+ "set",
266
+ "--service",
267
+ service,
268
+ "--environment",
269
+ environment,
270
+ "--stdin",
271
+ "--skip-deploys",
272
+ key
273
+ ], {
270
274
  cwd,
271
- stdio: capture ? "pipe" : "inherit",
275
+ stdio: ["pipe", capture ? "pipe" : "inherit", capture ? "pipe" : "inherit"],
272
276
  encoding: "utf8",
273
- env: effectiveEnv
277
+ env: effectiveEnv,
278
+ input: `${value}
279
+ `
274
280
  });
275
281
  if (result.status === 0) {
276
282
  return result;
@@ -830,8 +836,19 @@ async function verifyRailwayScheduledJobs(tenantRoot, scope, { fetchImpl = fetch
830
836
  checks
831
837
  };
832
838
  }
833
- function planRailwayServiceDeploy(service) {
834
- const args = ["up", "--service", service.serviceName ?? service.serviceId, "--ci"];
839
+ function shouldAttachRailwayDeployLogs(env = process.env) {
840
+ return configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_ATTACH_LOGS") === "1";
841
+ }
842
+ function planRailwayServiceDeploy(service, { env = process.env } = {}) {
843
+ const args = [
844
+ "up",
845
+ "--service",
846
+ service.serviceName ?? service.serviceId,
847
+ shouldAttachRailwayDeployLogs(env) ? "--ci" : "--detach"
848
+ ];
849
+ if (service.projectId) {
850
+ args.push("--project", service.projectId);
851
+ }
835
852
  const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
836
853
  if (environmentName) {
837
854
  args.push("--environment", environmentName);
@@ -842,6 +859,24 @@ function planRailwayServiceDeploy(service) {
842
859
  cwd: service.rootDir
843
860
  };
844
861
  }
862
+ async function resolveRailwayDeployProjectContext(service, { env = process.env } = {}) {
863
+ if (service.projectId) {
864
+ return service;
865
+ }
866
+ const workspace = await resolveRailwayWorkspaceContext({ env });
867
+ const { project } = await ensureRailwayProject({
868
+ projectId: service.projectId,
869
+ projectName: service.projectName,
870
+ defaultEnvironmentName: service.railwayEnvironment,
871
+ env,
872
+ workspace: workspace.id
873
+ });
874
+ return {
875
+ ...service,
876
+ projectId: project.id,
877
+ projectName: project.name ?? service.projectName
878
+ };
879
+ }
845
880
  async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, service, { env = process.env } = {}) {
846
881
  const wantsInstanceConfig = service.buildCommand || service.startCommand || service.rootDir || service.healthcheckPath || service.healthcheckTimeoutSeconds !== null || service.healthcheckTimeoutSeconds !== void 0 || service.healthcheckIntervalSeconds !== null || service.healthcheckIntervalSeconds !== void 0 || service.restartPolicy || service.runtimeMode;
847
882
  if (!wantsInstanceConfig) {
@@ -907,32 +942,34 @@ async function deployRailwayService(tenantRoot, service, {
907
942
  prefix,
908
943
  env = process.env
909
944
  } = {}) {
910
- const plan = planRailwayServiceDeploy(service);
911
945
  if (dryRun) {
946
+ const plan2 = planRailwayServiceDeploy(service, { env });
912
947
  return {
913
948
  service: service.key,
914
949
  status: "planned",
915
- command: [plan.command, ...plan.args].join(" "),
916
- cwd: plan.cwd,
950
+ command: [plan2.command, ...plan2.args].join(" "),
951
+ cwd: plan2.cwd,
917
952
  publicBaseUrl: service.publicBaseUrl
918
953
  };
919
954
  }
955
+ const deployService = await resolveRailwayDeployProjectContext(service, { env });
956
+ const plan = planRailwayServiceDeploy(deployService, { env });
920
957
  const taskPrefix = prefix ?? {
921
- scope: normalizeScope(service.scope ?? service.railwayEnvironment ?? "railway"),
922
- system: service.key === "api" ? "api" : "agents",
923
- task: `${service.key}-railway-deploy`,
958
+ scope: normalizeScope(deployService.scope ?? deployService.railwayEnvironment ?? "railway"),
959
+ system: deployService.key === "api" ? "api" : "agents",
960
+ task: `${deployService.key}-railway-deploy`,
924
961
  stage: "deploy"
925
962
  };
926
963
  const commandEnv = buildRailwayCommandEnv({ ...process.env, ...env });
927
- if (service.buildCommand) {
928
- const buildResult = await runPrefixedCommand("bash", ["-lc", service.buildCommand], {
929
- cwd: service.rootDir,
964
+ if (deployService.buildCommand) {
965
+ const buildResult = await runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
966
+ cwd: deployService.rootDir,
930
967
  env: commandEnv,
931
968
  write,
932
969
  prefix: { ...taskPrefix, stage: "build" }
933
970
  });
934
971
  if (buildResult.status !== 0) {
935
- throw new Error(`Railway ${service.key} build command failed.`);
972
+ throw new Error(`Railway ${deployService.key} build command failed.`);
936
973
  }
937
974
  }
938
975
  let lastFailure = null;
@@ -952,22 +989,22 @@ async function deployRailwayService(tenantRoot, service, {
952
989
  throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
953
990
  }
954
991
  const backoffMs = 5e3 * attempt;
955
- const warning = `Railway deploy for ${service.serviceName ?? service.serviceId ?? service.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
992
+ const warning = `Railway deploy for ${deployService.serviceName ?? deployService.serviceId ?? deployService.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
956
993
  write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][retry] ${warning}`, "stderr") : console.warn(warning);
957
994
  await sleep(backoffMs);
958
995
  }
959
996
  if (lastFailure) {
960
997
  throw new Error(lastFailure.stderr?.trim() || lastFailure.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
961
998
  }
962
- const runtimeConfiguration = await syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, service, {
999
+ const runtimeConfiguration = await syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, deployService, {
963
1000
  env: commandEnv
964
1001
  });
965
1002
  return {
966
- service: service.key,
1003
+ service: deployService.key,
967
1004
  status: "deployed",
968
1005
  command: [plan.command, ...plan.args].join(" "),
969
1006
  cwd: plan.cwd,
970
- publicBaseUrl: service.publicBaseUrl,
1007
+ publicBaseUrl: deployService.publicBaseUrl,
971
1008
  runtimeConfiguration: runtimeConfiguration ? {
972
1009
  updated: runtimeConfiguration.updated,
973
1010
  healthcheckPath: runtimeConfiguration.instance.healthcheckPath,
@@ -986,6 +1023,7 @@ export {
986
1023
  ensureRailwayProjectExists,
987
1024
  ensureRailwayScheduledJobs,
988
1025
  ensureRailwayServiceExists,
1026
+ isRailwayTransientFailure,
989
1027
  isUsableRailwayToken,
990
1028
  planRailwayServiceDeploy,
991
1029
  resolveRailwayAuthToken,
@@ -0,0 +1,172 @@
1
+ import { type GitRemoteWriteMode } from './git-remote-policy.ts';
2
+ import { type CommitMessageContext, type CommitMessageProvider, type CommitMessageProviderMode } from './commit-message-provider.ts';
3
+ import { type DevDependencyReferenceMode, type GitDependencyProtocol } from './package-reference-policy.ts';
4
+ export type RepoKind = 'package' | 'project';
5
+ export type RepoBranchMode = 'package-release-main' | 'package-dev-save' | 'project-save';
6
+ export type SaveVerifyMode = 'action-first' | 'local-only' | 'skip';
7
+ export type SaveCommitMessageMode = CommitMessageProviderMode;
8
+ export type SaveDevVersionStrategy = 'prerelease';
9
+ export type ReleaseBumpLevel = 'major' | 'minor' | 'patch';
10
+ export type RepositorySaveNode = {
11
+ id: string;
12
+ name: string;
13
+ path: string;
14
+ relativePath: string;
15
+ kind: RepoKind;
16
+ branch: string | null;
17
+ branchMode: RepoBranchMode;
18
+ packageJsonPath: string | null;
19
+ packageJson: Record<string, unknown> | null;
20
+ scripts: Record<string, string>;
21
+ remoteUrl: string | null;
22
+ dependencies: string[];
23
+ dependents: string[];
24
+ submoduleDependencies: string[];
25
+ plannedVersion: string | null;
26
+ plannedTag: string | null;
27
+ plannedDependencySpec: string | null;
28
+ };
29
+ export type RepositorySaveReport = {
30
+ name: string;
31
+ path: string;
32
+ branch: string | null;
33
+ dirty: boolean;
34
+ created: boolean;
35
+ resumed: boolean;
36
+ merged: boolean;
37
+ verified: boolean;
38
+ committed: boolean;
39
+ pushed: boolean;
40
+ deletedLocal: boolean;
41
+ deletedRemote: boolean;
42
+ tagName: string | null;
43
+ commitSha: string | null;
44
+ skippedReason: string | null;
45
+ publishWait: Record<string, unknown> | null;
46
+ version: string | null;
47
+ dependencySpec: string | null;
48
+ devTagMetadata: string | null;
49
+ replacedDevTags: string[];
50
+ branchMode: RepoBranchMode;
51
+ verification: RepositoryVerificationResult | null;
52
+ install: RepositoryInstallResult | null;
53
+ lockfileValidation: RepositoryLockfileValidationResult | null;
54
+ commitMessage: string | null;
55
+ commitMessageProvider: 'cloudflare-workers-ai' | 'fallback' | null;
56
+ commitMessageFallbackUsed: boolean;
57
+ commitMessageError: string | null;
58
+ };
59
+ export type RepositoryVerificationResult = {
60
+ mode: SaveVerifyMode;
61
+ status: 'passed' | 'failed' | 'skipped';
62
+ primary: 'verify:action' | 'verify:local' | null;
63
+ fallbackUsed: boolean;
64
+ error: string | null;
65
+ };
66
+ export type RepositoryInstallResult = {
67
+ status: 'completed' | 'skipped';
68
+ attempts: number;
69
+ reason: string | null;
70
+ };
71
+ export type RepositoryLockfileValidationResult = {
72
+ status: 'passed' | 'failed' | 'skipped';
73
+ command: string | null;
74
+ issues: string[];
75
+ error: string | null;
76
+ };
77
+ export type RepositoryCommitMessageContext = CommitMessageContext;
78
+ export type RepositoryCommitMessageProvider = CommitMessageProvider;
79
+ export type RepositorySaveResult = {
80
+ mode: 'root-only' | 'recursive-workspace';
81
+ branch: string;
82
+ scope: 'local' | 'staging' | 'prod';
83
+ repos: RepositorySaveReport[];
84
+ rootRepo: RepositorySaveReport;
85
+ waves: string[][];
86
+ plannedVersions: Record<string, string>;
87
+ };
88
+ export type RepositorySavePlanRepo = {
89
+ id: string;
90
+ name: string;
91
+ path: string;
92
+ relativePath: string;
93
+ kind: RepoKind;
94
+ currentBranch: string | null;
95
+ targetBranch: string;
96
+ branchMode: RepoBranchMode;
97
+ dirty: boolean;
98
+ dependencies: string[];
99
+ dependents: string[];
100
+ submoduleDependencies: string[];
101
+ currentVersion: string | null;
102
+ plannedVersion: string | null;
103
+ plannedTag: string | null;
104
+ plannedDependencySpec: string | null;
105
+ remoteUrl: string | null;
106
+ commands: string[];
107
+ notes: string[];
108
+ };
109
+ export type RepositorySavePlanWave = {
110
+ index: number;
111
+ parallel: boolean;
112
+ repos: string[];
113
+ commands: Array<{
114
+ repo: string;
115
+ commands: string[];
116
+ }>;
117
+ };
118
+ export type RepositorySavePlan = {
119
+ mode: 'root-only' | 'recursive-workspace';
120
+ branch: string;
121
+ scope: 'local' | 'staging' | 'prod';
122
+ devDependencyReferenceMode: DevDependencyReferenceMode;
123
+ gitDependencyProtocol: GitDependencyProtocol;
124
+ verifyMode: SaveVerifyMode;
125
+ commitMessageMode: SaveCommitMessageMode;
126
+ repos: RepositorySavePlanRepo[];
127
+ rootRepo: RepositorySavePlanRepo;
128
+ waves: RepositorySavePlanWave[];
129
+ plannedVersions: Record<string, string>;
130
+ plannedSteps: Array<{
131
+ id: string;
132
+ description: string;
133
+ }>;
134
+ };
135
+ export type RepositorySaveOptions = {
136
+ root: string;
137
+ gitRoot: string;
138
+ branch: string;
139
+ message?: string;
140
+ bump?: ReleaseBumpLevel;
141
+ devVersionStrategy?: SaveDevVersionStrategy;
142
+ devDependencyReferenceMode?: DevDependencyReferenceMode;
143
+ gitDependencyProtocol?: GitDependencyProtocol;
144
+ gitRemoteWriteMode?: GitRemoteWriteMode;
145
+ verifyMode?: SaveVerifyMode;
146
+ commitMessageMode?: SaveCommitMessageMode;
147
+ commitMessageProvider?: RepositoryCommitMessageProvider;
148
+ workflowRunId?: string | null;
149
+ includeRoot?: boolean;
150
+ stablePackageRelease?: boolean;
151
+ onProgress?: (message: string, stream?: 'stdout' | 'stderr') => void;
152
+ };
153
+ export declare function nextDevVersion(version: string, branch: string, date?: Date): string;
154
+ export declare function discoverRepositorySaveNodes(root: string, gitRoot?: string, branch?: string, options?: {
155
+ stablePackageRelease?: boolean;
156
+ }): RepositorySaveNode[];
157
+ export declare function repositorySaveWaves(nodes: RepositorySaveNode[]): RepositorySaveNode[][];
158
+ export declare function planRepositorySave(options: RepositorySaveOptions): RepositorySavePlan;
159
+ export declare function refreshAndValidateRootWorkspaceLockfileForSave(options: {
160
+ root: string;
161
+ gitRoot?: string;
162
+ branch?: string | null;
163
+ onProgress?: (message: string, stream?: 'stdout' | 'stderr') => void;
164
+ }): Promise<{
165
+ install: RepositoryInstallResult | null;
166
+ lockfileValidation: RepositoryLockfileValidationResult | null;
167
+ }>;
168
+ export declare function runRepositorySaveOrchestrator(options: RepositorySaveOptions): Promise<RepositorySaveResult>;
169
+ export declare function repositorySaveErrorDetails(error: unknown): {
170
+ exitCode: number | undefined;
171
+ details: Record<string, unknown> | undefined;
172
+ };