@ontrails/trails 0.2.0
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 +1906 -0
- package/README.md +48 -0
- package/bin/trails.ts +3 -0
- package/package.json +57 -0
- package/src/app.ts +167 -0
- package/src/clack.ts +111 -0
- package/src/cli.ts +308 -0
- package/src/completions.ts +431 -0
- package/src/lifecycle-source-io.ts +33 -0
- package/src/load-app-mirror.ts +202 -0
- package/src/local-state-io.ts +129 -0
- package/src/mcp-app.ts +42 -0
- package/src/mcp-options.ts +92 -0
- package/src/mcp.ts +8 -0
- package/src/project-writes.ts +377 -0
- package/src/regrade/audit.ts +571 -0
- package/src/regrade/config.ts +152 -0
- package/src/regrade/history.ts +636 -0
- package/src/regrade/lifecycle.ts +76 -0
- package/src/regrade/live-api-preserve.ts +123 -0
- package/src/regrade/plan-artifact.ts +515 -0
- package/src/regrade/plan-derivation.ts +301 -0
- package/src/regrade/prepared-run.ts +259 -0
- package/src/regrade/receipt-history.ts +446 -0
- package/src/regrade/source-transaction.ts +185 -0
- package/src/release/bindings.ts +58 -0
- package/src/release/changeset-packages.ts +99 -0
- package/src/release/check.ts +1191 -0
- package/src/release/cli-bundle.ts +575 -0
- package/src/release/config.ts +73 -0
- package/src/release/contract-facts.ts +425 -0
- package/src/release/homebrew.ts +221 -0
- package/src/release/index.ts +180 -0
- package/src/release/lock-roundtrip-smoke.ts +255 -0
- package/src/release/lock-roundtrip-workspace.ts +107 -0
- package/src/release/native-bun-publish.ts +964 -0
- package/src/release/native-bun-registry.ts +848 -0
- package/src/release/notes-cli.ts +171 -0
- package/src/release/notes.ts +390 -0
- package/src/release/pack-coherence.ts +455 -0
- package/src/release/package-route-facts.ts +146 -0
- package/src/release/packed-artifacts-smoke.ts +236 -0
- package/src/release/policy.ts +1780 -0
- package/src/release/semver.ts +104 -0
- package/src/release/smoke.ts +56 -0
- package/src/release/stable-version-release.ts +80 -0
- package/src/release/wayfinder-dogfood-smoke.ts +762 -0
- package/src/release/zero-line-transition.ts +68 -0
- package/src/retired-topo-command.ts +36 -0
- package/src/run-adapter-check.ts +76 -0
- package/src/run-argv.ts +133 -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-regrade-progress.ts +47 -0
- package/src/run-release-check.ts +74 -0
- package/src/run-schema.ts +74 -0
- package/src/run-trace.ts +273 -0
- package/src/run-warden.ts +39 -0
- package/src/run-watch-project.ts +52 -0
- package/src/run-watch.ts +381 -0
- package/src/run-wayfind-outline.ts +170 -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 +816 -0
- package/src/trails/add-trail.ts +141 -0
- package/src/trails/add-verify.ts +252 -0
- package/src/trails/compile.ts +118 -0
- package/src/trails/completions-complete.ts +236 -0
- package/src/trails/completions.ts +47 -0
- package/src/trails/config-explain.ts +43 -0
- package/src/trails/create-adapter.ts +785 -0
- package/src/trails/create-scaffold.ts +1215 -0
- package/src/trails/create-versions.ts +62 -0
- package/src/trails/create.ts +652 -0
- package/src/trails/deprecate.ts +59 -0
- package/src/trails/dev-clean.ts +80 -0
- package/src/trails/dev-reset.ts +48 -0
- package/src/trails/dev-stats.ts +71 -0
- package/src/trails/dev-support.ts +360 -0
- package/src/trails/doctor.ts +77 -0
- package/src/trails/draft-promote.ts +949 -0
- package/src/trails/guide.ts +106 -0
- package/src/trails/load-app.ts +1145 -0
- package/src/trails/operator-context.ts +66 -0
- package/src/trails/project-context-output.ts +304 -0
- package/src/trails/project-context.ts +613 -0
- package/src/trails/project.ts +65 -0
- package/src/trails/regrade.ts +4951 -0
- package/src/trails/release-check.ts +113 -0
- package/src/trails/release-smoke.ts +49 -0
- package/src/trails/revise.ts +53 -0
- package/src/trails/root-dir.ts +21 -0
- package/src/trails/run-example.ts +592 -0
- package/src/trails/run-examples.ts +149 -0
- package/src/trails/run.ts +496 -0
- package/src/trails/scaffold-json.ts +60 -0
- package/src/trails/scaffold-topo-identity.ts +479 -0
- package/src/trails/survey.ts +990 -0
- package/src/trails/topo-activation.ts +14 -0
- package/src/trails/topo-constants.ts +2 -0
- package/src/trails/topo-history.ts +47 -0
- package/src/trails/topo-output-schemas.ts +259 -0
- package/src/trails/topo-pin.ts +38 -0
- package/src/trails/topo-read-support.ts +368 -0
- package/src/trails/topo-reports.ts +809 -0
- package/src/trails/topo-store-support.ts +323 -0
- package/src/trails/topo-support.ts +247 -0
- package/src/trails/topo-unpin.ts +61 -0
- package/src/trails/topo.ts +92 -0
- package/src/trails/validate.ts +348 -0
- package/src/trails/version-lifecycle-support.ts +936 -0
- package/src/trails/warden-guide.ts +134 -0
- package/src/trails/warden.ts +598 -0
- package/src/trails/wayfind-diff.ts +716 -0
- package/src/trails/wayfind-outline.ts +876 -0
- package/src/trails/wayfind.ts +1319 -0
- package/src/versions.ts +31 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scaffold dependency version derivation for the `create.versions` trail.
|
|
3
|
+
*
|
|
4
|
+
* Generates or validates `apps/trails/src/scaffold-versions.generated.ts`
|
|
5
|
+
* from the root `package.json` catalog and devDependencies, and validates
|
|
6
|
+
* that generated `@ontrails/*` package pins track the `@ontrails/trails`
|
|
7
|
+
* version exactly.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { resolve } from 'node:path';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
ontrailsPackageRange as appOntrailsPackageRange,
|
|
14
|
+
trailsPackageVersion as appTrailsPackageVersion,
|
|
15
|
+
} from './versions.js';
|
|
16
|
+
|
|
17
|
+
interface RootPackageJson {
|
|
18
|
+
readonly catalog?: Record<string, string>;
|
|
19
|
+
readonly devDependencies?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface OntrailsPackagePinState {
|
|
23
|
+
readonly ontrailsPackageRange?: string;
|
|
24
|
+
readonly trailsPackageVersion?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface SyncScaffoldVersionsResult {
|
|
28
|
+
readonly generatedPath: string;
|
|
29
|
+
readonly mode: 'check' | 'write';
|
|
30
|
+
readonly written: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const diagnoseOntrailsPackagePin = ({
|
|
34
|
+
ontrailsPackageRange,
|
|
35
|
+
trailsPackageVersion,
|
|
36
|
+
}: OntrailsPackagePinState): string | undefined => {
|
|
37
|
+
if (
|
|
38
|
+
typeof ontrailsPackageRange !== 'string' ||
|
|
39
|
+
typeof trailsPackageVersion !== 'string'
|
|
40
|
+
) {
|
|
41
|
+
return (
|
|
42
|
+
'create.versions: apps/trails/src/versions.ts must export ' +
|
|
43
|
+
'`ontrailsPackageRange` and `trailsPackageVersion`.'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (ontrailsPackageRange !== trailsPackageVersion) {
|
|
47
|
+
return (
|
|
48
|
+
'create.versions: scaffolded @ontrails/* packages must be exact ' +
|
|
49
|
+
`pins for @ontrails/trails (${trailsPackageVersion}); got ` +
|
|
50
|
+
`${ontrailsPackageRange}.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const requireValue = (
|
|
57
|
+
value: string | undefined,
|
|
58
|
+
label: string,
|
|
59
|
+
source: string,
|
|
60
|
+
rootPackageJsonPath: string
|
|
61
|
+
): string => {
|
|
62
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`create.versions: missing "${label}" under ${source} in ${rootPackageJsonPath}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const loadScaffoldVersions = async (
|
|
71
|
+
rootPackageJsonPath: string
|
|
72
|
+
): Promise<Record<string, string> & Readonly<Record<string, string>>> => {
|
|
73
|
+
const rootPkg = (await Bun.file(
|
|
74
|
+
rootPackageJsonPath
|
|
75
|
+
).json()) as RootPackageJson;
|
|
76
|
+
const catalog = rootPkg.catalog ?? {};
|
|
77
|
+
const devDeps = rootPkg.devDependencies ?? {};
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
bunTypes: requireValue(
|
|
81
|
+
devDeps['@types/bun'],
|
|
82
|
+
'@types/bun',
|
|
83
|
+
'devDependencies',
|
|
84
|
+
rootPackageJsonPath
|
|
85
|
+
),
|
|
86
|
+
commander: requireValue(
|
|
87
|
+
catalog['commander'],
|
|
88
|
+
'commander',
|
|
89
|
+
'catalog',
|
|
90
|
+
rootPackageJsonPath
|
|
91
|
+
),
|
|
92
|
+
lefthook: requireValue(
|
|
93
|
+
devDeps['lefthook'],
|
|
94
|
+
'lefthook',
|
|
95
|
+
'devDependencies',
|
|
96
|
+
rootPackageJsonPath
|
|
97
|
+
),
|
|
98
|
+
oxfmt: requireValue(
|
|
99
|
+
devDeps['oxfmt'],
|
|
100
|
+
'oxfmt',
|
|
101
|
+
'devDependencies',
|
|
102
|
+
rootPackageJsonPath
|
|
103
|
+
),
|
|
104
|
+
oxlint: requireValue(
|
|
105
|
+
devDeps['oxlint'],
|
|
106
|
+
'oxlint',
|
|
107
|
+
'devDependencies',
|
|
108
|
+
rootPackageJsonPath
|
|
109
|
+
),
|
|
110
|
+
typescript: requireValue(
|
|
111
|
+
devDeps['typescript'],
|
|
112
|
+
'typescript',
|
|
113
|
+
'devDependencies',
|
|
114
|
+
rootPackageJsonPath
|
|
115
|
+
),
|
|
116
|
+
ultracite: requireValue(
|
|
117
|
+
devDeps['ultracite'],
|
|
118
|
+
'ultracite',
|
|
119
|
+
'devDependencies',
|
|
120
|
+
rootPackageJsonPath
|
|
121
|
+
),
|
|
122
|
+
zod: requireValue(catalog['zod'], 'zod', 'catalog', rootPackageJsonPath),
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const renderGeneratedFile = (
|
|
127
|
+
versions: Record<string, string> & Readonly<Record<string, string>>
|
|
128
|
+
): string => {
|
|
129
|
+
const keys = Object.keys(versions).toSorted();
|
|
130
|
+
const lines = keys.map((key: string) => ` ${key}: '${versions[key]}',`);
|
|
131
|
+
return [
|
|
132
|
+
'// GENERATED FILE — do not edit by hand. Run `bun run scaffold-versions:sync` to regenerate.',
|
|
133
|
+
'',
|
|
134
|
+
'export const scaffoldDependencyVersions = {',
|
|
135
|
+
...lines,
|
|
136
|
+
'} as const;',
|
|
137
|
+
'',
|
|
138
|
+
].join('\n');
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const syncScaffoldVersions = async (options: {
|
|
142
|
+
check: boolean;
|
|
143
|
+
rootDir: string;
|
|
144
|
+
}): Promise<SyncScaffoldVersionsResult> => {
|
|
145
|
+
const rootPackageJsonPath = resolve(options.rootDir, 'package.json');
|
|
146
|
+
const generatedPath = resolve(
|
|
147
|
+
options.rootDir,
|
|
148
|
+
'apps/trails/src/scaffold-versions.generated.ts'
|
|
149
|
+
);
|
|
150
|
+
const versions = await loadScaffoldVersions(rootPackageJsonPath);
|
|
151
|
+
const expected = renderGeneratedFile(versions);
|
|
152
|
+
|
|
153
|
+
if (options.check) {
|
|
154
|
+
const generatedFile = Bun.file(generatedPath);
|
|
155
|
+
const existing = (await generatedFile.exists())
|
|
156
|
+
? await generatedFile.text()
|
|
157
|
+
: undefined;
|
|
158
|
+
if (existing !== expected) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`create.versions: ${generatedPath} is out of date.\n` +
|
|
161
|
+
'Run `bun run scaffold-versions:sync` to regenerate.'
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
await Bun.write(generatedPath, expected);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Normally quiet because versions.ts derives both exports from one source;
|
|
169
|
+
// this trips only if future/manual drift breaks that invariant.
|
|
170
|
+
const diagnostic = diagnoseOntrailsPackagePin({
|
|
171
|
+
ontrailsPackageRange: appOntrailsPackageRange,
|
|
172
|
+
trailsPackageVersion: appTrailsPackageVersion,
|
|
173
|
+
});
|
|
174
|
+
if (diagnostic !== undefined) {
|
|
175
|
+
throw new Error(diagnostic);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
generatedPath,
|
|
180
|
+
mode: options.check ? 'check' : 'write',
|
|
181
|
+
written: !options.check,
|
|
182
|
+
};
|
|
183
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// GENERATED FILE — do not edit by hand. Run `bun run scaffold-versions:sync` to regenerate.
|
|
2
|
+
|
|
3
|
+
export const scaffoldDependencyVersions = {
|
|
4
|
+
bunTypes: '^1.3.11',
|
|
5
|
+
commander: '^14.0.3',
|
|
6
|
+
lefthook: '^2.1.1',
|
|
7
|
+
oxfmt: '0.47.0',
|
|
8
|
+
oxlint: '1.62.0',
|
|
9
|
+
typescript: '^5.9.3',
|
|
10
|
+
ultracite: '7.6.2',
|
|
11
|
+
zod: '^4.3.5',
|
|
12
|
+
} as const;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `adapter.check` trail -- Local adapter authoring readiness checks.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { adapterTargetPlacements, checkAdapters } from '@ontrails/adapter-kit';
|
|
6
|
+
import type { AdapterCheckReport } from '@ontrails/adapter-kit';
|
|
7
|
+
import { isPlainObject, Result, trail, ValidationError } from '@ontrails/core';
|
|
8
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
9
|
+
import { join, relative } from 'node:path';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
|
|
12
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
13
|
+
|
|
14
|
+
const adapterCheckInputSchema = z.object({
|
|
15
|
+
rootDir: z.string().optional().describe('Root directory to scan'),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const adapterPlacementSchema = z.enum(adapterTargetPlacements);
|
|
19
|
+
|
|
20
|
+
const adapterCheckDiagnosticSchema = z.object({
|
|
21
|
+
code: z.string().describe('Stable adapter diagnostic code'),
|
|
22
|
+
message: z.string(),
|
|
23
|
+
packageJsonPath: z.string(),
|
|
24
|
+
packageName: z.string().optional(),
|
|
25
|
+
placement: adapterPlacementSchema.optional(),
|
|
26
|
+
severity: z.enum(['error', 'warn']),
|
|
27
|
+
target: z.string().optional(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const adapterCheckSubjectSchema = z.object({
|
|
31
|
+
conformanceTestPaths: z.array(z.string()).readonly(),
|
|
32
|
+
key: z.string(),
|
|
33
|
+
ownerPackage: z.string(),
|
|
34
|
+
packageJsonPath: z.string(),
|
|
35
|
+
packageName: z.string(),
|
|
36
|
+
packageRoot: z.string(),
|
|
37
|
+
placement: adapterPlacementSchema,
|
|
38
|
+
target: z.string(),
|
|
39
|
+
targetKey: z.string(),
|
|
40
|
+
testingImport: z.string().optional(),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const adapterTargetSchema = z.object({
|
|
44
|
+
conformance: z
|
|
45
|
+
.object({
|
|
46
|
+
adapterType: z.string(),
|
|
47
|
+
casesFactory: z.string(),
|
|
48
|
+
runner: z.string(),
|
|
49
|
+
})
|
|
50
|
+
.optional(),
|
|
51
|
+
key: z.string(),
|
|
52
|
+
ownerPackage: z.string(),
|
|
53
|
+
packageJsonPath: z.string(),
|
|
54
|
+
packageRoot: z.string(),
|
|
55
|
+
placements: z.array(adapterPlacementSchema).readonly(),
|
|
56
|
+
supportExportTarget: z.string().optional(),
|
|
57
|
+
supportImport: z.string().optional(),
|
|
58
|
+
target: z.string(),
|
|
59
|
+
testingExportTarget: z.string().optional(),
|
|
60
|
+
testingImport: z.string().optional(),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const adapterCheckOutputSchema = z.object({
|
|
64
|
+
diagnostics: z.array(adapterCheckDiagnosticSchema).readonly(),
|
|
65
|
+
formatted: z.string(),
|
|
66
|
+
passed: z.boolean(),
|
|
67
|
+
subjects: z.array(adapterCheckSubjectSchema).readonly(),
|
|
68
|
+
targets: z.array(adapterTargetSchema).readonly(),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const relativeToRoot = (rootDir: string, path: string): string => {
|
|
72
|
+
const normalized = relative(rootDir, path).replaceAll('\\', '/');
|
|
73
|
+
return normalized.length === 0 || normalized.startsWith('..')
|
|
74
|
+
? path
|
|
75
|
+
: normalized;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const workspacePatternsFromManifest = (
|
|
79
|
+
manifest: Readonly<Record<string, unknown>>
|
|
80
|
+
): readonly string[] => {
|
|
81
|
+
const { workspaces } = manifest;
|
|
82
|
+
if (Array.isArray(workspaces)) {
|
|
83
|
+
return workspaces.filter(
|
|
84
|
+
(pattern): pattern is string => typeof pattern === 'string'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const packages = isPlainObject(workspaces)
|
|
89
|
+
? workspaces['packages']
|
|
90
|
+
: undefined;
|
|
91
|
+
return Array.isArray(packages)
|
|
92
|
+
? packages.filter(
|
|
93
|
+
(pattern): pattern is string => typeof pattern === 'string'
|
|
94
|
+
)
|
|
95
|
+
: [];
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const readWorkspaceManifest = (
|
|
99
|
+
packageJsonPath: string
|
|
100
|
+
): Result<Readonly<Record<string, unknown>>, ValidationError> => {
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
103
|
+
return isPlainObject(parsed)
|
|
104
|
+
? Result.ok(parsed)
|
|
105
|
+
: Result.err(
|
|
106
|
+
new ValidationError(
|
|
107
|
+
`adapter.check root package.json must contain a JSON object: "${packageJsonPath}"`
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
return Result.err(
|
|
112
|
+
new ValidationError(
|
|
113
|
+
`adapter.check could not read root package.json: "${packageJsonPath}"`,
|
|
114
|
+
error instanceof Error ? { cause: error } : undefined
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const validateAdapterCheckRoot = (
|
|
121
|
+
rootDir: string
|
|
122
|
+
): Result<void, ValidationError> => {
|
|
123
|
+
if (!existsSync(rootDir)) {
|
|
124
|
+
return Result.err(
|
|
125
|
+
new ValidationError(`adapter.check rootDir does not exist: "${rootDir}"`)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!statSync(rootDir).isDirectory()) {
|
|
130
|
+
return Result.err(
|
|
131
|
+
new ValidationError(
|
|
132
|
+
`adapter.check rootDir must be a directory: "${rootDir}"`
|
|
133
|
+
)
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const packageJsonPath = join(rootDir, 'package.json');
|
|
138
|
+
if (!existsSync(packageJsonPath)) {
|
|
139
|
+
return Result.err(
|
|
140
|
+
new ValidationError(
|
|
141
|
+
`adapter.check rootDir must contain a package.json workspace manifest: "${packageJsonPath}"`
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const manifest = readWorkspaceManifest(packageJsonPath);
|
|
147
|
+
if (manifest.isErr()) {
|
|
148
|
+
return manifest;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (workspacePatternsFromManifest(manifest.value).length === 0) {
|
|
152
|
+
return Result.err(
|
|
153
|
+
new ValidationError(
|
|
154
|
+
`adapter.check root package.json must declare workspace packages: "${packageJsonPath}"`
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return Result.ok();
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const formatAdapterCheckReport = (
|
|
163
|
+
report: AdapterCheckReport,
|
|
164
|
+
rootDir: string
|
|
165
|
+
): string => {
|
|
166
|
+
const passed = report.diagnostics.length === 0;
|
|
167
|
+
const lines = [
|
|
168
|
+
'## Adapter Check Report',
|
|
169
|
+
'',
|
|
170
|
+
`Result: ${passed ? 'PASS' : 'FAIL'}`,
|
|
171
|
+
`Targets: ${report.targets.length}`,
|
|
172
|
+
`Adapters: ${report.subjects.length}`,
|
|
173
|
+
`Diagnostics: ${report.diagnostics.length}`,
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
if (report.targets.length > 0) {
|
|
177
|
+
lines.push('', '### Targets');
|
|
178
|
+
for (const target of report.targets) {
|
|
179
|
+
lines.push(
|
|
180
|
+
`- ${target.key} (${target.placements.join(', ')}) from ${relativeToRoot(rootDir, target.packageJsonPath)}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (report.subjects.length > 0) {
|
|
186
|
+
lines.push('', '### Adapters');
|
|
187
|
+
for (const subject of report.subjects) {
|
|
188
|
+
const conformance =
|
|
189
|
+
subject.conformanceTestPaths.length === 0
|
|
190
|
+
? 'no conformance tests'
|
|
191
|
+
: `${subject.conformanceTestPaths.length} conformance test(s)`;
|
|
192
|
+
lines.push(
|
|
193
|
+
`- ${subject.packageName} -> ${subject.targetKey} (${subject.placement}, ${conformance})`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (report.diagnostics.length > 0) {
|
|
199
|
+
lines.push('', '### Diagnostics');
|
|
200
|
+
for (const diagnostic of report.diagnostics) {
|
|
201
|
+
lines.push(
|
|
202
|
+
`- ${diagnostic.severity.toUpperCase()} ${diagnostic.code} ${relativeToRoot(rootDir, diagnostic.packageJsonPath)}: ${diagnostic.message}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return lines.join('\n');
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const adapterCheckTrail = trail('adapter.check', {
|
|
211
|
+
description: 'Check adapter authoring readiness',
|
|
212
|
+
examples: [
|
|
213
|
+
{
|
|
214
|
+
input: {},
|
|
215
|
+
name: 'Check adapters in the current workspace',
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
implementation: (input, ctx) => {
|
|
219
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
220
|
+
if (rootDirResult.isErr()) {
|
|
221
|
+
return rootDirResult;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const rootDir = rootDirResult.value;
|
|
225
|
+
const validRoot = validateAdapterCheckRoot(rootDir);
|
|
226
|
+
if (validRoot.isErr()) {
|
|
227
|
+
return validRoot;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const report = checkAdapters(rootDir);
|
|
231
|
+
|
|
232
|
+
return Result.ok({
|
|
233
|
+
diagnostics: [...report.diagnostics],
|
|
234
|
+
formatted: formatAdapterCheckReport(report, rootDir),
|
|
235
|
+
passed: report.diagnostics.length === 0,
|
|
236
|
+
subjects: [...report.subjects],
|
|
237
|
+
targets: [...report.targets],
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
input: adapterCheckInputSchema,
|
|
241
|
+
intent: 'read',
|
|
242
|
+
output: adapterCheckOutputSchema,
|
|
243
|
+
permit: 'public',
|
|
244
|
+
});
|