@ontrails/trails 1.0.0-beta.14 → 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 +208 -0
- package/README.md +27 -0
- package/package.json +19 -8
- package/src/app.ts +17 -7
- package/src/clack.ts +1 -1
- package/src/cli.ts +304 -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 +172 -0
- package/src/trails/add-trail.ts +73 -27
- package/src/trails/add-verify.ts +68 -23
- package/src/trails/completions-complete.ts +165 -0
- package/src/trails/completions.ts +47 -0
- package/src/trails/create-scaffold.ts +101 -35
- package/src/trails/create.ts +87 -74
- package/src/trails/dev-clean.ts +31 -22
- package/src/trails/dev-reset.ts +9 -3
- package/src/trails/dev-stats.ts +28 -20
- package/src/trails/dev-support.ts +109 -95
- package/src/trails/draft-promote.ts +351 -107
- package/src/trails/guide.ts +55 -38
- package/src/trails/load-app.ts +712 -38
- 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 +517 -186
- package/src/trails/topo-activation.ts +385 -0
- package/src/trails/topo-compile.ts +55 -0
- package/src/trails/topo-history.ts +14 -11
- package/src/trails/topo-output-schemas.ts +175 -0
- package/src/trails/topo-pin.ts +25 -16
- package/src/trails/topo-read-support.ts +178 -238
- package/src/trails/topo-reports.ts +445 -63
- package/src/trails/topo-store-support.ts +67 -35
- package/src/trails/topo-support.ts +93 -147
- package/src/trails/topo-unpin.ts +17 -7
- package/src/trails/topo-verify.ts +19 -10
- package/src/trails/topo.ts +64 -31
- package/src/trails/warden-guide.ts +121 -0
- package/src/trails/warden.ts +137 -47
- package/src/versions.ts +28 -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 -20
- 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 -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 -10
- package/dist/src/trails/add-trail.d.ts.map +0 -1
- package/dist/src/trails/add-trail.js +0 -77
- 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 -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/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 -65
- 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 -38
- 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 -178
- 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 -386
- 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 -64
- package/dist/src/trails/guide.js.map +0 -1
- package/dist/src/trails/load-app.d.ts +0 -6
- package/dist/src/trails/load-app.d.ts.map +0 -1
- package/dist/src/trails/load-app.js +0 -67
- 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 -212
- 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 -18
- package/dist/src/trails/topo-export.d.ts.map +0 -1
- package/dist/src/trails/topo-export.js +0 -34
- package/dist/src/trails/topo-export.js.map +0 -1
- package/dist/src/trails/topo-history.d.ts +0 -24
- package/dist/src/trails/topo-history.d.ts.map +0 -1
- package/dist/src/trails/topo-history.js +0 -33
- package/dist/src/trails/topo-history.js.map +0 -1
- package/dist/src/trails/topo-pin.d.ts +0 -21
- package/dist/src/trails/topo-pin.d.ts.map +0 -1
- package/dist/src/trails/topo-pin.js +0 -35
- package/dist/src/trails/topo-pin.js.map +0 -1
- package/dist/src/trails/topo-read-support.d.ts +0 -54
- package/dist/src/trails/topo-read-support.d.ts.map +0 -1
- package/dist/src/trails/topo-read-support.js +0 -178
- package/dist/src/trails/topo-read-support.js.map +0 -1
- package/dist/src/trails/topo-reports.d.ts +0 -50
- package/dist/src/trails/topo-reports.d.ts.map +0 -1
- package/dist/src/trails/topo-reports.js +0 -122
- 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 -53
- 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 -87
- package/dist/src/trails/topo-support.d.ts.map +0 -1
- package/dist/src/trails/topo-support.js +0 -165
- package/dist/src/trails/topo-support.js.map +0 -1
- package/dist/src/trails/topo-unpin.d.ts +0 -15
- package/dist/src/trails/topo-unpin.d.ts.map +0 -1
- package/dist/src/trails/topo-unpin.js +0 -39
- 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 -28
- 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 -67
- package/dist/src/trails/topo.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 -89
- package/dist/src/trails/warden.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/__tests__/create.test.ts +0 -351
- package/src/__tests__/draft-promote.test.ts +0 -144
- package/src/__tests__/guide.test.ts +0 -91
- package/src/__tests__/load-app.test.ts +0 -58
- package/src/__tests__/survey.test.ts +0 -301
- package/src/__tests__/topo-dev.test.ts +0 -424
- package/src/__tests__/warden.test.ts +0 -74
- package/src/trails/add-trailhead.ts +0 -121
- package/src/trails/topo-export.ts +0 -39
- package/src/trails/topo-show.ts +0 -58
- package/tsconfig.json +0 -9
package/src/trails/survey.ts
CHANGED
|
@@ -1,296 +1,627 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `survey` trail -- Full topo introspection.
|
|
3
3
|
*
|
|
4
|
-
* Lists trails,
|
|
5
|
-
*
|
|
4
|
+
* Lists trails, looks up trails/resources/signals, and diffs against previous
|
|
5
|
+
* versions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { basename, extname, join } from 'node:path';
|
|
9
|
+
|
|
8
10
|
import type { Topo } from '@ontrails/core';
|
|
9
|
-
import { NotFoundError, Result, trail } from '@ontrails/core';
|
|
10
|
-
import type { DiffResult } from '@ontrails/schema';
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
deriveSafePath,
|
|
13
|
+
NotFoundError,
|
|
14
|
+
Result,
|
|
15
|
+
trail,
|
|
16
|
+
ValidationError,
|
|
17
|
+
} from '@ontrails/core';
|
|
18
|
+
import type { DiffEntry, DiffResult, TopoGraph } from '@ontrails/topographer';
|
|
19
|
+
import {
|
|
20
|
+
createTopoStore,
|
|
21
|
+
deriveTopoGraphDiff,
|
|
22
|
+
deriveTopoGraph,
|
|
23
|
+
TOPO_GRAPH_SCHEMA_VERSION,
|
|
24
|
+
readTopoGraph,
|
|
25
|
+
} from '@ontrails/topographer';
|
|
17
26
|
import { z } from 'zod';
|
|
18
27
|
|
|
19
|
-
import {
|
|
28
|
+
import { writeIsolatedExampleJsonFile } from '../local-state-io.js';
|
|
29
|
+
|
|
30
|
+
import { tryLoadFreshAppLease } from './load-app.js';
|
|
31
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
20
32
|
import {
|
|
21
33
|
buildCurrentTopoBrief,
|
|
22
|
-
buildCurrentTopoDetail,
|
|
23
34
|
buildCurrentTopoList,
|
|
35
|
+
buildCurrentTopoMatches,
|
|
36
|
+
buildCurrentTrailDetail,
|
|
37
|
+
buildCurrentResourceDetail,
|
|
38
|
+
buildCurrentSignalDetail,
|
|
39
|
+
readSurfaceLayerNamesFromContext,
|
|
24
40
|
} from './topo-read-support.js';
|
|
25
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
activationOverviewOutput,
|
|
43
|
+
resourceDetailOutput,
|
|
44
|
+
signalDetailOutput,
|
|
45
|
+
trailDetailOutput,
|
|
46
|
+
} from './topo-output-schemas.js';
|
|
47
|
+
import { createIsolatedExampleInput } from './topo-support.js';
|
|
48
|
+
import { briefReportSchema } from './topo-reports.js';
|
|
49
|
+
import type { SurfaceLayerNames } from './topo-reports.js';
|
|
26
50
|
|
|
27
51
|
export {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
briefReportSchema,
|
|
53
|
+
deriveBriefReport,
|
|
54
|
+
deriveResourceDetail,
|
|
55
|
+
deriveSignalDetail,
|
|
56
|
+
deriveSurveyList,
|
|
57
|
+
deriveTrailDetail,
|
|
32
58
|
} from './topo-reports.js';
|
|
33
59
|
export type {
|
|
34
60
|
BriefReport,
|
|
61
|
+
SignalDetailReport,
|
|
62
|
+
SurfaceLayerNames,
|
|
35
63
|
SurveyListReport,
|
|
36
64
|
TrailDetailReport,
|
|
37
65
|
} from './topo-reports.js';
|
|
38
66
|
|
|
39
67
|
// ---------------------------------------------------------------------------
|
|
40
|
-
//
|
|
68
|
+
// Survey diff helpers
|
|
41
69
|
// ---------------------------------------------------------------------------
|
|
42
70
|
|
|
43
|
-
|
|
71
|
+
interface SurveyDiffReport {
|
|
72
|
+
readonly against: string;
|
|
73
|
+
readonly breaking: readonly DiffEntry[];
|
|
74
|
+
readonly hasBreaking: boolean;
|
|
75
|
+
readonly info: readonly DiffEntry[];
|
|
76
|
+
readonly mode: 'diff';
|
|
77
|
+
readonly warnings: readonly DiffEntry[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const formatDiff = (diff: DiffResult, against: string): SurveyDiffReport => ({
|
|
81
|
+
against,
|
|
44
82
|
breaking: diff.breaking,
|
|
45
83
|
hasBreaking: diff.hasBreaking,
|
|
46
84
|
info: diff.info,
|
|
85
|
+
mode: 'diff',
|
|
47
86
|
warnings: diff.warnings,
|
|
48
87
|
});
|
|
49
88
|
|
|
89
|
+
const createDiffExampleInput = (): {
|
|
90
|
+
readonly against: string;
|
|
91
|
+
readonly module: string;
|
|
92
|
+
readonly rootDir: string;
|
|
93
|
+
} => {
|
|
94
|
+
const input = createIsolatedExampleInput('survey-diff');
|
|
95
|
+
writeIsolatedExampleJsonFile(input.rootDir, 'baseline/topo.lock', {
|
|
96
|
+
activationGraph: {
|
|
97
|
+
edgeCount: 0,
|
|
98
|
+
edges: [],
|
|
99
|
+
sourceCount: 0,
|
|
100
|
+
sourceKeys: [],
|
|
101
|
+
trailIds: [],
|
|
102
|
+
},
|
|
103
|
+
activationSources: {},
|
|
104
|
+
entries: [],
|
|
105
|
+
generatedAt: '2026-01-01T00:00:00.000Z',
|
|
106
|
+
topoGraphSchemaVersion: TOPO_GRAPH_SCHEMA_VERSION,
|
|
107
|
+
} satisfies TopoGraph);
|
|
108
|
+
return { ...input, against: 'baseline' };
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const isNotFound = (error: unknown): boolean =>
|
|
112
|
+
typeof error === 'object' &&
|
|
113
|
+
error !== null &&
|
|
114
|
+
(error as NodeJS.ErrnoException).code === 'ENOENT';
|
|
115
|
+
|
|
116
|
+
const readTopoGraphFile = async (
|
|
117
|
+
filePath: string
|
|
118
|
+
): Promise<TopoGraph | null> => {
|
|
119
|
+
try {
|
|
120
|
+
return (await Bun.file(filePath).json()) as TopoGraph;
|
|
121
|
+
} catch (error: unknown) {
|
|
122
|
+
if (isNotFound(error)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const readStoredTopoGraph = (
|
|
130
|
+
rootDir: string,
|
|
131
|
+
against: string
|
|
132
|
+
): TopoGraph | undefined => {
|
|
133
|
+
try {
|
|
134
|
+
const store = createTopoStore({ rootDir });
|
|
135
|
+
const stored =
|
|
136
|
+
store.exports.get({ pin: against }) ??
|
|
137
|
+
store.exports.get({ snapshotId: against });
|
|
138
|
+
return stored === undefined
|
|
139
|
+
? undefined
|
|
140
|
+
: (JSON.parse(stored.topoGraphJson) as TopoGraph);
|
|
141
|
+
} catch (error: unknown) {
|
|
142
|
+
if (error instanceof NotFoundError) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const readPathTopoGraph = async (
|
|
150
|
+
rootDir: string,
|
|
151
|
+
against: string
|
|
152
|
+
): Promise<Result<TopoGraph | null, Error>> => {
|
|
153
|
+
const safePath = deriveSafePath(rootDir, against);
|
|
154
|
+
if (safePath.isErr()) {
|
|
155
|
+
return safePath;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return Result.ok(
|
|
159
|
+
basename(safePath.value) === 'topo.lock' ||
|
|
160
|
+
extname(safePath.value) === '.json'
|
|
161
|
+
? await readTopoGraphFile(safePath.value)
|
|
162
|
+
: await readTopoGraph({ dir: safePath.value })
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const describeAgainstPathTarget = (against: string): string =>
|
|
167
|
+
basename(against) === 'topo.lock' || extname(against) === '.json'
|
|
168
|
+
? 'workspace-relative TopoGraph file'
|
|
169
|
+
: 'workspace-relative directory containing topo.lock';
|
|
170
|
+
|
|
171
|
+
const topoGraphNotFound = (against: string): NotFoundError =>
|
|
172
|
+
new NotFoundError(
|
|
173
|
+
`No TopoGraph found for: ${against}. Tried ${describeAgainstPathTarget(
|
|
174
|
+
against
|
|
175
|
+
)}, then topo-store pin and snapshot references.`
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const readAgainstTopoGraph = async (
|
|
179
|
+
rootDir: string,
|
|
180
|
+
against?: string | undefined
|
|
181
|
+
): Promise<Result<{ against: string; map: TopoGraph }, Error>> => {
|
|
182
|
+
if (against === undefined || against === 'saved') {
|
|
183
|
+
const map = await readTopoGraph({ dir: join(rootDir, '.trails') });
|
|
184
|
+
return map === null
|
|
185
|
+
? Result.err(
|
|
186
|
+
new NotFoundError(
|
|
187
|
+
'No saved TopoGraph found. Run `trails topo compile` first.'
|
|
188
|
+
)
|
|
189
|
+
)
|
|
190
|
+
: Result.ok({ against: 'saved', map });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Treat explicit filesystem targets as the most local user intent; stored
|
|
194
|
+
// pins and snapshot ids are fallback references when no path exists.
|
|
195
|
+
const pathMap = await readPathTopoGraph(rootDir, against);
|
|
196
|
+
if (pathMap.isErr()) {
|
|
197
|
+
return pathMap;
|
|
198
|
+
}
|
|
199
|
+
if (pathMap.value !== null) {
|
|
200
|
+
return Result.ok({ against, map: pathMap.value });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const storedMap = readStoredTopoGraph(rootDir, against);
|
|
204
|
+
if (storedMap !== undefined) {
|
|
205
|
+
return Result.ok({ against, map: storedMap });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return Result.err(topoGraphNotFound(against));
|
|
209
|
+
};
|
|
210
|
+
|
|
50
211
|
const buildSurveyDiff = async (
|
|
51
212
|
app: Topo,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
);
|
|
213
|
+
rootDir: string,
|
|
214
|
+
breakingOnly: boolean,
|
|
215
|
+
against?: string | undefined
|
|
216
|
+
): Promise<Result<SurveyDiffReport, Error>> => {
|
|
217
|
+
const currentMap = deriveTopoGraph(app);
|
|
218
|
+
const previous = await readAgainstTopoGraph(rootDir, against);
|
|
219
|
+
if (previous.isErr()) {
|
|
220
|
+
return previous;
|
|
62
221
|
}
|
|
63
222
|
|
|
64
|
-
const diff =
|
|
223
|
+
const diff = deriveTopoGraphDiff(previous.value.map, currentMap);
|
|
65
224
|
return Result.ok(
|
|
66
225
|
breakingOnly
|
|
67
|
-
? formatDiff({
|
|
68
|
-
|
|
69
|
-
entries: diff.breaking,
|
|
70
|
-
info: [],
|
|
71
|
-
warnings: [],
|
|
72
|
-
})
|
|
73
|
-
: formatDiff(diff)
|
|
226
|
+
? formatDiff({ ...diff, info: [], warnings: [] }, previous.value.against)
|
|
227
|
+
: formatDiff(diff, previous.value.against)
|
|
74
228
|
);
|
|
75
229
|
};
|
|
76
230
|
|
|
77
|
-
const
|
|
231
|
+
const buildSurveyLookup = (
|
|
232
|
+
app: Topo,
|
|
233
|
+
entityId: string,
|
|
234
|
+
rootDir: string,
|
|
235
|
+
surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
|
|
236
|
+
): Result<object, Error> => {
|
|
237
|
+
const matches = buildCurrentTopoMatches(app, entityId, {
|
|
238
|
+
rootDir,
|
|
239
|
+
surfaceLayerNames,
|
|
240
|
+
});
|
|
241
|
+
return Result.ok({ matches });
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const buildSurveyTrailDetail = (
|
|
245
|
+
app: Topo,
|
|
246
|
+
id: string,
|
|
247
|
+
rootDir: string,
|
|
248
|
+
surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
|
|
249
|
+
): Result<object, Error> => {
|
|
250
|
+
const detail = buildCurrentTrailDetail(app, id, {
|
|
251
|
+
rootDir,
|
|
252
|
+
surfaceLayerNames,
|
|
253
|
+
});
|
|
254
|
+
return detail === undefined
|
|
255
|
+
? Result.err(new NotFoundError(`Trail not found: ${id}`))
|
|
256
|
+
: Result.ok(detail);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const buildSurveyResourceDetail = (
|
|
78
260
|
app: Topo,
|
|
79
|
-
|
|
261
|
+
id: string,
|
|
80
262
|
rootDir: string
|
|
81
263
|
): Result<object, Error> => {
|
|
82
|
-
const detail =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return Result.err(
|
|
87
|
-
new NotFoundError(`Trail or provision not found: ${trailId}`)
|
|
88
|
-
);
|
|
264
|
+
const detail = buildCurrentResourceDetail(app, id, { rootDir });
|
|
265
|
+
return detail === undefined
|
|
266
|
+
? Result.err(new NotFoundError(`Resource not found: ${id}`))
|
|
267
|
+
: Result.ok(detail);
|
|
89
268
|
};
|
|
90
269
|
|
|
91
|
-
const
|
|
270
|
+
const buildSurveySignalDetail = (
|
|
92
271
|
app: Topo,
|
|
272
|
+
id: string,
|
|
93
273
|
rootDir: string
|
|
94
|
-
):
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return Result.ok({
|
|
100
|
-
hash: exported.value.hash,
|
|
101
|
-
lockPath: exported.value.lockPath,
|
|
102
|
-
mapPath: exported.value.mapPath,
|
|
103
|
-
});
|
|
274
|
+
): Result<object, Error> => {
|
|
275
|
+
const detail = buildCurrentSignalDetail(app, id, { rootDir });
|
|
276
|
+
return detail === undefined
|
|
277
|
+
? Result.err(new NotFoundError(`Signal not found: ${id}`))
|
|
278
|
+
: Result.ok(detail);
|
|
104
279
|
};
|
|
105
280
|
|
|
106
281
|
interface SurveyInput {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
generate: boolean;
|
|
111
|
-
openapi: boolean;
|
|
112
|
-
trailId?: string | undefined;
|
|
282
|
+
id?: string | undefined;
|
|
283
|
+
module?: string | undefined;
|
|
284
|
+
rootDir?: string | undefined;
|
|
113
285
|
}
|
|
114
286
|
|
|
115
|
-
type SurveyMode = '
|
|
287
|
+
type SurveyMode = 'lookup' | 'overview';
|
|
116
288
|
|
|
117
|
-
|
|
118
|
-
const modeChecks: readonly [(input: SurveyInput) => boolean, SurveyMode][] = [
|
|
119
|
-
[(i) => i.brief, 'brief'],
|
|
120
|
-
[(i) => Boolean(i.diff), 'diff'],
|
|
121
|
-
[(i) => Boolean(i.trailId), 'detail'],
|
|
122
|
-
[(i) => i.generate, 'generate'],
|
|
123
|
-
[(i) => i.openapi, 'openapi'],
|
|
124
|
-
];
|
|
289
|
+
type SurveyEnvelope = { readonly mode: SurveyMode } & Record<string, unknown>;
|
|
125
290
|
|
|
126
|
-
/** Determine which survey mode was requested, falling back to '
|
|
127
|
-
const
|
|
128
|
-
|
|
291
|
+
/** Determine which survey mode was requested, falling back to 'overview'. */
|
|
292
|
+
const deriveSurveyMode = (input: SurveyInput): SurveyMode =>
|
|
293
|
+
input.id === undefined || input.id === '' ? 'overview' : 'lookup';
|
|
129
294
|
|
|
130
295
|
type SurveyHandler = (
|
|
131
296
|
app: Topo,
|
|
132
297
|
input: SurveyInput,
|
|
133
|
-
rootDir: string
|
|
298
|
+
rootDir: string,
|
|
299
|
+
surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
|
|
134
300
|
) => Result<object, Error> | Promise<Result<object, Error>>;
|
|
135
301
|
|
|
136
302
|
/** Handlers keyed by survey mode. */
|
|
137
303
|
const surveyHandlers: Record<SurveyMode, SurveyHandler> = {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
generate: (app, _input, rootDir) => buildSurveyGenerate(app, rootDir),
|
|
144
|
-
list: (app, _input, rootDir) =>
|
|
304
|
+
lookup: (app, input, rootDir, surfaceLayerNames) =>
|
|
305
|
+
input.id === undefined || input.id === ''
|
|
306
|
+
? Result.err(new ValidationError('Survey lookup requires an id'))
|
|
307
|
+
: buildSurveyLookup(app, input.id, rootDir, surfaceLayerNames),
|
|
308
|
+
overview: (app, _input, rootDir) =>
|
|
145
309
|
Result.ok(buildCurrentTopoList(app, { rootDir })),
|
|
146
|
-
openapi: (app) => Result.ok(generateOpenApiSpec(app)),
|
|
147
310
|
};
|
|
148
311
|
|
|
312
|
+
const envelopeSurveyValue = (
|
|
313
|
+
mode: SurveyMode,
|
|
314
|
+
value: object
|
|
315
|
+
): SurveyEnvelope => ({ ...value, mode });
|
|
316
|
+
|
|
149
317
|
/** Dispatch to the appropriate survey sub-command based on input flags. */
|
|
150
|
-
const dispatchSurvey = (
|
|
318
|
+
const dispatchSurvey = async (
|
|
151
319
|
app: Topo,
|
|
152
320
|
input: SurveyInput,
|
|
153
|
-
rootDir: string
|
|
154
|
-
|
|
155
|
-
|
|
321
|
+
rootDir: string,
|
|
322
|
+
surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
|
|
323
|
+
): Promise<Result<SurveyEnvelope, Error>> => {
|
|
324
|
+
const mode = deriveSurveyMode(input);
|
|
156
325
|
const handler = surveyHandlers[mode];
|
|
157
|
-
|
|
326
|
+
const result = await handler(app, input, rootDir, surfaceLayerNames);
|
|
327
|
+
if (result.isErr()) {
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
return Result.ok(envelopeSurveyValue(mode, result.value));
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const detailInputSchema = z.object({
|
|
334
|
+
id: z.string().describe('Trail, resource, or signal ID'),
|
|
335
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
336
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const withFreshSurveyApp = async <T>(
|
|
340
|
+
input: { readonly module?: string | undefined },
|
|
341
|
+
rootDir: string,
|
|
342
|
+
consume: (app: Topo) => Promise<Result<T, Error>> | Result<T, Error>
|
|
343
|
+
): Promise<Result<T, Error>> => {
|
|
344
|
+
const leaseResult = await tryLoadFreshAppLease(input.module, rootDir);
|
|
345
|
+
if (leaseResult.isErr()) {
|
|
346
|
+
return Result.err(leaseResult.error);
|
|
347
|
+
}
|
|
348
|
+
const lease = leaseResult.value;
|
|
349
|
+
try {
|
|
350
|
+
return await consume(lease.app);
|
|
351
|
+
} finally {
|
|
352
|
+
lease.release();
|
|
353
|
+
}
|
|
158
354
|
};
|
|
159
355
|
|
|
356
|
+
const withResolvedSurveyApp = async <T>(
|
|
357
|
+
input: {
|
|
358
|
+
readonly module?: string | undefined;
|
|
359
|
+
readonly rootDir?: string | undefined;
|
|
360
|
+
},
|
|
361
|
+
cwd: string | undefined,
|
|
362
|
+
consume: (
|
|
363
|
+
app: Topo,
|
|
364
|
+
rootDir: string
|
|
365
|
+
) => Promise<Result<T, Error>> | Result<T, Error>
|
|
366
|
+
): Promise<Result<T, Error>> => {
|
|
367
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, cwd);
|
|
368
|
+
if (rootDirResult.isErr()) {
|
|
369
|
+
return Result.err(rootDirResult.error);
|
|
370
|
+
}
|
|
371
|
+
const rootDir = rootDirResult.value;
|
|
372
|
+
return withFreshSurveyApp(input, rootDir, (app) => consume(app, rootDir));
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const moduleInputSchema = z.object({
|
|
376
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
377
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const diffEntryOutput = z.object({
|
|
381
|
+
change: z.enum(['added', 'removed', 'modified']),
|
|
382
|
+
details: z.array(z.string()).readonly(),
|
|
383
|
+
id: z.string(),
|
|
384
|
+
kind: z.enum(['contour', 'trail', 'signal', 'resource']),
|
|
385
|
+
severity: z.enum(['info', 'warning', 'breaking']),
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const diffOutput = z.object({
|
|
389
|
+
against: z.string(),
|
|
390
|
+
breaking: z.array(diffEntryOutput),
|
|
391
|
+
hasBreaking: z.boolean(),
|
|
392
|
+
info: z.array(diffEntryOutput),
|
|
393
|
+
mode: z.literal('diff'),
|
|
394
|
+
warnings: z.array(diffEntryOutput),
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
const surveyMatchOutput = z.discriminatedUnion('kind', [
|
|
398
|
+
z.object({
|
|
399
|
+
detail: trailDetailOutput,
|
|
400
|
+
kind: z.literal('trail'),
|
|
401
|
+
}),
|
|
402
|
+
z.object({
|
|
403
|
+
detail: resourceDetailOutput,
|
|
404
|
+
kind: z.literal('resource'),
|
|
405
|
+
}),
|
|
406
|
+
z.object({
|
|
407
|
+
detail: signalDetailOutput,
|
|
408
|
+
kind: z.literal('signal'),
|
|
409
|
+
}),
|
|
410
|
+
]);
|
|
411
|
+
|
|
160
412
|
// ---------------------------------------------------------------------------
|
|
161
413
|
// Trail definition
|
|
162
414
|
// ---------------------------------------------------------------------------
|
|
163
415
|
|
|
164
416
|
export const surveyTrail = trail('survey', {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
417
|
+
args: ['id'],
|
|
418
|
+
blaze: async (input, ctx) =>
|
|
419
|
+
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
420
|
+
dispatchSurvey(app, input, rootDir, readSurfaceLayerNamesFromContext(ctx))
|
|
421
|
+
),
|
|
170
422
|
description: 'Full topo introspection',
|
|
171
423
|
examples: [
|
|
172
424
|
{
|
|
173
|
-
description: '
|
|
174
|
-
input:
|
|
175
|
-
name: '
|
|
425
|
+
description: 'Show all registered trails, resources, and signals',
|
|
426
|
+
input: createIsolatedExampleInput('survey-overview'),
|
|
427
|
+
name: 'Overview',
|
|
176
428
|
},
|
|
177
429
|
{
|
|
178
|
-
description: '
|
|
179
|
-
input: {
|
|
180
|
-
name: '
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
description: 'Generate an OpenAPI 3.1 specification for the topo',
|
|
184
|
-
input: { module: './src/app.ts', openapi: true },
|
|
185
|
-
name: 'OpenAPI spec',
|
|
430
|
+
description: 'Find every trail, resource, or signal with a matching ID',
|
|
431
|
+
input: { ...createIsolatedExampleInput('survey-lookup'), id: 'survey' },
|
|
432
|
+
name: 'Lookup by ID',
|
|
186
433
|
},
|
|
187
434
|
],
|
|
188
435
|
input: z.object({
|
|
189
|
-
|
|
190
|
-
.boolean()
|
|
191
|
-
.default(false)
|
|
192
|
-
.describe('Only show breaking changes'),
|
|
193
|
-
brief: z.boolean().default(false).describe('Quick capability summary'),
|
|
194
|
-
diff: z.string().optional().describe('Diff against a git ref'),
|
|
195
|
-
generate: z
|
|
196
|
-
.boolean()
|
|
197
|
-
.default(false)
|
|
198
|
-
.describe('Generate trailhead map and lock file'),
|
|
199
|
-
module: z
|
|
436
|
+
id: z
|
|
200
437
|
.string()
|
|
201
|
-
.
|
|
202
|
-
.describe('
|
|
203
|
-
|
|
204
|
-
|
|
438
|
+
.optional()
|
|
439
|
+
.describe('Trail, resource, or signal ID to look up'),
|
|
440
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
441
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
205
442
|
}),
|
|
206
443
|
intent: 'read',
|
|
207
|
-
output: z.
|
|
444
|
+
output: z.discriminatedUnion('mode', [
|
|
208
445
|
z.object({
|
|
446
|
+
activation: activationOverviewOutput,
|
|
209
447
|
count: z.number(),
|
|
210
448
|
entries: z.array(
|
|
211
449
|
z.object({
|
|
450
|
+
activatedBy: z.array(z.string()).readonly(),
|
|
451
|
+
activates: z.array(z.string()).readonly(),
|
|
212
452
|
examples: z.number(),
|
|
213
453
|
id: z.string(),
|
|
214
454
|
kind: z.string(),
|
|
215
455
|
safety: z.string(),
|
|
216
456
|
})
|
|
217
457
|
),
|
|
218
|
-
|
|
219
|
-
|
|
458
|
+
mode: z.literal('overview'),
|
|
459
|
+
resourceCount: z.number(),
|
|
460
|
+
resources: z.array(
|
|
220
461
|
z.object({
|
|
221
462
|
description: z.string().nullable(),
|
|
222
463
|
health: z.enum(['available', 'none']),
|
|
223
464
|
id: z.string(),
|
|
224
|
-
kind: z.literal('
|
|
465
|
+
kind: z.literal('resource'),
|
|
225
466
|
lifetime: z.literal('singleton'),
|
|
226
467
|
usedBy: z.array(z.string()),
|
|
227
468
|
})
|
|
228
469
|
),
|
|
470
|
+
signalCount: z.number(),
|
|
471
|
+
signals: z.array(
|
|
472
|
+
z.object({
|
|
473
|
+
consumers: z.array(z.string()).readonly(),
|
|
474
|
+
description: z.string().nullable(),
|
|
475
|
+
examples: z.number(),
|
|
476
|
+
from: z.array(z.string()).readonly(),
|
|
477
|
+
id: z.string(),
|
|
478
|
+
kind: z.literal('signal'),
|
|
479
|
+
payloadSchema: z.boolean(),
|
|
480
|
+
producers: z.array(z.string()).readonly(),
|
|
481
|
+
})
|
|
482
|
+
),
|
|
229
483
|
}),
|
|
230
484
|
z.object({
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
detours: z.boolean(),
|
|
234
|
-
examples: z.boolean(),
|
|
235
|
-
outputSchemas: z.boolean(),
|
|
236
|
-
provisions: z.boolean(),
|
|
237
|
-
signals: z.boolean(),
|
|
238
|
-
}),
|
|
239
|
-
name: z.string(),
|
|
240
|
-
provisions: z.number(),
|
|
241
|
-
signals: z.number(),
|
|
242
|
-
trails: z.number(),
|
|
243
|
-
version: z.string(),
|
|
244
|
-
}),
|
|
245
|
-
z.object({
|
|
246
|
-
breaking: z.array(z.unknown()),
|
|
247
|
-
hasBreaking: z.boolean(),
|
|
248
|
-
info: z.array(z.unknown()),
|
|
249
|
-
warnings: z.array(z.unknown()),
|
|
250
|
-
}),
|
|
251
|
-
z.object({
|
|
252
|
-
crosses: z.array(z.string()),
|
|
253
|
-
description: z.unknown().nullable(),
|
|
254
|
-
detours: z.unknown().nullable(),
|
|
255
|
-
examples: z.array(z.unknown()),
|
|
256
|
-
id: z.string(),
|
|
257
|
-
intent: z.enum(['read', 'write', 'destroy']),
|
|
258
|
-
kind: z.string(),
|
|
259
|
-
provisions: z.array(z.string()),
|
|
260
|
-
safety: z.string(),
|
|
261
|
-
}),
|
|
262
|
-
z.object({
|
|
263
|
-
description: z.string().nullable(),
|
|
264
|
-
health: z.enum(['available', 'none']),
|
|
265
|
-
id: z.string(),
|
|
266
|
-
kind: z.literal('provision'),
|
|
267
|
-
lifetime: z.literal('singleton'),
|
|
268
|
-
usedBy: z.array(z.string()),
|
|
269
|
-
}),
|
|
270
|
-
z.object({
|
|
271
|
-
hash: z.string(),
|
|
272
|
-
lockPath: z.string(),
|
|
273
|
-
mapPath: z.string(),
|
|
274
|
-
}),
|
|
275
|
-
z.object({
|
|
276
|
-
components: z.object({
|
|
277
|
-
schemas: z.record(z.string(), z.unknown()),
|
|
278
|
-
}),
|
|
279
|
-
info: z.object({
|
|
280
|
-
description: z.string().optional(),
|
|
281
|
-
title: z.string(),
|
|
282
|
-
version: z.string(),
|
|
283
|
-
}),
|
|
284
|
-
openapi: z.literal('3.1.0'),
|
|
285
|
-
paths: z.record(z.string(), z.record(z.string(), z.unknown())),
|
|
286
|
-
servers: z
|
|
287
|
-
.array(
|
|
288
|
-
z.object({
|
|
289
|
-
description: z.string().optional(),
|
|
290
|
-
url: z.string(),
|
|
291
|
-
})
|
|
292
|
-
)
|
|
293
|
-
.optional(),
|
|
485
|
+
matches: z.array(surveyMatchOutput),
|
|
486
|
+
mode: z.literal('lookup'),
|
|
294
487
|
}),
|
|
295
488
|
]),
|
|
296
489
|
});
|
|
490
|
+
|
|
491
|
+
export const surveyBriefTrail = trail('survey.brief', {
|
|
492
|
+
blaze: async (input, ctx) =>
|
|
493
|
+
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
494
|
+
Result.ok(buildCurrentTopoBrief(app, { rootDir }))
|
|
495
|
+
),
|
|
496
|
+
description: 'Summarize topo capabilities',
|
|
497
|
+
examples: [
|
|
498
|
+
{
|
|
499
|
+
description: 'Show counts and feature flags',
|
|
500
|
+
input: createIsolatedExampleInput('survey-brief'),
|
|
501
|
+
name: 'Brief capability report',
|
|
502
|
+
},
|
|
503
|
+
],
|
|
504
|
+
input: moduleInputSchema,
|
|
505
|
+
intent: 'read',
|
|
506
|
+
output: briefReportSchema,
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
export const surveyDiffTrail = trail('survey.diff', {
|
|
510
|
+
blaze: async (input, ctx) =>
|
|
511
|
+
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
512
|
+
buildSurveyDiff(app, rootDir, input.breakingOnly, input.against)
|
|
513
|
+
),
|
|
514
|
+
description: 'Diff the current topo against a saved TopoGraph',
|
|
515
|
+
examples: [
|
|
516
|
+
{
|
|
517
|
+
description: 'Compare current topo to a saved TopoGraph directory',
|
|
518
|
+
input: createDiffExampleInput(),
|
|
519
|
+
name: 'Diff against baseline',
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
description: 'Reject an empty saved map target',
|
|
523
|
+
error: 'ValidationError',
|
|
524
|
+
input: { against: '' },
|
|
525
|
+
name: 'Reject empty diff target',
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
description: 'Reject an empty target before filtering breaking drift',
|
|
529
|
+
error: 'ValidationError',
|
|
530
|
+
input: {
|
|
531
|
+
against: '',
|
|
532
|
+
breakingOnly: true,
|
|
533
|
+
},
|
|
534
|
+
name: 'Reject empty breaking-only target',
|
|
535
|
+
},
|
|
536
|
+
],
|
|
537
|
+
input: z.object({
|
|
538
|
+
against: z
|
|
539
|
+
.string()
|
|
540
|
+
.min(1)
|
|
541
|
+
.optional()
|
|
542
|
+
.describe(
|
|
543
|
+
'Saved TopoGraph target: "saved", a workspace path (topo.lock, .json file, or directory with topo.lock), then a pin/snapshot id'
|
|
544
|
+
),
|
|
545
|
+
breakingOnly: z
|
|
546
|
+
.boolean()
|
|
547
|
+
.default(false)
|
|
548
|
+
.describe('Only show breaking changes'),
|
|
549
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
550
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
551
|
+
}),
|
|
552
|
+
intent: 'read',
|
|
553
|
+
output: diffOutput,
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
export const surveyTrailDetailTrail = trail('survey.trail', {
|
|
557
|
+
args: ['id'],
|
|
558
|
+
blaze: async (input, ctx) =>
|
|
559
|
+
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
560
|
+
buildSurveyTrailDetail(
|
|
561
|
+
app,
|
|
562
|
+
input.id,
|
|
563
|
+
rootDir,
|
|
564
|
+
readSurfaceLayerNamesFromContext(ctx)
|
|
565
|
+
)
|
|
566
|
+
),
|
|
567
|
+
description: 'Inspect one trail by ID',
|
|
568
|
+
examples: [
|
|
569
|
+
{
|
|
570
|
+
description: 'Show trail contract detail',
|
|
571
|
+
input: {
|
|
572
|
+
...createIsolatedExampleInput('survey-trail-detail'),
|
|
573
|
+
id: 'survey',
|
|
574
|
+
},
|
|
575
|
+
name: 'Trail detail',
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
input: detailInputSchema,
|
|
579
|
+
intent: 'read',
|
|
580
|
+
output: trailDetailOutput,
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
export const surveyResourceTrail = trail('survey.resource', {
|
|
584
|
+
args: ['id'],
|
|
585
|
+
blaze: async (input, ctx) =>
|
|
586
|
+
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
587
|
+
buildSurveyResourceDetail(app, input.id, rootDir)
|
|
588
|
+
),
|
|
589
|
+
description: 'Inspect one resource by ID',
|
|
590
|
+
examples: [
|
|
591
|
+
{
|
|
592
|
+
description: 'Show resource usage detail',
|
|
593
|
+
error: 'NotFoundError',
|
|
594
|
+
input: {
|
|
595
|
+
...createIsolatedExampleInput('survey-resource-detail'),
|
|
596
|
+
id: 'db.main',
|
|
597
|
+
},
|
|
598
|
+
name: 'Resource detail',
|
|
599
|
+
},
|
|
600
|
+
],
|
|
601
|
+
input: detailInputSchema,
|
|
602
|
+
intent: 'read',
|
|
603
|
+
output: resourceDetailOutput,
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
export const surveySignalTrail = trail('survey.signal', {
|
|
607
|
+
args: ['id'],
|
|
608
|
+
blaze: async (input, ctx) =>
|
|
609
|
+
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
610
|
+
buildSurveySignalDetail(app, input.id, rootDir)
|
|
611
|
+
),
|
|
612
|
+
description: 'Inspect one signal by ID',
|
|
613
|
+
examples: [
|
|
614
|
+
{
|
|
615
|
+
description: 'Show signal producer and consumer detail',
|
|
616
|
+
error: 'NotFoundError',
|
|
617
|
+
input: {
|
|
618
|
+
...createIsolatedExampleInput('survey-signal-detail'),
|
|
619
|
+
id: 'hello.greeted',
|
|
620
|
+
},
|
|
621
|
+
name: 'Signal detail',
|
|
622
|
+
},
|
|
623
|
+
],
|
|
624
|
+
input: detailInputSchema,
|
|
625
|
+
intent: 'read',
|
|
626
|
+
output: signalDetailOutput,
|
|
627
|
+
});
|