@ontrails/trails 1.0.0-beta.2 → 1.0.0-beta.22
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/CHANGELOG.md +647 -0
- package/README.md +26 -0
- package/package.json +28 -7
- package/src/app.ts +86 -2
- package/src/clack.ts +22 -0
- package/src/cli.ts +330 -11
- package/src/completions.ts +240 -0
- package/src/lifecycle-source-io.ts +33 -0
- package/src/load-app-mirror.ts +202 -0
- package/src/local-state-io.ts +153 -0
- package/src/mcp-app.ts +30 -0
- package/src/mcp-options.ts +77 -0
- package/src/mcp.ts +8 -0
- package/src/project-writes.ts +377 -0
- package/src/release/bindings.ts +39 -0
- package/src/release/check.ts +818 -0
- package/src/release/config.ts +63 -0
- package/src/release/contract-facts.ts +425 -0
- package/src/release/index.ts +85 -0
- package/src/release/native-bun-publish.ts +651 -0
- package/src/release/native-bun-registry.ts +350 -0
- package/src/release/packed-artifacts-smoke.ts +236 -0
- package/src/release/smoke.ts +46 -0
- package/src/release/wayfinder-dogfood-smoke.ts +226 -0
- package/src/retired-topo-command.ts +36 -0
- package/src/run-adapter-check.ts +76 -0
- package/src/run-collision.ts +126 -0
- package/src/run-completions-install.ts +179 -0
- package/src/run-example.ts +149 -0
- package/src/run-examples.ts +148 -0
- package/src/run-quiet.ts +75 -0
- package/src/run-release-check.ts +74 -0
- package/src/run-trace.ts +273 -0
- package/src/run-warden.ts +39 -0
- package/src/run-watch.ts +432 -0
- package/src/scaffold-version-sync.ts +183 -0
- package/src/scaffold-versions.generated.ts +12 -0
- package/src/trails/adapter-check.ts +244 -0
- package/src/trails/add-surface.ts +94 -40
- package/src/trails/add-trail.ts +79 -41
- package/src/trails/add-verify.ts +95 -25
- package/src/trails/compile.ts +67 -0
- package/src/trails/completions-complete.ts +165 -0
- package/src/trails/completions.ts +47 -0
- package/src/trails/create-adapter.ts +1084 -0
- package/src/trails/create-scaffold.ts +399 -104
- package/src/trails/create-versions.ts +62 -0
- package/src/trails/create.ts +185 -71
- package/src/trails/deprecate.ts +59 -0
- package/src/trails/dev-clean.ts +82 -0
- package/src/trails/dev-reset.ts +50 -0
- package/src/trails/dev-stats.ts +72 -0
- package/src/trails/dev-support.ts +340 -0
- package/src/trails/doctor.ts +56 -0
- package/src/trails/draft-promote.ts +949 -0
- package/src/trails/guide.ts +74 -68
- package/src/trails/load-app.ts +1143 -15
- package/src/trails/project.ts +17 -3
- package/src/trails/release-check.ts +104 -0
- package/src/trails/release-smoke.ts +48 -0
- package/src/trails/revise.ts +53 -0
- package/src/trails/root-dir.ts +21 -0
- package/src/trails/run-example.ts +491 -0
- package/src/trails/run-examples.ts +145 -0
- package/src/trails/run.ts +410 -0
- package/src/trails/scaffold-json.ts +58 -0
- package/src/trails/survey.ts +881 -226
- package/src/trails/topo-activation.ts +385 -0
- package/src/trails/topo-constants.ts +2 -0
- package/src/trails/topo-history.ts +47 -0
- package/src/trails/topo-output-schemas.ts +248 -0
- package/src/trails/topo-pin.ts +52 -0
- package/src/trails/topo-read-support.ts +313 -0
- package/src/trails/topo-reports.ts +807 -0
- package/src/trails/topo-store-support.ts +174 -0
- package/src/trails/topo-support.ts +220 -0
- package/src/trails/topo-unpin.ts +61 -0
- package/src/trails/topo.ts +106 -0
- package/src/trails/validate.ts +38 -0
- package/src/trails/version-lifecycle-support.ts +945 -0
- package/src/trails/warden-guide.ts +129 -0
- package/src/trails/warden.ts +165 -58
- package/src/versions.ts +31 -0
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/__tests__/examples.test.ts +0 -6
- package/dist/bin/trails.d.ts +0 -3
- package/dist/bin/trails.d.ts.map +0 -1
- package/dist/bin/trails.js +0 -4
- package/dist/bin/trails.js.map +0 -1
- package/dist/src/app.d.ts +0 -2
- package/dist/src/app.d.ts.map +0 -1
- package/dist/src/app.js +0 -11
- package/dist/src/app.js.map +0 -1
- package/dist/src/clack.d.ts +0 -9
- package/dist/src/clack.d.ts.map +0 -1
- package/dist/src/clack.js +0 -62
- package/dist/src/clack.js.map +0 -1
- package/dist/src/cli.d.ts +0 -2
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -13
- package/dist/src/cli.js.map +0 -1
- package/dist/src/trails/add-surface.d.ts +0 -13
- package/dist/src/trails/add-surface.d.ts.map +0 -1
- package/dist/src/trails/add-surface.js +0 -88
- package/dist/src/trails/add-surface.js.map +0 -1
- package/dist/src/trails/add-trail.d.ts +0 -11
- package/dist/src/trails/add-trail.d.ts.map +0 -1
- package/dist/src/trails/add-trail.js +0 -85
- package/dist/src/trails/add-trail.js.map +0 -1
- package/dist/src/trails/add-verify.d.ts +0 -10
- package/dist/src/trails/add-verify.d.ts.map +0 -1
- package/dist/src/trails/add-verify.js +0 -67
- package/dist/src/trails/add-verify.js.map +0 -1
- package/dist/src/trails/create-scaffold.d.ts +0 -15
- package/dist/src/trails/create-scaffold.d.ts.map +0 -1
- package/dist/src/trails/create-scaffold.js +0 -288
- package/dist/src/trails/create-scaffold.js.map +0 -1
- package/dist/src/trails/create.d.ts +0 -22
- package/dist/src/trails/create.d.ts.map +0 -1
- package/dist/src/trails/create.js +0 -121
- package/dist/src/trails/create.js.map +0 -1
- package/dist/src/trails/guide.d.ts +0 -11
- package/dist/src/trails/guide.d.ts.map +0 -1
- package/dist/src/trails/guide.js +0 -80
- package/dist/src/trails/guide.js.map +0 -1
- package/dist/src/trails/load-app.d.ts +0 -4
- package/dist/src/trails/load-app.d.ts.map +0 -1
- package/dist/src/trails/load-app.js +0 -24
- package/dist/src/trails/load-app.js.map +0 -1
- package/dist/src/trails/project.d.ts +0 -8
- package/dist/src/trails/project.d.ts.map +0 -1
- package/dist/src/trails/project.js +0 -43
- package/dist/src/trails/project.js.map +0 -1
- package/dist/src/trails/survey.d.ts +0 -33
- package/dist/src/trails/survey.d.ts.map +0 -1
- package/dist/src/trails/survey.js +0 -225
- package/dist/src/trails/survey.js.map +0 -1
- package/dist/src/trails/warden.d.ts +0 -19
- package/dist/src/trails/warden.d.ts.map +0 -1
- package/dist/src/trails/warden.js +0 -88
- package/dist/src/trails/warden.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/__tests__/create.test.ts +0 -349
- package/src/__tests__/guide.test.ts +0 -91
- package/src/__tests__/load-app.test.ts +0 -15
- package/src/__tests__/survey.test.ts +0 -161
- package/src/__tests__/warden.test.ts +0 -74
- package/tsconfig.json +0 -9
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Result, trail } from '@ontrails/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { tryLoadFreshAppLease } from './load-app.js';
|
|
5
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
6
|
+
import {
|
|
7
|
+
createIsolatedExampleInput,
|
|
8
|
+
pinCurrentTopoSnapshot,
|
|
9
|
+
topoSnapshotOutput,
|
|
10
|
+
} from './topo-support.js';
|
|
11
|
+
|
|
12
|
+
export const topoPinTrail = trail('topo.pin', {
|
|
13
|
+
blaze: async (input, ctx) => {
|
|
14
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
15
|
+
if (rootDirResult.isErr()) {
|
|
16
|
+
return rootDirResult;
|
|
17
|
+
}
|
|
18
|
+
const rootDir = rootDirResult.value;
|
|
19
|
+
const leaseResult = await tryLoadFreshAppLease(input.module, rootDir);
|
|
20
|
+
if (leaseResult.isErr()) {
|
|
21
|
+
return leaseResult;
|
|
22
|
+
}
|
|
23
|
+
const lease = leaseResult.value;
|
|
24
|
+
try {
|
|
25
|
+
return Result.ok(
|
|
26
|
+
pinCurrentTopoSnapshot(lease.app, { name: input.name, rootDir })
|
|
27
|
+
);
|
|
28
|
+
} finally {
|
|
29
|
+
lease.release();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
description: 'Pin the current topo under a durable name',
|
|
33
|
+
examples: [
|
|
34
|
+
{
|
|
35
|
+
input: {
|
|
36
|
+
...createIsolatedExampleInput('topo-pin'),
|
|
37
|
+
name: 'before-auth-refactor',
|
|
38
|
+
},
|
|
39
|
+
name: 'Pin the current topo',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
input: z.object({
|
|
43
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
44
|
+
name: z.string().describe('Pin name'),
|
|
45
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
46
|
+
}),
|
|
47
|
+
intent: 'write',
|
|
48
|
+
output: z.object({
|
|
49
|
+
snapshot: topoSnapshotOutput,
|
|
50
|
+
}),
|
|
51
|
+
permit: { scopes: ['topo:write'] },
|
|
52
|
+
});
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only live topo consumer helpers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from topo-support.ts to isolate read-only topo consumer helpers,
|
|
5
|
+
* keeping module boundaries clean.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
import type { Topo, TrailContext } from '@ontrails/core';
|
|
12
|
+
import {
|
|
13
|
+
ConflictError,
|
|
14
|
+
deriveTrailsDbPath,
|
|
15
|
+
deriveTrailsDir,
|
|
16
|
+
NotFoundError,
|
|
17
|
+
Result,
|
|
18
|
+
SURFACE_LAYER_NAMES_KEY,
|
|
19
|
+
ValidationError,
|
|
20
|
+
} from '@ontrails/core';
|
|
21
|
+
import {
|
|
22
|
+
deriveTopoGraph,
|
|
23
|
+
deriveTopoGraphDiff,
|
|
24
|
+
deriveTopoGraphHash,
|
|
25
|
+
readLockManifest,
|
|
26
|
+
readTopoGraph,
|
|
27
|
+
stripTopoGraphForces,
|
|
28
|
+
} from '@ontrails/topographer';
|
|
29
|
+
import type { TopoGraph } from '@ontrails/topographer';
|
|
30
|
+
|
|
31
|
+
import type {
|
|
32
|
+
BriefReport,
|
|
33
|
+
SignalDetailReport,
|
|
34
|
+
SurfaceLayerNames,
|
|
35
|
+
SurveyListReport,
|
|
36
|
+
TrailDetailReport,
|
|
37
|
+
} from './topo-reports.js';
|
|
38
|
+
import {
|
|
39
|
+
countTrailExamples,
|
|
40
|
+
deriveBriefReport,
|
|
41
|
+
deriveResourceDetail,
|
|
42
|
+
deriveSignalDetail,
|
|
43
|
+
deriveSurveyList,
|
|
44
|
+
deriveTrailDetail,
|
|
45
|
+
} from './topo-reports.js';
|
|
46
|
+
import type { ActivationGraphReport } from './topo-activation.js';
|
|
47
|
+
import { deriveActivationGraph } from './topo-activation.js';
|
|
48
|
+
import type { TopoSummaryReport, TopoValidateReport } from './topo-support.js';
|
|
49
|
+
import { deriveRootDir, LOCK_PATH } from './topo-support.js';
|
|
50
|
+
import { deriveCurrentTopoExport } from './topo-store-support.js';
|
|
51
|
+
|
|
52
|
+
export type CurrentTrailDetail = TrailDetailReport;
|
|
53
|
+
|
|
54
|
+
export interface CurrentResourceDetail {
|
|
55
|
+
readonly description: string | null;
|
|
56
|
+
readonly health: 'available' | 'none';
|
|
57
|
+
readonly id: string;
|
|
58
|
+
readonly kind: 'resource';
|
|
59
|
+
readonly lifetime: 'singleton';
|
|
60
|
+
readonly usedBy: readonly string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type CurrentTopoDetail =
|
|
64
|
+
| CurrentResourceDetail
|
|
65
|
+
| CurrentTrailDetail
|
|
66
|
+
| SignalDetailReport;
|
|
67
|
+
|
|
68
|
+
export interface CurrentTopoMatch {
|
|
69
|
+
readonly kind: CurrentTopoDetail['kind'];
|
|
70
|
+
readonly detail: CurrentTopoDetail;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface CurrentTopoReadOptions {
|
|
74
|
+
readonly rootDir?: string | undefined;
|
|
75
|
+
readonly surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const isStringArray = (value: unknown): value is readonly string[] =>
|
|
79
|
+
Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
80
|
+
|
|
81
|
+
export const readSurfaceLayerNamesFromContext = (
|
|
82
|
+
ctx: TrailContext
|
|
83
|
+
): Partial<SurfaceLayerNames> => {
|
|
84
|
+
const value = ctx.extensions?.[SURFACE_LAYER_NAMES_KEY];
|
|
85
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
86
|
+
return {};
|
|
87
|
+
}
|
|
88
|
+
const raw = value as Record<string, unknown>;
|
|
89
|
+
return {
|
|
90
|
+
...(isStringArray(raw['cli']) ? { cli: raw['cli'] } : {}),
|
|
91
|
+
...(isStringArray(raw['http']) ? { http: raw['http'] } : {}),
|
|
92
|
+
...(isStringArray(raw['mcp']) ? { mcp: raw['mcp'] } : {}),
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const hasCommittedLock = (trailsDir: string): boolean =>
|
|
97
|
+
existsSync(join(trailsDir, 'trails.lock'));
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Public read-only consumers
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
export const buildTopoSummary = (
|
|
104
|
+
app: Topo,
|
|
105
|
+
options?: { readonly rootDir?: string }
|
|
106
|
+
): TopoSummaryReport => {
|
|
107
|
+
const rootDir = deriveRootDir(options?.rootDir);
|
|
108
|
+
const trailsDir = deriveTrailsDir({ rootDir });
|
|
109
|
+
return {
|
|
110
|
+
app: deriveBriefReport(app),
|
|
111
|
+
dbPath: deriveTrailsDbPath({ rootDir }),
|
|
112
|
+
list: deriveSurveyList(app),
|
|
113
|
+
lockExists: hasCommittedLock(trailsDir),
|
|
114
|
+
lockPath: LOCK_PATH,
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const buildCurrentTopoBrief = (
|
|
119
|
+
app: Topo,
|
|
120
|
+
_options?: { readonly rootDir?: string }
|
|
121
|
+
): BriefReport => deriveBriefReport(app);
|
|
122
|
+
|
|
123
|
+
export const buildCurrentTopoList = (
|
|
124
|
+
app: Topo,
|
|
125
|
+
_options?: { readonly rootDir?: string }
|
|
126
|
+
): SurveyListReport => deriveSurveyList(app);
|
|
127
|
+
|
|
128
|
+
export const buildCurrentGuideEntries = (
|
|
129
|
+
app: Topo,
|
|
130
|
+
_options?: { readonly rootDir?: string }
|
|
131
|
+
): readonly {
|
|
132
|
+
readonly description: string;
|
|
133
|
+
readonly exampleCount: number;
|
|
134
|
+
readonly id: string;
|
|
135
|
+
readonly kind: 'trail';
|
|
136
|
+
}[] =>
|
|
137
|
+
app
|
|
138
|
+
.list()
|
|
139
|
+
.map((trail) => ({
|
|
140
|
+
description: trail.description ?? '(no description)',
|
|
141
|
+
exampleCount: countTrailExamples(trail),
|
|
142
|
+
id: trail.id,
|
|
143
|
+
kind: 'trail' as const,
|
|
144
|
+
}))
|
|
145
|
+
.toSorted((a, b) => a.id.localeCompare(b.id));
|
|
146
|
+
|
|
147
|
+
export const buildCurrentTrailDetail = (
|
|
148
|
+
app: Topo,
|
|
149
|
+
id: string,
|
|
150
|
+
options?: CurrentTopoReadOptions
|
|
151
|
+
): CurrentTrailDetail | undefined => {
|
|
152
|
+
const trail = app.get(id);
|
|
153
|
+
return trail === undefined
|
|
154
|
+
? undefined
|
|
155
|
+
: deriveTrailDetail(trail, app, undefined, {
|
|
156
|
+
surfaceLayerNames: options?.surfaceLayerNames,
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const buildCurrentResourceDetail = (
|
|
161
|
+
app: Topo,
|
|
162
|
+
id: string,
|
|
163
|
+
_options?: { readonly rootDir?: string }
|
|
164
|
+
): CurrentResourceDetail | undefined =>
|
|
165
|
+
app.getResource(id) === undefined
|
|
166
|
+
? undefined
|
|
167
|
+
: (deriveResourceDetail(app, id) as CurrentResourceDetail);
|
|
168
|
+
|
|
169
|
+
export const buildCurrentSignalDetail = (
|
|
170
|
+
app: Topo,
|
|
171
|
+
id: string,
|
|
172
|
+
_options?: { readonly rootDir?: string }
|
|
173
|
+
): SignalDetailReport | undefined => deriveSignalDetail(app, id);
|
|
174
|
+
|
|
175
|
+
export const buildCurrentTopoDetail = (
|
|
176
|
+
app: Topo,
|
|
177
|
+
id: string,
|
|
178
|
+
options?: CurrentTopoReadOptions
|
|
179
|
+
): CurrentTopoDetail | undefined =>
|
|
180
|
+
buildCurrentTrailDetail(app, id, options) ??
|
|
181
|
+
buildCurrentResourceDetail(app, id) ??
|
|
182
|
+
buildCurrentSignalDetail(app, id);
|
|
183
|
+
|
|
184
|
+
export const buildCurrentTopoMatches = (
|
|
185
|
+
app: Topo,
|
|
186
|
+
id: string,
|
|
187
|
+
options?: CurrentTopoReadOptions
|
|
188
|
+
): readonly CurrentTopoMatch[] => {
|
|
189
|
+
const matches: CurrentTopoMatch[] = [];
|
|
190
|
+
let activationGraph: ActivationGraphReport | undefined;
|
|
191
|
+
const getActivationGraph = (): ActivationGraphReport =>
|
|
192
|
+
(activationGraph ??= deriveActivationGraph(app));
|
|
193
|
+
let topoGraph: ReturnType<typeof deriveTopoGraph> | undefined;
|
|
194
|
+
const getTopoGraph = (): ReturnType<typeof deriveTopoGraph> =>
|
|
195
|
+
(topoGraph ??= deriveTopoGraph(app));
|
|
196
|
+
|
|
197
|
+
const trail = app.get(id);
|
|
198
|
+
if (trail !== undefined) {
|
|
199
|
+
matches.push({
|
|
200
|
+
detail: deriveTrailDetail(trail, app, getActivationGraph(), {
|
|
201
|
+
surfaceLayerNames: options?.surfaceLayerNames,
|
|
202
|
+
topoGraph: getTopoGraph(),
|
|
203
|
+
}),
|
|
204
|
+
kind: 'trail',
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const resource = buildCurrentResourceDetail(app, id);
|
|
209
|
+
if (resource !== undefined) {
|
|
210
|
+
matches.push({ detail: resource, kind: 'resource' });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const signal = deriveSignalDetail(app, id, activationGraph);
|
|
214
|
+
if (signal !== undefined) {
|
|
215
|
+
matches.push({ detail: signal, kind: 'signal' });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return matches;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export const validateCurrentTopo = async (
|
|
222
|
+
app: Topo,
|
|
223
|
+
options?: { readonly rootDir?: string }
|
|
224
|
+
): Promise<Result<TopoValidateReport, Error>> => {
|
|
225
|
+
const rootDir = deriveRootDir(options?.rootDir);
|
|
226
|
+
let lockManifest: Awaited<ReturnType<typeof readLockManifest>>;
|
|
227
|
+
try {
|
|
228
|
+
lockManifest = await readLockManifest({
|
|
229
|
+
dir: deriveTrailsDir({ rootDir }),
|
|
230
|
+
});
|
|
231
|
+
} catch (error) {
|
|
232
|
+
const message =
|
|
233
|
+
error instanceof Error
|
|
234
|
+
? error.message
|
|
235
|
+
: 'Unable to read committed trails.lock manifest.';
|
|
236
|
+
return Result.err(
|
|
237
|
+
error instanceof Error
|
|
238
|
+
? new ValidationError(message, { cause: error })
|
|
239
|
+
: new ValidationError(message)
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (lockManifest === null) {
|
|
244
|
+
return Result.err(
|
|
245
|
+
new NotFoundError(
|
|
246
|
+
'No committed trails.lock found. Run `trails compile` first.'
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const currentExport = deriveCurrentTopoExport(app, { rootDir });
|
|
252
|
+
if (currentExport.isErr()) {
|
|
253
|
+
return currentExport;
|
|
254
|
+
}
|
|
255
|
+
const currentTopo = JSON.parse(
|
|
256
|
+
currentExport.value.topoGraphJson
|
|
257
|
+
) as TopoGraph;
|
|
258
|
+
const currentHash = currentExport.value.topoGraphHash;
|
|
259
|
+
const topoArtifact = lockManifest.artifacts.find(
|
|
260
|
+
(artifact) => artifact.role === 'topo' && artifact.path === 'topo.lock'
|
|
261
|
+
);
|
|
262
|
+
if (topoArtifact === undefined) {
|
|
263
|
+
return Result.err(
|
|
264
|
+
new NotFoundError(
|
|
265
|
+
'No topo.lock artifact found in trails.lock. Run `trails compile` first.'
|
|
266
|
+
)
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (topoArtifact.sha256 !== currentHash) {
|
|
271
|
+
const committedTopo = await readTopoGraph({
|
|
272
|
+
dir: deriveTrailsDir({ rootDir }),
|
|
273
|
+
});
|
|
274
|
+
if (committedTopo !== null) {
|
|
275
|
+
const committedHash = deriveTopoGraphHash(committedTopo);
|
|
276
|
+
const forceStrippedHash = deriveTopoGraphHash(
|
|
277
|
+
stripTopoGraphForces(committedTopo)
|
|
278
|
+
);
|
|
279
|
+
if (
|
|
280
|
+
committedHash === topoArtifact.sha256 &&
|
|
281
|
+
forceStrippedHash === currentHash
|
|
282
|
+
) {
|
|
283
|
+
return Result.ok({
|
|
284
|
+
committedHash: topoArtifact.sha256,
|
|
285
|
+
currentHash,
|
|
286
|
+
lockPath: LOCK_PATH,
|
|
287
|
+
stale: false,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const breakingSummary =
|
|
292
|
+
committedTopo === null
|
|
293
|
+
? ''
|
|
294
|
+
: (() => {
|
|
295
|
+
const diff = deriveTopoGraphDiff(committedTopo, currentTopo);
|
|
296
|
+
return diff.breaking.length > 0
|
|
297
|
+
? ` Breaking changes detected: ${diff.breaking.length}.`
|
|
298
|
+
: '';
|
|
299
|
+
})();
|
|
300
|
+
return Result.err(
|
|
301
|
+
new ConflictError(
|
|
302
|
+
`trails.lock is stale. Run \`trails compile\` to refresh it.${breakingSummary}`
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return Result.ok({
|
|
308
|
+
committedHash: topoArtifact.sha256,
|
|
309
|
+
currentHash,
|
|
310
|
+
lockPath: LOCK_PATH,
|
|
311
|
+
stale: false,
|
|
312
|
+
});
|
|
313
|
+
};
|