@treeseed/sdk 0.12.43 → 0.12.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.
Files changed (37) hide show
  1. package/dist/guarantees/index.d.ts +83 -0
  2. package/dist/guarantees/index.js +688 -86
  3. package/dist/hosting/graph.js +40 -6
  4. package/dist/operations/services/git-workflow.d.ts +16 -1
  5. package/dist/operations/services/git-workflow.js +65 -5
  6. package/dist/operations/services/github-api.js +0 -19
  7. package/dist/operations/services/hosted-service-checks.js +17 -1
  8. package/dist/operations/services/live-hosted-service-checks.d.ts +4 -0
  9. package/dist/operations/services/live-hosted-service-checks.js +7 -4
  10. package/dist/operations/services/local-cleanup.js +3 -7
  11. package/dist/operations/services/package-adapters.d.ts +14 -0
  12. package/dist/operations/services/package-adapters.js +36 -3
  13. package/dist/operations/services/package-artifacts.d.ts +37 -0
  14. package/dist/operations/services/package-artifacts.js +99 -0
  15. package/dist/operations/services/railway-deploy.js +78 -18
  16. package/dist/operations/services/railway-source-policy.d.ts +19 -0
  17. package/dist/operations/services/railway-source-policy.js +66 -0
  18. package/dist/operations/services/repository-save-orchestrator.js +12 -5
  19. package/dist/platform/desired-state.js +2 -3
  20. package/dist/reconcile/builtin-adapters.js +10 -2
  21. package/dist/reconcile/providers/railway-iac.d.ts +2 -0
  22. package/dist/reconcile/providers/railway-iac.js +31 -3
  23. package/dist/scenes/builtin-plugins.js +36 -5
  24. package/dist/scenes/device-matrix.js +2 -0
  25. package/dist/scenes/environment.js +1 -1
  26. package/dist/scenes/runner.js +28 -16
  27. package/dist/scenes/schema.js +31 -2
  28. package/dist/scenes/types.d.ts +25 -2
  29. package/dist/scenes/visual-audit-fixtures.js +9 -3
  30. package/dist/workflow/operations.d.ts +27 -92
  31. package/dist/workflow/operations.js +236 -144
  32. package/dist/workflow/runs.d.ts +1 -0
  33. package/dist/workflow/runs.js +57 -0
  34. package/dist/workflow-support.d.ts +1 -0
  35. package/dist/workflow-support.js +8 -0
  36. package/dist/workflow.d.ts +2 -0
  37. package/package.json +4 -1
@@ -85,6 +85,7 @@ export type TreeseedWorkflowLockInspection = {
85
85
  stale: boolean;
86
86
  staleReason: string | null;
87
87
  };
88
+ export declare function markActiveWorkflowRunsInterrupted(signal: NodeJS.Signals | string): string[];
88
89
  export declare function workflowLockScopeForCommand(command: TreeseedWorkflowRunCommand): TreeseedWorkflowLockScope;
89
90
  export declare function isSharedWorkflowCommand(command?: string | null): command is TreeseedWorkflowRunCommand;
90
91
  export declare function generateWorkflowRunId(command: TreeseedWorkflowRunCommand): string;
@@ -7,9 +7,47 @@ const WORKTREE_METADATA_PATH = ".treeseed/worktree.json";
7
7
  const LOCK_STALE_AFTER_MS = 4 * 60 * 60 * 1e3;
8
8
  const WORKFLOW_RUN_STORAGE_ROOTS = /* @__PURE__ */ new Map();
9
9
  const SHARED_LOCK_COMMANDS = /* @__PURE__ */ new Set(["stage", "release"]);
10
+ const ACTIVE_WORKFLOW_RUNS = /* @__PURE__ */ new Map();
11
+ let SIGNAL_HANDLERS_INSTALLED = false;
10
12
  function nowIso() {
11
13
  return (/* @__PURE__ */ new Date()).toISOString();
12
14
  }
15
+ function markActiveWorkflowRunsInterrupted(signal) {
16
+ const interrupted = [];
17
+ for (const [runId, root] of ACTIVE_WORKFLOW_RUNS) {
18
+ const journal = readWorkflowRunJournal(root, runId);
19
+ if (journal?.status === "running") {
20
+ updateWorkflowRunJournal(root, runId, (current) => ({
21
+ ...current,
22
+ status: "failed",
23
+ failure: {
24
+ code: "interrupted",
25
+ message: `Treeseed workflow was interrupted by ${signal}.`,
26
+ details: {
27
+ resumable: true,
28
+ recoverCommand: "treeseed recover",
29
+ resumeCommand: `treeseed resume ${runId}`
30
+ },
31
+ at: nowIso()
32
+ }
33
+ }));
34
+ }
35
+ releaseWorkflowLock(root, runId);
36
+ interrupted.push(runId);
37
+ }
38
+ ACTIVE_WORKFLOW_RUNS.clear();
39
+ return interrupted;
40
+ }
41
+ function installWorkflowSignalHandlers() {
42
+ if (SIGNAL_HANDLERS_INSTALLED) return;
43
+ SIGNAL_HANDLERS_INSTALLED = true;
44
+ for (const signal of ["SIGINT", "SIGTERM"]) {
45
+ process.once(signal, () => {
46
+ markActiveWorkflowRunsInterrupted(signal);
47
+ process.kill(process.pid, signal);
48
+ });
49
+ }
50
+ }
13
51
  function managedWorktreePrimaryRoot(root) {
14
52
  const metadataPath = resolve(root, WORKTREE_METADATA_PATH);
15
53
  if (!existsSync(metadataPath)) return null;
@@ -167,6 +205,21 @@ function acquireWorkflowLock(root, command, runId) {
167
205
  };
168
206
  }
169
207
  if (inspection.stale) {
208
+ if (inspection.lock?.runId) {
209
+ const staleJournal = readWorkflowRunJournal(root, inspection.lock.runId);
210
+ if (staleJournal?.status === "running") {
211
+ updateWorkflowRunJournal(root, inspection.lock.runId, (journal) => ({
212
+ ...journal,
213
+ status: "failed",
214
+ failure: {
215
+ code: "interrupted",
216
+ message: `Workflow lock became stale because ${inspection.staleReason ?? "the owning process ended"}.`,
217
+ details: { resumable: true, resumeCommand: `treeseed resume ${inspection.lock.runId}` },
218
+ at: nowIso()
219
+ }
220
+ }));
221
+ }
222
+ }
170
223
  rmSync(dirs.lockPath, { force: true });
171
224
  }
172
225
  const timestamp = nowIso();
@@ -186,6 +239,8 @@ function acquireWorkflowLock(root, command, runId) {
186
239
  };
187
240
  writeFileSync(dirs.lockPath, `${JSON.stringify(lock, null, 2)}
188
241
  `, "utf8");
242
+ ACTIVE_WORKFLOW_RUNS.set(runId, root);
243
+ installWorkflowSignalHandlers();
189
244
  return {
190
245
  acquired: true,
191
246
  lock,
@@ -209,6 +264,7 @@ function refreshWorkflowLock(root, runId) {
209
264
  return updated;
210
265
  }
211
266
  function releaseWorkflowLock(root, runId) {
267
+ ACTIVE_WORKFLOW_RUNS.delete(runId);
212
268
  const path = workflowLockPath(root, runId);
213
269
  const lock = safeJsonParse(path);
214
270
  if (!lock || lock.runId !== runId) {
@@ -627,6 +683,7 @@ export {
627
683
  listInterruptedWorkflowRuns,
628
684
  listRecentWorkflowRunJournals,
629
685
  listWorkflowRunJournals,
686
+ markActiveWorkflowRunsInterrupted,
630
687
  readWorkflowRunJournal,
631
688
  refreshWorkflowLock,
632
689
  releaseWorkflowLock,
@@ -15,6 +15,7 @@ export { getRailwayAuthProfile, listRailwayEnvironments, listRailwayProjects, li
15
15
  export { githubRepositoryCredentialEnvName, resolveGitHubCredentialForRepository, type TreeseedGitHubCredentialResolution, } from './operations/services/github-credentials.js';
16
16
  export { createGitHubApiClient, ensureGitHubActionsEnvironment, getLatestGitHubWorkflowRun, listGitHubEnvironmentSecretNames, listGitHubEnvironmentVariableNames, type GitHubWorkflowDispatchResult, type GitHubWorkflowRunSummary, } from './operations/services/github-api.js';
17
17
  export { inspectTreeseedGitLocks, inspectTreeseedGitLockSet, inspectTreeseedWorkspaceGitLocks, recoverTreeseedGitLocks, runTreeseedGitBatch, runTreeseedGit, type TreeseedGitLockDiagnostic, type TreeseedGitLockKind, type TreeseedGitLockProcessHint, type TreeseedGitBatchOperation, type TreeseedGitRunnerMode, type TreeseedGitRunnerResult, type TreeseedGitWorkspaceLockDiagnostics, } from './operations/services/git-runner.js';
18
+ export { buildTreeseedPackageArtifact, hydrateTreeseedPackageArtifacts, verifyTreeseedPackageArtifact, type TreeseedPackageArtifactManifest, } from './operations/services/package-artifacts.js';
18
19
  export { discoverTreeseedPackageAdapters, findTreeseedPackageAdapter, packageAdapterPlanSummary, planTreeseedPackageDevelopmentImage, runTreeseedPackageImageWorkflow, syncTreeseedPackageWorkflows, validateTreeseedPackageManifests, type TreeseedPackageAdapter, type TreeseedPackageDevelopmentImagePlan, type TreeseedPackageImageWorkflowOptions, type TreeseedPackageManifestValidation, type TreeseedPackageWorkflowSyncResult, type TreeseedPackageWorkflowTemplateKind, } from './operations/services/package-adapters.js';
19
20
  export { runTenantDeployPreflight, runWorkspaceReleasePreflight, runWorkspaceSavePreflight, } from './operations/services/save-deploy-preflight.js';
20
21
  export { collectCliPreflight } from './operations/services/workspace-preflight.js';
@@ -145,6 +145,11 @@ import {
145
145
  runTreeseedGitBatch,
146
146
  runTreeseedGit
147
147
  } from "./operations/services/git-runner.js";
148
+ import {
149
+ buildTreeseedPackageArtifact,
150
+ hydrateTreeseedPackageArtifacts,
151
+ verifyTreeseedPackageArtifact
152
+ } from "./operations/services/package-artifacts.js";
148
153
  import {
149
154
  discoverTreeseedPackageAdapters,
150
155
  findTreeseedPackageAdapter,
@@ -227,6 +232,7 @@ export {
227
232
  assertNoWorkspaceLinksInDeploymentLockfiles,
228
233
  assertTreeseedCommandEnvironment,
229
234
  branchExists,
235
+ buildTreeseedPackageArtifact,
230
236
  checkTreeseedProviderConnections,
231
237
  checkoutBranch,
232
238
  cleanupDestroyedState,
@@ -286,6 +292,7 @@ export {
286
292
  gitWorkflowRoot,
287
293
  githubRepositoryCredentialEnvName,
288
294
  hasMeaningfulChanges,
295
+ hydrateTreeseedPackageArtifacts,
289
296
  incrementVersion,
290
297
  inspectTreeseedGitLockSet,
291
298
  inspectTreeseedGitLocks,
@@ -371,6 +378,7 @@ export {
371
378
  validateDestroyPrerequisites,
372
379
  validateRailwayDeployPrerequisites,
373
380
  validateTreeseedPackageManifests,
381
+ verifyTreeseedPackageArtifact,
374
382
  waitForStagingAutomation,
375
383
  warnDeprecatedTreeseedLocalEnvFiles,
376
384
  withTreeseedKeyAgentAutopromptDisabled,
@@ -129,6 +129,7 @@ export type TreeseedUpdateInput = {
129
129
  push?: boolean;
130
130
  worktreeMode?: TreeseedWorkflowWorktreeMode;
131
131
  workspaceLinks?: 'auto' | 'off';
132
+ adoptChanges?: boolean;
132
133
  plan?: boolean;
133
134
  };
134
135
  export type TreeseedCiInput = {
@@ -170,6 +171,7 @@ export type TreeseedStageInput = {
170
171
  deleteBranch?: boolean;
171
172
  autoSave?: boolean;
172
173
  ciMode?: TreeseedStageCiMode | TreeseedWorkflowCiMode;
174
+ async?: boolean;
173
175
  releaseCandidate?: TreeseedReleaseCandidateMode;
174
176
  worktreeMode?: TreeseedWorkflowWorktreeMode;
175
177
  workspaceLinks?: 'auto' | 'off';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.12.43",
3
+ "version": "0.12.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": {
@@ -42,6 +42,8 @@
42
42
  "test": "npm run test:unit",
43
43
  "test:unit": "vitest run --config ./vitest.config.ts",
44
44
  "test:unit:fast": "vitest run --config ./vitest.fast.config.ts",
45
+ "test:guarantees": "vitest run --config ./vitest.guarantees.config.ts",
46
+ "test:guarantees:coverage": "vitest run --config ./vitest.guarantees.config.ts --coverage",
45
47
  "test:workflow:lifecycle": "vitest run --config ./vitest.config.ts test/utils/workflow-lifecycle.test.ts",
46
48
  "test:release": "npm run test:unit:fast",
47
49
  "test:smoke": "node --import tsx ./scripts/test-smoke.ts",
@@ -93,6 +95,7 @@
93
95
  },
94
96
  "devDependencies": {
95
97
  "@types/node": "^24.6.0",
98
+ "@vitest/coverage-v8": "^4.1.2",
96
99
  "drizzle-kit": "^0.31.10",
97
100
  "tsx": "^4.21.0",
98
101
  "vitest": "^4.1.2"