@agentxm/extension-lifecycle 0.28.11 → 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,596 @@
1
+ /**
2
+ * Advancing the skills a workspace selected.
3
+ *
4
+ * `skills update` re-resolves each selected, enabled skill against the source
5
+ * the workspace declared, then advances the ones whose resolution differs
6
+ * from what was accepted. Two constraints govern the version it lands on: the
7
+ * range the workspace itself recorded, and the ranges every Pack that owns
8
+ * the skill declares. Precedence, not intersection, decides between them —
9
+ * `@agentxm/extension-resolution`'s constraint precedence owns that rule, and
10
+ * this module supplies it the visible version list and carries its warnings
11
+ * onto the plan. A skill that cannot be re-resolved is reported as a skipped
12
+ * unit rather than failing the sweep, so one unreachable source does not stop
13
+ * every other advance.
14
+ *
15
+ * @experimental This API is unstable and may change without notice.
16
+ */
17
+ import * as Array from "effect/Array";
18
+ import * as DateTime from "effect/DateTime";
19
+ import * as Effect from "effect/Effect";
20
+ import * as Option from "effect/Option";
21
+ import { decodeExtensionNameSync, parseSourceQualifiedRegistrySourcePatternParts, } from "@agentxm/extension-model/unstable/extensions";
22
+ import { isWorkspaceSourceLocator } from "@agentxm/extension-model/unstable/sources/workspace";
23
+ import { classifyPublisherBindingTransition, detectHoldbackWarnings, isVersionEntryEligibleAt, makeConfiguredReleaseAgeEvaluation, normalizeReleaseAgeRecords, publisherTransitionWarning, registryBindingProposal, releaseAgeEvidence, releaseAgeHoldbackWarning, resolveConstrainedVersion, } from "@agentxm/extension-resolution";
24
+ import { resolveSource, SourceHostProviders } from "@agentxm/extension-sources";
25
+ import { createRegistryClient } from "@agentxm/registry-client";
26
+ import { operationPresentation, prepareExecutionCandidate, } from "@agentxm/workspace-operations";
27
+ import { acceptedResolutionRef, configuredRowsByName, WorkspaceMutations, } from "@agentxm/workspace-state";
28
+ import { ExtensionLifecycleFailed } from "../../errors.js";
29
+ import { withPublisherTrustConditions } from "../../publisher-binding.js";
30
+ import { installSkill } from "../../skills/operations/install.js";
31
+ import { buildSelectiveUpdatePlan } from "./plan.js";
32
+ import { selectUpdateTargets, } from "./selection.js";
33
+ import { ignoreVersionConstraintsCondition, selectiveUpdatePlanName, } from "./vocabulary.js";
34
+ const PLAN_NAME = selectiveUpdatePlanName("skill");
35
+ const PLAN_DESCRIPTION = "Update installed skills";
36
+ const NOTHING_INSTALLED = "No skills installed.";
37
+ /** The grammar a configured skill name must satisfy, said as recovery. */
38
+ const SKILL_NAME_RULES = "Use lowercase letters, numbers, and hyphens; up to 64 characters";
39
+ /**
40
+ * Every selected entry failed to re-resolve. That is a source-reachability
41
+ * problem, not a per-entry skip: nothing can be advanced and nothing can be
42
+ * reported as unchanged.
43
+ */
44
+ const allSkillResolutionsFailed = new ExtensionLifecycleFailed({
45
+ category: "network",
46
+ detail: "All matched skill source re-resolutions failed.",
47
+ recover: "Review the registries declared under `sources` in workspace settings",
48
+ cmd: "axm help settings",
49
+ });
50
+ /**
51
+ * The install operation reports more than the plan vocabulary carries. Only
52
+ * the outcome and its sentence cross into the step result; a failed step
53
+ * carries the typed failure the boundary renders.
54
+ */
55
+ const toJobStepResult = (result) => result.result === "error" && result.error !== undefined
56
+ ? { result: "error", message: result.message, error: result.error }
57
+ : { result: "success", message: result.message };
58
+ const skippedSkillStep = (outcome) => ({
59
+ readiness: "ready",
60
+ label: `Skip ${outcome.name}`,
61
+ run: Effect.succeed({
62
+ result: "success",
63
+ disposition: "skipped",
64
+ message: outcome.reason,
65
+ }),
66
+ });
67
+ const warningMessage = (warnings) => warnings.length === 0 ? undefined : warnings.join("; ");
68
+ const appendWarningsToResult = (warnings) => (result) => {
69
+ const message = warningMessage(warnings);
70
+ if (message === undefined || result.result === "error")
71
+ return result;
72
+ return {
73
+ ...result,
74
+ message: result.message.length === 0 ? message : `${result.message}; ${message}`,
75
+ };
76
+ };
77
+ const toRegistrySkillPattern = (source) => {
78
+ const parsed = parseSourceQualifiedRegistrySourcePatternParts(source);
79
+ if (parsed === undefined)
80
+ return Option.none();
81
+ if (parsed.type !== undefined && parsed.type !== "skills")
82
+ return Option.none();
83
+ return Option.some(parsed);
84
+ };
85
+ /**
86
+ * Per-skill constraints declared by the authoritative desired Pack graph. An
87
+ * incomplete graph is refused rather than guessed at: a missing Pack member
88
+ * would silently drop the constraint it declares.
89
+ */
90
+ const collectPackConstraints = Effect.fn("SelectiveSkillUpdate.packConstraints")(function* () {
91
+ const ws = yield* WorkspaceMutations;
92
+ const graph = yield* ws.getDesiredStateGraph();
93
+ if (!graph.complete) {
94
+ return yield* new ExtensionLifecycleFailed({
95
+ category: "validation",
96
+ detail: "Cannot update skills while the desired pack graph is incomplete",
97
+ });
98
+ }
99
+ const constraintMap = new Map();
100
+ for (const node of graph.nodes) {
101
+ if (node.type !== "skill")
102
+ continue;
103
+ for (const origin of node.origins) {
104
+ if (origin.type !== "pack" || origin.constraint === "*" || origin.constraint === "")
105
+ continue;
106
+ const existing = constraintMap.get(node.identity) ?? [];
107
+ existing.push({ packName: origin.pack, constraint: origin.constraint });
108
+ constraintMap.set(node.identity, existing);
109
+ }
110
+ }
111
+ return constraintMap;
112
+ });
113
+ /** Settle a `skills update` request: decide everything, write nothing. */
114
+ export const prepareSelectiveSkillUpdate = Effect.fn("SelectiveSkillUpdate.prepare")(function* (request) {
115
+ const ws = yield* WorkspaceMutations;
116
+ const sources = yield* SourceHostProviders;
117
+ const minimumReleaseAgeText = yield* ws.getMinimumReleaseAge();
118
+ const releaseAgeEvaluation = yield* makeConfiguredReleaseAgeEvaluation();
119
+ const allSkills = yield* ws.records.rows("skill").pipe(Effect.map(configuredRowsByName));
120
+ const lockedSkills = yield* ws
121
+ .getLockedSkills()
122
+ .pipe(Effect.catch(() => Effect.succeed({})));
123
+ const disabledSkillEntries = Object.entries(allSkills).flatMap(([name, entry]) => entry.enabled === false && entry.source !== undefined
124
+ ? [
125
+ {
126
+ type: "skip",
127
+ name,
128
+ source: entry.source,
129
+ reason: `Skipping ${name}: disabled`,
130
+ },
131
+ ]
132
+ : []);
133
+ const skillEntries = Object.entries(allSkills).flatMap(([name, entry]) => (entry.enabled && entry.source !== undefined ? [[name, entry.source]] : []));
134
+ if (skillEntries.length === 0) {
135
+ return {
136
+ outcome: "nothing",
137
+ reason: "none-installed",
138
+ message: NOTHING_INSTALLED,
139
+ subjectType: "skill",
140
+ planName: PLAN_NAME,
141
+ planDescription: PLAN_DESCRIPTION,
142
+ };
143
+ }
144
+ const selection = yield* selectUpdateTargets({
145
+ entries: skillEntries,
146
+ source: request.source,
147
+ nameFilters: request.nameFilters,
148
+ nameFilterFlag: request.nameFilterFlag,
149
+ resourceType: "skill",
150
+ resourceLabel: "skill",
151
+ resourceLabelPlural: "skills",
152
+ });
153
+ if (selection.kind === "nothing") {
154
+ return {
155
+ outcome: "nothing",
156
+ reason: selection.reason,
157
+ message: selection.message,
158
+ subjectType: "skill",
159
+ planName: PLAN_NAME,
160
+ planDescription: PLAN_DESCRIPTION,
161
+ };
162
+ }
163
+ const filteredEntries = selection.entries;
164
+ const packConstraintMap = yield* collectPackConstraints();
165
+ const findSkillRefs = (source, options) => sources
166
+ .find(source, {
167
+ names: options.skillNames,
168
+ type: "skill",
169
+ owner: options.owner,
170
+ versionRange: options.versionRange,
171
+ ...(options.minimumReleaseAge === undefined
172
+ ? {}
173
+ : { minimumReleaseAge: options.minimumReleaseAge }),
174
+ })
175
+ .pipe(Effect.map((refs) => Array.filter(refs, (ref) => ref.type === "skill")));
176
+ const resolveRegistrySkillWithConstraints = ({ source, owner, lookupName, userConstraint, packConstraints, evaluation, }) => Effect.gen(function* () {
177
+ const skillFqn = `${owner}/skills/${lookupName}`;
178
+ if (skillFqn === "@agentxm/skills/axm" && packConstraints.length === 0) {
179
+ const compatible = yield* sources.resolveNamedRegistry(source, {
180
+ owner,
181
+ type: "skill",
182
+ name: lookupName,
183
+ versionRange: userConstraint,
184
+ releaseAgeEvaluation: evaluation,
185
+ });
186
+ if (compatible.kind === "not_found") {
187
+ return yield* new ExtensionLifecycleFailed({
188
+ category: "not_found",
189
+ detail: `No compatible Registry release of "${skillFqn}" is available`,
190
+ recover: "Recover with the bundled AXM skill",
191
+ cmd: "axm skills install @agentxm/skills/axm --bundled",
192
+ });
193
+ }
194
+ if (compatible.kind === "version_unsatisfied") {
195
+ return yield* new ExtensionLifecycleFailed({
196
+ category: "conflict",
197
+ detail: `No visible release of "${skillFqn}" satisfies ${compatible.requestedRange}`,
198
+ });
199
+ }
200
+ if (compatible.kind === "policy_held") {
201
+ return Option.some({
202
+ kind: "policy_held",
203
+ record: {
204
+ reason: "minimum-release-age",
205
+ target: skillFqn,
206
+ dependencyPath: [skillFqn],
207
+ ...(Option.isSome(userConstraint) ? { requestedRange: userConstraint.value } : {}),
208
+ candidateVersion: compatible.candidate.version,
209
+ publishedAt: compatible.candidate.publishedAt,
210
+ eligibleAt: compatible.candidate.eligibleAt,
211
+ minimumReleaseAgeSeconds: compatible.candidate.minimumReleaseAgeSeconds,
212
+ },
213
+ });
214
+ }
215
+ if (compatible.ref.type !== "skill") {
216
+ return yield* new ExtensionLifecycleFailed({
217
+ category: "internal",
218
+ detail: `Registry resolved "${skillFqn}" as a non-skill extension`,
219
+ });
220
+ }
221
+ const holdbacks = compatible.kind === "exempted" || compatible.newerHeld === undefined
222
+ ? []
223
+ : [
224
+ {
225
+ reason: "minimum-release-age",
226
+ target: skillFqn,
227
+ dependencyPath: [skillFqn],
228
+ ...(Option.isSome(userConstraint)
229
+ ? { requestedRange: userConstraint.value }
230
+ : {}),
231
+ selectedVersion: compatible.ref.version,
232
+ candidateVersion: compatible.newerHeld.version,
233
+ publishedAt: compatible.newerHeld.publishedAt,
234
+ eligibleAt: compatible.newerHeld.eligibleAt,
235
+ minimumReleaseAgeSeconds: compatible.newerHeld.minimumReleaseAgeSeconds,
236
+ },
237
+ ];
238
+ const bypasses = compatible.kind === "selected"
239
+ ? []
240
+ : [
241
+ {
242
+ reason: "minimum-release-age",
243
+ target: skillFqn,
244
+ dependencyPath: [skillFqn],
245
+ ...(Option.isSome(userConstraint)
246
+ ? { requestedRange: userConstraint.value }
247
+ : {}),
248
+ selectedVersion: compatible.ref.version,
249
+ candidateVersion: compatible.bypassed.version,
250
+ publishedAt: compatible.bypassed.publishedAt,
251
+ eligibleAt: compatible.bypassed.eligibleAt,
252
+ minimumReleaseAgeSeconds: compatible.bypassed.minimumReleaseAgeSeconds,
253
+ ...compatible.exemption,
254
+ },
255
+ ];
256
+ return Option.some({
257
+ kind: "selected",
258
+ ref: compatible.ref,
259
+ versionRange: userConstraint,
260
+ holdbacks,
261
+ bypasses,
262
+ warnings: compatible.kind === "exempted" || compatible.newerHeld === undefined
263
+ ? []
264
+ : [
265
+ releaseAgeHoldbackWarning({
266
+ fqn: skillFqn,
267
+ selectedVersion: compatible.ref.version,
268
+ heldVersion: compatible.newerHeld.version,
269
+ minimumReleaseAge: minimumReleaseAgeText,
270
+ }),
271
+ ],
272
+ });
273
+ }
274
+ const location = source.location.protocol === "file:" ? source.location.pathname : source.location.href;
275
+ const client = yield* createRegistryClient(location);
276
+ const indexOption = yield* client.getExtensionIndex({
277
+ owner,
278
+ type: "skill",
279
+ name: lookupName,
280
+ });
281
+ if (Option.isNone(indexOption)) {
282
+ return Option.none();
283
+ }
284
+ const constraints = { userConstraint, packConstraints };
285
+ const [latestEntry] = indexOption.value.versions;
286
+ const latestVersion = latestEntry?.version;
287
+ if (latestVersion === undefined) {
288
+ return yield* new ExtensionLifecycleFailed({
289
+ category: "conflict",
290
+ detail: `Registry skill "${skillFqn}" has no published versions`,
291
+ recover: "Publish a skill version first.",
292
+ cmd: "axm skills publish",
293
+ });
294
+ }
295
+ const desiredVersion = resolveConstrainedVersion(indexOption.value.versions.map((entry) => entry.version), constraints, skillFqn);
296
+ if (Option.isNone(desiredVersion)) {
297
+ const constraintLabel = Option.match(userConstraint, {
298
+ onNone: () => "the configured constraints",
299
+ onSome: (constraint) => `"${constraint}"`,
300
+ });
301
+ return yield* new ExtensionLifecycleFailed({
302
+ category: "internal",
303
+ detail: `No published version of "${skillFqn}" satisfies ${constraintLabel}`,
304
+ recover: "Relax the version constraint or update the dependent pack constraints",
305
+ });
306
+ }
307
+ const desiredEntry = indexOption.value.versions.find((entry) => entry.version === desiredVersion.value.resolvedVersion);
308
+ if (desiredEntry === undefined) {
309
+ return yield* new ExtensionLifecycleFailed({
310
+ category: "internal",
311
+ detail: `Resolved version "${desiredVersion.value.resolvedVersion}" for "${skillFqn}" is missing from its Registry index`,
312
+ });
313
+ }
314
+ const matureVersions = indexOption.value.versions
315
+ .filter((entry) => isVersionEntryEligibleAt(entry, evaluation))
316
+ .map((entry) => entry.version);
317
+ const resolvedVersion = resolveConstrainedVersion(matureVersions, constraints, skillFqn);
318
+ if (Option.isNone(resolvedVersion)) {
319
+ const evidence = releaseAgeEvidence(desiredEntry, evaluation);
320
+ return Option.some({
321
+ kind: "policy_held",
322
+ record: {
323
+ reason: "minimum-release-age",
324
+ target: skillFqn,
325
+ dependencyPath: [skillFqn],
326
+ ...(Option.isSome(userConstraint) ? { requestedRange: userConstraint.value } : {}),
327
+ candidateVersion: evidence.version,
328
+ publishedAt: evidence.publishedAt,
329
+ eligibleAt: evidence.eligibleAt,
330
+ minimumReleaseAgeSeconds: evidence.minimumReleaseAgeSeconds,
331
+ },
332
+ });
333
+ }
334
+ const exactRefs = yield* findSkillRefs(source, {
335
+ skillNames: [lookupName],
336
+ owner: Option.some(owner),
337
+ versionRange: Option.some(resolvedVersion.value.resolvedVersion),
338
+ minimumReleaseAge: Option.some(evaluation.minimumReleaseAge),
339
+ });
340
+ const exactRef = exactRefs.find((ref) => ref.refType === "registry" &&
341
+ ref.skill.name === lookupName &&
342
+ ref.version === resolvedVersion.value.resolvedVersion);
343
+ if (exactRef === undefined) {
344
+ return yield* new ExtensionLifecycleFailed({
345
+ category: "internal",
346
+ detail: `Resolved version "${resolvedVersion.value.resolvedVersion}" for "${skillFqn}" could not be rediscovered`,
347
+ recover: "Re-fetch the skill source.",
348
+ cmd: "axm skills install --reinstall <source>",
349
+ });
350
+ }
351
+ const newerHeld = desiredEntry.version === resolvedVersion.value.resolvedVersion ||
352
+ isVersionEntryEligibleAt(desiredEntry, evaluation)
353
+ ? []
354
+ : (() => {
355
+ const evidence = releaseAgeEvidence(desiredEntry, evaluation);
356
+ return [
357
+ {
358
+ reason: "minimum-release-age",
359
+ target: skillFqn,
360
+ dependencyPath: [skillFqn],
361
+ ...(Option.isSome(userConstraint)
362
+ ? { requestedRange: userConstraint.value }
363
+ : {}),
364
+ selectedVersion: resolvedVersion.value.resolvedVersion,
365
+ candidateVersion: evidence.version,
366
+ publishedAt: evidence.publishedAt,
367
+ eligibleAt: evidence.eligibleAt,
368
+ minimumReleaseAgeSeconds: evidence.minimumReleaseAgeSeconds,
369
+ },
370
+ ];
371
+ })();
372
+ return Option.some({
373
+ kind: "selected",
374
+ ref: exactRef,
375
+ versionRange: userConstraint,
376
+ holdbacks: newerHeld,
377
+ warnings: [
378
+ ...(newerHeld.length === 0
379
+ ? []
380
+ : [
381
+ releaseAgeHoldbackWarning({
382
+ fqn: skillFqn,
383
+ selectedVersion: resolvedVersion.value.resolvedVersion,
384
+ heldVersion: desiredEntry.version,
385
+ minimumReleaseAge: minimumReleaseAgeText,
386
+ }),
387
+ ]),
388
+ ...resolvedVersion.value.warnings,
389
+ ...detectHoldbackWarnings(latestVersion, resolvedVersion.value.resolvedVersion, constraints, skillFqn),
390
+ ],
391
+ });
392
+ });
393
+ const decodeConfiguredSkillName = (name) => Effect.try({
394
+ try: () => decodeExtensionNameSync(name),
395
+ catch: () => new ExtensionLifecycleFailed({
396
+ category: "validation",
397
+ detail: `Configured skill name "${name}" is invalid`,
398
+ recover: SKILL_NAME_RULES,
399
+ }),
400
+ });
401
+ const results = yield* Effect.forEach(filteredEntries, ([name, sourceStr]) => {
402
+ const configuredRegistryPattern = toRegistrySkillPattern(sourceStr);
403
+ const isOfficialAxmSource = Option.exists(configuredRegistryPattern, (pattern) => pattern.owner === "@agentxm" && pattern.name === "axm");
404
+ return Effect.gen(function* () {
405
+ if (isWorkspaceSourceLocator(sourceStr)) {
406
+ return {
407
+ type: "skip",
408
+ name,
409
+ source: sourceStr,
410
+ reason: `Skill "${name}" is workspace-sourced and unchanged`,
411
+ };
412
+ }
413
+ const source = yield* resolveSource(sourceStr);
414
+ const registryPattern = toRegistrySkillPattern(sourceStr);
415
+ if (source.type === "registry" && Option.isSome(registryPattern)) {
416
+ const lookupName = registryPattern.value.name ?? (yield* decodeConfiguredSkillName(name));
417
+ const registryResolved = yield* resolveRegistrySkillWithConstraints({
418
+ source,
419
+ owner: registryPattern.value.owner,
420
+ lookupName,
421
+ userConstraint: registryPattern.value.versionRange === undefined
422
+ ? Option.none()
423
+ : Option.some(registryPattern.value.versionRange),
424
+ packConstraints: packConstraintMap.get(`${registryPattern.value.owner}/skills/${lookupName}`) ?? [],
425
+ evaluation: releaseAgeEvaluation,
426
+ });
427
+ if (Option.isSome(registryResolved)) {
428
+ if (registryResolved.value.kind === "policy_held") {
429
+ return {
430
+ type: "skip",
431
+ name,
432
+ source: sourceStr,
433
+ reason: `Skill "${name}" is held by the minimum release age until ${registryResolved.value.record.eligibleAt}`,
434
+ holdback: registryResolved.value.record,
435
+ };
436
+ }
437
+ return {
438
+ type: "match",
439
+ ref: registryResolved.value.ref,
440
+ versionRange: registryResolved.value.versionRange,
441
+ warnings: registryResolved.value.warnings,
442
+ holdbacks: registryResolved.value.holdbacks,
443
+ ...(registryResolved.value.bypasses === undefined
444
+ ? {}
445
+ : { bypasses: registryResolved.value.bypasses }),
446
+ };
447
+ }
448
+ }
449
+ const requestedOwner = Option.match(registryPattern, {
450
+ onNone: () => Option.none(),
451
+ onSome: (pattern) => Option.some(pattern.owner),
452
+ });
453
+ const namedRefs = yield* findSkillRefs(source, {
454
+ skillNames: [name],
455
+ owner: requestedOwner,
456
+ versionRange: Option.none(),
457
+ minimumReleaseAge: Option.some(releaseAgeEvaluation.minimumReleaseAge),
458
+ });
459
+ const skillRef = namedRefs.find((r) => r.skill.name === name);
460
+ if (skillRef) {
461
+ return {
462
+ type: "match",
463
+ ref: skillRef,
464
+ versionRange: Option.none(),
465
+ warnings: [],
466
+ holdbacks: [],
467
+ };
468
+ }
469
+ return {
470
+ type: "skip",
471
+ name,
472
+ source: sourceStr,
473
+ reason: `Skill "${name}" not found in source ${sources.origin(source)}`,
474
+ };
475
+ }).pipe(Effect.catch((error) => isOfficialAxmSource
476
+ ? Effect.fail(error)
477
+ : Effect.succeed({
478
+ type: "skip",
479
+ name,
480
+ source: sourceStr,
481
+ reason: `Failed to resolve "${name}": ${String(error)}`,
482
+ })));
483
+ }, { concurrency: "unbounded" });
484
+ const resolved = results.filter((result) => result.type === "match");
485
+ const skipped = results.filter((result) => result.type === "skip");
486
+ if (resolved.length === 0 &&
487
+ Option.isSome(request.source) &&
488
+ skipped.length > 0 &&
489
+ skipped.every((item) => !isWorkspaceSourceLocator(item.source) && item.holdback === undefined)) {
490
+ return yield* Effect.fail(allSkillResolutionsFailed);
491
+ }
492
+ if (resolved.length === 0 && skipped.length === 0) {
493
+ return yield* Effect.fail(allSkillResolutionsFailed);
494
+ }
495
+ // Classify every proposed Registry acceptance against the accepted
496
+ // resolution. A replaced publisher binding is a trust decision a person
497
+ // makes at a prompt; the plan carries it as an interactive-only condition.
498
+ const warningsBySkill = new Map();
499
+ const publisherTransitions = [];
500
+ for (const item of resolved) {
501
+ const proposed = registryBindingProposal(item.ref);
502
+ const accepted = lockedSkills[item.ref.skill.name];
503
+ const transition = proposed === undefined || accepted?.type !== "registry"
504
+ ? Option.none()
505
+ : classifyPublisherBindingTransition({
506
+ accepted: yield* acceptedResolutionRef({
507
+ workspace: ws,
508
+ type: "skill",
509
+ name: proposed.target,
510
+ }).pipe(Effect.mapError((cause) => new ExtensionLifecycleFailed({
511
+ category: "conflict",
512
+ detail: `The accepted resolution for skill "${proposed.target}" could not be read, so the proposed publisher binding cannot be checked`,
513
+ cause,
514
+ }))),
515
+ proposed,
516
+ });
517
+ if (Option.isSome(transition))
518
+ publisherTransitions.push(transition.value);
519
+ const warnings = Option.isSome(transition)
520
+ ? [publisherTransitionWarning(transition.value), ...item.warnings]
521
+ : item.warnings;
522
+ if (warnings.length > 0)
523
+ warningsBySkill.set(item.ref.skill.name, warnings);
524
+ }
525
+ const units = resolved.map((item) => ({
526
+ name: item.ref.skill.name,
527
+ ref: item.ref,
528
+ force: request.ignoreVersionConstraints || item.ref.refType !== "registry",
529
+ operation: {
530
+ name: "install-skill",
531
+ args: {
532
+ ref: item.ref,
533
+ force: request.ignoreVersionConstraints || item.ref.refType !== "registry",
534
+ versionRange: item.versionRange,
535
+ skipSettings: Option.none(),
536
+ strictUnknownAgents: Option.none(),
537
+ sourceName: Option.none(),
538
+ },
539
+ },
540
+ }));
541
+ const makeRunClosure = (operation) => installSkill(operation).pipe(Effect.map(toJobStepResult), Effect.map(appendWarningsToResult(warningsBySkill.get(operation.args.ref.skill.name) ?? [])));
542
+ const rawPlan = buildSelectiveUpdatePlan(units, lockedSkills, PLAN_NAME, Option.some(PLAN_DESCRIPTION), makeRunClosure);
543
+ const basePlanWithWarnings = {
544
+ ...rawPlan,
545
+ presentation: operationPresentation({ imperative: "update", past: "Updated", gerund: "Updating" }, "skill"),
546
+ releaseAge: {
547
+ evaluatedAt: DateTime.formatIso(releaseAgeEvaluation.evaluatedAt),
548
+ holdbacks: normalizeReleaseAgeRecords([
549
+ ...resolved.flatMap((item) => item.holdbacks),
550
+ ...skipped.flatMap((item) => (item.holdback === undefined ? [] : [item.holdback])),
551
+ ]),
552
+ bypasses: normalizeReleaseAgeRecords(resolved.flatMap((item) => item.bypasses ?? [])),
553
+ },
554
+ jobs: rawPlan.jobs.map((job) => ({
555
+ ...job,
556
+ steps: job.steps.map((step) => {
557
+ if (step.readiness !== "ready")
558
+ return step;
559
+ const message = warningMessage(warningsBySkill.get(step.label) ?? []);
560
+ return message === undefined ? step : { ...step, message };
561
+ }),
562
+ })),
563
+ };
564
+ const skippedSteps = [
565
+ ...skipped.filter((item) => item.holdback === undefined),
566
+ ...disabledSkillEntries,
567
+ ].map((item) => skippedSkillStep(item));
568
+ const [firstJob, ...restJobs] = basePlanWithWarnings.jobs;
569
+ const plan = skippedSteps.length === 0
570
+ ? basePlanWithWarnings
571
+ : firstJob === undefined
572
+ ? { ...basePlanWithWarnings, jobs: [{ concurrency: 1, steps: skippedSteps }] }
573
+ : {
574
+ ...basePlanWithWarnings,
575
+ jobs: [{ ...firstJob, steps: [...firstJob.steps, ...skippedSteps] }, ...restJobs],
576
+ };
577
+ const configuredAgentOperations = [
578
+ ...new Set(request.nameFilters.length > 0
579
+ ? request.nameFilters
580
+ : plan.jobs.flatMap((job) => job.steps.map((step) => step.label.replace(/^(?:Skip|Update)\s+/u, "")))),
581
+ ].map((name) => ({ extensionType: "skill", name, plannedState: "enabled" }));
582
+ const executionPlan = withPublisherTrustConditions({
583
+ ...plan,
584
+ riskConditions: [
585
+ ...(plan.riskConditions ?? []),
586
+ ...(request.ignoreVersionConstraints ? [ignoreVersionConstraintsCondition] : []),
587
+ ],
588
+ }, publisherTransitions);
589
+ return {
590
+ outcome: "planned",
591
+ subjectType: "skill",
592
+ planName: PLAN_NAME,
593
+ execution: yield* prepareExecutionCandidate(executionPlan, { configuredAgentOperations }),
594
+ };
595
+ });
596
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Advancing the subagents a workspace selected.
3
+ *
4
+ * `subagents update` re-resolves each selected, enabled subagent against the
5
+ * source the workspace declared and advances the ones whose resolution
6
+ * differs from what was accepted. A subagent that cannot be re-resolved, is
7
+ * workspace-authored, or is held by the minimum release age is reported as a
8
+ * skipped unit rather than failing the sweep.
9
+ *
10
+ * @experimental This API is unstable and may change without notice.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import { SubagentManager } from "@agentxm/extension-materialization";
14
+ import { SourceHostProviders } from "@agentxm/extension-sources";
15
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
16
+ import { ExtensionLifecycleFailed } from "../../errors.js";
17
+ import { StepFailureConversion } from "../../step-failure-conversion.js";
18
+ import type { SelectiveUpdateStepRequirements } from "./requirements.js";
19
+ import { type SelectiveUpdateSelectors } from "./selection.js";
20
+ /** Everything `subagents update` needs beyond the workspace it runs in. */
21
+ export interface SelectiveSubagentUpdateRequest extends SelectiveUpdateSelectors {
22
+ readonly kind: "selective-subagents";
23
+ /** Advance outside the version ranges installed Packs declare. */
24
+ readonly ignoreVersionConstraints: boolean;
25
+ }
26
+ /** Settle a `subagents update` request: decide everything, write nothing. */
27
+ export declare const prepareSelectiveSubagentUpdate: (request: SelectiveSubagentUpdateRequest) => Effect.Effect<{
28
+ outcome: "nothing";
29
+ reason: "none-installed";
30
+ message: string;
31
+ subjectType: "subagent";
32
+ planName: string;
33
+ planDescription: string;
34
+ execution?: never;
35
+ } | {
36
+ outcome: "nothing";
37
+ reason: "no-source-match" | "no-name-match";
38
+ message: string;
39
+ subjectType: "subagent";
40
+ planName: string;
41
+ planDescription: string;
42
+ execution?: never;
43
+ } | {
44
+ outcome: "planned";
45
+ subjectType: "subagent";
46
+ planName: string;
47
+ execution: import("@agentxm/workspace-operations").ExecutionCandidate<SelectiveUpdateStepRequirements, never>;
48
+ reason?: never;
49
+ message?: never;
50
+ planDescription?: never;
51
+ }, ExtensionLifecycleFailed | import("@agentxm/extension-sources").SourceSyntaxInvalid | import("@agentxm/extension-sources").SourceHostNotConfigured | import("@agentxm/extension-sources").SourceNotResolvable | import("@agentxm/extension-sources").SourceNetworkFailure | import("@agentxm/extension-sources").GitOperationFailed | import("@agentxm/extension-sources").WorkspaceCatalogUnavailable | import("@agentxm/extension-sources").AxmSkillGateUnavailable | import("@agentxm/registry-client").RegistryProblem | import("@agentxm/registry-client").RegistryRequestFailed | import("@agentxm/registry-client").RegistryOperationFailed | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileValidationError | import("@agentxm/extension-resolution").ExtensionResolutionFailed | import("@agentxm/workspace-operations").CandidateFingerprintFailed, StepFailureConversion | import("effect/FileSystem").FileSystem | import("effect/Path").Path | WorkspaceMutations | import("@agentxm/workspace-state").ConfiguredAgentOutcomesProvider | import("effect/unstable/http/HttpClient").HttpClient | import("@agentxm/extension-resolution").ReleaseAgePosture | import("effect/Scope").Scope | SourceHostProviders | SubagentManager | import("@agentxm/extension-sources").WorkspaceCatalog>;
52
+ //# sourceMappingURL=subagents.d.ts.map