@ontrails/trails 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1906 -0
- package/README.md +48 -0
- package/bin/trails.ts +3 -0
- package/package.json +57 -0
- package/src/app.ts +167 -0
- package/src/clack.ts +111 -0
- package/src/cli.ts +308 -0
- package/src/completions.ts +431 -0
- package/src/lifecycle-source-io.ts +33 -0
- package/src/load-app-mirror.ts +202 -0
- package/src/local-state-io.ts +129 -0
- package/src/mcp-app.ts +42 -0
- package/src/mcp-options.ts +92 -0
- package/src/mcp.ts +8 -0
- package/src/project-writes.ts +377 -0
- package/src/regrade/audit.ts +571 -0
- package/src/regrade/config.ts +152 -0
- package/src/regrade/history.ts +636 -0
- package/src/regrade/lifecycle.ts +76 -0
- package/src/regrade/live-api-preserve.ts +123 -0
- package/src/regrade/plan-artifact.ts +515 -0
- package/src/regrade/plan-derivation.ts +301 -0
- package/src/regrade/prepared-run.ts +259 -0
- package/src/regrade/receipt-history.ts +446 -0
- package/src/regrade/source-transaction.ts +185 -0
- package/src/release/bindings.ts +58 -0
- package/src/release/changeset-packages.ts +99 -0
- package/src/release/check.ts +1191 -0
- package/src/release/cli-bundle.ts +575 -0
- package/src/release/config.ts +73 -0
- package/src/release/contract-facts.ts +425 -0
- package/src/release/homebrew.ts +221 -0
- package/src/release/index.ts +180 -0
- package/src/release/lock-roundtrip-smoke.ts +255 -0
- package/src/release/lock-roundtrip-workspace.ts +107 -0
- package/src/release/native-bun-publish.ts +964 -0
- package/src/release/native-bun-registry.ts +848 -0
- package/src/release/notes-cli.ts +171 -0
- package/src/release/notes.ts +390 -0
- package/src/release/pack-coherence.ts +455 -0
- package/src/release/package-route-facts.ts +146 -0
- package/src/release/packed-artifacts-smoke.ts +236 -0
- package/src/release/policy.ts +1780 -0
- package/src/release/semver.ts +104 -0
- package/src/release/smoke.ts +56 -0
- package/src/release/stable-version-release.ts +80 -0
- package/src/release/wayfinder-dogfood-smoke.ts +762 -0
- package/src/release/zero-line-transition.ts +68 -0
- package/src/retired-topo-command.ts +36 -0
- package/src/run-adapter-check.ts +76 -0
- package/src/run-argv.ts +133 -0
- package/src/run-collision.ts +126 -0
- package/src/run-completions-install.ts +179 -0
- package/src/run-example.ts +149 -0
- package/src/run-examples.ts +148 -0
- package/src/run-quiet.ts +75 -0
- package/src/run-regrade-progress.ts +47 -0
- package/src/run-release-check.ts +74 -0
- package/src/run-schema.ts +74 -0
- package/src/run-trace.ts +273 -0
- package/src/run-warden.ts +39 -0
- package/src/run-watch-project.ts +52 -0
- package/src/run-watch.ts +381 -0
- package/src/run-wayfind-outline.ts +170 -0
- package/src/scaffold-version-sync.ts +183 -0
- package/src/scaffold-versions.generated.ts +12 -0
- package/src/trails/adapter-check.ts +244 -0
- package/src/trails/add-surface.ts +816 -0
- package/src/trails/add-trail.ts +141 -0
- package/src/trails/add-verify.ts +252 -0
- package/src/trails/compile.ts +118 -0
- package/src/trails/completions-complete.ts +236 -0
- package/src/trails/completions.ts +47 -0
- package/src/trails/config-explain.ts +43 -0
- package/src/trails/create-adapter.ts +785 -0
- package/src/trails/create-scaffold.ts +1215 -0
- package/src/trails/create-versions.ts +62 -0
- package/src/trails/create.ts +652 -0
- package/src/trails/deprecate.ts +59 -0
- package/src/trails/dev-clean.ts +80 -0
- package/src/trails/dev-reset.ts +48 -0
- package/src/trails/dev-stats.ts +71 -0
- package/src/trails/dev-support.ts +360 -0
- package/src/trails/doctor.ts +77 -0
- package/src/trails/draft-promote.ts +949 -0
- package/src/trails/guide.ts +106 -0
- package/src/trails/load-app.ts +1145 -0
- package/src/trails/operator-context.ts +66 -0
- package/src/trails/project-context-output.ts +304 -0
- package/src/trails/project-context.ts +613 -0
- package/src/trails/project.ts +65 -0
- package/src/trails/regrade.ts +4951 -0
- package/src/trails/release-check.ts +113 -0
- package/src/trails/release-smoke.ts +49 -0
- package/src/trails/revise.ts +53 -0
- package/src/trails/root-dir.ts +21 -0
- package/src/trails/run-example.ts +592 -0
- package/src/trails/run-examples.ts +149 -0
- package/src/trails/run.ts +496 -0
- package/src/trails/scaffold-json.ts +60 -0
- package/src/trails/scaffold-topo-identity.ts +479 -0
- package/src/trails/survey.ts +990 -0
- package/src/trails/topo-activation.ts +14 -0
- package/src/trails/topo-constants.ts +2 -0
- package/src/trails/topo-history.ts +47 -0
- package/src/trails/topo-output-schemas.ts +259 -0
- package/src/trails/topo-pin.ts +38 -0
- package/src/trails/topo-read-support.ts +368 -0
- package/src/trails/topo-reports.ts +809 -0
- package/src/trails/topo-store-support.ts +323 -0
- package/src/trails/topo-support.ts +247 -0
- package/src/trails/topo-unpin.ts +61 -0
- package/src/trails/topo.ts +92 -0
- package/src/trails/validate.ts +348 -0
- package/src/trails/version-lifecycle-support.ts +936 -0
- package/src/trails/warden-guide.ts +134 -0
- package/src/trails/warden.ts +598 -0
- package/src/trails/wayfind-diff.ts +716 -0
- package/src/trails/wayfind-outline.ts +876 -0
- package/src/trails/wayfind.ts +1319 -0
- package/src/versions.ts +31 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/* oxlint-disable eslint-plugin-jest/require-hook, max-statements -- end-to-end package smoke with temp consumer setup */
|
|
2
|
+
/**
|
|
3
|
+
* Packs public first-party packages into tarballs, installs them into a
|
|
4
|
+
* scratch consumer with first-party overrides, and runs the Warden/Trails CLI
|
|
5
|
+
* from the packed artifacts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { mkdir, mkdtemp, readdir, rm, writeFile } from 'node:fs/promises';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
11
|
+
|
|
12
|
+
const REPO_ROOT = resolve(process.cwd());
|
|
13
|
+
|
|
14
|
+
interface PackedSmokePackageJson {
|
|
15
|
+
readonly name?: string;
|
|
16
|
+
readonly private?: boolean;
|
|
17
|
+
readonly version?: string;
|
|
18
|
+
readonly workspaces?: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PackedSmokeWorkspace {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly path: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PackedArtifactsSmokeResult {
|
|
27
|
+
readonly check: 'packed-artifacts';
|
|
28
|
+
readonly message: string;
|
|
29
|
+
readonly packageCount: number;
|
|
30
|
+
readonly passed: true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const commandText = (cmd: readonly string[]): string => cmd.join(' ');
|
|
34
|
+
|
|
35
|
+
const readJson = async <T>(path: string): Promise<T> =>
|
|
36
|
+
(await Bun.file(path).json()) as T;
|
|
37
|
+
|
|
38
|
+
const lastOutputLine = (output: string): string => {
|
|
39
|
+
const line = output
|
|
40
|
+
.split(/\r?\n/)
|
|
41
|
+
.map((item) => item.trim())
|
|
42
|
+
.findLast((item) => item.length > 0);
|
|
43
|
+
if (line === undefined) {
|
|
44
|
+
throw new Error('Expected command output, received none');
|
|
45
|
+
}
|
|
46
|
+
return line;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const runCapture = async (
|
|
50
|
+
cmd: readonly string[],
|
|
51
|
+
cwd: string
|
|
52
|
+
): Promise<string> => {
|
|
53
|
+
const proc = Bun.spawn(cmd as string[], {
|
|
54
|
+
cwd,
|
|
55
|
+
stderr: 'pipe',
|
|
56
|
+
stdin: 'ignore',
|
|
57
|
+
stdout: 'pipe',
|
|
58
|
+
});
|
|
59
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
60
|
+
new Response(proc.stdout).text(),
|
|
61
|
+
new Response(proc.stderr).text(),
|
|
62
|
+
proc.exited,
|
|
63
|
+
]);
|
|
64
|
+
if (exitCode !== 0) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
[
|
|
67
|
+
`Command failed in ${cwd}: ${commandText(cmd)}`,
|
|
68
|
+
`exit: ${exitCode}`,
|
|
69
|
+
stdout.trim() ? `stdout:\n${stdout}` : undefined,
|
|
70
|
+
stderr.trim() ? `stderr:\n${stderr}` : undefined,
|
|
71
|
+
]
|
|
72
|
+
.filter((line): line is string => typeof line === 'string')
|
|
73
|
+
.join('\n')
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return stdout || stderr;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const workspaceDirs = async (): Promise<readonly string[]> => {
|
|
80
|
+
const rootPackage = await readJson<PackedSmokePackageJson>(
|
|
81
|
+
join(REPO_ROOT, 'package.json')
|
|
82
|
+
);
|
|
83
|
+
const dirs: string[] = [];
|
|
84
|
+
for (const pattern of rootPackage.workspaces ?? []) {
|
|
85
|
+
if (!pattern.endsWith('/*')) {
|
|
86
|
+
throw new Error(`Unsupported workspace pattern: ${pattern}`);
|
|
87
|
+
}
|
|
88
|
+
const base = join(REPO_ROOT, pattern.slice(0, -2));
|
|
89
|
+
for (const entry of await readdir(base, { withFileTypes: true })) {
|
|
90
|
+
const dir = join(base, entry.name);
|
|
91
|
+
if (
|
|
92
|
+
entry.isDirectory() &&
|
|
93
|
+
(await Bun.file(join(dir, 'package.json')).exists())
|
|
94
|
+
) {
|
|
95
|
+
dirs.push(dir);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return dirs.toSorted((a, b) => a.localeCompare(b));
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const publicFirstPartyWorkspaces = async (): Promise<
|
|
103
|
+
readonly PackedSmokeWorkspace[]
|
|
104
|
+
> => {
|
|
105
|
+
const workspaces: PackedSmokeWorkspace[] = [];
|
|
106
|
+
for (const path of await workspaceDirs()) {
|
|
107
|
+
const packageJson = await readJson<PackedSmokePackageJson>(
|
|
108
|
+
join(path, 'package.json')
|
|
109
|
+
);
|
|
110
|
+
if (
|
|
111
|
+
packageJson.private !== true &&
|
|
112
|
+
packageJson.name?.startsWith('@ontrails/') &&
|
|
113
|
+
packageJson.version !== undefined
|
|
114
|
+
) {
|
|
115
|
+
workspaces.push({
|
|
116
|
+
name: packageJson.name,
|
|
117
|
+
path,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return workspaces.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const packWorkspace = async (
|
|
125
|
+
workspace: PackedSmokeWorkspace,
|
|
126
|
+
packRoot: string
|
|
127
|
+
): Promise<string> => {
|
|
128
|
+
const output = await runCapture(
|
|
129
|
+
['bun', 'pm', 'pack', '--destination', packRoot, '--quiet'],
|
|
130
|
+
workspace.path
|
|
131
|
+
);
|
|
132
|
+
const tarball = lastOutputLine(output);
|
|
133
|
+
const destinationPath = isAbsolute(tarball)
|
|
134
|
+
? tarball
|
|
135
|
+
: join(packRoot, tarball);
|
|
136
|
+
if (await Bun.file(destinationPath).exists()) {
|
|
137
|
+
return destinationPath;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(
|
|
140
|
+
`bun pm pack did not create expected tarball for ${workspace.name}: ${destinationPath} (destination: ${packRoot})`
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const writeConsumerManifest = async (
|
|
145
|
+
consumerRoot: string,
|
|
146
|
+
tarballsByName: ReadonlyMap<string, string>
|
|
147
|
+
): Promise<void> => {
|
|
148
|
+
const tarballDependencies = Object.fromEntries(
|
|
149
|
+
[...tarballsByName.entries()].map(([name, tarball]) => [
|
|
150
|
+
name,
|
|
151
|
+
`file:${tarball}`,
|
|
152
|
+
])
|
|
153
|
+
);
|
|
154
|
+
await writeFile(
|
|
155
|
+
join(consumerRoot, 'package.json'),
|
|
156
|
+
`${JSON.stringify(
|
|
157
|
+
{
|
|
158
|
+
dependencies: tarballDependencies,
|
|
159
|
+
overrides: tarballDependencies,
|
|
160
|
+
private: true,
|
|
161
|
+
type: 'module',
|
|
162
|
+
},
|
|
163
|
+
null,
|
|
164
|
+
2
|
|
165
|
+
)}\n`
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const binPath = (consumerRoot: string, name: 'trails' | 'warden'): string =>
|
|
170
|
+
join(consumerRoot, 'node_modules', '.bin', name);
|
|
171
|
+
|
|
172
|
+
export const runPackedArtifactsSmoke =
|
|
173
|
+
async (): Promise<PackedArtifactsSmokeResult> => {
|
|
174
|
+
const tempRoot = await mkdtemp(join(tmpdir(), 'trails-packed-dogfood-'));
|
|
175
|
+
const packRoot = join(tempRoot, 'pack');
|
|
176
|
+
const consumerRoot = join(tempRoot, 'consumer');
|
|
177
|
+
let succeeded = false;
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
await Promise.all([
|
|
181
|
+
mkdir(packRoot, { recursive: true }),
|
|
182
|
+
mkdir(consumerRoot, { recursive: true }),
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
const workspaces = await publicFirstPartyWorkspaces();
|
|
186
|
+
const tarballsByName = new Map<string, string>();
|
|
187
|
+
for (const workspace of workspaces) {
|
|
188
|
+
tarballsByName.set(
|
|
189
|
+
workspace.name,
|
|
190
|
+
await packWorkspace(workspace, packRoot)
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
await writeConsumerManifest(consumerRoot, tarballsByName);
|
|
195
|
+
await runCapture(['bun', 'install', '--silent'], consumerRoot);
|
|
196
|
+
|
|
197
|
+
await runCapture(
|
|
198
|
+
[
|
|
199
|
+
binPath(consumerRoot, 'warden'),
|
|
200
|
+
'--root-dir',
|
|
201
|
+
REPO_ROOT,
|
|
202
|
+
'--lock',
|
|
203
|
+
'skip',
|
|
204
|
+
'--format',
|
|
205
|
+
'summary',
|
|
206
|
+
],
|
|
207
|
+
REPO_ROOT
|
|
208
|
+
);
|
|
209
|
+
await runCapture([binPath(consumerRoot, 'trails'), '--help'], REPO_ROOT);
|
|
210
|
+
await runCapture(
|
|
211
|
+
[binPath(consumerRoot, 'trails'), 'warden', '--lock', 'skip'],
|
|
212
|
+
REPO_ROOT
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
succeeded = true;
|
|
216
|
+
return {
|
|
217
|
+
check: 'packed-artifacts',
|
|
218
|
+
message: `Packed artifact smoke passed for ${workspaces.length} @ontrails/* packages.`,
|
|
219
|
+
packageCount: workspaces.length,
|
|
220
|
+
passed: true,
|
|
221
|
+
};
|
|
222
|
+
} finally {
|
|
223
|
+
if (succeeded) {
|
|
224
|
+
await rm(tempRoot, { force: true, recursive: true });
|
|
225
|
+
} else {
|
|
226
|
+
console.error(
|
|
227
|
+
`Packed dogfood temp root kept for inspection: ${tempRoot}`
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
if (import.meta.main) {
|
|
234
|
+
const result = await runPackedArtifactsSmoke();
|
|
235
|
+
console.log(result.message);
|
|
236
|
+
}
|