@ontrails/trails 1.0.0-beta.2 → 1.0.0-beta.22
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 +647 -0
- package/README.md +26 -0
- package/package.json +28 -7
- package/src/app.ts +86 -2
- package/src/clack.ts +22 -0
- package/src/cli.ts +330 -11
- package/src/completions.ts +240 -0
- package/src/lifecycle-source-io.ts +33 -0
- package/src/load-app-mirror.ts +202 -0
- package/src/local-state-io.ts +153 -0
- package/src/mcp-app.ts +30 -0
- package/src/mcp-options.ts +77 -0
- package/src/mcp.ts +8 -0
- package/src/project-writes.ts +377 -0
- package/src/release/bindings.ts +39 -0
- package/src/release/check.ts +818 -0
- package/src/release/config.ts +63 -0
- package/src/release/contract-facts.ts +425 -0
- package/src/release/index.ts +85 -0
- package/src/release/native-bun-publish.ts +651 -0
- package/src/release/native-bun-registry.ts +350 -0
- package/src/release/packed-artifacts-smoke.ts +236 -0
- package/src/release/smoke.ts +46 -0
- package/src/release/wayfinder-dogfood-smoke.ts +226 -0
- package/src/retired-topo-command.ts +36 -0
- package/src/run-adapter-check.ts +76 -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-release-check.ts +74 -0
- package/src/run-trace.ts +273 -0
- package/src/run-warden.ts +39 -0
- package/src/run-watch.ts +432 -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 +94 -40
- package/src/trails/add-trail.ts +79 -41
- package/src/trails/add-verify.ts +95 -25
- package/src/trails/compile.ts +67 -0
- package/src/trails/completions-complete.ts +165 -0
- package/src/trails/completions.ts +47 -0
- package/src/trails/create-adapter.ts +1084 -0
- package/src/trails/create-scaffold.ts +399 -104
- package/src/trails/create-versions.ts +62 -0
- package/src/trails/create.ts +185 -71
- package/src/trails/deprecate.ts +59 -0
- package/src/trails/dev-clean.ts +82 -0
- package/src/trails/dev-reset.ts +50 -0
- package/src/trails/dev-stats.ts +72 -0
- package/src/trails/dev-support.ts +340 -0
- package/src/trails/doctor.ts +56 -0
- package/src/trails/draft-promote.ts +949 -0
- package/src/trails/guide.ts +74 -68
- package/src/trails/load-app.ts +1143 -15
- package/src/trails/project.ts +17 -3
- package/src/trails/release-check.ts +104 -0
- package/src/trails/release-smoke.ts +48 -0
- package/src/trails/revise.ts +53 -0
- package/src/trails/root-dir.ts +21 -0
- package/src/trails/run-example.ts +491 -0
- package/src/trails/run-examples.ts +145 -0
- package/src/trails/run.ts +410 -0
- package/src/trails/scaffold-json.ts +58 -0
- package/src/trails/survey.ts +881 -226
- package/src/trails/topo-activation.ts +385 -0
- package/src/trails/topo-constants.ts +2 -0
- package/src/trails/topo-history.ts +47 -0
- package/src/trails/topo-output-schemas.ts +248 -0
- package/src/trails/topo-pin.ts +52 -0
- package/src/trails/topo-read-support.ts +313 -0
- package/src/trails/topo-reports.ts +807 -0
- package/src/trails/topo-store-support.ts +174 -0
- package/src/trails/topo-support.ts +220 -0
- package/src/trails/topo-unpin.ts +61 -0
- package/src/trails/topo.ts +106 -0
- package/src/trails/validate.ts +38 -0
- package/src/trails/version-lifecycle-support.ts +945 -0
- package/src/trails/warden-guide.ts +129 -0
- package/src/trails/warden.ts +165 -58
- package/src/versions.ts +31 -0
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/__tests__/examples.test.ts +0 -6
- package/dist/bin/trails.d.ts +0 -3
- package/dist/bin/trails.d.ts.map +0 -1
- package/dist/bin/trails.js +0 -4
- package/dist/bin/trails.js.map +0 -1
- package/dist/src/app.d.ts +0 -2
- package/dist/src/app.d.ts.map +0 -1
- package/dist/src/app.js +0 -11
- package/dist/src/app.js.map +0 -1
- package/dist/src/clack.d.ts +0 -9
- package/dist/src/clack.d.ts.map +0 -1
- package/dist/src/clack.js +0 -62
- package/dist/src/clack.js.map +0 -1
- package/dist/src/cli.d.ts +0 -2
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -13
- package/dist/src/cli.js.map +0 -1
- package/dist/src/trails/add-surface.d.ts +0 -13
- package/dist/src/trails/add-surface.d.ts.map +0 -1
- package/dist/src/trails/add-surface.js +0 -88
- package/dist/src/trails/add-surface.js.map +0 -1
- package/dist/src/trails/add-trail.d.ts +0 -11
- package/dist/src/trails/add-trail.d.ts.map +0 -1
- package/dist/src/trails/add-trail.js +0 -85
- package/dist/src/trails/add-trail.js.map +0 -1
- package/dist/src/trails/add-verify.d.ts +0 -10
- package/dist/src/trails/add-verify.d.ts.map +0 -1
- package/dist/src/trails/add-verify.js +0 -67
- package/dist/src/trails/add-verify.js.map +0 -1
- package/dist/src/trails/create-scaffold.d.ts +0 -15
- package/dist/src/trails/create-scaffold.d.ts.map +0 -1
- package/dist/src/trails/create-scaffold.js +0 -288
- package/dist/src/trails/create-scaffold.js.map +0 -1
- package/dist/src/trails/create.d.ts +0 -22
- package/dist/src/trails/create.d.ts.map +0 -1
- package/dist/src/trails/create.js +0 -121
- package/dist/src/trails/create.js.map +0 -1
- package/dist/src/trails/guide.d.ts +0 -11
- package/dist/src/trails/guide.d.ts.map +0 -1
- package/dist/src/trails/guide.js +0 -80
- package/dist/src/trails/guide.js.map +0 -1
- package/dist/src/trails/load-app.d.ts +0 -4
- package/dist/src/trails/load-app.d.ts.map +0 -1
- package/dist/src/trails/load-app.js +0 -24
- package/dist/src/trails/load-app.js.map +0 -1
- package/dist/src/trails/project.d.ts +0 -8
- package/dist/src/trails/project.d.ts.map +0 -1
- package/dist/src/trails/project.js +0 -43
- package/dist/src/trails/project.js.map +0 -1
- package/dist/src/trails/survey.d.ts +0 -33
- package/dist/src/trails/survey.d.ts.map +0 -1
- package/dist/src/trails/survey.js +0 -225
- package/dist/src/trails/survey.js.map +0 -1
- package/dist/src/trails/warden.d.ts +0 -19
- package/dist/src/trails/warden.d.ts.map +0 -1
- package/dist/src/trails/warden.js +0 -88
- package/dist/src/trails/warden.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/__tests__/create.test.ts +0 -349
- package/src/__tests__/guide.test.ts +0 -91
- package/src/__tests__/load-app.test.ts +0 -15
- package/src/__tests__/survey.test.ts +0 -161
- package/src/__tests__/warden.test.ts +0 -74
- package/tsconfig.json +0 -9
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `create.versions` trail -- Sync generated scaffold dependency versions.
|
|
3
|
+
*
|
|
4
|
+
* Derives `apps/trails/src/scaffold-versions.generated.ts` from the root
|
|
5
|
+
* `package.json` catalog and devDependencies. Graduated from
|
|
6
|
+
* `scripts/sync-scaffold-versions.ts`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Result, trail, ValidationError } from '@ontrails/core';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
|
|
12
|
+
import { syncScaffoldVersions } from '../scaffold-version-sync.js';
|
|
13
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
14
|
+
|
|
15
|
+
const createVersionsInputSchema = z.object({
|
|
16
|
+
check: z
|
|
17
|
+
.boolean()
|
|
18
|
+
.default(false)
|
|
19
|
+
.describe('Verify the generated file is current instead of writing'),
|
|
20
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const createVersionsOutputSchema = z.object({
|
|
24
|
+
generatedPath: z.string(),
|
|
25
|
+
mode: z.enum(['check', 'write']),
|
|
26
|
+
written: z.boolean(),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const createVersionsTrail = trail('create.versions', {
|
|
30
|
+
blaze: async (input, ctx) => {
|
|
31
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
32
|
+
if (rootDirResult.isErr()) {
|
|
33
|
+
return rootDirResult;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
return Result.ok(
|
|
38
|
+
await syncScaffoldVersions({
|
|
39
|
+
check: input.check,
|
|
40
|
+
rootDir: rootDirResult.value,
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return Result.err(
|
|
45
|
+
new ValidationError(
|
|
46
|
+
error instanceof Error ? error.message : String(error)
|
|
47
|
+
)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
description: 'Sync generated scaffold dependency versions',
|
|
52
|
+
examples: [
|
|
53
|
+
{
|
|
54
|
+
input: { check: true },
|
|
55
|
+
name: 'Verify generated scaffold versions are current',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
input: createVersionsInputSchema,
|
|
59
|
+
intent: 'write',
|
|
60
|
+
output: createVersionsOutputSchema,
|
|
61
|
+
permit: { scopes: ['project:write'] },
|
|
62
|
+
});
|
package/src/trails/create.ts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `create`
|
|
2
|
+
* `create` trail -- Create a new Trails project.
|
|
3
3
|
*
|
|
4
4
|
* Composes create.scaffold, add.surface, and add.verify sub-trails
|
|
5
|
-
* via ctx.
|
|
5
|
+
* via ctx.compose.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
8
|
+
import { InternalError, Result, trail } from '@ontrails/core';
|
|
9
|
+
import type { TrailContext } from '@ontrails/core';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
|
|
12
|
+
import {
|
|
13
|
+
PROJECT_NAME_MESSAGE,
|
|
14
|
+
PROJECT_NAME_PATTERN,
|
|
15
|
+
projectPathExists,
|
|
16
|
+
writeProjectFile,
|
|
17
|
+
} from '../project-writes.js';
|
|
18
|
+
|
|
12
19
|
// ---------------------------------------------------------------------------
|
|
13
20
|
// Helpers
|
|
14
21
|
// ---------------------------------------------------------------------------
|
|
15
22
|
|
|
16
23
|
type Starter = 'empty' | 'entity' | 'hello';
|
|
17
|
-
type Surface = 'cli' | 'mcp';
|
|
24
|
+
type Surface = 'cli' | 'http' | 'mcp';
|
|
18
25
|
|
|
19
|
-
interface
|
|
26
|
+
interface CreateInput {
|
|
20
27
|
readonly dir?: string | undefined;
|
|
21
28
|
readonly name: string;
|
|
22
29
|
readonly starter: Starter;
|
|
@@ -42,6 +49,18 @@ interface ScaffoldedProject {
|
|
|
42
49
|
readonly name: string;
|
|
43
50
|
}
|
|
44
51
|
|
|
52
|
+
interface SurfaceResult {
|
|
53
|
+
readonly created: string | null;
|
|
54
|
+
readonly dependency: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type TrailContextWithCompose = TrailContext & {
|
|
58
|
+
readonly compose: NonNullable<TrailContext['compose']>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const hasCompose = (ctx: TrailContext): ctx is TrailContextWithCompose =>
|
|
62
|
+
Boolean(ctx.compose);
|
|
63
|
+
|
|
45
64
|
const buildScaffoldInput = (input: ScaffoldRequest) => ({
|
|
46
65
|
...(input.dir === undefined ? {} : { dir: input.dir }),
|
|
47
66
|
name: input.name,
|
|
@@ -58,45 +77,34 @@ const buildVerifyInput = (input: VerifyRequest) => ({
|
|
|
58
77
|
name: input.name,
|
|
59
78
|
});
|
|
60
79
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
): Promise<Result<ScaffoldedProject, Error>> =>
|
|
65
|
-
follow('create.scaffold', buildScaffoldInput(input));
|
|
66
|
-
|
|
67
|
-
const addSurfaceFiles = async (
|
|
68
|
-
follow: FollowFn,
|
|
69
|
-
dir: string,
|
|
70
|
-
surfaces: readonly string[]
|
|
80
|
+
const collectSurfaceFiles = async (
|
|
81
|
+
surfaces: readonly string[],
|
|
82
|
+
addSurface: (surface: string) => Promise<Result<SurfaceResult, Error>>
|
|
71
83
|
): Promise<Result<string[], Error>> => {
|
|
72
84
|
const created: string[] = [];
|
|
73
85
|
|
|
74
86
|
for (const surface of surfaces) {
|
|
75
|
-
const result = await
|
|
76
|
-
'add.surface',
|
|
77
|
-
buildSurfaceInput(dir, surface)
|
|
78
|
-
);
|
|
87
|
+
const result = await addSurface(surface);
|
|
79
88
|
if (result.isErr()) {
|
|
80
89
|
return Result.err(result.error);
|
|
81
90
|
}
|
|
82
|
-
|
|
91
|
+
if (result.value.created !== null) {
|
|
92
|
+
created.push(result.value.created);
|
|
93
|
+
}
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
return Result.ok(created);
|
|
86
97
|
};
|
|
87
98
|
|
|
88
99
|
const collectVerifyFiles = async (
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
shouldVerify: boolean,
|
|
101
|
+
addVerify: () => Promise<Result<{ created: string[] }, Error>>
|
|
91
102
|
): Promise<Result<string[], Error>> => {
|
|
92
|
-
if (!
|
|
103
|
+
if (!shouldVerify) {
|
|
93
104
|
return Result.ok([]);
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
const result = await
|
|
97
|
-
'add.verify',
|
|
98
|
-
buildVerifyInput(input)
|
|
99
|
-
);
|
|
107
|
+
const result = await addVerify();
|
|
100
108
|
return result.isErr()
|
|
101
109
|
? Result.err(result.error)
|
|
102
110
|
: Result.ok(result.value.created);
|
|
@@ -105,48 +113,151 @@ const collectVerifyFiles = async (
|
|
|
105
113
|
const collectCreatedFiles = (
|
|
106
114
|
scaffolded: readonly string[],
|
|
107
115
|
surfaces: readonly string[],
|
|
108
|
-
verify: readonly string[]
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
): Promise<Result<{ created: string[]; dir: string; name: string }, Error>> => {
|
|
115
|
-
const scaffolded = await scaffoldProject(follow, input);
|
|
116
|
-
if (scaffolded.isErr()) {
|
|
117
|
-
return Result.err(scaffolded.error);
|
|
118
|
-
}
|
|
116
|
+
verify: readonly string[],
|
|
117
|
+
readme: string | null
|
|
118
|
+
): string[] =>
|
|
119
|
+
readme === null
|
|
120
|
+
? [...scaffolded, ...surfaces, ...verify]
|
|
121
|
+
: [...scaffolded, ...surfaces, ...verify, readme];
|
|
119
122
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
const surfaceReadmeLines = {
|
|
124
|
+
cli: '- `src/cli.ts` - CLI surface entry point',
|
|
125
|
+
http: '- `src/http.ts` - HTTP surface entry point',
|
|
126
|
+
mcp: '- `src/mcp.ts` - MCP surface entry point',
|
|
127
|
+
} satisfies Record<Surface, string>;
|
|
128
|
+
|
|
129
|
+
const starterReadmeLines = {
|
|
130
|
+
empty:
|
|
131
|
+
'Starts with an empty `src/trails/` directory for authoring from scratch.',
|
|
132
|
+
entity:
|
|
133
|
+
'Includes sample entity trails, a signal, and an in-memory store for exploration.',
|
|
134
|
+
hello: 'Includes a `hello` trail with examples for the first happy path.',
|
|
135
|
+
} satisfies Record<Starter, string>;
|
|
136
|
+
|
|
137
|
+
const generateReadme = (input: CreateInput): string => {
|
|
138
|
+
const surfaceLines = input.surfaces
|
|
139
|
+
.map((surface) => surfaceReadmeLines[surface])
|
|
140
|
+
.join('\n');
|
|
141
|
+
const verificationCommand = input.verify ? 'bun test\n' : '';
|
|
142
|
+
const verificationStructure = input.verify
|
|
143
|
+
? '- `__tests__/examples.test.ts` - examples-as-tests harness\n'
|
|
144
|
+
: '- Verification files were not generated for this project\n';
|
|
145
|
+
|
|
146
|
+
return `# ${input.name}
|
|
147
|
+
|
|
148
|
+
A Trails project. Trails is an agent-native, contract-first TypeScript framework: author a trail once with typed input, Result output, examples, intent, and meta; surface it through CLI, MCP, HTTP, or future WebSocket.
|
|
149
|
+
|
|
150
|
+
## Getting Started
|
|
151
|
+
|
|
152
|
+
\`\`\`bash
|
|
153
|
+
bun install
|
|
154
|
+
${verificationCommand}bun run warden
|
|
155
|
+
bun run survey
|
|
156
|
+
bun run guide
|
|
157
|
+
\`\`\`
|
|
158
|
+
|
|
159
|
+
## Project Structure
|
|
160
|
+
|
|
161
|
+
- \`src/app.ts\` - the topo that collects this project's trails
|
|
162
|
+
- \`src/trails/\` - trail definitions
|
|
163
|
+
${surfaceLines}
|
|
164
|
+
${verificationStructure}- \`AGENTS.md\` - project guidance for agents working in this app
|
|
128
165
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
166
|
+
## Starter
|
|
167
|
+
|
|
168
|
+
${starterReadmeLines[input.starter]}
|
|
169
|
+
|
|
170
|
+
## Next Steps
|
|
171
|
+
|
|
172
|
+
- Add a trail with \`bun run add\`
|
|
173
|
+
- Run \`bun run warden\` before review
|
|
174
|
+
- Read \`AGENTS.md\` for Trails vocabulary and conventions
|
|
175
|
+
`;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const writeReadme = async (
|
|
179
|
+
input: CreateInput,
|
|
180
|
+
dir: string
|
|
181
|
+
): Promise<Result<string | null, Error>> => {
|
|
182
|
+
const exists = projectPathExists(dir, 'README.md');
|
|
183
|
+
if (exists.isErr()) {
|
|
184
|
+
return Result.err(exists.error);
|
|
185
|
+
}
|
|
186
|
+
if (exists.value) {
|
|
187
|
+
return Result.ok(null);
|
|
132
188
|
}
|
|
133
189
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
dir: scaffolded.value.dir,
|
|
141
|
-
name: input.name,
|
|
142
|
-
});
|
|
190
|
+
const written = await writeProjectFile(
|
|
191
|
+
dir,
|
|
192
|
+
'README.md',
|
|
193
|
+
generateReadme(input)
|
|
194
|
+
);
|
|
195
|
+
return written.isErr() ? Result.err(written.error) : Result.ok('README.md');
|
|
143
196
|
};
|
|
144
197
|
|
|
145
198
|
// ---------------------------------------------------------------------------
|
|
146
|
-
//
|
|
199
|
+
// Trail definition
|
|
147
200
|
// ---------------------------------------------------------------------------
|
|
148
201
|
|
|
149
|
-
export const
|
|
202
|
+
export const createTrail = trail('create', {
|
|
203
|
+
blaze: async (input: CreateInput, ctx) => {
|
|
204
|
+
if (!hasCompose(ctx)) {
|
|
205
|
+
return Result.err(new InternalError('create trail requires ctx.compose'));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const scaffolded = await ctx.compose<ScaffoldedProject>(
|
|
209
|
+
'create.scaffold',
|
|
210
|
+
buildScaffoldInput(input)
|
|
211
|
+
);
|
|
212
|
+
if (scaffolded.isErr()) {
|
|
213
|
+
return scaffolded;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const finishCreate = async (): Promise<
|
|
217
|
+
Result<{ created: string[]; dir: string; name: string }, Error>
|
|
218
|
+
> => {
|
|
219
|
+
const surfaceFiles = await collectSurfaceFiles(
|
|
220
|
+
input.surfaces,
|
|
221
|
+
(surface) =>
|
|
222
|
+
ctx.compose<SurfaceResult>(
|
|
223
|
+
'add.surface',
|
|
224
|
+
buildSurfaceInput(scaffolded.value.dir, surface)
|
|
225
|
+
)
|
|
226
|
+
);
|
|
227
|
+
if (surfaceFiles.isErr()) {
|
|
228
|
+
return Result.err(surfaceFiles.error);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const verifyFiles = await collectVerifyFiles(input.verify, () =>
|
|
232
|
+
ctx.compose<{ created: string[] }>(
|
|
233
|
+
'add.verify',
|
|
234
|
+
buildVerifyInput(input)
|
|
235
|
+
)
|
|
236
|
+
);
|
|
237
|
+
if (verifyFiles.isErr()) {
|
|
238
|
+
return Result.err(verifyFiles.error);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const readmeFile = await writeReadme(input, scaffolded.value.dir);
|
|
242
|
+
if (readmeFile.isErr()) {
|
|
243
|
+
return Result.err(readmeFile.error);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return Result.ok({
|
|
247
|
+
created: collectCreatedFiles(
|
|
248
|
+
scaffolded.value.created,
|
|
249
|
+
surfaceFiles.value,
|
|
250
|
+
verifyFiles.value,
|
|
251
|
+
readmeFile.value
|
|
252
|
+
),
|
|
253
|
+
dir: scaffolded.value.dir,
|
|
254
|
+
name: input.name,
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
return finishCreate();
|
|
259
|
+
},
|
|
260
|
+
composes: ['create.scaffold', 'add.surface', 'add.verify'],
|
|
150
261
|
description: 'Create a new Trails project',
|
|
151
262
|
fields: {
|
|
152
263
|
starter: {
|
|
@@ -157,7 +268,7 @@ export const createRoute = hike('create', {
|
|
|
157
268
|
value: 'hello',
|
|
158
269
|
},
|
|
159
270
|
{
|
|
160
|
-
hint: '4 trails,
|
|
271
|
+
hint: '4 trails, signal, store',
|
|
161
272
|
label: 'Entity CRUD',
|
|
162
273
|
value: 'entity',
|
|
163
274
|
},
|
|
@@ -172,25 +283,27 @@ export const createRoute = hike('create', {
|
|
|
172
283
|
label: 'MCP',
|
|
173
284
|
value: 'mcp',
|
|
174
285
|
},
|
|
286
|
+
{
|
|
287
|
+
hint: 'Hono-powered HTTP endpoints',
|
|
288
|
+
label: 'HTTP',
|
|
289
|
+
value: 'http',
|
|
290
|
+
},
|
|
175
291
|
],
|
|
176
292
|
},
|
|
177
293
|
},
|
|
178
|
-
follows: ['create.scaffold', 'add.surface', 'add.verify'],
|
|
179
|
-
implementation: async (input: BlazeInput, ctx) => {
|
|
180
|
-
if (!ctx.follow) {
|
|
181
|
-
return Result.err(new Error('create route requires ctx.follow'));
|
|
182
|
-
}
|
|
183
|
-
return await runCreate(ctx.follow, input);
|
|
184
|
-
},
|
|
185
294
|
input: z.object({
|
|
186
295
|
dir: z.string().optional().describe('Parent directory'),
|
|
187
|
-
name: z
|
|
296
|
+
name: z
|
|
297
|
+
.string()
|
|
298
|
+
.regex(PROJECT_NAME_PATTERN, PROJECT_NAME_MESSAGE)
|
|
299
|
+
.describe('Project name'),
|
|
188
300
|
starter: z
|
|
189
301
|
.enum(['hello', 'entity', 'empty'])
|
|
190
302
|
.default('hello')
|
|
191
303
|
.describe('Starter trail'),
|
|
192
304
|
surfaces: z
|
|
193
|
-
.array(z.enum(['cli', 'mcp']))
|
|
305
|
+
.array(z.enum(['cli', 'http', 'mcp']))
|
|
306
|
+
.min(1)
|
|
194
307
|
.default(['cli'])
|
|
195
308
|
.describe('Surfaces'),
|
|
196
309
|
verify: z.boolean().default(true).describe('Include testing + warden'),
|
|
@@ -200,4 +313,5 @@ export const createRoute = hike('create', {
|
|
|
200
313
|
dir: z.string(),
|
|
201
314
|
name: z.string(),
|
|
202
315
|
}),
|
|
316
|
+
permit: { scopes: ['project:write'] },
|
|
203
317
|
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { trail } from '@ontrails/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
parseLifecycleTarget,
|
|
6
|
+
setVersionStatusSource,
|
|
7
|
+
withLifecycleApp,
|
|
8
|
+
} from './version-lifecycle-support.js';
|
|
9
|
+
|
|
10
|
+
export const deprecateTrail = trail('deprecate', {
|
|
11
|
+
args: ['target'],
|
|
12
|
+
blaze: async (input, ctx) =>
|
|
13
|
+
withLifecycleApp(input, ctx.cwd, async (_app, rootDir) => {
|
|
14
|
+
const target = parseLifecycleTarget(input.target);
|
|
15
|
+
if (target.isErr()) {
|
|
16
|
+
return target;
|
|
17
|
+
}
|
|
18
|
+
return setVersionStatusSource(
|
|
19
|
+
rootDir,
|
|
20
|
+
target.value,
|
|
21
|
+
input.archive ? 'archived' : 'deprecated',
|
|
22
|
+
{
|
|
23
|
+
migration: input.migration,
|
|
24
|
+
note: input.note,
|
|
25
|
+
reason: input.reason,
|
|
26
|
+
successor: input.successor,
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}),
|
|
30
|
+
description: 'Mark a historical trail version deprecated or archived',
|
|
31
|
+
input: z.object({
|
|
32
|
+
archive: z
|
|
33
|
+
.boolean()
|
|
34
|
+
.default(false)
|
|
35
|
+
.describe('Archive instead of deprecate'),
|
|
36
|
+
migration: z
|
|
37
|
+
.array(z.string())
|
|
38
|
+
.default([])
|
|
39
|
+
.describe('Migration guidance entries'),
|
|
40
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
41
|
+
note: z.string().optional().describe('Deprecation note'),
|
|
42
|
+
reason: z.string().optional().describe('Archive reason'),
|
|
43
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
44
|
+
successor: z
|
|
45
|
+
.number()
|
|
46
|
+
.int()
|
|
47
|
+
.positive()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Successor version'),
|
|
50
|
+
target: z.string().min(1).describe('Historical version target trail.id@N'),
|
|
51
|
+
}),
|
|
52
|
+
intent: 'write',
|
|
53
|
+
output: z.object({
|
|
54
|
+
file: z.string(),
|
|
55
|
+
trailId: z.string(),
|
|
56
|
+
updated: z.boolean(),
|
|
57
|
+
}),
|
|
58
|
+
permit: { scopes: ['version:write'] },
|
|
59
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Result, ValidationError, trail } from '@ontrails/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
cleanDevState,
|
|
6
|
+
DEFAULT_TOPO_SNAPSHOT_RETENTION,
|
|
7
|
+
} from './dev-support.js';
|
|
8
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
9
|
+
import { createIsolatedExampleInput } from './topo-support.js';
|
|
10
|
+
|
|
11
|
+
export const devCleanTrail = trail('dev.clean', {
|
|
12
|
+
blaze: (input, ctx) => {
|
|
13
|
+
if (input.dryRun !== true && input.yes !== true) {
|
|
14
|
+
return Result.err(
|
|
15
|
+
new ValidationError(
|
|
16
|
+
'Refusing to clean local state without `--yes` or `--dry-run`.'
|
|
17
|
+
)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
22
|
+
if (rootDirResult.isErr()) {
|
|
23
|
+
return rootDirResult;
|
|
24
|
+
}
|
|
25
|
+
const rootDir = rootDirResult.value;
|
|
26
|
+
return Result.ok(
|
|
27
|
+
cleanDevState({
|
|
28
|
+
dryRun: input.dryRun,
|
|
29
|
+
maxAge: input.traceAgeMs,
|
|
30
|
+
maxRecords: input.traces,
|
|
31
|
+
rootDir,
|
|
32
|
+
snapshotRetention: input.snapshots,
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
},
|
|
36
|
+
description: 'Prune unpinned topo snapshots and old trace records',
|
|
37
|
+
examples: [
|
|
38
|
+
{
|
|
39
|
+
input: {
|
|
40
|
+
dryRun: true,
|
|
41
|
+
rootDir: createIsolatedExampleInput('dev-clean').rootDir,
|
|
42
|
+
},
|
|
43
|
+
name: 'Preview local cleanup',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
input: z.object({
|
|
47
|
+
dryRun: z
|
|
48
|
+
.boolean()
|
|
49
|
+
.default(true)
|
|
50
|
+
.describe('Preview cleanup without changing state'),
|
|
51
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
52
|
+
snapshots: z
|
|
53
|
+
.number()
|
|
54
|
+
.default(DEFAULT_TOPO_SNAPSHOT_RETENTION)
|
|
55
|
+
.describe('Unpinned topo snapshots to retain'),
|
|
56
|
+
traceAgeMs: z
|
|
57
|
+
.number()
|
|
58
|
+
.default(7 * 24 * 60 * 60 * 1000)
|
|
59
|
+
.describe('Maximum retained trace age in milliseconds'),
|
|
60
|
+
traces: z.number().default(10_000).describe('Maximum retained trace count'),
|
|
61
|
+
yes: z.boolean().default(false).describe('Confirm destructive changes'),
|
|
62
|
+
}),
|
|
63
|
+
intent: 'destroy',
|
|
64
|
+
output: z.object({
|
|
65
|
+
dryRun: z.boolean(),
|
|
66
|
+
remaining: z.object({
|
|
67
|
+
pinnedCount: z.number(),
|
|
68
|
+
snapshotCount: z.number(),
|
|
69
|
+
traceCount: z.number(),
|
|
70
|
+
}),
|
|
71
|
+
removed: z.object({
|
|
72
|
+
topoSnapshots: z.number(),
|
|
73
|
+
traceRecords: z.number(),
|
|
74
|
+
}),
|
|
75
|
+
retention: z.object({
|
|
76
|
+
snapshots: z.number(),
|
|
77
|
+
traceAgeMs: z.number(),
|
|
78
|
+
traces: z.number(),
|
|
79
|
+
}),
|
|
80
|
+
}),
|
|
81
|
+
permit: { scopes: ['dev:write'] },
|
|
82
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Result, ValidationError, trail } from '@ontrails/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { resetDevState } from './dev-support.js';
|
|
5
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
6
|
+
import { createIsolatedExampleInput } from './topo-support.js';
|
|
7
|
+
|
|
8
|
+
export const devResetTrail = trail('dev.reset', {
|
|
9
|
+
blaze: (input, ctx) => {
|
|
10
|
+
if (input.dryRun !== true && input.yes !== true) {
|
|
11
|
+
return Result.err(
|
|
12
|
+
new ValidationError(
|
|
13
|
+
'Refusing to reset local state without `--yes` or `--dry-run`.'
|
|
14
|
+
)
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
19
|
+
if (rootDirResult.isErr()) {
|
|
20
|
+
return rootDirResult;
|
|
21
|
+
}
|
|
22
|
+
const rootDir = rootDirResult.value;
|
|
23
|
+
return Result.ok(resetDevState({ dryRun: input.dryRun, rootDir }));
|
|
24
|
+
},
|
|
25
|
+
description: 'Remove local Trails database artifacts',
|
|
26
|
+
examples: [
|
|
27
|
+
{
|
|
28
|
+
input: {
|
|
29
|
+
dryRun: true,
|
|
30
|
+
rootDir: createIsolatedExampleInput('dev-reset').rootDir,
|
|
31
|
+
},
|
|
32
|
+
name: 'Preview local reset',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
input: z.object({
|
|
36
|
+
dryRun: z
|
|
37
|
+
.boolean()
|
|
38
|
+
.default(true)
|
|
39
|
+
.describe('Preview reset without changing state'),
|
|
40
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
41
|
+
yes: z.boolean().default(false).describe('Confirm destructive changes'),
|
|
42
|
+
}),
|
|
43
|
+
intent: 'destroy',
|
|
44
|
+
output: z.object({
|
|
45
|
+
dryRun: z.boolean(),
|
|
46
|
+
removedCount: z.number(),
|
|
47
|
+
removedFiles: z.array(z.string()),
|
|
48
|
+
}),
|
|
49
|
+
permit: { scopes: ['dev:write'] },
|
|
50
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Result, trail } from '@ontrails/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
buildDevStats,
|
|
6
|
+
DEFAULT_TOPO_SNAPSHOT_RETENTION,
|
|
7
|
+
} from './dev-support.js';
|
|
8
|
+
import { resolveTrailRootDir } from './root-dir.js';
|
|
9
|
+
import { createIsolatedExampleInput } from './topo-support.js';
|
|
10
|
+
|
|
11
|
+
export const devStatsTrail = trail('dev.stats', {
|
|
12
|
+
blaze: (input, ctx) => {
|
|
13
|
+
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
14
|
+
if (rootDirResult.isErr()) {
|
|
15
|
+
return rootDirResult;
|
|
16
|
+
}
|
|
17
|
+
const rootDir = rootDirResult.value;
|
|
18
|
+
return Result.ok(
|
|
19
|
+
buildDevStats({
|
|
20
|
+
maxAge: input.traceAgeMs,
|
|
21
|
+
maxRecords: input.traces,
|
|
22
|
+
rootDir,
|
|
23
|
+
snapshotRetention: input.snapshots,
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
description: 'Show local Trails workspace state and retention',
|
|
28
|
+
examples: [
|
|
29
|
+
{
|
|
30
|
+
input: { rootDir: createIsolatedExampleInput('dev-stats').rootDir },
|
|
31
|
+
name: 'Show local dev state',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
input: z.object({
|
|
35
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
36
|
+
snapshots: z
|
|
37
|
+
.number()
|
|
38
|
+
.default(DEFAULT_TOPO_SNAPSHOT_RETENTION)
|
|
39
|
+
.describe('Unpinned topo snapshots to retain'),
|
|
40
|
+
traceAgeMs: z
|
|
41
|
+
.number()
|
|
42
|
+
.default(7 * 24 * 60 * 60 * 1000)
|
|
43
|
+
.describe('Maximum retained trace age in milliseconds'),
|
|
44
|
+
traces: z.number().default(10_000).describe('Maximum retained trace count'),
|
|
45
|
+
}),
|
|
46
|
+
intent: 'read',
|
|
47
|
+
output: z.object({
|
|
48
|
+
db: z.object({
|
|
49
|
+
exists: z.boolean(),
|
|
50
|
+
fileSizeBytes: z.number(),
|
|
51
|
+
path: z.string(),
|
|
52
|
+
}),
|
|
53
|
+
lock: z.object({
|
|
54
|
+
exists: z.boolean(),
|
|
55
|
+
fileSizeBytes: z.number(),
|
|
56
|
+
path: z.string(),
|
|
57
|
+
}),
|
|
58
|
+
retention: z.object({
|
|
59
|
+
snapshots: z.number(),
|
|
60
|
+
traceAgeMs: z.number(),
|
|
61
|
+
traces: z.number(),
|
|
62
|
+
}),
|
|
63
|
+
topo: z.object({
|
|
64
|
+
pinnedCount: z.number(),
|
|
65
|
+
prunableSnapshotCount: z.number(),
|
|
66
|
+
snapshotCount: z.number(),
|
|
67
|
+
}),
|
|
68
|
+
tracing: z.object({
|
|
69
|
+
recordCount: z.number(),
|
|
70
|
+
}),
|
|
71
|
+
}),
|
|
72
|
+
});
|