@agentxm/extension-lifecycle 0.28.12 → 0.28.13

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 (207) hide show
  1. package/dist/src/activation/display-paths.d.ts +25 -0
  2. package/dist/src/activation/display-paths.js +25 -0
  3. package/dist/src/activation/errors.d.ts +16 -0
  4. package/dist/src/activation/errors.js +7 -0
  5. package/dist/src/activation/set-activation.d.ts +134 -0
  6. package/dist/src/activation/set-activation.js +772 -0
  7. package/dist/src/demote/demote-to-external-source.d.ts +82 -0
  8. package/dist/src/demote/demote-to-external-source.js +233 -0
  9. package/dist/src/errors.d.ts +0 -8
  10. package/dist/src/errors.js +0 -8
  11. package/dist/src/glob.d.ts +35 -0
  12. package/dist/src/glob.js +75 -0
  13. package/dist/src/hooks/configured-agent-outcomes-provider.d.ts +7 -3
  14. package/dist/src/hooks/configured-agent-outcomes-provider.js +11 -4
  15. package/dist/src/hooks/install/plan.d.ts +45 -0
  16. package/dist/src/hooks/install/plan.js +224 -0
  17. package/dist/src/hooks/uninstall/plan.d.ts +20 -0
  18. package/dist/src/hooks/uninstall/plan.js +77 -0
  19. package/dist/src/index.d.ts +48 -16
  20. package/dist/src/index.js +60 -17
  21. package/dist/src/install/aggregate-projection-step.d.ts +16 -0
  22. package/dist/src/install/aggregate-projection-step.js +49 -0
  23. package/dist/src/install/configured.d.ts +65 -0
  24. package/dist/src/install/configured.js +406 -0
  25. package/dist/src/install/inline-mcp-operation.d.ts +4 -0
  26. package/dist/src/install/inline-mcp-operation.js +25 -0
  27. package/dist/src/install/install-extensions.d.ts +110 -0
  28. package/dist/src/install/install-extensions.js +282 -0
  29. package/dist/src/install/per-type-install.d.ts +12 -0
  30. package/dist/src/install/per-type-install.js +12 -0
  31. package/dist/src/install/registry-install-target.d.ts +35 -0
  32. package/dist/src/install/registry-install-target.js +66 -0
  33. package/dist/src/install/registry-login-suggestion.d.ts +21 -0
  34. package/dist/src/install/registry-login-suggestion.js +34 -0
  35. package/dist/src/install/registry-source-resolution.d.ts +54 -0
  36. package/dist/src/install/registry-source-resolution.js +216 -0
  37. package/dist/src/install/root-intent.d.ts +19 -0
  38. package/dist/src/install/root-intent.js +122 -0
  39. package/dist/src/install/selection-interaction.d.ts +46 -0
  40. package/dist/src/install/selection-interaction.js +22 -0
  41. package/dist/src/install/vocabulary.d.ts +143 -0
  42. package/dist/src/install/vocabulary.js +29 -0
  43. package/dist/src/knowledge/install/plan.d.ts +35 -0
  44. package/dist/src/knowledge/install/plan.js +128 -0
  45. package/dist/src/knowledge/uninstall/plan.d.ts +23 -0
  46. package/dist/src/knowledge/uninstall/plan.js +140 -0
  47. package/dist/src/live.d.ts +4 -11
  48. package/dist/src/live.js +4 -11
  49. package/dist/src/mcps/install/plan.d.ts +65 -0
  50. package/dist/src/mcps/install/plan.js +301 -0
  51. package/dist/src/mcps/operations/disable.d.ts +5 -3
  52. package/dist/src/mcps/operations/disable.js +6 -4
  53. package/dist/src/mcps/operations/enable.d.ts +5 -3
  54. package/dist/src/mcps/operations/enable.js +8 -6
  55. package/dist/src/mcps/operations/sync-outcome.d.ts +1 -1
  56. package/dist/src/mcps/operations/uninstall.d.ts +5 -3
  57. package/dist/src/mcps/operations/uninstall.js +4 -4
  58. package/dist/src/mcps/uninstall/plan.d.ts +24 -0
  59. package/dist/src/mcps/uninstall/plan.js +109 -0
  60. package/dist/src/packs/artifact.d.ts +21 -0
  61. package/dist/src/packs/artifact.js +32 -0
  62. package/dist/src/packs/constraint-gate.d.ts +30 -0
  63. package/dist/src/packs/constraint-gate.js +76 -0
  64. package/dist/src/packs/expansion.d.ts +13 -14
  65. package/dist/src/packs/expansion.js +1 -2
  66. package/dist/src/packs/graph-transition.d.ts +64 -0
  67. package/dist/src/packs/graph-transition.js +219 -0
  68. package/dist/src/packs/install/plan.d.ts +95 -0
  69. package/dist/src/packs/install/plan.js +845 -0
  70. package/dist/src/packs/member-install-step.d.ts +29 -0
  71. package/dist/src/packs/member-install-step.js +156 -0
  72. package/dist/src/packs/operations/install.d.ts +3 -3
  73. package/dist/src/packs/operations/install.js +5 -5
  74. package/dist/src/packs/promote-authored-pack.d.ts +86 -0
  75. package/dist/src/packs/promote-authored-pack.js +239 -0
  76. package/dist/src/packs/resolved-dependency.d.ts +9 -26
  77. package/dist/src/packs/resolved-dependency.js +8 -20
  78. package/dist/src/packs/uninstall/plan.d.ts +66 -0
  79. package/dist/src/packs/uninstall/plan.js +344 -0
  80. package/dist/src/packs/uninstall/readiness.d.ts +50 -0
  81. package/dist/src/packs/uninstall/readiness.js +130 -0
  82. package/dist/src/publisher-binding.d.ts +8 -40
  83. package/dist/src/publisher-binding.js +8 -46
  84. package/dist/src/rules/install/plan.d.ts +35 -0
  85. package/dist/src/rules/install/plan.js +133 -0
  86. package/dist/src/rules/uninstall/plan.d.ts +19 -0
  87. package/dist/src/rules/uninstall/plan.js +54 -0
  88. package/dist/src/skills/install/bundled.d.ts +73 -0
  89. package/dist/src/skills/install/bundled.js +244 -0
  90. package/dist/src/skills/install/plan.d.ts +72 -0
  91. package/dist/src/skills/install/plan.js +429 -0
  92. package/dist/src/skills/install/selection.d.ts +26 -0
  93. package/dist/src/skills/install/selection.js +41 -0
  94. package/dist/src/skills/install/source.d.ts +21 -0
  95. package/dist/src/skills/install/source.js +76 -0
  96. package/dist/src/skills/operations/disable.d.ts +3 -2
  97. package/dist/src/skills/operations/disable.js +7 -11
  98. package/dist/src/skills/operations/enable.d.ts +3 -2
  99. package/dist/src/skills/operations/enable.js +6 -8
  100. package/dist/src/skills/operations/install.d.ts +4 -4
  101. package/dist/src/skills/operations/install.js +13 -12
  102. package/dist/src/skills/uninstall/plan.d.ts +23 -0
  103. package/dist/src/skills/uninstall/plan.js +165 -0
  104. package/dist/src/skills/utils.js +1 -1
  105. package/dist/src/step-failure-conversion.d.ts +44 -0
  106. package/dist/src/step-failure-conversion.js +26 -0
  107. package/dist/src/step-failure.d.ts +29 -0
  108. package/dist/src/step-failure.js +130 -0
  109. package/dist/src/subagents/install/plan.d.ts +49 -0
  110. package/dist/src/subagents/install/plan.js +270 -0
  111. package/dist/src/subagents/install/selection.d.ts +26 -0
  112. package/dist/src/subagents/install/selection.js +37 -0
  113. package/dist/src/subagents/install/source.d.ts +18 -0
  114. package/dist/src/subagents/install/source.js +72 -0
  115. package/dist/src/subagents/operations/disable.d.ts +5 -3
  116. package/dist/src/subagents/operations/disable.js +5 -3
  117. package/dist/src/subagents/operations/enable.d.ts +5 -3
  118. package/dist/src/subagents/operations/enable.js +17 -12
  119. package/dist/src/subagents/uninstall/plan.d.ts +20 -0
  120. package/dist/src/subagents/uninstall/plan.js +142 -0
  121. package/dist/src/test-packages.d.ts +34 -0
  122. package/dist/src/test-packages.js +111 -0
  123. package/dist/src/test-registry.d.ts +78 -0
  124. package/dist/src/test-registry.js +223 -0
  125. package/dist/src/testing.d.ts +108 -0
  126. package/dist/src/testing.js +241 -0
  127. package/dist/src/uninstall/retention-policy.d.ts +21 -0
  128. package/dist/src/uninstall/retention-policy.js +28 -0
  129. package/dist/src/uninstall/root-intent.d.ts +17 -0
  130. package/dist/src/uninstall/root-intent.js +101 -0
  131. package/dist/src/uninstall/uninstall-extensions.d.ts +61 -0
  132. package/dist/src/uninstall/uninstall-extensions.js +127 -0
  133. package/dist/src/uninstall/vocabulary.d.ts +40 -0
  134. package/dist/src/uninstall/vocabulary.js +14 -0
  135. package/dist/src/update/atomicity.d.ts +22 -0
  136. package/dist/src/update/atomicity.js +23 -0
  137. package/dist/src/update/blockers.d.ts +31 -0
  138. package/dist/src/update/blockers.js +78 -0
  139. package/dist/src/update/configured.d.ts +78 -0
  140. package/dist/src/update/configured.js +546 -0
  141. package/dist/src/update/root-request.d.ts +39 -0
  142. package/dist/src/update/root-request.js +117 -0
  143. package/dist/src/update/selective/plan.d.ts +45 -0
  144. package/dist/src/update/selective/plan.js +61 -0
  145. package/dist/src/update/selective/requirements.d.ts +17 -0
  146. package/dist/src/update/selective/requirements.js +14 -0
  147. package/dist/src/update/selective/selection.d.ts +63 -0
  148. package/dist/src/update/selective/selection.js +85 -0
  149. package/dist/src/update/selective/skills.d.ts +55 -0
  150. package/dist/src/update/selective/skills.js +596 -0
  151. package/dist/src/update/selective/subagents.d.ts +52 -0
  152. package/dist/src/update/selective/subagents.js +331 -0
  153. package/dist/src/update/selective/use-case.d.ts +121 -0
  154. package/dist/src/update/selective/use-case.js +28 -0
  155. package/dist/src/update/selective/vocabulary.d.ts +43 -0
  156. package/dist/src/update/selective/vocabulary.js +28 -0
  157. package/dist/src/update/selector.d.ts +72 -0
  158. package/dist/src/update/selector.js +120 -0
  159. package/dist/src/update/targeted-plan.d.ts +30 -0
  160. package/dist/src/update/targeted-plan.js +113 -0
  161. package/dist/src/update/update-extensions.d.ts +164 -0
  162. package/dist/src/update/update-extensions.js +579 -0
  163. package/dist/src/workspace-paths.d.ts +31 -0
  164. package/dist/src/workspace-paths.js +46 -0
  165. package/package.json +22 -12
  166. package/dist/src/configured-entry-resolution.d.ts +0 -111
  167. package/dist/src/configured-entry-resolution.js +0 -731
  168. package/dist/src/failure-adapter.d.ts +0 -35
  169. package/dist/src/failure-adapter.js +0 -23
  170. package/dist/src/hooks/manager.d.ts +0 -15
  171. package/dist/src/hooks/manager.js +0 -769
  172. package/dist/src/internal/fs-helpers.d.ts +0 -12
  173. package/dist/src/internal/fs-helpers.js +0 -13
  174. package/dist/src/internal/integrity.d.ts +0 -13
  175. package/dist/src/internal/integrity.js +0 -17
  176. package/dist/src/knowledge/manager.d.ts +0 -11
  177. package/dist/src/knowledge/manager.js +0 -711
  178. package/dist/src/mcps/manager.d.ts +0 -16
  179. package/dist/src/mcps/manager.js +0 -247
  180. package/dist/src/mcps/operations/artifact.d.ts +0 -24
  181. package/dist/src/mcps/operations/artifact.js +0 -74
  182. package/dist/src/mcps/operations/install.d.ts +0 -78
  183. package/dist/src/mcps/operations/install.js +0 -596
  184. package/dist/src/packs/dependency-resolution.d.ts +0 -65
  185. package/dist/src/packs/dependency-resolution.js +0 -414
  186. package/dist/src/packs/manager.d.ts +0 -16
  187. package/dist/src/packs/manager.js +0 -181
  188. package/dist/src/registry-materialization.d.ts +0 -52
  189. package/dist/src/registry-materialization.js +0 -72
  190. package/dist/src/release-age-posture.d.ts +0 -23
  191. package/dist/src/release-age-posture.js +0 -15
  192. package/dist/src/resolution-timeout.d.ts +0 -5
  193. package/dist/src/resolution-timeout.js +0 -11
  194. package/dist/src/rules/manager.d.ts +0 -20
  195. package/dist/src/rules/manager.js +0 -480
  196. package/dist/src/skills/manager.d.ts +0 -18
  197. package/dist/src/skills/manager.js +0 -346
  198. package/dist/src/skills/materialization.d.ts +0 -54
  199. package/dist/src/skills/materialization.js +0 -158
  200. package/dist/src/skills/operations/source-hash.d.ts +0 -2
  201. package/dist/src/skills/operations/source-hash.js +0 -6
  202. package/dist/src/subagents/manager.d.ts +0 -18
  203. package/dist/src/subagents/manager.js +0 -722
  204. package/dist/src/workflows/install-command/workflow.d.ts +0 -56
  205. package/dist/src/workflows/install-command/workflow.js +0 -46
  206. package/dist/src/workflows/uninstall-command/workflow.d.ts +0 -42
  207. package/dist/src/workflows/uninstall-command/workflow.js +0 -29
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Uninstalling packs.
3
+ *
4
+ * Removing a pack removes every member no other origin still declares, in one
5
+ * transition: members first, while their pack-derived desired state is still
6
+ * observable, then the pack itself. A selected pack whose own manifest cannot
7
+ * be read is retired — its registration goes, its unverifiable content stays —
8
+ * and a graph incomplete for any other reason blocks instead.
9
+ *
10
+ * @experimental This API is unstable and may change without notice.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import * as FileSystem from "effect/FileSystem";
14
+ import * as Path from "effect/Path";
15
+ import { HookManager, KnowledgeManager, McpServerManager, PackManager, RuleManager, SkillManager, SubagentManager } from "@agentxm/extension-materialization";
16
+ import { type ExtensionFqnParts, type ExtensionName, type Handle } from "@agentxm/extension-model/unstable/extensions";
17
+ import { type Plan } from "@agentxm/workspace-operations";
18
+ import { type DesiredPackageAuthority, type DesiredStateGraph, type PackExtensionTarget } from "@agentxm/workspace-state";
19
+ import type { ExtensionLifecycleFailed } from "../../errors.js";
20
+ import { type InstallStepRequirements } from "../../install/vocabulary.js";
21
+ import { type PackRetirement } from "./readiness.js";
22
+ /** How the request named the pack to remove. */
23
+ export type PackUninstallSelector = {
24
+ readonly _tag: "ExactFqn";
25
+ readonly identity: ExtensionFqnParts & {
26
+ readonly type: "pack";
27
+ };
28
+ } | {
29
+ readonly _tag: "SimpleName";
30
+ readonly name: string;
31
+ };
32
+ /** One pack the removal resolved, with the desired identity it was resolved from. */
33
+ export interface ResolvedPackUninstallTarget extends PackExtensionTarget {
34
+ readonly owner: Handle;
35
+ readonly name: ExtensionName;
36
+ readonly authority: DesiredPackageAuthority;
37
+ readonly desiredIdentity: string;
38
+ }
39
+ /** The packs this removal withdraws. */
40
+ export interface PackUninstallIntent {
41
+ readonly packsToUninstall: ReadonlyArray<ResolvedPackUninstallTarget>;
42
+ }
43
+ /**
44
+ * The pack this candidate was resolved from must still be the pack in the
45
+ * graph when the transition applies; otherwise the candidate describes a
46
+ * decision that is no longer available.
47
+ */
48
+ export declare const validateResolvedPackUninstallTargets: (graph: DesiredStateGraph, targets: ReadonlyArray<ResolvedPackUninstallTarget>) => Effect.Effect<void, ExtensionLifecycleFailed>;
49
+ /**
50
+ * Preview and apply must reach one decision from unchanged inputs. A target
51
+ * whose package became readable — or unreadable — between the two phases is a
52
+ * different decision, so the candidate is stale rather than applicable.
53
+ */
54
+ export declare const validatePackRetirementFacts: (args: {
55
+ readonly planned: ReadonlyArray<PackRetirement>;
56
+ readonly observed: ReadonlyArray<PackRetirement> | undefined;
57
+ }) => Effect.Effect<void, ExtensionLifecycleFailed>;
58
+ /** Read the pack selector: an exact FQN, one name, or a glob over pack names. */
59
+ export declare const parsePackUninstallSelectors: (selector: string) => Effect.Effect<ReadonlyArray<PackUninstallSelector>, ExtensionLifecycleFailed, InstallStepRequirements>;
60
+ /** Resolve the selectors against the desired graph. */
61
+ export declare const finalizePackUninstallIntent: (selectors: ReadonlyArray<PackUninstallSelector>) => Effect.Effect<PackUninstallIntent, ExtensionLifecycleFailed, InstallStepRequirements>;
62
+ /** Everything the pack removal reads and writes through. */
63
+ export type PackUninstallRequirements = InstallStepRequirements | Path.Path | FileSystem.FileSystem | HookManager | KnowledgeManager | McpServerManager | PackManager | RuleManager | SkillManager | SubagentManager;
64
+ /** The single atomic closure a settled pack removal becomes. */
65
+ export declare const planPackUninstall: (intent: PackUninstallIntent) => Effect.Effect<Plan<InstallStepRequirements>, ExtensionLifecycleFailed, PackUninstallRequirements>;
66
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Uninstalling packs.
3
+ *
4
+ * Removing a pack removes every member no other origin still declares, in one
5
+ * transition: members first, while their pack-derived desired state is still
6
+ * observable, then the pack itself. A selected pack whose own manifest cannot
7
+ * be read is retired — its registration goes, its unverifiable content stays —
8
+ * and a graph incomplete for any other reason blocks instead.
9
+ *
10
+ * @experimental This API is unstable and may change without notice.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import * as FileSystem from "effect/FileSystem";
14
+ import * as Option from "effect/Option";
15
+ import * as Path from "effect/Path";
16
+ import { HookManager, KnowledgeManager, McpServerManager, PackManager, RuleManager, SkillManager, SubagentManager, buildUninstallOperation, toLabel, } from "@agentxm/extension-materialization";
17
+ import { parseExtensionFqnParts, } from "@agentxm/extension-model/unstable/extensions";
18
+ import { operationPresentation, } from "@agentxm/workspace-operations";
19
+ import { WorkspaceMutations, decodeDesiredExtensionIdentity, } from "@agentxm/workspace-state";
20
+ import { expandGlob } from "../../glob.js";
21
+ import { lifecycleStepFailure } from "../../step-failure.js";
22
+ import { buildAggregateProjectionStep } from "../../install/aggregate-projection-step.js";
23
+ import { installRefused } from "../../install/vocabulary.js";
24
+ import { exclusiveMemberRetentionPolicy, makeWorkspaceRetentionPolicy, } from "../../uninstall/retention-policy.js";
25
+ import { workspaceCanonicalNodePath } from "../../workspace-paths.js";
26
+ import { buildAtomicPackGraphStep, validatePackGraphPostcondition } from "../graph-transition.js";
27
+ import { PACK_UNINSTALL_GRAPH_BLOCKER_ID, planPackUninstallGraphReadiness, } from "./readiness.js";
28
+ const normalizedPackIdentity = (identity) => identity.startsWith("workspace:") ? identity.slice("workspace:".length) : identity;
29
+ const identityValidationError = (identity) => installRefused({
30
+ category: "validation",
31
+ detail: `Configured pack identity ${identity} is invalid`,
32
+ });
33
+ const readDesiredGraph = Effect.gen(function* () {
34
+ const ws = yield* WorkspaceMutations;
35
+ return yield* ws
36
+ .getDesiredStateGraph()
37
+ .pipe(Effect.mapError((cause) => installRefused({ category: "internal", detail: "Desired state could not be read", cause })));
38
+ });
39
+ /**
40
+ * The pack this candidate was resolved from must still be the pack in the
41
+ * graph when the transition applies; otherwise the candidate describes a
42
+ * decision that is no longer available.
43
+ */
44
+ export const validateResolvedPackUninstallTargets = (graph, targets) => Effect.gen(function* () {
45
+ for (const expected of targets) {
46
+ const current = graph.nodes.find((candidate) => candidate.type === "pack" && candidate.name === expected.name);
47
+ if (current === undefined) {
48
+ return yield* installRefused({
49
+ category: "conflict",
50
+ detail: `Pack ${expected.desiredIdentity} changed or was removed before uninstall`,
51
+ recover: "Inspect the current pack state, then retry the uninstall.",
52
+ cmd: `axm packs show ${expected.name}`,
53
+ });
54
+ }
55
+ const decoded = decodeDesiredExtensionIdentity(current.identity);
56
+ if (decoded === undefined || decoded.type !== "pack") {
57
+ return yield* identityValidationError(current.identity);
58
+ }
59
+ if (current.identity !== expected.desiredIdentity ||
60
+ decoded.authority !== expected.authority ||
61
+ decoded.owner !== expected.owner ||
62
+ decoded.name !== expected.name) {
63
+ return yield* installRefused({
64
+ category: "conflict",
65
+ detail: `Pack ${expected.desiredIdentity} changed or was removed before uninstall`,
66
+ recover: "Inspect the current pack state, then retry the uninstall.",
67
+ cmd: `axm packs show ${expected.name}`,
68
+ });
69
+ }
70
+ }
71
+ });
72
+ const retirementKey = (retirement) => `${retirement.pack}\u0000${retirement.reason}\u0000${retirement.manifestPath}`;
73
+ const retirementSetKey = (retirements) => [...retirements].map(retirementKey).sort().join("\u0001");
74
+ /**
75
+ * Preview and apply must reach one decision from unchanged inputs. A target
76
+ * whose package became readable — or unreadable — between the two phases is a
77
+ * different decision, so the candidate is stale rather than applicable.
78
+ */
79
+ export const validatePackRetirementFacts = (args) => {
80
+ if (args.observed !== undefined &&
81
+ retirementSetKey(args.observed) === retirementSetKey(args.planned)) {
82
+ return Effect.void;
83
+ }
84
+ const packs = [...new Set([...args.planned].map((retirement) => retirement.pack))];
85
+ return Effect.fail(installRefused({
86
+ category: "conflict",
87
+ detail: packs.length === 0
88
+ ? "The pack graph changed before uninstall"
89
+ : `Pack package readability for ${packs.join(", ")} changed before uninstall`,
90
+ recover: "Inspect the current pack state, then retry the uninstall.",
91
+ cmd: "axm packs list",
92
+ }));
93
+ };
94
+ const uninstallPresentation = operationPresentation({ imperative: "uninstall", past: "Uninstalled", gerund: "Uninstalling" }, "pack");
95
+ /** Read the pack selector: an exact FQN, one name, or a glob over pack names. */
96
+ export const parsePackUninstallSelectors = Effect.fn("UninstallExtensions.parsePackSelectors")(function* (selector) {
97
+ const requested = parseExtensionFqnParts(selector);
98
+ if (requested !== undefined && requested.type !== "pack") {
99
+ return yield* installRefused({
100
+ category: "validation",
101
+ detail: `Expected a pack identity, received ${selector}`,
102
+ });
103
+ }
104
+ if (requested !== undefined) {
105
+ return [
106
+ {
107
+ _tag: "ExactFqn",
108
+ identity: { owner: requested.owner, type: "pack", name: requested.name },
109
+ },
110
+ ];
111
+ }
112
+ if (!selector.includes("*"))
113
+ return [{ _tag: "SimpleName", name: selector }];
114
+ const graph = yield* readDesiredGraph;
115
+ const names = expandGlob(selector, graph.nodes.filter((node) => node.type === "pack").map((node) => node.name));
116
+ return names.map((name) => ({ _tag: "SimpleName", name }));
117
+ });
118
+ /** Resolve the selectors against the desired graph. */
119
+ export const finalizePackUninstallIntent = Effect.fn("UninstallExtensions.finalizePackIntent")(function* (selectors) {
120
+ const graph = yield* readDesiredGraph;
121
+ const targets = new Map();
122
+ for (const selector of selectors) {
123
+ const name = selector._tag === "ExactFqn" ? selector.identity.name : selector.name;
124
+ const candidates = graph.nodes.filter((candidate) => candidate.type === "pack" && candidate.name === name);
125
+ for (const node of candidates) {
126
+ const identity = decodeDesiredExtensionIdentity(node.identity);
127
+ if (identity === undefined || identity.type !== "pack") {
128
+ return yield* identityValidationError(node.identity);
129
+ }
130
+ if (selector._tag === "ExactFqn" && identity.owner !== selector.identity.owner)
131
+ continue;
132
+ targets.set(node.identity, {
133
+ type: "pack",
134
+ name: identity.name,
135
+ owner: identity.owner,
136
+ authority: identity.authority,
137
+ desiredIdentity: node.identity,
138
+ });
139
+ }
140
+ }
141
+ return { packsToUninstall: [...targets.values()] };
142
+ });
143
+ /** The single atomic closure a settled pack removal becomes. */
144
+ export const planPackUninstall = Effect.fn("UninstallExtensions.planPacks")(function* (intent) {
145
+ const ws = yield* WorkspaceMutations;
146
+ const path = yield* Path.Path;
147
+ const packManager = yield* PackManager;
148
+ const skillManager = yield* SkillManager;
149
+ const subagentManager = yield* SubagentManager;
150
+ const ruleManager = yield* RuleManager;
151
+ const hookManager = yield* HookManager;
152
+ const knowledgeManager = yield* KnowledgeManager;
153
+ const mcpServerManager = yield* McpServerManager;
154
+ const observedGraph = yield* readDesiredGraph;
155
+ const graphReadiness = planPackUninstallGraphReadiness(observedGraph, intent.packsToUninstall.map((pack) => pack.desiredIdentity), ws.scope);
156
+ if (graphReadiness.readiness === "blocked") {
157
+ return {
158
+ _tag: "Plan",
159
+ name: "Uninstall packs",
160
+ description: Option.some("Pack graph readiness prevents this uninstall."),
161
+ presentation: uninstallPresentation,
162
+ jobs: [
163
+ {
164
+ concurrency: 1,
165
+ steps: [
166
+ {
167
+ readiness: "error",
168
+ label: intent.packsToUninstall.map((pack) => pack.desiredIdentity).join(", ") ||
169
+ "Pack graph",
170
+ errorMessage: graphReadiness.detail,
171
+ blockingConditionIds: [PACK_UNINSTALL_GRAPH_BLOCKER_ID],
172
+ artifact: {
173
+ path: "pack graph",
174
+ scope: ws.scope,
175
+ change: "unchanged",
176
+ fileCount: 0,
177
+ targets: graphReadiness.facts.flatMap((fact) => fact.authoritativeLocations.map((location) => ({
178
+ path: location,
179
+ change: "unchanged",
180
+ }))),
181
+ },
182
+ },
183
+ ],
184
+ },
185
+ ],
186
+ riskConditions: [
187
+ {
188
+ level: "blocked",
189
+ id: PACK_UNINSTALL_GRAPH_BLOCKER_ID,
190
+ detail: graphReadiness.detail,
191
+ errorCode: "conflict",
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ if (intent.packsToUninstall.length === 0) {
197
+ return {
198
+ _tag: "Plan",
199
+ name: "Uninstall packs",
200
+ description: Option.none(),
201
+ presentation: uninstallPresentation,
202
+ jobs: [{ concurrency: 1, steps: [] }],
203
+ };
204
+ }
205
+ const graph = graphReadiness.graph;
206
+ const plannedRetirements = graphReadiness.retirements;
207
+ const retirementByIdentity = new Map(plannedRetirements.map((retirement) => [retirement.pack, retirement]));
208
+ // Only a selected pack can be retired, and members are never read from an
209
+ // unreadable manifest, so the lookup is keyed by the selected pack's name.
210
+ const retirementByPackName = new Map(intent.packsToUninstall.flatMap((pack) => {
211
+ const retirement = retirementByIdentity.get(normalizedPackIdentity(pack.desiredIdentity));
212
+ return retirement === undefined ? [] : [[pack.name, retirement]];
213
+ }));
214
+ const retentionPolicy = makeWorkspaceRetentionPolicy(ws);
215
+ const allTargets = new Map();
216
+ for (const pack of intent.packsToUninstall) {
217
+ allTargets.set(`pack:${pack.name}`, pack);
218
+ }
219
+ const removingPackIdentities = new Set(intent.packsToUninstall.map((pack) => pack.desiredIdentity));
220
+ for (const node of graph.nodes) {
221
+ if (node.type === "pack")
222
+ continue;
223
+ const removedOrigin = node.origins.some((origin) => origin.type === "pack" && removingPackIdentities.has(origin.pack));
224
+ if (!removedOrigin)
225
+ continue;
226
+ const retainedOrigin = node.origins.some((origin) => origin.type === "settings" ||
227
+ (origin.type === "pack" && !removingPackIdentities.has(origin.pack)));
228
+ if (retainedOrigin)
229
+ continue;
230
+ allTargets.set(`${node.type}:${node.name}`, { type: node.type, name: node.name });
231
+ }
232
+ // Remove members while their pack-derived desired state is still
233
+ // observable, then retire the owning pack.
234
+ const packTargets = [...allTargets.values()].filter((target) => target.type === "pack");
235
+ const depTargets = [...allTargets.values()].filter((target) => target.type !== "pack");
236
+ const orderedTargets = [...depTargets, ...packTargets];
237
+ const sourcePathByTarget = new Map(graph.nodes.map((node) => [
238
+ `${node.type}:${node.name}`,
239
+ workspaceCanonicalNodePath(path, ws, node),
240
+ ]));
241
+ const steps = orderedTargets.map((target) => {
242
+ switch (target.type) {
243
+ case "pack": {
244
+ const retirement = retirementByPackName.get(target.name);
245
+ return buildUninstallOperation(packManager, retentionPolicy, {
246
+ target,
247
+ toStepFailure: lifecycleStepFailure,
248
+ ...(retirement === undefined
249
+ ? {}
250
+ : {
251
+ retirement: {
252
+ // Results name workspace-relative paths, so the same
253
+ // retirement reads identically from any workspace.
254
+ manifestPath: path.relative(ws.baseDir, retirement.manifestPath),
255
+ reason: retirement.reason,
256
+ },
257
+ }),
258
+ });
259
+ }
260
+ case "skill":
261
+ return buildUninstallOperation(skillManager, exclusiveMemberRetentionPolicy, {
262
+ toStepFailure: lifecycleStepFailure,
263
+ target,
264
+ });
265
+ case "mcp-server":
266
+ return buildUninstallOperation(mcpServerManager, exclusiveMemberRetentionPolicy, {
267
+ toStepFailure: lifecycleStepFailure,
268
+ target,
269
+ });
270
+ case "subagent":
271
+ return buildUninstallOperation(subagentManager, exclusiveMemberRetentionPolicy, {
272
+ toStepFailure: lifecycleStepFailure,
273
+ target,
274
+ });
275
+ case "rule":
276
+ return buildUninstallOperation(ruleManager, exclusiveMemberRetentionPolicy, {
277
+ toStepFailure: lifecycleStepFailure,
278
+ target,
279
+ skipProjections: true,
280
+ });
281
+ case "hook":
282
+ return buildUninstallOperation(hookManager, exclusiveMemberRetentionPolicy, {
283
+ toStepFailure: lifecycleStepFailure,
284
+ target,
285
+ skipProjections: true,
286
+ });
287
+ case "knowledge":
288
+ return buildUninstallOperation(knowledgeManager, exclusiveMemberRetentionPolicy, {
289
+ toStepFailure: lifecycleStepFailure,
290
+ target,
291
+ skipProjections: true,
292
+ });
293
+ }
294
+ });
295
+ const projectionStep = yield* buildAggregateProjectionStep({
296
+ types: new Set(orderedTargets.map((target) => target.type)),
297
+ });
298
+ const registrationOnly = plannedRetirements.length === 0
299
+ ? ""
300
+ : ` (${plannedRetirements.length} pack${plannedRetirements.length === 1 ? "" : "s"} unregistered without removing package content)`;
301
+ const graphStep = yield* buildAtomicPackGraphStep({
302
+ label: `${intent.packsToUninstall.length} pack${intent.packsToUninstall.length === 1 ? "" : "s"}`,
303
+ message: `Uninstalled ${intent.packsToUninstall.length} pack${intent.packsToUninstall.length === 1 ? "" : "s"} and ${depTargets.length} exclusive member${depTargets.length === 1 ? "" : "s"}${registrationOnly}`,
304
+ artifact: {
305
+ path: "pack graph",
306
+ scope: ws.scope,
307
+ change: "removed",
308
+ fileCount: orderedTargets.length,
309
+ targets: orderedTargets.map((target) => ({
310
+ path: sourcePathByTarget.get(`${target.type}:${target.name}`) ?? toLabel(target),
311
+ // Content AXM could not verify is preserved, so its canonical path is
312
+ // never reported as removed.
313
+ change: target.type === "pack" && retirementByPackName.has(target.name) ? "unchanged" : "removed",
314
+ })),
315
+ },
316
+ children: [
317
+ ...steps.map((step) => ({ step, coverage: "ineligible" })),
318
+ ...Option.toArray(projectionStep).map((step) => ({
319
+ step,
320
+ coverage: "ineligible",
321
+ })),
322
+ ],
323
+ preTransition: Effect.gen(function* () {
324
+ const currentGraph = yield* readDesiredGraph;
325
+ yield* validateResolvedPackUninstallTargets(currentGraph, intent.packsToUninstall);
326
+ const currentReadiness = planPackUninstallGraphReadiness(currentGraph, intent.packsToUninstall.map((pack) => pack.desiredIdentity), ws.scope);
327
+ yield* validatePackRetirementFacts({
328
+ planned: plannedRetirements,
329
+ observed: currentReadiness.readiness === "ready" ? currentReadiness.retirements : undefined,
330
+ });
331
+ }),
332
+ validate: validatePackGraphPostcondition({ absent: orderedTargets }),
333
+ });
334
+ return {
335
+ _tag: "Plan",
336
+ name: intent.packsToUninstall.length === 1
337
+ ? "Uninstall pack"
338
+ : `Uninstall ${intent.packsToUninstall.length} packs`,
339
+ description: Option.none(),
340
+ presentation: uninstallPresentation,
341
+ jobs: [{ concurrency: 1, steps: [graphStep] }],
342
+ };
343
+ });
344
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1,50 @@
1
+ import type { DesiredStateGraph, DesiredStateProblem } from "@agentxm/workspace-state";
2
+ import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
3
+ /** Recovery-conformance identity for Pack uninstall planning on an incomplete graph. */
4
+ export declare const PACK_UNINSTALL_GRAPH_BLOCKER_ID: "packs/uninstall/desired-state-graph-complete";
5
+ /** Executable Pack-uninstall blocker identities covered by recovery conformance. */
6
+ export declare const packUninstallRecoveryIdentifiers: readonly ["packs/uninstall/desired-state-graph-complete"];
7
+ export interface PackUninstallGraphBlockerFact {
8
+ readonly problemType: DesiredStateProblem["type"] | "unknown";
9
+ readonly packs: ReadonlyArray<string>;
10
+ readonly member?: {
11
+ readonly type: string;
12
+ readonly name: string;
13
+ };
14
+ readonly authoritativeLocations: ReadonlyArray<string>;
15
+ readonly detail: string;
16
+ }
17
+ /** Why a selected Pack's own package could not be read. */
18
+ export type PackRetirementReason = "missing" | "invalid";
19
+ /**
20
+ * A selected Pack whose own package manifest is unreadable. Its registration is
21
+ * removable from positive evidence about the Pack itself; its content is not,
22
+ * because nothing about that content can be verified.
23
+ */
24
+ export interface PackRetirement {
25
+ readonly pack: string;
26
+ readonly manifestPath: string;
27
+ readonly reason: PackRetirementReason;
28
+ }
29
+ export type PackUninstallGraphReadiness = {
30
+ readonly readiness: "ready";
31
+ readonly graph: DesiredStateGraph;
32
+ readonly retirements: ReadonlyArray<PackRetirement>;
33
+ } | {
34
+ readonly readiness: "blocked";
35
+ readonly id: typeof PACK_UNINSTALL_GRAPH_BLOCKER_ID;
36
+ readonly facts: ReadonlyArray<PackUninstallGraphBlockerFact>;
37
+ readonly detail: string;
38
+ };
39
+ /**
40
+ * Build the Pack-uninstall readiness decision from the shared desired-state
41
+ * planner.
42
+ *
43
+ * The graph gate exists to stop a Pack transition computed from state AXM
44
+ * cannot read. A selected Pack whose own manifest is confirmed missing or
45
+ * undecodable is positive evidence about the removal target, not the absent
46
+ * evidence the gate guards against, so uninstall proceeds and removes only that
47
+ * Pack's registration. Incompleteness the target did not cause still blocks.
48
+ */
49
+ export declare const planPackUninstallGraphReadiness: (graph: DesiredStateGraph, selectedPacks: ReadonlyArray<string>, scope: WorkspaceScope) => PackUninstallGraphReadiness;
50
+ //# sourceMappingURL=readiness.d.ts.map
@@ -0,0 +1,130 @@
1
+ import { planDesiredStateGraph } from "@agentxm/workspace-projection";
2
+ import { workspaceCanonicalRoot, workspaceLockfilePath, workspaceSettingsPath, } from "../../workspace-paths.js";
3
+ /** Recovery-conformance identity for Pack uninstall planning on an incomplete graph. */
4
+ export const PACK_UNINSTALL_GRAPH_BLOCKER_ID = "packs/uninstall/desired-state-graph-complete";
5
+ /** Executable Pack-uninstall blocker identities covered by recovery conformance. */
6
+ export const packUninstallRecoveryIdentifiers = [PACK_UNINSTALL_GRAPH_BLOCKER_ID];
7
+ const normalizedPack = (identity) => identity.startsWith("workspace:") ? identity.slice("workspace:".length) : identity;
8
+ /**
9
+ * Problems the lock pass emits for a Pack as a consequence of its unreadable
10
+ * manifest. They add no information the gate does not already have from the
11
+ * primary problem, so they never block on their own account.
12
+ */
13
+ const isCompanionProblem = (problem) => problem.type === "pack-manifest-content-mismatch" ||
14
+ problem.type === "pack-resolution-unavailable";
15
+ /**
16
+ * Classify the selected Packs' own problems into retirements, or report that
17
+ * some selected Pack disagrees with the workspace in a way absence cannot
18
+ * explain. Readable-but-disagreeing state is drift, and stays blocked.
19
+ */
20
+ const retirementsFor = (problems) => {
21
+ const problemsByPack = new Map();
22
+ for (const problem of problems) {
23
+ if (!("pack" in problem))
24
+ return undefined;
25
+ const pack = normalizedPack(problem.pack);
26
+ const existing = problemsByPack.get(pack);
27
+ if (existing === undefined)
28
+ problemsByPack.set(pack, [problem]);
29
+ else
30
+ existing.push(problem);
31
+ }
32
+ const retirements = [];
33
+ for (const [pack, packProblems] of problemsByPack) {
34
+ let unreadable;
35
+ for (const problem of packProblems) {
36
+ if (problem.type === "pack-manifest-unavailable") {
37
+ unreadable ??= { manifestPath: problem.path, reason: "missing" };
38
+ continue;
39
+ }
40
+ if (problem.type === "pack-manifest-invalid") {
41
+ unreadable ??= { manifestPath: problem.path, reason: "invalid" };
42
+ continue;
43
+ }
44
+ if (isCompanionProblem(problem))
45
+ continue;
46
+ return undefined;
47
+ }
48
+ if (unreadable === undefined)
49
+ return undefined;
50
+ retirements.push({ pack, ...unreadable });
51
+ }
52
+ return retirements;
53
+ };
54
+ const locationsFor = (problem, scope) => {
55
+ if ("path" in problem && problem.path !== undefined)
56
+ return [problem.path];
57
+ if ("pack" in problem)
58
+ return [workspaceSettingsPath(scope), workspaceLockfilePath(scope)];
59
+ return [workspaceSettingsPath(scope), `${workspaceCanonicalRoot(scope)}/*/packs/*/pack.json`];
60
+ };
61
+ const factFor = (problem, selectedPacks, scope) => {
62
+ const packs = "pack" in problem ? [normalizedPack(problem.pack)] : selectedPacks.map(normalizedPack);
63
+ const authoritativeLocations = locationsFor(problem, scope);
64
+ const member = "extensionType" in problem ? { type: problem.extensionType, name: problem.name } : undefined;
65
+ const subject = member === undefined ? `Pack ${packs.join(", ")}` : `${member.type} member ${member.name}`;
66
+ const problemDetail = "detail" in problem
67
+ ? problem.detail
68
+ : "constraints" in problem
69
+ ? `constraints ${problem.constraints.join(", ")}`
70
+ : "identities" in problem
71
+ ? `identities ${problem.identities.join(", ")}`
72
+ : problem.type;
73
+ return {
74
+ problemType: problem.type,
75
+ packs,
76
+ ...(member === undefined ? {} : { member }),
77
+ authoritativeLocations,
78
+ detail: `${subject}: ${problem.type} (${problemDetail}); authoritative location${authoritativeLocations.length === 1 ? "" : "s"}: ${authoritativeLocations.join(", ")}`,
79
+ };
80
+ };
81
+ /**
82
+ * Build the Pack-uninstall readiness decision from the shared desired-state
83
+ * planner.
84
+ *
85
+ * The graph gate exists to stop a Pack transition computed from state AXM
86
+ * cannot read. A selected Pack whose own manifest is confirmed missing or
87
+ * undecodable is positive evidence about the removal target, not the absent
88
+ * evidence the gate guards against, so uninstall proceeds and removes only that
89
+ * Pack's registration. Incompleteness the target did not cause still blocks.
90
+ */
91
+ export const planPackUninstallGraphReadiness = (graph, selectedPacks, scope) => {
92
+ const decision = planDesiredStateGraph(graph);
93
+ if (decision.readiness === "ready")
94
+ return { ...decision, retirements: [] };
95
+ const selected = new Set(selectedPacks.map(normalizedPack));
96
+ const foreign = [];
97
+ const own = [];
98
+ for (const problem of decision.problems) {
99
+ if ("pack" in problem && selected.has(normalizedPack(problem.pack)))
100
+ own.push(problem);
101
+ else
102
+ foreign.push(problem);
103
+ }
104
+ if (foreign.length === 0 && own.length > 0) {
105
+ const retirements = retirementsFor(own);
106
+ if (retirements !== undefined)
107
+ return { readiness: "ready", graph, retirements };
108
+ }
109
+ const facts = decision.problems.length === 0
110
+ ? [
111
+ {
112
+ problemType: "unknown",
113
+ packs: selectedPacks.map(normalizedPack),
114
+ authoritativeLocations: [workspaceSettingsPath(scope), workspaceLockfilePath(scope)],
115
+ detail: `Pack ${selectedPacks.map(normalizedPack).join(", ")}: desired-state graph is incomplete; authoritative locations: ${workspaceSettingsPath(scope)}, ${workspaceLockfilePath(scope)}`,
116
+ },
117
+ ]
118
+ : decision.problems.map((problem) => factFor(problem, selectedPacks, scope));
119
+ const foreignPacks = [
120
+ ...new Set(foreign.flatMap((problem) => ("pack" in problem ? [normalizedPack(problem.pack)] : []))),
121
+ ];
122
+ const remedy = foreignPacks.length === 0 ? "" : `; restore or uninstall ${foreignPacks.join(", ")} first`;
123
+ return {
124
+ readiness: "blocked",
125
+ id: PACK_UNINSTALL_GRAPH_BLOCKER_ID,
126
+ facts,
127
+ detail: `Cannot uninstall Pack graph because desired state is incomplete: ${facts.map((fact) => fact.detail).join("; ")}${remedy}`,
128
+ };
129
+ };
130
+ //# sourceMappingURL=readiness.js.map
@@ -1,53 +1,21 @@
1
1
  /**
2
- * Publisher binding trust classification.
2
+ * Publisher-change plan shaping.
3
3
  *
4
- * A Registry resolution binds a publisher identity. When an operation
5
- * proposes to replace an already accepted binding for the same configured
6
- * extension with a different one, that transition is a trust decision a
7
- * person makes at a prompt: no flag and no unattended mode can approve it.
8
- * Every route that can replace an accepted binding — root and type update
9
- * forms, reinstall and re-resolution, and pack closures — classifies the
10
- * transition from the structured accepted and proposed identities here, so
11
- * the same rule holds everywhere the transition can occur.
12
- *
13
- * A first acceptance is not a change, and an integrity mismatch while
14
- * reacquiring the same accepted identity remains a hard failure elsewhere.
4
+ * `@agentxm/extension-resolution` classifies whether a proposed Registry
5
+ * acceptance replaces an accepted publisher binding. This module turns that
6
+ * classification into plan vocabulary: the per-step warning, the
7
+ * interactive-only risk condition, and the blocking condition raised when an
8
+ * accepted resolution cannot be read at all.
15
9
  *
16
10
  * @experimental This API is unstable and may change without notice.
17
11
  */
18
12
  import * as Effect from "effect/Effect";
19
13
  import type * as FileSystem from "effect/FileSystem";
20
- import * as Option from "effect/Option";
21
14
  import type * as Path from "effect/Path";
22
- import type { ExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/extension-ref";
23
- import type { ExtensionType } from "@agentxm/extension-model/unstable/extensions";
24
- import type { Plan, PlanRiskCondition, RegistryBindingProposal } from "@agentxm/workspace-operations";
15
+ import { type PublisherBindingTransition } from "@agentxm/extension-resolution";
16
+ import type { Plan, PlanRiskCondition } from "@agentxm/workspace-operations";
25
17
  import { WorkspaceMutations } from "@agentxm/workspace-state";
26
- export interface PublisherBindingTransition {
27
- readonly extensionType: ExtensionType;
28
- /** The configured (local) name whose accepted resolution changes publisher. */
29
- readonly target: string;
30
- readonly owner: string;
31
- readonly packageName: string;
32
- /** The accepted publisher binding being replaced. */
33
- readonly accepted: string;
34
- /** The publisher binding the operation proposes to accept. */
35
- readonly proposed: string;
36
- }
37
18
  export declare const PUBLISHER_CHANGE_CONDITION_ID = "publisher-ownership-change";
38
- /** The structured proposal an extension ref makes, when it is a Registry ref. */
39
- export declare const registryBindingProposal: (ref: ExtensionRef) => RegistryBindingProposal | undefined;
40
- /**
41
- * Classify one proposed acceptance against the accepted resolution for the
42
- * same configured target. Only a Registry binding replacing a different
43
- * Registry binding is a publisher change.
44
- */
45
- export declare const classifyPublisherBindingTransition: (args: {
46
- readonly accepted: Option.Option<ExtensionRef>;
47
- readonly proposed: RegistryBindingProposal;
48
- }) => Option.Option<PublisherBindingTransition>;
49
- /** The warning a step carries when its acceptance changes publisher. */
50
- export declare const publisherTransitionWarning: (transition: PublisherBindingTransition) => string;
51
19
  /**
52
20
  * The interactive-only condition a plan carries when any of its steps
53
21
  * replaces an accepted publisher binding.