@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,170 @@
1
+ /**
2
+ * Skill subject module: declared/resolved/actual payload types, scanner
3
+ * composition, and projections via the shared `projectInstalledExtensions`
4
+ * helper.
5
+ *
6
+ * Per Decision 4 (single service + per-subject modules) and Decision 9
7
+ * (read-model rows) of the workspace read-model design, this module owns:
8
+ *
9
+ * - the subject-specific declared/resolved/actual payload types
10
+ * (`DeclaredSkills`, `ResolvedSkills`, `ActualSkills`);
11
+ * - the subject-specific origin union (`SkillDetectionOrigin`) and
12
+ * skill-specific facts (`contentRoot`, `sourcePath`, `packageRoot`,
13
+ * `hasSkillMd`, `hasSkillJson`);
14
+ * - scanner composition (canonical-extensions + agent-dir × skill-rendering
15
+ * agents);
16
+ * - the `installed` / `active` / `unmanaged` projections, wired
17
+ * through the helper with a skill-specific `SubjectPolicy`.
18
+ *
19
+ * The factory `makeSkillExtensionsApi(deps)` returns a `SkillExtensionsApi`
20
+ * with cells whose public types are dependency-closed. Phase 9 composes the
21
+ * factory inputs (`loaders`, `scanners`, `installedPacks`, `diagnostics`)
22
+ * inside `WorkspaceReadModelLive`.
23
+ */
24
+ import * as Effect from "effect/Effect";
25
+ import * as Option from "effect/Option";
26
+ import type { AgentId } from "@agentxm/extension-model/unstable/agents/types";
27
+ import { type ExtensionName } from "@agentxm/extension-model/unstable/extensions/common";
28
+ import type { Lockfile, SkillLockEntry } from "../../../lockfile/schema.js";
29
+ import type { Settings, SkillEntry } from "../../../settings/schema.js";
30
+ import type { Diagnostics } from "../diagnostics.js";
31
+ import type { LockfileReadError, SettingsReadError } from "../errors.js";
32
+ import type { AgentDirOccurrence, CanonicalExtensionOccurrence } from "../scanners/types.js";
33
+ import type { ActivationState, ExtensionKey, InstallationOrigin, InstalledPackRef, Scope } from "../types.js";
34
+ /**
35
+ * Subject-specific origin discriminator for an `ActualSkill`. Mirrors the spec
36
+ * scenarios that distinguish canonical AXM, external AXM, and agent-rendered
37
+ * skill directories.
38
+ */
39
+ export type SkillDetectionOrigin = {
40
+ readonly _tag: "canonical-axm-skill";
41
+ } | {
42
+ readonly _tag: "external-axm-skill";
43
+ } | {
44
+ readonly _tag: "agent-skill-dir";
45
+ readonly agentId: AgentId;
46
+ };
47
+ /**
48
+ * One declared skill entry. Wraps the raw settings entry without re-shaping
49
+ * fields; `name` is lifted out for ergonomic lookup.
50
+ */
51
+ export interface DeclaredSkill {
52
+ readonly name: ExtensionName;
53
+ readonly entry: SkillEntry;
54
+ }
55
+ /** Decoded skills declared in `axm.json`. */
56
+ export type DeclaredSkills = ReadonlyArray<DeclaredSkill>;
57
+ /** One resolved skill entry from the lockfile, wrapping the raw lock entry. */
58
+ export interface ResolvedSkill {
59
+ readonly name: ExtensionName;
60
+ readonly lockEntry: SkillLockEntry;
61
+ }
62
+ /** Decoded skills resolved in the lockfile. */
63
+ export type ResolvedSkills = ReadonlyArray<ResolvedSkill>;
64
+ /**
65
+ * One observable skill materialization. Carries the subject-specific origin
66
+ * plus skill-specific facts:
67
+ *
68
+ * - `contentRoot` — the directory containing the rendered skill (the same
69
+ * value as the underlying scanner's `contentLocation`);
70
+ * - `sourcePath` — absolute path to the canonical content file inside
71
+ * `contentRoot` (`SKILL.md`); equal to `null` if the file does not exist;
72
+ * - `packageRoot` — for canonical/external AXM, the registry-publish package
73
+ * root (parent of `src/<name>/`); `null` for agent-rendered skills;
74
+ * - `hasSkillMd` — convenience boolean derived from `sourcePath`;
75
+ * - `hasSkillJson` — placeholder for the optional `skill.json` companion file
76
+ * (left `false` in v1; Phase 9 wiring will flip when `agent-settings` or a
77
+ * future scanner detects it).
78
+ */
79
+ export interface ActualSkill {
80
+ readonly key: ExtensionKey<"skill">;
81
+ readonly origin: SkillDetectionOrigin;
82
+ readonly contentRoot: string;
83
+ readonly sourcePath: string | null;
84
+ readonly packageRoot: string | null;
85
+ readonly hasSkillMd: boolean;
86
+ readonly hasSkillJson: boolean;
87
+ }
88
+ /** Actual skills payload — array of observed materialization occurrences. */
89
+ export type ActualSkills = ReadonlyArray<ActualSkill>;
90
+ /** Pack-member entry for a skill: per Decision 9 it is the resolved member. */
91
+ export interface SkillPackMember {
92
+ readonly name: ExtensionName;
93
+ readonly providingPack: InstalledPackRef;
94
+ }
95
+ /** Installed skill row. */
96
+ export interface InstalledSkill {
97
+ readonly key: ExtensionKey<"skill">;
98
+ readonly installationOrigin: InstallationOrigin<DeclaredSkill, SkillPackMember>;
99
+ readonly activation: ActivationState;
100
+ readonly resolved: Option.Option<ResolvedSkill>;
101
+ readonly actual: ReadonlyArray<ActualSkill>;
102
+ readonly providingPacks: ReadonlyArray<InstalledPackRef>;
103
+ }
104
+ /** Unmanaged skill row — one actual occurrence not attached to an installed row. */
105
+ export interface UnmanagedSkill {
106
+ readonly key: ExtensionKey<"skill">;
107
+ readonly actual: ActualSkill;
108
+ }
109
+ /**
110
+ * Cached source loaders the factory captures. `Effect.cached` is applied at
111
+ * the loader site (Phase 4); the helper just consumes whatever shape the
112
+ * caller passes in.
113
+ */
114
+ export interface SkillScopedLoaders {
115
+ readonly settings: Effect.Effect<Option.Option<Settings>, SettingsReadError>;
116
+ readonly lockfile: Effect.Effect<Option.Option<Lockfile>, LockfileReadError>;
117
+ }
118
+ /**
119
+ * Cached scanner outputs the factory captures. The factory composes
120
+ * canonical-extensions + agent-dir occurrences into the actual skill array.
121
+ */
122
+ export interface SkillScanners {
123
+ readonly canonical: Effect.Effect<ReadonlyArray<CanonicalExtensionOccurrence>>;
124
+ readonly agentDir: Effect.Effect<ReadonlyArray<AgentDirOccurrence>>;
125
+ }
126
+ /**
127
+ * One installed-pack entry consumed by the projection. Pack-resolved member
128
+ * groups are read from the **installed pack manifest** in Phase 9; for unit
129
+ * tests the caller passes a synthetic shape.
130
+ */
131
+ export interface InstalledPackForSkills {
132
+ readonly ref: InstalledPackRef;
133
+ readonly skills: ReadonlyArray<SkillPackMember>;
134
+ }
135
+ /**
136
+ * Inputs `makeSkillExtensionsApi` captures.
137
+ */
138
+ export interface SkillExtensionsApiDeps {
139
+ readonly scope: Scope;
140
+ readonly loaders: SkillScopedLoaders;
141
+ readonly scanners: SkillScanners;
142
+ readonly installedPacks: Effect.Effect<ReadonlyArray<InstalledPackForSkills>, SettingsReadError | LockfileReadError>;
143
+ readonly diagnostics: Diagnostics;
144
+ }
145
+ /**
146
+ * Public skill API exposed by `ctx.scope(scope).skills`. Cells are
147
+ * dependency-closed and never carry `FileSystem | Path` requirements.
148
+ */
149
+ export interface SkillExtensionsApi {
150
+ readonly declared: Effect.Effect<Option.Option<DeclaredSkills>, SettingsReadError>;
151
+ readonly resolved: Effect.Effect<Option.Option<ResolvedSkills>, LockfileReadError>;
152
+ readonly actual: Effect.Effect<ActualSkills>;
153
+ readonly installed: Effect.Effect<ReadonlyArray<InstalledSkill>, SettingsReadError | LockfileReadError>;
154
+ readonly byName: (name: string) => Effect.Effect<Option.Option<InstalledSkill>, SettingsReadError | LockfileReadError>;
155
+ readonly declaredByName: (name: string) => Effect.Effect<Option.Option<DeclaredSkill>, SettingsReadError>;
156
+ readonly active: Effect.Effect<ReadonlyArray<InstalledSkill>, SettingsReadError | LockfileReadError>;
157
+ readonly unmanaged: Effect.Effect<ReadonlyArray<UnmanagedSkill>, SettingsReadError | LockfileReadError>;
158
+ }
159
+ /**
160
+ * Build the skill subject API over the captured loaders, scanners, and pack
161
+ * set.
162
+ *
163
+ * Returns an `Effect` because the projection cell is wrapped in
164
+ * `Effect.cached` so all four derived cells (`installed` / `active` /
165
+ * `unmanaged`) share a single in-flight execution and the
166
+ * projection — including its diagnostic side effects — runs at most once per
167
+ * scope, mirroring the `state.ts` loader pattern.
168
+ */
169
+ export declare const makeSkillExtensionsApi: (deps: SkillExtensionsApiDeps) => Effect.Effect<SkillExtensionsApi>;
170
+ //# sourceMappingURL=skill.d.ts.map
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Skill subject module: declared/resolved/actual payload types, scanner
3
+ * composition, and projections via the shared `projectInstalledExtensions`
4
+ * helper.
5
+ *
6
+ * Per Decision 4 (single service + per-subject modules) and Decision 9
7
+ * (read-model rows) of the workspace read-model design, this module owns:
8
+ *
9
+ * - the subject-specific declared/resolved/actual payload types
10
+ * (`DeclaredSkills`, `ResolvedSkills`, `ActualSkills`);
11
+ * - the subject-specific origin union (`SkillDetectionOrigin`) and
12
+ * skill-specific facts (`contentRoot`, `sourcePath`, `packageRoot`,
13
+ * `hasSkillMd`, `hasSkillJson`);
14
+ * - scanner composition (canonical-extensions + agent-dir × skill-rendering
15
+ * agents);
16
+ * - the `installed` / `active` / `unmanaged` projections, wired
17
+ * through the helper with a skill-specific `SubjectPolicy`.
18
+ *
19
+ * The factory `makeSkillExtensionsApi(deps)` returns a `SkillExtensionsApi`
20
+ * with cells whose public types are dependency-closed. Phase 9 composes the
21
+ * factory inputs (`loaders`, `scanners`, `installedPacks`, `diagnostics`)
22
+ * inside `WorkspaceReadModelLive`.
23
+ */
24
+ import * as Effect from "effect/Effect";
25
+ import * as Option from "effect/Option";
26
+ import { decodeExtensionNameSync, } from "@agentxm/extension-model/unstable/extensions/common";
27
+ import { filterMapOccurrences } from "./actual-helpers.js";
28
+ import { canonicalAxmPackageRoot } from "./package-root.js";
29
+ import { makeProjectedSubjectCells, projectInstalledExtensions, } from "./projection.js";
30
+ // ---------------------------------------------------------------------------
31
+ // Helpers — declared / resolved / actual normalization
32
+ // ---------------------------------------------------------------------------
33
+ const declaredFromSettings = (settings) => {
34
+ if (settings.skills === undefined)
35
+ return [];
36
+ return Object.entries(settings.skills).map(([name, entry]) => ({
37
+ name: decodeExtensionNameSync(name),
38
+ entry,
39
+ }));
40
+ };
41
+ const resolvedFromLockfile = (lockfile) => {
42
+ if (lockfile.skills === undefined)
43
+ return [];
44
+ return Object.entries(lockfile.skills).map(([name, lockEntry]) => ({
45
+ name: decodeExtensionNameSync(name),
46
+ lockEntry,
47
+ }));
48
+ };
49
+ const canonicalToActualSkill = (occ, scope) => {
50
+ const isExternal = occ.origin === "external-axm";
51
+ // canonical-axm contentLocation ends in `<package>/src` for authored and
52
+ // owner-qualified packages; external-axm contentLocation is the legacy
53
+ // user-scope external package root.
54
+ const packageRoot = canonicalAxmPackageRoot(occ);
55
+ return {
56
+ key: { scope, type: "skill", name: occ.name },
57
+ origin: isExternal ? { _tag: "external-axm-skill" } : { _tag: "canonical-axm-skill" },
58
+ contentRoot: occ.contentLocation,
59
+ sourcePath: Option.getOrNull(occ.subjectFile),
60
+ packageRoot,
61
+ hasSkillMd: occ.subjectFileExists,
62
+ // Scanner does not probe `skill.json` yet; keep `false` until a future
63
+ // scanner emission carries it.
64
+ hasSkillJson: false,
65
+ };
66
+ };
67
+ const agentDirToActualSkill = (occ, scope) => ({
68
+ key: { scope, type: "skill", name: occ.name },
69
+ origin: { _tag: "agent-skill-dir", agentId: occ.agentId },
70
+ contentRoot: occ.contentLocation,
71
+ sourcePath: Option.getOrNull(occ.subjectFile),
72
+ packageRoot: null,
73
+ hasSkillMd: occ.subjectFileExists,
74
+ // Scanner does not probe `skill.json` yet; keep `false` until a future
75
+ // scanner emission carries it.
76
+ hasSkillJson: false,
77
+ });
78
+ const simpleName = (name) => name;
79
+ const orphanResolvedWarning = (name) => ({
80
+ source: "lockfile",
81
+ message: `skill: lockfile entry "${name}" has no matching declared or pack-member home`,
82
+ code: "orphan-resolved",
83
+ });
84
+ const skillPolicy = (scope) => ({
85
+ declaredEntries: (declared) => declared,
86
+ declaredName: (entry) => entry.name,
87
+ declaredActivation: (entry) => (entry.entry.enabled ? "enabled" : "disabled"),
88
+ resolvedEntries: (resolved) => resolved,
89
+ resolvedName: (entry) => simpleName(entry.name),
90
+ actualEntries: (actual) => actual,
91
+ actualName: (entry) => entry.key.name,
92
+ packMemberName: (member) => simpleName(member.name),
93
+ packMemberActivation: () => "enabled",
94
+ attachActualToInstalled: (name, actual) => actual.filter((a) => a.key.name === name),
95
+ notClaimedBySubjectPolicy: () => true,
96
+ buildInstalledRow: (input) => ({
97
+ key: { scope, type: "skill", name: input.name },
98
+ installationOrigin: input.installationOrigin,
99
+ activation: input.activation,
100
+ resolved: input.resolved,
101
+ actual: input.actual,
102
+ providingPacks: input.providingPacks,
103
+ }),
104
+ buildUnmanagedRow: (entry) => ({
105
+ key: { scope, type: "skill", name: entry.key.name },
106
+ actual: entry,
107
+ }),
108
+ resolvedOrphanWarning: orphanResolvedWarning,
109
+ });
110
+ /**
111
+ * Build the skill subject API over the captured loaders, scanners, and pack
112
+ * set.
113
+ *
114
+ * Returns an `Effect` because the projection cell is wrapped in
115
+ * `Effect.cached` so all four derived cells (`installed` / `active` /
116
+ * `unmanaged`) share a single in-flight execution and the
117
+ * projection — including its diagnostic side effects — runs at most once per
118
+ * scope, mirroring the `state.ts` loader pattern.
119
+ */
120
+ export const makeSkillExtensionsApi = (deps) => Effect.gen(function* () {
121
+ const { scope, loaders, scanners, installedPacks, diagnostics } = deps;
122
+ const declared = loaders.settings.pipe(Effect.map((opt) => Option.map(opt, (settings) => declaredFromSettings(settings))));
123
+ const resolved = loaders.lockfile.pipe(Effect.map((opt) => Option.map(opt, (lockfile) => resolvedFromLockfile(lockfile))));
124
+ const actual = Effect.gen(function* () {
125
+ const canonical = yield* scanners.canonical;
126
+ const agentDir = yield* scanners.agentDir;
127
+ const fromCanonical = filterMapOccurrences(canonical, "skill", (occ) => canonicalToActualSkill(occ, scope));
128
+ const fromAgentDir = filterMapOccurrences(agentDir, "skill", (occ) => agentDirToActualSkill(occ, scope));
129
+ return [...fromCanonical, ...fromAgentDir];
130
+ });
131
+ const project = yield* Effect.cached(projectInstalledExtensions({
132
+ declared,
133
+ resolved,
134
+ actual,
135
+ installedPacks: installedPacks.pipe(Effect.map((packs) => packs.map((p) => ({ ref: p.ref, members: p.skills })))),
136
+ packMembers: (pack) => pack.members,
137
+ packRef: (pack) => pack.ref,
138
+ policy: skillPolicy(scope),
139
+ diagnostics,
140
+ }));
141
+ return makeProjectedSubjectCells({
142
+ declared,
143
+ resolved,
144
+ actual,
145
+ project,
146
+ });
147
+ });
148
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Subagent subject module: declared/resolved/actual payloads, scanner
3
+ * composition (canonical-extensions + agent-dir × subagent-rendering agents),
4
+ * and projections via the shared helper.
5
+ *
6
+ * Activation comes from the declared `enabled` flag, mirroring skills and
7
+ * commands. Single-file subagent surfaces (e.g., `roo`'s `.roomodes`) emit
8
+ * one occurrence per file path; the file itself is the materialization.
9
+ */
10
+ import * as Effect from "effect/Effect";
11
+ import * as Option from "effect/Option";
12
+ import type { AgentId } from "@agentxm/extension-model/unstable/agents/types";
13
+ import { type ExtensionName } from "@agentxm/extension-model/unstable/extensions/common";
14
+ import type { Lockfile, SubagentLockEntry } from "../../../lockfile/schema.js";
15
+ import type { Settings, SubagentEntry } from "../../../settings/schema.js";
16
+ import type { Diagnostics } from "../diagnostics.js";
17
+ import type { LockfileReadError, SettingsReadError } from "../errors.js";
18
+ import type { AgentDirOccurrence, CanonicalExtensionOccurrence } from "../scanners/types.js";
19
+ import type { ActivationState, ExtensionKey, InstallationOrigin, InstalledPackRef, Scope } from "../types.js";
20
+ export type SubagentDetectionOrigin = {
21
+ readonly _tag: "canonical-axm-subagent";
22
+ } | {
23
+ readonly _tag: "external-axm-subagent";
24
+ } | {
25
+ readonly _tag: "agent-subagent-dir";
26
+ readonly agentId: AgentId;
27
+ };
28
+ export interface DeclaredSubagent {
29
+ readonly name: ExtensionName;
30
+ readonly entry: SubagentEntry;
31
+ }
32
+ export type DeclaredSubagents = ReadonlyArray<DeclaredSubagent>;
33
+ export interface ResolvedSubagent {
34
+ readonly name: ExtensionName;
35
+ readonly lockEntry: SubagentLockEntry;
36
+ }
37
+ export type ResolvedSubagents = ReadonlyArray<ResolvedSubagent>;
38
+ export interface ActualSubagent {
39
+ readonly key: ExtensionKey<"subagent">;
40
+ readonly origin: SubagentDetectionOrigin;
41
+ readonly contentRoot: string;
42
+ readonly sourcePath: string | null;
43
+ readonly packageRoot: string | null;
44
+ }
45
+ export type ActualSubagents = ReadonlyArray<ActualSubagent>;
46
+ export interface SubagentPackMember {
47
+ readonly name: ExtensionName;
48
+ readonly providingPack: InstalledPackRef;
49
+ }
50
+ export interface InstalledSubagent {
51
+ readonly key: ExtensionKey<"subagent">;
52
+ readonly installationOrigin: InstallationOrigin<DeclaredSubagent, SubagentPackMember>;
53
+ readonly activation: ActivationState;
54
+ readonly resolved: Option.Option<ResolvedSubagent>;
55
+ readonly actual: ReadonlyArray<ActualSubagent>;
56
+ readonly providingPacks: ReadonlyArray<InstalledPackRef>;
57
+ }
58
+ export interface UnmanagedSubagent {
59
+ readonly key: ExtensionKey<"subagent">;
60
+ readonly actual: ActualSubagent;
61
+ }
62
+ export interface SubagentScopedLoaders {
63
+ readonly settings: Effect.Effect<Option.Option<Settings>, SettingsReadError>;
64
+ readonly lockfile: Effect.Effect<Option.Option<Lockfile>, LockfileReadError>;
65
+ }
66
+ export interface SubagentScanners {
67
+ readonly canonical: Effect.Effect<ReadonlyArray<CanonicalExtensionOccurrence>>;
68
+ readonly agentDir: Effect.Effect<ReadonlyArray<AgentDirOccurrence>>;
69
+ }
70
+ export interface InstalledPackForSubagents {
71
+ readonly ref: InstalledPackRef;
72
+ readonly subagents: ReadonlyArray<SubagentPackMember>;
73
+ }
74
+ export interface SubagentExtensionsApiDeps {
75
+ readonly scope: Scope;
76
+ readonly loaders: SubagentScopedLoaders;
77
+ readonly scanners: SubagentScanners;
78
+ readonly installedPacks: Effect.Effect<ReadonlyArray<InstalledPackForSubagents>, SettingsReadError | LockfileReadError>;
79
+ readonly diagnostics: Diagnostics;
80
+ }
81
+ export interface SubagentExtensionsApi {
82
+ readonly declared: Effect.Effect<Option.Option<DeclaredSubagents>, SettingsReadError>;
83
+ readonly resolved: Effect.Effect<Option.Option<ResolvedSubagents>, LockfileReadError>;
84
+ readonly actual: Effect.Effect<ActualSubagents>;
85
+ readonly installed: Effect.Effect<ReadonlyArray<InstalledSubagent>, SettingsReadError | LockfileReadError>;
86
+ readonly byName: (name: string) => Effect.Effect<Option.Option<InstalledSubagent>, SettingsReadError | LockfileReadError>;
87
+ readonly declaredByName: (name: string) => Effect.Effect<Option.Option<DeclaredSubagent>, SettingsReadError>;
88
+ readonly active: Effect.Effect<ReadonlyArray<InstalledSubagent>, SettingsReadError | LockfileReadError>;
89
+ readonly unmanaged: Effect.Effect<ReadonlyArray<UnmanagedSubagent>, SettingsReadError | LockfileReadError>;
90
+ }
91
+ /**
92
+ * Build the subagent subject API. Returns an `Effect` because the projection
93
+ * cell is wrapped in `Effect.cached` so the four derived cells share one
94
+ * in-flight execution per scope, mirroring `state.ts`.
95
+ */
96
+ export declare const makeSubagentExtensionsApi: (deps: SubagentExtensionsApiDeps) => Effect.Effect<SubagentExtensionsApi>;
97
+ //# sourceMappingURL=subagent.d.ts.map
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Subagent subject module: declared/resolved/actual payloads, scanner
3
+ * composition (canonical-extensions + agent-dir × subagent-rendering agents),
4
+ * and projections via the shared helper.
5
+ *
6
+ * Activation comes from the declared `enabled` flag, mirroring skills and
7
+ * commands. Single-file subagent surfaces (e.g., `roo`'s `.roomodes`) emit
8
+ * one occurrence per file path; the file itself is the materialization.
9
+ */
10
+ import * as Effect from "effect/Effect";
11
+ import * as Option from "effect/Option";
12
+ import { decodeExtensionNameSync, } from "@agentxm/extension-model/unstable/extensions/common";
13
+ import { filterMapOccurrences } from "./actual-helpers.js";
14
+ import { canonicalAxmPackageRoot } from "./package-root.js";
15
+ import { makeProjectedSubjectCells, projectInstalledExtensions, } from "./projection.js";
16
+ // ---------------------------------------------------------------------------
17
+ // Helpers
18
+ // ---------------------------------------------------------------------------
19
+ const declaredFromSettings = (settings) => {
20
+ if (settings.subagents === undefined)
21
+ return [];
22
+ return Object.entries(settings.subagents).map(([name, entry]) => ({
23
+ name: decodeExtensionNameSync(name),
24
+ entry,
25
+ }));
26
+ };
27
+ const resolvedFromLockfile = (lockfile) => {
28
+ if (lockfile.subagents === undefined)
29
+ return [];
30
+ return Object.entries(lockfile.subagents).map(([name, lockEntry]) => ({
31
+ name: decodeExtensionNameSync(name),
32
+ lockEntry,
33
+ }));
34
+ };
35
+ const canonicalToActual = (occ, scope) => {
36
+ const isExternal = occ.origin === "external-axm";
37
+ const packageRoot = canonicalAxmPackageRoot(occ);
38
+ return {
39
+ key: { scope, type: "subagent", name: occ.name },
40
+ origin: isExternal ? { _tag: "external-axm-subagent" } : { _tag: "canonical-axm-subagent" },
41
+ contentRoot: occ.contentLocation,
42
+ sourcePath: Option.getOrNull(occ.subjectFile),
43
+ packageRoot,
44
+ };
45
+ };
46
+ const agentDirToActual = (occ, scope) => ({
47
+ key: { scope, type: "subagent", name: occ.name },
48
+ origin: { _tag: "agent-subagent-dir", agentId: occ.agentId },
49
+ contentRoot: occ.contentLocation,
50
+ // For directory-style subagents the scanner emits `<dir>/${name}.md`; for
51
+ // single-file surfaces (e.g., `.roomodes`) the scanner emits the file path
52
+ // itself. Either way `subjectFile` is `Some` for agent-dir subagent occs.
53
+ sourcePath: Option.getOrNull(occ.subjectFile),
54
+ packageRoot: null,
55
+ });
56
+ const orphanResolvedWarning = (name) => ({
57
+ source: "lockfile",
58
+ message: `subagent: lockfile entry "${name}" has no matching declared or pack-member home`,
59
+ code: "orphan-resolved",
60
+ });
61
+ const subagentPolicy = (scope) => ({
62
+ declaredEntries: (d) => d,
63
+ declaredName: (e) => e.name,
64
+ declaredActivation: (e) => (e.entry.enabled ? "enabled" : "disabled"),
65
+ resolvedEntries: (r) => r,
66
+ resolvedName: (e) => e.name,
67
+ actualEntries: (a) => a,
68
+ actualName: (e) => e.key.name,
69
+ packMemberName: (m) => m.name,
70
+ packMemberActivation: () => "enabled",
71
+ attachActualToInstalled: (name, actual) => actual.filter((a) => a.key.name === name),
72
+ notClaimedBySubjectPolicy: () => true,
73
+ buildInstalledRow: (input) => ({
74
+ key: { scope, type: "subagent", name: input.name },
75
+ installationOrigin: input.installationOrigin,
76
+ activation: input.activation,
77
+ resolved: input.resolved,
78
+ actual: input.actual,
79
+ providingPacks: input.providingPacks,
80
+ }),
81
+ buildUnmanagedRow: (entry) => ({
82
+ key: { scope, type: "subagent", name: entry.key.name },
83
+ actual: entry,
84
+ }),
85
+ resolvedOrphanWarning: orphanResolvedWarning,
86
+ });
87
+ /**
88
+ * Build the subagent subject API. Returns an `Effect` because the projection
89
+ * cell is wrapped in `Effect.cached` so the four derived cells share one
90
+ * in-flight execution per scope, mirroring `state.ts`.
91
+ */
92
+ export const makeSubagentExtensionsApi = (deps) => Effect.gen(function* () {
93
+ const { scope, loaders, scanners, installedPacks, diagnostics } = deps;
94
+ const declared = loaders.settings.pipe(Effect.map((opt) => Option.map(opt, declaredFromSettings)));
95
+ const resolved = loaders.lockfile.pipe(Effect.map((opt) => Option.map(opt, resolvedFromLockfile)));
96
+ const actual = Effect.gen(function* () {
97
+ const canonical = yield* scanners.canonical;
98
+ const agentDir = yield* scanners.agentDir;
99
+ const fromCanonical = filterMapOccurrences(canonical, "subagent", (occ) => canonicalToActual(occ, scope));
100
+ const fromAgentDir = filterMapOccurrences(agentDir, "subagent", (occ) => agentDirToActual(occ, scope));
101
+ return [...fromCanonical, ...fromAgentDir];
102
+ });
103
+ const project = yield* Effect.cached(projectInstalledExtensions({
104
+ declared,
105
+ resolved,
106
+ actual,
107
+ installedPacks: installedPacks.pipe(Effect.map((packs) => packs.map((p) => ({ ref: p.ref, members: p.subagents })))),
108
+ packMembers: (pack) => pack.members,
109
+ packRef: (pack) => pack.ref,
110
+ policy: subagentPolicy(scope),
111
+ diagnostics,
112
+ }));
113
+ return makeProjectedSubjectCells({
114
+ declared,
115
+ resolved,
116
+ actual,
117
+ project,
118
+ });
119
+ });
120
+ //# sourceMappingURL=subagent.js.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Agent-directory scanner: enumerates per-agent skill and subagent
3
+ * directories declared by the existing `AgentRegistry`. Each occurrence
4
+ * carries an `agent-dir` discriminator parameterized by `agentId` and the
5
+ * subject `type`.
6
+ *
7
+ * Subject coverage in v1:
8
+ *
9
+ * - skill — every agent with a non-empty `agent.skills.dir`.
10
+ * - subagent — every agent with `agent.subagents?.dir`. Single-file
11
+ * subagent surfaces (`isFile === true`, e.g., `roo`'s `.roomodes`) emit one
12
+ * occurrence per file path; the file itself is the materialization.
13
+ *
14
+ * Rules: no agent in the v1 `AgentRegistry` exposes a rules directory, so the
15
+ * scanner emits no rule occurrences.
16
+ *
17
+ * Each occurrence carries structural fields the subject modules need for
18
+ * cross-platform path handling — `pathSegments` (the absolute path split via
19
+ * the `Path` service) and `subjectFile` (the canonical primary file inside
20
+ * the subject directory) — plus a probed `subjectFileExists` flag so subject
21
+ * modules do not hardcode presence.
22
+ *
23
+ * Per Decision 5, scanner output is occurrence-shaped. The public effect
24
+ * carries no `FileSystem | Path` requirement; per-file partial failures
25
+ * publish diagnostic warnings rather than failing the cell.
26
+ *
27
+ * The scanner avoids `fs.stat` and uses only `fs.exists` / `fs.readDirectory`
28
+ * so it remains compatible with the fixture builder's in-memory `FileSystem`.
29
+ */
30
+ import * as Effect from "effect/Effect";
31
+ import type * as FileSystem from "effect/FileSystem";
32
+ import type * as Path from "effect/Path";
33
+ import type { AgentDescriptor, AgentId } from "@agentxm/extension-model/unstable/agents/types";
34
+ import type { Diagnostics } from "../diagnostics.js";
35
+ import type { Scope } from "../types.js";
36
+ import type { AgentDirOccurrence } from "./types.js";
37
+ export interface AgentDirScannerDeps {
38
+ readonly fs: FileSystem.FileSystem;
39
+ readonly path: Path.Path;
40
+ readonly workspaceRoot: string;
41
+ readonly scope: Scope;
42
+ readonly diagnostics: Diagnostics;
43
+ readonly agentRegistry?: Readonly<Partial<Record<AgentId, AgentDescriptor>>>;
44
+ }
45
+ /**
46
+ * Closure helper: returns the dependency-closed scanner effect.
47
+ */
48
+ export declare const makeAgentDirScanner: (deps: AgentDirScannerDeps) => Effect.Effect<ReadonlyArray<AgentDirOccurrence>>;
49
+ //# sourceMappingURL=agent-dir.d.ts.map