@agentxm/workspace-state 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 (215) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +11 -0
  3. package/dist/src/index.d.ts +72 -0
  4. package/dist/src/index.js +88 -0
  5. package/dist/src/knowledge/discovery-config.d.ts +12 -0
  6. package/dist/src/knowledge/discovery-config.js +9 -0
  7. package/dist/src/lockfile/accepted-registry-version.d.ts +12 -0
  8. package/dist/src/lockfile/accepted-registry-version.js +13 -0
  9. package/dist/src/lockfile/entry-fields.d.ts +189 -0
  10. package/dist/src/lockfile/entry-fields.js +89 -0
  11. package/dist/src/lockfile/errors.d.ts +48 -0
  12. package/dist/src/lockfile/errors.js +27 -0
  13. package/dist/src/lockfile/index.d.ts +18 -0
  14. package/dist/src/lockfile/index.js +16 -0
  15. package/dist/src/lockfile/lockfile.d.ts +2255 -0
  16. package/dist/src/lockfile/lockfile.js +235 -0
  17. package/dist/src/lockfile/resolved-version.d.ts +4 -0
  18. package/dist/src/lockfile/resolved-version.js +7 -0
  19. package/dist/src/lockfile/schema.d.ts +3062 -0
  20. package/dist/src/lockfile/schema.js +406 -0
  21. package/dist/src/schema/index.d.ts +3 -0
  22. package/dist/src/schema/index.js +2 -0
  23. package/dist/src/schema/read-and-validate-json-file.d.ts +20 -0
  24. package/dist/src/schema/read-and-validate-json-file.js +85 -0
  25. package/dist/src/schema/types.d.ts +26 -0
  26. package/dist/src/schema/types.js +2 -0
  27. package/dist/src/settings/errors.d.ts +22 -0
  28. package/dist/src/settings/errors.js +15 -0
  29. package/dist/src/settings/format-preserving-json.d.ts +40 -0
  30. package/dist/src/settings/format-preserving-json.js +80 -0
  31. package/dist/src/settings/index.d.ts +15 -0
  32. package/dist/src/settings/index.js +14 -0
  33. package/dist/src/settings/schema.d.ts +687 -0
  34. package/dist/src/settings/schema.js +977 -0
  35. package/dist/src/settings/settings.d.ts +38 -0
  36. package/dist/src/settings/settings.js +213 -0
  37. package/dist/src/testing.d.ts +17 -0
  38. package/dist/src/testing.js +17 -0
  39. package/dist/src/utils/atomic-write.d.ts +67 -0
  40. package/dist/src/utils/atomic-write.js +71 -0
  41. package/dist/src/utils/environment.d.ts +16 -0
  42. package/dist/src/utils/environment.js +19 -0
  43. package/dist/src/utils/path-safety.d.ts +25 -0
  44. package/dist/src/utils/path-safety.js +34 -0
  45. package/dist/src/utils/resolve-parent-symlinks.d.ts +16 -0
  46. package/dist/src/utils/resolve-parent-symlinks.js +36 -0
  47. package/dist/src/workspace/accepted-canonical-ref.d.ts +58 -0
  48. package/dist/src/workspace/accepted-canonical-ref.js +229 -0
  49. package/dist/src/workspace/artifact-change.d.ts +14 -0
  50. package/dist/src/workspace/artifact-change.js +18 -0
  51. package/dist/src/workspace/canonical-observation.d.ts +39 -0
  52. package/dist/src/workspace/canonical-observation.js +307 -0
  53. package/dist/src/workspace/configured-agent-outcome.d.ts +22 -0
  54. package/dist/src/workspace/configured-agent-outcome.js +33 -0
  55. package/dist/src/workspace/configured-agent-outcomes-provider.d.ts +50 -0
  56. package/dist/src/workspace/configured-agent-outcomes-provider.js +26 -0
  57. package/dist/src/workspace/configured-agent-outcomes.d.ts +48 -0
  58. package/dist/src/workspace/configured-agent-outcomes.js +113 -0
  59. package/dist/src/workspace/configured-entry-resolution/types.d.ts +32 -0
  60. package/dist/src/workspace/configured-entry-resolution/types.js +2 -0
  61. package/dist/src/workspace/configured-entry-resolution/workspace-ref.d.ts +32 -0
  62. package/dist/src/workspace/configured-entry-resolution/workspace-ref.js +176 -0
  63. package/dist/src/workspace/constants.d.ts +6 -0
  64. package/dist/src/workspace/constants.js +6 -0
  65. package/dist/src/workspace/create-symlink.d.ts +26 -0
  66. package/dist/src/workspace/create-symlink.js +87 -0
  67. package/dist/src/workspace/desired-pack-lock.d.ts +18 -0
  68. package/dist/src/workspace/desired-pack-lock.js +132 -0
  69. package/dist/src/workspace/desired-state-enabled.d.ts +18 -0
  70. package/dist/src/workspace/desired-state-enabled.js +16 -0
  71. package/dist/src/workspace/desired-state-graph.d.ts +114 -0
  72. package/dist/src/workspace/desired-state-graph.js +384 -0
  73. package/dist/src/workspace/desired-state-problem-text.d.ts +6 -0
  74. package/dist/src/workspace/desired-state-problem-text.js +27 -0
  75. package/dist/src/workspace/errors.d.ts +184 -0
  76. package/dist/src/workspace/errors.js +79 -0
  77. package/dist/src/workspace/extension-name.d.ts +28 -0
  78. package/dist/src/workspace/extension-name.js +66 -0
  79. package/dist/src/workspace/extension-paths.d.ts +82 -0
  80. package/dist/src/workspace/extension-paths.js +172 -0
  81. package/dist/src/workspace/footprint-recorder.d.ts +30 -0
  82. package/dist/src/workspace/footprint-recorder.js +32 -0
  83. package/dist/src/workspace/layout.d.ts +43 -0
  84. package/dist/src/workspace/layout.js +164 -0
  85. package/dist/src/workspace/lock-entry-to-ref.d.ts +40 -0
  86. package/dist/src/workspace/lock-entry-to-ref.js +433 -0
  87. package/dist/src/workspace/lock-entry-to-source-params.d.ts +26 -0
  88. package/dist/src/workspace/lock-entry-to-source-params.js +81 -0
  89. package/dist/src/workspace/locked-entries.d.ts +30 -0
  90. package/dist/src/workspace/locked-entries.js +34 -0
  91. package/dist/src/workspace/materialized-file-target.d.ts +14 -0
  92. package/dist/src/workspace/materialized-file-target.js +14 -0
  93. package/dist/src/workspace/materialized-tree.d.ts +23 -0
  94. package/dist/src/workspace/materialized-tree.js +90 -0
  95. package/dist/src/workspace/mcp-entry-semantics.d.ts +31 -0
  96. package/dist/src/workspace/mcp-entry-semantics.js +60 -0
  97. package/dist/src/workspace/observed-installed.d.ts +9 -0
  98. package/dist/src/workspace/observed-installed.js +9 -0
  99. package/dist/src/workspace/pack-manifest-content-identity.d.ts +12 -0
  100. package/dist/src/workspace/pack-manifest-content-identity.js +20 -0
  101. package/dist/src/workspace/pack-paths.d.ts +24 -0
  102. package/dist/src/workspace/pack-paths.js +16 -0
  103. package/dist/src/workspace/package-hash.d.ts +25 -0
  104. package/dist/src/workspace/package-hash.js +45 -0
  105. package/dist/src/workspace/paths.d.ts +24 -0
  106. package/dist/src/workspace/paths.js +52 -0
  107. package/dist/src/workspace/read-model/__fixtures__/builder.d.ts +199 -0
  108. package/dist/src/workspace/read-model/__fixtures__/builder.js +588 -0
  109. package/dist/src/workspace/read-model/__fixtures__/decoders.d.ts +15 -0
  110. package/dist/src/workspace/read-model/__fixtures__/decoders.js +15 -0
  111. package/dist/src/workspace/read-model/__fixtures__/occurrences.d.ts +72 -0
  112. package/dist/src/workspace/read-model/__fixtures__/occurrences.js +134 -0
  113. package/dist/src/workspace/read-model/__fixtures__/scenario-harness.d.ts +99 -0
  114. package/dist/src/workspace/read-model/__fixtures__/scenario-harness.js +142 -0
  115. package/dist/src/workspace/read-model/__fixtures__/test-layer.d.ts +60 -0
  116. package/dist/src/workspace/read-model/__fixtures__/test-layer.js +57 -0
  117. package/dist/src/workspace/read-model/agent-presence.d.ts +32 -0
  118. package/dist/src/workspace/read-model/agent-presence.js +21 -0
  119. package/dist/src/workspace/read-model/agent-root-resolver.d.ts +38 -0
  120. package/dist/src/workspace/read-model/agent-root-resolver.js +35 -0
  121. package/dist/src/workspace/read-model/agents/index.d.ts +38 -0
  122. package/dist/src/workspace/read-model/agents/index.js +45 -0
  123. package/dist/src/workspace/read-model/agents/shared.d.ts +27 -0
  124. package/dist/src/workspace/read-model/agents/shared.js +63 -0
  125. package/dist/src/workspace/read-model/agents/types.d.ts +133 -0
  126. package/dist/src/workspace/read-model/agents/types.js +51 -0
  127. package/dist/src/workspace/read-model/diagnostics.d.ts +18 -0
  128. package/dist/src/workspace/read-model/diagnostics.js +14 -0
  129. package/dist/src/workspace/read-model/discovery/index.d.ts +5 -0
  130. package/dist/src/workspace/read-model/discovery/index.js +5 -0
  131. package/dist/src/workspace/read-model/discovery/plugin-manifests.d.ts +16 -0
  132. package/dist/src/workspace/read-model/discovery/plugin-manifests.js +168 -0
  133. package/dist/src/workspace/read-model/discovery/skills.d.ts +58 -0
  134. package/dist/src/workspace/read-model/discovery/skills.js +263 -0
  135. package/dist/src/workspace/read-model/discovery/subagents.d.ts +37 -0
  136. package/dist/src/workspace/read-model/discovery/subagents.js +48 -0
  137. package/dist/src/workspace/read-model/errors.d.ts +93 -0
  138. package/dist/src/workspace/read-model/errors.js +30 -0
  139. package/dist/src/workspace/read-model/extensions/actual-helpers.d.ts +4 -0
  140. package/dist/src/workspace/read-model/extensions/actual-helpers.js +4 -0
  141. package/dist/src/workspace/read-model/extensions/hook.d.ts +104 -0
  142. package/dist/src/workspace/read-model/extensions/hook.js +119 -0
  143. package/dist/src/workspace/read-model/extensions/index.d.ts +19 -0
  144. package/dist/src/workspace/read-model/extensions/index.js +43 -0
  145. package/dist/src/workspace/read-model/extensions/indexByName.d.ts +31 -0
  146. package/dist/src/workspace/read-model/extensions/indexByName.js +30 -0
  147. package/dist/src/workspace/read-model/extensions/inventory.d.ts +99 -0
  148. package/dist/src/workspace/read-model/extensions/inventory.js +111 -0
  149. package/dist/src/workspace/read-model/extensions/knowledge.d.ts +101 -0
  150. package/dist/src/workspace/read-model/extensions/knowledge.js +121 -0
  151. package/dist/src/workspace/read-model/extensions/mcp-server.d.ts +106 -0
  152. package/dist/src/workspace/read-model/extensions/mcp-server.js +122 -0
  153. package/dist/src/workspace/read-model/extensions/pack.d.ts +104 -0
  154. package/dist/src/workspace/read-model/extensions/pack.js +123 -0
  155. package/dist/src/workspace/read-model/extensions/package-root.d.ts +39 -0
  156. package/dist/src/workspace/read-model/extensions/package-root.js +48 -0
  157. package/dist/src/workspace/read-model/extensions/projection.d.ts +137 -0
  158. package/dist/src/workspace/read-model/extensions/projection.js +180 -0
  159. package/dist/src/workspace/read-model/extensions/rule.d.ts +104 -0
  160. package/dist/src/workspace/read-model/extensions/rule.js +113 -0
  161. package/dist/src/workspace/read-model/extensions/skill.d.ts +170 -0
  162. package/dist/src/workspace/read-model/extensions/skill.js +148 -0
  163. package/dist/src/workspace/read-model/extensions/subagent.d.ts +97 -0
  164. package/dist/src/workspace/read-model/extensions/subagent.js +120 -0
  165. package/dist/src/workspace/read-model/scanners/agent-dir.d.ts +49 -0
  166. package/dist/src/workspace/read-model/scanners/agent-dir.js +180 -0
  167. package/dist/src/workspace/read-model/scanners/agent-root.d.ts +73 -0
  168. package/dist/src/workspace/read-model/scanners/agent-root.js +148 -0
  169. package/dist/src/workspace/read-model/scanners/agent-settings.d.ts +43 -0
  170. package/dist/src/workspace/read-model/scanners/agent-settings.js +54 -0
  171. package/dist/src/workspace/read-model/scanners/canonical-extensions.d.ts +48 -0
  172. package/dist/src/workspace/read-model/scanners/canonical-extensions.js +237 -0
  173. package/dist/src/workspace/read-model/scanners/fs-helpers.d.ts +63 -0
  174. package/dist/src/workspace/read-model/scanners/fs-helpers.js +106 -0
  175. package/dist/src/workspace/read-model/scanners/index.d.ts +15 -0
  176. package/dist/src/workspace/read-model/scanners/index.js +34 -0
  177. package/dist/src/workspace/read-model/scanners/mcp-config.d.ts +47 -0
  178. package/dist/src/workspace/read-model/scanners/mcp-config.js +212 -0
  179. package/dist/src/workspace/read-model/scanners/types.d.ts +170 -0
  180. package/dist/src/workspace/read-model/scanners/types.js +86 -0
  181. package/dist/src/workspace/read-model/service.d.ts +103 -0
  182. package/dist/src/workspace/read-model/service.js +391 -0
  183. package/dist/src/workspace/read-model/state.d.ts +35 -0
  184. package/dist/src/workspace/read-model/state.js +97 -0
  185. package/dist/src/workspace/read-model/types.d.ts +75 -0
  186. package/dist/src/workspace/read-model/types.js +26 -0
  187. package/dist/src/workspace/read-model-record-readers.d.ts +34 -0
  188. package/dist/src/workspace/read-model-record-readers.js +467 -0
  189. package/dist/src/workspace/read-model-record-rows.d.ts +45 -0
  190. package/dist/src/workspace/read-model-record-rows.js +33 -0
  191. package/dist/src/workspace/read-model-record-types.d.ts +45 -0
  192. package/dist/src/workspace/read-model-record-types.js +13 -0
  193. package/dist/src/workspace/remove-if-exists.d.ts +13 -0
  194. package/dist/src/workspace/remove-if-exists.js +26 -0
  195. package/dist/src/workspace/rendered-files.d.ts +53 -0
  196. package/dist/src/workspace/rendered-files.js +50 -0
  197. package/dist/src/workspace/scope-refusal.d.ts +26 -0
  198. package/dist/src/workspace/scope-refusal.js +29 -0
  199. package/dist/src/workspace/service-interface.d.ts +479 -0
  200. package/dist/src/workspace/service-interface.js +27 -0
  201. package/dist/src/workspace/service.d.ts +1665 -0
  202. package/dist/src/workspace/service.js +1263 -0
  203. package/dist/src/workspace/setup-scope-support.d.ts +27 -0
  204. package/dist/src/workspace/setup-scope-support.js +299 -0
  205. package/dist/src/workspace/skill-paths.d.ts +33 -0
  206. package/dist/src/workspace/skill-paths.js +14 -0
  207. package/dist/src/workspace/source-metadata.d.ts +7 -0
  208. package/dist/src/workspace/source-metadata.js +10 -0
  209. package/dist/src/workspace/source-to-lock-entry.d.ts +32 -0
  210. package/dist/src/workspace/source-to-lock-entry.js +68 -0
  211. package/dist/src/workspace/test-stubs.d.ts +144 -0
  212. package/dist/src/workspace/test-stubs.js +412 -0
  213. package/dist/src/workspace/transaction.d.ts +218 -0
  214. package/dist/src/workspace/transaction.js +177 -0
  215. package/package.json +57 -0
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Canonical-extensions scanner: enumerates authored project type roots and
3
+ * source-qualified acquired packages beneath `agent_extensions/` or the
4
+ * corresponding user-scope `agent_extensions/` root.
5
+ *
6
+ * Per Decision 5 of the workspace read-model design, scanner output is
7
+ * occurrence-shaped. Each emitted occurrence carries the scanner-tier origin
8
+ * discriminator (`canonical-axm` | `external-axm`) plus the extension type;
9
+ * Phase 7 maps these into per-subject origin unions.
10
+ *
11
+ * Each occurrence carries structural fields the subject modules need for
12
+ * cross-platform path handling — `pathSegments` (the absolute path split via
13
+ * the `Path` service) and `subjectFile` (the canonical primary content file
14
+ * for the subject type, e.g., `<dir>/SKILL.md` for skills) — plus a probed
15
+ * `subjectFileExists` flag so subject modules do not hardcode presence.
16
+ *
17
+ * Scanner contract:
18
+ *
19
+ * - Public effect carries no `FileSystem | Path` requirement. Construction
20
+ * takes a deps record and returns an `Effect<ReadonlyArray<…>>`.
21
+ * - Per-file partial failures (a directory we cannot enumerate) become
22
+ * diagnostic warnings, not errors. The error channel stays empty.
23
+ * - WorkspaceMutations-root path-escape is checked at provider construction (Phase 9),
24
+ * not inside the scanner.
25
+ *
26
+ * The scanner avoids `fs.stat` and uses only `fs.exists` / `fs.readDirectory`
27
+ * so it remains compatible with the fixture builder's in-memory `FileSystem`.
28
+ * "Is this a directory" is decided by whether `readDirectory` returns
29
+ * successfully; non-directory entries are silently ignored.
30
+ */
31
+ import * as Effect from "effect/Effect";
32
+ import * as Option from "effect/Option";
33
+ import * as Schema from "effect/Schema";
34
+ import { decodeExtensionNameSync, ExtensionNameSchema, ExtensionTypeSchema, } from "@agentxm/extension-model/unstable/extensions/common";
35
+ import { HandleSchema } from "@agentxm/extension-model/unstable/extensions/handle";
36
+ import { MANIFEST_FILENAME_BY_TYPE } from "@agentxm/registry-protocol/unstable/publish/manifest-policy";
37
+ import { parseSkillMd } from "@agentxm/registry-protocol/unstable/content/skill-content";
38
+ import { DISCOVERY_SKIPPED_DIRECTORIES } from "@agentxm/extension-model/unstable/discovery-walk";
39
+ import { makeAbsolutePath } from "@agentxm/extension-model/unstable/path-types";
40
+ import { childEntries, fileExists, filterDirectories, splitAbsolutePathSegments, } from "./fs-helpers.js";
41
+ const SCANNER_NAME = "canonical-extensions";
42
+ /**
43
+ * Closure helper: returns the dependency-closed scanner effect.
44
+ */
45
+ export const makeCanonicalExtensionsScanner = (deps) => scanCanonicalExtensions(deps);
46
+ // ---------------------------------------------------------------------------
47
+ // Subject file mapping
48
+ // ---------------------------------------------------------------------------
49
+ /**
50
+ * Map an extension type + name to the canonical primary content file name
51
+ * inside the subject's directory, when the subject has one. Subject types
52
+ * without a fixed primary file return `null`.
53
+ *
54
+ * - `skill` → `SKILL.md` (fixed)
55
+ * - `subagent` → `${name}.md` (e.g., `code-reviewer.md`)
56
+ */
57
+ const subjectFileNameFor = (type, name) => {
58
+ switch (type) {
59
+ case "skill":
60
+ return "SKILL.md";
61
+ case "subagent":
62
+ return `${name}.md`;
63
+ default:
64
+ return null;
65
+ }
66
+ };
67
+ // ---------------------------------------------------------------------------
68
+ // Internal helpers
69
+ // ---------------------------------------------------------------------------
70
+ /**
71
+ * Build one occurrence record from a discovered subject directory. Probes
72
+ * the canonical subject file (e.g., `SKILL.md`) when applicable.
73
+ */
74
+ const buildOccurrence = (deps, args) => Effect.gen(function* () {
75
+ const { fs, path, layout, diagnostics } = deps;
76
+ const resolvedName = args.name ?? path.basename(args.nameDir);
77
+ const subjectFileName = subjectFileNameFor(args.extensionType, resolvedName);
78
+ const subjectFile = subjectFileName === null
79
+ ? Option.none()
80
+ : Option.some(makeAbsolutePath(path, path.join(args.nameDir, subjectFileName)));
81
+ const subjectFileExists = Option.isSome(subjectFile)
82
+ ? yield* fileExists(SCANNER_NAME, fs, diagnostics, subjectFile.value)
83
+ : false;
84
+ const contentLocation = makeAbsolutePath(path, args.nameDir);
85
+ const occurrence = {
86
+ _tag: "canonical-extension",
87
+ scope: layout.scope,
88
+ type: args.extensionType,
89
+ origin: args.origin,
90
+ name: decodeExtensionNameSync(resolvedName),
91
+ owner: args.owner,
92
+ contentLocation,
93
+ pathSegments: splitAbsolutePathSegments(path, args.nameDir),
94
+ subjectFile,
95
+ subjectFileExists,
96
+ };
97
+ return occurrence;
98
+ });
99
+ const manifestFilenames = new Set(Object.values(MANIFEST_FILENAME_BY_TYPE));
100
+ const ScannableManifestIdentitySchema = Schema.Struct({
101
+ owner: HandleSchema,
102
+ type: ExtensionTypeSchema,
103
+ name: ExtensionNameSchema,
104
+ });
105
+ const extensionTypeForManifest = (filename) => {
106
+ switch (filename) {
107
+ case "skill.json":
108
+ return "skill";
109
+ case "mcp.json":
110
+ return "mcp-server";
111
+ case "subagent.json":
112
+ return "subagent";
113
+ case "rule.json":
114
+ return "rule";
115
+ case "hook.json":
116
+ return "hook";
117
+ case "knowledge.json":
118
+ return "knowledge";
119
+ case "pack.json":
120
+ return "pack";
121
+ default:
122
+ return undefined;
123
+ }
124
+ };
125
+ const readNativeIdentity = (deps, dir, entries) => Effect.gen(function* () {
126
+ const filename = entries.find((entry) => manifestFilenames.has(entry));
127
+ if (filename === undefined)
128
+ return Option.none();
129
+ const filenameType = extensionTypeForManifest(filename);
130
+ if (filenameType === undefined)
131
+ return Option.none();
132
+ const raw = yield* deps.fs.readFileString(deps.path.join(dir, filename)).pipe(Effect.option);
133
+ if (Option.isNone(raw)) {
134
+ return Option.some({
135
+ type: filenameType,
136
+ name: decodeExtensionNameSync(deps.path.basename(dir)),
137
+ owner: null,
138
+ });
139
+ }
140
+ const identity = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ScannableManifestIdentitySchema))(raw.value).pipe(Effect.option);
141
+ if (Option.isNone(identity) || MANIFEST_FILENAME_BY_TYPE[identity.value.type] !== filename) {
142
+ return Option.some({
143
+ type: filenameType,
144
+ name: decodeExtensionNameSync(deps.path.basename(dir)),
145
+ owner: null,
146
+ });
147
+ }
148
+ return identity;
149
+ });
150
+ const scanAcquiredDirectory = (deps, dir) => Effect.gen(function* () {
151
+ const childPaths = yield* childEntries(SCANNER_NAME, deps.fs, deps.diagnostics, deps.path, dir);
152
+ const entries = childPaths.map((childPath) => deps.path.basename(childPath));
153
+ const nativeIdentity = yield* readNativeIdentity(deps, dir, entries);
154
+ if (Option.isSome(nativeIdentity)) {
155
+ const identity = nativeIdentity.value;
156
+ const contentDir = identity.type === "pack" || identity.type === "mcp-server"
157
+ ? dir
158
+ : deps.path.join(dir, "src");
159
+ const contentDirExists = yield* deps.fs.readDirectory(contentDir).pipe(Effect.as(true), Effect.catch(() => Effect.succeed(false)));
160
+ if (!contentDirExists)
161
+ return [];
162
+ return [
163
+ yield* buildOccurrence(deps, {
164
+ extensionType: identity.type,
165
+ origin: "canonical-axm",
166
+ nameDir: contentDir,
167
+ name: identity.name,
168
+ owner: identity.owner,
169
+ }),
170
+ ];
171
+ }
172
+ if (entries.includes("SKILL.md")) {
173
+ const raw = yield* deps.fs
174
+ .readFileString(deps.path.join(dir, "SKILL.md"))
175
+ .pipe(Effect.option);
176
+ const parsed = Option.flatMap(raw, (content) => parseSkillMd(content, deps.path.basename(dir)));
177
+ if (Option.isSome(parsed)) {
178
+ return [
179
+ yield* buildOccurrence(deps, {
180
+ extensionType: "skill",
181
+ origin: "external-axm",
182
+ nameDir: dir,
183
+ name: parsed.value.name,
184
+ owner: null,
185
+ }),
186
+ ];
187
+ }
188
+ }
189
+ const childCandidates = entries
190
+ .filter((entry) => !DISCOVERY_SKIPPED_DIRECTORIES.has(entry))
191
+ .map((entry) => deps.path.join(dir, entry));
192
+ const childDirs = yield* filterDirectories(deps.fs, childCandidates);
193
+ const nested = yield* Effect.forEach(childDirs, (childDir) => scanAcquiredDirectory(deps, childDir), { concurrency: "unbounded" });
194
+ return nested.flat();
195
+ });
196
+ const authoredTypeDirectories = [
197
+ { type: "skill", localDir: "skills" },
198
+ { type: "mcp-server", localDir: "mcps" },
199
+ { type: "subagent", localDir: "subagents" },
200
+ { type: "rule", localDir: "rules" },
201
+ { type: "hook", localDir: "hooks" },
202
+ { type: "knowledge", localDir: "knowledge" },
203
+ { type: "pack", localDir: "packs" },
204
+ ];
205
+ const scanAuthoredType = (deps, extensionType) => Effect.gen(function* () {
206
+ if (deps.layout.scope !== "project" || deps.layout.owner === undefined)
207
+ return [];
208
+ const root = deps.layout.authoredRoot(extensionType);
209
+ const packageCandidates = yield* childEntries(SCANNER_NAME, deps.fs, deps.diagnostics, deps.path, root);
210
+ const packageDirs = yield* filterDirectories(deps.fs, packageCandidates);
211
+ const occurrences = yield* Effect.forEach(packageDirs, (packageDir) => {
212
+ const nameDir = extensionType === "pack" || extensionType === "mcp-server"
213
+ ? packageDir
214
+ : deps.path.join(packageDir, "src");
215
+ return deps.fs.readDirectory(nameDir).pipe(Effect.flatMap(() => buildOccurrence(deps, {
216
+ extensionType,
217
+ origin: "canonical-axm",
218
+ nameDir,
219
+ name: deps.path.basename(packageDir),
220
+ owner: deps.layout.scope === "project" ? (deps.layout.owner ?? null) : null,
221
+ })), Effect.map((occurrence) => [occurrence]), Effect.catch(() => Effect.succeed([])));
222
+ }, { concurrency: "unbounded" });
223
+ return occurrences.flat();
224
+ });
225
+ // ---------------------------------------------------------------------------
226
+ // Scanner body
227
+ // ---------------------------------------------------------------------------
228
+ const scanCanonicalExtensions = Effect.fn("workspace.read-model.scanner.canonical-extensions")(function* (deps) {
229
+ const { layout } = deps;
230
+ const extensionsRoot = layout.acquiredRoot;
231
+ const acquired = yield* scanAcquiredDirectory(deps, extensionsRoot);
232
+ if (layout.scope !== "project")
233
+ return acquired;
234
+ const authored = yield* Effect.forEach(authoredTypeDirectories, ({ type }) => scanAuthoredType(deps, type), { concurrency: "unbounded" });
235
+ return [...acquired, ...authored.flat()];
236
+ });
237
+ //# sourceMappingURL=canonical-extensions.js.map
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Shared filesystem helpers used by the workspace read-model scanners.
3
+ *
4
+ * Each scanner needs the same handful of resilient `FileSystem` probes:
5
+ * "does this file exist", "list this directory's children", "filter to
6
+ * subdirectories only", and "split an absolute path by the platform
7
+ * separator". Before this module they were duplicated nearly verbatim across
8
+ * `agent-dir.ts`, `agent-settings.ts`, and `canonical-extensions.ts`, with
9
+ * subtle drift in their diagnostic-message prefixes and in whether
10
+ * `filterDirectories` accepted a `diagnostics` argument.
11
+ *
12
+ * Helpers in this module:
13
+ *
14
+ * - Take a `scannerName` so each scanner's diagnostics carry its own prefix
15
+ * (`canonical-extensions:`, `agent-dir:`, etc.) — matching the call-site
16
+ * strings the existing scanner tests assert on.
17
+ * - Return `Option<T>` from probe-style helpers (`fileExists`,
18
+ * `directoryCandidate`) so callers can compose with `Array.getSomes`
19
+ * instead of `null` sentinels. Boolean wrappers stay available where the
20
+ * caller cares about presence directly.
21
+ * - Carry no `R` requirement: each helper takes `fs` / `path` / `diagnostics`
22
+ * directly as arguments and the resulting `Effect` is dependency-closed.
23
+ */
24
+ import * as Effect from "effect/Effect";
25
+ import type * as FileSystem from "effect/FileSystem";
26
+ import type * as Path from "effect/Path";
27
+ import type { Diagnostics } from "../diagnostics.js";
28
+ /**
29
+ * Probe a path with `fs.exists`. Returns `true` when the file exists,
30
+ * `false` when it does not, and emits a `scanner-io` diagnostic and returns
31
+ * `false` when the probe itself errors.
32
+ */
33
+ export declare const fileExists: (scannerName: string, fs: FileSystem.FileSystem, diagnostics: Diagnostics, filePath: string) => Effect.Effect<boolean>;
34
+ /**
35
+ * Enumerate the immediate children of `parent` and return their absolute
36
+ * paths. When `parent` is absent, returns `[]`. When `parent` exists but
37
+ * cannot be enumerated, emits a `scanner-io` diagnostic and returns `[]`.
38
+ *
39
+ * Callers feed the result into `filterDirectories` to keep only
40
+ * subdirectories, or treat each entry as a candidate file to probe.
41
+ */
42
+ export declare const childEntries: (scannerName: string, fs: FileSystem.FileSystem, diagnostics: Diagnostics, path: Path.Path, parent: string) => Effect.Effect<ReadonlyArray<string>>;
43
+ /**
44
+ * Filter `candidates` down to entries that are directories. Directory
45
+ * detection uses a successful `readDirectory` call so the helper stays
46
+ * compatible with the v1 fixture builder's in-memory `FileSystem`, which
47
+ * does not implement `fs.stat`.
48
+ *
49
+ * Failures (file or unreadable directory) are silently dropped: an explicit
50
+ * warning here would fire on every regular file inside a scanned tree
51
+ * (`README.md`, `SKILL.md`, etc.). The shared scanner test still asserts
52
+ * that failing-fs cases surface warnings via the parent `readDirectory`.
53
+ */
54
+ export declare const filterDirectories: (fs: FileSystem.FileSystem, candidates: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<string>>;
55
+ /**
56
+ * Split an absolute path into its constituent segments using the `Path`
57
+ * service's platform separator. Subject modules consume the array so they do
58
+ * not re-parse the string with a hard-coded `/` separator. POSIX
59
+ * `/ws/.claude/skills/x` → `["", "ws", ".claude", "skills", "x"]`; Windows
60
+ * `C:\\ws\\.claude\\skills\\x` → `["C:", "ws", ".claude", "skills", "x"]`.
61
+ */
62
+ export declare const splitAbsolutePathSegments: (path: Path.Path, absolute: string) => ReadonlyArray<string>;
63
+ //# sourceMappingURL=fs-helpers.d.ts.map
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Shared filesystem helpers used by the workspace read-model scanners.
3
+ *
4
+ * Each scanner needs the same handful of resilient `FileSystem` probes:
5
+ * "does this file exist", "list this directory's children", "filter to
6
+ * subdirectories only", and "split an absolute path by the platform
7
+ * separator". Before this module they were duplicated nearly verbatim across
8
+ * `agent-dir.ts`, `agent-settings.ts`, and `canonical-extensions.ts`, with
9
+ * subtle drift in their diagnostic-message prefixes and in whether
10
+ * `filterDirectories` accepted a `diagnostics` argument.
11
+ *
12
+ * Helpers in this module:
13
+ *
14
+ * - Take a `scannerName` so each scanner's diagnostics carry its own prefix
15
+ * (`canonical-extensions:`, `agent-dir:`, etc.) — matching the call-site
16
+ * strings the existing scanner tests assert on.
17
+ * - Return `Option<T>` from probe-style helpers (`fileExists`,
18
+ * `directoryCandidate`) so callers can compose with `Array.getSomes`
19
+ * instead of `null` sentinels. Boolean wrappers stay available where the
20
+ * caller cares about presence directly.
21
+ * - Carry no `R` requirement: each helper takes `fs` / `path` / `diagnostics`
22
+ * directly as arguments and the resulting `Effect` is dependency-closed.
23
+ */
24
+ import * as Array from "effect/Array";
25
+ import * as Effect from "effect/Effect";
26
+ import * as Option from "effect/Option";
27
+ /**
28
+ * Probe a path with `fs.exists`. Returns `true` when the file exists,
29
+ * `false` when it does not, and emits a `scanner-io` diagnostic and returns
30
+ * `false` when the probe itself errors.
31
+ */
32
+ export const fileExists = (scannerName, fs, diagnostics, filePath) => Effect.gen(function* () {
33
+ const exists = yield* Effect.result(fs.exists(filePath));
34
+ if (exists._tag === "Failure") {
35
+ yield* diagnostics.append({
36
+ source: "scanner",
37
+ message: `${scannerName}: cannot stat ${filePath}`,
38
+ path: filePath,
39
+ code: "scanner-io",
40
+ });
41
+ return false;
42
+ }
43
+ return exists.success;
44
+ });
45
+ /**
46
+ * Enumerate the immediate children of `parent` and return their absolute
47
+ * paths. When `parent` is absent, returns `[]`. When `parent` exists but
48
+ * cannot be enumerated, emits a `scanner-io` diagnostic and returns `[]`.
49
+ *
50
+ * Callers feed the result into `filterDirectories` to keep only
51
+ * subdirectories, or treat each entry as a candidate file to probe.
52
+ */
53
+ export const childEntries = (scannerName, fs, diagnostics, path, parent) => Effect.gen(function* () {
54
+ const exists = yield* Effect.result(fs.exists(parent));
55
+ if (exists._tag === "Failure") {
56
+ yield* diagnostics.append({
57
+ source: "scanner",
58
+ message: `${scannerName}: cannot stat ${parent}`,
59
+ path: parent,
60
+ code: "scanner-io",
61
+ });
62
+ return [];
63
+ }
64
+ if (!exists.success)
65
+ return [];
66
+ const entries = yield* Effect.result(fs.readDirectory(parent));
67
+ if (entries._tag === "Failure") {
68
+ yield* diagnostics.append({
69
+ source: "scanner",
70
+ message: `${scannerName}: cannot read directory ${parent}`,
71
+ path: parent,
72
+ code: "scanner-io",
73
+ });
74
+ return [];
75
+ }
76
+ return entries.success.map((entry) => path.join(parent, entry));
77
+ });
78
+ /**
79
+ * Filter `candidates` down to entries that are directories. Directory
80
+ * detection uses a successful `readDirectory` call so the helper stays
81
+ * compatible with the v1 fixture builder's in-memory `FileSystem`, which
82
+ * does not implement `fs.stat`.
83
+ *
84
+ * Failures (file or unreadable directory) are silently dropped: an explicit
85
+ * warning here would fire on every regular file inside a scanned tree
86
+ * (`README.md`, `SKILL.md`, etc.). The shared scanner test still asserts
87
+ * that failing-fs cases surface warnings via the parent `readDirectory`.
88
+ */
89
+ export const filterDirectories = (fs, candidates) => Effect.gen(function* () {
90
+ const checks = yield* Effect.forEach(candidates, (candidate) => Effect.gen(function* () {
91
+ const result = yield* Effect.result(fs.readDirectory(candidate));
92
+ if (result._tag === "Failure")
93
+ return Option.none();
94
+ return Option.some(candidate);
95
+ }), { concurrency: "unbounded" });
96
+ return Array.getSomes(checks);
97
+ });
98
+ /**
99
+ * Split an absolute path into its constituent segments using the `Path`
100
+ * service's platform separator. Subject modules consume the array so they do
101
+ * not re-parse the string with a hard-coded `/` separator. POSIX
102
+ * `/ws/.claude/skills/x` → `["", "ws", ".claude", "skills", "x"]`; Windows
103
+ * `C:\\ws\\.claude\\skills\\x` → `["C:", "ws", ".claude", "skills", "x"]`.
104
+ */
105
+ export const splitAbsolutePathSegments = (path, absolute) => absolute.split(path.sep);
106
+ //# sourceMappingURL=fs-helpers.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Scanner barrel: re-exports every per-scanner factory and the shared
3
+ * occurrence-shape types from one entry point so `context.ts` can pull
4
+ * scanner wiring from a single module.
5
+ *
6
+ * Each scanner module owns its own deps interface, occurrence shape, and
7
+ * partial-failure semantics; this barrel only re-exports — no logic.
8
+ */
9
+ export { makeCanonicalExtensionsScanner, type CanonicalExtensionsScannerDeps, } from "./canonical-extensions.js";
10
+ export { makeAgentDirScanner, type AgentDirScannerDeps } from "./agent-dir.js";
11
+ export { makeMcpConfigScanner, type McpConfigScannerDeps } from "./mcp-config.js";
12
+ export { makeAgentSettingsScanner, type AgentSettingsScannerDeps } from "./agent-settings.js";
13
+ export { agentRootSegment, detectAgentRootCollisions, makeAgentRootResolverState, type AgentRootResolverState, } from "./agent-root.js";
14
+ export { dedupeByIdentity, occurrenceIdentity, occurrenceIdentityKey, type AgentDirOccurrence, type AgentDirSubjectType, type AgentSettingsOccurrence, type CanonicalExtensionOccurrence, type CanonicalExtensionOriginKind, type McpConfigOccurrence, type McpConfigSurface, type OccurrenceIdentity, type ScannerOccurrence, } from "./types.js";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Scanner barrel: re-exports every per-scanner factory and the shared
3
+ * occurrence-shape types from one entry point so `context.ts` can pull
4
+ * scanner wiring from a single module.
5
+ *
6
+ * Each scanner module owns its own deps interface, occurrence shape, and
7
+ * partial-failure semantics; this barrel only re-exports — no logic.
8
+ */
9
+ // ---------------------------------------------------------------------------
10
+ // Canonical-extensions scanner
11
+ // ---------------------------------------------------------------------------
12
+ export { makeCanonicalExtensionsScanner, } from "./canonical-extensions.js";
13
+ // ---------------------------------------------------------------------------
14
+ // Agent-directory scanner
15
+ // ---------------------------------------------------------------------------
16
+ export { makeAgentDirScanner } from "./agent-dir.js";
17
+ // ---------------------------------------------------------------------------
18
+ // MCP-config scanner (workspace + per-agent)
19
+ // ---------------------------------------------------------------------------
20
+ export { makeMcpConfigScanner } from "./mcp-config.js";
21
+ // ---------------------------------------------------------------------------
22
+ // Agent-settings scanner
23
+ // ---------------------------------------------------------------------------
24
+ export { makeAgentSettingsScanner } from "./agent-settings.js";
25
+ // ---------------------------------------------------------------------------
26
+ // Shared agent-root resolver used by both the agent-settings and mcp-config
27
+ // scanners.
28
+ // ---------------------------------------------------------------------------
29
+ export { agentRootSegment, detectAgentRootCollisions, makeAgentRootResolverState, } from "./agent-root.js";
30
+ // ---------------------------------------------------------------------------
31
+ // Shared occurrence-shape types and identity helpers
32
+ // ---------------------------------------------------------------------------
33
+ export { dedupeByIdentity, occurrenceIdentity, occurrenceIdentityKey, } from "./types.js";
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * MCP-config scanner: plans physical targets from the capability catalog,
3
+ * reads each physical file once, and emits one occurrence per declared server.
4
+ * Shared targets remain shared observations; agent-native targets retain the
5
+ * exact agent id whose private surface supplied the observation.
6
+ *
7
+ * Per-file partial failures (unreadable config, bad JSON, schema-incompatible
8
+ * payload) become diagnostic warnings rather than errors. The error channel
9
+ * stays empty.
10
+ *
11
+ * MCP config layout:
12
+ *
13
+ * ```json
14
+ * {
15
+ * "mcpServers": {
16
+ * "<server-name>": { ... }
17
+ * }
18
+ * }
19
+ * ```
20
+ *
21
+ * The scanner emits one occurrence per `<server-name>` and captures each
22
+ * record-shaped server payload for import/adoption flows.
23
+ */
24
+ import * as Effect from "effect/Effect";
25
+ import type * as FileSystem from "effect/FileSystem";
26
+ import type * as Path from "effect/Path";
27
+ import type { AgentDescriptor, AgentId } from "@agentxm/extension-model/unstable/agents/types";
28
+ import type { Diagnostics } from "../diagnostics.js";
29
+ import type { Scope } from "../types.js";
30
+ import type { McpConfigOccurrence } from "./types.js";
31
+ /**
32
+ * Inputs the live layer captures before invoking the scanner. The optional
33
+ * `agentRegistry` mirrors the agent-dir scanner.
34
+ */
35
+ export interface McpConfigScannerDeps {
36
+ readonly fs: FileSystem.FileSystem;
37
+ readonly path: Path.Path;
38
+ readonly workspaceRoot: string;
39
+ readonly scope: Scope;
40
+ readonly diagnostics: Diagnostics;
41
+ readonly agentRegistry?: Readonly<Partial<Record<AgentId, AgentDescriptor>>>;
42
+ }
43
+ /**
44
+ * Closure helper: returns the dependency-closed scanner effect.
45
+ */
46
+ export declare const makeMcpConfigScanner: (deps: McpConfigScannerDeps) => Effect.Effect<ReadonlyArray<McpConfigOccurrence>>;
47
+ //# sourceMappingURL=mcp-config.d.ts.map