@agentxm/registry-protocol 0.28.4-bootstrap.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/LICENSE +110 -0
- package/README.md +13 -0
- package/dist/src/unstable/content/agent-skills-standard.d.ts +17 -0
- package/dist/src/unstable/content/agent-skills-standard.js +24 -0
- package/dist/src/unstable/content/frontmatter.d.ts +52 -0
- package/dist/src/unstable/content/frontmatter.js +115 -0
- package/dist/src/unstable/content/index.d.ts +11 -0
- package/dist/src/unstable/content/index.js +11 -0
- package/dist/src/unstable/content/skill-content.d.ts +43 -0
- package/dist/src/unstable/content/skill-content.js +184 -0
- package/dist/src/unstable/content/skill-types.d.ts +22 -0
- package/dist/src/unstable/content/skill-types.js +9 -0
- package/dist/src/unstable/content/subagent-content.d.ts +58 -0
- package/dist/src/unstable/content/subagent-content.js +101 -0
- package/dist/src/unstable/knowledge/index.d.ts +8 -0
- package/dist/src/unstable/knowledge/index.js +8 -0
- package/dist/src/unstable/knowledge/knowledge-search.d.ts +32 -0
- package/dist/src/unstable/knowledge/knowledge-search.js +147 -0
- package/dist/src/unstable/knowledge/okf.d.ts +86 -0
- package/dist/src/unstable/knowledge/okf.js +1090 -0
- package/dist/src/unstable/lint/catalog/hook/decision-portability.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/hook/decision-portability.js +40 -0
- package/dist/src/unstable/lint/catalog/hook/entrypoint-exists.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/hook/entrypoint-exists.js +39 -0
- package/dist/src/unstable/lint/catalog/hook/envelope.d.ts +6 -0
- package/dist/src/unstable/lint/catalog/hook/envelope.js +15 -0
- package/dist/src/unstable/lint/catalog/hook/matcher-raw-portability.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/hook/matcher-raw-portability.js +51 -0
- package/dist/src/unstable/lint/catalog/hook.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/hook.js +17 -0
- package/dist/src/unstable/lint/catalog/knowledge/diagnostics.d.ts +128 -0
- package/dist/src/unstable/lint/catalog/knowledge/diagnostics.js +78 -0
- package/dist/src/unstable/lint/catalog/knowledge/envelope.d.ts +6 -0
- package/dist/src/unstable/lint/catalog/knowledge/envelope.js +15 -0
- package/dist/src/unstable/lint/catalog/knowledge.d.ts +5 -0
- package/dist/src/unstable/lint/catalog/knowledge.js +11 -0
- package/dist/src/unstable/lint/catalog/mcp-server/envelope.d.ts +6 -0
- package/dist/src/unstable/lint/catalog/mcp-server/envelope.js +15 -0
- package/dist/src/unstable/lint/catalog/mcp-server.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/mcp-server.js +6 -0
- package/dist/src/unstable/lint/catalog/pack/manifest-keys-recognized.d.ts +28 -0
- package/dist/src/unstable/lint/catalog/pack/manifest-keys-recognized.js +38 -0
- package/dist/src/unstable/lint/catalog/pack/manifest-present.d.ts +17 -0
- package/dist/src/unstable/lint/catalog/pack/manifest-present.js +24 -0
- package/dist/src/unstable/lint/catalog/pack/manifest-schema-valid.d.ts +25 -0
- package/dist/src/unstable/lint/catalog/pack/manifest-schema-valid.js +33 -0
- package/dist/src/unstable/lint/catalog/pack-accessor/contexts.d.ts +51 -0
- package/dist/src/unstable/lint/catalog/pack-accessor/contexts.js +45 -0
- package/dist/src/unstable/lint/catalog/pack-accessor/vft.d.ts +60 -0
- package/dist/src/unstable/lint/catalog/pack-accessor/vft.js +85 -0
- package/dist/src/unstable/lint/catalog/pack.d.ts +37 -0
- package/dist/src/unstable/lint/catalog/pack.js +47 -0
- package/dist/src/unstable/lint/catalog/rule/envelope.d.ts +6 -0
- package/dist/src/unstable/lint/catalog/rule/envelope.js +15 -0
- package/dist/src/unstable/lint/catalog/rule.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/rule.js +6 -0
- package/dist/src/unstable/lint/catalog/shared/envelope-rules.d.ts +93 -0
- package/dist/src/unstable/lint/catalog/shared/envelope-rules.js +89 -0
- package/dist/src/unstable/lint/catalog/shared/manifest-json.d.ts +18 -0
- package/dist/src/unstable/lint/catalog/shared/manifest-json.js +28 -0
- package/dist/src/unstable/lint/catalog/shared/manifest-present.d.ts +25 -0
- package/dist/src/unstable/lint/catalog/shared/manifest-present.js +37 -0
- package/dist/src/unstable/lint/catalog/shared/recommended-packs-rules.d.ts +70 -0
- package/dist/src/unstable/lint/catalog/shared/recommended-packs-rules.js +139 -0
- package/dist/src/unstable/lint/catalog/shared/schema-rule.d.ts +58 -0
- package/dist/src/unstable/lint/catalog/shared/schema-rule.js +103 -0
- package/dist/src/unstable/lint/catalog/skill/frontmatter-parseable.d.ts +31 -0
- package/dist/src/unstable/lint/catalog/skill/frontmatter-parseable.js +148 -0
- package/dist/src/unstable/lint/catalog/skill/frontmatter-standard-valid.d.ts +13 -0
- package/dist/src/unstable/lint/catalog/skill/frontmatter-standard-valid.js +61 -0
- package/dist/src/unstable/lint/catalog/skill/manifest-keys-recognized.d.ts +26 -0
- package/dist/src/unstable/lint/catalog/skill/manifest-keys-recognized.js +41 -0
- package/dist/src/unstable/lint/catalog/skill/manifest-present.d.ts +23 -0
- package/dist/src/unstable/lint/catalog/skill/manifest-present.js +32 -0
- package/dist/src/unstable/lint/catalog/skill/manifest-schema-valid.d.ts +21 -0
- package/dist/src/unstable/lint/catalog/skill/manifest-schema-valid.js +36 -0
- package/dist/src/unstable/lint/catalog/skill/recommended-packs-valid.d.ts +8 -0
- package/dist/src/unstable/lint/catalog/skill/recommended-packs-valid.js +12 -0
- package/dist/src/unstable/lint/catalog/skill/skill-md-present.d.ts +17 -0
- package/dist/src/unstable/lint/catalog/skill/skill-md-present.js +37 -0
- package/dist/src/unstable/lint/catalog/skill/standalone-declaration-valid.d.ts +8 -0
- package/dist/src/unstable/lint/catalog/skill/standalone-declaration-valid.js +12 -0
- package/dist/src/unstable/lint/catalog/skill-accessor/contexts.d.ts +61 -0
- package/dist/src/unstable/lint/catalog/skill-accessor/contexts.js +55 -0
- package/dist/src/unstable/lint/catalog/skill-accessor/vft.d.ts +77 -0
- package/dist/src/unstable/lint/catalog/skill-accessor/vft.js +135 -0
- package/dist/src/unstable/lint/catalog/skill.d.ts +44 -0
- package/dist/src/unstable/lint/catalog/skill.js +64 -0
- package/dist/src/unstable/lint/catalog/subagent/envelope.d.ts +6 -0
- package/dist/src/unstable/lint/catalog/subagent/envelope.js +15 -0
- package/dist/src/unstable/lint/catalog/subagent.d.ts +4 -0
- package/dist/src/unstable/lint/catalog/subagent.js +6 -0
- package/dist/src/unstable/lint/compose-path.d.ts +28 -0
- package/dist/src/unstable/lint/compose-path.js +64 -0
- package/dist/src/unstable/lint/config.d.ts +103 -0
- package/dist/src/unstable/lint/config.js +140 -0
- package/dist/src/unstable/lint/context.d.ts +246 -0
- package/dist/src/unstable/lint/context.js +21 -0
- package/dist/src/unstable/lint/describe-document.d.ts +31 -0
- package/dist/src/unstable/lint/describe-document.js +50 -0
- package/dist/src/unstable/lint/evaluate.d.ts +47 -0
- package/dist/src/unstable/lint/evaluate.js +82 -0
- package/dist/src/unstable/lint/issues-to-findings.d.ts +35 -0
- package/dist/src/unstable/lint/issues-to-findings.js +149 -0
- package/dist/src/unstable/lint/publish.d.ts +49 -0
- package/dist/src/unstable/lint/publish.js +86 -0
- package/dist/src/unstable/lint/rule.d.ts +98 -0
- package/dist/src/unstable/lint/rule.js +18 -0
- package/dist/src/unstable/publish/archive-guardrails.d.ts +39 -0
- package/dist/src/unstable/publish/archive-guardrails.js +250 -0
- package/dist/src/unstable/publish/filtered-package-validation.d.ts +24 -0
- package/dist/src/unstable/publish/filtered-package-validation.js +117 -0
- package/dist/src/unstable/publish/index.d.ts +12 -0
- package/dist/src/unstable/publish/index.js +12 -0
- package/dist/src/unstable/publish/ingest-limits.d.ts +25 -0
- package/dist/src/unstable/publish/ingest-limits.js +41 -0
- package/dist/src/unstable/publish/input-normalization.d.ts +40 -0
- package/dist/src/unstable/publish/input-normalization.js +125 -0
- package/dist/src/unstable/publish/manifest-policy.d.ts +611 -0
- package/dist/src/unstable/publish/manifest-policy.js +196 -0
- package/dist/src/unstable/publish/test-zip-helpers.d.ts +13 -0
- package/dist/src/unstable/publish/test-zip-helpers.js +117 -0
- package/dist/src/unstable/publish/visibility.d.ts +161 -0
- package/dist/src/unstable/publish/visibility.js +124 -0
- package/dist/src/unstable/registry/discover-schema.d.ts +68 -0
- package/dist/src/unstable/registry/discover-schema.js +35 -0
- package/dist/src/unstable/registry/index.d.ts +9 -0
- package/dist/src/unstable/registry/index.js +9 -0
- package/dist/src/unstable/registry/publication-set.d.ts +303 -0
- package/dist/src/unstable/registry/publication-set.js +507 -0
- package/dist/src/unstable/registry/release-age-policy.d.ts +57 -0
- package/dist/src/unstable/registry/release-age-policy.js +117 -0
- package/dist/src/unstable/registry/schema.d.ts +220 -0
- package/dist/src/unstable/registry/schema.js +114 -0
- package/dist/src/unstable/suggested-action.d.ts +19 -0
- package/dist/src/unstable/suggested-action.js +42 -0
- package/package.json +214 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-context types and narrow accessors.
|
|
3
|
+
*
|
|
4
|
+
* Each rule-context type bundles a caller-decoded `subject` with a narrow
|
|
5
|
+
* caller-bound accessor and a `displayRoot` used for path rendering. Rules
|
|
6
|
+
* consume accessors as ordinary property access (no Layer wiring); tests pass
|
|
7
|
+
* literal fakes.
|
|
8
|
+
*
|
|
9
|
+
* Phase 2 pins the context shapes and accessor interfaces. Phases 3a, 3b, and
|
|
10
|
+
* 3c land the concrete `subject` decoders and VFT-/platform-backed accessor
|
|
11
|
+
* implementations.
|
|
12
|
+
*
|
|
13
|
+
* Accessor surfaces are intentionally minimal — rules SHALL see only the
|
|
14
|
+
* methods the v1 catalog requires. Extending a surface is a Phase 3a/3b/3c
|
|
15
|
+
* action with a documented rule consumer, not a free action.
|
|
16
|
+
*
|
|
17
|
+
* @experimental This API is unstable and may change without notice.
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
import type * as Effect from "effect/Effect";
|
|
21
|
+
import type { KnowledgeInspection } from "../knowledge/okf.js";
|
|
22
|
+
/**
|
|
23
|
+
* Tagged error surfaced by `SkillFileAccessor` / `PackFileAccessor` when a
|
|
24
|
+
* read fails for reasons other than "file not found" (which is represented
|
|
25
|
+
* by `exists -> false`).
|
|
26
|
+
*
|
|
27
|
+
* Concrete implementations live in Phases 3a/3b; this interface fixes the
|
|
28
|
+
* error shape rules can rely on.
|
|
29
|
+
*
|
|
30
|
+
* @experimental This API is unstable and may change without notice.
|
|
31
|
+
*/
|
|
32
|
+
export interface FileAccessError {
|
|
33
|
+
readonly _tag: "FileAccessError";
|
|
34
|
+
/** Accessor-relative posix path that failed. */
|
|
35
|
+
readonly path: string;
|
|
36
|
+
/** Machine-readable reason. */
|
|
37
|
+
readonly reason: "path-escape" | "read-error" | "io-error";
|
|
38
|
+
/** Human-readable detail; no rendered display path. */
|
|
39
|
+
readonly message: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Narrow skill-rooted file accessor.
|
|
43
|
+
*
|
|
44
|
+
* Root is the directory containing `SKILL.md`. Paths are posix and relative
|
|
45
|
+
* to the root; implementations MUST reject path-traversal attempts (`..`,
|
|
46
|
+
* absolute paths, symlink escapes) by returning `false` from `exists` or
|
|
47
|
+
* failing `readBytes` with `FileAccessError { reason: "path-escape" }`.
|
|
48
|
+
*
|
|
49
|
+
* @experimental This API is unstable and may change without notice.
|
|
50
|
+
*/
|
|
51
|
+
export interface SkillFileAccessor {
|
|
52
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
53
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Narrow pack-rooted file accessor.
|
|
57
|
+
*
|
|
58
|
+
* Root is the directory containing `pack.json`. Same traversal
|
|
59
|
+
* constraints as `SkillFileAccessor`.
|
|
60
|
+
*
|
|
61
|
+
* @experimental This API is unstable and may change without notice.
|
|
62
|
+
*/
|
|
63
|
+
export interface PackFileAccessor {
|
|
64
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
65
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
66
|
+
}
|
|
67
|
+
export interface SubagentFileAccessor {
|
|
68
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
69
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
70
|
+
}
|
|
71
|
+
export interface McpServerFileAccessor {
|
|
72
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
73
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
74
|
+
}
|
|
75
|
+
export interface HookFileAccessor {
|
|
76
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
77
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
78
|
+
}
|
|
79
|
+
export interface RuleFileAccessor {
|
|
80
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
81
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
82
|
+
}
|
|
83
|
+
export interface KnowledgeFileAccessor {
|
|
84
|
+
readonly exists: (path: string) => Effect.Effect<boolean>;
|
|
85
|
+
readonly readBytes: (path: string) => Effect.Effect<Uint8Array, FileAccessError>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Context passed to `skill/*` rules.
|
|
89
|
+
*
|
|
90
|
+
* `subject` is the caller-decoded skill content (SKILL.md frontmatter +
|
|
91
|
+
* optional skill.json). Phase 3a refines the `subject` type to the concrete
|
|
92
|
+
* `SkillContent` shape; Phase 2 leaves it structurally open so the rule
|
|
93
|
+
* primitives don't need a circular dependency on the skill module.
|
|
94
|
+
*
|
|
95
|
+
* `displayRoot` is posix and relative; `""` means the accessor root is the
|
|
96
|
+
* rendering base. See `./compose-path.ts` for the four documented cases.
|
|
97
|
+
*
|
|
98
|
+
* @experimental This API is unstable and may change without notice.
|
|
99
|
+
*/
|
|
100
|
+
export interface SkillRuleContext<S = SkillContent> {
|
|
101
|
+
readonly subject: S;
|
|
102
|
+
/**
|
|
103
|
+
* Content-root accessor. Rooted at the directory containing `SKILL.md`.
|
|
104
|
+
* For native (registry-installed) skills this is the `src/` sub-directory
|
|
105
|
+
* of the package; for non-native skills it is the skill's own
|
|
106
|
+
* directory. Rules validating skill content (`skill-md-present`,
|
|
107
|
+
* `frontmatter-parseable`, and any future rule evaluating files that
|
|
108
|
+
* render into agent directories) read through this accessor.
|
|
109
|
+
*/
|
|
110
|
+
readonly files: SkillFileAccessor;
|
|
111
|
+
/**
|
|
112
|
+
* Package-root accessor. Rooted at the skill's package root —
|
|
113
|
+
* the directory containing `skill.json` for native skills. For non-native
|
|
114
|
+
* skills that have no package/content split, this MAY alias `files`.
|
|
115
|
+
* Rules validating package-shape concerns (`manifest-present` and any
|
|
116
|
+
* future rule inspecting files at or above the content root) read through
|
|
117
|
+
* this accessor.
|
|
118
|
+
*/
|
|
119
|
+
readonly packageFiles: SkillFileAccessor;
|
|
120
|
+
readonly displayRoot: string;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Concrete subject shape passed to `skill/*` rules.
|
|
124
|
+
*
|
|
125
|
+
* Rules read `SKILL.md` bytes through `context.files` (the authoritative
|
|
126
|
+
* source shared across publish and `axm lint`). The `subject` carries only
|
|
127
|
+
* what rules can't efficiently re-derive from bytes:
|
|
128
|
+
*
|
|
129
|
+
* - `isNative` — whether the caller expects this skill to carry a
|
|
130
|
+
* `skill.json` manifest. Native (registry-installed) skills set this to
|
|
131
|
+
* `true`; non-native (managed external) skills set it to `false`. Rules
|
|
132
|
+
* that depend on `skill.json` (`skill/manifest-present`,
|
|
133
|
+
* `skill/manifest-schema-valid`, `skill/manifest-keys-recognized`)
|
|
134
|
+
* early-return `[]` when `isNative === false`, so the same catalog covers
|
|
135
|
+
* both.
|
|
136
|
+
* - `skillJson` — the already-decoded `skill.json` contents when present
|
|
137
|
+
* (caller decodes once, rules don't re-read + re-parse). `undefined` when
|
|
138
|
+
* the file is absent. Schema-valid rules pipe this into
|
|
139
|
+
* `Schema.decodeUnknownResult(SkillManifestSchema)`; keys-recognized
|
|
140
|
+
* enumerates top-level keys after narrowing to `Record<string, unknown>`.
|
|
141
|
+
*
|
|
142
|
+
* Workspace consumers build `SkillContent` via `buildSkillRuleContexts`
|
|
143
|
+
* against the lint workspace view; publish builds one `SkillContent` per
|
|
144
|
+
* incoming archive.
|
|
145
|
+
*
|
|
146
|
+
* @experimental This API is unstable and may change without notice.
|
|
147
|
+
*/
|
|
148
|
+
export interface SkillContent {
|
|
149
|
+
readonly isNative: boolean;
|
|
150
|
+
readonly skillJson: unknown;
|
|
151
|
+
/** Agent-facing skill directory name used for the standard name-match check. */
|
|
152
|
+
readonly expectedName?: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Context passed to `pack/*` rules.
|
|
156
|
+
*
|
|
157
|
+
* `subject` is the caller-decoded pack content — concrete `PackContent` shape
|
|
158
|
+
* defined below. Packs are registry-only at v1 (no non-native arm), so the
|
|
159
|
+
* subject carries only the already-decoded manifest and rules read
|
|
160
|
+
* `pack.json` bytes through `context.files` as needed.
|
|
161
|
+
*
|
|
162
|
+
* @experimental This API is unstable and may change without notice.
|
|
163
|
+
*/
|
|
164
|
+
export interface PackRuleContext<S = PackContent> {
|
|
165
|
+
readonly subject: S;
|
|
166
|
+
readonly files: PackFileAccessor;
|
|
167
|
+
readonly displayRoot: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Concrete subject shape passed to `pack/*` rules.
|
|
171
|
+
*
|
|
172
|
+
* Rules read `pack.json` bytes through `context.files` (the
|
|
173
|
+
* authoritative source shared across publish and `axm lint`). The `subject`
|
|
174
|
+
* carries only what rules can't efficiently re-derive from bytes:
|
|
175
|
+
*
|
|
176
|
+
* - `packJson` — the already-decoded `pack.json` contents when
|
|
177
|
+
* present (caller decodes once, rules don't re-read + re-parse).
|
|
178
|
+
* `undefined` when the file is absent. Schema-valid rules pipe this into
|
|
179
|
+
* `Schema.decodeUnknownResult(PackManifestSchema)`;
|
|
180
|
+
* keys-recognized enumerates top-level keys after narrowing to
|
|
181
|
+
* `Record<string, unknown>`.
|
|
182
|
+
*
|
|
183
|
+
* Unlike `SkillContent`, there is no `isNative` discriminator — packs are
|
|
184
|
+
* registry-only and every pack context is expected to expose a manifest.
|
|
185
|
+
* The presence rule (`pack/manifest-present`) owns the absence arm.
|
|
186
|
+
*
|
|
187
|
+
* Workspace consumers build `PackContent` via `buildPackRuleContexts`
|
|
188
|
+
* against the lint workspace view; publish builds one `PackContent` per
|
|
189
|
+
* incoming archive.
|
|
190
|
+
*
|
|
191
|
+
* @experimental This API is unstable and may change without notice.
|
|
192
|
+
*/
|
|
193
|
+
export interface PackContent {
|
|
194
|
+
readonly packJson: unknown;
|
|
195
|
+
}
|
|
196
|
+
export interface SubagentRuleContext<S = SubagentContent> {
|
|
197
|
+
readonly subject: S;
|
|
198
|
+
readonly files: SubagentFileAccessor;
|
|
199
|
+
readonly displayRoot: string;
|
|
200
|
+
}
|
|
201
|
+
export interface SubagentContent {
|
|
202
|
+
readonly subagentJson: unknown;
|
|
203
|
+
}
|
|
204
|
+
export interface McpServerRuleContext<S = McpServerContent> {
|
|
205
|
+
readonly subject: S;
|
|
206
|
+
readonly files: McpServerFileAccessor;
|
|
207
|
+
readonly displayRoot: string;
|
|
208
|
+
}
|
|
209
|
+
export interface McpServerContent {
|
|
210
|
+
readonly mcpServerJson: unknown;
|
|
211
|
+
}
|
|
212
|
+
export interface HookRuleContext<S = HookContent> {
|
|
213
|
+
readonly subject: S;
|
|
214
|
+
readonly files: HookFileAccessor;
|
|
215
|
+
readonly displayRoot: string;
|
|
216
|
+
}
|
|
217
|
+
export interface HookContent {
|
|
218
|
+
readonly hookJson: unknown;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Context passed to `rule/*` rules.
|
|
222
|
+
*
|
|
223
|
+
* The doubled word is unavoidable: `rule` is an extension type and `rule` is
|
|
224
|
+
* also the lint primitive, so the context for the `rule` extension type is a
|
|
225
|
+
* `RuleRuleContext`. Every other name here follows `<Type>RuleContext`.
|
|
226
|
+
*/
|
|
227
|
+
export interface RuleRuleContext<S = RuleContent> {
|
|
228
|
+
readonly subject: S;
|
|
229
|
+
readonly files: RuleFileAccessor;
|
|
230
|
+
readonly displayRoot: string;
|
|
231
|
+
}
|
|
232
|
+
export interface RuleContent {
|
|
233
|
+
readonly ruleJson: unknown;
|
|
234
|
+
}
|
|
235
|
+
export interface KnowledgeRuleContext<S = KnowledgeContent> {
|
|
236
|
+
readonly subject: S;
|
|
237
|
+
readonly files: KnowledgeFileAccessor;
|
|
238
|
+
readonly displayRoot: string;
|
|
239
|
+
/** Absolute package root used once while constructing the cached inspection. */
|
|
240
|
+
readonly packageRoot?: string;
|
|
241
|
+
}
|
|
242
|
+
export interface KnowledgeContent {
|
|
243
|
+
readonly knowledgeJson: unknown;
|
|
244
|
+
readonly inspection?: KnowledgeInspection;
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-context types and narrow accessors.
|
|
3
|
+
*
|
|
4
|
+
* Each rule-context type bundles a caller-decoded `subject` with a narrow
|
|
5
|
+
* caller-bound accessor and a `displayRoot` used for path rendering. Rules
|
|
6
|
+
* consume accessors as ordinary property access (no Layer wiring); tests pass
|
|
7
|
+
* literal fakes.
|
|
8
|
+
*
|
|
9
|
+
* Phase 2 pins the context shapes and accessor interfaces. Phases 3a, 3b, and
|
|
10
|
+
* 3c land the concrete `subject` decoders and VFT-/platform-backed accessor
|
|
11
|
+
* implementations.
|
|
12
|
+
*
|
|
13
|
+
* Accessor surfaces are intentionally minimal — rules SHALL see only the
|
|
14
|
+
* methods the v1 catalog requires. Extending a surface is a Phase 3a/3b/3c
|
|
15
|
+
* action with a documented rule consumer, not a free action.
|
|
16
|
+
*
|
|
17
|
+
* @experimental This API is unstable and may change without notice.
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place lint turns a document filename into the human label that opens
|
|
3
|
+
* a finding message ("Skill manifest has unrecognized top-level field ...").
|
|
4
|
+
*
|
|
5
|
+
* Three copies of this switch used to exist — one in `issues-to-findings.ts`,
|
|
6
|
+
* one in `catalog/shared/schema-rule.ts`, one in
|
|
7
|
+
* `catalog/shared/manifest-json.ts` — and they had drifted: only one knew
|
|
8
|
+
* `hook.json`, none knew `rule.json` or `knowledge.json`, and the parse-failure
|
|
9
|
+
* copy defaulted to "Manifest" where the others defaulted to "Document".
|
|
10
|
+
*
|
|
11
|
+
* The manifest labels are derived from `MANIFEST_FILENAME_BY_TYPE` and
|
|
12
|
+
* `extensionTypeSentenceLabels`, both of which are total over `ExtensionType`,
|
|
13
|
+
* so a new extension type gets a label the moment its row lands in
|
|
14
|
+
* `EXTENSION_TYPE_TABLE`.
|
|
15
|
+
*
|
|
16
|
+
* @experimental This API is unstable and may change without notice.
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
/** Label used when a filename matches no known document. */
|
|
20
|
+
export declare const UNKNOWN_DOCUMENT_LABEL = "Document";
|
|
21
|
+
/**
|
|
22
|
+
* Describe the document at `file` for use as the subject of a finding message.
|
|
23
|
+
*
|
|
24
|
+
* Keyed by basename, so both bare accessor-relative filenames (`hook.json`,
|
|
25
|
+
* as the per-extension rules pass) and workspace-relative paths
|
|
26
|
+
* (`axm.json`, as `issues-to-findings` passes) resolve.
|
|
27
|
+
*
|
|
28
|
+
* @experimental This API is unstable and may change without notice.
|
|
29
|
+
*/
|
|
30
|
+
export declare const describeSchemaDocument: (file: string) => string;
|
|
31
|
+
//# sourceMappingURL=describe-document.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place lint turns a document filename into the human label that opens
|
|
3
|
+
* a finding message ("Skill manifest has unrecognized top-level field ...").
|
|
4
|
+
*
|
|
5
|
+
* Three copies of this switch used to exist — one in `issues-to-findings.ts`,
|
|
6
|
+
* one in `catalog/shared/schema-rule.ts`, one in
|
|
7
|
+
* `catalog/shared/manifest-json.ts` — and they had drifted: only one knew
|
|
8
|
+
* `hook.json`, none knew `rule.json` or `knowledge.json`, and the parse-failure
|
|
9
|
+
* copy defaulted to "Manifest" where the others defaulted to "Document".
|
|
10
|
+
*
|
|
11
|
+
* The manifest labels are derived from `MANIFEST_FILENAME_BY_TYPE` and
|
|
12
|
+
* `extensionTypeSentenceLabels`, both of which are total over `ExtensionType`,
|
|
13
|
+
* so a new extension type gets a label the moment its row lands in
|
|
14
|
+
* `EXTENSION_TYPE_TABLE`.
|
|
15
|
+
*
|
|
16
|
+
* @experimental This API is unstable and may change without notice.
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
import { extensionTypeSentenceLabels, extensionTypes, } from "@agentxm/extension-model/unstable/extensions/common";
|
|
20
|
+
import { LOCKFILE_NAME } from "@agentxm/extension-model/unstable/workspace-files";
|
|
21
|
+
import { MANIFEST_FILENAME_BY_TYPE } from "../publish/manifest-policy.js";
|
|
22
|
+
import { SETTINGS_FILENAME } from "@agentxm/extension-model/unstable/workspace-files";
|
|
23
|
+
/** Label used when a filename matches no known document. */
|
|
24
|
+
export const UNKNOWN_DOCUMENT_LABEL = "Document";
|
|
25
|
+
const capitalizeFirst = (value) => value.length === 0 ? value : `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
26
|
+
// eslint-disable-next-line no-restricted-syntax -- Immutable lookup over the closed manifest filename vocabulary.
|
|
27
|
+
const documentLabels = new Map([
|
|
28
|
+
...extensionTypes.map((type) => [
|
|
29
|
+
MANIFEST_FILENAME_BY_TYPE[type],
|
|
30
|
+
`${capitalizeFirst(extensionTypeSentenceLabels[type])} manifest`,
|
|
31
|
+
]),
|
|
32
|
+
[SETTINGS_FILENAME, "Workspace settings"],
|
|
33
|
+
[LOCKFILE_NAME, "Lockfile"],
|
|
34
|
+
]);
|
|
35
|
+
const basename = (file) => {
|
|
36
|
+
const normalized = file.replace(/\\/g, "/");
|
|
37
|
+
const parts = normalized.split("/");
|
|
38
|
+
return parts[parts.length - 1] ?? normalized;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Describe the document at `file` for use as the subject of a finding message.
|
|
42
|
+
*
|
|
43
|
+
* Keyed by basename, so both bare accessor-relative filenames (`hook.json`,
|
|
44
|
+
* as the per-extension rules pass) and workspace-relative paths
|
|
45
|
+
* (`axm.json`, as `issues-to-findings` passes) resolve.
|
|
46
|
+
*
|
|
47
|
+
* @experimental This API is unstable and may change without notice.
|
|
48
|
+
*/
|
|
49
|
+
export const describeSchemaDocument = (file) => documentLabels.get(basename(file)) ?? UNKNOWN_DOCUMENT_LABEL;
|
|
50
|
+
//# sourceMappingURL=describe-document.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure evaluator for the lint engine.
|
|
3
|
+
*
|
|
4
|
+
* `evaluateContexts(rules, contexts, config)` pairs each rule with each context,
|
|
5
|
+
* invokes `rule.check`, applies permitted severity overrides from
|
|
6
|
+
* `config.rules`, and drops warning findings configured `"off"`.
|
|
7
|
+
*
|
|
8
|
+
* Both functions are plain `Effect` values; neither requires a Layer or an
|
|
9
|
+
* ambient service. See the `lint-engine` design doc §3 for the rationale
|
|
10
|
+
* behind library primitives over a central engine service.
|
|
11
|
+
*
|
|
12
|
+
* @experimental This API is unstable and may change without notice.
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import * as Effect from "effect/Effect";
|
|
16
|
+
import type { LintConfig } from "./config.js";
|
|
17
|
+
import type { LintFinding, LintRule } from "./rule.js";
|
|
18
|
+
/**
|
|
19
|
+
* One `(rule, context, findings)` evaluation result.
|
|
20
|
+
*
|
|
21
|
+
* `findings` is emitted after severity overrides from `config.rules` have been
|
|
22
|
+
* applied; rule-level severity is the platform default, finding-level severity
|
|
23
|
+
* is the effective post-override severity.
|
|
24
|
+
*
|
|
25
|
+
* @experimental This API is unstable and may change without notice.
|
|
26
|
+
*/
|
|
27
|
+
export interface Evaluated<C> {
|
|
28
|
+
readonly rule: LintRule<C>;
|
|
29
|
+
readonly context: C;
|
|
30
|
+
readonly findings: ReadonlyArray<LintFinding>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Pair each rule with each context, run `rule.check`, apply severity overrides
|
|
34
|
+
* from `config.rules`, and return one `Evaluated<C>` per pair.
|
|
35
|
+
*
|
|
36
|
+
* Findings whose configured severity is `"off"` are suppressed entirely; the
|
|
37
|
+
* `Evaluated` entry still ships (with an empty `findings` array) so consumers
|
|
38
|
+
* that group by rule still see the rule ran.
|
|
39
|
+
*
|
|
40
|
+
* Rules are evaluated in catalog order; contexts are evaluated in caller
|
|
41
|
+
* order. Rule-context invocation is sequential within a single
|
|
42
|
+
* `evaluateContexts` call so tests can observe deterministic ordering.
|
|
43
|
+
*
|
|
44
|
+
* @experimental This API is unstable and may change without notice.
|
|
45
|
+
*/
|
|
46
|
+
export declare const evaluateContexts: <C>(rules: ReadonlyArray<LintRule<C>>, contexts: ReadonlyArray<C>, config: LintConfig) => Effect.Effect<ReadonlyArray<Evaluated<C>>>;
|
|
47
|
+
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure evaluator for the lint engine.
|
|
3
|
+
*
|
|
4
|
+
* `evaluateContexts(rules, contexts, config)` pairs each rule with each context,
|
|
5
|
+
* invokes `rule.check`, applies permitted severity overrides from
|
|
6
|
+
* `config.rules`, and drops warning findings configured `"off"`.
|
|
7
|
+
*
|
|
8
|
+
* Both functions are plain `Effect` values; neither requires a Layer or an
|
|
9
|
+
* ambient service. See the `lint-engine` design doc §3 for the rationale
|
|
10
|
+
* behind library primitives over a central engine service.
|
|
11
|
+
*
|
|
12
|
+
* @experimental This API is unstable and may change without notice.
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import * as Effect from "effect/Effect";
|
|
16
|
+
// -----------------------------------------------------------------------------
|
|
17
|
+
// Severity override
|
|
18
|
+
// -----------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Translate a `LintRuleSeverity` config value into an effective `Severity`
|
|
21
|
+
* or the `"off"` sentinel. `"warn"` maps to `"warning"` so downstream code
|
|
22
|
+
* sees the canonical three-severity alphabet.
|
|
23
|
+
*
|
|
24
|
+
* `config.rules` keys are exact rule ids with no wildcard / glob support in v1;
|
|
25
|
+
* see `./config.ts` for the schema.
|
|
26
|
+
*/
|
|
27
|
+
const translateConfigValue = (value) => {
|
|
28
|
+
switch (value) {
|
|
29
|
+
case "warn":
|
|
30
|
+
return "warning";
|
|
31
|
+
case "off":
|
|
32
|
+
case "info":
|
|
33
|
+
case "error":
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const applyOverride = (defaultSeverity, override) => {
|
|
38
|
+
if (defaultSeverity === "error") {
|
|
39
|
+
return "error";
|
|
40
|
+
}
|
|
41
|
+
if (override === undefined) {
|
|
42
|
+
return defaultSeverity;
|
|
43
|
+
}
|
|
44
|
+
const translated = translateConfigValue(override);
|
|
45
|
+
return defaultSeverity === "warning" && translated === "info" ? "warning" : translated;
|
|
46
|
+
};
|
|
47
|
+
const withSeverity = (finding, severity) => ({
|
|
48
|
+
...finding,
|
|
49
|
+
severity,
|
|
50
|
+
});
|
|
51
|
+
// -----------------------------------------------------------------------------
|
|
52
|
+
// evaluateContexts
|
|
53
|
+
// -----------------------------------------------------------------------------
|
|
54
|
+
/**
|
|
55
|
+
* Pair each rule with each context, run `rule.check`, apply severity overrides
|
|
56
|
+
* from `config.rules`, and return one `Evaluated<C>` per pair.
|
|
57
|
+
*
|
|
58
|
+
* Findings whose configured severity is `"off"` are suppressed entirely; the
|
|
59
|
+
* `Evaluated` entry still ships (with an empty `findings` array) so consumers
|
|
60
|
+
* that group by rule still see the rule ran.
|
|
61
|
+
*
|
|
62
|
+
* Rules are evaluated in catalog order; contexts are evaluated in caller
|
|
63
|
+
* order. Rule-context invocation is sequential within a single
|
|
64
|
+
* `evaluateContexts` call so tests can observe deterministic ordering.
|
|
65
|
+
*
|
|
66
|
+
* @experimental This API is unstable and may change without notice.
|
|
67
|
+
*/
|
|
68
|
+
export const evaluateContexts = (rules, contexts, config) => Effect.forEach(rules.flatMap((rule) => contexts.map((context) => ({ rule, context }))), ({ rule, context }) => evaluateOne(rule, context, config), { concurrency: 1 });
|
|
69
|
+
const evaluateOne = (rule, context, config) => Effect.map(rule.check(context), (rawFindings) => ({
|
|
70
|
+
rule,
|
|
71
|
+
context,
|
|
72
|
+
findings: applySeverityConfig(rule, rawFindings, config),
|
|
73
|
+
}));
|
|
74
|
+
const applySeverityConfig = (rule, findings, config) => {
|
|
75
|
+
const override = config.rules?.[rule.id];
|
|
76
|
+
const effective = applyOverride(rule.severity, override);
|
|
77
|
+
if (effective === "off") {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
return findings.map((finding) => withSeverity(finding, effective));
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `issuesToFindings` — shared schema-delegation helper.
|
|
3
|
+
*
|
|
4
|
+
* `-schema-valid` rules delegate their `check` to Effect Schema via
|
|
5
|
+
* `Schema.decodeUnknownResult(schema, { onExcessProperty: "ignore" })` (or the
|
|
6
|
+
* Effect/Exit equivalents) and map the resulting `Issue` tree 1:1 to
|
|
7
|
+
* `AdvisoryFinding`s through this helper. Rules never re-implement schema
|
|
8
|
+
* checks inline; the paired `-keys-recognized` rule owns unknown-key hygiene
|
|
9
|
+
* at warning severity.
|
|
10
|
+
*
|
|
11
|
+
* The helper walks the recursive `SchemaIssue.Issue` tree, accumulating a
|
|
12
|
+
* path at each `Pointer` node and emitting one finding per leaf issue.
|
|
13
|
+
* Composite nodes recurse into their children. Each finding's `message`
|
|
14
|
+
* is branch-specific and guide-conformant: invariant failure first, raw
|
|
15
|
+
* schema detail second when needed, remediation last. `location.file` is the
|
|
16
|
+
* caller-supplied file (the manifest file); v1 does not parse byte positions
|
|
17
|
+
* out of `Issue` values.
|
|
18
|
+
*
|
|
19
|
+
* @experimental This API is unstable and may change without notice.
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
import * as SchemaIssue from "effect/SchemaIssue";
|
|
23
|
+
import type { AdvisoryFinding, Severity } from "./rule.js";
|
|
24
|
+
/**
|
|
25
|
+
* Walk an `Issue` tree and produce one finding per leaf issue.
|
|
26
|
+
*
|
|
27
|
+
* @param ruleId - `<namespace>/<name>` id of the calling rule.
|
|
28
|
+
* @param severity - Severity to stamp on each emitted finding.
|
|
29
|
+
* @param file - Accessor-relative file path to stamp on `location.file`.
|
|
30
|
+
* @param issue - Root `Issue` produced by `Schema.decodeUnknown*`.
|
|
31
|
+
*
|
|
32
|
+
* @experimental This API is unstable and may change without notice.
|
|
33
|
+
*/
|
|
34
|
+
export declare const issuesToFindings: (ruleId: string, severity: Severity, file: string, issue: SchemaIssue.Issue) => ReadonlyArray<AdvisoryFinding>;
|
|
35
|
+
//# sourceMappingURL=issues-to-findings.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `issuesToFindings` — shared schema-delegation helper.
|
|
3
|
+
*
|
|
4
|
+
* `-schema-valid` rules delegate their `check` to Effect Schema via
|
|
5
|
+
* `Schema.decodeUnknownResult(schema, { onExcessProperty: "ignore" })` (or the
|
|
6
|
+
* Effect/Exit equivalents) and map the resulting `Issue` tree 1:1 to
|
|
7
|
+
* `AdvisoryFinding`s through this helper. Rules never re-implement schema
|
|
8
|
+
* checks inline; the paired `-keys-recognized` rule owns unknown-key hygiene
|
|
9
|
+
* at warning severity.
|
|
10
|
+
*
|
|
11
|
+
* The helper walks the recursive `SchemaIssue.Issue` tree, accumulating a
|
|
12
|
+
* path at each `Pointer` node and emitting one finding per leaf issue.
|
|
13
|
+
* Composite nodes recurse into their children. Each finding's `message`
|
|
14
|
+
* is branch-specific and guide-conformant: invariant failure first, raw
|
|
15
|
+
* schema detail second when needed, remediation last. `location.file` is the
|
|
16
|
+
* caller-supplied file (the manifest file); v1 does not parse byte positions
|
|
17
|
+
* out of `Issue` values.
|
|
18
|
+
*
|
|
19
|
+
* @experimental This API is unstable and may change without notice.
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
import * as SchemaIssue from "effect/SchemaIssue";
|
|
23
|
+
import { describeSchemaDocument } from "./describe-document.js";
|
|
24
|
+
// -----------------------------------------------------------------------------
|
|
25
|
+
// Public helper
|
|
26
|
+
// -----------------------------------------------------------------------------
|
|
27
|
+
/**
|
|
28
|
+
* Walk an `Issue` tree and produce one finding per leaf issue.
|
|
29
|
+
*
|
|
30
|
+
* @param ruleId - `<namespace>/<name>` id of the calling rule.
|
|
31
|
+
* @param severity - Severity to stamp on each emitted finding.
|
|
32
|
+
* @param file - Accessor-relative file path to stamp on `location.file`.
|
|
33
|
+
* @param issue - Root `Issue` produced by `Schema.decodeUnknown*`.
|
|
34
|
+
*
|
|
35
|
+
* @experimental This API is unstable and may change without notice.
|
|
36
|
+
*/
|
|
37
|
+
export const issuesToFindings = (ruleId, severity, file, issue) => {
|
|
38
|
+
const findings = [];
|
|
39
|
+
walkIssue(issue, [], (leaf, path) => {
|
|
40
|
+
findings.push(toFinding(ruleId, severity, file, leaf, path));
|
|
41
|
+
});
|
|
42
|
+
return findings;
|
|
43
|
+
};
|
|
44
|
+
const walkIssue = (issue, path, visit) => {
|
|
45
|
+
switch (issue._tag) {
|
|
46
|
+
case "Pointer": {
|
|
47
|
+
walkIssue(issue.issue, [...path, ...issue.path], visit);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
case "Composite":
|
|
51
|
+
case "AnyOf": {
|
|
52
|
+
if (issue.issues.length === 0) {
|
|
53
|
+
// No union member matched / no nested issues — treat as a leaf so
|
|
54
|
+
// the caller sees at least one finding for the covering diagnostic.
|
|
55
|
+
visit(issue, path);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const child of issue.issues) {
|
|
59
|
+
walkIssue(child, path, visit);
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
case "Filter":
|
|
64
|
+
case "Encoding": {
|
|
65
|
+
walkIssue(issue.issue, path, visit);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
case "InvalidType":
|
|
69
|
+
case "InvalidValue":
|
|
70
|
+
case "MissingKey":
|
|
71
|
+
case "UnexpectedKey":
|
|
72
|
+
case "Forbidden":
|
|
73
|
+
case "OneOf": {
|
|
74
|
+
visit(issue, path);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const toFinding = (ruleId, severity, file, issue, path) => {
|
|
80
|
+
return {
|
|
81
|
+
kind: "advisory",
|
|
82
|
+
ruleId,
|
|
83
|
+
severity,
|
|
84
|
+
message: formatIssueMessage(describeSchemaDocument(file), file, issue, path),
|
|
85
|
+
location: { file },
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
const formatIssueMessage = (documentLabel, file, issue, path) => {
|
|
89
|
+
const pathStr = formatPath(path);
|
|
90
|
+
const valueRef = describeValueReference(documentLabel, pathStr);
|
|
91
|
+
switch (issue._tag) {
|
|
92
|
+
case "MissingKey":
|
|
93
|
+
return formatMissingKeyMessage(documentLabel, file, path, pathStr);
|
|
94
|
+
case "UnexpectedKey":
|
|
95
|
+
return formatUnexpectedKeyMessage(documentLabel, file, pathStr);
|
|
96
|
+
case "InvalidType":
|
|
97
|
+
return `${valueRef} has the wrong type. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "replace it with a value of the expected type")}`;
|
|
98
|
+
case "InvalidValue":
|
|
99
|
+
return `${valueRef} is invalid. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "update it so it satisfies the schema constraint")}`;
|
|
100
|
+
case "Forbidden":
|
|
101
|
+
return `${valueRef} uses a value or operation the schema does not allow. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "update it so the document satisfies the schema")}`;
|
|
102
|
+
case "OneOf":
|
|
103
|
+
return `${valueRef} matches more than one allowed shape. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "rewrite it so exactly one allowed shape matches")}`;
|
|
104
|
+
case "AnyOf":
|
|
105
|
+
return `${valueRef} does not match any allowed shape. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "rewrite it so it matches one of the allowed shapes")}`;
|
|
106
|
+
case "Filter":
|
|
107
|
+
return `${valueRef} fails a schema constraint. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "update it so it satisfies the constraint")}`;
|
|
108
|
+
case "Encoding":
|
|
109
|
+
return `${valueRef} cannot be encoded or decoded as required by the schema. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "update it to the shape the schema expects")}`;
|
|
110
|
+
case "Pointer":
|
|
111
|
+
return `${documentLabel} has a schema problem${pathStr === "" ? "" : ` at ${pathStr}`}. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "fix the value at that path so the document satisfies the schema")}`;
|
|
112
|
+
case "Composite":
|
|
113
|
+
return `${valueRef} has multiple schema problems. Detail: ${formatSchemaIssue(issue)}. ${formatRemediation(file, "fix the referenced values so the document satisfies the schema")}`;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const formatSchemaIssue = SchemaIssue.makeFormatterDefault();
|
|
117
|
+
const formatMissingKeyMessage = (documentLabel, file, path, pathStr) => {
|
|
118
|
+
const lastSegment = path[path.length - 1];
|
|
119
|
+
const parentPath = formatPath(path.slice(0, -1));
|
|
120
|
+
if (typeof lastSegment === "string" && pathStr !== "") {
|
|
121
|
+
return parentPath === ""
|
|
122
|
+
? `${documentLabel} is missing required field \`${pathStr}\`. ${formatRemediation(file, `add \`${lastSegment}\``)}`
|
|
123
|
+
: `${documentLabel} is missing required field \`${pathStr}\`. ${formatRemediation(file, `add \`${lastSegment}\` under \`${parentPath}\``)}`;
|
|
124
|
+
}
|
|
125
|
+
if (lastSegment !== undefined && pathStr !== "") {
|
|
126
|
+
return `${documentLabel} is missing a required item at \`${pathStr}\`. ${formatRemediation(file, "add the missing item at that path")}`;
|
|
127
|
+
}
|
|
128
|
+
return `${documentLabel} is missing a required value. ${formatRemediation(file, "add the required value")}`;
|
|
129
|
+
};
|
|
130
|
+
const formatUnexpectedKeyMessage = (documentLabel, file, pathStr) => pathStr === ""
|
|
131
|
+
? `${documentLabel} has an unrecognized field. ${formatRemediation(file, "remove it or rename it to the intended field name")}`
|
|
132
|
+
: `${documentLabel} has unrecognized field \`${pathStr}\`. ${formatRemediation(file, "remove it or rename it to the intended field name")}`;
|
|
133
|
+
const describeValueReference = (documentLabel, pathStr) => pathStr === "" ? documentLabel : `${documentLabel} field \`${pathStr}\``;
|
|
134
|
+
const formatRemediation = (file, manualAction) => isLockfile(file)
|
|
135
|
+
? "Regenerate the workspace lockfile from workspace settings by reinstalling the declared extensions."
|
|
136
|
+
: `Edit \`${file}\` and ${manualAction}.`;
|
|
137
|
+
const formatPath = (path) => path.reduce((acc, segment) => {
|
|
138
|
+
if (typeof segment === "number") {
|
|
139
|
+
return `${acc}[${String(segment)}]`;
|
|
140
|
+
}
|
|
141
|
+
return acc === "" ? String(segment) : `${acc}.${String(segment)}`;
|
|
142
|
+
}, "");
|
|
143
|
+
const basename = (file) => {
|
|
144
|
+
const normalized = file.replace(/\\/g, "/");
|
|
145
|
+
const parts = normalized.split("/");
|
|
146
|
+
return parts[parts.length - 1] ?? normalized;
|
|
147
|
+
};
|
|
148
|
+
const isLockfile = (file) => basename(file) === "axm-lock.yaml";
|
|
149
|
+
//# sourceMappingURL=issues-to-findings.js.map
|