@ontrails/trails 1.0.0-beta.17 → 1.0.0-beta.19
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 +139 -0
- package/README.md +7 -10
- package/package.json +13 -12
- package/src/app.ts +14 -4
- package/src/cli.ts +16 -0
- package/src/lifecycle-source-io.ts +33 -0
- package/src/project-writes.ts +62 -5
- package/src/retired-topo-command.ts +36 -0
- package/src/run-adapter-check.ts +76 -0
- package/src/run-collision.ts +1 -0
- package/src/trails/adapter-check.ts +244 -0
- package/src/trails/add-surface.ts +18 -18
- package/src/trails/add-trail.ts +3 -2
- package/src/trails/add-verify.ts +30 -6
- package/src/trails/{topo-compile.ts → compile.ts} +16 -8
- package/src/trails/completions-complete.ts +1 -1
- package/src/trails/create-adapter.ts +1084 -0
- package/src/trails/create-scaffold.ts +243 -29
- package/src/trails/create.ts +118 -17
- package/src/trails/deprecate.ts +59 -0
- package/src/trails/dev-clean.ts +2 -2
- package/src/trails/dev-reset.ts +2 -2
- package/src/trails/dev-stats.ts +1 -1
- package/src/trails/doctor.ts +56 -0
- package/src/trails/draft-promote.ts +1 -0
- package/src/trails/guide.ts +2 -2
- package/src/trails/revise.ts +53 -0
- package/src/trails/run-example.ts +12 -7
- package/src/trails/run-examples.ts +3 -3
- package/src/trails/run.ts +7 -4
- package/src/trails/survey.ts +332 -25
- package/src/trails/topo-history.ts +1 -1
- package/src/trails/topo-output-schemas.ts +30 -1
- package/src/trails/topo-pin.ts +3 -2
- package/src/trails/topo-read-support.ts +49 -8
- package/src/trails/topo-reports.ts +39 -22
- package/src/trails/topo-store-support.ts +62 -16
- package/src/trails/topo-support.ts +1 -1
- package/src/trails/topo-unpin.ts +2 -2
- package/src/trails/topo.ts +2 -2
- package/src/trails/{topo-verify.ts → validate.ts} +7 -7
- package/src/trails/version-lifecycle-support.ts +945 -0
- package/src/trails/warden-guide.ts +8 -0
- package/src/trails/warden.ts +18 -2
- package/src/versions.ts +4 -1
|
@@ -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
|
+
});
|
package/src/trails/dev-clean.ts
CHANGED
|
@@ -20,7 +20,7 @@ export const devCleanTrail = trail('dev.clean', {
|
|
|
20
20
|
|
|
21
21
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
22
22
|
if (rootDirResult.isErr()) {
|
|
23
|
-
return
|
|
23
|
+
return rootDirResult;
|
|
24
24
|
}
|
|
25
25
|
const rootDir = rootDirResult.value;
|
|
26
26
|
return Result.ok(
|
|
@@ -78,5 +78,5 @@ export const devCleanTrail = trail('dev.clean', {
|
|
|
78
78
|
traces: z.number(),
|
|
79
79
|
}),
|
|
80
80
|
}),
|
|
81
|
-
permit: { scopes: ['dev:
|
|
81
|
+
permit: { scopes: ['dev:write'] },
|
|
82
82
|
});
|
package/src/trails/dev-reset.ts
CHANGED
|
@@ -17,7 +17,7 @@ export const devResetTrail = trail('dev.reset', {
|
|
|
17
17
|
|
|
18
18
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
19
19
|
if (rootDirResult.isErr()) {
|
|
20
|
-
return
|
|
20
|
+
return rootDirResult;
|
|
21
21
|
}
|
|
22
22
|
const rootDir = rootDirResult.value;
|
|
23
23
|
return Result.ok(resetDevState({ dryRun: input.dryRun, rootDir }));
|
|
@@ -46,5 +46,5 @@ export const devResetTrail = trail('dev.reset', {
|
|
|
46
46
|
removedCount: z.number(),
|
|
47
47
|
removedFiles: z.array(z.string()),
|
|
48
48
|
}),
|
|
49
|
-
permit: { scopes: ['dev:
|
|
49
|
+
permit: { scopes: ['dev:write'] },
|
|
50
50
|
});
|
package/src/trails/dev-stats.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const devStatsTrail = trail('dev.stats', {
|
|
|
12
12
|
blaze: (input, ctx) => {
|
|
13
13
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
14
14
|
if (rootDirResult.isErr()) {
|
|
15
|
-
return
|
|
15
|
+
return rootDirResult;
|
|
16
16
|
}
|
|
17
17
|
const rootDir = rootDirResult.value;
|
|
18
18
|
return Result.ok(
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { deriveTrailsDir, Result, trail } from '@ontrails/core';
|
|
2
|
+
import { readTopoGraph } from '@ontrails/topographer';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
deriveDoctorSummary,
|
|
7
|
+
withLifecycleApp,
|
|
8
|
+
} from './version-lifecycle-support.js';
|
|
9
|
+
|
|
10
|
+
const readDoctorForceGraph = async (
|
|
11
|
+
rootDir: string
|
|
12
|
+
): Promise<Awaited<ReturnType<typeof readTopoGraph>> | undefined> => {
|
|
13
|
+
try {
|
|
14
|
+
return await readTopoGraph({ dir: deriveTrailsDir({ rootDir }) });
|
|
15
|
+
} catch {
|
|
16
|
+
// Force audit details are supplemental; stale topo locks should not block doctor counts.
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const doctorTrail = trail('doctor', {
|
|
22
|
+
blaze: async (input, ctx) =>
|
|
23
|
+
withLifecycleApp(input, ctx.cwd, async (app, rootDir) => {
|
|
24
|
+
const forceGraph = await readDoctorForceGraph(rootDir);
|
|
25
|
+
return Result.ok(deriveDoctorSummary(app, { forceGraph }));
|
|
26
|
+
}),
|
|
27
|
+
description: 'Diagnose trail versioning lifecycle state',
|
|
28
|
+
input: z.object({
|
|
29
|
+
module: z.string().optional().describe('Path to the app module'),
|
|
30
|
+
rootDir: z.string().optional().describe('Workspace root directory'),
|
|
31
|
+
}),
|
|
32
|
+
intent: 'read',
|
|
33
|
+
output: z.object({
|
|
34
|
+
archived: z.number(),
|
|
35
|
+
deprecated: z.number(),
|
|
36
|
+
forceDetails: z.array(
|
|
37
|
+
z
|
|
38
|
+
.object({
|
|
39
|
+
acceptedAt: z.string(),
|
|
40
|
+
change: z.enum(['modified', 'removed']),
|
|
41
|
+
detail: z.string(),
|
|
42
|
+
id: z.string(),
|
|
43
|
+
kind: z.enum(['contour', 'trail', 'signal', 'resource']),
|
|
44
|
+
reason: z.string().optional(),
|
|
45
|
+
scope: z.enum(['entry', 'graph']),
|
|
46
|
+
severity: z.literal('breaking'),
|
|
47
|
+
source: z.literal('trails compile --force'),
|
|
48
|
+
})
|
|
49
|
+
.strict()
|
|
50
|
+
),
|
|
51
|
+
forceEvents: z.number(),
|
|
52
|
+
mode: z.literal('doctor'),
|
|
53
|
+
trails: z.number(),
|
|
54
|
+
versioned: z.number(),
|
|
55
|
+
}),
|
|
56
|
+
});
|
package/src/trails/guide.ts
CHANGED
|
@@ -36,12 +36,12 @@ export const guideTrail = trail('guide', {
|
|
|
36
36
|
blaze: async (input, ctx) => {
|
|
37
37
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
38
38
|
if (rootDirResult.isErr()) {
|
|
39
|
-
return
|
|
39
|
+
return rootDirResult;
|
|
40
40
|
}
|
|
41
41
|
const rootDir = rootDirResult.value;
|
|
42
42
|
const leaseResult = await tryLoadFreshAppLease(input.module, rootDir);
|
|
43
43
|
if (leaseResult.isErr()) {
|
|
44
|
-
return
|
|
44
|
+
return leaseResult;
|
|
45
45
|
}
|
|
46
46
|
const lease = leaseResult.value;
|
|
47
47
|
|
|
@@ -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
|
+
});
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
run,
|
|
11
11
|
trail,
|
|
12
12
|
} from '@ontrails/core';
|
|
13
|
-
import type { StructuredTrailExample, Topo } from '@ontrails/core';
|
|
13
|
+
import type { BasePermit, StructuredTrailExample, Topo } from '@ontrails/core';
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
|
|
16
16
|
import { tryLoadFreshAppLease } from './load-app.js';
|
|
@@ -350,7 +350,8 @@ const determineMode = (
|
|
|
350
350
|
const buildComparisonEnvelope = async (
|
|
351
351
|
app: Topo,
|
|
352
352
|
trailId: string,
|
|
353
|
-
exampleName: string
|
|
353
|
+
exampleName: string,
|
|
354
|
+
permit: BasePermit | undefined
|
|
354
355
|
): Promise<Result<RunExampleComparison, Error>> => {
|
|
355
356
|
const exampleResult = findExample(app, trailId, exampleName);
|
|
356
357
|
if (exampleResult.isErr()) {
|
|
@@ -358,7 +359,9 @@ const buildComparisonEnvelope = async (
|
|
|
358
359
|
}
|
|
359
360
|
const example = exampleResult.value;
|
|
360
361
|
const mode = determineMode(example);
|
|
361
|
-
const executed = await run(app, trailId, example.input
|
|
362
|
+
const executed = await run(app, trailId, example.input, {
|
|
363
|
+
ctx: permit === undefined ? {} : { permit },
|
|
364
|
+
});
|
|
362
365
|
const actual = projectActual(executed);
|
|
363
366
|
|
|
364
367
|
if (mode === 'error') {
|
|
@@ -425,7 +428,7 @@ export const runExampleTrail = trail('run.example', {
|
|
|
425
428
|
blaze: async (input, ctx) => {
|
|
426
429
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
427
430
|
if (rootDirResult.isErr()) {
|
|
428
|
-
return
|
|
431
|
+
return rootDirResult;
|
|
429
432
|
}
|
|
430
433
|
const rootDir = rootDirResult.value;
|
|
431
434
|
const moduleResolution = await resolveRunModulePath(
|
|
@@ -435,7 +438,7 @@ export const runExampleTrail = trail('run.example', {
|
|
|
435
438
|
input.app
|
|
436
439
|
);
|
|
437
440
|
if (moduleResolution.isErr()) {
|
|
438
|
-
return
|
|
441
|
+
return moduleResolution;
|
|
439
442
|
}
|
|
440
443
|
|
|
441
444
|
const leaseResult = await tryLoadFreshAppLease(
|
|
@@ -443,7 +446,7 @@ export const runExampleTrail = trail('run.example', {
|
|
|
443
446
|
rootDir
|
|
444
447
|
);
|
|
445
448
|
if (leaseResult.isErr()) {
|
|
446
|
-
return
|
|
449
|
+
return leaseResult;
|
|
447
450
|
}
|
|
448
451
|
const lease = leaseResult.value;
|
|
449
452
|
|
|
@@ -451,7 +454,8 @@ export const runExampleTrail = trail('run.example', {
|
|
|
451
454
|
return await buildComparisonEnvelope(
|
|
452
455
|
lease.app,
|
|
453
456
|
input.id,
|
|
454
|
-
input.exampleName
|
|
457
|
+
input.exampleName,
|
|
458
|
+
ctx.permit
|
|
455
459
|
);
|
|
456
460
|
} finally {
|
|
457
461
|
lease.release();
|
|
@@ -479,4 +483,5 @@ export const runExampleTrail = trail('run.example', {
|
|
|
479
483
|
}),
|
|
480
484
|
intent: 'write',
|
|
481
485
|
output: runExampleComparisonSchema,
|
|
486
|
+
permit: { scopes: ['trails:run'] },
|
|
482
487
|
});
|
|
@@ -89,7 +89,7 @@ export const runExamplesTrail = trail('run.examples', {
|
|
|
89
89
|
blaze: async (input, ctx) => {
|
|
90
90
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
91
91
|
if (rootDirResult.isErr()) {
|
|
92
|
-
return
|
|
92
|
+
return rootDirResult;
|
|
93
93
|
}
|
|
94
94
|
const rootDir = rootDirResult.value;
|
|
95
95
|
const moduleResolution = await resolveRunModulePath(
|
|
@@ -99,7 +99,7 @@ export const runExamplesTrail = trail('run.examples', {
|
|
|
99
99
|
input.app
|
|
100
100
|
);
|
|
101
101
|
if (moduleResolution.isErr()) {
|
|
102
|
-
return
|
|
102
|
+
return moduleResolution;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
const leaseResult = await tryLoadFreshAppLease(
|
|
@@ -107,7 +107,7 @@ export const runExamplesTrail = trail('run.examples', {
|
|
|
107
107
|
rootDir
|
|
108
108
|
);
|
|
109
109
|
if (leaseResult.isErr()) {
|
|
110
|
-
return
|
|
110
|
+
return leaseResult;
|
|
111
111
|
}
|
|
112
112
|
const lease = leaseResult.value;
|
|
113
113
|
|
package/src/trails/run.ts
CHANGED
|
@@ -322,7 +322,7 @@ export const runTrail = trail('run', {
|
|
|
322
322
|
blaze: async (input, ctx) => {
|
|
323
323
|
const rootDirResult = resolveTrailRootDir(input.rootDir, ctx.cwd);
|
|
324
324
|
if (rootDirResult.isErr()) {
|
|
325
|
-
return
|
|
325
|
+
return rootDirResult;
|
|
326
326
|
}
|
|
327
327
|
const rootDir = rootDirResult.value;
|
|
328
328
|
|
|
@@ -334,18 +334,20 @@ export const runTrail = trail('run', {
|
|
|
334
334
|
input.app
|
|
335
335
|
);
|
|
336
336
|
if (moduleResolution.isErr()) {
|
|
337
|
-
return
|
|
337
|
+
return moduleResolution;
|
|
338
338
|
}
|
|
339
339
|
const modulePath = moduleResolution.value;
|
|
340
340
|
|
|
341
341
|
const leaseResult = await tryLoadFreshAppLease(modulePath, rootDir);
|
|
342
342
|
if (leaseResult.isErr()) {
|
|
343
|
-
return
|
|
343
|
+
return leaseResult;
|
|
344
344
|
}
|
|
345
345
|
const lease = leaseResult.value;
|
|
346
346
|
|
|
347
347
|
try {
|
|
348
|
-
const result = await run(lease.app, input.id, input.input
|
|
348
|
+
const result = await run(lease.app, input.id, input.input, {
|
|
349
|
+
ctx: ctx.permit === undefined ? {} : { permit: ctx.permit },
|
|
350
|
+
});
|
|
349
351
|
if (result.isErr()) {
|
|
350
352
|
return Result.err(result.error);
|
|
351
353
|
}
|
|
@@ -400,4 +402,5 @@ export const runTrail = trail('run', {
|
|
|
400
402
|
}),
|
|
401
403
|
intent: 'write',
|
|
402
404
|
output: innerTrailResultSchema,
|
|
405
|
+
permit: { scopes: ['trails:run'] },
|
|
403
406
|
});
|