@treeseed/sdk 0.6.43 → 0.6.45

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.
@@ -137,6 +137,14 @@ export declare function deployProjectPlatform(options: ProjectPlatformActionOpti
137
137
  skipped: boolean;
138
138
  reason: string;
139
139
  };
140
+ railwayResources: {
141
+ ok: boolean;
142
+ checks: any[];
143
+ } | {
144
+ ok: boolean;
145
+ skipped: boolean;
146
+ reason: string;
147
+ };
140
148
  pages: {
141
149
  ok: boolean;
142
150
  status: number;
@@ -315,6 +323,14 @@ export declare function monitorProjectPlatform(options: ProjectPlatformActionOpt
315
323
  skipped: boolean;
316
324
  reason: string;
317
325
  };
326
+ railwayResources: {
327
+ ok: boolean;
328
+ checks: any[];
329
+ } | {
330
+ ok: boolean;
331
+ skipped: boolean;
332
+ reason: string;
333
+ };
318
334
  pages: {
319
335
  ok: boolean;
320
336
  status: number;
@@ -498,6 +514,14 @@ export declare function runProjectPlatformAction(action: ProjectPlatformAction,
498
514
  skipped: boolean;
499
515
  reason: string;
500
516
  };
517
+ railwayResources: {
518
+ ok: boolean;
519
+ checks: any[];
520
+ } | {
521
+ ok: boolean;
522
+ skipped: boolean;
523
+ reason: string;
524
+ };
501
525
  pages: {
502
526
  ok: boolean;
503
527
  status: number;
@@ -637,6 +661,14 @@ export declare function runProjectPlatformAction(action: ProjectPlatformAction,
637
661
  skipped: boolean;
638
662
  reason: string;
639
663
  };
664
+ railwayResources: {
665
+ ok: boolean;
666
+ checks: any[];
667
+ } | {
668
+ ok: boolean;
669
+ skipped: boolean;
670
+ reason: string;
671
+ };
640
672
  pages: {
641
673
  ok: boolean;
642
674
  status: number;
@@ -35,6 +35,7 @@ import {
35
35
  ensureRailwayScheduledJobs,
36
36
  validateRailwayDeployPrerequisites,
37
37
  validateRailwayServiceConfiguration,
38
+ verifyRailwayManagedResources,
38
39
  verifyRailwayScheduledJobs
39
40
  } from "./railway-deploy.js";
40
41
  import { loadCliDeployConfig, packageScriptPath } from "./runtime-tools.js";
@@ -1209,6 +1210,7 @@ async function publishProjectContent(options) {
1209
1210
  }
1210
1211
  async function monitorProjectPlatform(options) {
1211
1212
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1213
+ const env = { ...process.env, ...options.env ?? {} };
1212
1214
  const target = createPersistentDeployTarget(options.scope === "local" ? "staging" : options.scope);
1213
1215
  const siteConfig = loadCliDeployConfig(options.tenantRoot);
1214
1216
  const selectedSystems = new Set(resolveProjectPlatformBootstrapSystems(options, siteConfig));
@@ -1228,12 +1230,14 @@ async function monitorProjectPlatform(options) {
1228
1230
  r2: options.dryRun ? { ok: true, skipped: true, reason: "dry_run" } : probeR2(options.tenantRoot, siteConfig, state, target),
1229
1231
  queue: options.dryRun ? Promise.resolve({ ok: true, skipped: true, reason: "dry_run" }) : probeQueue(siteConfig, state),
1230
1232
  scaleProbe: probeScaleConfiguration(siteConfig, state),
1233
+ railwayResources: options.scope === "local" || !apiSelected && !agentsSelected ? Promise.resolve({ ok: true, skipped: true, reason: options.scope === "local" ? "local_scope" : "railway_not_selected" }) : verifyRailwayManagedResources(options.tenantRoot, options.scope, { env, settleDeployments: true }),
1231
1234
  readiness: state.readiness
1232
1235
  };
1233
1236
  const resolvedChecks = {
1234
1237
  ...checks,
1235
1238
  r2: await checks.r2,
1236
- queue: await checks.queue
1239
+ queue: await checks.queue,
1240
+ railwayResources: await checks.railwayResources
1237
1241
  };
1238
1242
  const ok = [
1239
1243
  resolvedChecks.pages,
@@ -1243,7 +1247,8 @@ async function monitorProjectPlatform(options) {
1243
1247
  resolvedChecks.agentHealth,
1244
1248
  resolvedChecks.r2,
1245
1249
  resolvedChecks.queue,
1246
- resolvedChecks.scaleProbe
1250
+ resolvedChecks.scaleProbe,
1251
+ resolvedChecks.railwayResources
1247
1252
  ].every((check) => check?.ok === true || check?.skipped === true);
1248
1253
  if (!ok) {
1249
1254
  const failedChecks = Object.entries(resolvedChecks).filter(([, check]) => check && typeof check === "object" && check.ok !== true && check.skipped !== true).map(([name, check]) => `${name}: ${JSON.stringify(check)}`);
@@ -2,6 +2,7 @@ import { type TreeseedBootstrapTaskPrefix, type TreeseedBootstrapWriter } from '
2
2
  export declare function deriveRailwayWorkerRunnerServiceName(projectSlug: any, index?: number): string;
3
3
  export declare function deriveRailwayWorkerRunnerVolumeName(serviceName: any, environmentName?: string): string;
4
4
  export declare function railwayServiceRuntimeStartCommand(service: any): any;
5
+ export declare function collectRailwayDeploymentStatusChecks(statusPayload: any, scope: any, services: any): any;
5
6
  export declare function isUsableRailwayToken(value: any): boolean;
6
7
  export declare function resolveRailwayAuthToken(env?: NodeJS.ProcessEnv): string;
7
8
  export declare function buildRailwayCommandEnv(env?: NodeJS.ProcessEnv): {
@@ -12,6 +13,43 @@ export declare function runRailway(args: any, { cwd, capture, allowFailure, inpu
12
13
  capture?: boolean | undefined;
13
14
  allowFailure?: boolean | undefined;
14
15
  }): import("child_process").SpawnSyncReturns<string>;
16
+ export declare function waitForRailwayManagedDeploymentsSettled(tenantRoot: any, scope: any, { services, env, timeoutMs, pollMs, }?: {
17
+ services?: ({
18
+ key: string;
19
+ scope: string;
20
+ projectId: string | null;
21
+ projectName: string;
22
+ serviceId: string | null;
23
+ serviceName: string;
24
+ rootDir: string;
25
+ publicBaseUrl: string | null;
26
+ railwayEnvironment: string;
27
+ buildCommand: string | null;
28
+ startCommand: string | null;
29
+ healthcheckPath: any;
30
+ healthcheckTimeoutSeconds: any;
31
+ healthcheckIntervalSeconds: any;
32
+ restartPolicy: any;
33
+ runtimeMode: any;
34
+ schedule: string[];
35
+ hostingKind: string;
36
+ runnerPool: {
37
+ bootstrapIndex: number;
38
+ volumeMountPath: string;
39
+ } | null;
40
+ } | null)[] | undefined;
41
+ env?: NodeJS.ProcessEnv | undefined;
42
+ timeoutMs?: number | undefined;
43
+ pollMs?: number | undefined;
44
+ }): Promise<{
45
+ ok: boolean;
46
+ checks: any;
47
+ message?: undefined;
48
+ } | {
49
+ ok: boolean;
50
+ checks: any;
51
+ message: string;
52
+ }>;
15
53
  export declare function setRailwaySecretVariable({ cwd, service, environment, key, value, env, capture, allowFailure }: {
16
54
  cwd: any;
17
55
  service: any;
@@ -281,6 +319,16 @@ export declare function verifyRailwayScheduledJobs(tenantRoot: any, scope: any,
281
319
  unsupported?: undefined;
282
320
  message?: undefined;
283
321
  }>;
322
+ export declare function verifyRailwayManagedResources(tenantRoot: any, scope: any, { fetchImpl, apiToken, apiUrl, env, settleDeployments, settleTimeoutMs, settlePollMs, }?: {
323
+ fetchImpl?: typeof fetch | undefined;
324
+ env?: NodeJS.ProcessEnv | undefined;
325
+ settleDeployments?: boolean | undefined;
326
+ settleTimeoutMs?: number | undefined;
327
+ settlePollMs?: number | undefined;
328
+ }): Promise<{
329
+ ok: boolean;
330
+ checks: any[];
331
+ }>;
284
332
  export declare function planRailwayServiceDeploy(service: any, { env }?: {
285
333
  env?: NodeJS.ProcessEnv | undefined;
286
334
  }): {
@@ -15,6 +15,7 @@ import {
15
15
  listRailwayEnvironments,
16
16
  listRailwayProjects,
17
17
  listRailwayServices,
18
+ listRailwayVolumes,
18
19
  normalizeRailwayEnvironmentName,
19
20
  resolveRailwayApiToken,
20
21
  resolveRailwayApiUrl,
@@ -94,6 +95,74 @@ function parseRailwayJsonOutput(output) {
94
95
  }
95
96
  return null;
96
97
  }
98
+ function railwayEdgeNodes(value) {
99
+ return Array.isArray(value?.edges) ? value.edges.map((entry) => entry?.node).filter(Boolean) : [];
100
+ }
101
+ function railwayStatusEnvironmentNodes(payload) {
102
+ if (!payload || typeof payload !== "object") {
103
+ return [];
104
+ }
105
+ if (Array.isArray(payload.environments)) {
106
+ return payload.environments;
107
+ }
108
+ return railwayEdgeNodes(payload.environments);
109
+ }
110
+ function railwayStatusDeploymentSettled(status) {
111
+ const normalized = String(status ?? "").trim().toUpperCase();
112
+ return normalized === "SUCCESS" || normalized === "SLEEPING";
113
+ }
114
+ function collectRailwayDeploymentStatusChecks(statusPayload, scope, services) {
115
+ const expectedEnvironment = resolveRailwayEnvironmentForScope(scope);
116
+ const environments = railwayStatusEnvironmentNodes(statusPayload);
117
+ const environment = environments.find(
118
+ (candidate) => normalizeRailwayEnvironmentName(candidate?.name) === expectedEnvironment
119
+ ) ?? null;
120
+ if (!environment) {
121
+ return services.map((service) => ({
122
+ type: "deployment-status",
123
+ service: service.key,
124
+ serviceName: service.serviceName,
125
+ environment: expectedEnvironment,
126
+ ok: false,
127
+ status: "missing_environment",
128
+ message: `Railway status did not include the ${expectedEnvironment} environment.`
129
+ }));
130
+ }
131
+ const instances = railwayEdgeNodes(environment.serviceInstances);
132
+ return services.map((service) => {
133
+ const instance = instances.find((candidate) => candidate?.serviceName === service.serviceName) ?? null;
134
+ if (!instance) {
135
+ return {
136
+ type: "deployment-status",
137
+ service: service.key,
138
+ serviceName: service.serviceName,
139
+ environment: expectedEnvironment,
140
+ ok: false,
141
+ status: "missing_service_instance",
142
+ message: `Railway status did not include service ${service.serviceName} in ${expectedEnvironment}.`
143
+ };
144
+ }
145
+ const deployment = instance.latestDeployment ?? null;
146
+ const status = String(deployment?.status ?? "").trim().toUpperCase();
147
+ const instanceStatuses = Array.isArray(deployment?.instances) ? deployment.instances.map((entry) => String(entry?.status ?? "").trim()).filter(Boolean) : [];
148
+ const ok = railwayStatusDeploymentSettled(status);
149
+ return {
150
+ type: "deployment-status",
151
+ service: service.key,
152
+ serviceName: service.serviceName,
153
+ environment: normalizeRailwayEnvironmentName(environment.name),
154
+ ok,
155
+ status: status || "missing_deployment",
156
+ observed: {
157
+ status: status || null,
158
+ deploymentStopped: deployment?.deploymentStopped ?? null,
159
+ instanceStatuses,
160
+ volumeMounts: Array.isArray(deployment?.meta?.volumeMounts) ? deployment.meta.volumeMounts : []
161
+ },
162
+ message: ok ? void 0 : `Railway deployment for ${service.serviceName} is not settled yet; observed ${status || "missing deployment status"}.`
163
+ };
164
+ });
165
+ }
97
166
  function normalizeRailwayCliVolume(value, { serviceId, environmentId, fallbackName, fallbackMountPath }) {
98
167
  if (!value || typeof value !== "object") {
99
168
  return null;
@@ -320,6 +389,50 @@ function runRailway(args, { cwd, capture = false, allowFailure = false, input, e
320
389
  }
321
390
  return result;
322
391
  }
392
+ async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
393
+ services = configuredRailwayServices(tenantRoot, scope),
394
+ env = process.env,
395
+ timeoutMs = 18e4,
396
+ pollMs = 15e3
397
+ } = {}) {
398
+ const deadline = Date.now() + timeoutMs;
399
+ let checks = [];
400
+ let lastError = null;
401
+ for (; ; ) {
402
+ try {
403
+ const result = runRailway(["status", "--json"], {
404
+ cwd: tenantRoot,
405
+ capture: true,
406
+ env
407
+ });
408
+ const payload = parseRailwayJsonOutput(result.stdout);
409
+ checks = collectRailwayDeploymentStatusChecks(payload, scope, services);
410
+ lastError = null;
411
+ if (checks.every((entry) => entry.ok === true)) {
412
+ return { ok: true, checks };
413
+ }
414
+ } catch (error) {
415
+ lastError = error;
416
+ checks = services.map((service) => ({
417
+ type: "deployment-status",
418
+ service: service.key,
419
+ serviceName: service.serviceName,
420
+ environment: resolveRailwayEnvironmentForScope(scope),
421
+ ok: false,
422
+ status: "status_error",
423
+ message: error instanceof Error ? error.message : String(error)
424
+ }));
425
+ }
426
+ if (Date.now() >= deadline) {
427
+ return {
428
+ ok: false,
429
+ checks,
430
+ message: lastError instanceof Error ? lastError.message : "Railway deployments did not settle before the monitor timeout."
431
+ };
432
+ }
433
+ await sleep(pollMs);
434
+ }
435
+ }
323
436
  function setRailwaySecretVariable({ cwd, service, environment, key, value, env = process.env, capture = false, allowFailure = false }) {
324
437
  const effectiveEnv = buildRailwayCommandEnv({
325
438
  ...process.env,
@@ -841,6 +954,131 @@ async function verifyRailwayScheduledJobs(tenantRoot, scope, { fetchImpl = fetch
841
954
  checks
842
955
  };
843
956
  }
957
+ async function verifyRailwayManagedResources(tenantRoot, scope, {
958
+ fetchImpl = fetch,
959
+ apiToken,
960
+ apiUrl,
961
+ env = process.env,
962
+ settleDeployments = false,
963
+ settleTimeoutMs = 18e4,
964
+ settlePollMs = 15e3
965
+ } = {}) {
966
+ const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
967
+ const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
968
+ const effectiveEnv = { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl };
969
+ const services = configuredRailwayServices(tenantRoot, scope);
970
+ const checks = [];
971
+ for (const service of services) {
972
+ const target = await resolveRailwayScheduleTarget({
973
+ projectId: service.projectId,
974
+ projectName: service.projectName,
975
+ serviceId: service.serviceId,
976
+ serviceName: service.serviceName,
977
+ environment: normalizeRailwayEnvironmentName(service.railwayEnvironment),
978
+ environmentId: envValue("TREESEED_RAILWAY_ENVIRONMENT_ID") || null
979
+ }, {
980
+ env: effectiveEnv,
981
+ fetchImpl,
982
+ ensure: false
983
+ });
984
+ if (!target.project || !target.environment || !target.service) {
985
+ checks.push({
986
+ type: "service",
987
+ service: service.key,
988
+ serviceName: service.serviceName,
989
+ projectName: service.projectName,
990
+ environment: service.railwayEnvironment,
991
+ ok: false,
992
+ status: "missing",
993
+ message: `Railway service ${service.serviceName} is missing in ${service.railwayEnvironment}.`
994
+ });
995
+ continue;
996
+ }
997
+ const instance = await getRailwayServiceInstance({
998
+ serviceId: target.service.id,
999
+ environmentId: target.environment.id,
1000
+ env: effectiveEnv,
1001
+ fetchImpl
1002
+ });
1003
+ checks.push({
1004
+ type: "service-instance",
1005
+ service: service.key,
1006
+ serviceName: target.service.name,
1007
+ serviceId: target.service.id,
1008
+ projectId: target.project.id,
1009
+ environment: target.environment.name,
1010
+ environmentId: target.environment.id,
1011
+ instanceId: instance.id,
1012
+ ok: Boolean(instance.id),
1013
+ status: instance.id ? "checked" : "missing",
1014
+ observed: instance.id ? {
1015
+ rootDirectory: instance.rootDirectory,
1016
+ startCommand: instance.startCommand,
1017
+ cronSchedule: instance.cronSchedule,
1018
+ sleepApplication: instance.sleepApplication,
1019
+ runtimeMode: instance.runtimeMode
1020
+ } : null,
1021
+ message: instance.id ? void 0 : `Railway service instance for ${target.service.name} is missing in ${target.environment.name}.`
1022
+ });
1023
+ if (service.key === "workerRunner") {
1024
+ const expectedVolumeName = deriveRailwayWorkerRunnerVolumeName(target.service.name, target.environment.name);
1025
+ const volumes = await listRailwayVolumes({
1026
+ projectId: target.project.id,
1027
+ env: effectiveEnv,
1028
+ fetchImpl
1029
+ });
1030
+ const volume = volumes.find(
1031
+ (candidate) => candidate.name === expectedVolumeName && candidate.instances.some((entry) => entry.serviceId === target.service.id && entry.environmentId === target.environment.id && entry.mountPath === WORKER_RUNNER_VOLUME_MOUNT_PATH)
1032
+ ) ?? null;
1033
+ checks.push({
1034
+ type: "worker-runner-volume",
1035
+ service: service.key,
1036
+ serviceName: target.service.name,
1037
+ serviceId: target.service.id,
1038
+ projectId: target.project.id,
1039
+ environment: target.environment.name,
1040
+ environmentId: target.environment.id,
1041
+ volumeName: expectedVolumeName,
1042
+ mountPath: WORKER_RUNNER_VOLUME_MOUNT_PATH,
1043
+ ok: Boolean(volume),
1044
+ status: volume ? "checked" : "missing",
1045
+ observed: volume ? {
1046
+ id: volume.id,
1047
+ name: volume.name,
1048
+ instances: volume.instances
1049
+ } : null,
1050
+ message: volume ? void 0 : `Railway worker-runner volume ${expectedVolumeName} is missing or is not mounted at ${WORKER_RUNNER_VOLUME_MOUNT_PATH}.`
1051
+ });
1052
+ }
1053
+ }
1054
+ const schedules = await verifyRailwayScheduledJobs(tenantRoot, scope, {
1055
+ fetchImpl,
1056
+ apiToken: effectiveApiToken,
1057
+ apiUrl: effectiveApiUrl,
1058
+ env: effectiveEnv
1059
+ });
1060
+ for (const check of schedules.checks ?? []) {
1061
+ checks.push({
1062
+ type: "schedule",
1063
+ ...check
1064
+ });
1065
+ }
1066
+ if (settleDeployments) {
1067
+ const settled = await waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
1068
+ services,
1069
+ env: effectiveEnv,
1070
+ timeoutMs: settleTimeoutMs,
1071
+ pollMs: settlePollMs
1072
+ });
1073
+ for (const check of settled.checks ?? []) {
1074
+ checks.push(check);
1075
+ }
1076
+ }
1077
+ return {
1078
+ ok: checks.every((entry) => entry.ok === true || entry.skipped === true),
1079
+ checks
1080
+ };
1081
+ }
844
1082
  function shouldAttachRailwayDeployLogs(env = process.env) {
845
1083
  return configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_ATTACH_LOGS") === "1";
846
1084
  }
@@ -1148,6 +1386,7 @@ async function deployRailwayService(tenantRoot, service, {
1148
1386
  }
1149
1387
  export {
1150
1388
  buildRailwayCommandEnv,
1389
+ collectRailwayDeploymentStatusChecks,
1151
1390
  configuredRailwayScheduledJobs,
1152
1391
  configuredRailwayServices,
1153
1392
  deployRailwayService,
@@ -1168,5 +1407,7 @@ export {
1168
1407
  setRailwaySecretVariable,
1169
1408
  validateRailwayDeployPrerequisites,
1170
1409
  validateRailwayServiceConfiguration,
1171
- verifyRailwayScheduledJobs
1410
+ verifyRailwayManagedResources,
1411
+ verifyRailwayScheduledJobs,
1412
+ waitForRailwayManagedDeploymentsSettled
1172
1413
  };
@@ -319,7 +319,7 @@ function normalizeSaveVerifyMode(mode) {
319
319
  }
320
320
  }
321
321
  function shouldUseHostedSaveCi(input) {
322
- return normalizeCiMode(input.ciMode, "save") === "hosted" || input.verifyMode === "hosted" || input.verifyMode === "both";
322
+ return normalizeCiMode(input.ciMode, "save") === "hosted" || input.verifyMode === "hosted" || input.verifyMode === "both" || input.verifyDeployedResources === true;
323
323
  }
324
324
  function worktreePayload(root, requestedMode) {
325
325
  const metadata = managedWorkflowWorktreeMetadata(root);
@@ -2875,7 +2875,8 @@ async function workflowSave(helpers, input) {
2875
2875
  ciMode: effectiveInput.ciMode ?? "auto",
2876
2876
  worktreeMode: effectiveInput.worktreeMode ?? "auto",
2877
2877
  commitMessageMode: effectiveInput.commitMessageMode ?? "auto",
2878
- workspaceLinks: effectiveInput.workspaceLinks ?? "auto"
2878
+ workspaceLinks: effectiveInput.workspaceLinks ?? "auto",
2879
+ verifyDeployedResources: effectiveInput.verifyDeployedResources === true
2879
2880
  },
2880
2881
  [
2881
2882
  {
@@ -2971,6 +2972,13 @@ async function workflowSave(helpers, input) {
2971
2972
  branch,
2972
2973
  headSha: savedRootRepo.commitSha
2973
2974
  }] : [],
2975
+ ...effectiveInput.verifyDeployedResources === true && scope !== "local" && savedRootRepo.pushed && savedRootRepo.commitSha && branch ? [{
2976
+ name: savedRootRepo.name,
2977
+ repoPath: savedRootRepo.path,
2978
+ workflow: "deploy.yml",
2979
+ branch,
2980
+ headSha: savedRootRepo.commitSha
2981
+ }] : [],
2974
2982
  ...savedPackageReports.filter((repo) => repo.pushed && repo.commitSha && repo.branch).map((repo) => ({
2975
2983
  name: repo.name,
2976
2984
  repoPath: repo.path,
@@ -2978,7 +2986,11 @@ async function workflowSave(helpers, input) {
2978
2986
  branch: String(repo.branch),
2979
2987
  headSha: String(repo.commitSha)
2980
2988
  }))
2981
- ], "hosted", { root, runId: workflowRun.runId }).then((workflowGates) => ({ workflowGates }))) : { workflowGates: [] };
2989
+ ], "hosted", {
2990
+ root,
2991
+ runId: workflowRun.runId,
2992
+ onProgress: (line, stream) => helpers.write(line, stream)
2993
+ }).then((workflowGates) => ({ workflowGates }))) : { workflowGates: [] };
2982
2994
  const releaseCandidate = branch === STAGING_BRANCH ? await executeJournalStep(root, workflowRun.runId, "release-candidate", () => {
2983
2995
  const releaseSession = resolveTreeseedWorkflowSession(root);
2984
2996
  const stagingReleasePlan = buildReleasePlanSnapshot({
@@ -3289,6 +3301,7 @@ async function workflowStage(helpers, input) {
3289
3301
  const effectiveInput = autoResumeRun ? autoResumeRun.input : input;
3290
3302
  const message = ensureMessage("stage", effectiveInput.message, "a resolution message");
3291
3303
  const ciMode = normalizeCiMode(effectiveInput.ciMode, "stage");
3304
+ const waitForStaging = effectiveInput.verifyDeployedResources === true || effectiveInput.waitForStaging !== false;
3292
3305
  if (executionMode === "plan") {
3293
3306
  const blockers = [];
3294
3307
  if (initialSession.branchRole !== "feature") {
@@ -3371,11 +3384,12 @@ async function workflowStage(helpers, input) {
3371
3384
  session,
3372
3385
  {
3373
3386
  message,
3374
- waitForStaging: effectiveInput.waitForStaging !== false,
3387
+ waitForStaging,
3375
3388
  deletePreview: effectiveInput.deletePreview !== false,
3376
3389
  deleteBranch: effectiveInput.deleteBranch !== false,
3377
3390
  ciMode,
3378
- worktreeMode: effectiveInput.worktreeMode ?? "auto"
3391
+ worktreeMode: effectiveInput.worktreeMode ?? "auto",
3392
+ verifyDeployedResources: effectiveInput.verifyDeployedResources === true
3379
3393
  },
3380
3394
  [
3381
3395
  { id: "workspace-unlink", description: "Remove local workspace links", repoName: rootRepo.name, repoPath: rootRepo.path, branch: featureBranch, resumable: true },
@@ -3491,7 +3505,7 @@ async function workflowStage(helpers, input) {
3491
3505
  exitCode: 12
3492
3506
  });
3493
3507
  }
3494
- const stageWorkflowGateResult = effectiveInput.waitForStaging === false ? (skipJournalStep(root, workflowRun.runId, "wait-staging", { status: "skipped", reason: "disabled" }), { status: "skipped", reason: "disabled" }) : await executeJournalStep(root, workflowRun.runId, "wait-staging", () => waitForWorkflowGates("stage", [
3508
+ const stageWorkflowGateResult = !waitForStaging ? (skipJournalStep(root, workflowRun.runId, "wait-staging", { status: "skipped", reason: "disabled" }), { status: "skipped", reason: "disabled" }) : await executeJournalStep(root, workflowRun.runId, "wait-staging", () => waitForWorkflowGates("stage", [
3495
3509
  {
3496
3510
  name: rootRepo.name,
3497
3511
  repoPath: rootRepo.path,
@@ -3506,7 +3520,11 @@ async function workflowStage(helpers, input) {
3506
3520
  branch: STAGING_BRANCH,
3507
3521
  headSha: String(report.commitSha)
3508
3522
  }))
3509
- ], ciMode, { root, runId: workflowRun.runId }).then((workflowGates) => ({
3523
+ ], ciMode, {
3524
+ root,
3525
+ runId: workflowRun.runId,
3526
+ onProgress: (line, stream) => helpers.write(line, stream)
3527
+ }).then((workflowGates) => ({
3510
3528
  status: "completed",
3511
3529
  workflowGates
3512
3530
  })));
@@ -111,6 +111,7 @@ export type TreeseedSaveInput = {
111
111
  worktreeMode?: TreeseedWorkflowWorktreeMode;
112
112
  commitMessageMode?: 'auto' | 'cloudflare' | 'generated' | 'fallback';
113
113
  workspaceLinks?: 'auto' | 'off';
114
+ verifyDeployedResources?: boolean;
114
115
  plan?: boolean;
115
116
  dryRun?: boolean;
116
117
  };
@@ -153,6 +154,7 @@ export type TreeseedStageInput = {
153
154
  ciMode?: TreeseedWorkflowCiMode;
154
155
  worktreeMode?: TreeseedWorkflowWorktreeMode;
155
156
  workspaceLinks?: 'auto' | 'off';
157
+ verifyDeployedResources?: boolean;
156
158
  plan?: boolean;
157
159
  dryRun?: boolean;
158
160
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.6.43",
3
+ "version": "0.6.45",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {