@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.
Files changed (197) hide show
  1. package/CHANGELOG.md +208 -0
  2. package/README.md +27 -0
  3. package/package.json +19 -8
  4. package/src/app.ts +17 -7
  5. package/src/clack.ts +1 -1
  6. package/src/cli.ts +304 -10
  7. package/src/completions.ts +240 -0
  8. package/src/load-app-mirror.ts +160 -0
  9. package/src/local-state-io.ts +153 -0
  10. package/src/project-writes.ts +320 -0
  11. package/src/run-collision.ts +125 -0
  12. package/src/run-completions-install.ts +179 -0
  13. package/src/run-example.ts +149 -0
  14. package/src/run-examples.ts +148 -0
  15. package/src/run-quiet.ts +75 -0
  16. package/src/run-trace.ts +273 -0
  17. package/src/run-warden.ts +39 -0
  18. package/src/run-watch.ts +432 -0
  19. package/src/scaffold-versions.generated.ts +12 -0
  20. package/src/trails/add-surface.ts +172 -0
  21. package/src/trails/add-trail.ts +73 -27
  22. package/src/trails/add-verify.ts +68 -23
  23. package/src/trails/completions-complete.ts +165 -0
  24. package/src/trails/completions.ts +47 -0
  25. package/src/trails/create-scaffold.ts +101 -35
  26. package/src/trails/create.ts +87 -74
  27. package/src/trails/dev-clean.ts +31 -22
  28. package/src/trails/dev-reset.ts +9 -3
  29. package/src/trails/dev-stats.ts +28 -20
  30. package/src/trails/dev-support.ts +109 -95
  31. package/src/trails/draft-promote.ts +351 -107
  32. package/src/trails/guide.ts +55 -38
  33. package/src/trails/load-app.ts +712 -38
  34. package/src/trails/root-dir.ts +21 -0
  35. package/src/trails/run-example.ts +482 -0
  36. package/src/trails/run-examples.ts +141 -0
  37. package/src/trails/run.ts +403 -0
  38. package/src/trails/survey.ts +517 -186
  39. package/src/trails/topo-activation.ts +385 -0
  40. package/src/trails/topo-compile.ts +55 -0
  41. package/src/trails/topo-history.ts +14 -11
  42. package/src/trails/topo-output-schemas.ts +175 -0
  43. package/src/trails/topo-pin.ts +25 -16
  44. package/src/trails/topo-read-support.ts +178 -238
  45. package/src/trails/topo-reports.ts +445 -63
  46. package/src/trails/topo-store-support.ts +67 -35
  47. package/src/trails/topo-support.ts +93 -147
  48. package/src/trails/topo-unpin.ts +17 -7
  49. package/src/trails/topo-verify.ts +19 -10
  50. package/src/trails/topo.ts +64 -31
  51. package/src/trails/warden-guide.ts +121 -0
  52. package/src/trails/warden.ts +137 -47
  53. package/src/versions.ts +28 -0
  54. package/.turbo/turbo-build.log +0 -1
  55. package/.turbo/turbo-lint.log +0 -3
  56. package/.turbo/turbo-typecheck.log +0 -1
  57. package/__tests__/examples.test.ts +0 -20
  58. package/dist/bin/trails.d.ts +0 -3
  59. package/dist/bin/trails.d.ts.map +0 -1
  60. package/dist/bin/trails.js +0 -4
  61. package/dist/bin/trails.js.map +0 -1
  62. package/dist/src/app.d.ts +0 -2
  63. package/dist/src/app.d.ts.map +0 -1
  64. package/dist/src/app.js +0 -22
  65. package/dist/src/app.js.map +0 -1
  66. package/dist/src/clack.d.ts +0 -9
  67. package/dist/src/clack.d.ts.map +0 -1
  68. package/dist/src/clack.js +0 -84
  69. package/dist/src/clack.js.map +0 -1
  70. package/dist/src/cli.d.ts +0 -2
  71. package/dist/src/cli.d.ts.map +0 -1
  72. package/dist/src/cli.js +0 -13
  73. package/dist/src/cli.js.map +0 -1
  74. package/dist/src/trails/add-surface.d.ts +0 -13
  75. package/dist/src/trails/add-surface.d.ts.map +0 -1
  76. package/dist/src/trails/add-surface.js +0 -88
  77. package/dist/src/trails/add-surface.js.map +0 -1
  78. package/dist/src/trails/add-trail.d.ts +0 -10
  79. package/dist/src/trails/add-trail.d.ts.map +0 -1
  80. package/dist/src/trails/add-trail.js +0 -77
  81. package/dist/src/trails/add-trail.js.map +0 -1
  82. package/dist/src/trails/add-trailhead.d.ts +0 -13
  83. package/dist/src/trails/add-trailhead.d.ts.map +0 -1
  84. package/dist/src/trails/add-trailhead.js +0 -88
  85. package/dist/src/trails/add-trailhead.js.map +0 -1
  86. package/dist/src/trails/add-verify.d.ts +0 -10
  87. package/dist/src/trails/add-verify.d.ts.map +0 -1
  88. package/dist/src/trails/add-verify.js +0 -67
  89. package/dist/src/trails/add-verify.js.map +0 -1
  90. package/dist/src/trails/create-scaffold.d.ts +0 -15
  91. package/dist/src/trails/create-scaffold.d.ts.map +0 -1
  92. package/dist/src/trails/create-scaffold.js +0 -288
  93. package/dist/src/trails/create-scaffold.js.map +0 -1
  94. package/dist/src/trails/create.d.ts +0 -22
  95. package/dist/src/trails/create.d.ts.map +0 -1
  96. package/dist/src/trails/create.js +0 -121
  97. package/dist/src/trails/create.js.map +0 -1
  98. package/dist/src/trails/dev-clean.d.ts +0 -9
  99. package/dist/src/trails/dev-clean.d.ts.map +0 -1
  100. package/dist/src/trails/dev-clean.js +0 -65
  101. package/dist/src/trails/dev-clean.js.map +0 -1
  102. package/dist/src/trails/dev-reset.d.ts +0 -6
  103. package/dist/src/trails/dev-reset.d.ts.map +0 -1
  104. package/dist/src/trails/dev-reset.js +0 -38
  105. package/dist/src/trails/dev-reset.js.map +0 -1
  106. package/dist/src/trails/dev-stats.d.ts +0 -7
  107. package/dist/src/trails/dev-stats.d.ts.map +0 -1
  108. package/dist/src/trails/dev-stats.js +0 -61
  109. package/dist/src/trails/dev-stats.js.map +0 -1
  110. package/dist/src/trails/dev-support.d.ts +0 -64
  111. package/dist/src/trails/dev-support.d.ts.map +0 -1
  112. package/dist/src/trails/dev-support.js +0 -178
  113. package/dist/src/trails/dev-support.js.map +0 -1
  114. package/dist/src/trails/draft-promote.d.ts +0 -18
  115. package/dist/src/trails/draft-promote.d.ts.map +0 -1
  116. package/dist/src/trails/draft-promote.js +0 -386
  117. package/dist/src/trails/draft-promote.js.map +0 -1
  118. package/dist/src/trails/guide.d.ts +0 -21
  119. package/dist/src/trails/guide.d.ts.map +0 -1
  120. package/dist/src/trails/guide.js +0 -64
  121. package/dist/src/trails/guide.js.map +0 -1
  122. package/dist/src/trails/load-app.d.ts +0 -6
  123. package/dist/src/trails/load-app.d.ts.map +0 -1
  124. package/dist/src/trails/load-app.js +0 -67
  125. package/dist/src/trails/load-app.js.map +0 -1
  126. package/dist/src/trails/project.d.ts +0 -8
  127. package/dist/src/trails/project.d.ts.map +0 -1
  128. package/dist/src/trails/project.js +0 -54
  129. package/dist/src/trails/project.js.map +0 -1
  130. package/dist/src/trails/survey.d.ts +0 -18
  131. package/dist/src/trails/survey.d.ts.map +0 -1
  132. package/dist/src/trails/survey.js +0 -212
  133. package/dist/src/trails/survey.js.map +0 -1
  134. package/dist/src/trails/topo-constants.d.ts +0 -3
  135. package/dist/src/trails/topo-constants.d.ts.map +0 -1
  136. package/dist/src/trails/topo-constants.js +0 -3
  137. package/dist/src/trails/topo-constants.js.map +0 -1
  138. package/dist/src/trails/topo-export.d.ts +0 -18
  139. package/dist/src/trails/topo-export.d.ts.map +0 -1
  140. package/dist/src/trails/topo-export.js +0 -34
  141. package/dist/src/trails/topo-export.js.map +0 -1
  142. package/dist/src/trails/topo-history.d.ts +0 -24
  143. package/dist/src/trails/topo-history.d.ts.map +0 -1
  144. package/dist/src/trails/topo-history.js +0 -33
  145. package/dist/src/trails/topo-history.js.map +0 -1
  146. package/dist/src/trails/topo-pin.d.ts +0 -21
  147. package/dist/src/trails/topo-pin.d.ts.map +0 -1
  148. package/dist/src/trails/topo-pin.js +0 -35
  149. package/dist/src/trails/topo-pin.js.map +0 -1
  150. package/dist/src/trails/topo-read-support.d.ts +0 -54
  151. package/dist/src/trails/topo-read-support.d.ts.map +0 -1
  152. package/dist/src/trails/topo-read-support.js +0 -178
  153. package/dist/src/trails/topo-read-support.js.map +0 -1
  154. package/dist/src/trails/topo-reports.d.ts +0 -50
  155. package/dist/src/trails/topo-reports.d.ts.map +0 -1
  156. package/dist/src/trails/topo-reports.js +0 -122
  157. package/dist/src/trails/topo-reports.js.map +0 -1
  158. package/dist/src/trails/topo-show.d.ts +0 -23
  159. package/dist/src/trails/topo-show.d.ts.map +0 -1
  160. package/dist/src/trails/topo-show.js +0 -53
  161. package/dist/src/trails/topo-show.js.map +0 -1
  162. package/dist/src/trails/topo-store-support.d.ts +0 -13
  163. package/dist/src/trails/topo-store-support.d.ts.map +0 -1
  164. package/dist/src/trails/topo-store-support.js +0 -55
  165. package/dist/src/trails/topo-store-support.js.map +0 -1
  166. package/dist/src/trails/topo-support.d.ts +0 -87
  167. package/dist/src/trails/topo-support.d.ts.map +0 -1
  168. package/dist/src/trails/topo-support.js +0 -165
  169. package/dist/src/trails/topo-support.js.map +0 -1
  170. package/dist/src/trails/topo-unpin.d.ts +0 -15
  171. package/dist/src/trails/topo-unpin.d.ts.map +0 -1
  172. package/dist/src/trails/topo-unpin.js +0 -39
  173. package/dist/src/trails/topo-unpin.js.map +0 -1
  174. package/dist/src/trails/topo-verify.d.ts +0 -5
  175. package/dist/src/trails/topo-verify.d.ts.map +0 -1
  176. package/dist/src/trails/topo-verify.js +0 -28
  177. package/dist/src/trails/topo-verify.js.map +0 -1
  178. package/dist/src/trails/topo.d.ts +0 -5
  179. package/dist/src/trails/topo.d.ts.map +0 -1
  180. package/dist/src/trails/topo.js +0 -67
  181. package/dist/src/trails/topo.js.map +0 -1
  182. package/dist/src/trails/warden.d.ts +0 -19
  183. package/dist/src/trails/warden.d.ts.map +0 -1
  184. package/dist/src/trails/warden.js +0 -89
  185. package/dist/src/trails/warden.js.map +0 -1
  186. package/dist/tsconfig.tsbuildinfo +0 -1
  187. package/src/__tests__/create.test.ts +0 -351
  188. package/src/__tests__/draft-promote.test.ts +0 -144
  189. package/src/__tests__/guide.test.ts +0 -91
  190. package/src/__tests__/load-app.test.ts +0 -58
  191. package/src/__tests__/survey.test.ts +0 -301
  192. package/src/__tests__/topo-dev.test.ts +0 -424
  193. package/src/__tests__/warden.test.ts +0 -74
  194. package/src/trails/add-trailhead.ts +0 -121
  195. package/src/trails/topo-export.ts +0 -39
  196. package/src/trails/topo-show.ts +0 -58
  197. package/tsconfig.json +0 -9
@@ -1,9 +1,11 @@
1
1
  import { Result, trail } from '@ontrails/core';
2
2
  import { z } from 'zod';
3
3
 
4
- import { loadApp } from './load-app.js';
4
+ import { tryLoadFreshAppLease } from './load-app.js';
5
+ import { resolveTrailRootDir } from './root-dir.js';
6
+ import { activationOverviewOutput } from './topo-output-schemas.js';
5
7
  import { buildTopoSummary } from './topo-read-support.js';
6
- import { DEFAULT_APP_MODULE } from './topo-support.js';
8
+ import { createIsolatedExampleInput } from './topo-support.js';
7
9
 
8
10
  const summaryOutput = z.object({
9
11
  app: z.object({
@@ -12,37 +14,59 @@ const summaryOutput = z.object({
12
14
  detours: z.boolean(),
13
15
  examples: z.boolean(),
14
16
  outputSchemas: z.boolean(),
15
- provisions: z.boolean(),
17
+ resources: z.boolean(),
16
18
  signals: z.boolean(),
17
19
  }),
18
20
  name: z.string(),
19
- provisions: z.number(),
21
+ resources: z.number(),
20
22
  signals: z.number(),
21
23
  trails: z.number(),
22
24
  version: z.string(),
23
25
  }),
24
26
  dbPath: z.string(),
25
27
  list: z.object({
28
+ activation: activationOverviewOutput,
26
29
  count: z.number(),
27
- entries: z.array(
28
- z.object({
29
- examples: z.number(),
30
- id: z.string(),
31
- kind: z.string(),
32
- safety: z.string(),
33
- })
34
- ),
35
- provisionCount: z.number(),
36
- provisions: z.array(
37
- z.object({
38
- description: z.string().nullable(),
39
- health: z.enum(['available', 'none']),
40
- id: z.string(),
41
- kind: z.literal('provision'),
42
- lifetime: z.literal('singleton'),
43
- usedBy: z.array(z.string()),
44
- })
45
- ),
30
+ entries: z
31
+ .array(
32
+ z.object({
33
+ activatedBy: z.array(z.string()).readonly(),
34
+ activates: z.array(z.string()).readonly(),
35
+ examples: z.number(),
36
+ id: z.string(),
37
+ kind: z.string(),
38
+ safety: z.string(),
39
+ })
40
+ )
41
+ .readonly(),
42
+ resourceCount: z.number(),
43
+ resources: z
44
+ .array(
45
+ z.object({
46
+ description: z.string().nullable(),
47
+ health: z.enum(['available', 'none']),
48
+ id: z.string(),
49
+ kind: z.literal('resource'),
50
+ lifetime: z.literal('singleton'),
51
+ usedBy: z.array(z.string()).readonly(),
52
+ })
53
+ )
54
+ .readonly(),
55
+ signalCount: z.number(),
56
+ signals: z
57
+ .array(
58
+ z.object({
59
+ consumers: z.array(z.string()).readonly(),
60
+ description: z.string().nullable(),
61
+ examples: z.number(),
62
+ from: z.array(z.string()).readonly(),
63
+ id: z.string(),
64
+ kind: z.literal('signal'),
65
+ payloadSchema: z.boolean(),
66
+ producers: z.array(z.string()).readonly(),
67
+ })
68
+ )
69
+ .readonly(),
46
70
  }),
47
71
  lockExists: z.boolean(),
48
72
  lockPath: z.string(),
@@ -50,22 +74,31 @@ const summaryOutput = z.object({
50
74
 
51
75
  export const topoTrail = trail('topo', {
52
76
  blaze: async (input, ctx) => {
53
- const rootDir = input.rootDir ?? ctx.cwd ?? process.cwd();
54
- const app = await loadApp(input.module, rootDir);
55
- return Result.ok(buildTopoSummary(app, { rootDir }));
77
+ const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
78
+ if (rootDirResult.isErr()) {
79
+ return Result.err(rootDirResult.error);
80
+ }
81
+ const rootDir = rootDirResult.value;
82
+ const leaseResult = await tryLoadFreshAppLease(input.module, rootDir);
83
+ if (leaseResult.isErr()) {
84
+ return Result.err(leaseResult.error);
85
+ }
86
+ const lease = leaseResult.value;
87
+ try {
88
+ return Result.ok(buildTopoSummary(lease.app, { rootDir }));
89
+ } finally {
90
+ lease.release();
91
+ }
56
92
  },
57
93
  description: 'Show the current topo summary and entry list',
58
94
  examples: [
59
95
  {
60
- input: {},
96
+ input: createIsolatedExampleInput('topo-summary'),
61
97
  name: 'Show the current topo summary',
62
98
  },
63
99
  ],
64
100
  input: z.object({
65
- module: z
66
- .string()
67
- .default(DEFAULT_APP_MODULE)
68
- .describe('Path to the app module'),
101
+ module: z.string().optional().describe('Path to the app module'),
69
102
  rootDir: z.string().optional().describe('Workspace root directory'),
70
103
  }),
71
104
  intent: 'read',
@@ -0,0 +1,121 @@
1
+ import type { FieldOverride } from '@ontrails/core';
2
+ import { Result, trail } from '@ontrails/core';
3
+ import {
4
+ buildWardenGuideManifest,
5
+ formatWardenGuide,
6
+ wardenDepthValues,
7
+ wardenGuideFormatValues,
8
+ wardenRuleConcerns,
9
+ wardenRuleLifecycleStates,
10
+ wardenRuleScopes,
11
+ wardenRuleTiers,
12
+ } from '@ontrails/warden';
13
+ import { z } from 'zod';
14
+
15
+ const wardenGuidanceLinkSchema = z.object({
16
+ label: z.string(),
17
+ path: z.string().optional(),
18
+ url: z.string().optional(),
19
+ });
20
+
21
+ const wardenGuidanceSchema = z.object({
22
+ commands: z.array(z.string()).readonly().optional(),
23
+ docs: z.array(wardenGuidanceLinkSchema).readonly().optional(),
24
+ relatedRules: z.array(z.string()).readonly().optional(),
25
+ steps: z.array(z.string()).readonly().optional(),
26
+ summary: z.string(),
27
+ });
28
+
29
+ const wardenRuleGuideEntrySchema = z.object({
30
+ concern: z.enum(wardenRuleConcerns),
31
+ depth: z.enum(wardenDepthValues),
32
+ description: z.string(),
33
+ docs: z.array(wardenGuidanceLinkSchema).readonly(),
34
+ guidance: wardenGuidanceSchema.optional(),
35
+ id: z.string(),
36
+ invariant: z.string(),
37
+ lifecycle: z.object({
38
+ retireWhen: z.string().optional(),
39
+ state: z.enum(wardenRuleLifecycleStates),
40
+ }),
41
+ scope: z.enum(wardenRuleScopes),
42
+ severity: z.enum(['error', 'warn']),
43
+ tier: z.enum(wardenRuleTiers),
44
+ });
45
+
46
+ const wardenGuideManifestSchema = z.object({
47
+ generatedFrom: z.object({
48
+ package: z.literal('@ontrails/warden'),
49
+ registries: z.tuple([
50
+ z.literal('wardenRules'),
51
+ z.literal('wardenTopoRules'),
52
+ ]),
53
+ source: z.literal('builtin-rule-metadata'),
54
+ }),
55
+ kind: z.literal('trails-warden-guide-manifest'),
56
+ ruleCount: z.number(),
57
+ rules: z.array(wardenRuleGuideEntrySchema).readonly(),
58
+ version: z.literal(1),
59
+ });
60
+
61
+ const wardenGuideInputSchema = z.object({
62
+ guideFormat: z
63
+ .enum(wardenGuideFormatValues)
64
+ .default('markdown')
65
+ .describe('Guide output format'),
66
+ });
67
+
68
+ const wardenGuideFields = {
69
+ guideFormat: {
70
+ aliases: true,
71
+ options: [
72
+ {
73
+ hint: 'Human-readable Warden guide',
74
+ label: 'Markdown',
75
+ value: 'markdown',
76
+ },
77
+ {
78
+ hint: 'Compact guidance for agent context',
79
+ label: 'Agent JSON',
80
+ value: 'agent-json',
81
+ },
82
+ {
83
+ hint: 'Full structured rule manifest',
84
+ label: 'Manifest',
85
+ value: 'manifest',
86
+ },
87
+ ],
88
+ },
89
+ } satisfies Readonly<
90
+ Record<'guideFormat', FieldOverride & { readonly aliases: true }>
91
+ >;
92
+
93
+ export const wardenGuideTrail = trail('warden.guide', {
94
+ blaze: (input) => {
95
+ const manifest = buildWardenGuideManifest();
96
+ return Result.ok({
97
+ format: input.guideFormat,
98
+ formatted: formatWardenGuide(manifest, input.guideFormat),
99
+ manifest,
100
+ });
101
+ },
102
+ description: 'Project Warden rule guidance as markdown or JSON',
103
+ examples: [
104
+ {
105
+ input: { guideFormat: 'markdown' },
106
+ name: 'Markdown guide',
107
+ },
108
+ {
109
+ input: { guideFormat: 'agent-json' },
110
+ name: 'Agent JSON guide',
111
+ },
112
+ ],
113
+ fields: wardenGuideFields,
114
+ input: wardenGuideInputSchema,
115
+ intent: 'read',
116
+ output: z.object({
117
+ format: z.enum(wardenGuideFormatValues),
118
+ formatted: z.string(),
119
+ manifest: wardenGuideManifestSchema,
120
+ }),
121
+ });
@@ -1,54 +1,159 @@
1
1
  /**
2
2
  * `warden` trail -- Governance checks.
3
3
  *
4
- * Thin wrapper around `runWarden` and `formatWardenReport` from @ontrails/warden.
4
+ * Thin wrapper around the shared @ontrails/warden command surface.
5
5
  */
6
6
 
7
7
  import { Result, trail } from '@ontrails/core';
8
8
  import {
9
- formatGitHubAnnotations,
10
- formatJson,
11
- formatSummary,
12
- formatWardenReport,
13
- runWarden,
9
+ diagnosticSchema,
10
+ runWardenCommand,
11
+ wardenDepthValues,
12
+ wardenDraftsValues,
13
+ wardenFailOnValues,
14
+ wardenFormatValues,
15
+ wardenLockValues,
14
16
  } from '@ontrails/warden';
15
17
  import { z } from 'zod';
16
18
 
17
- import { loadApp } from './load-app.js';
19
+ import { resolveTrailRootDir } from './root-dir.js';
18
20
 
19
21
  // ---------------------------------------------------------------------------
20
22
  // Trail definition
21
23
  // ---------------------------------------------------------------------------
22
24
 
25
+ const wardenInputSchema = z.object({
26
+ apps: z
27
+ .array(z.string())
28
+ .optional()
29
+ .describe('App names or module paths to govern'),
30
+ cached: z.boolean().default(false).describe('Alias for --lock cached'),
31
+ ci: z.boolean().default(false).describe('Use the CI Warden preset'),
32
+ configPath: z.string().optional().describe('Path to trails.config.ts'),
33
+ depth: z
34
+ .enum(wardenDepthValues)
35
+ .optional()
36
+ .describe('Cumulative analysis depth'),
37
+ drafts: z.enum(wardenDraftsValues).optional().describe('Draft state mode'),
38
+ excludeDrafts: z
39
+ .boolean()
40
+ .default(false)
41
+ .describe('Alias for --drafts exclude'),
42
+ failOn: z.enum(wardenFailOnValues).optional().describe('Failure threshold'),
43
+ format: z.enum(wardenFormatValues).optional().describe('Output format'),
44
+ github: z.boolean().default(false).describe('Alias for --format github'),
45
+ includeDrafts: z
46
+ .boolean()
47
+ .default(false)
48
+ .describe('Alias for --drafts include'),
49
+ json: z.boolean().default(false).describe('Alias for --format json'),
50
+ lock: z.enum(wardenLockValues).optional().describe('Lockfile mode'),
51
+ noLockMutation: z
52
+ .boolean()
53
+ .default(false)
54
+ .describe('Suppress lockfile mutation'),
55
+ onlyDrafts: z.boolean().default(false).describe('Alias for --drafts only'),
56
+ prePush: z.boolean().default(false).describe('Use the pre-push preset'),
57
+ refresh: z.boolean().default(false).describe('Alias for --lock refresh'),
58
+ rootDir: z.string().optional().describe('Root directory to scan'),
59
+ skipLock: z.boolean().default(false).describe('Alias for --lock skip'),
60
+ strict: z.boolean().default(false).describe('Alias for --fail-on warning'),
61
+ summary: z.boolean().default(false).describe('Alias for --format summary'),
62
+ });
63
+
64
+ type WardenTrailInput = z.infer<typeof wardenInputSchema>;
65
+
66
+ const pushFlag = (args: string[], condition: boolean, flag: string): void => {
67
+ if (condition) {
68
+ args.push(flag);
69
+ }
70
+ };
71
+
72
+ const pushValue = (
73
+ args: string[],
74
+ flag: string,
75
+ value: string | undefined
76
+ ): void => {
77
+ if (value !== undefined) {
78
+ args.push(flag, value);
79
+ }
80
+ };
81
+
82
+ const pushApps = (
83
+ args: string[],
84
+ apps: readonly string[] | undefined
85
+ ): void => {
86
+ if (apps !== undefined && apps.length > 0) {
87
+ args.push('--apps', apps.join(','));
88
+ }
89
+ };
90
+
91
+ export const buildWardenCommandArgs = (
92
+ input: WardenTrailInput
93
+ ): readonly string[] => {
94
+ const args: string[] = [];
95
+
96
+ pushFlag(args, input.prePush, '--pre-push');
97
+ pushFlag(args, input.ci, '--ci');
98
+ pushValue(args, '--depth', input.depth);
99
+ if (input.strict) {
100
+ args.push('--strict');
101
+ } else {
102
+ pushValue(args, '--fail-on', input.failOn);
103
+ }
104
+ if (input.github) {
105
+ args.push('--github');
106
+ } else if (input.json) {
107
+ args.push('--json');
108
+ } else if (input.summary) {
109
+ args.push('--summary');
110
+ } else {
111
+ pushValue(args, '--format', input.format);
112
+ }
113
+ if (input.skipLock) {
114
+ args.push('--skip-lock');
115
+ } else if (input.refresh) {
116
+ args.push('--refresh');
117
+ } else if (input.cached) {
118
+ args.push('--cached');
119
+ } else {
120
+ pushValue(args, '--lock', input.lock);
121
+ }
122
+ if (input.onlyDrafts) {
123
+ args.push('--only-drafts');
124
+ } else if (input.excludeDrafts) {
125
+ args.push('--exclude-drafts');
126
+ } else if (input.includeDrafts) {
127
+ args.push('--include-drafts');
128
+ } else {
129
+ pushValue(args, '--drafts', input.drafts);
130
+ }
131
+ pushFlag(args, input.noLockMutation, '--no-lock-mutation');
132
+ pushValue(args, '--config-path', input.configPath);
133
+ pushApps(args, input.apps);
134
+
135
+ return args;
136
+ };
137
+
23
138
  export const wardenTrail = trail('warden', {
24
139
  blaze: async (input, ctx) => {
25
- const rootDir = input.rootDir ?? ctx.cwd ?? process.cwd();
26
- // oxlint-disable-next-line prefer-await-to-then -- catch converts rejection to undefined cleanly
27
- const topo = await loadApp('./src/app.ts', rootDir).catch(
28
- (): undefined => undefined
29
- );
30
-
31
- const report = await runWarden({
32
- driftOnly: input.driftOnly,
33
- lintOnly: input.lintOnly,
34
- rootDir,
35
- topo,
140
+ const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
141
+ if (rootDirResult.isErr()) {
142
+ return Result.err(rootDirResult.error);
143
+ }
144
+ const rootDir = rootDirResult.value;
145
+ const result = await runWardenCommand({
146
+ args: buildWardenCommandArgs(input),
147
+ cwd: rootDir,
148
+ env: ctx.env ?? {},
36
149
  });
37
-
38
- const formatters: Record<string, (r: typeof report) => string> = {
39
- github: formatGitHubAnnotations,
40
- json: formatJson,
41
- summary: formatSummary,
42
- text: formatWardenReport,
43
- };
44
- const formatter = formatters[input.format] ?? formatWardenReport;
45
- const formatted = formatter(report);
150
+ const { report } = result;
46
151
 
47
152
  return Result.ok({
48
- diagnostics: report.diagnostics,
153
+ diagnostics: [...report.diagnostics],
49
154
  drift: report.drift,
50
155
  errorCount: report.errorCount,
51
- formatted,
156
+ formatted: result.output,
52
157
  passed: report.passed,
53
158
  warnCount: report.warnCount,
54
159
  });
@@ -57,8 +162,7 @@ export const wardenTrail = trail('warden', {
57
162
  examples: [
58
163
  {
59
164
  input: {
60
- driftOnly: false,
61
- lintOnly: false,
165
+ lock: 'skip',
62
166
  },
63
167
  name: 'Default warden run',
64
168
  },
@@ -69,25 +173,11 @@ export const wardenTrail = trail('warden', {
69
173
  name: 'GitHub Actions annotations',
70
174
  },
71
175
  ],
72
- input: z.object({
73
- driftOnly: z.boolean().default(false).describe('Only run drift detection'),
74
- format: z
75
- .enum(['text', 'json', 'github', 'summary'])
76
- .default('text')
77
- .describe('Output format: text, json, github, or summary'),
78
- lintOnly: z.boolean().default(false).describe('Only run lint rules'),
79
- rootDir: z.string().optional().describe('Root directory to scan'),
80
- }),
176
+ input: wardenInputSchema,
81
177
  intent: 'read',
82
178
  output: z.object({
83
179
  diagnostics: z.array(
84
- z.object({
85
- filePath: z.string(),
86
- line: z.number(),
87
- message: z.string(),
88
- rule: z.string(),
89
- severity: z.enum(['error', 'warn']),
90
- })
180
+ diagnosticSchema.extend({ topoName: z.string().optional() })
91
181
  ),
92
182
  drift: z
93
183
  .object({
@@ -0,0 +1,28 @@
1
+ import { scaffoldDependencyVersions } from './scaffold-versions.generated.js';
2
+
3
+ interface PackageJson {
4
+ readonly version?: string;
5
+ }
6
+
7
+ const readPackageJson = async (url: URL): Promise<PackageJson> =>
8
+ (await Bun.file(url).json()) as PackageJson;
9
+
10
+ const appPackageJson = await readPackageJson(
11
+ new URL('../package.json', import.meta.url)
12
+ );
13
+
14
+ const requireVersion = (value: string | undefined, label: string): string => {
15
+ if (typeof value !== 'string' || value.length === 0) {
16
+ throw new Error(`Missing version for ${label}`);
17
+ }
18
+ return value;
19
+ };
20
+
21
+ export const trailsPackageVersion = requireVersion(
22
+ appPackageJson.version,
23
+ '@ontrails/trails'
24
+ );
25
+
26
+ export const ontrailsPackageRange = `^${trailsPackageVersion}`;
27
+
28
+ export { scaffoldDependencyVersions };
@@ -1 +0,0 @@
1
- $ tsc -b
@@ -1,3 +0,0 @@
1
- $ oxlint ./src
2
- Found 0 warnings and 0 errors.
3
- Finished in 16ms on 37 files with 93 rules using 24 threads.
@@ -1 +0,0 @@
1
- $ tsc --noEmit
@@ -1,20 +0,0 @@
1
- /* oxlint-disable eslint-plugin-jest/require-hook -- testExamples registers tests at module scope */
2
- import { afterAll, beforeAll } from 'bun:test';
3
- import { rmSync } from 'node:fs';
4
- import { resolve } from 'node:path';
5
-
6
- import { testExamples } from '@ontrails/testing';
7
-
8
- import { app } from '../src/app.js';
9
-
10
- const trailsWorkspaceDir = resolve(import.meta.dir, '..', '.trails');
11
-
12
- beforeAll(() => {
13
- rmSync(trailsWorkspaceDir, { force: true, recursive: true });
14
- });
15
-
16
- afterAll(() => {
17
- rmSync(trailsWorkspaceDir, { force: true, recursive: true });
18
- });
19
-
20
- testExamples(app);
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env bun
2
- import '../src/cli.js';
3
- //# sourceMappingURL=trails.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trails.d.ts","sourceRoot":"","sources":["../../bin/trails.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC"}
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env bun
2
- /* oxlint-disable eslint-plugin-jest/require-hook -- CLI bin entrypoints execute at module scope */
3
- import '../src/cli.js';
4
- //# sourceMappingURL=trails.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trails.js","sourceRoot":"","sources":["../../bin/trails.ts"],"names":[],"mappings":";AACA,mGAAmG;AACnG,OAAO,eAAe,CAAC"}
package/dist/src/app.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare const app: import("@ontrails/core").Topo;
2
- //# sourceMappingURL=app.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,GAAG,+BAqBf,CAAC"}
package/dist/src/app.js DELETED
@@ -1,22 +0,0 @@
1
- import { topo } from '@ontrails/core';
2
- import * as addTrailhead from './trails/add-trailhead.js';
3
- import * as addTrail from './trails/add-trail.js';
4
- import * as addVerify from './trails/add-verify.js';
5
- import * as create from './trails/create.js';
6
- import * as createScaffold from './trails/create-scaffold.js';
7
- import * as devClean from './trails/dev-clean.js';
8
- import * as devReset from './trails/dev-reset.js';
9
- import * as devStats from './trails/dev-stats.js';
10
- import * as draftPromote from './trails/draft-promote.js';
11
- import * as guide from './trails/guide.js';
12
- import * as survey from './trails/survey.js';
13
- import * as topoExport from './trails/topo-export.js';
14
- import * as topoHistory from './trails/topo-history.js';
15
- import * as topoPin from './trails/topo-pin.js';
16
- import * as topoShow from './trails/topo-show.js';
17
- import * as topoCommand from './trails/topo.js';
18
- import * as topoUnpin from './trails/topo-unpin.js';
19
- import * as topoVerify from './trails/topo-verify.js';
20
- import * as warden from './trails/warden.js';
21
- export const app = topo('trails', survey, topoCommand, topoShow, topoHistory, topoPin, topoUnpin, topoExport, topoVerify, devStats, devClean, devReset, guide, draftPromote, warden, create, createScaffold, addTrailhead, addVerify, addTrail);
22
- //# sourceMappingURL=app.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,OAAO,KAAK,YAAY,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,YAAY,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAC3C,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,UAAU,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,WAAW,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,OAAO,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,UAAU,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAE7C,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CACrB,QAAQ,EACR,MAAM,EACN,WAAW,EACX,QAAQ,EACR,WAAW,EACX,OAAO,EACP,SAAS,EACT,UAAU,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,MAAM,EACN,MAAM,EACN,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,CACT,CAAC"}
@@ -1,9 +0,0 @@
1
- /**
2
- * Clack-backed input resolver for the Trails CLI.
3
- *
4
- * This stays at the app gate so @ontrails/cli remains prompt-library agnostic.
5
- */
6
- import type { InputResolver } from '@ontrails/cli';
7
- /** Fill missing input by prompting with Clack when interactive. */
8
- export declare const resolveInputWithClack: InputResolver;
9
- //# sourceMappingURL=clack.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"clack.d.ts","sourceRoot":"","sources":["../../src/clack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAS,aAAa,EAAuB,MAAM,eAAe,CAAC;AAmF/E,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,EAAE,aAoBnC,CAAC"}