@ontrails/warden 1.0.0-beta.30 → 1.0.0-beta.39
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 +105 -0
- package/README.md +23 -1
- package/bin/warden.ts +1 -0
- package/package.json +9 -9
- package/src/cli.ts +160 -14
- package/src/command.ts +48 -5
- package/src/config.ts +9 -0
- package/src/drift.ts +116 -7
- package/src/fix.ts +8 -2
- package/src/formatters.ts +3 -8
- package/src/index.ts +32 -2
- package/src/project-context.ts +286 -3
- package/src/rules/ast.ts +4 -0
- package/src/rules/duplicate-exported-symbol.ts +211 -0
- package/src/rules/duplicate-public-contract.ts +2 -1
- package/src/rules/governed-symbol-residue.ts +131 -0
- package/src/rules/implementation-returns-result.ts +1 -3
- package/src/rules/index.ts +44 -3
- package/src/rules/metadata.ts +108 -14
- package/src/rules/no-legacy-cli-alias-export.ts +247 -0
- package/src/rules/no-retired-cross-vocabulary.ts +19 -9
- package/src/rules/permit-governance.ts +1 -1
- package/src/rules/public-export-example-coverage.ts +5 -0
- package/src/rules/public-internal-deep-imports.ts +3 -63
- package/src/rules/registry-names.ts +12 -2
- package/src/rules/retired-vocabulary.ts +396 -0
- package/src/rules/signal-graph-coaching.ts +32 -3
- package/src/rules/surface-overlay-coherence.ts +262 -0
- package/src/rules/{surface-facet-coherence.ts → surface-trailhead-coherence.ts} +46 -42
- package/src/rules/trail-fork-coaching.ts +1 -1
- package/src/rules/trailhead-override-divergence.ts +356 -0
- package/src/rules/types.ts +84 -4
- package/src/rules/webhook-route-collision.ts +64 -1
- package/src/trails/duplicate-exported-symbol.trail.ts +48 -0
- package/src/trails/duplicate-public-contract.trail.ts +1 -1
- package/src/trails/governed-symbol-residue.trail.ts +24 -0
- package/src/trails/index.ts +6 -1
- package/src/trails/no-legacy-cli-alias-export.trail.ts +41 -0
- package/src/trails/schema.ts +39 -0
- package/src/trails/surface-overlay-coherence.trail.ts +24 -0
- package/src/trails/{surface-facet-coherence.trail.ts → surface-trailhead-coherence.trail.ts} +5 -5
- package/src/trails/trail-fork-coaching.trail.ts +1 -1
- package/src/trails/trailhead-override-divergence.trail.ts +47 -0
- package/src/trails/wrap-rule.ts +10 -0
- package/src/workspaces.ts +30 -69
package/src/command.ts
CHANGED
|
@@ -12,8 +12,10 @@ import type {
|
|
|
12
12
|
CliFlagValueAlias,
|
|
13
13
|
CliFlagValueAliasDeclaration,
|
|
14
14
|
} from '@ontrails/cli';
|
|
15
|
+
import { resolveTrailsOverlays } from '@ontrails/adapter-kit';
|
|
15
16
|
import type { Topo } from '@ontrails/core';
|
|
16
17
|
import { AmbiguousError, NotFoundError } from '@ontrails/core';
|
|
18
|
+
import type { TopoGraphOverlayRegistration } from '@ontrails/topographer';
|
|
17
19
|
import {
|
|
18
20
|
loadTrailsConfigValue,
|
|
19
21
|
resolveTrailsProjectRoot,
|
|
@@ -26,6 +28,7 @@ import type {
|
|
|
26
28
|
WardenDraftsMode,
|
|
27
29
|
WardenFailOn,
|
|
28
30
|
WardenFormat,
|
|
31
|
+
WardenScope,
|
|
29
32
|
WardenLockMode,
|
|
30
33
|
} from './config.js';
|
|
31
34
|
import {
|
|
@@ -57,6 +60,7 @@ interface MutableWardenConfigLayer {
|
|
|
57
60
|
drafts?: WardenDraftsMode | undefined;
|
|
58
61
|
failOn?: WardenFailOn | undefined;
|
|
59
62
|
format?: WardenFormat | undefined;
|
|
63
|
+
scope?: WardenScope | undefined;
|
|
60
64
|
lock?: WardenLockMode | undefined;
|
|
61
65
|
noLockMutation?: boolean | undefined;
|
|
62
66
|
}
|
|
@@ -95,6 +99,12 @@ const splitApps = (value: string): readonly string[] =>
|
|
|
95
99
|
.map((entry) => entry.trim())
|
|
96
100
|
.filter((entry) => entry.length > 0);
|
|
97
101
|
|
|
102
|
+
const splitCommaDelimitedValues = (value: string): readonly string[] =>
|
|
103
|
+
value
|
|
104
|
+
.split(',')
|
|
105
|
+
.map((entry) => entry.trim())
|
|
106
|
+
.filter((entry) => entry.length > 0);
|
|
107
|
+
|
|
98
108
|
const isAllowedValue = <T extends string>(
|
|
99
109
|
value: string,
|
|
100
110
|
allowed: readonly T[]
|
|
@@ -248,6 +258,7 @@ const parseTokens = (
|
|
|
248
258
|
'no-lock-mutation': { type: 'boolean' },
|
|
249
259
|
'pre-push': { type: 'boolean' },
|
|
250
260
|
'root-dir': { type: 'string' },
|
|
261
|
+
'scope-exclude': { multiple: true, type: 'string' },
|
|
251
262
|
strict: { type: 'boolean' },
|
|
252
263
|
...valueAliasParseOptions,
|
|
253
264
|
},
|
|
@@ -397,6 +408,19 @@ const applyCommandOption = (
|
|
|
397
408
|
state.configPath = value;
|
|
398
409
|
return;
|
|
399
410
|
}
|
|
411
|
+
if (token.name === 'scope-exclude') {
|
|
412
|
+
if (value === undefined) {
|
|
413
|
+
state.diagnostics.push(
|
|
414
|
+
diagnostic({ message: '--scope-exclude requires a path glob.' })
|
|
415
|
+
);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const existing = state.cli.scope?.exclude ?? [];
|
|
419
|
+
state.cli.scope = {
|
|
420
|
+
exclude: [...existing, ...splitCommaDelimitedValues(value)],
|
|
421
|
+
};
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
400
424
|
if (token.name === 'fix') {
|
|
401
425
|
state.fix = true;
|
|
402
426
|
return;
|
|
@@ -660,12 +684,22 @@ const resolveNamedAppModulePath = (
|
|
|
660
684
|
: resolveFilesystemModulePath(rootDir, matched);
|
|
661
685
|
};
|
|
662
686
|
|
|
663
|
-
|
|
687
|
+
interface LoadedWardenTopoModule {
|
|
688
|
+
/** App-module overlay registrations read through the shared channel. */
|
|
689
|
+
readonly overlays?: readonly TopoGraphOverlayRegistration[] | undefined;
|
|
690
|
+
readonly topo: Topo;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const importTopoFromModulePath = async (
|
|
694
|
+
modulePath: string
|
|
695
|
+
): Promise<LoadedWardenTopoModule> => {
|
|
664
696
|
const loaded = (await import(pathToFileURL(modulePath).href)) as Record<
|
|
665
697
|
string,
|
|
666
698
|
unknown
|
|
667
699
|
>;
|
|
668
|
-
|
|
700
|
+
const topo = extractTopo(modulePath, loaded);
|
|
701
|
+
const overlays = resolveTrailsOverlays(loaded, modulePath);
|
|
702
|
+
return overlays === undefined ? { topo } : { overlays, topo };
|
|
669
703
|
};
|
|
670
704
|
|
|
671
705
|
const topoLoadDiagnostic = ({
|
|
@@ -737,9 +771,11 @@ export const resolveWardenTopoTargets = async ({
|
|
|
737
771
|
for (const appName of apps) {
|
|
738
772
|
try {
|
|
739
773
|
const modulePath = resolveNamedAppModulePath(rootDir, appName);
|
|
774
|
+
const loaded = await importTopoFromModulePath(modulePath);
|
|
740
775
|
topos.push({
|
|
741
776
|
name: appName,
|
|
742
|
-
|
|
777
|
+
overlays: loaded.overlays,
|
|
778
|
+
topo: loaded.topo,
|
|
743
779
|
});
|
|
744
780
|
} catch (error) {
|
|
745
781
|
diagnostics.push(
|
|
@@ -756,10 +792,16 @@ export const resolveWardenTopoTargets = async ({
|
|
|
756
792
|
|
|
757
793
|
try {
|
|
758
794
|
const modulePath = resolveDiscoveredModulePath(rootDir);
|
|
759
|
-
const
|
|
795
|
+
const loaded = await importTopoFromModulePath(modulePath);
|
|
760
796
|
return {
|
|
761
797
|
diagnostics,
|
|
762
|
-
topos: [
|
|
798
|
+
topos: [
|
|
799
|
+
{
|
|
800
|
+
name: loaded.topo.name,
|
|
801
|
+
overlays: loaded.overlays,
|
|
802
|
+
topo: loaded.topo,
|
|
803
|
+
},
|
|
804
|
+
],
|
|
763
805
|
};
|
|
764
806
|
} catch (error) {
|
|
765
807
|
if (error instanceof NotFoundError) {
|
|
@@ -821,6 +863,7 @@ const buildRunOptions = ({
|
|
|
821
863
|
lock: cli.lock,
|
|
822
864
|
noLockMutation: cli.noLockMutation,
|
|
823
865
|
rootDir,
|
|
866
|
+
scope: cli.scope,
|
|
824
867
|
topos,
|
|
825
868
|
}),
|
|
826
869
|
env,
|
package/src/config.ts
CHANGED
|
@@ -10,6 +10,13 @@ export const wardenDraftsValues = ['include', 'exclude', 'only'] as const;
|
|
|
10
10
|
|
|
11
11
|
const appNameSchema = z.string().min(1);
|
|
12
12
|
|
|
13
|
+
const wardenScopeSchema = z
|
|
14
|
+
.object({
|
|
15
|
+
exclude: z.array(z.string().min(1)).default([]),
|
|
16
|
+
})
|
|
17
|
+
.strict()
|
|
18
|
+
.default({ exclude: [] });
|
|
19
|
+
|
|
13
20
|
const wardenConfigObjectSchema = z
|
|
14
21
|
.object({
|
|
15
22
|
apps: z.array(appNameSchema).min(1).optional(),
|
|
@@ -18,6 +25,7 @@ const wardenConfigObjectSchema = z
|
|
|
18
25
|
failOn: z.enum(wardenFailOnValues).default('error'),
|
|
19
26
|
format: z.enum(wardenFormatValues).default('summary'),
|
|
20
27
|
lock: z.enum(wardenLockValues).default('auto'),
|
|
28
|
+
scope: wardenScopeSchema,
|
|
21
29
|
})
|
|
22
30
|
.strict();
|
|
23
31
|
|
|
@@ -31,6 +39,7 @@ export type WardenDepth = (typeof wardenDepthValues)[number];
|
|
|
31
39
|
export type WardenDraftsMode = (typeof wardenDraftsValues)[number];
|
|
32
40
|
export type WardenFailOn = (typeof wardenFailOnValues)[number];
|
|
33
41
|
export type WardenFormat = (typeof wardenFormatValues)[number];
|
|
42
|
+
export type WardenScope = z.output<typeof wardenScopeSchema>;
|
|
34
43
|
export type WardenLockMode = (typeof wardenLockValues)[number];
|
|
35
44
|
|
|
36
45
|
export interface WardenConfigLayer extends Partial<WardenConfig> {
|
package/src/drift.ts
CHANGED
|
@@ -15,14 +15,33 @@ import {
|
|
|
15
15
|
ValidationError,
|
|
16
16
|
} from '@ontrails/core';
|
|
17
17
|
import {
|
|
18
|
+
collectTopoGraphOverlays,
|
|
18
19
|
createTopoStore,
|
|
19
20
|
deriveTopoGraph,
|
|
20
21
|
deriveTopoGraphHash,
|
|
21
22
|
isTopoArtifactRegenerationError,
|
|
22
23
|
readLockManifest,
|
|
24
|
+
readTopoGraph,
|
|
23
25
|
readTrailsLock,
|
|
24
26
|
} from '@ontrails/topographer';
|
|
25
|
-
import type {
|
|
27
|
+
import type {
|
|
28
|
+
DeriveTopoGraphOptions,
|
|
29
|
+
LockManifest,
|
|
30
|
+
TopoGraphOverlays,
|
|
31
|
+
} from '@ontrails/topographer';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Derive options `checkDrift` accepts so the fresh comparison graph carries
|
|
35
|
+
* the same app-module overlays the committed lock embeds.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import type { CheckDriftOptions } from '@ontrails/warden';
|
|
40
|
+
*
|
|
41
|
+
* const options: CheckDriftOptions = { overlays: lease.overlays };
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type CheckDriftOptions = Pick<DeriveTopoGraphOptions, 'overlays'>;
|
|
26
45
|
|
|
27
46
|
/**
|
|
28
47
|
* Result of a drift check comparing committed trails.lock against the current state.
|
|
@@ -36,6 +55,12 @@ export interface DriftResult {
|
|
|
36
55
|
readonly committedHash: string | null;
|
|
37
56
|
/** Hash computed from the current trail topology */
|
|
38
57
|
readonly currentHash: string;
|
|
58
|
+
/**
|
|
59
|
+
* Overlay namespaces whose committed facts differ from the freshly derived
|
|
60
|
+
* facts, sorted lexicographically. Present only when the lock is stale and
|
|
61
|
+
* the caller supplied a topo plus derive options.
|
|
62
|
+
*/
|
|
63
|
+
readonly driftedOverlayNamespaces?: readonly string[] | undefined;
|
|
39
64
|
}
|
|
40
65
|
|
|
41
66
|
interface BlockedLockRead {
|
|
@@ -91,14 +116,89 @@ const isBlockedLockRead = (
|
|
|
91
116
|
): result is BlockedLockRead =>
|
|
92
117
|
result !== null && 'kind' in result && result.kind === 'blocked-lock-read';
|
|
93
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Read the committed lock's embedded graph overlays, tolerating both the v4
|
|
121
|
+
* root `trails.lock` envelope and the legacy `.trails/` artifact layout.
|
|
122
|
+
*/
|
|
123
|
+
const readCommittedGraphOverlays = async (
|
|
124
|
+
rootDir: string
|
|
125
|
+
): Promise<TopoGraphOverlays | undefined> => {
|
|
126
|
+
const committedGraph =
|
|
127
|
+
(await readTopoGraph({ dir: rootDir })) ??
|
|
128
|
+
(await readTopoGraph({ dir: deriveTrailsDir({ rootDir }) }));
|
|
129
|
+
return committedGraph?.overlays;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Name the overlay namespaces whose committed facts drifted from the freshly
|
|
134
|
+
* derived facts. Compares canonical JSON per namespace across the union of
|
|
135
|
+
* committed and current namespaces; returns a sorted list.
|
|
136
|
+
*/
|
|
137
|
+
const collectDriftedOverlayNamespaces = async (
|
|
138
|
+
rootDir: string,
|
|
139
|
+
topo: Topo,
|
|
140
|
+
options: CheckDriftOptions
|
|
141
|
+
): Promise<readonly string[]> => {
|
|
142
|
+
let committed: TopoGraphOverlays | undefined;
|
|
143
|
+
try {
|
|
144
|
+
committed = await readCommittedGraphOverlays(rootDir);
|
|
145
|
+
} catch {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const current = collectTopoGraphOverlays(topo, options.overlays);
|
|
149
|
+
const namespaces = new Set([
|
|
150
|
+
...Object.keys(committed ?? {}),
|
|
151
|
+
...Object.keys(current ?? {}),
|
|
152
|
+
]);
|
|
153
|
+
return [...namespaces]
|
|
154
|
+
.filter(
|
|
155
|
+
(namespace) =>
|
|
156
|
+
JSON.stringify(committed?.[namespace]) !==
|
|
157
|
+
JSON.stringify(current?.[namespace])
|
|
158
|
+
)
|
|
159
|
+
.toSorted();
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Format a stale drift result into one human-readable sentence.
|
|
164
|
+
*
|
|
165
|
+
* Names the drifted overlay namespaces when the drift check identified them,
|
|
166
|
+
* and always points at `trails compile` as the remediation.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* import { staleDriftMessage } from './drift.js';
|
|
171
|
+
*
|
|
172
|
+
* staleDriftMessage({
|
|
173
|
+
* committedHash: 'aaa',
|
|
174
|
+
* currentHash: 'bbb',
|
|
175
|
+
* driftedOverlayNamespaces: ['surfaces'],
|
|
176
|
+
* stale: true,
|
|
177
|
+
* });
|
|
178
|
+
* // => 'trails.lock is stale — drifted overlay namespaces: surfaces (regenerate with `trails compile`)'
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export const staleDriftMessage = (drift: DriftResult): string => {
|
|
182
|
+
const namespaces = drift.driftedOverlayNamespaces;
|
|
183
|
+
const detail =
|
|
184
|
+
namespaces !== undefined && namespaces.length > 0
|
|
185
|
+
? ` — drifted overlay namespaces: ${namespaces.join(', ')}`
|
|
186
|
+
: '';
|
|
187
|
+
return `trails.lock is stale${detail} (regenerate with \`trails compile\`)`;
|
|
188
|
+
};
|
|
189
|
+
|
|
94
190
|
/**
|
|
95
191
|
* Check whether the committed trails.lock is stale compared to the current topology.
|
|
96
192
|
*
|
|
97
193
|
* When no topo is provided, returns a clean result (no drift detectable without runtime info).
|
|
194
|
+
* When a topo is provided, `options.overlays` carries the app-module overlay
|
|
195
|
+
* registrations so the fresh comparison graph embeds the same namespaced
|
|
196
|
+
* facts the compile path writes into the committed lock.
|
|
98
197
|
*/
|
|
99
198
|
export const checkDrift = async (
|
|
100
199
|
rootDir: string,
|
|
101
|
-
topo?: Topo | undefined
|
|
200
|
+
topo?: Topo | undefined,
|
|
201
|
+
options?: CheckDriftOptions | undefined
|
|
102
202
|
): Promise<DriftResult> => {
|
|
103
203
|
try {
|
|
104
204
|
const lockManifest = await readCommittedLockManifest(rootDir);
|
|
@@ -127,15 +227,24 @@ export const checkDrift = async (
|
|
|
127
227
|
const currentHash =
|
|
128
228
|
topo === undefined
|
|
129
229
|
? (readStoredHash() ?? 'unknown')
|
|
130
|
-
: deriveTopoGraphHash(deriveTopoGraph(topo));
|
|
230
|
+
: deriveTopoGraphHash(deriveTopoGraph(topo, options));
|
|
231
|
+
const stale =
|
|
232
|
+
topoArtifact !== null &&
|
|
233
|
+
currentHash !== 'unknown' &&
|
|
234
|
+
topoArtifact.sha256 !== currentHash;
|
|
235
|
+
const driftedOverlayNamespaces =
|
|
236
|
+
stale && topo !== undefined && options !== undefined
|
|
237
|
+
? await collectDriftedOverlayNamespaces(rootDir, topo, options)
|
|
238
|
+
: undefined;
|
|
131
239
|
|
|
132
240
|
return {
|
|
133
241
|
committedHash: topoArtifact?.sha256 ?? null,
|
|
134
242
|
currentHash,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
243
|
+
...(driftedOverlayNamespaces === undefined ||
|
|
244
|
+
driftedOverlayNamespaces.length === 0
|
|
245
|
+
? {}
|
|
246
|
+
: { driftedOverlayNamespaces }),
|
|
247
|
+
stale,
|
|
139
248
|
};
|
|
140
249
|
} catch (error) {
|
|
141
250
|
if (
|
package/src/fix.ts
CHANGED
|
@@ -95,16 +95,22 @@ export const applySafeFixesToSource = (
|
|
|
95
95
|
const applied: WardenDiagnostic[] = [];
|
|
96
96
|
const skipped: WardenDiagnostic[] = [];
|
|
97
97
|
const edits: ResolvedEdit[] = [];
|
|
98
|
+
const seenEdits = new Set<string>();
|
|
98
99
|
|
|
99
100
|
for (const diagnostic of diagnostics) {
|
|
100
101
|
if (hasSafeFixEdits(diagnostic)) {
|
|
101
102
|
applied.push(diagnostic);
|
|
102
103
|
for (const edit of diagnostic.fix.edits) {
|
|
103
|
-
|
|
104
|
+
const resolvedEdit = {
|
|
104
105
|
end: edit.end,
|
|
105
106
|
replacement: edit.replacement,
|
|
106
107
|
start: edit.start,
|
|
107
|
-
}
|
|
108
|
+
};
|
|
109
|
+
const key = `${String(resolvedEdit.start)}\0${String(resolvedEdit.end)}\0${resolvedEdit.replacement}`;
|
|
110
|
+
if (!seenEdits.has(key)) {
|
|
111
|
+
seenEdits.add(key);
|
|
112
|
+
edits.push(resolvedEdit);
|
|
113
|
+
}
|
|
108
114
|
}
|
|
109
115
|
} else {
|
|
110
116
|
skipped.push(diagnostic);
|
package/src/formatters.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { WardenReport } from './cli.js';
|
|
10
|
+
import { staleDriftMessage } from './drift.js';
|
|
10
11
|
import type { WardenGuidanceLink, WardenSeverity } from './rules/types.js';
|
|
11
12
|
|
|
12
13
|
/** Map warden severity to GitHub Actions annotation level. */
|
|
@@ -35,9 +36,7 @@ export const formatGitHubAnnotations = (report: WardenReport): string => {
|
|
|
35
36
|
if (report.drift?.blockedReason !== undefined) {
|
|
36
37
|
lines.push(`::error::drift: ${report.drift.blockedReason}`);
|
|
37
38
|
} else if (report.drift?.stale) {
|
|
38
|
-
lines.push(
|
|
39
|
-
'::error::drift: trails.lock is stale (regenerate with `trails compile`)'
|
|
40
|
-
);
|
|
39
|
+
lines.push(`::error::drift: ${staleDriftMessage(report.drift)}`);
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
return lines.join('\n');
|
|
@@ -144,11 +143,7 @@ const driftSection = (drift: WardenReport['drift']): readonly string[] => {
|
|
|
144
143
|
if (!drift?.stale) {
|
|
145
144
|
return [];
|
|
146
145
|
}
|
|
147
|
-
return [
|
|
148
|
-
'',
|
|
149
|
-
'### Drift',
|
|
150
|
-
'- trails.lock is stale (regenerate with `trails compile`)',
|
|
151
|
-
];
|
|
146
|
+
return ['', '### Drift', `- ${staleDriftMessage(drift)}`];
|
|
152
147
|
};
|
|
153
148
|
|
|
154
149
|
/** Render safe-fix counts when a fix pass was requested. */
|
package/src/index.ts
CHANGED
|
@@ -14,10 +14,12 @@ export type {
|
|
|
14
14
|
ProjectContext,
|
|
15
15
|
TopoAwareWardenRule,
|
|
16
16
|
WardenDiagnostic,
|
|
17
|
+
WardenExportedSymbolDefinition,
|
|
17
18
|
WardenFix,
|
|
18
19
|
WardenFixCapability,
|
|
19
20
|
WardenFixClass,
|
|
20
21
|
WardenFixEdit,
|
|
22
|
+
WardenFixScanTargets,
|
|
21
23
|
WardenFixSafety,
|
|
22
24
|
WardenGuidance,
|
|
23
25
|
WardenGuidanceLink,
|
|
@@ -34,8 +36,21 @@ export type {
|
|
|
34
36
|
// Rule registry
|
|
35
37
|
export {
|
|
36
38
|
builtinWardenRuleMetadata,
|
|
39
|
+
formatGovernedVocabularyTransitionGuide,
|
|
40
|
+
getGovernedVocabularyTransition,
|
|
41
|
+
governedVocabularyLiteralRenameSchema,
|
|
42
|
+
governedVocabularyPreserveRuleSchema,
|
|
43
|
+
governedVocabularyRegistrySchema,
|
|
44
|
+
governedVocabularyScopeSchema,
|
|
45
|
+
governedVocabularySymbolRenameSchema,
|
|
46
|
+
governedVocabularyTargetSchema,
|
|
47
|
+
governedVocabularyTransitionSchema,
|
|
48
|
+
governedVocabularyTransitionStatuses,
|
|
49
|
+
governedVocabularyTransitions,
|
|
37
50
|
getWardenRuleMetadata,
|
|
38
51
|
listWardenRuleMetadata,
|
|
52
|
+
listGovernedVocabularyTransitions,
|
|
53
|
+
requireGovernedVocabularyTransition,
|
|
39
54
|
wardenFixClasses,
|
|
40
55
|
wardenFixSafeties,
|
|
41
56
|
wardenRuleConcerns,
|
|
@@ -45,6 +60,15 @@ export {
|
|
|
45
60
|
wardenRules,
|
|
46
61
|
wardenTopoRules,
|
|
47
62
|
} from './rules/index.js';
|
|
63
|
+
export type {
|
|
64
|
+
GovernedVocabularyLiteralRename,
|
|
65
|
+
GovernedVocabularyPreserveRule,
|
|
66
|
+
GovernedVocabularyScope,
|
|
67
|
+
GovernedVocabularySymbolRename,
|
|
68
|
+
GovernedVocabularyTarget,
|
|
69
|
+
GovernedVocabularyTransition,
|
|
70
|
+
GovernedVocabularyTransitionInput,
|
|
71
|
+
} from './rules/index.js';
|
|
48
72
|
|
|
49
73
|
// Rule-scoped cache controls for long-lived consumers (watch mode, LSPs).
|
|
50
74
|
export { clearImplementationReturnsResultCache } from './rules/implementation-returns-result.js';
|
|
@@ -100,6 +124,7 @@ export type {
|
|
|
100
124
|
WardenDraftsMode,
|
|
101
125
|
WardenFailOn,
|
|
102
126
|
WardenFormat,
|
|
127
|
+
WardenScope,
|
|
103
128
|
WardenLockMode,
|
|
104
129
|
EffectiveWardenConfig,
|
|
105
130
|
ResolveWardenConfigOptions,
|
|
@@ -116,7 +141,7 @@ export {
|
|
|
116
141
|
} from './formatters.js';
|
|
117
142
|
|
|
118
143
|
// Drift detection
|
|
119
|
-
export type { DriftResult } from './drift.js';
|
|
144
|
+
export type { CheckDriftOptions, DriftResult } from './drift.js';
|
|
120
145
|
export { checkDrift } from './drift.js';
|
|
121
146
|
|
|
122
147
|
// Project-local rule loading
|
|
@@ -174,6 +199,7 @@ export {
|
|
|
174
199
|
deadPublicTrailTrail,
|
|
175
200
|
deprecationWithoutGuidanceTrail,
|
|
176
201
|
diagnosticSchema,
|
|
202
|
+
duplicateExportedSymbolTrail,
|
|
177
203
|
duplicatePublicContractTrail,
|
|
178
204
|
draftFileMarkingTrail,
|
|
179
205
|
draftVisibleDebtTrail,
|
|
@@ -181,6 +207,7 @@ export {
|
|
|
181
207
|
exampleValidTrail,
|
|
182
208
|
firesDeclarationsTrail,
|
|
183
209
|
forkWithoutPreservedBlazeTrail,
|
|
210
|
+
governedSymbolResidueTrail,
|
|
184
211
|
implementationReturnsResultTrail,
|
|
185
212
|
incompleteAccessorForStandardOpTrail,
|
|
186
213
|
incompleteCrudTrail,
|
|
@@ -193,6 +220,7 @@ export {
|
|
|
193
220
|
noDevPermitInSourceTrail,
|
|
194
221
|
noDestructuredComposeTrail,
|
|
195
222
|
noDirectImplementationCallTrail,
|
|
223
|
+
noLegacyCliAliasExportTrail,
|
|
196
224
|
noLegacyLayerImportsTrail,
|
|
197
225
|
noNativeErrorResultTrail,
|
|
198
226
|
noRedundantResultErrorWrapTrail,
|
|
@@ -224,8 +252,10 @@ export {
|
|
|
224
252
|
scheduledDestroyIntentTrail,
|
|
225
253
|
signalGraphCoachingTrail,
|
|
226
254
|
staticResourceAccessorPreferenceTrail,
|
|
227
|
-
|
|
255
|
+
surfaceOverlayCoherenceTrail,
|
|
256
|
+
surfaceTrailheadCoherenceTrail,
|
|
228
257
|
trailForkCoachingTrail,
|
|
258
|
+
trailheadOverrideDivergenceTrail,
|
|
229
259
|
unmaterializedActivationSourceTrail,
|
|
230
260
|
topoAwareRuleInput,
|
|
231
261
|
unreachableDetourShadowingTrail,
|