@agentxm/workspace-lint 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.
Files changed (100) hide show
  1. package/LICENSE +110 -0
  2. package/dist/src/catalog/index.d.ts +31 -0
  3. package/dist/src/catalog/index.js +60 -0
  4. package/dist/src/catalog/workspace/agents-detected-declared.d.ts +23 -0
  5. package/dist/src/catalog/workspace/agents-detected-declared.js +61 -0
  6. package/dist/src/catalog/workspace/agents-recognized.d.ts +23 -0
  7. package/dist/src/catalog/workspace/agents-recognized.js +64 -0
  8. package/dist/src/catalog/workspace/axm-skill-compatible.d.ts +4 -0
  9. package/dist/src/catalog/workspace/axm-skill-compatible.js +51 -0
  10. package/dist/src/catalog/workspace/configured-but-not-installed.d.ts +4 -0
  11. package/dist/src/catalog/workspace/configured-but-not-installed.js +88 -0
  12. package/dist/src/catalog/workspace/desired-state-reconcilable.d.ts +4 -0
  13. package/dist/src/catalog/workspace/desired-state-reconcilable.js +96 -0
  14. package/dist/src/catalog/workspace/display-paths.d.ts +7 -0
  15. package/dist/src/catalog/workspace/display-paths.js +4 -0
  16. package/dist/src/catalog/workspace/helpers/empty.d.ts +18 -0
  17. package/dist/src/catalog/workspace/helpers/empty.js +16 -0
  18. package/dist/src/catalog/workspace/helpers/finding.d.ts +10 -0
  19. package/dist/src/catalog/workspace/helpers/finding.js +11 -0
  20. package/dist/src/catalog/workspace/helpers/source-categorize.d.ts +16 -0
  21. package/dist/src/catalog/workspace/helpers/source-categorize.js +51 -0
  22. package/dist/src/catalog/workspace/hook-ownership-ambiguous.d.ts +4 -0
  23. package/dist/src/catalog/workspace/hook-ownership-ambiguous.js +25 -0
  24. package/dist/src/catalog/workspace/initialized.d.ts +22 -0
  25. package/dist/src/catalog/workspace/initialized.js +58 -0
  26. package/dist/src/catalog/workspace/instructions-agent-supported.d.ts +4 -0
  27. package/dist/src/catalog/workspace/instructions-agent-supported.js +38 -0
  28. package/dist/src/catalog/workspace/instructions-gitignore-current.d.ts +4 -0
  29. package/dist/src/catalog/workspace/instructions-gitignore-current.js +49 -0
  30. package/dist/src/catalog/workspace/instructions-source-present.d.ts +4 -0
  31. package/dist/src/catalog/workspace/instructions-source-present.js +41 -0
  32. package/dist/src/catalog/workspace/instructions-target-current.d.ts +4 -0
  33. package/dist/src/catalog/workspace/instructions-target-current.js +51 -0
  34. package/dist/src/catalog/workspace/instructions-target-stale.d.ts +9 -0
  35. package/dist/src/catalog/workspace/instructions-target-stale.js +41 -0
  36. package/dist/src/catalog/workspace/instructions-target-unowned.d.ts +10 -0
  37. package/dist/src/catalog/workspace/instructions-target-unowned.js +59 -0
  38. package/dist/src/catalog/workspace/knowledge-state-valid.d.ts +5 -0
  39. package/dist/src/catalog/workspace/knowledge-state-valid.js +65 -0
  40. package/dist/src/catalog/workspace/lockfile-valid.d.ts +5 -0
  41. package/dist/src/catalog/workspace/lockfile-valid.js +63 -0
  42. package/dist/src/catalog/workspace/managed-file-unowned.d.ts +4 -0
  43. package/dist/src/catalog/workspace/managed-file-unowned.js +25 -0
  44. package/dist/src/catalog/workspace/mcps-agent-drift.d.ts +4 -0
  45. package/dist/src/catalog/workspace/mcps-agent-drift.js +139 -0
  46. package/dist/src/catalog/workspace/mcps-agent-orphaned.d.ts +4 -0
  47. package/dist/src/catalog/workspace/mcps-agent-orphaned.js +64 -0
  48. package/dist/src/catalog/workspace/mcps-no-secret-literal.d.ts +4 -0
  49. package/dist/src/catalog/workspace/mcps-no-secret-literal.js +67 -0
  50. package/dist/src/catalog/workspace/mcps-shared-target-compatible.d.ts +4 -0
  51. package/dist/src/catalog/workspace/mcps-shared-target-compatible.js +58 -0
  52. package/dist/src/catalog/workspace/mcps-transport-exclusivity.d.ts +4 -0
  53. package/dist/src/catalog/workspace/mcps-transport-exclusivity.js +67 -0
  54. package/dist/src/catalog/workspace/packs-declarations-valid.d.ts +19 -0
  55. package/dist/src/catalog/workspace/packs-declarations-valid.js +110 -0
  56. package/dist/src/catalog/workspace/packs-dependencies-resolved.d.ts +5 -0
  57. package/dist/src/catalog/workspace/packs-dependencies-resolved.js +49 -0
  58. package/dist/src/catalog/workspace/projections-current.d.ts +15 -0
  59. package/dist/src/catalog/workspace/projections-current.js +35 -0
  60. package/dist/src/catalog/workspace/settings-keys-recognized.d.ts +17 -0
  61. package/dist/src/catalog/workspace/settings-keys-recognized.js +90 -0
  62. package/dist/src/catalog/workspace/settings-schema-valid.d.ts +27 -0
  63. package/dist/src/catalog/workspace/settings-schema-valid.js +68 -0
  64. package/dist/src/catalog/workspace/skills-artifacts-correct.d.ts +28 -0
  65. package/dist/src/catalog/workspace/skills-artifacts-correct.js +143 -0
  66. package/dist/src/catalog/workspace/skills-declarations-valid.d.ts +27 -0
  67. package/dist/src/catalog/workspace/skills-declarations-valid.js +102 -0
  68. package/dist/src/catalog/workspace/skills-integrity-valid.d.ts +28 -0
  69. package/dist/src/catalog/workspace/skills-integrity-valid.js +95 -0
  70. package/dist/src/catalog/workspace/skills-lockfile-aligned.d.ts +5 -0
  71. package/dist/src/catalog/workspace/skills-lockfile-aligned.js +64 -0
  72. package/dist/src/catalog/workspace/source-endpoints-aligned.d.ts +5 -0
  73. package/dist/src/catalog/workspace/source-endpoints-aligned.js +75 -0
  74. package/dist/src/catalog/workspace-fixtures/fixture-state.d.ts +8 -0
  75. package/dist/src/catalog/workspace-fixtures/fixture-state.js +120 -0
  76. package/dist/src/catalog/workspace-fixtures/interpret-ops.d.ts +11 -0
  77. package/dist/src/catalog/workspace-fixtures/interpret-ops.js +9 -0
  78. package/dist/src/catalog/workspace-read-model/lint-workspace.d.ts +191 -0
  79. package/dist/src/catalog/workspace-read-model/lint-workspace.js +651 -0
  80. package/dist/src/catalog/workspace-read-model/manifest-json.d.ts +14 -0
  81. package/dist/src/catalog/workspace-read-model/manifest-json.js +27 -0
  82. package/dist/src/catalog/workspace.d.ts +58 -0
  83. package/dist/src/catalog/workspace.js +164 -0
  84. package/dist/src/catalog-contexts.d.ts +106 -0
  85. package/dist/src/catalog-contexts.js +95 -0
  86. package/dist/src/cli.d.ts +239 -0
  87. package/dist/src/cli.js +1077 -0
  88. package/dist/src/index.d.ts +10 -0
  89. package/dist/src/index.js +21 -0
  90. package/dist/src/json-schema.d.ts +121 -0
  91. package/dist/src/json-schema.js +99 -0
  92. package/dist/src/run/errors.d.ts +23 -0
  93. package/dist/src/run/errors.js +21 -0
  94. package/dist/src/run/settings.d.ts +63 -0
  95. package/dist/src/run/settings.js +139 -0
  96. package/dist/src/run/staged-workspace.d.ts +31 -0
  97. package/dist/src/run/staged-workspace.js +273 -0
  98. package/dist/src/workspace-context.d.ts +129 -0
  99. package/dist/src/workspace-context.js +12 -0
  100. package/package.json +55 -0
@@ -0,0 +1,651 @@
1
+ // @effect-diagnostics anyUnknownInErrorContext:off — lint converts opaque read-model failures into fact-only findings at this boundary
2
+ /**
3
+ * `LintWorkspace` — single helper that produces both the per-rule
4
+ * `WorkspaceRuleContext` and the flat `LintWorkspaceView` projection a lint
5
+ * run needs, sharing one `WorkspaceReadModelLive` setup.
6
+ *
7
+ * `LintWorkspaceView` exposes `installedSkills: InstalledSkillInfo[]` and
8
+ * `installedPacks: InstalledPackInfo[]` with per-provenance `displayRoot`s:
9
+ *
10
+ * Registry-installed native skill: `agent_extensions/<source>/<@owner>/skills/<name>/src/`
11
+ * Portable acquired skill: `agent_extensions/<source>/<source-full-name>/`
12
+ * Registry pack: `agent_extensions/<source>/<@owner>/packs/<name>/`
13
+ * (NO `src/` — matches the on-disk layout.)
14
+ *
15
+ * The companion `WorkspaceRuleContext` is scoped to project or user.
16
+ * User-scope resolution uses `.axm/workspace/` under `$AXM_USER_HOME` when set,
17
+ * otherwise under `$HOME`; a follow-up owns the broader XDG story.
18
+ *
19
+ * @experimental This API is unstable and may change without notice.
20
+ * @packageDocumentation
21
+ */
22
+ import * as Effect from "effect/Effect";
23
+ import * as FileSystem from "effect/FileSystem";
24
+ import * as Layer from "effect/Layer";
25
+ import * as Option from "effect/Option";
26
+ import * as Path from "effect/Path";
27
+ import * as Result from "effect/Result";
28
+ import * as Schema from "effect/Schema";
29
+ import { makeAbsolutePath } from "@agentxm/extension-model/unstable/path-types";
30
+ import { AgentRootResolverLive } from "@agentxm/workspace-state";
31
+ import { makeWorkspaceReadModel, WorkspaceReadModelConfig, } from "@agentxm/workspace-state";
32
+ import { AXM_DIR_NAME, USER_WORKSPACE_DIRECTORY } from "@agentxm/workspace-state";
33
+ import { makePlatformSkillFileAccessor } from "@agentxm/extension-workspace";
34
+ import { makePlatformPackFileAccessor } from "@agentxm/extension-workspace";
35
+ import { acquiredExtensionDisplayPathFromLockEntry, } from "@agentxm/workspace-state";
36
+ import { parseRegistrySourceRef } from "@agentxm/extension-model/unstable/extensions/registry-source";
37
+ import { HOOK_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/hooks/manifest-schema";
38
+ import { KNOWLEDGE_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/knowledge/manifest-schema";
39
+ import { inspectKnowledgePackage, buildPackDependencyReachability, readAxmSkillWorkspaceCompatibility, observeInstructionProjection, resolveInstructionsConfig, } from "@agentxm/extension-workspace";
40
+ import { MCP_SERVER_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/mcps/manifest-schema";
41
+ import { canonicalDisplayRoot } from "../workspace/display-paths.js";
42
+ import { RULE_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/rules/manifest-schema";
43
+ import { PACK_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/packs/manifest-schema";
44
+ import { PackManifestSchema } from "@agentxm/extension-model/unstable/packs/manifest-schema";
45
+ import { MANIFEST_FILENAME as SKILL_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/skills/manifest-schema";
46
+ import { MANIFEST_FILENAME as SUBAGENT_MANIFEST_FILENAME } from "@agentxm/extension-model/unstable/subagents/manifest-schema";
47
+ import { readManifestJson } from "./manifest-json.js";
48
+ import { toExtensionTypePlural } from "@agentxm/extension-model/unstable/extensions/common";
49
+ /**
50
+ * Build the per-rule `WorkspaceRuleContext` and the flat `LintWorkspaceView`
51
+ * via a single {@link makeWorkspaceReadModel} invocation.
52
+ *
53
+ * `WorkspaceRootEscape` is surfaced in the error channel by the factory when
54
+ * `workspaceRoot` or `userHome` escape the filesystem root.
55
+ *
56
+ * @experimental This API is unstable and may change without notice.
57
+ */
58
+ export const buildLintWorkspace = (args) => {
59
+ const platformLayer = Layer.mergeAll(Layer.succeed(FileSystem.FileSystem, args.platform.fs), Layer.succeed(Path.Path, args.platform.path));
60
+ const env = Layer.mergeAll(platformLayer, Layer.succeed(WorkspaceReadModelConfig, {
61
+ projectRoot: makeAbsolutePath(args.platform.path, args.workspaceRoot),
62
+ userHome: makeAbsolutePath(args.platform.path, args.userHome),
63
+ allowedRoot: makeAbsolutePath(args.platform.path, "/"),
64
+ }), AgentRootResolverLive.pipe(Layer.provide(platformLayer)));
65
+ return Effect.gen(function* () {
66
+ const readModel = yield* makeWorkspaceReadModel(args.scope);
67
+ const axmDir = args.scope === "user"
68
+ ? args.platform.path.join(args.userHome, AXM_DIR_NAME, USER_WORKSPACE_DIRECTORY, AXM_DIR_NAME)
69
+ : args.platform.path.join(args.workspaceRoot, AXM_DIR_NAME);
70
+ const projection = yield* buildLintWorkspaceView({
71
+ platform: args.platform,
72
+ workspaceRoot: args.workspaceRoot,
73
+ readModel,
74
+ scope: args.scope,
75
+ inspectKnowledge: args.inspectKnowledge ?? inspectKnowledgePackage,
76
+ });
77
+ const rule = {
78
+ subject: { root: args.workspaceRoot, scope: args.scope },
79
+ workspace: readModel,
80
+ axmDirExists: args.platform.fs.exists(axmDir).pipe(Effect.catch(() => Effect.succeed(false))),
81
+ instructions: yield* makeInstructionAccessor({
82
+ platform: args.platform,
83
+ workspaceRoot: args.workspaceRoot,
84
+ scope: args.scope,
85
+ readModel,
86
+ gitIndexView: args.gitIndexView === true,
87
+ }),
88
+ // The projection already read every installed manifest; hand the same
89
+ // values to workspace rules rather than re-reading them per rule.
90
+ installedExtensions: { manifests: Effect.succeed(projection.installedManifests) },
91
+ packDependencyReachability: Effect.succeed(projection.packDependencyReachability),
92
+ ...(args.owner === undefined ? {} : { owner: args.owner }),
93
+ ...(args.projections === undefined ? {} : { projections: args.projections }),
94
+ ...(args.axmSkillCompatibilityPolicy === undefined
95
+ ? {}
96
+ : {
97
+ axmSkillCompatibility: readAxmSkillWorkspaceCompatibility({
98
+ platform: args.platform,
99
+ workspace: readModel,
100
+ policy: args.axmSkillCompatibilityPolicy,
101
+ }),
102
+ }),
103
+ displayRoot: args.displayRoot ?? "",
104
+ };
105
+ return { rule, view: projection.view };
106
+ }).pipe(Effect.provide(env));
107
+ };
108
+ /**
109
+ * The instruction rules share one observation per lint run: roots are
110
+ * discovered and the plan is expanded once, and every rule reads target and
111
+ * `.gitignore` facts from the same snapshot.
112
+ */
113
+ const makeInstructionAccessor = (args) => Effect.gen(function* () {
114
+ const platformLayer = Layer.mergeAll(Layer.succeed(FileSystem.FileSystem, args.platform.fs), Layer.succeed(Path.Path, args.platform.path));
115
+ const snapshot = yield* Effect.cached(Effect.gen(function* () {
116
+ const settings = yield* args.readModel.state.settings.pipe(Effect.catch(() => Effect.succeed(Option.none())));
117
+ if (Option.isNone(settings))
118
+ return Option.none();
119
+ const rawConfig = Option.fromUndefinedOr(settings.value.instructionFiles);
120
+ if (Option.isNone(rawConfig) || rawConfig.value === false)
121
+ return Option.none();
122
+ return Option.some(yield* observeInstructionProjection({
123
+ workspaceRoot: args.workspaceRoot,
124
+ scope: args.scope,
125
+ configuredAgents: settings.value.agents ?? [],
126
+ config: resolveInstructionsConfig(rawConfig.value),
127
+ gitIndexView: args.gitIndexView,
128
+ }).pipe(Effect.provide(platformLayer)));
129
+ }));
130
+ return { snapshot };
131
+ });
132
+ const joinManifestPath = (root, filename) => root === "" || root === "." ? filename : `${root}/${filename}`;
133
+ const buildLintWorkspaceView = (args) => Effect.gen(function* () {
134
+ const [skills, packs, subagents, mcpServers, hooks, rules, knowledge] = yield* Effect.all([
135
+ args.readModel.skills.installed,
136
+ args.readModel.packs.installed,
137
+ args.readModel.subagents.installed,
138
+ args.readModel.mcpServers.installed,
139
+ args.readModel.hooks.installed,
140
+ args.readModel.rules.installed,
141
+ args.readModel.knowledge.installed,
142
+ ], { concurrency: "unbounded" });
143
+ const namedSkills = skills.flatMap((skill) => {
144
+ const built = installedSkillToInfo(args, skill);
145
+ return built === undefined
146
+ ? []
147
+ : [
148
+ {
149
+ name: skill.key.name,
150
+ manifestPath: joinManifestPath(built.packageDisplayRoot, SKILL_MANIFEST_FILENAME),
151
+ info: built.info,
152
+ },
153
+ ];
154
+ });
155
+ const installedPacks = packs.flatMap((pack) => {
156
+ const info = installedPackToInfo(args, pack);
157
+ return info === undefined ? [] : [{ installed: pack, info }];
158
+ });
159
+ const namedSubagents = subagents.flatMap((subagent) => {
160
+ const context = installedSubagentToContext(args, subagent);
161
+ return context === undefined
162
+ ? []
163
+ : [namedContext(subagent.key.name, context, SUBAGENT_MANIFEST_FILENAME)];
164
+ });
165
+ const namedMcpServers = mcpServers.flatMap((mcpServer) => {
166
+ const context = installedMcpServerToContext(args, mcpServer);
167
+ return context === undefined
168
+ ? []
169
+ : [namedContext(mcpServer.key.name, context, MCP_SERVER_MANIFEST_FILENAME)];
170
+ });
171
+ const namedHooks = hooks.flatMap((hook) => {
172
+ const context = installedHookToContext(args, hook);
173
+ return context === undefined
174
+ ? []
175
+ : [namedContext(hook.key.name, context, HOOK_MANIFEST_FILENAME)];
176
+ });
177
+ const namedRules = rules.flatMap((rule) => {
178
+ const context = installedRuleToContext(args, rule);
179
+ return context === undefined
180
+ ? []
181
+ : [namedContext(rule.key.name, context, RULE_MANIFEST_FILENAME)];
182
+ });
183
+ const namedKnowledge = knowledge.flatMap((bundle) => {
184
+ const context = installedKnowledgeToContext(args, bundle);
185
+ return context === undefined
186
+ ? []
187
+ : [namedContext(bundle.key.name, context, KNOWLEDGE_MANIFEST_FILENAME)];
188
+ });
189
+ const [skillsWithJson, installedPacksWithJson, subagentsWithJson, mcpServersWithJson, hooksWithJson, rulesWithJson, knowledgeWithJson,] = yield* Effect.all([
190
+ populateSkillManifestJson(namedSkills),
191
+ populatePackManifestJson(installedPacks),
192
+ populateSubagentManifestJson(namedSubagents),
193
+ populateMcpServerManifestJson(namedMcpServers),
194
+ populateHookManifestJson(namedHooks),
195
+ populateRuleManifestJson(namedRules),
196
+ populateKnowledgeManifestJson(namedKnowledge, args.inspectKnowledge),
197
+ ], { concurrency: "unbounded" });
198
+ return {
199
+ view: {
200
+ installedSkills: skillsWithJson.map((entry) => entry.info),
201
+ installedPacks: installedPacksWithJson.map((entry) => entry.info),
202
+ subagentContexts: subagentsWithJson.map((entry) => entry.context),
203
+ mcpServerContexts: mcpServersWithJson.map((entry) => entry.context),
204
+ hookContexts: hooksWithJson.map((entry) => entry.context),
205
+ ruleContexts: rulesWithJson.map((entry) => entry.context),
206
+ knowledgeContexts: knowledgeWithJson.map((entry) => entry.context),
207
+ },
208
+ installedManifests: [
209
+ ...skillsWithJson.map((entry) => ({
210
+ extensionType: "skill",
211
+ name: entry.name,
212
+ manifestPath: entry.manifestPath,
213
+ manifestJson: entry.info.skillJson,
214
+ })),
215
+ ...toManifests("subagent", subagentsWithJson, (c) => c.subject.subagentJson),
216
+ ...toManifests("mcp-server", mcpServersWithJson, (c) => c.subject.mcpServerJson),
217
+ ...toManifests("hook", hooksWithJson, (c) => c.subject.hookJson),
218
+ ...toManifests("rule", rulesWithJson, (c) => c.subject.ruleJson),
219
+ ...toManifests("knowledge", knowledgeWithJson, (c) => c.subject.knowledgeJson),
220
+ ],
221
+ packDependencyReachability: buildPackDependencyReachability({
222
+ packs: installedPacksWithJson.flatMap(toPackDependencyDeclaration),
223
+ members: [
224
+ ...skills.flatMap((entry) => memberObservation("skill", entry.resolved)),
225
+ ...subagents.flatMap((entry) => memberObservation("subagent", entry.resolved)),
226
+ ...mcpServers.flatMap((entry) => memberObservation("mcp-server", entry.resolved)),
227
+ ...hooks.flatMap((entry) => memberObservation("hook", entry.resolved)),
228
+ ...rules.flatMap((entry) => memberObservation("rule", entry.resolved)),
229
+ ...knowledge.flatMap((entry) => memberObservation("knowledge", entry.resolved)),
230
+ ],
231
+ }),
232
+ };
233
+ });
234
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
235
+ const memberObservation = (extensionType, resolved) => {
236
+ if (Option.isNone(resolved) || !isRecord(resolved.value.lockEntry))
237
+ return [];
238
+ const entry = resolved.value.lockEntry;
239
+ const authority = entry["type"];
240
+ const owner = entry["owner"];
241
+ const name = entry["name"];
242
+ const version = authority === "workspace" ? entry["version"] : entry["resolvedVersion"];
243
+ if ((authority !== "workspace" && authority !== "registry") ||
244
+ typeof owner !== "string" ||
245
+ typeof name !== "string" ||
246
+ typeof version !== "string") {
247
+ return [];
248
+ }
249
+ return [
250
+ {
251
+ fqn: `${owner}/${toExtensionTypePlural(extensionType)}/${name}`,
252
+ version,
253
+ authority,
254
+ },
255
+ ];
256
+ };
257
+ const installedPackAuthority = (installed) => {
258
+ if (Option.isSome(installed.resolved)) {
259
+ return "registry";
260
+ }
261
+ if (installed.installationOrigin._tag !== "direct")
262
+ return "registry";
263
+ const declared = installed.installationOrigin.declared.entry;
264
+ const source = typeof declared === "string" ? declared : declared.source;
265
+ return source === "workspace" ? "workspace" : "registry";
266
+ };
267
+ const toPackDependencyDeclaration = (entry) => {
268
+ const decoded = Schema.decodeUnknownResult(PackManifestSchema)(entry.info.packJson);
269
+ if (Result.isFailure(decoded))
270
+ return [];
271
+ const manifest = decoded.success;
272
+ return [
273
+ {
274
+ packFqn: `${manifest.owner}/packs/${manifest.name}`,
275
+ packAuthority: installedPackAuthority(entry.installed),
276
+ manifestPath: joinManifestPath(entry.info.displayRoot, PACK_MANIFEST_FILENAME),
277
+ dependencies: manifest.dependencies,
278
+ },
279
+ ];
280
+ };
281
+ const namedContext = (name, context, manifestFilename) => ({
282
+ name,
283
+ manifestPath: joinManifestPath(context.displayRoot, manifestFilename),
284
+ context,
285
+ });
286
+ const toManifests = (extensionType, entries, manifestJson) => entries.map((entry) => ({
287
+ extensionType,
288
+ name: entry.name,
289
+ manifestPath: entry.manifestPath,
290
+ manifestJson: manifestJson(entry.context),
291
+ }));
292
+ const populateSkillManifestJson = (namedSkills) => Effect.forEach(namedSkills, (entry) => Effect.gen(function* () {
293
+ if (!entry.info.isNative) {
294
+ return entry;
295
+ }
296
+ const skillJson = yield* readManifestJson(entry.info.packageFiles, SKILL_MANIFEST_FILENAME);
297
+ return { ...entry, info: { ...entry.info, skillJson } };
298
+ }), { concurrency: "unbounded" });
299
+ const populateSubagentManifestJson = (entries) => Effect.forEach(entries, (entry) => Effect.gen(function* () {
300
+ const subagentJson = yield* readManifestJson(entry.context.files, SUBAGENT_MANIFEST_FILENAME);
301
+ return { ...entry, context: { ...entry.context, subject: { subagentJson } } };
302
+ }), { concurrency: "unbounded" });
303
+ const populateMcpServerManifestJson = (entries) => Effect.forEach(entries, (entry) => Effect.gen(function* () {
304
+ const mcpServerJson = yield* readManifestJson(entry.context.files, MCP_SERVER_MANIFEST_FILENAME);
305
+ return { ...entry, context: { ...entry.context, subject: { mcpServerJson } } };
306
+ }), { concurrency: "unbounded" });
307
+ const populateHookManifestJson = (entries) => Effect.forEach(entries, (entry) => Effect.gen(function* () {
308
+ const hookJson = yield* readManifestJson(entry.context.files, HOOK_MANIFEST_FILENAME);
309
+ return { ...entry, context: { ...entry.context, subject: { hookJson } } };
310
+ }), { concurrency: "unbounded" });
311
+ const populateRuleManifestJson = (entries) => Effect.forEach(entries, (entry) => Effect.gen(function* () {
312
+ const ruleJson = yield* readManifestJson(entry.context.files, RULE_MANIFEST_FILENAME);
313
+ return { ...entry, context: { ...entry.context, subject: { ruleJson } } };
314
+ }), { concurrency: "unbounded" });
315
+ const populateKnowledgeManifestJson = (entries, inspectKnowledge) => Effect.forEach(entries, (entry) => Effect.gen(function* () {
316
+ const knowledgeJson = yield* readManifestJson(entry.context.files, KNOWLEDGE_MANIFEST_FILENAME);
317
+ const inspection = entry.context.packageRoot === undefined
318
+ ? undefined
319
+ : yield* inspectKnowledge(entry.context.packageRoot).pipe(Effect.map((result) => result.inspection), Effect.catch(() => Effect.succeed(undefined)));
320
+ const subject = {
321
+ knowledgeJson,
322
+ ...(inspection === undefined ? {} : { inspection }),
323
+ };
324
+ return {
325
+ ...entry,
326
+ context: { ...entry.context, subject },
327
+ };
328
+ }), { concurrency: "unbounded" });
329
+ const populatePackManifestJson = (installedPacks) => Effect.forEach(installedPacks, (entry) => Effect.gen(function* () {
330
+ const packJson = yield* readManifestJson(entry.info.files, PACK_MANIFEST_FILENAME);
331
+ return { ...entry, info: { ...entry.info, packJson } };
332
+ }), { concurrency: "unbounded" });
333
+ const installedSkillToInfo = (args, skill) => {
334
+ const actual = chooseSkillActual(skill.actual);
335
+ if (actual !== undefined) {
336
+ const files = makePlatformSkillFileAccessor(args.platform, actual.contentRoot);
337
+ const packageRoot = actual.packageRoot ?? actual.contentRoot;
338
+ return {
339
+ info: {
340
+ isNative: isNativeSkill(skill, actual),
341
+ skillJson: undefined,
342
+ expectedName: skill.key.name,
343
+ displayRoot: relativeDisplayRoot(args, actual.contentRoot),
344
+ files,
345
+ packageFiles: makePlatformSkillFileAccessor(args.platform, packageRoot),
346
+ },
347
+ packageDisplayRoot: relativeDisplayRoot(args, packageRoot),
348
+ };
349
+ }
350
+ const resolved = skill.resolved;
351
+ if (Option.isSome(resolved)) {
352
+ const info = buildAcquiredInstalledSkillInfo({
353
+ platform: args.platform,
354
+ workspaceRoot: args.workspaceRoot,
355
+ scope: args.scope,
356
+ lockEntry: resolved.value.lockEntry,
357
+ name: skill.key.name,
358
+ });
359
+ return {
360
+ info,
361
+ packageDisplayRoot: acquiredPackageDisplayRoot(args.scope, resolved.value.lockEntry, "skills", skill.key.name),
362
+ };
363
+ }
364
+ if (skill.installationOrigin._tag === "direct") {
365
+ const parsed = parseRegistrySourceRef(skill.installationOrigin.declared.entry.source);
366
+ if (parsed !== undefined && parsed.type === "skills") {
367
+ return nativeSkillInfo(args, "agentxm", parsed.owner, skill.key.name);
368
+ }
369
+ }
370
+ return undefined;
371
+ };
372
+ const nativeSkillInfo = (args, sourceName, owner, name) => ({
373
+ info: buildNativeInstalledSkillInfo({
374
+ platform: args.platform,
375
+ workspaceRoot: args.workspaceRoot,
376
+ scope: args.scope,
377
+ sourceName,
378
+ owner,
379
+ name,
380
+ skillJson: undefined,
381
+ }),
382
+ packageDisplayRoot: `${canonicalDisplayRoot(args.scope)}/${sourceName}/${owner}/skills/${name}`,
383
+ });
384
+ const installedPackToInfo = (args, pack) => {
385
+ const actual = choosePackActual(pack.actual);
386
+ if (actual !== undefined) {
387
+ return {
388
+ packJson: undefined,
389
+ displayRoot: relativeDisplayRoot(args, actual.contentRoot),
390
+ files: makePlatformPackFileAccessor(args.platform, actual.contentRoot),
391
+ };
392
+ }
393
+ const resolved = pack.resolved;
394
+ if (Option.isSome(resolved) && resolved.value.lockEntry.type === "registry") {
395
+ return buildInstalledPackInfo({
396
+ platform: args.platform,
397
+ workspaceRoot: args.workspaceRoot,
398
+ scope: args.scope,
399
+ sourceName: resolved.value.lockEntry.sourceName,
400
+ owner: resolved.value.lockEntry.owner,
401
+ name: pack.key.name,
402
+ packJson: undefined,
403
+ });
404
+ }
405
+ if (pack.installationOrigin._tag === "direct") {
406
+ const parsed = parseRegistrySourceRef(pack.installationOrigin.declared.entry.source);
407
+ if (parsed !== undefined && parsed.type === "packs") {
408
+ return buildInstalledPackInfo({
409
+ platform: args.platform,
410
+ workspaceRoot: args.workspaceRoot,
411
+ scope: args.scope,
412
+ sourceName: "agentxm",
413
+ owner: parsed.owner,
414
+ name: pack.key.name,
415
+ packJson: undefined,
416
+ });
417
+ }
418
+ }
419
+ return undefined;
420
+ };
421
+ const installedSubagentToContext = (args, subagent) => {
422
+ const root = subagentPackageRoot(args, subagent);
423
+ if (root === undefined) {
424
+ return undefined;
425
+ }
426
+ return {
427
+ subject: { subagentJson: undefined },
428
+ files: makePlatformPackFileAccessor(args.platform, root),
429
+ displayRoot: relativeDisplayRoot(args, root),
430
+ };
431
+ };
432
+ const installedMcpServerToContext = (args, mcpServer) => {
433
+ const root = mcpServerPackageRoot(args, mcpServer);
434
+ if (root === undefined) {
435
+ return undefined;
436
+ }
437
+ return {
438
+ subject: { mcpServerJson: undefined },
439
+ files: makePlatformPackFileAccessor(args.platform, root),
440
+ displayRoot: relativeDisplayRoot(args, root),
441
+ };
442
+ };
443
+ const installedHookToContext = (args, hook) => {
444
+ const root = canonicalPackageRoot(args, {
445
+ name: hook.key.name,
446
+ plural: "hooks",
447
+ actual: hook.actual,
448
+ resolved: hook.resolved,
449
+ installationOrigin: hook.installationOrigin,
450
+ });
451
+ if (root === undefined) {
452
+ return undefined;
453
+ }
454
+ return {
455
+ subject: { hookJson: undefined },
456
+ files: makePlatformPackFileAccessor(args.platform, root),
457
+ displayRoot: relativeDisplayRoot(args, root),
458
+ };
459
+ };
460
+ const installedRuleToContext = (args, rule) => {
461
+ const root = canonicalPackageRoot(args, {
462
+ name: rule.key.name,
463
+ plural: "rules",
464
+ actual: rule.actual,
465
+ resolved: rule.resolved,
466
+ installationOrigin: rule.installationOrigin,
467
+ });
468
+ if (root === undefined) {
469
+ return undefined;
470
+ }
471
+ return {
472
+ subject: { ruleJson: undefined },
473
+ files: makePlatformPackFileAccessor(args.platform, root),
474
+ displayRoot: relativeDisplayRoot(args, root),
475
+ };
476
+ };
477
+ const installedKnowledgeToContext = (args, bundle) => {
478
+ const root = canonicalPackageRoot(args, {
479
+ name: bundle.key.name,
480
+ plural: "knowledge",
481
+ actual: bundle.actual,
482
+ resolved: bundle.resolved,
483
+ installationOrigin: bundle.installationOrigin,
484
+ });
485
+ if (root === undefined) {
486
+ return undefined;
487
+ }
488
+ return {
489
+ subject: { knowledgeJson: undefined },
490
+ files: makePlatformPackFileAccessor(args.platform, root),
491
+ displayRoot: relativeDisplayRoot(args, root),
492
+ packageRoot: root,
493
+ };
494
+ };
495
+ /**
496
+ * Locate an installed package's root the same way for every family whose
497
+ * canonical layout is source-qualified: prefer a scanned `packageRoot`, then
498
+ * reconstruct the exact path from the accepted lock entry.
499
+ *
500
+ * Returns `undefined` when neither applies — the extension is
501
+ * configured but not on disk in a location lint can read, which is
502
+ * `workspace/configured-but-not-installed`'s finding to make, not a per-type
503
+ * manifest rule's.
504
+ */
505
+ const canonicalPackageRoot = (args, subject) => {
506
+ const scanned = subject.actual.find((entry) => entry.packageRoot !== null);
507
+ if (scanned?.packageRoot !== undefined && scanned.packageRoot !== null) {
508
+ return scanned.packageRoot;
509
+ }
510
+ const resolved = subject.resolved;
511
+ if (Option.isSome(resolved)) {
512
+ return args.platform.path.resolve(args.workspaceRoot, acquiredPackageDisplayRoot(args.scope, resolved.value.lockEntry, subject.plural, subject.name));
513
+ }
514
+ return undefined;
515
+ };
516
+ const chooseSkillActual = (actual) => actual.find((entry) => entry.origin._tag !== "agent-skill-dir") ?? actual[0];
517
+ const choosePackActual = (actual) => actual[0];
518
+ const chooseSubagentActual = (actual) => actual.find((entry) => entry.packageRoot !== null);
519
+ const chooseMcpServerActual = (actual) => actual.find((entry) => entry.contentRoot !== null);
520
+ const subagentPackageRoot = (args, subagent) => {
521
+ const actual = chooseSubagentActual(subagent.actual);
522
+ if (actual?.packageRoot !== undefined && actual.packageRoot !== null) {
523
+ return actual.packageRoot;
524
+ }
525
+ const resolved = subagent.resolved;
526
+ if (Option.isSome(resolved)) {
527
+ return args.platform.path.resolve(args.workspaceRoot, acquiredPackageDisplayRoot(args.scope, resolved.value.lockEntry, "subagents", subagent.key.name));
528
+ }
529
+ if (subagent.installationOrigin._tag === "direct") {
530
+ const parsed = parseRegistrySourceRef(subagent.installationOrigin.declared.entry.source);
531
+ if (parsed !== undefined && parsed.type === "subagents") {
532
+ return args.platform.path.resolve(args.workspaceRoot, `${canonicalDisplayRoot(args.scope)}/agentxm/${parsed.owner}/subagents/${subagent.key.name}`);
533
+ }
534
+ }
535
+ return undefined;
536
+ };
537
+ const mcpServerPackageRoot = (args, mcpServer) => {
538
+ const actual = chooseMcpServerActual(mcpServer.actual);
539
+ if (actual?.contentRoot !== undefined && actual.contentRoot !== null) {
540
+ return actual.contentRoot;
541
+ }
542
+ const resolved = mcpServer.resolved;
543
+ if (Option.isSome(resolved)) {
544
+ return args.platform.path.resolve(args.workspaceRoot, acquiredPackageDisplayRoot(args.scope, resolved.value.lockEntry, "mcps", mcpServer.key.name));
545
+ }
546
+ if (mcpServer.installationOrigin._tag === "direct") {
547
+ const source = mcpServer.installationOrigin.declared.entry.source;
548
+ if (source === undefined)
549
+ return undefined;
550
+ const parsed = parseRegistrySourceRef(source);
551
+ if (parsed !== undefined && parsed.type === "mcps") {
552
+ return args.platform.path.resolve(args.workspaceRoot, `${canonicalDisplayRoot(args.scope)}/agentxm/${parsed.owner}/mcps/${mcpServer.key.name}`);
553
+ }
554
+ }
555
+ return undefined;
556
+ };
557
+ const isNativeSkill = (skill, actual) => {
558
+ const resolved = skill.resolved;
559
+ if (Option.isSome(resolved)) {
560
+ return resolved.value.lockEntry.packageFormat === "agentxm";
561
+ }
562
+ if (actual.origin._tag === "canonical-axm-skill") {
563
+ return true;
564
+ }
565
+ if (skill.installationOrigin._tag !== "direct") {
566
+ return false;
567
+ }
568
+ const parsed = parseRegistrySourceRef(skill.installationOrigin.declared.entry.source);
569
+ return parsed !== undefined && parsed.type === "skills";
570
+ };
571
+ const relativeDisplayRoot = (args, absoluteRoot) => args.platform.path.relative(args.workspaceRoot, absoluteRoot);
572
+ const acquiredPackageDisplayRoot = (scope, entry, type, name) => acquiredExtensionDisplayPathFromLockEntry(canonicalDisplayRoot(scope), entry, type, name);
573
+ // -----------------------------------------------------------------------------
574
+ // Provenance → displayRoot helpers
575
+ // -----------------------------------------------------------------------------
576
+ /**
577
+ * Compute the `displayRoot` for a registry-installed native skill.
578
+ *
579
+ * @experimental This API is unstable and may change without notice.
580
+ */
581
+ export const registryNativeSkillDisplayRoot = (scope, sourceName, owner, name) => `${canonicalDisplayRoot(scope)}/${sourceName}/${owner}/skills/${name}/src`;
582
+ /**
583
+ * Compute the content `displayRoot` for a source-qualified acquired skill.
584
+ *
585
+ * @experimental This API is unstable and may change without notice.
586
+ */
587
+ export const acquiredSkillDisplayRoot = (scope, entry, name) => {
588
+ const packageRoot = acquiredPackageDisplayRoot(scope, entry, "skills", name);
589
+ return entry.packageFormat === "agent-skill" ? packageRoot : `${packageRoot}/src`;
590
+ };
591
+ /**
592
+ * Compute the `displayRoot` for a registry-installed pack.
593
+ *
594
+ * **No `src/` segment** — matches the on-disk layout at
595
+ * `packages/workspace-state/src/workspace/pack-paths.ts#computePackPathsForLayout`.
596
+ *
597
+ * @experimental This API is unstable and may change without notice.
598
+ */
599
+ export const registryPackDisplayRoot = (scope, sourceName, owner, name) => `${canonicalDisplayRoot(scope)}/${sourceName}/${owner}/packs/${name}`;
600
+ /**
601
+ * Build an `InstalledSkillInfo` rooted at `agent_extensions/<owner>/skills/<name>/src/`.
602
+ *
603
+ * @experimental This API is unstable and may change without notice.
604
+ */
605
+ export const buildNativeInstalledSkillInfo = (args) => {
606
+ const packageRoot = args.platform.path.resolve(args.workspaceRoot, `${canonicalDisplayRoot(args.scope)}/${args.sourceName}/${args.owner}/skills/${args.name}`);
607
+ const contentRoot = args.platform.path.resolve(packageRoot, "src");
608
+ return {
609
+ isNative: true,
610
+ skillJson: args.skillJson,
611
+ expectedName: args.name,
612
+ displayRoot: registryNativeSkillDisplayRoot(args.scope, args.sourceName, args.owner, args.name),
613
+ files: makePlatformSkillFileAccessor(args.platform, contentRoot),
614
+ packageFiles: makePlatformSkillFileAccessor(args.platform, packageRoot),
615
+ };
616
+ };
617
+ /**
618
+ * Build an `InstalledSkillInfo` rooted at its exact accepted source-qualified path.
619
+ *
620
+ * @experimental This API is unstable and may change without notice.
621
+ */
622
+ export const buildAcquiredInstalledSkillInfo = (args) => {
623
+ const packageRoot = args.platform.path.resolve(args.workspaceRoot, acquiredPackageDisplayRoot(args.scope, args.lockEntry, "skills", args.name));
624
+ const contentRoot = args.lockEntry.packageFormat === "agent-skill"
625
+ ? packageRoot
626
+ : args.platform.path.resolve(packageRoot, "src");
627
+ return {
628
+ isNative: args.lockEntry.packageFormat === "agentxm",
629
+ skillJson: undefined,
630
+ expectedName: args.name,
631
+ displayRoot: acquiredSkillDisplayRoot(args.scope, args.lockEntry, args.name),
632
+ files: makePlatformSkillFileAccessor(args.platform, contentRoot),
633
+ packageFiles: makePlatformSkillFileAccessor(args.platform, packageRoot),
634
+ };
635
+ };
636
+ /**
637
+ * Build an `InstalledPackInfo` rooted at `agent_extensions/<owner>/packs/<name>/`.
638
+ *
639
+ * **No `src/` segment** — matches the on-disk pack layout.
640
+ *
641
+ * @experimental This API is unstable and may change without notice.
642
+ */
643
+ export const buildInstalledPackInfo = (args) => {
644
+ const absoluteRoot = args.platform.path.resolve(args.workspaceRoot, `${canonicalDisplayRoot(args.scope)}/${args.sourceName}/${args.owner}/packs/${args.name}`);
645
+ return {
646
+ packJson: args.packJson,
647
+ displayRoot: registryPackDisplayRoot(args.scope, args.sourceName, args.owner, args.name),
648
+ files: makePlatformPackFileAccessor(args.platform, absoluteRoot),
649
+ };
650
+ };
651
+ //# sourceMappingURL=lint-workspace.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Manifest JSON reader for workspace lint projections.
3
+ *
4
+ * Reads through the already-rooted per-extension file accessor, parses loose
5
+ * JSON, and returns the raw parsed value. It intentionally does not decode
6
+ * against a manifest schema because unknown keys must remain visible to the
7
+ * `*-keys-recognized` rules.
8
+ *
9
+ * @experimental This API is unstable and may change without notice.
10
+ */
11
+ import * as Effect from "effect/Effect";
12
+ import type { PackFileAccessor } from "@agentxm/registry-protocol/unstable/lint/context";
13
+ export declare const readManifestJson: (accessor: PackFileAccessor, filename: string) => Effect.Effect<unknown | undefined>;
14
+ //# sourceMappingURL=manifest-json.d.ts.map