@ontrails/trails 1.0.0-beta.30 → 1.0.0-beta.32
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 +89 -0
- package/README.md +2 -2
- package/package.json +16 -16
- package/src/cli.ts +1 -0
- package/src/mcp-options.ts +1 -0
- package/src/regrade/config.ts +152 -0
- package/src/release/pack-coherence.ts +1 -3
- package/src/trails/create-adapter.ts +19 -79
- package/src/trails/deprecate.ts +1 -1
- package/src/trails/guide.ts +4 -4
- package/src/trails/load-app.ts +21 -72
- package/src/trails/regrade.ts +227 -7
- package/src/trails/revise.ts +1 -1
- package/src/trails/survey.ts +12 -12
- package/src/trails/topo-activation.ts +14 -385
- package/src/trails/topo-read-support.ts +13 -13
- package/src/trails/topo.ts +2 -2
- package/src/trails/version-lifecycle-support.ts +11 -11
- package/src/trails/warden-guide.ts +9 -4
- package/src/trails/warden.ts +15 -0
package/src/trails/regrade.ts
CHANGED
|
@@ -2,19 +2,41 @@
|
|
|
2
2
|
* `regrade` trail -- Run downstream migration checks and safe rewrites.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { NotFoundError, Result, trail, validateOutput } from '@ontrails/core';
|
|
6
|
-
import type { Result as TrailsResult } from '@ontrails/core';
|
|
7
5
|
import {
|
|
6
|
+
InternalError,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
Result,
|
|
9
|
+
ValidationError,
|
|
10
|
+
pathScopeSchema,
|
|
11
|
+
trail,
|
|
12
|
+
validateOutput,
|
|
13
|
+
} from '@ontrails/core';
|
|
14
|
+
import type { PathScope, Result as TrailsResult } from '@ontrails/core';
|
|
15
|
+
import {
|
|
16
|
+
loadWardenTermRewriteClasses,
|
|
8
17
|
regradeReportOutput,
|
|
9
18
|
runRegrade,
|
|
10
|
-
|
|
19
|
+
runVocabularyRegrade,
|
|
11
20
|
} from '@ontrails/regrade';
|
|
12
|
-
import type { RegradeReport } from '@ontrails/regrade';
|
|
21
|
+
import type { RegradeReport, VocabularyRegradePlan } from '@ontrails/regrade';
|
|
13
22
|
import { z } from 'zod';
|
|
14
23
|
|
|
24
|
+
import { loadRegradeConfig } from '../regrade/config.js';
|
|
15
25
|
import { resolveTrailRootDir } from './root-dir.js';
|
|
16
26
|
|
|
17
|
-
const
|
|
27
|
+
const regradePathScopeInputSchema = pathScopeSchema.extend({
|
|
28
|
+
exclude: pathScopeSchema.shape.exclude.describe(
|
|
29
|
+
'Root-relative path globs to exclude during Regrade collection'
|
|
30
|
+
),
|
|
31
|
+
extensions: pathScopeSchema.shape.extensions.describe(
|
|
32
|
+
'Source file extensions to scan during Regrade collection'
|
|
33
|
+
),
|
|
34
|
+
include: pathScopeSchema.shape.include.describe(
|
|
35
|
+
'Root-relative path patterns to include in vocabulary regrade mode'
|
|
36
|
+
),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const regradeInputSchema = regradePathScopeInputSchema.extend({
|
|
18
40
|
apply: z
|
|
19
41
|
.boolean()
|
|
20
42
|
.default(false)
|
|
@@ -23,19 +45,217 @@ const regradeInputSchema = z.object({
|
|
|
23
45
|
.array(z.string())
|
|
24
46
|
.optional()
|
|
25
47
|
.describe('Regrade class ids to run (defaults to all built-in classes)'),
|
|
48
|
+
configPath: z
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Path to a Trails config file with regrade defaults'),
|
|
52
|
+
from: z
|
|
53
|
+
.string()
|
|
54
|
+
.min(1)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('Source vocabulary term for a vocabulary regrade'),
|
|
57
|
+
includeEntries: z
|
|
58
|
+
.enum(['actionable', 'all'])
|
|
59
|
+
.default('actionable')
|
|
60
|
+
.describe(
|
|
61
|
+
'Report entry detail to include; counts always cover the full run'
|
|
62
|
+
),
|
|
63
|
+
intent: z
|
|
64
|
+
.string()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe('Human-authored migration intent for a vocabulary regrade'),
|
|
67
|
+
overrides: z
|
|
68
|
+
.record(z.string().min(1), z.string().min(1))
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Explicit source-form to target-form mappings'),
|
|
71
|
+
preserve: z
|
|
72
|
+
.array(z.string().min(1))
|
|
73
|
+
.optional()
|
|
74
|
+
.describe(
|
|
75
|
+
'Regex or literal contexts to preserve during a vocabulary regrade'
|
|
76
|
+
),
|
|
26
77
|
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
78
|
+
to: z
|
|
79
|
+
.string()
|
|
80
|
+
.min(1)
|
|
81
|
+
.optional()
|
|
82
|
+
.describe('Target vocabulary term for a vocabulary regrade'),
|
|
27
83
|
});
|
|
28
84
|
|
|
85
|
+
const hasVocabularyInput = (input: z.output<typeof regradeInputSchema>) =>
|
|
86
|
+
input.from !== undefined ||
|
|
87
|
+
input.include !== undefined ||
|
|
88
|
+
input.intent !== undefined ||
|
|
89
|
+
input.overrides !== undefined ||
|
|
90
|
+
input.preserve !== undefined ||
|
|
91
|
+
input.to !== undefined;
|
|
92
|
+
|
|
93
|
+
const classModeCollection = (
|
|
94
|
+
input: z.output<typeof regradeInputSchema>,
|
|
95
|
+
configScope?: RegradeConfigScope | undefined
|
|
96
|
+
):
|
|
97
|
+
| {
|
|
98
|
+
readonly exclude?: readonly string[];
|
|
99
|
+
readonly extensions?: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
| undefined => {
|
|
102
|
+
if (
|
|
103
|
+
configScope?.exclude === undefined &&
|
|
104
|
+
configScope?.extensions === undefined &&
|
|
105
|
+
input.exclude === undefined &&
|
|
106
|
+
input.extensions === undefined
|
|
107
|
+
) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
...(configScope?.exclude === undefined
|
|
113
|
+
? {}
|
|
114
|
+
: { exclude: configScope.exclude }),
|
|
115
|
+
...(configScope?.extensions === undefined
|
|
116
|
+
? {}
|
|
117
|
+
: { extensions: configScope.extensions }),
|
|
118
|
+
...(input.exclude === undefined ? {} : { exclude: input.exclude }),
|
|
119
|
+
...(input.extensions === undefined ? {} : { extensions: input.extensions }),
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
interface RegradeConfigScope {
|
|
124
|
+
readonly exclude?: PathScope['exclude'] | undefined;
|
|
125
|
+
readonly extensions?: PathScope['extensions'] | undefined;
|
|
126
|
+
readonly include?: PathScope['include'] | undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const vocabularyScopeFromConfig = (
|
|
130
|
+
scope: RegradeConfigScope | undefined
|
|
131
|
+
): VocabularyRegradePlan['scope'] | undefined =>
|
|
132
|
+
scope === undefined
|
|
133
|
+
? undefined
|
|
134
|
+
: {
|
|
135
|
+
...(scope.exclude === undefined ? {} : { exclude: scope.exclude }),
|
|
136
|
+
...(scope.extensions === undefined
|
|
137
|
+
? {}
|
|
138
|
+
: { extensions: scope.extensions }),
|
|
139
|
+
...(scope.include === undefined ? {} : { include: scope.include }),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const buildVocabularyPlan = (
|
|
143
|
+
input: z.output<typeof regradeInputSchema>,
|
|
144
|
+
configScope?: VocabularyRegradePlan['scope']
|
|
145
|
+
): TrailsResult<VocabularyRegradePlan, ValidationError> => {
|
|
146
|
+
if (input.from === undefined || input.to === undefined) {
|
|
147
|
+
return Result.err(
|
|
148
|
+
new ValidationError('A vocabulary regrade requires both `from` and `to`.')
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
if (input.classIds !== undefined) {
|
|
152
|
+
return Result.err(
|
|
153
|
+
new ValidationError(
|
|
154
|
+
'`classIds` selects class-mode Regrade and cannot be combined with vocabulary-regrade `from`/`to`.'
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return Result.ok({
|
|
160
|
+
from: input.from,
|
|
161
|
+
id: `vocabulary:${input.from}->${input.to}`,
|
|
162
|
+
kind: 'vocabulary',
|
|
163
|
+
...(input.intent === undefined ? {} : { intent: input.intent }),
|
|
164
|
+
...(input.overrides === undefined ? {} : { overrides: input.overrides }),
|
|
165
|
+
...(input.preserve === undefined
|
|
166
|
+
? {}
|
|
167
|
+
: {
|
|
168
|
+
preserve: input.preserve.map((pattern) => ({
|
|
169
|
+
pattern,
|
|
170
|
+
reason: 'preserved-by-operator-input',
|
|
171
|
+
})),
|
|
172
|
+
}),
|
|
173
|
+
scope: {
|
|
174
|
+
...configScope,
|
|
175
|
+
...(input.exclude === undefined ? {} : { exclude: input.exclude }),
|
|
176
|
+
...(input.extensions === undefined
|
|
177
|
+
? {}
|
|
178
|
+
: { extensions: input.extensions }),
|
|
179
|
+
...(input.include === undefined ? {} : { include: input.include }),
|
|
180
|
+
},
|
|
181
|
+
to: input.to,
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
|
|
29
185
|
export const regradeTrail = trail('regrade', {
|
|
30
|
-
|
|
186
|
+
args: ['from', 'to'],
|
|
187
|
+
blaze: async (input, ctx) => {
|
|
31
188
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
32
189
|
if (rootDirResult.isErr()) {
|
|
33
190
|
return rootDirResult;
|
|
34
191
|
}
|
|
35
192
|
|
|
193
|
+
const configResult = await loadRegradeConfig({
|
|
194
|
+
...(input.configPath === undefined
|
|
195
|
+
? {}
|
|
196
|
+
: { configPath: input.configPath }),
|
|
197
|
+
env: ctx.env,
|
|
198
|
+
rootDir: rootDirResult.value,
|
|
199
|
+
});
|
|
200
|
+
if (configResult.isErr()) {
|
|
201
|
+
return configResult;
|
|
202
|
+
}
|
|
203
|
+
const configScope = configResult.value.config?.scope;
|
|
204
|
+
|
|
205
|
+
if (hasVocabularyInput(input)) {
|
|
206
|
+
const planResult = buildVocabularyPlan(
|
|
207
|
+
input,
|
|
208
|
+
vocabularyScopeFromConfig(configScope)
|
|
209
|
+
);
|
|
210
|
+
if (planResult.isErr()) {
|
|
211
|
+
return planResult;
|
|
212
|
+
}
|
|
213
|
+
const reportResult: TrailsResult<RegradeReport | null, Error> =
|
|
214
|
+
runVocabularyRegrade({
|
|
215
|
+
apply: input.apply,
|
|
216
|
+
includeEntries: input.includeEntries,
|
|
217
|
+
plan: planResult.value,
|
|
218
|
+
root: rootDirResult.value,
|
|
219
|
+
});
|
|
220
|
+
if (reportResult.isErr()) {
|
|
221
|
+
return reportResult;
|
|
222
|
+
}
|
|
223
|
+
const report = reportResult.value;
|
|
224
|
+
if (report === null) {
|
|
225
|
+
return Result.err(
|
|
226
|
+
new NotFoundError(
|
|
227
|
+
`Regrade root "${rootDirResult.value}" could not be read as a directory.`
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
const validated: TrailsResult<
|
|
232
|
+
z.output<typeof regradeReportOutput>,
|
|
233
|
+
Error
|
|
234
|
+
> = validateOutput(regradeReportOutput, report);
|
|
235
|
+
if (validated.isErr()) {
|
|
236
|
+
return validated;
|
|
237
|
+
}
|
|
238
|
+
return Result.ok(validated.value);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const classSet = await loadWardenTermRewriteClasses(rootDirResult.value);
|
|
242
|
+
if (classSet.diagnostics.length > 0) {
|
|
243
|
+
return Result.err(
|
|
244
|
+
new InternalError('Failed to load Regrade project Warden rules.', {
|
|
245
|
+
context: {
|
|
246
|
+
diagnostics: classSet.diagnostics,
|
|
247
|
+
rootDir: rootDirResult.value,
|
|
248
|
+
},
|
|
249
|
+
})
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const collection = classModeCollection(input, configScope);
|
|
36
254
|
const reportResult: TrailsResult<RegradeReport | null, Error> = runRegrade({
|
|
37
255
|
apply: input.apply,
|
|
38
|
-
classes:
|
|
256
|
+
classes: classSet.classes,
|
|
257
|
+
...(collection === undefined ? {} : { collection }),
|
|
258
|
+
includeEntries: input.includeEntries,
|
|
39
259
|
root: rootDirResult.value,
|
|
40
260
|
...(input.classIds === undefined
|
|
41
261
|
? {}
|
package/src/trails/revise.ts
CHANGED
package/src/trails/survey.ts
CHANGED
|
@@ -30,12 +30,12 @@ import { writeIsolatedExampleJsonFile } from '../local-state-io.js';
|
|
|
30
30
|
|
|
31
31
|
import { withFreshAppLease, withOperatorRootDir } from './operator-context.js';
|
|
32
32
|
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
deriveCurrentTopoBrief,
|
|
34
|
+
deriveCurrentTopoList,
|
|
35
|
+
deriveCurrentTopoMatches,
|
|
36
|
+
deriveCurrentTrailDetail,
|
|
37
|
+
deriveCurrentResourceDetail,
|
|
38
|
+
deriveCurrentSignalDetail,
|
|
39
39
|
readSurfaceLayerNamesFromContext,
|
|
40
40
|
} from './topo-read-support.js';
|
|
41
41
|
import {
|
|
@@ -511,7 +511,7 @@ const buildSurveyLookup = (
|
|
|
511
511
|
| undefined,
|
|
512
512
|
surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
|
|
513
513
|
): Result<object, Error> => {
|
|
514
|
-
const matches =
|
|
514
|
+
const matches = deriveCurrentTopoMatches(app, entityId, {
|
|
515
515
|
cliAliases,
|
|
516
516
|
rootDir,
|
|
517
517
|
surfaceLayerNames,
|
|
@@ -528,7 +528,7 @@ const buildSurveyTrailDetail = (
|
|
|
528
528
|
| undefined,
|
|
529
529
|
surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
|
|
530
530
|
): Result<object, Error> => {
|
|
531
|
-
const detail =
|
|
531
|
+
const detail = deriveCurrentTrailDetail(app, id, {
|
|
532
532
|
cliAliases,
|
|
533
533
|
rootDir,
|
|
534
534
|
surfaceLayerNames,
|
|
@@ -543,7 +543,7 @@ const buildSurveyResourceDetail = (
|
|
|
543
543
|
id: string,
|
|
544
544
|
rootDir: string
|
|
545
545
|
): Result<object, Error> => {
|
|
546
|
-
const detail =
|
|
546
|
+
const detail = deriveCurrentResourceDetail(app, id, { rootDir });
|
|
547
547
|
return detail === undefined
|
|
548
548
|
? Result.err(new NotFoundError(`Resource not found: ${id}`))
|
|
549
549
|
: Result.ok(detail);
|
|
@@ -554,7 +554,7 @@ const buildSurveySignalDetail = (
|
|
|
554
554
|
id: string,
|
|
555
555
|
rootDir: string
|
|
556
556
|
): Result<object, Error> => {
|
|
557
|
-
const detail =
|
|
557
|
+
const detail = deriveCurrentSignalDetail(app, id, { rootDir });
|
|
558
558
|
return detail === undefined
|
|
559
559
|
? Result.err(new NotFoundError(`Signal not found: ${id}`))
|
|
560
560
|
: Result.ok(detail);
|
|
@@ -600,7 +600,7 @@ const surveyHandlers: Record<SurveyMode, SurveyHandler> = {
|
|
|
600
600
|
surfaceLayerNames
|
|
601
601
|
),
|
|
602
602
|
overview: (app, _input, rootDir) =>
|
|
603
|
-
Result.ok(
|
|
603
|
+
Result.ok(deriveCurrentTopoList(app, { rootDir })),
|
|
604
604
|
};
|
|
605
605
|
|
|
606
606
|
const envelopeSurveyValue = (
|
|
@@ -824,7 +824,7 @@ export const surveyTrail = trail('survey', {
|
|
|
824
824
|
export const surveyBriefTrail = trail('survey.brief', {
|
|
825
825
|
blaze: async (input, ctx) =>
|
|
826
826
|
withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
|
|
827
|
-
Result.ok(
|
|
827
|
+
Result.ok(deriveCurrentTopoBrief(app, { rootDir }))
|
|
828
828
|
),
|
|
829
829
|
description: 'Summarize topo capabilities',
|
|
830
830
|
examples: [
|