@ontrails/trails 1.0.0-beta.15 → 1.0.0-beta.16
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 +197 -2
- package/README.md +27 -0
- package/package.json +19 -8
- package/src/app.ts +15 -5
- package/src/cli.ts +303 -10
- package/src/completions.ts +240 -0
- package/src/load-app-mirror.ts +160 -0
- package/src/local-state-io.ts +153 -0
- package/src/project-writes.ts +320 -0
- package/src/run-collision.ts +125 -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-trace.ts +273 -0
- package/src/run-warden.ts +39 -0
- package/src/run-watch.ts +432 -0
- package/src/scaffold-versions.generated.ts +12 -0
- package/src/trails/add-surface.ts +45 -23
- package/src/trails/add-trail.ts +27 -17
- package/src/trails/add-verify.ts +57 -17
- package/src/trails/completions-complete.ts +165 -0
- package/src/trails/completions.ts +47 -0
- package/src/trails/create-scaffold.ts +86 -33
- package/src/trails/create.ts +11 -3
- package/src/trails/dev-clean.ts +6 -1
- package/src/trails/dev-reset.ts +6 -1
- package/src/trails/dev-stats.ts +6 -1
- package/src/trails/dev-support.ts +29 -17
- package/src/trails/draft-promote.ts +289 -80
- package/src/trails/guide.ts +54 -34
- package/src/trails/load-app.ts +251 -56
- package/src/trails/root-dir.ts +21 -0
- package/src/trails/run-example.ts +482 -0
- package/src/trails/run-examples.ts +141 -0
- package/src/trails/run.ts +403 -0
- package/src/trails/survey.ts +506 -200
- package/src/trails/topo-activation.ts +385 -0
- package/src/trails/topo-compile.ts +55 -0
- package/src/trails/topo-history.ts +6 -1
- package/src/trails/topo-output-schemas.ts +175 -0
- package/src/trails/topo-pin.ts +19 -6
- package/src/trails/topo-read-support.ts +171 -228
- package/src/trails/topo-reports.ts +400 -25
- package/src/trails/topo-store-support.ts +43 -19
- package/src/trails/topo-support.ts +18 -28
- package/src/trails/topo-unpin.ts +6 -1
- package/src/trails/topo-verify.ts +18 -5
- package/src/trails/topo.ts +60 -23
- package/src/trails/warden-guide.ts +121 -0
- package/src/trails/warden.ts +137 -56
- package/src/versions.ts +3 -18
- 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 -45
- 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 -22
- 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 -84
- 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 -14
- 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 -110
- package/dist/src/trails/add-surface.js.map +0 -1
- package/dist/src/trails/add-trail.d.ts +0 -12
- package/dist/src/trails/add-trail.d.ts.map +0 -1
- package/dist/src/trails/add-trail.js +0 -104
- package/dist/src/trails/add-trail.js.map +0 -1
- package/dist/src/trails/add-trailhead.d.ts +0 -13
- package/dist/src/trails/add-trailhead.d.ts.map +0 -1
- package/dist/src/trails/add-trailhead.js +0 -88
- package/dist/src/trails/add-trailhead.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 -68
- 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 -295
- package/dist/src/trails/create-scaffold.js.map +0 -1
- package/dist/src/trails/create.d.ts +0 -18
- package/dist/src/trails/create.d.ts.map +0 -1
- package/dist/src/trails/create.js +0 -126
- package/dist/src/trails/create.js.map +0 -1
- package/dist/src/trails/dev-clean.d.ts +0 -9
- package/dist/src/trails/dev-clean.d.ts.map +0 -1
- package/dist/src/trails/dev-clean.js +0 -66
- package/dist/src/trails/dev-clean.js.map +0 -1
- package/dist/src/trails/dev-reset.d.ts +0 -6
- package/dist/src/trails/dev-reset.d.ts.map +0 -1
- package/dist/src/trails/dev-reset.js +0 -39
- package/dist/src/trails/dev-reset.js.map +0 -1
- package/dist/src/trails/dev-stats.d.ts +0 -7
- package/dist/src/trails/dev-stats.d.ts.map +0 -1
- package/dist/src/trails/dev-stats.js +0 -61
- package/dist/src/trails/dev-stats.js.map +0 -1
- package/dist/src/trails/dev-support.d.ts +0 -64
- package/dist/src/trails/dev-support.d.ts.map +0 -1
- package/dist/src/trails/dev-support.js +0 -181
- package/dist/src/trails/dev-support.js.map +0 -1
- package/dist/src/trails/draft-promote.d.ts +0 -18
- package/dist/src/trails/draft-promote.d.ts.map +0 -1
- package/dist/src/trails/draft-promote.js +0 -400
- package/dist/src/trails/draft-promote.js.map +0 -1
- package/dist/src/trails/guide.d.ts +0 -21
- package/dist/src/trails/guide.d.ts.map +0 -1
- package/dist/src/trails/guide.js +0 -61
- package/dist/src/trails/guide.js.map +0 -1
- package/dist/src/trails/load-app.d.ts +0 -12
- package/dist/src/trails/load-app.d.ts.map +0 -1
- package/dist/src/trails/load-app.js +0 -415
- 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 -54
- package/dist/src/trails/project.js.map +0 -1
- package/dist/src/trails/survey.d.ts +0 -18
- package/dist/src/trails/survey.d.ts.map +0 -1
- package/dist/src/trails/survey.js +0 -234
- package/dist/src/trails/survey.js.map +0 -1
- package/dist/src/trails/topo-constants.d.ts +0 -3
- package/dist/src/trails/topo-constants.d.ts.map +0 -1
- package/dist/src/trails/topo-constants.js +0 -3
- package/dist/src/trails/topo-constants.js.map +0 -1
- package/dist/src/trails/topo-export.d.ts +0 -19
- package/dist/src/trails/topo-export.d.ts.map +0 -1
- package/dist/src/trails/topo-export.js +0 -31
- package/dist/src/trails/topo-export.js.map +0 -1
- package/dist/src/trails/topo-history.d.ts +0 -20
- package/dist/src/trails/topo-history.d.ts.map +0 -1
- package/dist/src/trails/topo-history.js +0 -32
- package/dist/src/trails/topo-history.js.map +0 -1
- package/dist/src/trails/topo-pin.d.ts +0 -17
- package/dist/src/trails/topo-pin.d.ts.map +0 -1
- package/dist/src/trails/topo-pin.js +0 -31
- package/dist/src/trails/topo-pin.js.map +0 -1
- package/dist/src/trails/topo-read-support.d.ts +0 -58
- package/dist/src/trails/topo-read-support.d.ts.map +0 -1
- package/dist/src/trails/topo-read-support.js +0 -167
- package/dist/src/trails/topo-read-support.js.map +0 -1
- package/dist/src/trails/topo-reports.d.ts +0 -54
- package/dist/src/trails/topo-reports.d.ts.map +0 -1
- package/dist/src/trails/topo-reports.js +0 -128
- package/dist/src/trails/topo-reports.js.map +0 -1
- package/dist/src/trails/topo-show.d.ts +0 -23
- package/dist/src/trails/topo-show.d.ts.map +0 -1
- package/dist/src/trails/topo-show.js +0 -49
- package/dist/src/trails/topo-show.js.map +0 -1
- package/dist/src/trails/topo-store-support.d.ts +0 -13
- package/dist/src/trails/topo-store-support.d.ts.map +0 -1
- package/dist/src/trails/topo-store-support.js +0 -55
- package/dist/src/trails/topo-store-support.js.map +0 -1
- package/dist/src/trails/topo-support.d.ts +0 -76
- package/dist/src/trails/topo-support.d.ts.map +0 -1
- package/dist/src/trails/topo-support.js +0 -132
- package/dist/src/trails/topo-support.js.map +0 -1
- package/dist/src/trails/topo-unpin.d.ts +0 -20
- package/dist/src/trails/topo-unpin.d.ts.map +0 -1
- package/dist/src/trails/topo-unpin.js +0 -44
- package/dist/src/trails/topo-unpin.js.map +0 -1
- package/dist/src/trails/topo-verify.d.ts +0 -5
- package/dist/src/trails/topo-verify.d.ts.map +0 -1
- package/dist/src/trails/topo-verify.js +0 -24
- package/dist/src/trails/topo-verify.js.map +0 -1
- package/dist/src/trails/topo.d.ts +0 -5
- package/dist/src/trails/topo.d.ts.map +0 -1
- package/dist/src/trails/topo.js +0 -63
- package/dist/src/trails/topo.js.map +0 -1
- package/dist/src/trails/warden.d.ts +0 -20
- package/dist/src/trails/warden.d.ts.map +0 -1
- package/dist/src/trails/warden.js +0 -98
- package/dist/src/trails/warden.js.map +0 -1
- package/dist/src/versions.d.ts +0 -12
- package/dist/src/versions.d.ts.map +0 -1
- package/dist/src/versions.js +0 -23
- package/dist/src/versions.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/__tests__/add-trail.test.ts +0 -97
- package/src/__tests__/create.test.ts +0 -415
- package/src/__tests__/draft-promote.test.ts +0 -144
- package/src/__tests__/guide.test.ts +0 -96
- package/src/__tests__/load-app.test.ts +0 -419
- package/src/__tests__/survey.test.ts +0 -377
- package/src/__tests__/topo-dev.test.ts +0 -426
- package/src/__tests__/warden.test.ts +0 -74
- package/src/trails/topo-export.ts +0 -35
- package/src/trails/topo-show.ts +0 -54
- package/tsconfig.json +0 -9
- package/tsconfig.tests.json +0 -10
|
@@ -1,207 +1,91 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Read-only topo
|
|
2
|
+
* Read-only live topo consumer helpers.
|
|
3
3
|
*
|
|
4
|
-
* Extracted from topo-support.ts to isolate read-only
|
|
4
|
+
* Extracted from topo-support.ts to isolate read-only topo consumer helpers,
|
|
5
5
|
* keeping module boundaries clean.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { existsSync } from 'node:fs';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
|
|
11
|
+
import type { Topo, TrailContext } from '@ontrails/core';
|
|
11
12
|
import {
|
|
12
13
|
ConflictError,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
listTopoSnapshots,
|
|
14
|
+
deriveTrailsDbPath,
|
|
15
|
+
deriveTrailsDir,
|
|
16
16
|
NotFoundError,
|
|
17
17
|
Result,
|
|
18
|
+
SURFACE_LAYER_NAMES_KEY,
|
|
19
|
+
ValidationError,
|
|
18
20
|
} from '@ontrails/core';
|
|
19
|
-
import
|
|
21
|
+
import { deriveTopoGraph, readLockManifest } from '@ontrails/topographer';
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
BriefReport,
|
|
25
|
+
SignalDetailReport,
|
|
26
|
+
SurfaceLayerNames,
|
|
27
|
+
SurveyListReport,
|
|
28
|
+
TrailDetailReport,
|
|
29
|
+
} from './topo-reports.js';
|
|
20
30
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
deriveBriefReport,
|
|
32
|
+
deriveResourceDetail,
|
|
33
|
+
deriveSignalDetail,
|
|
34
|
+
deriveSurveyList,
|
|
35
|
+
deriveTrailDetail,
|
|
36
|
+
} from './topo-reports.js';
|
|
37
|
+
import type { ActivationGraphReport } from './topo-activation.js';
|
|
38
|
+
import { deriveActivationGraph } from './topo-activation.js';
|
|
27
39
|
import type { TopoSummaryReport, TopoVerifyReport } from './topo-support.js';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
createCurrentTopoSnapshot,
|
|
31
|
-
deriveRootDir,
|
|
32
|
-
LOCK_PATH,
|
|
33
|
-
} from './topo-support.js';
|
|
40
|
+
import { deriveRootDir, LOCK_PATH } from './topo-support.js';
|
|
41
|
+
import { deriveCurrentTopoExport } from './topo-store-support.js';
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
// Internal types
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
43
|
+
export type CurrentTrailDetail = TrailDetailReport;
|
|
38
44
|
|
|
39
|
-
interface
|
|
40
|
-
readonly detours?: readonly {
|
|
41
|
-
readonly on: string;
|
|
42
|
-
readonly maxAttempts: number;
|
|
43
|
-
}[];
|
|
44
|
-
readonly kind: 'resource' | 'signal' | 'trail';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface CurrentTrailDetail {
|
|
48
|
-
readonly crosses: string[];
|
|
49
|
-
readonly description: string | null;
|
|
50
|
-
readonly detours:
|
|
51
|
-
| readonly { readonly on: string; readonly maxAttempts: number }[]
|
|
52
|
-
| null;
|
|
53
|
-
readonly examples: unknown[];
|
|
54
|
-
readonly id: string;
|
|
55
|
-
readonly intent: 'destroy' | 'read' | 'write';
|
|
56
|
-
readonly kind: string;
|
|
57
|
-
readonly pattern: string | null;
|
|
58
|
-
readonly resources: string[];
|
|
59
|
-
readonly safety: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface CurrentResourceDetail {
|
|
45
|
+
export interface CurrentResourceDetail {
|
|
63
46
|
readonly description: string | null;
|
|
64
47
|
readonly health: 'available' | 'none';
|
|
65
48
|
readonly id: string;
|
|
66
49
|
readonly kind: 'resource';
|
|
67
50
|
readonly lifetime: 'singleton';
|
|
68
|
-
readonly usedBy: string[];
|
|
51
|
+
readonly usedBy: readonly string[];
|
|
69
52
|
}
|
|
70
53
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const topoStoreRef = (snapshotId: string) => ({ snapshotId }) as const;
|
|
76
|
-
|
|
77
|
-
const hasCommittedLock = (trailsDir: string): boolean =>
|
|
78
|
-
existsSync(join(trailsDir, 'trails.lock'));
|
|
79
|
-
|
|
80
|
-
const readSurfaceEntries = (
|
|
81
|
-
surfaceMapJson: string
|
|
82
|
-
): readonly StoredSurfaceMapEntry[] =>
|
|
83
|
-
(
|
|
84
|
-
JSON.parse(surfaceMapJson) as {
|
|
85
|
-
readonly entries: readonly StoredSurfaceMapEntry[];
|
|
86
|
-
}
|
|
87
|
-
).entries;
|
|
54
|
+
export type CurrentTopoDetail =
|
|
55
|
+
| CurrentResourceDetail
|
|
56
|
+
| CurrentTrailDetail
|
|
57
|
+
| SignalDetailReport;
|
|
88
58
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
snapshot: TopoSnapshot
|
|
94
|
-
): BriefReport => {
|
|
95
|
-
const trails = store.trails.list({ snapshot: ref });
|
|
96
|
-
const exportRecord = store.exports.get(ref);
|
|
97
|
-
const trailEntries =
|
|
98
|
-
exportRecord === undefined
|
|
99
|
-
? []
|
|
100
|
-
: readSurfaceEntries(exportRecord.surfaceMapJson).filter(
|
|
101
|
-
(entry) => entry.kind === 'trail'
|
|
102
|
-
);
|
|
59
|
+
export interface CurrentTopoMatch {
|
|
60
|
+
readonly kind: CurrentTopoDetail['kind'];
|
|
61
|
+
readonly detail: CurrentTopoDetail;
|
|
62
|
+
}
|
|
103
63
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
examples: trails.some((trail) => trail.hasExamples),
|
|
109
|
-
outputSchemas: trails.some((trail) => trail.hasOutput),
|
|
110
|
-
resources: snapshot.resourceCount > 0,
|
|
111
|
-
signals: snapshot.signalCount > 0,
|
|
112
|
-
},
|
|
113
|
-
name: app.name,
|
|
114
|
-
resources: snapshot.resourceCount,
|
|
115
|
-
signals: snapshot.signalCount,
|
|
116
|
-
trails: snapshot.trailCount,
|
|
117
|
-
version: REPORT_VERSION,
|
|
118
|
-
};
|
|
119
|
-
};
|
|
64
|
+
export interface CurrentTopoReadOptions {
|
|
65
|
+
readonly rootDir?: string | undefined;
|
|
66
|
+
readonly surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined;
|
|
67
|
+
}
|
|
120
68
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
ref: ReturnType<typeof topoStoreRef>
|
|
124
|
-
): SurveyListReport => {
|
|
125
|
-
const trails = store.trails.list({ snapshot: ref });
|
|
126
|
-
const resources = store.resources.list({ snapshot: ref });
|
|
69
|
+
const isStringArray = (value: unknown): value is readonly string[] =>
|
|
70
|
+
Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
127
71
|
|
|
72
|
+
export const readSurfaceLayerNamesFromContext = (
|
|
73
|
+
ctx: TrailContext
|
|
74
|
+
): Partial<SurfaceLayerNames> => {
|
|
75
|
+
const value = ctx.extensions?.[SURFACE_LAYER_NAMES_KEY];
|
|
76
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
const raw = value as Record<string, unknown>;
|
|
128
80
|
return {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
id: trail.id,
|
|
133
|
-
kind: trail.kind,
|
|
134
|
-
safety: trail.safety,
|
|
135
|
-
})),
|
|
136
|
-
resourceCount: resources.length,
|
|
137
|
-
resources: resources.map((resource) => ({
|
|
138
|
-
description: resource.description,
|
|
139
|
-
health: resource.health,
|
|
140
|
-
id: resource.id,
|
|
141
|
-
kind: resource.kind,
|
|
142
|
-
lifetime: resource.lifetime,
|
|
143
|
-
usedBy: resource.usedBy,
|
|
144
|
-
})),
|
|
81
|
+
...(isStringArray(raw['cli']) ? { cli: raw['cli'] } : {}),
|
|
82
|
+
...(isStringArray(raw['http']) ? { http: raw['http'] } : {}),
|
|
83
|
+
...(isStringArray(raw['mcp']) ? { mcp: raw['mcp'] } : {}),
|
|
145
84
|
};
|
|
146
85
|
};
|
|
147
86
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
ReturnType<ReturnType<typeof createTopoStore>['trails']['get']>
|
|
151
|
-
>
|
|
152
|
-
): CurrentTrailDetail => ({
|
|
153
|
-
crosses: [...detail.crosses],
|
|
154
|
-
description: detail.description,
|
|
155
|
-
detours: detail.detours,
|
|
156
|
-
examples: [...detail.examples],
|
|
157
|
-
id: detail.id,
|
|
158
|
-
intent: detail.intent,
|
|
159
|
-
kind: detail.kind,
|
|
160
|
-
pattern: detail.pattern,
|
|
161
|
-
resources: [...detail.resources],
|
|
162
|
-
safety: detail.safety,
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const buildResourceDetailFromStore = (
|
|
166
|
-
resource: NonNullable<
|
|
167
|
-
ReturnType<ReturnType<typeof createTopoStore>['resources']['get']>
|
|
168
|
-
>
|
|
169
|
-
): CurrentResourceDetail => ({
|
|
170
|
-
description: resource.description,
|
|
171
|
-
health: resource.health,
|
|
172
|
-
id: resource.id,
|
|
173
|
-
kind: resource.kind,
|
|
174
|
-
lifetime: resource.lifetime,
|
|
175
|
-
usedBy: [...resource.usedBy],
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// ---------------------------------------------------------------------------
|
|
179
|
-
// withCurrentTopoStore
|
|
180
|
-
// ---------------------------------------------------------------------------
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Run a read callback against the latest topo store state.
|
|
184
|
-
*
|
|
185
|
-
* Uses the most recent existing snapshot when available, only creating a new
|
|
186
|
-
* snapshot when no prior snapshot exists. This avoids unbounded snapshot
|
|
187
|
-
* accumulation from
|
|
188
|
-
* read-only operations like survey, guide, and show.
|
|
189
|
-
*/
|
|
190
|
-
const withCurrentTopoStore = <T>(
|
|
191
|
-
app: Topo,
|
|
192
|
-
rootDir: string,
|
|
193
|
-
read: (
|
|
194
|
-
store: ReturnType<typeof createTopoStore>,
|
|
195
|
-
ref: ReturnType<typeof topoStoreRef>,
|
|
196
|
-
snapshot: TopoSnapshot
|
|
197
|
-
) => T
|
|
198
|
-
): T => {
|
|
199
|
-
const [existingSnapshot] = listTopoSnapshots({ limit: 1, rootDir });
|
|
200
|
-
const snapshot =
|
|
201
|
-
existingSnapshot ?? createCurrentTopoSnapshot(app, { rootDir });
|
|
202
|
-
const store = createTopoStore({ rootDir });
|
|
203
|
-
return read(store, topoStoreRef(snapshot.id), snapshot);
|
|
204
|
-
};
|
|
87
|
+
const hasCommittedLock = (trailsDir: string): boolean =>
|
|
88
|
+
existsSync(join(trailsDir, 'trails.lock'));
|
|
205
89
|
|
|
206
90
|
// ---------------------------------------------------------------------------
|
|
207
91
|
// Public read-only consumers
|
|
@@ -213,72 +97,116 @@ export const buildTopoSummary = (
|
|
|
213
97
|
): TopoSummaryReport => {
|
|
214
98
|
const rootDir = deriveRootDir(options?.rootDir);
|
|
215
99
|
const trailsDir = deriveTrailsDir({ rootDir });
|
|
216
|
-
return
|
|
217
|
-
app:
|
|
100
|
+
return {
|
|
101
|
+
app: deriveBriefReport(app),
|
|
218
102
|
dbPath: deriveTrailsDbPath({ rootDir }),
|
|
219
|
-
list:
|
|
103
|
+
list: deriveSurveyList(app),
|
|
220
104
|
lockExists: hasCommittedLock(trailsDir),
|
|
221
105
|
lockPath: LOCK_PATH,
|
|
222
|
-
}
|
|
106
|
+
};
|
|
223
107
|
};
|
|
224
108
|
|
|
225
109
|
export const buildCurrentTopoBrief = (
|
|
226
110
|
app: Topo,
|
|
227
|
-
|
|
228
|
-
): BriefReport =>
|
|
229
|
-
const rootDir = deriveRootDir(options?.rootDir);
|
|
230
|
-
return withCurrentTopoStore(app, rootDir, (store, ref, snapshot) =>
|
|
231
|
-
buildBriefReportFromStore(app, store, ref, snapshot)
|
|
232
|
-
);
|
|
233
|
-
};
|
|
111
|
+
_options?: { readonly rootDir?: string }
|
|
112
|
+
): BriefReport => deriveBriefReport(app);
|
|
234
113
|
|
|
235
114
|
export const buildCurrentTopoList = (
|
|
236
115
|
app: Topo,
|
|
237
|
-
|
|
238
|
-
): SurveyListReport =>
|
|
239
|
-
const rootDir = deriveRootDir(options?.rootDir);
|
|
240
|
-
return withCurrentTopoStore(app, rootDir, (store, ref) =>
|
|
241
|
-
buildSurveyListFromStore(store, ref)
|
|
242
|
-
);
|
|
243
|
-
};
|
|
116
|
+
_options?: { readonly rootDir?: string }
|
|
117
|
+
): SurveyListReport => deriveSurveyList(app);
|
|
244
118
|
|
|
245
119
|
export const buildCurrentGuideEntries = (
|
|
246
120
|
app: Topo,
|
|
247
|
-
|
|
121
|
+
_options?: { readonly rootDir?: string }
|
|
248
122
|
): readonly {
|
|
249
123
|
readonly description: string;
|
|
250
124
|
readonly exampleCount: number;
|
|
251
125
|
readonly id: string;
|
|
252
|
-
readonly kind:
|
|
253
|
-
}[] =>
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
126
|
+
readonly kind: 'trail';
|
|
127
|
+
}[] =>
|
|
128
|
+
app
|
|
129
|
+
.list()
|
|
130
|
+
.map((trail) => ({
|
|
257
131
|
description: trail.description ?? '(no description)',
|
|
258
|
-
exampleCount: trail.
|
|
132
|
+
exampleCount: trail.examples?.length ?? 0,
|
|
259
133
|
id: trail.id,
|
|
260
|
-
kind: trail
|
|
134
|
+
kind: 'trail' as const,
|
|
261
135
|
}))
|
|
262
|
-
|
|
136
|
+
.toSorted((a, b) => a.id.localeCompare(b.id));
|
|
137
|
+
|
|
138
|
+
export const buildCurrentTrailDetail = (
|
|
139
|
+
app: Topo,
|
|
140
|
+
id: string,
|
|
141
|
+
options?: CurrentTopoReadOptions
|
|
142
|
+
): CurrentTrailDetail | undefined => {
|
|
143
|
+
const trail = app.get(id);
|
|
144
|
+
return trail === undefined
|
|
145
|
+
? undefined
|
|
146
|
+
: deriveTrailDetail(trail, app, undefined, {
|
|
147
|
+
surfaceLayerNames: options?.surfaceLayerNames,
|
|
148
|
+
});
|
|
263
149
|
};
|
|
264
150
|
|
|
151
|
+
export const buildCurrentResourceDetail = (
|
|
152
|
+
app: Topo,
|
|
153
|
+
id: string,
|
|
154
|
+
_options?: { readonly rootDir?: string }
|
|
155
|
+
): CurrentResourceDetail | undefined =>
|
|
156
|
+
app.getResource(id) === undefined
|
|
157
|
+
? undefined
|
|
158
|
+
: (deriveResourceDetail(app, id) as CurrentResourceDetail);
|
|
159
|
+
|
|
160
|
+
export const buildCurrentSignalDetail = (
|
|
161
|
+
app: Topo,
|
|
162
|
+
id: string,
|
|
163
|
+
_options?: { readonly rootDir?: string }
|
|
164
|
+
): SignalDetailReport | undefined => deriveSignalDetail(app, id);
|
|
165
|
+
|
|
265
166
|
export const buildCurrentTopoDetail = (
|
|
266
167
|
app: Topo,
|
|
267
168
|
id: string,
|
|
268
|
-
options?:
|
|
269
|
-
):
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (trail !== undefined) {
|
|
274
|
-
return buildTrailDetailFromStore(trail);
|
|
275
|
-
}
|
|
169
|
+
options?: CurrentTopoReadOptions
|
|
170
|
+
): CurrentTopoDetail | undefined =>
|
|
171
|
+
buildCurrentTrailDetail(app, id, options) ??
|
|
172
|
+
buildCurrentResourceDetail(app, id) ??
|
|
173
|
+
buildCurrentSignalDetail(app, id);
|
|
276
174
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
175
|
+
export const buildCurrentTopoMatches = (
|
|
176
|
+
app: Topo,
|
|
177
|
+
id: string,
|
|
178
|
+
options?: CurrentTopoReadOptions
|
|
179
|
+
): readonly CurrentTopoMatch[] => {
|
|
180
|
+
const matches: CurrentTopoMatch[] = [];
|
|
181
|
+
let activationGraph: ActivationGraphReport | undefined;
|
|
182
|
+
const getActivationGraph = (): ActivationGraphReport =>
|
|
183
|
+
(activationGraph ??= deriveActivationGraph(app));
|
|
184
|
+
let topoGraph: ReturnType<typeof deriveTopoGraph> | undefined;
|
|
185
|
+
const getTopoGraph = (): ReturnType<typeof deriveTopoGraph> =>
|
|
186
|
+
(topoGraph ??= deriveTopoGraph(app));
|
|
187
|
+
|
|
188
|
+
const trail = app.get(id);
|
|
189
|
+
if (trail !== undefined) {
|
|
190
|
+
matches.push({
|
|
191
|
+
detail: deriveTrailDetail(trail, app, getActivationGraph(), {
|
|
192
|
+
surfaceLayerNames: options?.surfaceLayerNames,
|
|
193
|
+
topoGraph: getTopoGraph(),
|
|
194
|
+
}),
|
|
195
|
+
kind: 'trail',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const resource = buildCurrentResourceDetail(app, id);
|
|
200
|
+
if (resource !== undefined) {
|
|
201
|
+
matches.push({ detail: resource, kind: 'resource' });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const signal = deriveSignalDetail(app, id, activationGraph);
|
|
205
|
+
if (signal !== undefined) {
|
|
206
|
+
matches.push({ detail: signal, kind: 'signal' });
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return matches;
|
|
282
210
|
};
|
|
283
211
|
|
|
284
212
|
export const verifyCurrentTopo = async (
|
|
@@ -286,42 +214,57 @@ export const verifyCurrentTopo = async (
|
|
|
286
214
|
options?: { readonly rootDir?: string }
|
|
287
215
|
): Promise<Result<TopoVerifyReport, Error>> => {
|
|
288
216
|
const rootDir = deriveRootDir(options?.rootDir);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
217
|
+
let lockManifest: Awaited<ReturnType<typeof readLockManifest>>;
|
|
218
|
+
try {
|
|
219
|
+
lockManifest = await readLockManifest({
|
|
220
|
+
dir: deriveTrailsDir({ rootDir }),
|
|
221
|
+
});
|
|
222
|
+
} catch (error) {
|
|
223
|
+
const message =
|
|
224
|
+
error instanceof Error
|
|
225
|
+
? error.message
|
|
226
|
+
: 'Unable to read committed trails.lock manifest.';
|
|
227
|
+
return Result.err(
|
|
228
|
+
error instanceof Error
|
|
229
|
+
? new ValidationError(message, { cause: error })
|
|
230
|
+
: new ValidationError(message)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
292
233
|
|
|
293
|
-
if (
|
|
234
|
+
if (lockManifest === null) {
|
|
294
235
|
return Result.err(
|
|
295
236
|
new NotFoundError(
|
|
296
|
-
'No committed trails.lock found. Run `trails topo
|
|
237
|
+
'No committed trails.lock found. Run `trails topo compile` first.'
|
|
297
238
|
)
|
|
298
239
|
);
|
|
299
240
|
}
|
|
300
241
|
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
242
|
+
const currentExport = deriveCurrentTopoExport(app, { rootDir });
|
|
243
|
+
if (currentExport.isErr()) {
|
|
244
|
+
return currentExport;
|
|
245
|
+
}
|
|
246
|
+
const currentHash = currentExport.value.topoGraphHash;
|
|
247
|
+
const topoArtifact = lockManifest.artifacts.find(
|
|
248
|
+
(artifact) => artifact.role === 'topo' && artifact.path === 'topo.lock'
|
|
305
249
|
);
|
|
306
|
-
|
|
307
|
-
if (currentHash === undefined) {
|
|
250
|
+
if (topoArtifact === undefined) {
|
|
308
251
|
return Result.err(
|
|
309
|
-
new
|
|
310
|
-
'No
|
|
252
|
+
new NotFoundError(
|
|
253
|
+
'No topo.lock artifact found in trails.lock. Run `trails topo compile` first.'
|
|
311
254
|
)
|
|
312
255
|
);
|
|
313
256
|
}
|
|
314
257
|
|
|
315
|
-
if (
|
|
258
|
+
if (topoArtifact.sha256 !== currentHash) {
|
|
316
259
|
return Result.err(
|
|
317
260
|
new ConflictError(
|
|
318
|
-
'trails.lock is stale. Run `trails topo
|
|
261
|
+
'trails.lock is stale. Run `trails topo compile` to refresh it.'
|
|
319
262
|
)
|
|
320
263
|
);
|
|
321
264
|
}
|
|
322
265
|
|
|
323
266
|
return Result.ok({
|
|
324
|
-
committedHash:
|
|
267
|
+
committedHash: topoArtifact.sha256,
|
|
325
268
|
currentHash,
|
|
326
269
|
lockPath: LOCK_PATH,
|
|
327
270
|
stale: false,
|