@ontrails/trails 1.0.0-beta.42 → 1.0.0-beta.45
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 +70 -0
- package/README.md +1 -1
- package/package.json +21 -17
- package/src/mcp-options.ts +1 -0
- package/src/regrade/audit.ts +482 -0
- package/src/regrade/history.ts +250 -42
- package/src/regrade/live-api-preserve.ts +117 -2
- package/src/regrade/plan-artifact.ts +192 -13
- package/src/regrade/plan-derivation.ts +301 -0
- package/src/regrade/source-transaction.ts +75 -0
- package/src/release/bindings.ts +22 -3
- package/src/release/check.ts +312 -10
- package/src/release/config.ts +10 -0
- package/src/release/index.ts +12 -0
- package/src/release/native-bun-publish.ts +403 -90
- package/src/release/native-bun-registry.ts +102 -37
- package/src/release/package-route-facts.ts +146 -0
- package/src/release/policy.ts +2 -2
- package/src/run-completions-install.ts +4 -4
- package/src/run-trace.ts +4 -4
- package/src/trails/dev-support.ts +1 -1
- package/src/trails/regrade.ts +803 -126
- package/src/trails/release-check.ts +8 -0
- package/src/trails/run-example.ts +2 -2
- package/src/trails/survey.ts +6 -6
- package/src/trails/topo-output-schemas.ts +8 -8
- package/src/trails/topo-reports.ts +44 -44
- package/src/trails/topo-store-support.ts +2 -4
- package/src/trails/warden-guide.ts +1 -1
|
@@ -43,6 +43,7 @@ export type RegistryResult =
|
|
|
43
43
|
readonly status: 'published';
|
|
44
44
|
readonly version: string;
|
|
45
45
|
readonly versionPublished: boolean | undefined;
|
|
46
|
+
readonly versionProof?: RegistryVersionProof | undefined;
|
|
46
47
|
readonly workspaceVersion: string;
|
|
47
48
|
}
|
|
48
49
|
| {
|
|
@@ -82,18 +83,20 @@ export interface PackageRegistryFacts {
|
|
|
82
83
|
readonly error?: string | undefined;
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
/** Consumer-facing evidence for an exact package version. */
|
|
87
|
+
export type RegistryVersionProof =
|
|
88
|
+
| { readonly kind: 'consumer-pack'; readonly published: true }
|
|
89
|
+
| { readonly kind: 'exact-metadata'; readonly published: true }
|
|
90
|
+
| { readonly kind: 'unavailable'; readonly published: false };
|
|
91
|
+
|
|
85
92
|
/**
|
|
86
93
|
* Classify a package's registry state from two orthogonal facts — whether the
|
|
87
94
|
* target version is published, and where the dist-tag points relative to it —
|
|
88
95
|
* plus reachability. Members are mutually exclusive by construction.
|
|
89
96
|
*
|
|
90
|
-
* `
|
|
91
|
-
*
|
|
92
|
-
* `undefined`
|
|
93
|
-
* release-policy behavior. When the tag already points at the target, an
|
|
94
|
-
* unprobed (`undefined`) state counts as published and yields `complete`, which
|
|
95
|
-
* matches the policy `versionPublished ?? true` default. `undefined` means the
|
|
96
|
-
* exact-version probe was not run, including policy inputs and compatibility
|
|
97
|
+
* `complete` requires affirmative consumer proof. A matching dist-tag cannot
|
|
98
|
+
* substitute for exact-version metadata or an equivalent package fetch.
|
|
99
|
+
* `undefined` means the consumer probe was not run, including compatibility
|
|
97
100
|
* callers that supply an injected registry view without a version probe.
|
|
98
101
|
*/
|
|
99
102
|
export const classifyPackageRegistryState = (
|
|
@@ -120,9 +123,9 @@ export const classifyPackageRegistryState = (
|
|
|
120
123
|
return { currentTagVersion: expectedTagVersion, kind: 'tag-points-ahead' };
|
|
121
124
|
}
|
|
122
125
|
if (tagAtTarget) {
|
|
123
|
-
return versionPublished ===
|
|
124
|
-
? { kind: '
|
|
125
|
-
: { kind: '
|
|
126
|
+
return versionPublished === true
|
|
127
|
+
? { kind: 'complete' }
|
|
128
|
+
: { kind: 'needs-publish' };
|
|
126
129
|
}
|
|
127
130
|
if (versionPublished === true) {
|
|
128
131
|
return { currentTagVersion: expectedTagVersion, kind: 'needs-tag-repair' };
|
|
@@ -131,13 +134,16 @@ export const classifyPackageRegistryState = (
|
|
|
131
134
|
};
|
|
132
135
|
|
|
133
136
|
/** Map a registry probe result into the classifier's fact shape. */
|
|
134
|
-
const
|
|
137
|
+
export const factsFromRegistryResult = (
|
|
138
|
+
result: RegistryResult
|
|
139
|
+
): PackageRegistryFacts => {
|
|
135
140
|
if (result.status === 'published') {
|
|
136
141
|
return {
|
|
137
142
|
expectedTagVersion: result.expectedTagVersion,
|
|
138
143
|
status: 'published',
|
|
139
144
|
targetVersion: result.workspaceVersion,
|
|
140
|
-
versionPublished:
|
|
145
|
+
versionPublished:
|
|
146
|
+
result.versionProof?.published ?? result.versionPublished,
|
|
141
147
|
};
|
|
142
148
|
}
|
|
143
149
|
if (result.status === 'inaccessible') {
|
|
@@ -165,7 +171,8 @@ Options:
|
|
|
165
171
|
--tag <tag> Expected npm dist-tag. Defaults to .changeset/pre.json
|
|
166
172
|
tag while in prerelease mode, otherwise "latest".
|
|
167
173
|
--require-published Fail when any workspace package is missing from npm.
|
|
168
|
-
Use after publication to
|
|
174
|
+
Use after publication to require exact metadata or
|
|
175
|
+
equivalent consumer package-fetch proof.
|
|
169
176
|
-h, --help Show this help and exit.
|
|
170
177
|
|
|
171
178
|
Exit codes: 0 success, 1 registry posture failure, 2 arg-parse error.`;
|
|
@@ -459,12 +466,23 @@ export type RegistryVersionView = (
|
|
|
459
466
|
version: string
|
|
460
467
|
) => Promise<boolean | undefined>;
|
|
461
468
|
|
|
469
|
+
/** Probe with evidence that distinguishes metadata from package fetch proof. */
|
|
470
|
+
export type RegistryVersionProofView = (
|
|
471
|
+
name: string,
|
|
472
|
+
version: string
|
|
473
|
+
) => Promise<RegistryVersionProof>;
|
|
474
|
+
|
|
475
|
+
export type RegistryVersionProbeView = (
|
|
476
|
+
name: string,
|
|
477
|
+
version: string
|
|
478
|
+
) => Promise<boolean | RegistryVersionProof | undefined>;
|
|
479
|
+
|
|
462
480
|
const UNKNOWN_REGISTRY_VERSION_STATE: { readonly published?: boolean } = {};
|
|
463
481
|
const unknownRegistryVersionView: RegistryVersionView = async () =>
|
|
464
482
|
UNKNOWN_REGISTRY_VERSION_STATE.published;
|
|
465
483
|
|
|
466
|
-
export const
|
|
467
|
-
(runNpm: NpmCommandRunner = runNpmCommand):
|
|
484
|
+
export const createNpmRegistryVersionProofView =
|
|
485
|
+
(runNpm: NpmCommandRunner = runNpmCommand): RegistryVersionProofView =>
|
|
468
486
|
async (name, version) => {
|
|
469
487
|
const { exitCode, stderr, stdout } = await runNpm([
|
|
470
488
|
'view',
|
|
@@ -474,12 +492,14 @@ export const createNpmRegistryVersionView =
|
|
|
474
492
|
]);
|
|
475
493
|
|
|
476
494
|
if (exitCode === 0) {
|
|
477
|
-
return JSON.parse(stdout.trim()) === version
|
|
495
|
+
return JSON.parse(stdout.trim()) === version
|
|
496
|
+
? { kind: 'exact-metadata', published: true }
|
|
497
|
+
: { kind: 'unavailable', published: false };
|
|
478
498
|
}
|
|
479
|
-
if (
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
499
|
+
if (
|
|
500
|
+
!isNpmExactVersionMissingOutput(stdout, stderr) &&
|
|
501
|
+
!isNpmNotFoundOutput(stdout, stderr)
|
|
502
|
+
) {
|
|
483
503
|
throw new Error(
|
|
484
504
|
stderr.trim() || `npm view failed for ${name}@${version}`
|
|
485
505
|
);
|
|
@@ -496,21 +516,35 @@ export const createNpmRegistryVersionView =
|
|
|
496
516
|
packResult.stdout,
|
|
497
517
|
name,
|
|
498
518
|
version
|
|
499
|
-
)
|
|
519
|
+
)
|
|
520
|
+
? { kind: 'consumer-pack', published: true }
|
|
521
|
+
: { kind: 'unavailable', published: false };
|
|
500
522
|
}
|
|
501
523
|
if (isNpmExactVersionMissingOutput(packResult.stdout, packResult.stderr)) {
|
|
502
|
-
return false;
|
|
524
|
+
return { kind: 'unavailable', published: false };
|
|
503
525
|
}
|
|
504
526
|
if (isNpmNotFoundOutput(packResult.stdout, packResult.stderr)) {
|
|
505
|
-
return false;
|
|
527
|
+
return { kind: 'unavailable', published: false };
|
|
506
528
|
}
|
|
507
529
|
throw new Error(
|
|
508
530
|
packResult.stderr.trim() || `npm pack failed for ${name}@${version}`
|
|
509
531
|
);
|
|
510
532
|
};
|
|
511
533
|
|
|
534
|
+
export const createNpmRegistryVersionView = (
|
|
535
|
+
runNpm: NpmCommandRunner = runNpmCommand
|
|
536
|
+
): RegistryVersionView => {
|
|
537
|
+
const proofView = createNpmRegistryVersionProofView(runNpm);
|
|
538
|
+
return async (name, version) => {
|
|
539
|
+
const proof = await proofView(name, version);
|
|
540
|
+
return proof.published;
|
|
541
|
+
};
|
|
542
|
+
};
|
|
543
|
+
|
|
512
544
|
export const npmRegistryVersionView: RegistryVersionView =
|
|
513
545
|
createNpmRegistryVersionView();
|
|
546
|
+
export const npmRegistryVersionProofView: RegistryVersionProofView =
|
|
547
|
+
createNpmRegistryVersionProofView();
|
|
514
548
|
|
|
515
549
|
/** Run async tasks with a bounded number in flight, preserving input order. */
|
|
516
550
|
const mapBounded = async <T, R>(
|
|
@@ -536,7 +570,7 @@ const mapBounded = async <T, R>(
|
|
|
536
570
|
const checkWorkspaceRegistryPosture = async (
|
|
537
571
|
workspace: RegistryWorkspace,
|
|
538
572
|
view: RegistryView,
|
|
539
|
-
versionView:
|
|
573
|
+
versionView: RegistryVersionProbeView,
|
|
540
574
|
expectedTag: string
|
|
541
575
|
): Promise<RegistryResult> => {
|
|
542
576
|
try {
|
|
@@ -549,13 +583,19 @@ const checkWorkspaceRegistryPosture = async (
|
|
|
549
583
|
};
|
|
550
584
|
}
|
|
551
585
|
const distTags = registry['dist-tags'] ?? {};
|
|
586
|
+
const versionProbe = await versionView(workspace.name, workspace.version);
|
|
587
|
+
const versionProof =
|
|
588
|
+
typeof versionProbe === 'object' ? versionProbe : undefined;
|
|
589
|
+
const versionPublished =
|
|
590
|
+
typeof versionProbe === 'object' ? versionProbe.published : versionProbe;
|
|
552
591
|
return {
|
|
553
592
|
distTags,
|
|
554
593
|
expectedTagVersion: distTags[expectedTag],
|
|
555
594
|
name: workspace.name,
|
|
556
595
|
status: 'published',
|
|
557
596
|
version: registry.version ?? '(unknown)',
|
|
558
|
-
|
|
597
|
+
...(versionProof === undefined ? {} : { versionProof }),
|
|
598
|
+
versionPublished,
|
|
559
599
|
workspaceVersion: workspace.version,
|
|
560
600
|
};
|
|
561
601
|
} catch (error) {
|
|
@@ -569,14 +609,14 @@ const checkWorkspaceRegistryPosture = async (
|
|
|
569
609
|
};
|
|
570
610
|
|
|
571
611
|
type CheckRegistryPostureArgs =
|
|
572
|
-
| readonly [versionView:
|
|
612
|
+
| readonly [versionView: RegistryVersionProbeView, expectedTag: string]
|
|
573
613
|
| readonly [expectedTag: string];
|
|
574
614
|
|
|
575
615
|
const normalizeCheckRegistryPostureArgs = (
|
|
576
616
|
args: CheckRegistryPostureArgs
|
|
577
617
|
): {
|
|
578
618
|
readonly expectedTag: string;
|
|
579
|
-
readonly versionView:
|
|
619
|
+
readonly versionView: RegistryVersionProbeView;
|
|
580
620
|
} => {
|
|
581
621
|
if (args.length === 1) {
|
|
582
622
|
return { expectedTag: args[0], versionView: unknownRegistryVersionView };
|
|
@@ -592,7 +632,7 @@ export function checkRegistryPosture(
|
|
|
592
632
|
export function checkRegistryPosture(
|
|
593
633
|
workspaces: readonly RegistryWorkspace[],
|
|
594
634
|
view: RegistryView,
|
|
595
|
-
versionView:
|
|
635
|
+
versionView: RegistryVersionProbeView,
|
|
596
636
|
expectedTag: string
|
|
597
637
|
): Promise<RegistryResult[]>;
|
|
598
638
|
export async function checkRegistryPosture(
|
|
@@ -624,6 +664,19 @@ const normalizeRegistryCheckPhase = (
|
|
|
624
664
|
return phaseOrRequirePublished ? 'published' : 'ready';
|
|
625
665
|
};
|
|
626
666
|
|
|
667
|
+
const targetVersionFailure = (result: RegistryResult): string => {
|
|
668
|
+
if (result.status !== 'published') {
|
|
669
|
+
return 'is not published';
|
|
670
|
+
}
|
|
671
|
+
if (result.versionProof?.kind === 'unavailable') {
|
|
672
|
+
return 'lacks exact-version metadata and consumer pack proof';
|
|
673
|
+
}
|
|
674
|
+
if (result.versionPublished === undefined) {
|
|
675
|
+
return 'publish state was not probed';
|
|
676
|
+
}
|
|
677
|
+
return 'is not published';
|
|
678
|
+
};
|
|
679
|
+
|
|
627
680
|
export const registryPostureErrors = (
|
|
628
681
|
results: readonly RegistryResult[],
|
|
629
682
|
expectedTag: string,
|
|
@@ -632,7 +685,7 @@ export const registryPostureErrors = (
|
|
|
632
685
|
const phase = normalizeRegistryCheckPhase(phaseOrRequirePublished);
|
|
633
686
|
const errors: string[] = [];
|
|
634
687
|
for (const result of results) {
|
|
635
|
-
const state = classifyPackageRegistryState(
|
|
688
|
+
const state = classifyPackageRegistryState(factsFromRegistryResult(result));
|
|
636
689
|
if (state.kind === 'registry-inaccessible') {
|
|
637
690
|
errors.push(`${result.name}: registry probe failed: ${state.error}`);
|
|
638
691
|
continue;
|
|
@@ -649,12 +702,8 @@ export const registryPostureErrors = (
|
|
|
649
702
|
if (state.kind === 'first-time-package') {
|
|
650
703
|
errors.push(`${result.name}: package is missing from the registry`);
|
|
651
704
|
} else if (state.kind === 'needs-publish') {
|
|
652
|
-
const targetState =
|
|
653
|
-
result.status === 'published' && result.versionPublished === undefined
|
|
654
|
-
? 'publish state was not probed'
|
|
655
|
-
: 'is not published';
|
|
656
705
|
errors.push(
|
|
657
|
-
`${result.name}: target version ${result.workspaceVersion} ${
|
|
706
|
+
`${result.name}: target version ${result.workspaceVersion} ${targetVersionFailure(result)}`
|
|
658
707
|
);
|
|
659
708
|
} else if (state.kind === 'needs-tag-repair') {
|
|
660
709
|
errors.push(
|
|
@@ -673,8 +722,18 @@ export const formatDistTagSummary = (
|
|
|
673
722
|
);
|
|
674
723
|
|
|
675
724
|
const formatTargetVersionStatus = (
|
|
725
|
+
proof: RegistryVersionProof | undefined,
|
|
676
726
|
versionPublished: boolean | undefined
|
|
677
727
|
): string => {
|
|
728
|
+
if (proof?.kind === 'exact-metadata') {
|
|
729
|
+
return 'exact-version metadata available';
|
|
730
|
+
}
|
|
731
|
+
if (proof?.kind === 'consumer-pack') {
|
|
732
|
+
return 'exact-version metadata unavailable, consumer pack available';
|
|
733
|
+
}
|
|
734
|
+
if (proof?.kind === 'unavailable') {
|
|
735
|
+
return 'exact-version metadata and consumer pack unavailable';
|
|
736
|
+
}
|
|
678
737
|
if (versionPublished === true) {
|
|
679
738
|
return 'target version published';
|
|
680
739
|
}
|
|
@@ -691,7 +750,10 @@ const printResults = (
|
|
|
691
750
|
console.log(`Registry preflight for dist-tag "${expectedTag}"`);
|
|
692
751
|
for (const result of results) {
|
|
693
752
|
if (result.status === 'published') {
|
|
694
|
-
const targetStatus = formatTargetVersionStatus(
|
|
753
|
+
const targetStatus = formatTargetVersionStatus(
|
|
754
|
+
result.versionProof,
|
|
755
|
+
result.versionPublished
|
|
756
|
+
);
|
|
695
757
|
console.log(
|
|
696
758
|
`✓ ${result.name}@${result.workspaceVersion}: package exists, ${targetStatus} (registry version ${result.version}, expected ${expectedTag}=${result.expectedTagVersion ?? 'missing'}, tags ${formatDistTagSummary(result.distTags)})`
|
|
697
759
|
);
|
|
@@ -709,11 +771,14 @@ const normalizeRegistryPreflightViews = (
|
|
|
709
771
|
view: RegistryView | undefined,
|
|
710
772
|
versionView: RegistryVersionView | undefined
|
|
711
773
|
): {
|
|
712
|
-
readonly versionView:
|
|
774
|
+
readonly versionView: RegistryVersionProbeView;
|
|
713
775
|
readonly view: RegistryView;
|
|
714
776
|
} => {
|
|
715
777
|
if (view === undefined) {
|
|
716
|
-
return {
|
|
778
|
+
return {
|
|
779
|
+
versionView: npmRegistryVersionProofView,
|
|
780
|
+
view: npmRegistryView,
|
|
781
|
+
};
|
|
717
782
|
}
|
|
718
783
|
return { versionView: versionView ?? unknownRegistryVersionView, view };
|
|
719
784
|
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { listGovernedVocabularyTransitions } from '@ontrails/warden';
|
|
2
|
+
|
|
3
|
+
import type { WorkspaceInfo } from './check.js';
|
|
4
|
+
|
|
5
|
+
export interface PackageRouteReleaseFact {
|
|
6
|
+
readonly kind: 'classified' | 'single';
|
|
7
|
+
readonly sourcePackage: string;
|
|
8
|
+
readonly targetPackage?: string;
|
|
9
|
+
readonly transitionId: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PackageRouteReleaseDiagnostic {
|
|
13
|
+
readonly code:
|
|
14
|
+
| 'missing-governed-package-route'
|
|
15
|
+
| 'missing-governed-package-route-target';
|
|
16
|
+
readonly message: string;
|
|
17
|
+
readonly sourcePackage: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PackageRouteReleaseIntent {
|
|
21
|
+
readonly eligiblePackages: readonly string[];
|
|
22
|
+
readonly sourcePackage: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isPublishableTrailsPackage = (workspace: WorkspaceInfo): boolean =>
|
|
26
|
+
!workspace.isPrivate && workspace.name.startsWith('@ontrails/');
|
|
27
|
+
|
|
28
|
+
const findPackageRouteTransition = (
|
|
29
|
+
transitions: ReturnType<typeof listGovernedVocabularyTransitions>,
|
|
30
|
+
sourcePackage: string
|
|
31
|
+
) => {
|
|
32
|
+
const direct = transitions.find(
|
|
33
|
+
(transition) => transition.from === sourcePackage
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (direct) {
|
|
37
|
+
return { target: direct.target, transition: direct };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (const transition of transitions) {
|
|
41
|
+
const moduleSpecifierRoute = transition.stringLiteralRenames.find(
|
|
42
|
+
(route) =>
|
|
43
|
+
route.from === sourcePackage &&
|
|
44
|
+
route.moduleSpecifier?.targetPackage !== undefined
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (moduleSpecifierRoute?.moduleSpecifier?.targetPackage) {
|
|
48
|
+
return {
|
|
49
|
+
target: {
|
|
50
|
+
kind: 'single' as const,
|
|
51
|
+
to: moduleSpecifierRoute.moduleSpecifier.targetPackage,
|
|
52
|
+
},
|
|
53
|
+
transition,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return null;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const findPackageRouteReleaseFacts = ({
|
|
62
|
+
baseWorkspaces,
|
|
63
|
+
workspaces,
|
|
64
|
+
}: {
|
|
65
|
+
readonly baseWorkspaces: readonly WorkspaceInfo[];
|
|
66
|
+
readonly workspaces: readonly WorkspaceInfo[];
|
|
67
|
+
}): {
|
|
68
|
+
readonly diagnostics: readonly PackageRouteReleaseDiagnostic[];
|
|
69
|
+
readonly facts: readonly PackageRouteReleaseFact[];
|
|
70
|
+
readonly intents: readonly PackageRouteReleaseIntent[];
|
|
71
|
+
} => {
|
|
72
|
+
const currentPackages = new Set(
|
|
73
|
+
workspaces
|
|
74
|
+
.filter(isPublishableTrailsPackage)
|
|
75
|
+
.map((workspace) => workspace.name)
|
|
76
|
+
);
|
|
77
|
+
const removedPackages = baseWorkspaces
|
|
78
|
+
.filter(isPublishableTrailsPackage)
|
|
79
|
+
.map((workspace) => workspace.name)
|
|
80
|
+
.filter((name) => !currentPackages.has(name))
|
|
81
|
+
.toSorted();
|
|
82
|
+
const transitions = listGovernedVocabularyTransitions();
|
|
83
|
+
const diagnostics: PackageRouteReleaseDiagnostic[] = [];
|
|
84
|
+
const facts: PackageRouteReleaseFact[] = [];
|
|
85
|
+
const intents: PackageRouteReleaseIntent[] = [];
|
|
86
|
+
|
|
87
|
+
for (const sourcePackage of removedPackages) {
|
|
88
|
+
const resolvedRoute = findPackageRouteTransition(
|
|
89
|
+
transitions,
|
|
90
|
+
sourcePackage
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (!resolvedRoute) {
|
|
94
|
+
diagnostics.push({
|
|
95
|
+
code: 'missing-governed-package-route',
|
|
96
|
+
message: `Public package removal '${sourcePackage}' requires an exact governed Regrade route. Add the route to the governed transition registry, then run trails regrade plan/check.`,
|
|
97
|
+
sourcePackage,
|
|
98
|
+
});
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { target, transition } = resolvedRoute;
|
|
103
|
+
|
|
104
|
+
if (target.kind === 'classified') {
|
|
105
|
+
const classifiedTarget = target;
|
|
106
|
+
const eligiblePackages = [...currentPackages]
|
|
107
|
+
.filter((packageName) =>
|
|
108
|
+
classifiedTarget.options.some(
|
|
109
|
+
(option) =>
|
|
110
|
+
option.to === packageName ||
|
|
111
|
+
option.to.startsWith(`${packageName}/`)
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
.toSorted();
|
|
115
|
+
facts.push({
|
|
116
|
+
kind: 'classified',
|
|
117
|
+
sourcePackage,
|
|
118
|
+
transitionId: transition.id,
|
|
119
|
+
});
|
|
120
|
+
intents.push({ eligiblePackages, sourcePackage });
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!currentPackages.has(target.to)) {
|
|
125
|
+
diagnostics.push({
|
|
126
|
+
code: 'missing-governed-package-route-target',
|
|
127
|
+
message: `Governed Regrade route '${transition.id}' maps '${sourcePackage}' to '${target.to}', but that publishable target package is absent. Add the target package before applying the route, or use a classified transition with an explicit non-migratable reason for a multi-owner fold.`,
|
|
128
|
+
sourcePackage,
|
|
129
|
+
});
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
facts.push({
|
|
134
|
+
kind: 'single',
|
|
135
|
+
sourcePackage,
|
|
136
|
+
targetPackage: target.to,
|
|
137
|
+
transitionId: transition.id,
|
|
138
|
+
});
|
|
139
|
+
intents.push({
|
|
140
|
+
eligiblePackages: [target.to],
|
|
141
|
+
sourcePackage,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { diagnostics, facts, intents };
|
|
146
|
+
};
|
package/src/release/policy.ts
CHANGED
|
@@ -999,13 +999,13 @@ const registryPackagesFromResults = (
|
|
|
999
999
|
const readRegistryPackages = async (
|
|
1000
1000
|
distTag: string
|
|
1001
1001
|
): Promise<readonly ReleasePolicyRegistryPackage[]> => {
|
|
1002
|
-
const { checkRegistryPosture, npmRegistryView,
|
|
1002
|
+
const { checkRegistryPosture, npmRegistryView, npmRegistryVersionProofView } =
|
|
1003
1003
|
await import('./native-bun-registry.js');
|
|
1004
1004
|
const workspaces = await discoverRegistryWorkspaces(repoRoot);
|
|
1005
1005
|
const results = await checkRegistryPosture(
|
|
1006
1006
|
workspaces,
|
|
1007
1007
|
npmRegistryView,
|
|
1008
|
-
|
|
1008
|
+
npmRegistryVersionProofView,
|
|
1009
1009
|
distTag
|
|
1010
1010
|
);
|
|
1011
1011
|
return registryPackagesFromResults(results);
|
|
@@ -12,7 +12,7 @@ import { homedir } from 'node:os';
|
|
|
12
12
|
import { dirname, join } from 'node:path';
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
|
|
15
|
+
renderPublicSurfaceError,
|
|
16
16
|
Result,
|
|
17
17
|
ValidationError,
|
|
18
18
|
} from '@ontrails/core';
|
|
@@ -138,9 +138,9 @@ export const runCompletionsInstall = async (
|
|
|
138
138
|
|
|
139
139
|
const handleCliError = (error: unknown): void => {
|
|
140
140
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
141
|
-
const
|
|
142
|
-
process.stderr.write(`Error: ${
|
|
143
|
-
process.exit(
|
|
141
|
+
const rendering = renderPublicSurfaceError('cli', err);
|
|
142
|
+
process.stderr.write(`Error: ${rendering.message}\n`);
|
|
143
|
+
process.exit(rendering.code);
|
|
144
144
|
};
|
|
145
145
|
|
|
146
146
|
const findCompletionsCommand = (program: Command): Command | undefined =>
|
package/src/run-trace.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* intrinsic tracing pipeline in `@ontrails/core` records every trail-,
|
|
6
6
|
* span-, signal-, and activation-level event during the invocation. After
|
|
7
7
|
* the trail completes (success or failure), the records are rendered as a
|
|
8
|
-
* tree to stderr via `renderTraceTree` from `@ontrails/
|
|
8
|
+
* tree to stderr via `renderTraceTree` from `@ontrails/observability`. Under
|
|
9
9
|
* `--json`, the structured `TraceRecord[]` is also emitted on stdout as
|
|
10
10
|
* the `tracing` field of a Result envelope.
|
|
11
11
|
*
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
import { getTraceSink, registerTraceSink } from '@ontrails/core';
|
|
27
27
|
import type { TraceRecord, TraceSink } from '@ontrails/core';
|
|
28
|
-
import { createMemorySink, renderTraceTree } from '@ontrails/
|
|
29
|
-
import type { MemoryTraceSink } from '@ontrails/
|
|
28
|
+
import { createMemorySink, renderTraceTree } from '@ontrails/observability';
|
|
29
|
+
import type { MemoryTraceSink } from '@ontrails/observability';
|
|
30
30
|
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
32
|
// Argv detection
|
|
@@ -166,7 +166,7 @@ const errorFromUnknown = (
|
|
|
166
166
|
* On success, the inner value is taken straight from the trail's
|
|
167
167
|
* `Result.ok(...)` payload. On failure the envelope captures the error's
|
|
168
168
|
* `name` and `message` -- both safe to serialize and consistent with how
|
|
169
|
-
* other Trails surfaces
|
|
169
|
+
* other Trails surfaces render errors.
|
|
170
170
|
*/
|
|
171
171
|
export const buildTraceJsonEnvelope = (
|
|
172
172
|
result: ResultLike,
|