@ontrails/trails 1.0.0-beta.4 → 1.0.0-beta.41

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.
Files changed (165) hide show
  1. package/CHANGELOG.md +1104 -4
  2. package/README.md +27 -0
  3. package/package.json +31 -7
  4. package/src/app.ts +147 -3
  5. package/src/cli.ts +345 -11
  6. package/src/completions.ts +240 -0
  7. package/src/lifecycle-source-io.ts +33 -0
  8. package/src/load-app-mirror.ts +202 -0
  9. package/src/local-state-io.ts +173 -0
  10. package/src/mcp-app.ts +42 -0
  11. package/src/mcp-options.ts +91 -0
  12. package/src/mcp.ts +8 -0
  13. package/src/project-writes.ts +377 -0
  14. package/src/regrade/config.ts +152 -0
  15. package/src/regrade/history.ts +430 -0
  16. package/src/regrade/live-api-preserve.ts +8 -0
  17. package/src/regrade/plan-artifact.ts +285 -0
  18. package/src/release/bindings.ts +39 -0
  19. package/src/release/check.ts +844 -0
  20. package/src/release/config.ts +63 -0
  21. package/src/release/contract-facts.ts +425 -0
  22. package/src/release/index.ts +142 -0
  23. package/src/release/lock-roundtrip-smoke.ts +230 -0
  24. package/src/release/native-bun-publish.ts +651 -0
  25. package/src/release/native-bun-registry.ts +765 -0
  26. package/src/release/notes-cli.ts +171 -0
  27. package/src/release/notes.ts +390 -0
  28. package/src/release/pack-coherence.ts +455 -0
  29. package/src/release/packed-artifacts-smoke.ts +236 -0
  30. package/src/release/policy.ts +1687 -0
  31. package/src/release/semver.ts +104 -0
  32. package/src/release/smoke.ts +56 -0
  33. package/src/release/wayfinder-dogfood-smoke.ts +760 -0
  34. package/src/retired-topo-command.ts +36 -0
  35. package/src/run-adapter-check.ts +76 -0
  36. package/src/run-collision.ts +126 -0
  37. package/src/run-completions-install.ts +179 -0
  38. package/src/run-example.ts +149 -0
  39. package/src/run-examples.ts +148 -0
  40. package/src/run-quiet.ts +75 -0
  41. package/src/run-release-check.ts +74 -0
  42. package/src/run-schema.ts +74 -0
  43. package/src/run-trace.ts +273 -0
  44. package/src/run-warden.ts +39 -0
  45. package/src/run-watch.ts +432 -0
  46. package/src/run-wayfind-outline.ts +170 -0
  47. package/src/scaffold-version-sync.ts +183 -0
  48. package/src/scaffold-versions.generated.ts +12 -0
  49. package/src/trails/adapter-check.ts +244 -0
  50. package/src/trails/add-surface.ts +99 -45
  51. package/src/trails/add-trail.ts +84 -37
  52. package/src/trails/add-verify.ts +100 -30
  53. package/src/trails/compile.ts +58 -0
  54. package/src/trails/completions-complete.ts +165 -0
  55. package/src/trails/completions.ts +47 -0
  56. package/src/trails/create-adapter.ts +785 -0
  57. package/src/trails/create-scaffold.ts +401 -106
  58. package/src/trails/create-versions.ts +62 -0
  59. package/src/trails/create.ts +186 -72
  60. package/src/trails/deprecate.ts +59 -0
  61. package/src/trails/dev-clean.ts +82 -0
  62. package/src/trails/dev-reset.ts +50 -0
  63. package/src/trails/dev-stats.ts +72 -0
  64. package/src/trails/dev-support.ts +360 -0
  65. package/src/trails/doctor.ts +77 -0
  66. package/src/trails/draft-promote.ts +949 -0
  67. package/src/trails/guide.ts +70 -68
  68. package/src/trails/load-app.ts +1123 -15
  69. package/src/trails/operator-context.ts +66 -0
  70. package/src/trails/project.ts +17 -3
  71. package/src/trails/regrade.ts +3091 -0
  72. package/src/trails/release-check.ts +105 -0
  73. package/src/trails/release-smoke.ts +49 -0
  74. package/src/trails/revise.ts +53 -0
  75. package/src/trails/root-dir.ts +21 -0
  76. package/src/trails/run-example.ts +475 -0
  77. package/src/trails/run-examples.ts +129 -0
  78. package/src/trails/run.ts +434 -0
  79. package/src/trails/scaffold-json.ts +58 -0
  80. package/src/trails/survey.ts +877 -214
  81. package/src/trails/topo-activation.ts +14 -0
  82. package/src/trails/topo-constants.ts +2 -0
  83. package/src/trails/topo-history.ts +47 -0
  84. package/src/trails/topo-output-schemas.ts +259 -0
  85. package/src/trails/topo-pin.ts +38 -0
  86. package/src/trails/topo-read-support.ts +368 -0
  87. package/src/trails/topo-reports.ts +809 -0
  88. package/src/trails/topo-store-support.ts +325 -0
  89. package/src/trails/topo-support.ts +220 -0
  90. package/src/trails/topo-unpin.ts +61 -0
  91. package/src/trails/topo.ts +92 -0
  92. package/src/trails/validate.ts +27 -0
  93. package/src/trails/version-lifecycle-support.ts +936 -0
  94. package/src/trails/warden-guide.ts +134 -0
  95. package/src/trails/warden.ts +198 -58
  96. package/src/trails/wayfind-outline.ts +876 -0
  97. package/src/trails/wayfind.ts +1053 -0
  98. package/src/versions.ts +31 -0
  99. package/.turbo/turbo-build.log +0 -1
  100. package/.turbo/turbo-lint.log +0 -3
  101. package/.turbo/turbo-typecheck.log +0 -1
  102. package/__tests__/examples.test.ts +0 -6
  103. package/dist/bin/trails.d.ts +0 -3
  104. package/dist/bin/trails.d.ts.map +0 -1
  105. package/dist/bin/trails.js +0 -4
  106. package/dist/bin/trails.js.map +0 -1
  107. package/dist/src/app.d.ts +0 -2
  108. package/dist/src/app.d.ts.map +0 -1
  109. package/dist/src/app.js +0 -11
  110. package/dist/src/app.js.map +0 -1
  111. package/dist/src/clack.d.ts +0 -9
  112. package/dist/src/clack.d.ts.map +0 -1
  113. package/dist/src/clack.js +0 -84
  114. package/dist/src/clack.js.map +0 -1
  115. package/dist/src/cli.d.ts +0 -2
  116. package/dist/src/cli.d.ts.map +0 -1
  117. package/dist/src/cli.js +0 -13
  118. package/dist/src/cli.js.map +0 -1
  119. package/dist/src/trails/add-surface.d.ts +0 -13
  120. package/dist/src/trails/add-surface.d.ts.map +0 -1
  121. package/dist/src/trails/add-surface.js +0 -88
  122. package/dist/src/trails/add-surface.js.map +0 -1
  123. package/dist/src/trails/add-trail.d.ts +0 -10
  124. package/dist/src/trails/add-trail.d.ts.map +0 -1
  125. package/dist/src/trails/add-trail.js +0 -77
  126. package/dist/src/trails/add-trail.js.map +0 -1
  127. package/dist/src/trails/add-verify.d.ts +0 -10
  128. package/dist/src/trails/add-verify.d.ts.map +0 -1
  129. package/dist/src/trails/add-verify.js +0 -67
  130. package/dist/src/trails/add-verify.js.map +0 -1
  131. package/dist/src/trails/create-scaffold.d.ts +0 -15
  132. package/dist/src/trails/create-scaffold.d.ts.map +0 -1
  133. package/dist/src/trails/create-scaffold.js +0 -288
  134. package/dist/src/trails/create-scaffold.js.map +0 -1
  135. package/dist/src/trails/create.d.ts +0 -22
  136. package/dist/src/trails/create.d.ts.map +0 -1
  137. package/dist/src/trails/create.js +0 -121
  138. package/dist/src/trails/create.js.map +0 -1
  139. package/dist/src/trails/guide.d.ts +0 -11
  140. package/dist/src/trails/guide.d.ts.map +0 -1
  141. package/dist/src/trails/guide.js +0 -80
  142. package/dist/src/trails/guide.js.map +0 -1
  143. package/dist/src/trails/load-app.d.ts +0 -4
  144. package/dist/src/trails/load-app.d.ts.map +0 -1
  145. package/dist/src/trails/load-app.js +0 -24
  146. package/dist/src/trails/load-app.js.map +0 -1
  147. package/dist/src/trails/project.d.ts +0 -8
  148. package/dist/src/trails/project.d.ts.map +0 -1
  149. package/dist/src/trails/project.js +0 -43
  150. package/dist/src/trails/project.js.map +0 -1
  151. package/dist/src/trails/survey.d.ts +0 -31
  152. package/dist/src/trails/survey.d.ts.map +0 -1
  153. package/dist/src/trails/survey.js +0 -221
  154. package/dist/src/trails/survey.js.map +0 -1
  155. package/dist/src/trails/warden.d.ts +0 -19
  156. package/dist/src/trails/warden.d.ts.map +0 -1
  157. package/dist/src/trails/warden.js +0 -88
  158. package/dist/src/trails/warden.js.map +0 -1
  159. package/dist/tsconfig.tsbuildinfo +0 -1
  160. package/src/__tests__/create.test.ts +0 -349
  161. package/src/__tests__/guide.test.ts +0 -91
  162. package/src/__tests__/load-app.test.ts +0 -15
  163. package/src/__tests__/survey.test.ts +0 -159
  164. package/src/__tests__/warden.test.ts +0 -74
  165. package/tsconfig.json +0 -9
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Saved Regrade plan artifact shape plus the slug, path, and hash helpers
3
+ * shared by the `regrade` trails and the consolidated Regrade history module.
4
+ */
5
+
6
+ import { isPlainObject } from '@ontrails/core';
7
+ import { vocabularyRegradePlanSchema } from '@ontrails/regrade';
8
+ import type {
9
+ RegradeReport,
10
+ RegradeReportEntry,
11
+ VocabularyRegradePlan,
12
+ } from '@ontrails/regrade';
13
+ import { createHash } from 'node:crypto';
14
+ import { join, normalize, relative } from 'node:path';
15
+ import { z } from 'zod';
16
+
17
+ export const REGRADE_PLAN_SCHEMA_VERSION = 1;
18
+
19
+ const regradePlanProvenanceValueSchema = z.enum(['authored', 'derived']);
20
+
21
+ const classRegradePlanScopeSchema = z
22
+ .object({
23
+ exclude: z
24
+ .array(z.string())
25
+ .optional()
26
+ .describe('Root-relative path globs excluded from the class run'),
27
+ extensions: z
28
+ .array(z.string())
29
+ .optional()
30
+ .describe('Source file extensions scanned by the class run'),
31
+ include: z
32
+ .array(z.string())
33
+ .optional()
34
+ .describe('Root-relative path globs collected during the class run'),
35
+ })
36
+ .strict();
37
+
38
+ /**
39
+ * A saved class-mode Regrade plan: which classes run, over what scope, and
40
+ * why. The parallel payload to {@link vocabularyRegradePlanSchema} — the
41
+ * `kind` discriminant keeps existing vocabulary plan artifacts
42
+ * byte-compatible.
43
+ */
44
+ const classRegradePlanSchema = z.object({
45
+ classIds: z
46
+ .array(z.string().min(1))
47
+ .min(1)
48
+ .describe('Regrade class ids this plan runs'),
49
+ id: z.string().min(1).describe('Stable Regrade plan identifier'),
50
+ intent: z
51
+ .string()
52
+ .optional()
53
+ .describe('Human-authored migration intent for the class run'),
54
+ kind: z.literal('class').describe('Regrade plan kind'),
55
+ name: z
56
+ .string()
57
+ .min(1)
58
+ .optional()
59
+ .describe(
60
+ 'Authored transition name; keys the saved plan and consolidated history filenames'
61
+ ),
62
+ scope: classRegradePlanScopeSchema
63
+ .optional()
64
+ .describe('Collection scope for the class run'),
65
+ });
66
+
67
+ export type ClassRegradePlan = z.output<typeof classRegradePlanSchema>;
68
+
69
+ const regradePlanBodySchema = z.discriminatedUnion('kind', [
70
+ vocabularyRegradePlanSchema,
71
+ classRegradePlanSchema,
72
+ ]);
73
+
74
+ export type RegradePlanBody = VocabularyRegradePlan | ClassRegradePlan;
75
+
76
+ const regradeExpansionCandidateSchema = z.union([
77
+ z.object({
78
+ evidence: z
79
+ .array(
80
+ z.object({
81
+ column: z.number().optional(),
82
+ detail: z.string().optional(),
83
+ line: z.number().optional(),
84
+ path: z.string(),
85
+ })
86
+ )
87
+ .default([]),
88
+ kind: z.enum(['file-rename', 'form', 'namespace', 'preserve']),
89
+ reason: z.string().optional(),
90
+ status: z.enum(['pending', 'rejected']).default('pending'),
91
+ suggestedClassification: z.string(),
92
+ value: z.string(),
93
+ }),
94
+ z
95
+ .object({
96
+ detail: z.string().optional(),
97
+ path: z.string(),
98
+ status: z.enum(['pending', 'rejected']).default('pending'),
99
+ })
100
+ .transform((candidate) => ({
101
+ evidence: [
102
+ {
103
+ ...(candidate.detail === undefined
104
+ ? {}
105
+ : { detail: candidate.detail }),
106
+ path: candidate.path,
107
+ },
108
+ ],
109
+ kind: 'file-rename' as const,
110
+ ...(candidate.detail === undefined ? {} : { reason: candidate.detail }),
111
+ status: candidate.status,
112
+ suggestedClassification: 'legacy-path-candidate',
113
+ value: candidate.path,
114
+ })),
115
+ ]);
116
+
117
+ export const regradePlanArtifactSchema = z
118
+ .object({
119
+ expansion: z
120
+ .object({
121
+ candidates: z.array(regradeExpansionCandidateSchema).default([]),
122
+ })
123
+ .optional(),
124
+ kind: z.literal('regrade-plan'),
125
+ path: z.string(),
126
+ plan: regradePlanBodySchema,
127
+ provenance: z.object({
128
+ fields: z.record(z.string(), regradePlanProvenanceValueSchema),
129
+ }),
130
+ schemaVersion: z.literal(REGRADE_PLAN_SCHEMA_VERSION),
131
+ sourceHash: z.string(),
132
+ transitionId: z
133
+ .string()
134
+ .min(1)
135
+ .optional()
136
+ .describe(
137
+ 'Stable transition identity this plan re-runs; preserves the consolidated history spine'
138
+ ),
139
+ })
140
+ .strict();
141
+
142
+ export interface RegradePlanExpansion {
143
+ readonly candidates: readonly {
144
+ readonly evidence: readonly {
145
+ readonly column?: number | undefined;
146
+ readonly detail?: string | undefined;
147
+ readonly line?: number | undefined;
148
+ readonly path: string;
149
+ }[];
150
+ readonly kind: 'file-rename' | 'form' | 'namespace' | 'preserve';
151
+ readonly reason?: string | undefined;
152
+ readonly status: 'pending' | 'rejected';
153
+ readonly suggestedClassification: string;
154
+ readonly value: string;
155
+ }[];
156
+ }
157
+
158
+ export interface RegradePlanArtifact {
159
+ readonly expansion?: RegradePlanExpansion | undefined;
160
+ readonly kind: 'regrade-plan';
161
+ readonly path: string;
162
+ readonly plan: RegradePlanBody;
163
+ readonly provenance: {
164
+ readonly fields: Readonly<Record<string, 'authored' | 'derived'>>;
165
+ };
166
+ readonly schemaVersion: typeof REGRADE_PLAN_SCHEMA_VERSION;
167
+ readonly sourceHash: string;
168
+ readonly transitionId?: string | undefined;
169
+ }
170
+
171
+ /** A plan artifact narrowed to a vocabulary plan body. */
172
+ export type VocabularyRegradePlanArtifact = RegradePlanArtifact & {
173
+ readonly plan: VocabularyRegradePlan;
174
+ };
175
+
176
+ const regradeSlugText = (text: string): string =>
177
+ text
178
+ .toLowerCase()
179
+ .replaceAll(/[^a-z0-9]+/g, '-')
180
+ .replaceAll(/^-|-$/g, '');
181
+
182
+ const regradePlanSlug = (plan: Pick<VocabularyRegradePlan, 'from' | 'to'>) =>
183
+ regradeSlugText(`${plan.from}-to-${plan.to}`);
184
+
185
+ export const regradePlanSlugForBody = (plan: RegradePlanBody): string =>
186
+ plan.kind === 'class'
187
+ ? regradeSlugText(plan.name ?? plan.classIds.join('-'))
188
+ : regradePlanSlug(plan);
189
+
190
+ const normalizeRelativePath = (path: string): string =>
191
+ normalize(path).replaceAll('\\', '/');
192
+
193
+ export const rootRelativePath = (
194
+ rootDir: string,
195
+ absolutePath: string
196
+ ): string => normalizeRelativePath(relative(rootDir, absolutePath));
197
+
198
+ export const regradePlanDirectory = (rootDir: string): string =>
199
+ join(rootDir, '.trails', 'regrade');
200
+
201
+ export const regradePlanPathForPlan = (
202
+ rootDir: string,
203
+ plan: RegradePlanBody
204
+ ): string =>
205
+ join(regradePlanDirectory(rootDir), `${regradePlanSlugForBody(plan)}.json`);
206
+
207
+ const sourceHashEntryFacts = (
208
+ entries: readonly RegradeReportEntry[]
209
+ ): readonly Pick<
210
+ RegradeReportEntry,
211
+ 'classId' | 'notes' | 'outcome' | 'path' | 'reason' | 'reviewDetails'
212
+ >[] =>
213
+ entries
214
+ .filter(
215
+ (entry) => entry.outcome === 'rewrite' || entry.outcome === 'needs-review'
216
+ )
217
+ .map(({ classId, notes, outcome, path, reason, reviewDetails }) => ({
218
+ ...(classId === undefined ? {} : { classId }),
219
+ ...(notes === undefined ? {} : { notes }),
220
+ outcome,
221
+ path,
222
+ ...(reason === undefined ? {} : { reason }),
223
+ ...(reviewDetails === undefined ? {} : { reviewDetails }),
224
+ }));
225
+
226
+ const canonicalizeJsonValue = (value: unknown): unknown => {
227
+ if (Array.isArray(value)) {
228
+ return value.map((entry) => canonicalizeJsonValue(entry));
229
+ }
230
+ if (isPlainObject(value)) {
231
+ return Object.fromEntries(
232
+ Object.keys(value)
233
+ .toSorted()
234
+ .map((key) => [key, canonicalizeJsonValue(value[key])])
235
+ );
236
+ }
237
+ return value;
238
+ };
239
+
240
+ /**
241
+ * JSON.stringify with recursively sorted object keys so structurally equal
242
+ * values serialize identically regardless of key insertion order. Arrays keep
243
+ * their authored order.
244
+ */
245
+ export const canonicalJsonStringify = (value: unknown): string =>
246
+ JSON.stringify(canonicalizeJsonValue(value));
247
+
248
+ const regradeSourceHashFacts = (report: RegradeReport): unknown => ({
249
+ entries: sourceHashEntryFacts(report.entries),
250
+ ledger: report.run?.ledger,
251
+ selectedClassIds: report.selectedClassIds,
252
+ });
253
+
254
+ const hashSerializedSourceFacts = (serialized: string): string =>
255
+ createHash('sha256').update(serialized).digest('hex');
256
+
257
+ export const regradeSourceHash = (report: RegradeReport): string =>
258
+ hashSerializedSourceFacts(
259
+ canonicalJsonStringify(regradeSourceHashFacts(report))
260
+ );
261
+
262
+ export const legacyRegradeSourceHash = (report: RegradeReport): string =>
263
+ hashSerializedSourceFacts(JSON.stringify(regradeSourceHashFacts(report)));
264
+
265
+ /** Match source evidence written before canonical JSON hashing. */
266
+ export const regradeSourceHashMatches = (
267
+ stampedHash: string,
268
+ report: RegradeReport
269
+ ): boolean =>
270
+ stampedHash === regradeSourceHash(report) ||
271
+ stampedHash === legacyRegradeSourceHash(report);
272
+
273
+ export const regradeSourceHashes = (
274
+ report: RegradeReport
275
+ ): readonly string[] => [
276
+ ...new Set([regradeSourceHash(report), legacyRegradeSourceHash(report)]),
277
+ ];
278
+
279
+ /**
280
+ * Canonical content hash of a resolved Regrade plan body — the authored
281
+ * migration intent. Stable across key insertion order; changes on any edit to
282
+ * the plan contents.
283
+ */
284
+ export const regradePlanContentHash = (plan: RegradePlanBody): string =>
285
+ createHash('sha256').update(canonicalJsonStringify(plan)).digest('hex');
@@ -0,0 +1,39 @@
1
+ export const releaseBindingKindValues = ['native', 'adapter'] as const;
2
+ export type ReleaseBindingKind = (typeof releaseBindingKindValues)[number];
3
+
4
+ export const releaseBindingPlacementValues = [
5
+ 'same-package',
6
+ 'subpath',
7
+ 'extracted',
8
+ ] as const;
9
+ export type ReleaseBindingPlacement =
10
+ (typeof releaseBindingPlacementValues)[number];
11
+
12
+ export const releaseBindingCapabilityValues = [
13
+ 'pack-check',
14
+ 'publish',
15
+ 'registry-preflight',
16
+ ] as const;
17
+ export type ReleaseBindingCapability =
18
+ (typeof releaseBindingCapabilityValues)[number];
19
+
20
+ export interface ReleaseBindingDescriptor {
21
+ readonly boundary: 'foreign' | 'trails-owned';
22
+ readonly capabilities: readonly ReleaseBindingCapability[];
23
+ readonly description: string;
24
+ readonly id: string;
25
+ readonly kind: ReleaseBindingKind;
26
+ readonly placement: ReleaseBindingPlacement;
27
+ readonly runtime: string;
28
+ }
29
+
30
+ export const nativeBunReleaseBinding = {
31
+ boundary: 'trails-owned',
32
+ capabilities: ['pack-check', 'publish', 'registry-preflight'],
33
+ description:
34
+ 'Built-in Bun release binding for Trails-owned package pack checks, npm registry preflight, and lockstep package publication.',
35
+ id: 'release.binding.native-bun',
36
+ kind: 'native',
37
+ placement: 'same-package',
38
+ runtime: 'bun',
39
+ } satisfies ReleaseBindingDescriptor;