@agentxm/extension-materialization 0.28.14-preview.1789139351.5cd4595aa

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 (89) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +16 -0
  3. package/dist/src/desired-state/errors.d.ts +22 -0
  4. package/dist/src/desired-state/errors.js +22 -0
  5. package/dist/src/desired-state/retained-materialization.d.ts +58 -0
  6. package/dist/src/desired-state/retained-materialization.js +119 -0
  7. package/dist/src/errors.d.ts +42 -0
  8. package/dist/src/errors.js +14 -0
  9. package/dist/src/extensions/canonical-directory.d.ts +106 -0
  10. package/dist/src/extensions/canonical-directory.js +210 -0
  11. package/dist/src/extensions/canonical-reuse.d.ts +43 -0
  12. package/dist/src/extensions/canonical-reuse.js +38 -0
  13. package/dist/src/extensions/copy-directory.d.ts +50 -0
  14. package/dist/src/extensions/copy-directory.js +78 -0
  15. package/dist/src/extensions/errors.d.ts +97 -0
  16. package/dist/src/extensions/errors.js +42 -0
  17. package/dist/src/extensions/materializable-from-disk.d.ts +37 -0
  18. package/dist/src/extensions/materializable-from-disk.js +89 -0
  19. package/dist/src/extensions/operations.d.ts +252 -0
  20. package/dist/src/extensions/operations.js +631 -0
  21. package/dist/src/hooks/errors.d.ts +33 -0
  22. package/dist/src/hooks/errors.js +18 -0
  23. package/dist/src/hooks/manager.d.ts +13 -0
  24. package/dist/src/hooks/manager.js +778 -0
  25. package/dist/src/index.d.ts +44 -0
  26. package/dist/src/index.js +56 -0
  27. package/dist/src/knowledge/errors.d.ts +75 -0
  28. package/dist/src/knowledge/errors.js +36 -0
  29. package/dist/src/knowledge/manager.d.ts +9 -0
  30. package/dist/src/knowledge/manager.js +709 -0
  31. package/dist/src/live.d.ts +20 -0
  32. package/dist/src/live.js +20 -0
  33. package/dist/src/manager-contract.d.ts +136 -0
  34. package/dist/src/manager-contract.js +19 -0
  35. package/dist/src/manager-registry-live.d.ts +11 -0
  36. package/dist/src/manager-registry-live.js +23 -0
  37. package/dist/src/manager-registry.d.ts +37 -0
  38. package/dist/src/manager-registry.js +22 -0
  39. package/dist/src/managers.d.ts +147 -0
  40. package/dist/src/managers.js +32 -0
  41. package/dist/src/mcps/artifact.d.ts +24 -0
  42. package/dist/src/mcps/artifact.js +74 -0
  43. package/dist/src/mcps/authored-materialization.d.ts +28 -0
  44. package/dist/src/mcps/authored-materialization.js +34 -0
  45. package/dist/src/mcps/errors.d.ts +105 -0
  46. package/dist/src/mcps/errors.js +40 -0
  47. package/dist/src/mcps/install-operation.d.ts +92 -0
  48. package/dist/src/mcps/install-operation.js +557 -0
  49. package/dist/src/mcps/manager.d.ts +15 -0
  50. package/dist/src/mcps/manager.js +253 -0
  51. package/dist/src/mcps/native-entry.d.ts +51 -0
  52. package/dist/src/mcps/native-entry.js +100 -0
  53. package/dist/src/mcps/secret-store-live.d.ts +14 -0
  54. package/dist/src/mcps/secret-store-live.js +58 -0
  55. package/dist/src/mcps/secret-store.d.ts +55 -0
  56. package/dist/src/mcps/secret-store.js +33 -0
  57. package/dist/src/packs/errors.d.ts +50 -0
  58. package/dist/src/packs/errors.js +24 -0
  59. package/dist/src/packs/manager.d.ts +16 -0
  60. package/dist/src/packs/manager.js +189 -0
  61. package/dist/src/projection-participants-live.d.ts +17 -0
  62. package/dist/src/projection-participants-live.js +66 -0
  63. package/dist/src/projection-step-failure.d.ts +19 -0
  64. package/dist/src/projection-step-failure.js +76 -0
  65. package/dist/src/registry-materialization.d.ts +52 -0
  66. package/dist/src/registry-materialization.js +67 -0
  67. package/dist/src/rules/errors.d.ts +31 -0
  68. package/dist/src/rules/errors.js +17 -0
  69. package/dist/src/rules/manager.d.ts +18 -0
  70. package/dist/src/rules/manager.js +492 -0
  71. package/dist/src/skills/errors.d.ts +42 -0
  72. package/dist/src/skills/errors.js +21 -0
  73. package/dist/src/skills/manager.d.ts +17 -0
  74. package/dist/src/skills/manager.js +339 -0
  75. package/dist/src/skills/materialization.d.ts +52 -0
  76. package/dist/src/skills/materialization.js +168 -0
  77. package/dist/src/skills/skill-artifact.d.ts +38 -0
  78. package/dist/src/skills/skill-artifact.js +70 -0
  79. package/dist/src/skills/source-hash.d.ts +2 -0
  80. package/dist/src/skills/source-hash.js +6 -0
  81. package/dist/src/subagents/errors.d.ts +43 -0
  82. package/dist/src/subagents/errors.js +20 -0
  83. package/dist/src/subagents/lock-entry-builder.d.ts +20 -0
  84. package/dist/src/subagents/lock-entry-builder.js +63 -0
  85. package/dist/src/subagents/manager.d.ts +17 -0
  86. package/dist/src/subagents/manager.js +736 -0
  87. package/dist/src/testing.d.ts +87 -0
  88. package/dist/src/testing.js +116 -0
  89. package/package.json +70 -0
@@ -0,0 +1,631 @@
1
+ /**
2
+ * Shared extension closure recipes — install, materialize, uninstall, and the
3
+ * authored-package transition.
4
+ *
5
+ * A recipe composes one manager's contract into one plan step. Requirements
6
+ * stay explicit: the step declares the manager's `R` plus the transaction
7
+ * scope its closure runs in, and the command boundary composes them once. The
8
+ * facts a materialization observed travel from `materializeInstall` to the
9
+ * settings and lockfile writes and to the step's artifact as values.
10
+ *
11
+ * @experimental This API is unstable and may change without notice.
12
+ * @packageDocumentation
13
+ */
14
+ import * as Effect from "effect/Effect";
15
+ import * as Option from "effect/Option";
16
+ import { LifecyclePostconditionViolated, ScaffoldedExtensionUnresolved } from "./errors.js";
17
+ import { SourceAuthorityBlocked } from "@agentxm/extension-resolution";
18
+ import { applyProjectionPlans, projectionPlanExclusionWarnings, } from "@agentxm/workspace-projection";
19
+ import { isWorkspaceSourceLocator } from "@agentxm/extension-model/unstable/sources/workspace";
20
+ import { evaluateSourceAuthority } from "@agentxm/extension-resolution";
21
+ import { formatDeprecationWarning } from "@agentxm/registry-client";
22
+ import { runWorkspaceTransaction } from "@agentxm/workspace-transactions";
23
+ import { toExtensionTypePlural } from "@agentxm/extension-model/unstable/extensions/common";
24
+ // -----------------------------------------------------------------------------
25
+ // Target Helpers
26
+ // -----------------------------------------------------------------------------
27
+ /**
28
+ * Derive an ExtensionTarget from an ExtensionRef.
29
+ *
30
+ * Pack targets include owner; leaf-extension targets are name-only.
31
+ */
32
+ export const targetFromRef = (ref) => {
33
+ switch (ref.type) {
34
+ case "skill":
35
+ return { type: "skill", name: ref.skill.name };
36
+ case "pack":
37
+ return { type: "pack", name: ref.pack.name, owner: ref.owner };
38
+ case "mcp-server":
39
+ return { type: "mcp-server", name: ref.server.name };
40
+ case "subagent":
41
+ return { type: "subagent", name: ref.subagent.name };
42
+ case "rule":
43
+ return { type: "rule", name: ref.rule.name };
44
+ case "hook":
45
+ return { type: "hook", name: ref.hook.name };
46
+ case "knowledge":
47
+ return { type: "knowledge", name: ref.knowledge.name };
48
+ }
49
+ };
50
+ export const extensionRefLifecycleWarnings = (ref) => ref.refType === "registry"
51
+ ? [
52
+ ...(ref.deprecation === undefined
53
+ ? []
54
+ : [
55
+ formatDeprecationWarning(`${ref.owner}/${toExtensionTypePlural(ref.type)}/${ref.name}`, ref.deprecation),
56
+ ]),
57
+ ...(ref.lifecycleWarnings ?? []),
58
+ ]
59
+ : [];
60
+ export const extensionRefRegistryLifecycle = (ref) => ref.refType !== "registry" || ref.deprecation === undefined
61
+ ? undefined
62
+ : { deprecation: ref.deprecation };
63
+ /**
64
+ * Produce a display label from an ExtensionTarget.
65
+ *
66
+ * Pack targets render as `owner/name`; others render as `name`.
67
+ */
68
+ export const toLabel = (target) => target.type === "pack" ? `${target.owner}/${target.name}` : target.name;
69
+ /**
70
+ * Produce a stable step identity key from an ExtensionTarget.
71
+ *
72
+ * This is internal plan identity, not display text.
73
+ */
74
+ export const toStepKey = (target) => target.type === "pack"
75
+ ? `${target.type}:${target.owner}/${target.name}`
76
+ : `${target.type}:${target.name}`;
77
+ /**
78
+ * Format a single PackageUrlParts as a compact display string.
79
+ *
80
+ * Examples: `pkg:npm/react`, `pkg:npm/@angular/core@18.0.0`
81
+ */
82
+ export const formatPackageUrlParts = (parts) => {
83
+ const ns = parts.namespace !== undefined ? `${parts.namespace}/` : "";
84
+ const ver = parts.version !== undefined ? `@${parts.version}` : "";
85
+ return `pkg:${parts.type}/${ns}${parts.name}${ver}`;
86
+ };
87
+ /**
88
+ * Build a display label with optional packages suffix.
89
+ *
90
+ * When packages is non-empty, appends them parenthesized:
91
+ * `code-review (pkg:npm/react, pkg:npm/typescript)`
92
+ */
93
+ export const toLabelWithCompanions = (target, packages) => {
94
+ const base = toLabel(target);
95
+ if (packages.length === 0)
96
+ return base;
97
+ const purls = packages.map(formatPackageUrlParts).join(", ");
98
+ return `${base} (${purls})`;
99
+ };
100
+ const NO_PROJECTION_WARNINGS = [];
101
+ /**
102
+ * Render the manager's shared aggregate units and return the operator-facing
103
+ * report for every desired contributor those units could not render. The
104
+ * report travels with the step that performed the render.
105
+ */
106
+ const applyManagerProjectionPlans = (manager) => manager.projectionPlans === undefined
107
+ ? Effect.succeed(NO_PROJECTION_WARNINGS)
108
+ : manager
109
+ .projectionPlans()
110
+ .pipe(Effect.flatMap((plans) => applyProjectionPlans(plans).pipe(Effect.as(projectionPlanExclusionWarnings(plans)))));
111
+ const isConfigured = (manager, target) => {
112
+ if (manager.isConfigured !== undefined)
113
+ return manager.isConfigured({ target });
114
+ if (manager.getConfiguredSource === undefined)
115
+ return Effect.succeed(false);
116
+ return manager.getConfiguredSource({ target }).pipe(Effect.map(Option.isSome));
117
+ };
118
+ /**
119
+ * Execute the canonical install sequence.
120
+ *
121
+ * Root installs materialize and commit desired state plus any accepted external
122
+ * resolution before validating the observable postcondition. Pack-derived
123
+ * installs omit the root settings declaration while retaining that resolution.
124
+ */
125
+ const runInstallOperation = (manager, args) => Effect.gen(function* () {
126
+ const target = targetFromRef(args.ref);
127
+ const configuredSource = manager.getConfiguredSource === undefined
128
+ ? Option.none()
129
+ : yield* manager.getConfiguredSource({ target });
130
+ const authority = evaluateSourceAuthority({
131
+ target: { ...target, identity: toStepKey(target) },
132
+ relationship: { kind: "root" },
133
+ requested: {
134
+ identity: `${args.ref.refType}:${toStepKey(target)}`,
135
+ workspace: args.ref.refType === "workspace",
136
+ },
137
+ ...(Option.isNone(configuredSource)
138
+ ? {}
139
+ : {
140
+ configured: {
141
+ identity: configuredSource.value,
142
+ workspace: isWorkspaceSourceLocator(configuredSource.value),
143
+ },
144
+ }),
145
+ ...(args.allowWorkspaceReplacement === undefined
146
+ ? {}
147
+ : { allowWorkspaceReplacement: args.allowWorkspaceReplacement }),
148
+ });
149
+ if (authority.kind === "blocked") {
150
+ return yield* new SourceAuthorityBlocked({
151
+ detail: authority.fact.detail,
152
+ recovery: authority.fact.recovery,
153
+ });
154
+ }
155
+ const installedBefore = args.installedBefore === undefined ? false : yield* args.installedBefore;
156
+ const transaction = yield* runWorkspaceTransaction({
157
+ transition: Effect.gen(function* () {
158
+ const cleanupSupersededCanonical = manager.prepareSourceTransition === undefined
159
+ ? Effect.void
160
+ : yield* manager.prepareSourceTransition({ ref: args.ref });
161
+ const materialization = yield* manager.materializeInstall({
162
+ ref: args.ref,
163
+ ...(args.force === undefined ? {} : { force: args.force }),
164
+ });
165
+ if (!args.skipSettings) {
166
+ yield* manager.upsertSettingsEntry({
167
+ ref: args.ref,
168
+ versionRange: args.versionRange,
169
+ materialization: Option.some(materialization),
170
+ });
171
+ }
172
+ yield* manager.upsertLockfileEntry({
173
+ ref: args.ref,
174
+ materialization: Option.some(materialization),
175
+ });
176
+ yield* cleanupSupersededCanonical;
177
+ // Desired state and canonical content are committed; render every
178
+ // shared aggregate unit once from the complete contributor set.
179
+ const projectionWarnings = args.skipProjections !== true
180
+ ? yield* applyManagerProjectionPlans(manager)
181
+ : NO_PROJECTION_WARNINGS;
182
+ return { installedBefore, materialization, projectionWarnings };
183
+ }),
184
+ validate: () => Effect.gen(function* () {
185
+ if (args.deferObservableValidation !== true) {
186
+ const installed = yield* manager.isInstalled({ target });
187
+ if (!installed) {
188
+ return yield* new LifecyclePostconditionViolated({
189
+ postcondition: "install-observable",
190
+ targetType: target.type,
191
+ targetName: target.name,
192
+ });
193
+ }
194
+ }
195
+ if (args.skipSettings !== true &&
196
+ (manager.isConfigured !== undefined || manager.getConfiguredSource !== undefined)) {
197
+ const configured = yield* isConfigured(manager, target);
198
+ if (!configured) {
199
+ return yield* new LifecyclePostconditionViolated({
200
+ postcondition: "install-declared",
201
+ targetType: target.type,
202
+ targetName: target.name,
203
+ });
204
+ }
205
+ }
206
+ }),
207
+ });
208
+ const artifact = args.buildArtifact === undefined
209
+ ? undefined
210
+ : yield* args.buildArtifact({
211
+ installedBefore,
212
+ materialization: Option.some(transaction.materialization),
213
+ });
214
+ const artifactWithLifecycle = artifact === undefined ||
215
+ args.ref.refType !== "registry" ||
216
+ args.ref.deprecation === undefined
217
+ ? artifact
218
+ : { ...artifact, registryLifecycle: { deprecation: args.ref.deprecation } };
219
+ return {
220
+ result: "success",
221
+ message: args.message ?? "Applied install operation",
222
+ ...(artifactWithLifecycle === undefined ? {} : { artifact: artifactWithLifecycle }),
223
+ ...(transaction.projectionWarnings.length === 0
224
+ ? {}
225
+ : { warnings: transaction.projectionWarnings }),
226
+ };
227
+ }).pipe(Effect.mapError(args.toStepFailure));
228
+ /**
229
+ * Build a PlannedJobStep for an install operation.
230
+ *
231
+ * The step keeps the manager's requirements and the transaction scope in its
232
+ * `run` effect; the command boundary composes them once.
233
+ */
234
+ export const buildInstallOperation = (manager, args) => {
235
+ const target = targetFromRef(args.ref);
236
+ const companionPkgs = args.ref.refType === "registry" ? args.ref.packages : [];
237
+ const lifecycleWarnings = extensionRefLifecycleWarnings(args.ref);
238
+ const registryLifecycle = extensionRefRegistryLifecycle(args.ref);
239
+ // The proposed Registry identity travels with the step as structured data,
240
+ // so trust classification compares bindings rather than reading warnings.
241
+ const registryBinding = args.ref.refType === "registry"
242
+ ? {
243
+ extensionType: args.ref.type,
244
+ target: target.name,
245
+ owner: args.ref.owner,
246
+ packageName: args.ref.name,
247
+ version: args.ref.version,
248
+ publisherBindingId: args.ref.publisherBindingId,
249
+ }
250
+ : undefined;
251
+ const base = {
252
+ key: toStepKey(target),
253
+ label: toLabelWithCompanions(target, companionPkgs),
254
+ run: runInstallOperation(manager, args),
255
+ ...(registryLifecycle === undefined ? {} : { registryLifecycle }),
256
+ ...(registryBinding === undefined ? {} : { registryBinding }),
257
+ };
258
+ return lifecycleWarnings.length === 0
259
+ ? { ...base, readiness: "ready" }
260
+ : {
261
+ ...base,
262
+ readiness: "warn",
263
+ warnMessage: lifecycleWarnings.join("; "),
264
+ };
265
+ };
266
+ /**
267
+ * Build a PlannedJobStep for `new` commands.
268
+ *
269
+ * A read-only preflight runs first. The transaction then snapshots the source
270
+ * path, scaffolds it, seeds desired state, resolves the canonical package, and
271
+ * materializes projections before validating the authored postcondition.
272
+ */
273
+ export const buildAuthoredExtensionStep = (manager, args) => {
274
+ const target = args.target;
275
+ return {
276
+ key: toStepKey(target),
277
+ label: args.label ?? toLabel(target),
278
+ readiness: "ready",
279
+ ...(args.plannedArtifact === undefined ? {} : { artifact: args.plannedArtifact }),
280
+ run: (args.allowConfiguredSourceTransition === true
281
+ ? Effect.void
282
+ : manager.listMaterializable()).pipe(Effect.andThen(runWorkspaceTransaction({
283
+ targets: Array.from(new Set([args.location, ...(args.transactionTargets ?? [])])).sort(),
284
+ transition: Effect.gen(function* () {
285
+ if (args.preflight !== undefined)
286
+ yield* args.preflight;
287
+ yield* args.scaffold;
288
+ yield* args.markAuthored;
289
+ const materializable = yield* manager.listMaterializable();
290
+ const ref = materializable.find((candidate) => toStepKey(targetFromRef(candidate)) === toStepKey(target));
291
+ if (ref === undefined) {
292
+ return yield* new ScaffoldedExtensionUnresolved({
293
+ targetType: target.type,
294
+ targetName: target.name,
295
+ });
296
+ }
297
+ const installedBefore = args.installedBefore === undefined ? false : yield* args.installedBefore;
298
+ let materialization = Option.none();
299
+ if (args.enabled !== false || args.materializeWhenDisabled === true) {
300
+ materialization =
301
+ args.materializeInstall === undefined
302
+ ? Option.some(yield* manager.materializeInstall({ ref }))
303
+ : yield* args.materializeInstall(ref);
304
+ }
305
+ yield* manager.upsertSettingsEntry({
306
+ ref,
307
+ versionRange: args.versionRange,
308
+ materialization,
309
+ });
310
+ if (args.finalizeAuthored !== undefined) {
311
+ yield* args.finalizeAuthored;
312
+ }
313
+ if (args.enabled === false && args.materializeWhenDisabled === true) {
314
+ yield* manager.materializeDeactivate({ target });
315
+ }
316
+ else if (args.enabled !== false) {
317
+ // Desired state is committed; render shared aggregate units once
318
+ // from the complete contributor set.
319
+ return {
320
+ ref,
321
+ installedBefore,
322
+ materialization,
323
+ projectionWarnings: yield* applyManagerProjectionPlans(manager),
324
+ };
325
+ }
326
+ return {
327
+ ref,
328
+ installedBefore,
329
+ materialization,
330
+ projectionWarnings: NO_PROJECTION_WARNINGS,
331
+ };
332
+ }),
333
+ validate: () => Effect.gen(function* () {
334
+ const installed = yield* manager.isInstalled({ target });
335
+ if (args.enabled !== false && !installed) {
336
+ return yield* new LifecyclePostconditionViolated({
337
+ postcondition: "new-observable",
338
+ targetType: target.type,
339
+ targetName: target.name,
340
+ });
341
+ }
342
+ if (manager.getConfiguredSource !== undefined) {
343
+ const configured = yield* manager.getConfiguredSource({ target });
344
+ if (Option.isNone(configured)) {
345
+ return yield* new LifecyclePostconditionViolated({
346
+ postcondition: "new-declared",
347
+ targetType: target.type,
348
+ targetName: target.name,
349
+ });
350
+ }
351
+ }
352
+ }),
353
+ })), Effect.flatMap(({ installedBefore, materialization }) => Effect.gen(function* () {
354
+ const artifact = args.buildArtifact === undefined
355
+ ? undefined
356
+ : yield* args.buildArtifact({ installedBefore, materialization });
357
+ return {
358
+ result: "success",
359
+ message: args.message,
360
+ ...(artifact === undefined ? {} : { artifact }),
361
+ };
362
+ })), Effect.mapError(args.toStepFailure)),
363
+ };
364
+ };
365
+ /**
366
+ * Build a PlannedJobStep for existing `new` commands.
367
+ *
368
+ * New commands remain enabled by default while sharing the authored-package
369
+ * transaction used by fork and native import.
370
+ */
371
+ export const buildNewExtensionStep = (manager, args) => {
372
+ if (args.ref.refType !== "workspace") {
373
+ return {
374
+ key: toStepKey(args.target),
375
+ label: args.label ?? toLabel(args.target),
376
+ readiness: "error",
377
+ errorMessage: "New authored extensions require a workspace source",
378
+ };
379
+ }
380
+ return buildAuthoredExtensionStep(manager, {
381
+ ...args,
382
+ location: args.ref.location,
383
+ enabled: true,
384
+ });
385
+ };
386
+ const runMaterializeOperation = (manager, args) => Effect.gen(function* () {
387
+ const target = targetFromRef(args.ref);
388
+ const materialization = yield* runWorkspaceTransaction({
389
+ transition: Effect.gen(function* () {
390
+ const observed = yield* manager.materializeInstall({
391
+ ref: args.ref,
392
+ ...(args.force === undefined ? {} : { force: args.force }),
393
+ });
394
+ if (args.validateMaterialized !== undefined) {
395
+ yield* args.validateMaterialized({ materialization: observed });
396
+ }
397
+ yield* manager.upsertLockfileEntry({
398
+ ref: args.ref,
399
+ materialization: Option.some(observed),
400
+ });
401
+ return observed;
402
+ }),
403
+ validate: () => manager.isInstalled({ target }).pipe(Effect.flatMap((installed) => installed
404
+ ? Effect.void
405
+ : new LifecyclePostconditionViolated({
406
+ postcondition: "materialize-observable",
407
+ targetType: target.type,
408
+ targetName: target.name,
409
+ }))),
410
+ });
411
+ const artifact = args.buildArtifact === undefined ? undefined : yield* args.buildArtifact({ materialization });
412
+ return {
413
+ result: "success",
414
+ message: args.message ?? "Synced agent artifacts",
415
+ ...(artifact === undefined ? {} : { artifact }),
416
+ };
417
+ }).pipe(Effect.mapError(args.toStepFailure));
418
+ export const buildMaterializeOperation = (manager, args) => {
419
+ const target = targetFromRef(args.ref);
420
+ const companionPkgs = args.ref.refType === "registry" ? args.ref.packages : [];
421
+ return {
422
+ key: toStepKey(target),
423
+ label: args.label ?? toLabelWithCompanions(target, companionPkgs),
424
+ readiness: "ready",
425
+ run: runMaterializeOperation(manager, args),
426
+ };
427
+ };
428
+ const uninstallSettlementMessage = (target, settlement) => {
429
+ const label = toLabel(target);
430
+ if (settlement.declaration === "absent" && settlement.canonical === "absent") {
431
+ return `${label} is already absent`;
432
+ }
433
+ switch (settlement.canonical) {
434
+ case "absent":
435
+ return `Unconfigured ${label}; no canonical package was present`;
436
+ case "removed":
437
+ return `Removed ${label}`;
438
+ case "retained-by-pack":
439
+ return `Unconfigured ${label}; retained its package because an installed pack still requires it`;
440
+ case "preserved-authored":
441
+ return `Unconfigured ${label}; preserved its workspace-authored source`;
442
+ case "preserved-unowned":
443
+ return `Unconfigured ${label}; preserved canonical content without an accepted source owner`;
444
+ case "preserved-unreadable":
445
+ return `Unconfigured ${label}; preserved its package because its manifest could not be read`;
446
+ }
447
+ };
448
+ /**
449
+ * Plain-language account of a registration-only removal: what was retired, why
450
+ * its content could not be verified, what was left in place, and what the
451
+ * operator can do about the remainder.
452
+ */
453
+ const unreadablePackageWarning = (target, retirement) => `${toLabel(target)}: its package manifest ${retirement.reason === "missing" ? "is missing" : "cannot be read"} at ${retirement.manifestPath}, so AXM removed its configuration entry and accepted resolution and left its package content in place. Delete that content yourself once you no longer need it.`;
454
+ /**
455
+ * Execute the uninstall sequence with retention check.
456
+ *
457
+ * If the target is still required by an installed pack:
458
+ * 1. Remove settings entry
459
+ *
460
+ * If not required:
461
+ * 1. Unmaterialize from disk
462
+ * 2. Remove lockfile entry
463
+ * 3. Remove settings entry
464
+ */
465
+ const runUninstallOperation = (manager, retentionPolicy, args) => Effect.gen(function* () {
466
+ const configuredSource = manager.getConfiguredSource === undefined
467
+ ? Option.none()
468
+ : yield* manager.getConfiguredSource({ target: args.target });
469
+ const configured = yield* isConfigured(manager, args.target);
470
+ const transition = Effect.gen(function* () {
471
+ const applyProjections = () => args.skipProjections !== true
472
+ ? applyManagerProjectionPlans(manager)
473
+ : Effect.succeed(NO_PROJECTION_WARNINGS);
474
+ if (args.retirement !== undefined) {
475
+ // Nothing about the package can be verified, so only the registration
476
+ // AXM itself wrote is removable. Canonical content stays untouched.
477
+ yield* manager.removeSettingsEntry({
478
+ target: args.target,
479
+ materialization: Option.none(),
480
+ });
481
+ yield* manager.removeLockfileEntry({
482
+ target: args.target,
483
+ materialization: Option.none(),
484
+ });
485
+ return {
486
+ settlement: {
487
+ declaration: "removed",
488
+ canonical: "preserved-unreadable",
489
+ },
490
+ unmaterialization: Option.none(),
491
+ expectedInstalled: undefined,
492
+ projectionWarnings: yield* applyProjections(),
493
+ };
494
+ }
495
+ const isInstalled = yield* manager.isInstalled({ target: args.target });
496
+ if (!isInstalled) {
497
+ if (configured) {
498
+ // Configured extensions may still own native agent projections even
499
+ // when they have no canonical managed package on disk.
500
+ const withdrawn = yield* manager.materializeUninstall({ target: args.target });
501
+ const unmaterialization = Option.some(withdrawn);
502
+ yield* manager.removeSettingsEntry({
503
+ target: args.target,
504
+ materialization: unmaterialization,
505
+ });
506
+ yield* manager.removeLockfileEntry({
507
+ target: args.target,
508
+ materialization: unmaterialization,
509
+ });
510
+ return {
511
+ settlement: {
512
+ declaration: "removed",
513
+ canonical: "absent",
514
+ },
515
+ unmaterialization,
516
+ expectedInstalled: false,
517
+ projectionWarnings: yield* applyProjections(),
518
+ };
519
+ }
520
+ return {
521
+ settlement: {
522
+ declaration: "absent",
523
+ canonical: "absent",
524
+ },
525
+ unmaterialization: Option.none(),
526
+ expectedInstalled: false,
527
+ projectionWarnings: NO_PROJECTION_WARNINGS,
528
+ };
529
+ }
530
+ const stillRequiredByPack = yield* retentionPolicy.isRequiredByInstalledPack({
531
+ target: args.target,
532
+ });
533
+ if (stillRequiredByPack) {
534
+ yield* manager.removeSettingsEntry({ target: args.target, materialization: Option.none() });
535
+ return {
536
+ settlement: {
537
+ declaration: "removed",
538
+ canonical: "retained-by-pack",
539
+ },
540
+ unmaterialization: Option.none(),
541
+ expectedInstalled: true,
542
+ projectionWarnings: yield* applyProjections(),
543
+ };
544
+ }
545
+ const unmaterialization = Option.some(yield* manager.materializeUninstall({ target: args.target }));
546
+ yield* manager.removeSettingsEntry({
547
+ target: args.target,
548
+ materialization: unmaterialization,
549
+ });
550
+ yield* manager.removeLockfileEntry({
551
+ target: args.target,
552
+ materialization: unmaterialization,
553
+ });
554
+ // The target has left the desired-state graph; re-render every shared
555
+ // aggregate unit once so only reachable contributors remain.
556
+ const projectionWarnings = yield* applyProjections();
557
+ return {
558
+ projectionWarnings,
559
+ unmaterialization,
560
+ settlement: {
561
+ declaration: "removed",
562
+ canonical: Option.match(configuredSource, {
563
+ onNone: () => "preserved-unowned",
564
+ onSome: (source) => isWorkspaceSourceLocator(source)
565
+ ? "preserved-authored"
566
+ : "removed",
567
+ }),
568
+ },
569
+ expectedInstalled: Option.match(configuredSource, {
570
+ onNone: () => undefined,
571
+ onSome: (source) => (isWorkspaceSourceLocator(source) ? undefined : false),
572
+ }),
573
+ };
574
+ });
575
+ const result = yield* runWorkspaceTransaction({
576
+ transition,
577
+ validate: (outcome) => Effect.gen(function* () {
578
+ if (manager.isConfigured !== undefined || manager.getConfiguredSource !== undefined) {
579
+ const remainsConfigured = yield* isConfigured(manager, args.target);
580
+ if (remainsConfigured) {
581
+ return yield* new LifecyclePostconditionViolated({
582
+ postcondition: "uninstall-remains-declared",
583
+ targetType: args.target.type,
584
+ targetName: args.target.name,
585
+ });
586
+ }
587
+ }
588
+ const installed = yield* manager.isInstalled({ target: args.target });
589
+ if (outcome.expectedInstalled !== undefined && installed !== outcome.expectedInstalled) {
590
+ return yield* new LifecyclePostconditionViolated({
591
+ postcondition: "uninstall-observed-state",
592
+ targetType: args.target.type,
593
+ targetName: args.target.name,
594
+ });
595
+ }
596
+ }),
597
+ });
598
+ const warnings = [
599
+ ...(args.retirement === undefined
600
+ ? []
601
+ : [unreadablePackageWarning(args.target, args.retirement)]),
602
+ ...result.projectionWarnings,
603
+ ];
604
+ const artifact = args.buildArtifact === undefined
605
+ ? undefined
606
+ : yield* args.buildArtifact({
607
+ settlement: result.settlement,
608
+ unmaterialization: result.unmaterialization,
609
+ });
610
+ return {
611
+ result: "success",
612
+ message: uninstallSettlementMessage(args.target, result.settlement),
613
+ ...(result.settlement.declaration === "absent" ? { disposition: "unchanged" } : {}),
614
+ ...(artifact === undefined ? {} : { artifact }),
615
+ ...(warnings.length === 0 ? {} : { warnings }),
616
+ };
617
+ }).pipe(Effect.mapError(args.toStepFailure));
618
+ /**
619
+ * Build a PlannedJobStep for an uninstall operation.
620
+ *
621
+ * The step keeps the manager's requirements and the transaction scope in its
622
+ * `run` effect; the command boundary composes them once.
623
+ */
624
+ export const buildUninstallOperation = (manager, retentionPolicy, args) => {
625
+ return {
626
+ label: toLabel(args.target),
627
+ readiness: "ready",
628
+ run: runUninstallOperation(manager, retentionPolicy, args),
629
+ };
630
+ };
631
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Typed failure family for the hook manager and managed hook-group editing.
3
+ * Fields are domain facts; the application error boundary owns rendering,
4
+ * codes, and suggestions.
5
+ *
6
+ * @experimental This API is unstable and may change without notice.
7
+ */
8
+ import type { HookConfigInvalid, HookIoFailed } from "@agentxm/agent-integration";
9
+ declare const HookDefinitionInvalid_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
10
+ readonly _tag: "HookDefinitionInvalid";
11
+ } & Readonly<A>;
12
+ /**
13
+ * A hook package, binding, or projection input did not validate. `detail`
14
+ * carries the site's fact sentence verbatim.
15
+ */
16
+ export declare class HookDefinitionInvalid extends HookDefinitionInvalid_base<{
17
+ readonly detail: string;
18
+ readonly cause?: unknown;
19
+ }> {
20
+ }
21
+ declare const HookInstallStateMissing_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
22
+ readonly _tag: "HookInstallStateMissing";
23
+ } & Readonly<A>;
24
+ /** A lock entry was requested before install recorded the package state. */
25
+ export declare class HookInstallStateMissing extends HookInstallStateMissing_base<{
26
+ readonly name: string;
27
+ readonly kind: "tree-integrity" | "content-identity";
28
+ }> {
29
+ }
30
+ /** Every failure the hook manager constructs. */
31
+ export type HookManagerError = HookDefinitionInvalid | HookConfigInvalid | HookIoFailed | HookInstallStateMissing;
32
+ export {};
33
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Typed failure family for the hook manager and managed hook-group editing.
3
+ * Fields are domain facts; the application error boundary owns rendering,
4
+ * codes, and suggestions.
5
+ *
6
+ * @experimental This API is unstable and may change without notice.
7
+ */
8
+ import * as Data from "effect/Data";
9
+ /**
10
+ * A hook package, binding, or projection input did not validate. `detail`
11
+ * carries the site's fact sentence verbatim.
12
+ */
13
+ export class HookDefinitionInvalid extends Data.TaggedError("HookDefinitionInvalid") {
14
+ }
15
+ /** A lock entry was requested before install recorded the package state. */
16
+ export class HookInstallStateMissing extends Data.TaggedError("HookInstallStateMissing") {
17
+ }
18
+ //# sourceMappingURL=errors.js.map