@treeseed/sdk 0.12.15 → 0.12.17
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.
- package/dist/hosting/builtins.js +1 -1
- package/dist/hosting/graph.js +11 -4
- package/dist/operations/services/railway-deploy.js +1 -1
- package/dist/reconcile/builtin-adapters.js +1 -1
- package/dist/reconcile/engine.js +5 -5
- package/dist/reconcile/state.d.ts +2 -2
- package/dist/reconcile/state.js +4 -4
- package/dist/workflow/operations.js +18 -2
- package/dist/workflow/runs.d.ts +4 -1
- package/dist/workflow/runs.js +37 -2
- package/package.json +1 -1
package/dist/hosting/builtins.js
CHANGED
|
@@ -54,7 +54,7 @@ function defaultVerify(input) {
|
|
|
54
54
|
issues: []
|
|
55
55
|
}
|
|
56
56
|
];
|
|
57
|
-
if (input.unit.host.id === "railway" && input.environment === "prod" && unitConfig(input).sourceMode === "image") {
|
|
57
|
+
if (input.unit.host.id === "railway" && input.environment === "prod" && unitConfig(input).sourceMode === "image" && input.unit.serviceType.id !== "relational-database" && unitConfig(input).resourceType !== "postgres") {
|
|
58
58
|
const imageRef = unitConfig(input).imageRef;
|
|
59
59
|
const hasImageRef = typeof imageRef === "string" && imageRef.trim().length > 0;
|
|
60
60
|
checks.push({
|
package/dist/hosting/graph.js
CHANGED
|
@@ -60,7 +60,7 @@ function resolvePublicTreeDxRoot(input) {
|
|
|
60
60
|
].filter((candidate) => Boolean(candidate));
|
|
61
61
|
return candidates.find((candidate) => existsSync(resolve(candidate, "treeseed.package.yaml")) || existsSync(resolve(candidate, ".git"))) ?? candidates[0];
|
|
62
62
|
}
|
|
63
|
-
function publicTreeDxSourcePolicy(input, config) {
|
|
63
|
+
function publicTreeDxSourcePolicy(input, config, launchEnv) {
|
|
64
64
|
const railway = config.publicTreeDxFederation?.railway ?? {};
|
|
65
65
|
const configuredSource = railway.source && typeof railway.source === "object" && !Array.isArray(railway.source) ? railway.source : {};
|
|
66
66
|
const configuredMode = typeof railway.sourceMode === "string" ? railway.sourceMode : null;
|
|
@@ -68,6 +68,7 @@ function publicTreeDxSourcePolicy(input, config) {
|
|
|
68
68
|
const repository = typeof railway.sourceRepo === "string" ? railway.sourceRepo : typeof configuredSource.repository === "string" ? configuredSource.repository : typeof configuredSource.repo === "string" ? configuredSource.repo : readPackageRepository(treeDxRoot) ?? "treeseed-ai/treedx";
|
|
69
69
|
const sourceMode = configuredMode === "git" || configuredMode === "image" ? configuredMode : input.environment === "staging" ? "git" : "image";
|
|
70
70
|
if (sourceMode !== "git") {
|
|
71
|
+
const imageRef = typeof launchEnv.TREESEED_PUBLIC_TREEDX_IMAGE_REF === "string" && launchEnv.TREESEED_PUBLIC_TREEDX_IMAGE_REF.trim() ? launchEnv.TREESEED_PUBLIC_TREEDX_IMAGE_REF.trim() : null;
|
|
71
72
|
return {
|
|
72
73
|
sourceMode: "image",
|
|
73
74
|
sourceRepo: null,
|
|
@@ -75,6 +76,7 @@ function publicTreeDxSourcePolicy(input, config) {
|
|
|
75
76
|
sourceCommit: null,
|
|
76
77
|
sourceRootDirectory: null,
|
|
77
78
|
image: "treeseed/treedx",
|
|
79
|
+
imageRef,
|
|
78
80
|
imageTagRef: "TREESEED_PUBLIC_TREEDX_IMAGE_REF"
|
|
79
81
|
};
|
|
80
82
|
}
|
|
@@ -110,6 +112,7 @@ function railwayImageRefEnvForService(serviceKey) {
|
|
|
110
112
|
if (serviceKey === "operationsRunner") return "TREESEED_OPERATIONS_RUNNER_IMAGE_REF";
|
|
111
113
|
if (serviceKey === "capacityProviderManager") return "TREESEED_AGENT_MANAGER_IMAGE_REF";
|
|
112
114
|
if (serviceKey === "capacityProviderRunner") return "TREESEED_AGENT_RUNNER_IMAGE_REF";
|
|
115
|
+
if (String(serviceKey).startsWith("public-treedx-node-")) return "TREESEED_PUBLIC_TREEDX_IMAGE_REF";
|
|
113
116
|
return null;
|
|
114
117
|
}
|
|
115
118
|
function defaultRailwayImageRefForService(serviceKey, environment) {
|
|
@@ -295,14 +298,17 @@ function buildProfileFromDeployConfig(input) {
|
|
|
295
298
|
publicTreeDxProjectGroup(environment, config),
|
|
296
299
|
privateTreeDxProjectGroup()
|
|
297
300
|
];
|
|
298
|
-
const railwayImageRefEnvKeys = [
|
|
301
|
+
const railwayImageRefEnvKeys = [.../* @__PURE__ */ new Set([
|
|
302
|
+
...Object.keys(config.services ?? {}).map((serviceKey) => railwayImageRefEnvForService(serviceKey)).filter((value) => Boolean(value)),
|
|
303
|
+
...config.hosting?.kind === "treeseed_control_plane" ? ["TREESEED_PUBLIC_TREEDX_IMAGE_REF"] : []
|
|
304
|
+
])];
|
|
299
305
|
let railwayImageRefEnv = {};
|
|
300
306
|
try {
|
|
301
307
|
railwayImageRefEnv = resolveTreeseedMachineEnvironmentValues(input.configRoot ?? input.tenantRoot, environment, railwayImageRefEnvKeys);
|
|
302
308
|
} catch {
|
|
303
309
|
railwayImageRefEnv = {};
|
|
304
310
|
}
|
|
305
|
-
const launchEnv = mergeRecord(process.env,
|
|
311
|
+
const launchEnv = mergeRecord(railwayImageRefEnv, process.env, input.env);
|
|
306
312
|
if (config.surfaces?.web && config.surfaces.web.enabled !== false) {
|
|
307
313
|
services.push({
|
|
308
314
|
id: "web",
|
|
@@ -419,7 +425,7 @@ function buildProfileFromDeployConfig(input) {
|
|
|
419
425
|
}
|
|
420
426
|
if (config.hosting?.kind === "treeseed_control_plane") {
|
|
421
427
|
const treeDxNodePool = publicTreeDxNodePool(config);
|
|
422
|
-
const treeDxSourcePolicy = publicTreeDxSourcePolicy(input, config);
|
|
428
|
+
const treeDxSourcePolicy = publicTreeDxSourcePolicy(input, config, launchEnv);
|
|
423
429
|
const treeDxNodeUnits = Array.from({ length: treeDxNodePool.bootstrapCount }, (_, offset) => {
|
|
424
430
|
const nodeIndex = offset + 1;
|
|
425
431
|
const serviceName = indexedName("public-treedx-node", nodeIndex);
|
|
@@ -431,6 +437,7 @@ function buildProfileFromDeployConfig(input) {
|
|
|
431
437
|
projectGroupId: "public-treedx-federation",
|
|
432
438
|
config: {
|
|
433
439
|
...treeDxSourcePolicy.image ? { image: treeDxSourcePolicy.image } : {},
|
|
440
|
+
...treeDxSourcePolicy.imageRef ? { imageRef: treeDxSourcePolicy.imageRef } : {},
|
|
434
441
|
...treeDxSourcePolicy.imageTagRef ? { imageTagRef: treeDxSourcePolicy.imageTagRef } : {},
|
|
435
442
|
sourceMode: treeDxSourcePolicy.sourceMode,
|
|
436
443
|
...treeDxSourcePolicy.sourceRepo ? { sourceRepo: treeDxSourcePolicy.sourceRepo } : {},
|
|
@@ -629,7 +629,7 @@ function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, app
|
|
|
629
629
|
} catch {
|
|
630
630
|
machineEnv = {};
|
|
631
631
|
}
|
|
632
|
-
const imageRefEnv = { ...process.env, ...
|
|
632
|
+
const imageRefEnv = { ...machineEnv, ...process.env, ...envOverlay };
|
|
633
633
|
let identity;
|
|
634
634
|
try {
|
|
635
635
|
identity = resolveTreeseedResourceIdentity(deployConfig, createPersistentDeployTarget(normalizedScope));
|
|
@@ -2134,7 +2134,7 @@ function getPersistedCustomDomainState(input, provider, domain) {
|
|
|
2134
2134
|
}
|
|
2135
2135
|
if (provider === "railway") {
|
|
2136
2136
|
try {
|
|
2137
|
-
const state = loadTreeseedReconcileState(input.context.tenantRoot, input.context.target);
|
|
2137
|
+
const state = loadTreeseedReconcileState(input.context.tenantRoot, input.context.target, input.context.launchEnv);
|
|
2138
2138
|
const unitId = createTreeseedReconcileUnitId("custom-domain:api", domain);
|
|
2139
2139
|
const unit = state.units[unitId];
|
|
2140
2140
|
const reconciled = unit?.lastReconciledState;
|
package/dist/reconcile/engine.js
CHANGED
|
@@ -204,7 +204,7 @@ async function refreshTreeseedUnits({
|
|
|
204
204
|
const units = filterUnitsBySelector(baseUnits, selector);
|
|
205
205
|
const deployConfig = derived.deployConfig;
|
|
206
206
|
const registry = createTreeseedReconcileRegistry(deployConfig);
|
|
207
|
-
const reconcileState = loadTreeseedReconcileState(tenantRoot, target);
|
|
207
|
+
const reconcileState = loadTreeseedReconcileState(tenantRoot, target, env);
|
|
208
208
|
const context = createRunContext(tenantRoot, target, env, write);
|
|
209
209
|
const observations = /* @__PURE__ */ new Map();
|
|
210
210
|
await runByDependencyLevel(topologicallySortDesiredUnits(units), async (unit) => {
|
|
@@ -294,7 +294,7 @@ async function reconcileTreeseedTarget({
|
|
|
294
294
|
const persistVerifiedResult = async (persisted, verifiedResult) => {
|
|
295
295
|
persistChain = persistChain.then(() => {
|
|
296
296
|
persistResult(planned.state, persisted, verifiedResult);
|
|
297
|
-
writeTreeseedReconcileState(tenantRoot, planned.state);
|
|
297
|
+
writeTreeseedReconcileState(tenantRoot, planned.state, env);
|
|
298
298
|
});
|
|
299
299
|
await persistChain;
|
|
300
300
|
};
|
|
@@ -458,7 +458,7 @@ async function reconcileTreeseedTarget({
|
|
|
458
458
|
results.push(verifiedResult);
|
|
459
459
|
});
|
|
460
460
|
if (!dryRun) {
|
|
461
|
-
writeTreeseedReconcileState(tenantRoot, planned.state);
|
|
461
|
+
writeTreeseedReconcileState(tenantRoot, planned.state, env);
|
|
462
462
|
}
|
|
463
463
|
return {
|
|
464
464
|
target,
|
|
@@ -477,10 +477,10 @@ async function destroyTreeseedTargetUnits({
|
|
|
477
477
|
units: explicitUnits,
|
|
478
478
|
write
|
|
479
479
|
}) {
|
|
480
|
-
const { units: allUnits, deployConfig } = deriveTreeseedDesiredUnits({ tenantRoot, target });
|
|
480
|
+
const { units: allUnits, deployConfig } = deriveTreeseedDesiredUnits({ tenantRoot, target, env });
|
|
481
481
|
const units = filterUnitsBySelector(explicitUnits ?? allUnits, selector);
|
|
482
482
|
const registry = createTreeseedReconcileRegistry(deployConfig);
|
|
483
|
-
const reconcileState = loadTreeseedReconcileState(tenantRoot, target);
|
|
483
|
+
const reconcileState = loadTreeseedReconcileState(tenantRoot, target, env);
|
|
484
484
|
const context = createRunContext(tenantRoot, target, env, write);
|
|
485
485
|
const results = [];
|
|
486
486
|
for (const unit of reverseTopologicallySortedUnits(units)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TreeseedDesiredUnit, TreeseedReconcileStateRecord, TreeseedReconcileTarget, TreeseedUnitPersistedState } from './contracts.js';
|
|
2
2
|
export declare function migrateLegacyDeployStateUnits(legacyState: Record<string, any>, target: TreeseedReconcileTarget): Record<string, TreeseedUnitPersistedState>;
|
|
3
|
-
export declare function loadTreeseedReconcileState(tenantRoot: string, target: TreeseedReconcileTarget): TreeseedReconcileStateRecord;
|
|
4
|
-
export declare function writeTreeseedReconcileState(tenantRoot: string, reconcileState: TreeseedReconcileStateRecord): void;
|
|
3
|
+
export declare function loadTreeseedReconcileState(tenantRoot: string, target: TreeseedReconcileTarget, env?: NodeJS.ProcessEnv | Record<string, string | undefined>): TreeseedReconcileStateRecord;
|
|
4
|
+
export declare function writeTreeseedReconcileState(tenantRoot: string, reconcileState: TreeseedReconcileStateRecord, env?: NodeJS.ProcessEnv | Record<string, string | undefined>): void;
|
|
5
5
|
export declare function ensureTreeseedPersistedUnitState(reconcileState: TreeseedReconcileStateRecord, unit: TreeseedDesiredUnit): TreeseedUnitPersistedState;
|
|
6
6
|
export declare function updateTreeseedPersistedUnitState(reconcileState: TreeseedReconcileStateRecord, state: TreeseedUnitPersistedState): void;
|
|
7
7
|
export declare function desiredUnitSpecHash(unit: TreeseedDesiredUnit): string;
|
package/dist/reconcile/state.js
CHANGED
|
@@ -227,8 +227,8 @@ function migrateLegacyDeployStateUnits(legacyState, target) {
|
|
|
227
227
|
}
|
|
228
228
|
return units;
|
|
229
229
|
}
|
|
230
|
-
function loadTreeseedReconcileState(tenantRoot, target) {
|
|
231
|
-
const deployConfig = loadTreeseedPlatformConfig({ tenantRoot, environment: target.kind === "persistent" ? target.scope : "staging", env
|
|
230
|
+
function loadTreeseedReconcileState(tenantRoot, target, env = process.env) {
|
|
231
|
+
const deployConfig = loadTreeseedPlatformConfig({ tenantRoot, environment: target.kind === "persistent" ? target.scope : "staging", env }).deployConfig;
|
|
232
232
|
const legacyState = loadDeployState(tenantRoot, deployConfig, { target });
|
|
233
233
|
const persistedUnits = legacyState.units && typeof legacyState.units === "object" ? legacyState.units : migrateLegacyDeployStateUnits(legacyState, target);
|
|
234
234
|
return {
|
|
@@ -238,8 +238,8 @@ function loadTreeseedReconcileState(tenantRoot, target) {
|
|
|
238
238
|
units: { ...persistedUnits }
|
|
239
239
|
};
|
|
240
240
|
}
|
|
241
|
-
function writeTreeseedReconcileState(tenantRoot, reconcileState) {
|
|
242
|
-
const deployConfig = loadTreeseedPlatformConfig({ tenantRoot, environment: reconcileState.target.kind === "persistent" ? reconcileState.target.scope : "staging", env
|
|
241
|
+
function writeTreeseedReconcileState(tenantRoot, reconcileState, env = process.env) {
|
|
242
|
+
const deployConfig = loadTreeseedPlatformConfig({ tenantRoot, environment: reconcileState.target.kind === "persistent" ? reconcileState.target.scope : "staging", env }).deployConfig;
|
|
243
243
|
const legacyState = loadDeployState(tenantRoot, deployConfig, { target: reconcileState.target });
|
|
244
244
|
writeDeployState(tenantRoot, {
|
|
245
245
|
...legacyState,
|
|
@@ -1708,7 +1708,7 @@ function prepareFreshReleaseRun(root, branch, rootRepo, packageReports) {
|
|
|
1708
1708
|
]);
|
|
1709
1709
|
const archived = [];
|
|
1710
1710
|
const blockers = [];
|
|
1711
|
-
for (const journal of listInterruptedWorkflowRuns(root).filter((entry) => entry.command === "release")) {
|
|
1711
|
+
for (const journal of listInterruptedWorkflowRuns(root, { recentLimit: 50 }).filter((entry) => entry.command === "release")) {
|
|
1712
1712
|
const classification = classifyWorkflowRunJournal(journal, {
|
|
1713
1713
|
currentBranch: branch,
|
|
1714
1714
|
currentHeads
|
|
@@ -1741,7 +1741,7 @@ function findAutoResumableReleaseRun(root, branch, rootRepo, packageReports, opt
|
|
|
1741
1741
|
[rootRepo.name, rootRepo.commitSha ?? null],
|
|
1742
1742
|
...packageReports.map((report) => [report.name, report.commitSha ?? null])
|
|
1743
1743
|
]);
|
|
1744
|
-
return listInterruptedWorkflowRuns(root).find((journal) => {
|
|
1744
|
+
return listInterruptedWorkflowRuns(root, { recentLimit: 50 }).find((journal) => {
|
|
1745
1745
|
if (journal.command !== "release" || !journal.resumable || journal.session.branchName !== STAGING_BRANCH) {
|
|
1746
1746
|
return false;
|
|
1747
1747
|
}
|
|
@@ -5246,22 +5246,32 @@ ${blockers.join("\n")}`, {
|
|
|
5246
5246
|
async function workflowRelease(helpers, input) {
|
|
5247
5247
|
try {
|
|
5248
5248
|
return await withContextEnv(helpers.context.env, async () => {
|
|
5249
|
+
const traceReleaseStartup = (phase) => {
|
|
5250
|
+
console.error(`[release][startup] ${phase}`);
|
|
5251
|
+
};
|
|
5252
|
+
traceReleaseStartup("resolve workspace");
|
|
5249
5253
|
const root = workspaceRoot(resolveProjectRootOrThrow("release", helpers.cwd()));
|
|
5254
|
+
traceReleaseStartup("resolve session");
|
|
5250
5255
|
const session = resolveTreeseedWorkflowSession(root);
|
|
5251
5256
|
const executionMode = normalizeExecutionMode(input);
|
|
5257
|
+
traceReleaseStartup("inspect root repo");
|
|
5252
5258
|
const rootRepo = createWorkspaceRootRepoReport(root);
|
|
5259
|
+
traceReleaseStartup("inspect package repos");
|
|
5253
5260
|
const packageReports = createWorkspacePackageReports(root);
|
|
5254
5261
|
const explicitResumeRunId = helpers.context.workflow?.resumeRunId ?? null;
|
|
5262
|
+
traceReleaseStartup("check auto resume");
|
|
5255
5263
|
const autoResumeRun = executionMode === "execute" && !explicitResumeRunId && input.fresh !== true ? findAutoResumableReleaseRun(root, session.branchName, rootRepo, packageReports, { archiveStale: false }) : null;
|
|
5256
5264
|
const planAutoResumeRun = executionMode === "plan" && input.fresh !== true ? findAutoResumableReleaseRun(root, session.branchName, rootRepo, packageReports) : null;
|
|
5257
5265
|
const effectiveInput = autoResumeRun ? {
|
|
5258
5266
|
...autoResumeRun.input,
|
|
5259
5267
|
ciMode: input.ciMode ?? autoResumeRun.input.ciMode
|
|
5260
5268
|
} : input;
|
|
5269
|
+
traceReleaseStartup("local cleanup");
|
|
5261
5270
|
const localCleanup = maybeRunLocalWorkflowCleanup(helpers, root, "release", effectiveInput);
|
|
5262
5271
|
const level = effectiveInput.bump ?? "patch";
|
|
5263
5272
|
const ciMode = normalizeCiMode(effectiveInput.ciMode, "release");
|
|
5264
5273
|
const packageSelection = session.packageSelection;
|
|
5274
|
+
traceReleaseStartup("build release plan");
|
|
5265
5275
|
const plannedRelease = buildReleasePlanSnapshot({
|
|
5266
5276
|
root,
|
|
5267
5277
|
mode: session.mode,
|
|
@@ -5274,10 +5284,12 @@ async function workflowRelease(helpers, input) {
|
|
|
5274
5284
|
blockers: []
|
|
5275
5285
|
});
|
|
5276
5286
|
const selectedPackageNames = releasePlanPackageSelection(plannedRelease.packageSelection).selected;
|
|
5287
|
+
traceReleaseStartup("collect blockers");
|
|
5277
5288
|
const blockers = collectReleasePlanBlockers(session, session.mode, selectedPackageNames, {
|
|
5278
5289
|
level,
|
|
5279
5290
|
repairVersionLine: effectiveInput.repairVersionLine === true
|
|
5280
5291
|
});
|
|
5292
|
+
traceReleaseStartup("collect production readiness");
|
|
5281
5293
|
const plannedReadiness = collectTreeseedDeploymentReadiness({
|
|
5282
5294
|
tenantRoot: root,
|
|
5283
5295
|
environment: "prod",
|
|
@@ -5314,13 +5326,16 @@ async function workflowRelease(helpers, input) {
|
|
|
5314
5326
|
releaseBasePayload
|
|
5315
5327
|
);
|
|
5316
5328
|
}
|
|
5329
|
+
traceReleaseStartup("validate blockers");
|
|
5317
5330
|
if (blockers.length > 0) {
|
|
5318
5331
|
workflowError("release", "validation_failed", `Treeseed release cannot continue until blockers are resolved:
|
|
5319
5332
|
${blockers.join("\n")}`, {
|
|
5320
5333
|
details: { blockers, releasePlan: plannedRelease }
|
|
5321
5334
|
});
|
|
5322
5335
|
}
|
|
5336
|
+
traceReleaseStartup("prepare fresh release");
|
|
5323
5337
|
const freshPreparation = input.fresh === true ? prepareFreshReleaseRun(root, session.branchName, rootRepo, packageReports) : { archived: [], blockers: [] };
|
|
5338
|
+
traceReleaseStartup("compute versions");
|
|
5324
5339
|
const selectedVersions = releasePlanVersionMap(plannedRelease.plannedVersions);
|
|
5325
5340
|
const stableVersions = new Map([
|
|
5326
5341
|
...releasePlanStableDependencyVersionMap(plannedRelease).entries(),
|
|
@@ -5331,6 +5346,7 @@ ${blockers.join("\n")}`, {
|
|
|
5331
5346
|
...stableVersions.entries()
|
|
5332
5347
|
]);
|
|
5333
5348
|
const selectedPackageSet = new Set(selectedPackageNames);
|
|
5349
|
+
traceReleaseStartup("acquire workflow run");
|
|
5334
5350
|
const workflowRun = acquireWorkflowRun(
|
|
5335
5351
|
"release",
|
|
5336
5352
|
session,
|
package/dist/workflow/runs.d.ts
CHANGED
|
@@ -131,4 +131,7 @@ export declare function createWorkflowRunJournal(root: string, options: {
|
|
|
131
131
|
steps: Omit<TreeseedWorkflowRunStep, 'status' | 'completedAt' | 'data'>[];
|
|
132
132
|
}): TreeseedWorkflowRunJournal;
|
|
133
133
|
export declare function listWorkflowRunJournals(root: string): TreeseedWorkflowRunJournal[];
|
|
134
|
-
export declare function
|
|
134
|
+
export declare function listRecentWorkflowRunJournals(root: string, limit?: number): TreeseedWorkflowRunJournal[];
|
|
135
|
+
export declare function listInterruptedWorkflowRuns(root: string, options?: {
|
|
136
|
+
recentLimit?: number;
|
|
137
|
+
}): TreeseedWorkflowRunJournal[];
|
package/dist/workflow/runs.js
CHANGED
|
@@ -576,8 +576,42 @@ function listWorkflowRunJournals(root) {
|
|
|
576
576
|
}
|
|
577
577
|
return [...byId.values()].sort((left, right) => right.createdAt.localeCompare(left.createdAt));
|
|
578
578
|
}
|
|
579
|
-
function
|
|
580
|
-
|
|
579
|
+
function listRecentWorkflowRunJournalsForScope(root, scope, limit) {
|
|
580
|
+
const runsDir = workflowRunsRoot(root, null, scope);
|
|
581
|
+
if (!existsSync(runsDir)) {
|
|
582
|
+
return [];
|
|
583
|
+
}
|
|
584
|
+
return readdirSync(runsDir).filter((entry) => entry.endsWith(".json")).map((entry) => {
|
|
585
|
+
const path = resolve(runsDir, entry);
|
|
586
|
+
try {
|
|
587
|
+
return { path, mtimeMs: statSync(path).mtimeMs };
|
|
588
|
+
} catch {
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
}).filter((entry) => entry != null).sort((left, right) => right.mtimeMs - left.mtimeMs).slice(0, Math.max(1, limit)).map((entry) => {
|
|
592
|
+
try {
|
|
593
|
+
if (statSync(entry.path).size > 5 * 1024 * 1024) {
|
|
594
|
+
const archivedSummary = archivedWorkflowRunSummary(entry.path);
|
|
595
|
+
if (archivedSummary) return archivedSummary;
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
return safeJsonParse(entry.path);
|
|
601
|
+
}).filter((entry) => entry != null);
|
|
602
|
+
}
|
|
603
|
+
function listRecentWorkflowRunJournals(root, limit = 50) {
|
|
604
|
+
const local = listRecentWorkflowRunJournalsForScope(root, "worktree", limit);
|
|
605
|
+
const shared = listRecentWorkflowRunJournalsForScope(root, "shared", limit);
|
|
606
|
+
const byId = /* @__PURE__ */ new Map();
|
|
607
|
+
for (const journal of [...local, ...shared]) {
|
|
608
|
+
byId.set(journal.runId, journal);
|
|
609
|
+
}
|
|
610
|
+
return [...byId.values()].sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, Math.max(1, limit));
|
|
611
|
+
}
|
|
612
|
+
function listInterruptedWorkflowRuns(root, options = {}) {
|
|
613
|
+
const journals = options.recentLimit ? listRecentWorkflowRunJournals(root, options.recentLimit) : listWorkflowRunJournals(root);
|
|
614
|
+
return journals.filter((journal) => journal.status === "failed" && journal.resumable);
|
|
581
615
|
}
|
|
582
616
|
export {
|
|
583
617
|
acquireWorkflowLock,
|
|
@@ -591,6 +625,7 @@ export {
|
|
|
591
625
|
inspectWorkflowLock,
|
|
592
626
|
isSharedWorkflowCommand,
|
|
593
627
|
listInterruptedWorkflowRuns,
|
|
628
|
+
listRecentWorkflowRunJournals,
|
|
594
629
|
listWorkflowRunJournals,
|
|
595
630
|
readWorkflowRunJournal,
|
|
596
631
|
refreshWorkflowLock,
|