@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,137 @@
1
+ /**
2
+ * Shared projection helper: composes installed/active/unmanaged from
3
+ * declared/resolved/actual plus the installed-pack set.
4
+ *
5
+ * Per the projection invariant in the workspace read-model design (Decision 7):
6
+ *
7
+ * ```ts
8
+ * direct = declared.map(withInstallationOrigin("direct"));
9
+ * implicit = installedPacks
10
+ * .flatMap(p => p.members)
11
+ * .filter(notDeclaredByName) // direct (incl. disabled) wins
12
+ * .map(withInstallationOrigin("pack-member"));
13
+ * installed = direct + implicit;
14
+ * active = installed.filter(activation === "enabled");
15
+ * unmanaged = actual
16
+ * .filter(notClaimedByInstalled)
17
+ * .filter(notClaimedBySubjectPolicy);
18
+ * ```
19
+ *
20
+ * The helper owns:
21
+ * - direct-over-pack precedence;
22
+ * - disabled-direct still claims actual occurrences (excluded from active and
23
+ * from unmanaged);
24
+ * - actual-occurrence attachment via `policy.attachActualToInstalled`;
25
+ * - orphaned-resolved diagnostics — resolved entries with no direct or
26
+ * pack-member home publish a warning;
27
+ * - deterministic name-sorted ordering.
28
+ *
29
+ * The helper does NOT own subject row shape or subject policy. Both come in as
30
+ * parameters via `SubjectPolicy<...>`.
31
+ */
32
+ import * as Effect from "effect/Effect";
33
+ import * as Option from "effect/Option";
34
+ import type { Diagnostics, Warning } from "../diagnostics.js";
35
+ import type { LockfileReadError, SettingsReadError } from "../errors.js";
36
+ import type { ActivationState, InstallationOrigin, InstalledPackRef } from "../types.js";
37
+ import { type RowWithKey } from "./indexByName.js";
38
+ /**
39
+ * One entry within a subject's `declared` payload. The shape is opaque to the
40
+ * helper; the policy callbacks bridge to subject internals.
41
+ */
42
+ export type TDeclaredEntry<TDeclared> = TDeclared extends ReadonlyArray<infer E> ? E : TDeclared;
43
+ /** One entry within a subject's `resolved` payload. */
44
+ export type TResolvedEntry<TResolved> = TResolved extends ReadonlyArray<infer E> ? E : TResolved;
45
+ /** One actual occurrence within a subject's `actual` payload. */
46
+ export type TActualEntry<TActual> = TActual extends ReadonlyArray<infer E> ? E : TActual;
47
+ /**
48
+ * Subject-specific policy callbacks the projection helper requires.
49
+ */
50
+ export interface SubjectPolicy<TDeclared, TResolved, TActual, TPackMember, TInstalled, TUnmanaged> {
51
+ /** Iterate the subject's declared entries from a decoded `declared` payload. */
52
+ readonly declaredEntries: (declared: TDeclared) => ReadonlyArray<TDeclaredEntry<TDeclared>>;
53
+ /** Extract the subject name from a declared entry. */
54
+ readonly declaredName: (entry: TDeclaredEntry<TDeclared>) => string;
55
+ /**
56
+ * Activation state derived from a declared entry.
57
+ */
58
+ readonly declaredActivation: (entry: TDeclaredEntry<TDeclared>) => ActivationState;
59
+ /** Iterate the subject's resolved entries from a decoded `resolved` payload. */
60
+ readonly resolvedEntries: (resolved: TResolved) => ReadonlyArray<TResolvedEntry<TResolved>>;
61
+ /** Extract the subject name from a resolved entry. */
62
+ readonly resolvedName: (entry: TResolvedEntry<TResolved>) => string;
63
+ /** Iterate the subject's actual occurrences from an `actual` payload. */
64
+ readonly actualEntries: (actual: TActual) => ReadonlyArray<TActualEntry<TActual>>;
65
+ /** Extract the subject name from an actual occurrence. */
66
+ readonly actualName: (entry: TActualEntry<TActual>) => string;
67
+ /** Extract the subject name from a pack-member entry. */
68
+ readonly packMemberName: (member: TPackMember) => string;
69
+ /** Activation state for a pack-member installed row. */
70
+ readonly packMemberActivation: (member: TPackMember) => ActivationState;
71
+ /** Filter actual occurrences to those that match a given installed name. */
72
+ readonly attachActualToInstalled: (name: string, actual: ReadonlyArray<TActualEntry<TActual>>) => ReadonlyArray<TActualEntry<TActual>>;
73
+ /**
74
+ * Subject-policy filter for unmanaged actual occurrences. Returns `true` if
75
+ * the occurrence is NOT claimed by subject-specific policy.
76
+ */
77
+ readonly notClaimedBySubjectPolicy: (entry: TActualEntry<TActual>) => boolean;
78
+ /** Build a subject installed row from the assembled facts. */
79
+ readonly buildInstalledRow: (input: BuildInstalledRowInput<TDeclared, TResolved, TActual, TPackMember>) => TInstalled;
80
+ /** Build a subject unmanaged row from one actual occurrence. */
81
+ readonly buildUnmanagedRow: (entry: TActualEntry<TActual>) => TUnmanaged;
82
+ /** Build the orphan-resolved warning published when a resolved entry has no home. */
83
+ readonly resolvedOrphanWarning: (name: string) => Warning;
84
+ }
85
+ /**
86
+ * Input passed to `buildInstalledRow`. Carries everything the subject needs
87
+ * to construct its installed row.
88
+ */
89
+ export interface BuildInstalledRowInput<TDeclared, TResolved, TActual, TPackMember> {
90
+ readonly name: string;
91
+ readonly installationOrigin: InstallationOrigin<TDeclaredEntry<TDeclared>, TPackMember>;
92
+ readonly activation: ActivationState;
93
+ readonly resolved: Option.Option<TResolvedEntry<TResolved>>;
94
+ readonly actual: ReadonlyArray<TActualEntry<TActual>>;
95
+ readonly providingPacks: ReadonlyArray<InstalledPackRef>;
96
+ }
97
+ export interface ProjectInstalledExtensionsInput<TDeclared, TResolved, TActual, TPack, TPackMember, TInstalled, TUnmanaged> {
98
+ readonly declared: Effect.Effect<Option.Option<TDeclared>, SettingsReadError>;
99
+ readonly resolved: Effect.Effect<Option.Option<TResolved>, LockfileReadError>;
100
+ readonly actual: Effect.Effect<TActual>;
101
+ readonly installedPacks: Effect.Effect<ReadonlyArray<TPack>, SettingsReadError | LockfileReadError>;
102
+ readonly packMembers: (pack: TPack) => ReadonlyArray<TPackMember>;
103
+ readonly packRef: (pack: TPack) => InstalledPackRef;
104
+ readonly policy: SubjectPolicy<TDeclared, TResolved, TActual, TPackMember, TInstalled, TUnmanaged>;
105
+ readonly diagnostics: Diagnostics;
106
+ }
107
+ export interface ProjectInstalledExtensionsOutput<TInstalled, TUnmanaged> {
108
+ readonly installed: ReadonlyArray<TInstalled>;
109
+ readonly active: ReadonlyArray<TInstalled>;
110
+ readonly unmanaged: ReadonlyArray<TUnmanaged>;
111
+ }
112
+ export declare const makeProjectedSubjectCells: <TDeclaredEntry extends {
113
+ readonly name: string;
114
+ }, TDeclared extends ReadonlyArray<TDeclaredEntry>, TResolved, TActual, TInstalled extends RowWithKey, TUnmanaged>(args: {
115
+ readonly declared: Effect.Effect<Option.Option<TDeclared>, SettingsReadError>;
116
+ readonly resolved: Effect.Effect<Option.Option<TResolved>, LockfileReadError>;
117
+ readonly actual: Effect.Effect<TActual>;
118
+ readonly project: Effect.Effect<ProjectInstalledExtensionsOutput<TInstalled, TUnmanaged>, SettingsReadError | LockfileReadError>;
119
+ }) => {
120
+ declared: Effect.Effect<Option.Option<TDeclared>, SettingsReadError, never>;
121
+ resolved: Effect.Effect<Option.Option<TResolved>, LockfileReadError, never>;
122
+ actual: Effect.Effect<TActual, never, never>;
123
+ installed: Effect.Effect<readonly TInstalled[], SettingsReadError | LockfileReadError, never>;
124
+ byName: (name: string) => Effect.Effect<Option.Option<TInstalled>, SettingsReadError | LockfileReadError, never>;
125
+ declaredByName: (name: string) => Effect.Effect<Option.Option<Exclude<TDeclaredEntry, undefined>>, SettingsReadError, never>;
126
+ active: Effect.Effect<readonly TInstalled[], SettingsReadError | LockfileReadError, never>;
127
+ unmanaged: Effect.Effect<readonly TUnmanaged[], SettingsReadError | LockfileReadError, never>;
128
+ };
129
+ /**
130
+ * Compose installed, active, and unmanaged rows from declared/resolved/actual
131
+ * plus the installed-pack set, per the projection invariant.
132
+ *
133
+ * Source-read failures propagate so invalid persisted authority is never
134
+ * treated as absent.
135
+ */
136
+ export declare const projectInstalledExtensions: <TDeclared, TResolved, TActual, TPack, TPackMember, TInstalled, TUnmanaged>(input: ProjectInstalledExtensionsInput<TDeclared, TResolved, TActual, TPack, TPackMember, TInstalled, TUnmanaged>) => Effect.Effect<ProjectInstalledExtensionsOutput<TInstalled, TUnmanaged>, SettingsReadError | LockfileReadError>;
137
+ //# sourceMappingURL=projection.d.ts.map
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Shared projection helper: composes installed/active/unmanaged from
3
+ * declared/resolved/actual plus the installed-pack set.
4
+ *
5
+ * Per the projection invariant in the workspace read-model design (Decision 7):
6
+ *
7
+ * ```ts
8
+ * direct = declared.map(withInstallationOrigin("direct"));
9
+ * implicit = installedPacks
10
+ * .flatMap(p => p.members)
11
+ * .filter(notDeclaredByName) // direct (incl. disabled) wins
12
+ * .map(withInstallationOrigin("pack-member"));
13
+ * installed = direct + implicit;
14
+ * active = installed.filter(activation === "enabled");
15
+ * unmanaged = actual
16
+ * .filter(notClaimedByInstalled)
17
+ * .filter(notClaimedBySubjectPolicy);
18
+ * ```
19
+ *
20
+ * The helper owns:
21
+ * - direct-over-pack precedence;
22
+ * - disabled-direct still claims actual occurrences (excluded from active and
23
+ * from unmanaged);
24
+ * - actual-occurrence attachment via `policy.attachActualToInstalled`;
25
+ * - orphaned-resolved diagnostics — resolved entries with no direct or
26
+ * pack-member home publish a warning;
27
+ * - deterministic name-sorted ordering.
28
+ *
29
+ * The helper does NOT own subject row shape or subject policy. Both come in as
30
+ * parameters via `SubjectPolicy<...>`.
31
+ */
32
+ import * as Array from "effect/Array";
33
+ import * as Effect from "effect/Effect";
34
+ import * as Option from "effect/Option";
35
+ import { findByName } from "./indexByName.js";
36
+ export const makeProjectedSubjectCells = (args) => ({
37
+ declared: args.declared,
38
+ resolved: args.resolved,
39
+ actual: args.actual,
40
+ installed: args.project.pipe(Effect.map((out) => out.installed)),
41
+ byName: (name) => args.project.pipe(Effect.map((out) => findByName(out.installed, name))),
42
+ declaredByName: (name) => args.declared.pipe(Effect.map((opt) => Option.flatMap(opt, (rows) => Option.fromUndefinedOr(rows.find((row) => row.name === name))))),
43
+ active: args.project.pipe(Effect.map((out) => out.active)),
44
+ unmanaged: args.project.pipe(Effect.map((out) => out.unmanaged)),
45
+ });
46
+ // ---------------------------------------------------------------------------
47
+ // Public helper
48
+ // ---------------------------------------------------------------------------
49
+ /**
50
+ * Compose installed, active, and unmanaged rows from declared/resolved/actual
51
+ * plus the installed-pack set, per the projection invariant.
52
+ *
53
+ * Source-read failures propagate so invalid persisted authority is never
54
+ * treated as absent.
55
+ */
56
+ export const projectInstalledExtensions = (input) => Effect.gen(function* () {
57
+ const { declared, resolved, actual, installedPacks, packMembers, packRef, policy, diagnostics, } = input;
58
+ // 1. Read the three layers + installed packs. Invalid persisted authority
59
+ // fails the projection instead of being treated as absent.
60
+ const declaredOpt = yield* declared;
61
+ const resolvedOpt = yield* resolved;
62
+ const actualPayload = yield* actual;
63
+ const packs = yield* installedPacks;
64
+ // 2. Iterate raw evidence into per-name lookups using first-wins
65
+ // deduplication. `dedupeFirstByName` builds an immutable Map keyed by
66
+ // the policy-derived name; subsequent entries with the same name are
67
+ // dropped, so the projection stays deterministic.
68
+ const emptyDeclared = [];
69
+ const emptyResolved = [];
70
+ const declaredEntries = Option.match(declaredOpt, {
71
+ onNone: () => emptyDeclared,
72
+ onSome: (d) => policy.declaredEntries(d),
73
+ });
74
+ const resolvedEntries = Option.match(resolvedOpt, {
75
+ onNone: () => emptyResolved,
76
+ onSome: (r) => policy.resolvedEntries(r),
77
+ });
78
+ const actualEntries = policy.actualEntries(actualPayload);
79
+ const declaredByName = dedupeFirstByName(declaredEntries, policy.declaredName);
80
+ const resolvedByName = dedupeFirstByName(resolvedEntries, policy.resolvedName);
81
+ const packMemberPairs = packs.flatMap((pack) => {
82
+ const ref = packRef(pack);
83
+ return packMembers(pack).map((member) => [member, ref]);
84
+ });
85
+ const memberByName = packMemberPairs.reduce((acc, [member, ref]) => {
86
+ const name = policy.packMemberName(member);
87
+ const existing = acc.get(name);
88
+ const next = new Map(acc);
89
+ if (existing === undefined) {
90
+ next.set(name, { member, pack: ref, providingPacks: [ref] });
91
+ }
92
+ else {
93
+ next.set(name, {
94
+ member: existing.member,
95
+ pack: existing.pack,
96
+ providingPacks: [...existing.providingPacks, ref],
97
+ });
98
+ }
99
+ return next;
100
+ }, new Map());
101
+ const direct = Array.getSomes(Array.fromIterable(declaredByName.entries()).map(([name, entry]) => {
102
+ const activation = policy.declaredActivation(entry);
103
+ const memberState = memberByName.get(name);
104
+ const providingPacks = memberState === undefined ? [] : memberState.providingPacks;
105
+ const attached = policy.attachActualToInstalled(name, actualEntries);
106
+ const row = policy.buildInstalledRow({
107
+ name,
108
+ installationOrigin: { _tag: "direct", declared: entry },
109
+ activation,
110
+ resolved: Option.fromUndefinedOr(resolvedByName.get(name)),
111
+ actual: attached,
112
+ providingPacks,
113
+ });
114
+ return Option.some({ name, row, activation });
115
+ }));
116
+ // 5. Implicit pack-member rows: skip names already declared (direct wins,
117
+ // including disabled).
118
+ const implicit = Array.getSomes(Array.fromIterable(memberByName.entries()).map(([name, state]) => {
119
+ if (declaredByName.has(name))
120
+ return Option.none(); // direct wins
121
+ const activation = policy.packMemberActivation(state.member);
122
+ const attached = policy.attachActualToInstalled(name, actualEntries);
123
+ const row = policy.buildInstalledRow({
124
+ name,
125
+ installationOrigin: {
126
+ _tag: "pack-member",
127
+ member: state.member,
128
+ pack: state.pack,
129
+ },
130
+ activation,
131
+ resolved: Option.fromUndefinedOr(resolvedByName.get(name)),
132
+ actual: attached,
133
+ providingPacks: state.providingPacks,
134
+ });
135
+ return Option.some({ name, row, activation });
136
+ }));
137
+ // 6. Sort by name for deterministic ordering.
138
+ const installedNamed = [...direct, ...implicit].sort((a, b) => a.name.localeCompare(b.name));
139
+ const installedNames = new Set(installedNamed.map((r) => r.name));
140
+ const installed = installedNamed.map((r) => r.row);
141
+ const active = installedNamed
142
+ .filter((r) => r.activation === "enabled")
143
+ .map((r) => r.row);
144
+ // 7. Orphaned-resolved diagnostics: any resolved entry whose name is
145
+ // neither declared nor present as a pack-member. Collect orphan names
146
+ // first, then publish sequentially via Effect.forEach to keep the
147
+ // diagnostics buffer in deterministic order.
148
+ const orphanNames = Array.fromIterable(resolvedByName.keys()).filter((name) => !declaredByName.has(name) && !memberByName.has(name));
149
+ yield* Effect.forEach(orphanNames, (name) => diagnostics.append(policy.resolvedOrphanWarning(name)), { discard: true });
150
+ // 8. Unmanaged: actual occurrences not claimed by an installed row and
151
+ // passing subject policy.
152
+ const unmanaged = Array.getSomes(actualEntries.map((entry) => {
153
+ const name = policy.actualName(entry);
154
+ if (installedNames.has(name))
155
+ return Option.none();
156
+ if (!policy.notClaimedBySubjectPolicy(entry))
157
+ return Option.none();
158
+ return Option.some(policy.buildUnmanagedRow(entry));
159
+ }));
160
+ return {
161
+ installed,
162
+ active,
163
+ unmanaged,
164
+ };
165
+ });
166
+ /**
167
+ * Build a name-indexed read-only map, keeping the first occurrence per name.
168
+ * Subsequent entries with the same name are dropped; the original input order
169
+ * determines which one wins. Pure helper used to dedupe declared/resolved
170
+ * entry arrays.
171
+ */
172
+ const dedupeFirstByName = (entries, nameOf) => entries.reduce((acc, entry) => {
173
+ const name = nameOf(entry);
174
+ if (acc.has(name))
175
+ return acc;
176
+ const next = new Map(acc);
177
+ next.set(name, entry);
178
+ return next;
179
+ }, new Map());
180
+ //# sourceMappingURL=projection.js.map
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Rule subject module: declared/resolved/actual payloads, scanner composition,
3
+ * and projections via the shared helper.
4
+ *
5
+ * Rules have no `axm.json` entry shape and no `axm-lock.yaml` entry
6
+ * shape in v1. Actual occurrences come from the canonical-extensions
7
+ * scanner (`type === "rule"`); the agent-dir scanner emits no rule
8
+ * occurrences in the v1 `AgentRegistry`, but the subject module accepts an
9
+ * agent-dir scanner input so future agents can register rule directories
10
+ * without further changes here.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import * as Option from "effect/Option";
14
+ import type { AgentId } from "@agentxm/extension-model/unstable/agents/types";
15
+ import { type ExtensionName } from "@agentxm/extension-model/unstable/extensions/common";
16
+ import type { Lockfile, RuleLockEntry } from "../../../lockfile/schema.js";
17
+ import type { RuleEntry, Settings } from "../../../settings/schema.js";
18
+ import type { Diagnostics } from "../diagnostics.js";
19
+ import type { LockfileReadError, SettingsReadError } from "../errors.js";
20
+ import type { CanonicalExtensionOccurrence } from "../scanners/types.js";
21
+ import type { ActivationState, ExtensionKey, InstallationOrigin, InstalledPackRef, Scope } from "../types.js";
22
+ export type RuleDetectionOrigin = {
23
+ readonly _tag: "canonical-axm-rule";
24
+ } | {
25
+ readonly _tag: "external-axm-rule";
26
+ } | {
27
+ readonly _tag: "agent-rule-dir";
28
+ readonly agentId: AgentId;
29
+ };
30
+ export interface DeclaredRule {
31
+ readonly name: ExtensionName;
32
+ readonly entry: RuleEntry;
33
+ }
34
+ export type DeclaredRules = ReadonlyArray<DeclaredRule>;
35
+ export interface ResolvedRule {
36
+ readonly name: ExtensionName;
37
+ readonly lockEntry: RuleLockEntry;
38
+ }
39
+ export type ResolvedRules = ReadonlyArray<ResolvedRule>;
40
+ export interface ActualRule {
41
+ readonly key: ExtensionKey<"rule">;
42
+ readonly origin: RuleDetectionOrigin;
43
+ readonly contentRoot: string;
44
+ readonly packageRoot: string | null;
45
+ }
46
+ export type ActualRules = ReadonlyArray<ActualRule>;
47
+ export interface RulePackMember {
48
+ readonly name: ExtensionName;
49
+ readonly providingPack: InstalledPackRef;
50
+ }
51
+ export interface InstalledRule {
52
+ readonly key: ExtensionKey<"rule">;
53
+ readonly installationOrigin: InstallationOrigin<DeclaredRule, RulePackMember>;
54
+ readonly activation: ActivationState;
55
+ readonly resolved: Option.Option<ResolvedRule>;
56
+ readonly actual: ReadonlyArray<ActualRule>;
57
+ readonly providingPacks: ReadonlyArray<InstalledPackRef>;
58
+ }
59
+ export interface UnmanagedRule {
60
+ readonly key: ExtensionKey<"rule">;
61
+ readonly actual: ActualRule;
62
+ }
63
+ /**
64
+ * Rule scanners. v1 ships a canonical scanner only; the v1 `AgentRegistry`
65
+ * does not register rule directories, so there is no agent-dir rule input.
66
+ * If a future agent registers a rule directory, this scanner record gains an
67
+ * `agentDir` field and the subject module wires through `agent-rule-dir`
68
+ * origins.
69
+ */
70
+ export interface RuleScanners {
71
+ readonly canonical: Effect.Effect<ReadonlyArray<CanonicalExtensionOccurrence>>;
72
+ }
73
+ export interface RuleScopedLoaders {
74
+ readonly settings: Effect.Effect<Option.Option<Settings>, SettingsReadError>;
75
+ readonly lockfile: Effect.Effect<Option.Option<Lockfile>, LockfileReadError>;
76
+ }
77
+ export interface InstalledPackForRules {
78
+ readonly ref: InstalledPackRef;
79
+ readonly rules: ReadonlyArray<RulePackMember>;
80
+ }
81
+ export interface RuleExtensionsApiDeps {
82
+ readonly scope: Scope;
83
+ readonly loaders: RuleScopedLoaders;
84
+ readonly scanners: RuleScanners;
85
+ readonly installedPacks: Effect.Effect<ReadonlyArray<InstalledPackForRules>, SettingsReadError | LockfileReadError>;
86
+ readonly diagnostics: Diagnostics;
87
+ }
88
+ export interface RuleExtensionsApi {
89
+ readonly declared: Effect.Effect<Option.Option<DeclaredRules>, SettingsReadError>;
90
+ readonly resolved: Effect.Effect<Option.Option<ResolvedRules>, LockfileReadError>;
91
+ readonly actual: Effect.Effect<ActualRules>;
92
+ readonly installed: Effect.Effect<ReadonlyArray<InstalledRule>, SettingsReadError | LockfileReadError>;
93
+ readonly byName: (name: string) => Effect.Effect<Option.Option<InstalledRule>, SettingsReadError | LockfileReadError>;
94
+ readonly declaredByName: (name: string) => Effect.Effect<Option.Option<DeclaredRule>, SettingsReadError>;
95
+ readonly active: Effect.Effect<ReadonlyArray<InstalledRule>, SettingsReadError | LockfileReadError>;
96
+ readonly unmanaged: Effect.Effect<ReadonlyArray<UnmanagedRule>, SettingsReadError | LockfileReadError>;
97
+ }
98
+ /**
99
+ * Build the rule subject API. Returns an `Effect` because the projection
100
+ * cell is wrapped in `Effect.cached` so the four derived cells share one
101
+ * in-flight execution per scope, mirroring `state.ts`.
102
+ */
103
+ export declare const makeRuleExtensionsApi: (deps: RuleExtensionsApiDeps) => Effect.Effect<RuleExtensionsApi>;
104
+ //# sourceMappingURL=rule.d.ts.map
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Rule subject module: declared/resolved/actual payloads, scanner composition,
3
+ * and projections via the shared helper.
4
+ *
5
+ * Rules have no `axm.json` entry shape and no `axm-lock.yaml` entry
6
+ * shape in v1. Actual occurrences come from the canonical-extensions
7
+ * scanner (`type === "rule"`); the agent-dir scanner emits no rule
8
+ * occurrences in the v1 `AgentRegistry`, but the subject module accepts an
9
+ * agent-dir scanner input so future agents can register rule directories
10
+ * without further changes here.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import * as Option from "effect/Option";
14
+ import { decodeExtensionNameSync, } from "@agentxm/extension-model/unstable/extensions/common";
15
+ import { filterMapOccurrences } from "./actual-helpers.js";
16
+ import { canonicalAxmPackageRoot } from "./package-root.js";
17
+ import { makeProjectedSubjectCells, projectInstalledExtensions, } from "./projection.js";
18
+ // ---------------------------------------------------------------------------
19
+ // Helpers
20
+ // ---------------------------------------------------------------------------
21
+ const canonicalToActual = (occ, scope) => {
22
+ const isExternal = occ.origin === "external-axm";
23
+ const packageRoot = canonicalAxmPackageRoot(occ);
24
+ return {
25
+ key: { scope, type: "rule", name: occ.name },
26
+ origin: isExternal ? { _tag: "external-axm-rule" } : { _tag: "canonical-axm-rule" },
27
+ contentRoot: occ.contentLocation,
28
+ packageRoot,
29
+ };
30
+ };
31
+ const declaredFromSettings = (settings) => {
32
+ if (settings.rules === undefined)
33
+ return [];
34
+ return Object.entries(settings.rules).map(([name, entry]) => ({
35
+ name: decodeExtensionNameSync(name),
36
+ entry,
37
+ }));
38
+ };
39
+ const resolvedFromLockfile = (lockfile) => {
40
+ if (lockfile.rules === undefined)
41
+ return [];
42
+ return Object.entries(lockfile.rules).map(([name, lockEntry]) => ({
43
+ name: decodeExtensionNameSync(name),
44
+ lockEntry,
45
+ }));
46
+ };
47
+ const orphanResolvedWarning = (name) => ({
48
+ source: "lockfile",
49
+ message: `rule: lockfile entry "${name}" has no matching declared or pack-member home`,
50
+ code: "orphan-resolved",
51
+ });
52
+ const rulePolicy = (scope) => ({
53
+ declaredEntries: (d) => d,
54
+ declaredName: (entry) => entry.name,
55
+ declaredActivation: (entry) => (entry.entry.enabled === false ? "disabled" : "enabled"),
56
+ resolvedEntries: (r) => r,
57
+ resolvedName: (entry) => entry.name,
58
+ actualEntries: (a) => a,
59
+ actualName: (e) => e.key.name,
60
+ packMemberName: (m) => m.name,
61
+ packMemberActivation: () => "enabled",
62
+ attachActualToInstalled: (name, actual) => actual.filter((a) => a.key.name === name),
63
+ notClaimedBySubjectPolicy: () => true,
64
+ buildInstalledRow: (input) => ({
65
+ key: { scope, type: "rule", name: input.name },
66
+ installationOrigin: input.installationOrigin,
67
+ activation: input.activation,
68
+ resolved: input.resolved,
69
+ actual: input.actual,
70
+ providingPacks: input.providingPacks,
71
+ }),
72
+ buildUnmanagedRow: (entry) => ({
73
+ key: { scope, type: "rule", name: entry.key.name },
74
+ actual: entry,
75
+ }),
76
+ resolvedOrphanWarning: orphanResolvedWarning,
77
+ });
78
+ /**
79
+ * Build the rule subject API. Returns an `Effect` because the projection
80
+ * cell is wrapped in `Effect.cached` so the four derived cells share one
81
+ * in-flight execution per scope, mirroring `state.ts`.
82
+ */
83
+ export const makeRuleExtensionsApi = (deps) => Effect.gen(function* () {
84
+ const { scope, scanners, diagnostics } = deps;
85
+ const declared = deps.loaders.settings.pipe(Effect.map((opt) => Option.map(opt, declaredFromSettings)));
86
+ const resolved = deps.loaders.lockfile.pipe(Effect.map((opt) => Option.map(opt, resolvedFromLockfile)));
87
+ const actual = Effect.gen(function* () {
88
+ const canonical = yield* scanners.canonical;
89
+ return filterMapOccurrences(canonical, "rule", (occ) => canonicalToActual(occ, scope));
90
+ });
91
+ const project = yield* Effect.cached(projectInstalledExtensions({
92
+ declared,
93
+ resolved,
94
+ actual,
95
+ installedPacks: deps.installedPacks,
96
+ packMembers: (pack) => pack.rules,
97
+ packRef: (pack) => pack.ref,
98
+ policy: rulePolicy(scope),
99
+ diagnostics,
100
+ }));
101
+ return {
102
+ ...makeProjectedSubjectCells({
103
+ declared,
104
+ resolved,
105
+ actual,
106
+ project,
107
+ }),
108
+ declared,
109
+ resolved,
110
+ actual,
111
+ };
112
+ });
113
+ //# sourceMappingURL=rule.js.map