@ontrails/trails 1.0.0-beta.3 → 1.0.0-beta.30

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 (157) hide show
  1. package/CHANGELOG.md +886 -0
  2. package/README.md +27 -0
  3. package/package.json +30 -7
  4. package/src/app.ts +125 -2
  5. package/src/cli.ts +344 -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 +40 -0
  11. package/src/mcp-options.ts +76 -0
  12. package/src/mcp.ts +8 -0
  13. package/src/project-writes.ts +377 -0
  14. package/src/release/bindings.ts +39 -0
  15. package/src/release/check.ts +844 -0
  16. package/src/release/config.ts +63 -0
  17. package/src/release/contract-facts.ts +425 -0
  18. package/src/release/index.ts +125 -0
  19. package/src/release/native-bun-publish.ts +651 -0
  20. package/src/release/native-bun-registry.ts +754 -0
  21. package/src/release/pack-coherence.ts +457 -0
  22. package/src/release/packed-artifacts-smoke.ts +236 -0
  23. package/src/release/policy.ts +1684 -0
  24. package/src/release/semver.ts +104 -0
  25. package/src/release/smoke.ts +46 -0
  26. package/src/release/wayfinder-dogfood-smoke.ts +760 -0
  27. package/src/retired-topo-command.ts +36 -0
  28. package/src/run-adapter-check.ts +76 -0
  29. package/src/run-collision.ts +126 -0
  30. package/src/run-completions-install.ts +179 -0
  31. package/src/run-example.ts +149 -0
  32. package/src/run-examples.ts +148 -0
  33. package/src/run-quiet.ts +75 -0
  34. package/src/run-release-check.ts +74 -0
  35. package/src/run-schema.ts +41 -0
  36. package/src/run-trace.ts +273 -0
  37. package/src/run-warden.ts +39 -0
  38. package/src/run-watch.ts +432 -0
  39. package/src/run-wayfind-outline.ts +166 -0
  40. package/src/scaffold-version-sync.ts +183 -0
  41. package/src/scaffold-versions.generated.ts +12 -0
  42. package/src/trails/adapter-check.ts +244 -0
  43. package/src/trails/add-surface.ts +94 -40
  44. package/src/trails/add-trail.ts +79 -41
  45. package/src/trails/add-verify.ts +95 -25
  46. package/src/trails/compile.ts +59 -0
  47. package/src/trails/completions-complete.ts +165 -0
  48. package/src/trails/completions.ts +47 -0
  49. package/src/trails/create-adapter.ts +1084 -0
  50. package/src/trails/create-scaffold.ts +399 -104
  51. package/src/trails/create-versions.ts +62 -0
  52. package/src/trails/create.ts +186 -72
  53. package/src/trails/deprecate.ts +59 -0
  54. package/src/trails/dev-clean.ts +82 -0
  55. package/src/trails/dev-reset.ts +50 -0
  56. package/src/trails/dev-stats.ts +72 -0
  57. package/src/trails/dev-support.ts +360 -0
  58. package/src/trails/doctor.ts +77 -0
  59. package/src/trails/draft-promote.ts +949 -0
  60. package/src/trails/guide.ts +71 -69
  61. package/src/trails/load-app.ts +1193 -16
  62. package/src/trails/operator-context.ts +66 -0
  63. package/src/trails/project.ts +17 -3
  64. package/src/trails/regrade.ts +72 -0
  65. package/src/trails/release-check.ts +105 -0
  66. package/src/trails/release-smoke.ts +48 -0
  67. package/src/trails/revise.ts +53 -0
  68. package/src/trails/root-dir.ts +21 -0
  69. package/src/trails/run-example.ts +475 -0
  70. package/src/trails/run-examples.ts +129 -0
  71. package/src/trails/run.ts +434 -0
  72. package/src/trails/scaffold-json.ts +58 -0
  73. package/src/trails/survey.ts +896 -227
  74. package/src/trails/topo-activation.ts +385 -0
  75. package/src/trails/topo-constants.ts +2 -0
  76. package/src/trails/topo-history.ts +47 -0
  77. package/src/trails/topo-output-schemas.ts +259 -0
  78. package/src/trails/topo-pin.ts +38 -0
  79. package/src/trails/topo-read-support.ts +363 -0
  80. package/src/trails/topo-reports.ts +809 -0
  81. package/src/trails/topo-store-support.ts +307 -0
  82. package/src/trails/topo-support.ts +219 -0
  83. package/src/trails/topo-unpin.ts +61 -0
  84. package/src/trails/topo.ts +92 -0
  85. package/src/trails/validate.ts +27 -0
  86. package/src/trails/version-lifecycle-support.ts +935 -0
  87. package/src/trails/warden-guide.ts +129 -0
  88. package/src/trails/warden.ts +183 -58
  89. package/src/trails/wayfind.ts +1001 -0
  90. package/src/versions.ts +31 -0
  91. package/.turbo/turbo-build.log +0 -1
  92. package/.turbo/turbo-lint.log +0 -3
  93. package/.turbo/turbo-typecheck.log +0 -1
  94. package/__tests__/examples.test.ts +0 -6
  95. package/dist/bin/trails.d.ts +0 -3
  96. package/dist/bin/trails.d.ts.map +0 -1
  97. package/dist/bin/trails.js +0 -4
  98. package/dist/bin/trails.js.map +0 -1
  99. package/dist/src/app.d.ts +0 -2
  100. package/dist/src/app.d.ts.map +0 -1
  101. package/dist/src/app.js +0 -11
  102. package/dist/src/app.js.map +0 -1
  103. package/dist/src/clack.d.ts +0 -9
  104. package/dist/src/clack.d.ts.map +0 -1
  105. package/dist/src/clack.js +0 -84
  106. package/dist/src/clack.js.map +0 -1
  107. package/dist/src/cli.d.ts +0 -2
  108. package/dist/src/cli.d.ts.map +0 -1
  109. package/dist/src/cli.js +0 -13
  110. package/dist/src/cli.js.map +0 -1
  111. package/dist/src/trails/add-surface.d.ts +0 -13
  112. package/dist/src/trails/add-surface.d.ts.map +0 -1
  113. package/dist/src/trails/add-surface.js +0 -88
  114. package/dist/src/trails/add-surface.js.map +0 -1
  115. package/dist/src/trails/add-trail.d.ts +0 -11
  116. package/dist/src/trails/add-trail.d.ts.map +0 -1
  117. package/dist/src/trails/add-trail.js +0 -85
  118. package/dist/src/trails/add-trail.js.map +0 -1
  119. package/dist/src/trails/add-verify.d.ts +0 -10
  120. package/dist/src/trails/add-verify.d.ts.map +0 -1
  121. package/dist/src/trails/add-verify.js +0 -67
  122. package/dist/src/trails/add-verify.js.map +0 -1
  123. package/dist/src/trails/create-scaffold.d.ts +0 -15
  124. package/dist/src/trails/create-scaffold.d.ts.map +0 -1
  125. package/dist/src/trails/create-scaffold.js +0 -288
  126. package/dist/src/trails/create-scaffold.js.map +0 -1
  127. package/dist/src/trails/create.d.ts +0 -22
  128. package/dist/src/trails/create.d.ts.map +0 -1
  129. package/dist/src/trails/create.js +0 -121
  130. package/dist/src/trails/create.js.map +0 -1
  131. package/dist/src/trails/guide.d.ts +0 -11
  132. package/dist/src/trails/guide.d.ts.map +0 -1
  133. package/dist/src/trails/guide.js +0 -80
  134. package/dist/src/trails/guide.js.map +0 -1
  135. package/dist/src/trails/load-app.d.ts +0 -4
  136. package/dist/src/trails/load-app.d.ts.map +0 -1
  137. package/dist/src/trails/load-app.js +0 -24
  138. package/dist/src/trails/load-app.js.map +0 -1
  139. package/dist/src/trails/project.d.ts +0 -8
  140. package/dist/src/trails/project.d.ts.map +0 -1
  141. package/dist/src/trails/project.js +0 -43
  142. package/dist/src/trails/project.js.map +0 -1
  143. package/dist/src/trails/survey.d.ts +0 -33
  144. package/dist/src/trails/survey.d.ts.map +0 -1
  145. package/dist/src/trails/survey.js +0 -225
  146. package/dist/src/trails/survey.js.map +0 -1
  147. package/dist/src/trails/warden.d.ts +0 -19
  148. package/dist/src/trails/warden.d.ts.map +0 -1
  149. package/dist/src/trails/warden.js +0 -88
  150. package/dist/src/trails/warden.js.map +0 -1
  151. package/dist/tsconfig.tsbuildinfo +0 -1
  152. package/src/__tests__/create.test.ts +0 -349
  153. package/src/__tests__/guide.test.ts +0 -91
  154. package/src/__tests__/load-app.test.ts +0 -15
  155. package/src/__tests__/survey.test.ts +0 -161
  156. package/src/__tests__/warden.test.ts +0 -74
  157. package/tsconfig.json +0 -9
@@ -0,0 +1,66 @@
1
+ import type { Result } from '@ontrails/core';
2
+
3
+ import { tryLoadFreshAppLease } from './load-app.js';
4
+ import type { FreshAppLease } from './load-app.js';
5
+ import { resolveTrailRootDir } from './root-dir.js';
6
+
7
+ interface RootDirInput {
8
+ readonly rootDir?: string | undefined;
9
+ }
10
+
11
+ interface FreshAppInput extends RootDirInput {
12
+ readonly module?: string | undefined;
13
+ }
14
+
15
+ interface RootDirContext {
16
+ readonly cwd?: string | undefined;
17
+ }
18
+
19
+ interface FreshAppContext {
20
+ readonly lease: FreshAppLease;
21
+ readonly rootDir: string;
22
+ }
23
+
24
+ export const withOperatorRootDir = async <T>(
25
+ input: RootDirInput,
26
+ ctx: RootDirContext,
27
+ consume: (rootDir: string) => Result<T, Error> | Promise<Result<T, Error>>
28
+ ): Promise<Result<T, Error>> => {
29
+ const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
30
+ if (rootDirResult.isErr()) {
31
+ return rootDirResult;
32
+ }
33
+ return await consume(rootDirResult.value);
34
+ };
35
+
36
+ export const withFreshAppLease = async <T>(
37
+ modulePath: string | undefined,
38
+ rootDir: string,
39
+ consume: (
40
+ lease: FreshAppLease
41
+ ) => Result<T, Error> | Promise<Result<T, Error>>
42
+ ): Promise<Result<T, Error>> => {
43
+ const leaseResult = await tryLoadFreshAppLease(modulePath, rootDir);
44
+ if (leaseResult.isErr()) {
45
+ return leaseResult;
46
+ }
47
+ const lease = leaseResult.value;
48
+ try {
49
+ return await consume(lease);
50
+ } finally {
51
+ lease.release();
52
+ }
53
+ };
54
+
55
+ export const withFreshOperatorApp = async <T>(
56
+ input: FreshAppInput,
57
+ ctx: RootDirContext,
58
+ consume: (
59
+ context: FreshAppContext
60
+ ) => Result<T, Error> | Promise<Result<T, Error>>
61
+ ): Promise<Result<T, Error>> =>
62
+ withOperatorRootDir(input, ctx, (rootDir) =>
63
+ withFreshAppLease(input.module, rootDir, (lease) =>
64
+ consume({ lease, rootDir })
65
+ )
66
+ );
@@ -5,10 +5,24 @@
5
5
  import { existsSync } from 'node:fs';
6
6
  import { join } from 'node:path';
7
7
 
8
+ import { isDraftMarkedFile } from '@ontrails/warden';
9
+
8
10
  /** Return all TypeScript entries in a project's src directory. */
9
- const scanSourceEntries = (srcDir: string): string[] => [
10
- ...new Bun.Glob('*.ts').scanSync({ cwd: srcDir }),
11
- ];
11
+ const sourceEntryPriority = (entry: string): number => {
12
+ if (entry === 'app.ts') {
13
+ return 0;
14
+ }
15
+ return isDraftMarkedFile(entry) ? 2 : 1;
16
+ };
17
+
18
+ const scanSourceEntries = (srcDir: string): string[] =>
19
+ [...new Bun.Glob('*.ts').scanSync({ cwd: srcDir })].toSorted((a, b) => {
20
+ const priority = sourceEntryPriority(a) - sourceEntryPriority(b);
21
+ if (priority === 0) {
22
+ return a.localeCompare(b);
23
+ }
24
+ return priority;
25
+ });
12
26
 
13
27
  /** Resolve an entry to an app import if it contains topo(). */
14
28
  const toTopoImport = async (
@@ -0,0 +1,72 @@
1
+ /**
2
+ * `regrade` trail -- Run downstream migration checks and safe rewrites.
3
+ */
4
+
5
+ import { NotFoundError, Result, trail, validateOutput } from '@ontrails/core';
6
+ import type { Result as TrailsResult } from '@ontrails/core';
7
+ import {
8
+ regradeReportOutput,
9
+ runRegrade,
10
+ wardenTermRewriteClasses,
11
+ } from '@ontrails/regrade';
12
+ import type { RegradeReport } from '@ontrails/regrade';
13
+ import { z } from 'zod';
14
+
15
+ import { resolveTrailRootDir } from './root-dir.js';
16
+
17
+ const regradeInputSchema = z.object({
18
+ apply: z
19
+ .boolean()
20
+ .default(false)
21
+ .describe('Write safe rewrites to disk; dry-run report only by default'),
22
+ classIds: z
23
+ .array(z.string())
24
+ .optional()
25
+ .describe('Regrade class ids to run (defaults to all built-in classes)'),
26
+ rootDir: z.string().optional().describe('Workspace root directory'),
27
+ });
28
+
29
+ export const regradeTrail = trail('regrade', {
30
+ blaze: (input, ctx) => {
31
+ const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
32
+ if (rootDirResult.isErr()) {
33
+ return rootDirResult;
34
+ }
35
+
36
+ const reportResult: TrailsResult<RegradeReport | null, Error> = runRegrade({
37
+ apply: input.apply,
38
+ classes: wardenTermRewriteClasses,
39
+ root: rootDirResult.value,
40
+ ...(input.classIds === undefined
41
+ ? {}
42
+ : { selection: { classIds: input.classIds } }),
43
+ });
44
+ if (reportResult.isErr()) {
45
+ return reportResult;
46
+ }
47
+
48
+ const report = reportResult.value;
49
+ if (report === null) {
50
+ return Result.err(
51
+ new NotFoundError(
52
+ `Regrade root "${rootDirResult.value}" could not be read as a directory.`
53
+ )
54
+ );
55
+ }
56
+
57
+ const validated: TrailsResult<
58
+ z.output<typeof regradeReportOutput>,
59
+ Error
60
+ > = validateOutput(regradeReportOutput, report);
61
+ if (validated.isErr()) {
62
+ return validated;
63
+ }
64
+
65
+ return Result.ok(validated.value);
66
+ },
67
+ description: 'Run downstream migration checks and safe rewrites',
68
+ input: regradeInputSchema,
69
+ intent: 'write',
70
+ output: regradeReportOutput,
71
+ permit: 'public',
72
+ });
@@ -0,0 +1,105 @@
1
+ /**
2
+ * `release.check` trail -- Branch-local release rule evaluation.
3
+ */
4
+
5
+ import { Result, trail, ValidationError } from '@ontrails/core';
6
+ import { z } from 'zod';
7
+
8
+ import { runReleaseCheck } from '../release/check.js';
9
+ import { resolveTrailRootDir } from './root-dir.js';
10
+
11
+ const releaseCheckInputSchema = z.object({
12
+ baseRef: z
13
+ .string()
14
+ .optional()
15
+ .describe('Base git ref for changed-file and contract fact comparison'),
16
+ changedFiles: z
17
+ .string()
18
+ .optional()
19
+ .describe('Path to a newline-delimited changed-file list'),
20
+ configPath: z.string().optional().describe('Path to trails.config.ts'),
21
+ releaseNone: z
22
+ .boolean()
23
+ .default(false)
24
+ .describe('Compatibility no-release override'),
25
+ rootDir: z.string().optional().describe('Workspace root directory'),
26
+ });
27
+
28
+ const contractReleaseFactAspectSchema = z.enum([
29
+ 'input',
30
+ 'output',
31
+ 'surfaces',
32
+ 'trail',
33
+ 'visibility',
34
+ ]);
35
+
36
+ const contractReleaseFactSchema = z.object({
37
+ aspect: contractReleaseFactAspectSchema,
38
+ baseHash: z.string().nullable(),
39
+ changedFiles: z.array(z.string()).readonly(),
40
+ currentHash: z.string().nullable(),
41
+ packageName: z.string().optional(),
42
+ path: z.string(),
43
+ trailId: z.string(),
44
+ workspacePath: z.string().optional(),
45
+ });
46
+
47
+ const releaseCheckOutputSchema = z.object({
48
+ activePackageChangesetsWithoutReleaseFacts: z.array(z.string()).readonly(),
49
+ affectedPackages: z.array(z.string()).readonly(),
50
+ changedChangesets: z.array(z.string()).readonly(),
51
+ configPath: z.string().optional(),
52
+ contractFacts: z.array(contractReleaseFactSchema).readonly(),
53
+ coveredPackages: z.array(z.string()).readonly(),
54
+ errors: z.array(z.string()).readonly(),
55
+ formatted: z.string(),
56
+ matchedRuleIds: z.array(z.string()).readonly(),
57
+ noReleaseOverride: z.boolean(),
58
+ passed: z.boolean(),
59
+ releaseNone: z.boolean(),
60
+ uncoveredContractFacts: z.array(contractReleaseFactSchema).readonly(),
61
+ versionRelease: z.boolean(),
62
+ });
63
+
64
+ export const releaseCheckTrail = trail('release.check', {
65
+ blaze: async (input, ctx) => {
66
+ const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
67
+ if (rootDirResult.isErr()) {
68
+ return rootDirResult;
69
+ }
70
+
71
+ try {
72
+ return Result.ok(
73
+ await runReleaseCheck({
74
+ ...(input.baseRef === undefined ? {} : { baseRef: input.baseRef }),
75
+ ...(input.changedFiles === undefined
76
+ ? {}
77
+ : { changedFilesPath: input.changedFiles }),
78
+ ...(input.configPath === undefined
79
+ ? {}
80
+ : { configPath: input.configPath }),
81
+ env: ctx.env ?? {},
82
+ releaseNone: input.releaseNone,
83
+ repoRoot: rootDirResult.value,
84
+ })
85
+ );
86
+ } catch (error) {
87
+ return Result.err(
88
+ new ValidationError(
89
+ error instanceof Error ? error.message : String(error)
90
+ )
91
+ );
92
+ }
93
+ },
94
+ description: 'Check branch-local release rules',
95
+ examples: [
96
+ {
97
+ input: { baseRef: 'HEAD' },
98
+ name: 'Check release rules from the current HEAD',
99
+ },
100
+ ],
101
+ input: releaseCheckInputSchema,
102
+ intent: 'read',
103
+ output: releaseCheckOutputSchema,
104
+ permit: 'public',
105
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `release.smoke` trail -- Local release confidence checks.
3
+ */
4
+
5
+ import { Result, trail, ValidationError } from '@ontrails/core';
6
+ import { z } from 'zod';
7
+
8
+ import { releaseSmokeCheckValues, runReleaseSmoke } from '../release/smoke.js';
9
+
10
+ const releaseSmokeCheckSchema = z.enum(releaseSmokeCheckValues);
11
+
12
+ const releaseSmokeInputSchema = z.object({
13
+ check: z.string().default('all').describe('Release smoke check to run'),
14
+ });
15
+
16
+ const releaseSmokeCheckResultSchema = z.object({
17
+ check: z.enum(['packed-artifacts', 'wayfinder-dogfood']),
18
+ message: z.string(),
19
+ packageCount: z.number().optional(),
20
+ passed: z.literal(true),
21
+ trailCount: z.number().optional(),
22
+ });
23
+
24
+ const releaseSmokeOutputSchema = z.object({
25
+ checks: z.array(releaseSmokeCheckResultSchema).readonly(),
26
+ message: z.string(),
27
+ passed: z.literal(true),
28
+ });
29
+
30
+ export const releaseSmokeTrail = trail('release.smoke', {
31
+ blaze: async (input) => {
32
+ try {
33
+ const check = releaseSmokeCheckSchema.parse(input.check);
34
+ return Result.ok(await runReleaseSmoke(check));
35
+ } catch (error) {
36
+ return Result.err(
37
+ new ValidationError(
38
+ error instanceof Error ? error.message : String(error)
39
+ )
40
+ );
41
+ }
42
+ },
43
+ description: 'Run local release confidence smoke checks',
44
+ input: releaseSmokeInputSchema,
45
+ intent: 'read',
46
+ output: releaseSmokeOutputSchema,
47
+ permit: 'public',
48
+ });
@@ -0,0 +1,53 @@
1
+ import { Result, ValidationError, trail } from '@ontrails/core';
2
+ import { z } from 'zod';
3
+
4
+ import {
5
+ findLifecycleTrail,
6
+ forkVersionEntrySource,
7
+ parseLifecycleTarget,
8
+ reviseTrailSource,
9
+ withLifecycleApp,
10
+ } from './version-lifecycle-support.js';
11
+
12
+ export const reviseTrail = trail('revise', {
13
+ args: ['target'],
14
+ blaze: async (input, ctx) =>
15
+ withLifecycleApp(input, ctx.cwd, async (app, rootDir) => {
16
+ const target = parseLifecycleTarget(input.target);
17
+ if (target.isErr()) {
18
+ return target;
19
+ }
20
+ if (target.value.version !== undefined) {
21
+ return input.as === 'fork'
22
+ ? forkVersionEntrySource(rootDir, target.value)
23
+ : Result.err(
24
+ new ValidationError(
25
+ 'Revising a specific historical entry requires --as fork'
26
+ )
27
+ );
28
+ }
29
+ const found = findLifecycleTrail(app, target.value.trailId);
30
+ if (found.isErr()) {
31
+ return found;
32
+ }
33
+ return reviseTrailSource(rootDir, found.value, input.as);
34
+ }),
35
+ description: 'Scaffold the next trail version entry',
36
+ input: z.object({
37
+ as: z
38
+ .enum(['revision', 'fork'])
39
+ .default('revision')
40
+ .describe('Version entry shape to scaffold'),
41
+ module: z.string().optional().describe('Path to the app module'),
42
+ rootDir: z.string().optional().describe('Workspace root directory'),
43
+ target: z.string().min(1).describe('Trail target, optionally trail.id@N'),
44
+ }),
45
+ intent: 'write',
46
+ output: z.object({
47
+ file: z.string(),
48
+ trailId: z.string(),
49
+ updated: z.boolean(),
50
+ warnings: z.array(z.string()).optional(),
51
+ }),
52
+ permit: { scopes: ['version:write'] },
53
+ });
@@ -0,0 +1,21 @@
1
+ import { Result, ValidationError } from '@ontrails/core';
2
+
3
+ const ROOT_DIR_MESSAGE =
4
+ 'Trail execution requires rootDir input or ctx.cwd from the runtime context.';
5
+
6
+ export const resolveTrailRootDir = (
7
+ rootDir: string | undefined,
8
+ cwd: string | undefined
9
+ ): Result<string, ValidationError> => {
10
+ const resolved = rootDir ?? cwd;
11
+ return resolved === undefined
12
+ ? Result.err(new ValidationError(ROOT_DIR_MESSAGE))
13
+ : Result.ok(resolved);
14
+ };
15
+
16
+ export const requireTrailRootDir = (rootDir: string | undefined): string => {
17
+ if (rootDir === undefined) {
18
+ throw new ValidationError(ROOT_DIR_MESSAGE);
19
+ }
20
+ return rootDir;
21
+ };