@agentxm/extension-materialization 0.29.4 → 0.30.1

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.
@@ -1,3 +1,5 @@
1
+ import { usableAcceptedCanonical } from "@agentxm/workspace-state";
2
+ import { LifecyclePostconditionViolated } from "../extensions/errors.js";
1
3
  /**
2
4
  * Rule manager service.
3
5
  *
@@ -424,6 +426,22 @@ export const RuleManagerLive = Layer.effect(RuleManager, Effect.gen(function* ()
424
426
  aggregateProjectionObservation: Ref.get(lastProjection),
425
427
  isInstalled: ({ target }) => isObservedInstalled(ws, "rule", target.name).pipe(Effect.withSpan("RuleManager.isInstalled")),
426
428
  materializeInstall,
429
+ acquireCanonical: materializeInstall,
430
+ materializeRetained: ({ target }) => Effect.gen(function* () {
431
+ const canonical = yield* usableAcceptedCanonical({
432
+ workspace: ws,
433
+ type: "rule",
434
+ name: target.name,
435
+ });
436
+ if (Option.isNone(canonical) || canonical.value.ref.type !== "rule") {
437
+ return yield* new LifecyclePostconditionViolated({
438
+ postcondition: "materialize-observable",
439
+ targetType: "rule",
440
+ targetName: target.name,
441
+ });
442
+ }
443
+ return yield* materializeInstall({ ref: canonical.value.ref });
444
+ }),
427
445
  prepareSourceTransition: ({ ref }) => provide(prepareAcceptedCanonicalTransition({
428
446
  workspace: ws,
429
447
  type: "rule",
@@ -448,45 +466,17 @@ export const RuleManagerLive = Layer.effect(RuleManager, Effect.gen(function* ()
448
466
  }),
449
467
  materializeUninstall,
450
468
  materializeDeactivate,
451
- upsertSettingsEntry: Effect.fn("RuleManager.upsertSettingsEntry")(function* ({ ref, versionRange, materialization, }) {
452
- const lockEntry = yield* buildLockEntry(ref, materialization);
453
- if (Option.isNone(lockEntry)) {
454
- yield* ws.setRuleEntry(ref.rule.name, {
455
- source: "workspace",
456
- enabled: true,
457
- });
458
- return;
459
- }
460
- if (lockEntry.value.type === "registry") {
461
- yield* validateExactResolvedVersion(`rules.${ref.rule.name}.resolvedVersion`, lockEntry.value.resolvedVersion);
462
- }
463
- yield* ws.setRule({
464
- name: ref.rule.name,
465
- lockEntry: lockEntry.value,
466
- versionRange,
467
- });
468
- }),
469
- removeSettingsEntry: Effect.fn("RuleManager.removeSettingsEntry")(function* ({ target }) {
470
- yield* ws.removeRuleSettings(target.name);
471
- }),
472
- upsertLockfileEntry: Effect.fn("RuleManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
469
+ acceptedResolution: Effect.fn("RuleManager.acceptedResolution")(function* ({ ref, materialization, }) {
473
470
  const lockEntry = yield* buildLockEntry(ref, materialization);
474
471
  if (Option.isNone(lockEntry)) {
475
- yield* ws.removeRuleLock(ref.rule.name);
476
- return;
472
+ return Option.none();
477
473
  }
478
474
  if (lockEntry.value.type === "registry") {
479
475
  yield* validateExactResolvedVersion(`rules.${ref.rule.name}.resolvedVersion`, lockEntry.value.resolvedVersion);
480
476
  }
481
- yield* ws.setRuleLock({
482
- name: ref.rule.name,
483
- lockEntry: lockEntry.value,
484
- versionRange: Option.none(),
485
- });
486
- }),
487
- removeLockfileEntry: Effect.fn("RuleManager.removeLockfileEntry")(function* ({ target }) {
488
- yield* ws.removeRuleLock(target.name);
477
+ return Option.some({ key: ref.rule.name, entry: lockEntry.value });
489
478
  }),
479
+ withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
490
480
  };
491
481
  }));
492
482
  //# sourceMappingURL=manager.js.map
@@ -5,7 +5,8 @@
5
5
  *
6
6
  * @experimental This API is unstable and may change without notice.
7
7
  */
8
- import type { AxmSkillCompatibilityUnavailable, AxmSkillIncompatible } from "@agentxm/extension-resolution";
8
+ import type { AxmSkillCompatibilityUnavailable } from "@agentxm/cli-maintenance/official-skill/application";
9
+ import type { AxmSkillIncompatible } from "@agentxm/cli-maintenance/official-skill/domain";
9
10
  declare const SkillDefinitionInvalid_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
11
  readonly _tag: "SkillDefinitionInvalid";
11
12
  } & Readonly<A>;
@@ -1,3 +1,5 @@
1
+ import { usableAcceptedCanonical } from "@agentxm/workspace-state";
2
+ import { LifecyclePostconditionViolated } from "../extensions/errors.js";
1
3
  /**
2
4
  * Skill extension manager service.
3
5
  *
@@ -216,6 +218,45 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
216
218
  return yield* isObservedInstalled(ws, "skill", target.name);
217
219
  }),
218
220
  materializeInstall,
221
+ acquireCanonical: ({ ref, force }) => Effect.gen(function* () {
222
+ const locked = yield* ws.getLockedSkill(ref.skill.name);
223
+ const materialized = yield* materializeSkillCanonical({
224
+ ref,
225
+ sanitizedName: sanitizeName(ref.skill.name),
226
+ baseDir,
227
+ layout: ws.layout,
228
+ reuse: {
229
+ force: force === true,
230
+ lockedVersion: ref.refType === "registry" ? acceptedRegistryVersionForRef(locked, ref) : undefined,
231
+ lockedTreeIntegrity: Option.isSome(locked) ? locked.value.treeIntegrity : undefined,
232
+ },
233
+ });
234
+ const sourceHash = ref.refType === "workspace"
235
+ ? ref.sourceHash
236
+ : ref.refType === "registry"
237
+ ? yield* computePackageContentHash(path.dirname(materialized.skillSrcPath))
238
+ : yield* computeSkillSourceHash(materialized.skillSrcPath);
239
+ return {
240
+ sourceHash: Option.some(sourceHash),
241
+ treeIntegrity: Option.fromUndefinedOr(materialized.treeIntegrity),
242
+ observation: { agents: [], targets: [] },
243
+ };
244
+ }),
245
+ materializeRetained: ({ target }) => Effect.gen(function* () {
246
+ const canonical = yield* usableAcceptedCanonical({
247
+ workspace: ws,
248
+ type: "skill",
249
+ name: target.name,
250
+ });
251
+ if (Option.isNone(canonical) || canonical.value.ref.type !== "skill") {
252
+ return yield* new LifecyclePostconditionViolated({
253
+ postcondition: "materialize-observable",
254
+ targetType: "skill",
255
+ targetName: target.name,
256
+ });
257
+ }
258
+ return yield* materializeInstall({ ref: canonical.value.ref });
259
+ }),
219
260
  prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
220
261
  workspace: ws,
221
262
  type: "skill",
@@ -249,49 +290,7 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
249
290
  }),
250
291
  materializeUninstall,
251
292
  materializeDeactivate,
252
- upsertSettingsEntry: Effect.fn("SkillManager.upsertSettingsEntry")(function* ({ ref, versionRange, materialization, }) {
253
- const workspaceRelativeLocalSourcePath = ref.refType === "local"
254
- ? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
255
- : Option.none();
256
- if (ref.refType === "local" && Option.isNone(workspaceRelativeLocalSourcePath)) {
257
- return yield* new SkillDefinitionInvalid({
258
- detail: `Local skill source path must stay within the workspace root: ${ref.source.path}`,
259
- });
260
- }
261
- const sourceHash = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.sourceHash)));
262
- const treeIntegrity = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity)));
263
- if (ref.refType === "workspace") {
264
- return yield* ws.setSkillEntry(ref.skill.name, {
265
- source: "workspace",
266
- enabled: true,
267
- });
268
- }
269
- if (sourceHash === undefined || treeIntegrity === undefined) {
270
- return yield* new SkillInstallStateMissing({
271
- name: ref.skill.name,
272
- kind: "content-identity",
273
- });
274
- }
275
- const lockEntry = buildSkillLockEntry(ref, workspaceRelativeLocalSourcePath, sourceHash, treeIntegrity);
276
- if (lockEntry === undefined) {
277
- return yield* new SkillInstallStateMissing({
278
- name: ref.skill.name,
279
- kind: "external-resolution",
280
- });
281
- }
282
- if (lockEntry.type === "registry") {
283
- yield* validateExactResolvedVersion(`skills.${ref.skill.name}.resolvedVersion`, lockEntry.resolvedVersion);
284
- }
285
- return yield* ws.setSkill({
286
- name: ref.skill.name,
287
- lockEntry,
288
- versionRange,
289
- });
290
- }),
291
- removeSettingsEntry: ({ target }) => ws
292
- .removeSkillFromSettings(target.name)
293
- .pipe(Effect.withSpan("SkillManager.removeSettingsEntry")),
294
- upsertLockfileEntry: Effect.fn("SkillManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
293
+ acceptedResolution: Effect.fn("SkillManager.acceptedResolution")(function* ({ ref, materialization, }) {
295
294
  const workspaceRelativeLocalSourcePath = ref.refType === "local"
296
295
  ? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
297
296
  : Option.none();
@@ -301,8 +300,7 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
301
300
  });
302
301
  }
303
302
  if (ref.refType === "workspace") {
304
- yield* ws.removeSkillLock(ref.skill.name);
305
- return;
303
+ return Option.none();
306
304
  }
307
305
  const sourceHash = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.sourceHash)));
308
306
  const treeIntegrity = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity)));
@@ -322,15 +320,9 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
322
320
  if (lockEntry.type === "registry") {
323
321
  yield* validateExactResolvedVersion(`skills.${ref.skill.name}.resolvedVersion`, lockEntry.resolvedVersion);
324
322
  }
325
- return yield* ws.setSkillLock({
326
- name: ref.skill.name,
327
- lockEntry,
328
- versionRange: Option.none(),
329
- });
323
+ return Option.some({ key: ref.skill.name, entry: lockEntry });
330
324
  }),
331
- removeLockfileEntry: ({ target }) => ws
332
- .removeSkillLock(target.name)
333
- .pipe(Effect.withSpan("SkillManager.removeLockfileEntry")),
325
+ withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
334
326
  };
335
327
  }));
336
328
  // -----------------------------------------------------------------------------
@@ -35,10 +35,10 @@ export declare const materializeSkillCanonical: (args: {
35
35
  }) => Effect.Effect<{
36
36
  skillSrcPath: string & import("effect/Brand").Brand<"AbsolutePath">;
37
37
  treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
38
- }, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").PackageCopyFailed | import("@agentxm/extension-resolution").AxmSkillCompatibilityUnavailable | import("@agentxm/extension-resolution").AxmSkillIncompatible | import("@agentxm/workspace-state").MaterializedTreeInvalid | import("../extensions/canonical-directory.js").CanonicalDirectoryReplacementError, FileSystem.FileSystem | Path.Path> | Effect.Effect<{
38
+ }, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").PackageCopyFailed | import("@agentxm/cli-maintenance/official-skill/application").AxmSkillCompatibilityUnavailable | import("@agentxm/cli-maintenance/official-skill/domain").AxmSkillIncompatible | import("@agentxm/workspace-state").MaterializedTreeInvalid | import("../extensions/canonical-directory.js").CanonicalDirectoryReplacementError, FileSystem.FileSystem | Path.Path> | Effect.Effect<{
39
39
  skillSrcPath: string & import("effect/Brand").Brand<"AbsolutePath">;
40
40
  treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
41
- }, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").ArchiveIntegrityMismatch | import("@agentxm/extension-resolution").AxmSkillCompatibilityUnavailable | import("@agentxm/extension-resolution").AxmSkillIncompatible | import("@agentxm/workspace-state").MaterializedTreeInvalid | import("@agentxm/registry-client").RegistryClientFailure | import("../extensions/canonical-directory.js").CanonicalDirectoryReplacementError, FileSystem.FileSystem | Path.Path | import("effect/unstable/http/HttpClient").HttpClient> | Effect.Effect<MaterializedSkillCanonical, import("@agentxm/workspace-state").PathTraversalDetected | import("@agentxm/extension-resolution").AxmSkillCompatibilityUnavailable | import("@agentxm/extension-resolution").AxmSkillIncompatible, FileSystem.FileSystem | Path.Path>;
41
+ }, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").ArchiveIntegrityMismatch | import("@agentxm/cli-maintenance/official-skill/application").AxmSkillCompatibilityUnavailable | import("@agentxm/cli-maintenance/official-skill/domain").AxmSkillIncompatible | import("@agentxm/workspace-state").MaterializedTreeInvalid | import("@agentxm/registry-client").RegistryClientFailure | import("../extensions/canonical-directory.js").CanonicalDirectoryReplacementError, FileSystem.FileSystem | Path.Path | import("effect/unstable/http/HttpClient").HttpClient> | Effect.Effect<MaterializedSkillCanonical, import("@agentxm/workspace-state").PathTraversalDetected | import("@agentxm/cli-maintenance/official-skill/application").AxmSkillCompatibilityUnavailable | import("@agentxm/cli-maintenance/official-skill/domain").AxmSkillIncompatible, FileSystem.FileSystem | Path.Path>;
42
42
  export declare const ensureSkillAgentArtifact: (args: {
43
43
  readonly canonicalSkillSrcPath: string;
44
44
  readonly targetDir: string;
@@ -29,7 +29,11 @@ export declare const skillArtifactFromTargets: (args: {
29
29
  readonly change: JobStepArtifact["change"];
30
30
  readonly workspaceTargets?: ReadonlyArray<JobStepArtifactTarget>;
31
31
  }) => Effect.Effect<{
32
- targets?: JobStepArtifactTarget[];
32
+ targets?: (JobStepArtifactTarget | {
33
+ agentIds?: readonly string[];
34
+ path: string;
35
+ change: "created" | "updated" | "removed" | "unchanged";
36
+ })[];
33
37
  path: string;
34
38
  scope: "project" | "user";
35
39
  agents: readonly string[];
@@ -1,3 +1,5 @@
1
+ import { usableAcceptedCanonical } from "@agentxm/workspace-state";
2
+ import { LifecyclePostconditionViolated } from "../extensions/errors.js";
1
3
  /**
2
4
  * Subagent extension manager service.
3
5
  *
@@ -633,6 +635,31 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
633
635
  return yield* isObservedInstalled(ws, "subagent", target.name);
634
636
  }),
635
637
  materializeInstall,
638
+ acquireCanonical: ({ ref, force }) => Effect.gen(function* () {
639
+ const { sanitized, paths: { canonicalPath, subagentSrcPath }, } = getCanonicalPaths(ref);
640
+ const treeIntegrity = yield* materializeCanonical(ref, sanitized, canonicalPath, subagentSrcPath, force === true);
641
+ yield* readSubagentContent(subagentSrcPath, ref.subagent.name);
642
+ return {
643
+ sourceHash: Option.some(yield* computePackageContentHash(canonicalPath)),
644
+ treeIntegrity: Option.fromUndefinedOr(treeIntegrity),
645
+ observation: { agents: [], targets: [] },
646
+ };
647
+ }),
648
+ materializeRetained: ({ target }) => Effect.gen(function* () {
649
+ const canonical = yield* usableAcceptedCanonical({
650
+ workspace: ws,
651
+ type: "subagent",
652
+ name: target.name,
653
+ });
654
+ if (Option.isNone(canonical) || canonical.value.ref.type !== "subagent") {
655
+ return yield* new LifecyclePostconditionViolated({
656
+ postcondition: "materialize-observable",
657
+ targetType: "subagent",
658
+ targetName: target.name,
659
+ });
660
+ }
661
+ return yield* materializeInstall({ ref: canonical.value.ref });
662
+ }),
636
663
  prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
637
664
  workspace: ws,
638
665
  type: "subagent",
@@ -651,7 +678,7 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
651
678
  }),
652
679
  materializeUninstall,
653
680
  materializeDeactivate,
654
- upsertSettingsEntry: Effect.fn("SubagentManager.upsertSettingsEntry")(function* ({ ref, versionRange, materialization, }) {
681
+ acceptedResolution: Effect.fn("SubagentManager.acceptedResolution")(function* ({ ref, materialization, }) {
655
682
  const workspaceRelativeLocalSourcePath = ref.refType === "local"
656
683
  ? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
657
684
  : Option.none();
@@ -660,50 +687,8 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
660
687
  detail: `Local subagent source path must stay within the workspace root: ${ref.source.path}`,
661
688
  });
662
689
  }
663
- const state = acquiredState(materialization);
664
690
  if (ref.refType === "workspace") {
665
- return yield* ws.setSubagentEntry(ref.subagent.name, {
666
- source: "workspace",
667
- enabled: true,
668
- });
669
- }
670
- if (state === undefined) {
671
- return yield* new SubagentInstallStateMissing({
672
- name: ref.subagent.name,
673
- kind: "content-identity",
674
- });
675
- }
676
- const lockEntry = buildSubagentLockEntry(ref, state.sourceHash, state.treeIntegrity, workspaceRelativeLocalSourcePath);
677
- if (lockEntry === undefined) {
678
- return yield* new SubagentInstallStateMissing({
679
- name: ref.subagent.name,
680
- kind: "external-resolution",
681
- });
682
- }
683
- if (lockEntry.type === "registry") {
684
- yield* validateExactResolvedVersion(`subagents.${ref.subagent.name}.resolvedVersion`, lockEntry.resolvedVersion);
685
- }
686
- return yield* ws.setSubagent({
687
- name: ref.subagent.name,
688
- lockEntry,
689
- versionRange,
690
- });
691
- }),
692
- removeSettingsEntry: ({ target }) => ws
693
- .removeSubagentSettings(target.name)
694
- .pipe(Effect.withSpan("SubagentManager.removeSettingsEntry")),
695
- upsertLockfileEntry: Effect.fn("SubagentManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
696
- const workspaceRelativeLocalSourcePath = ref.refType === "local"
697
- ? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
698
- : Option.none();
699
- if (ref.refType === "local" && Option.isNone(workspaceRelativeLocalSourcePath)) {
700
- return yield* new SubagentDefinitionInvalid({
701
- detail: `Local subagent source path must stay within the workspace root: ${ref.source.path}`,
702
- });
703
- }
704
- if (ref.refType === "workspace") {
705
- yield* ws.removeSubagentLock(ref.subagent.name);
706
- return;
691
+ return Option.none();
707
692
  }
708
693
  const state = acquiredState(materialization);
709
694
  if (state === undefined) {
@@ -722,15 +707,9 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
722
707
  if (lockEntry.type === "registry") {
723
708
  yield* validateExactResolvedVersion(`subagents.${ref.subagent.name}.resolvedVersion`, lockEntry.resolvedVersion);
724
709
  }
725
- return yield* ws.setSubagentLock({
726
- name: ref.subagent.name,
727
- lockEntry,
728
- versionRange: Option.none(),
729
- });
710
+ return Option.some({ key: ref.subagent.name, entry: lockEntry });
730
711
  }),
731
- removeLockfileEntry: ({ target }) => ws
732
- .removeSubagentLock(target.name)
733
- .pipe(Effect.withSpan("SubagentManager.removeLockfileEntry")),
712
+ withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
734
713
  };
735
714
  }));
736
715
  //# sourceMappingURL=manager.js.map
@@ -1,71 +1,5 @@
1
- /**
2
- * In-memory materialization doubles for feature tests: a manager whose
3
- * surfaces are recorded rather than written, a retention policy that never
4
- * retains, and a structural serialization of a recipe's typed failure into the
5
- * plan-step vocabulary.
6
- *
7
- * These are deliberately behavioural, not mocks of a shape: a test asserts on
8
- * what the recorder observed, so a contract change that stops calling a
9
- * surface fails the test rather than passing silently.
10
- *
11
- * @experimental This API is unstable and may change without notice.
12
- * @packageDocumentation
13
- */
14
1
  import * as Layer from "effect/Layer";
15
- import * as Option from "effect/Option";
16
- import { StepFailure } from "@agentxm/workspace-operations";
17
- import type { ExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/extension-ref";
18
- import type { ExtensionTarget } from "@agentxm/workspace-state";
19
- import type { ExtensionManager, ManagerRequirements, MaterializationFacts } from "./manager-contract.js";
20
- import type { CallerStepFailure, UninstallRetentionPolicy } from "./extensions/operations.js";
21
2
  import { McpSecretStore } from "./mcps/secret-store.js";
22
- /** The manager surfaces one recipe touched, in the order it touched them. */
23
- export type RecordedManagerSurface = "materializeInstall" | "materializeUninstall" | "materializeDeactivate" | "upsertSettingsEntry" | "removeSettingsEntry" | "upsertLockfileEntry" | "removeLockfileEntry" | "listMaterializable" | "projectionPlans";
24
- /** What an in-memory manager observed while a recipe ran against it. */
25
- export interface RecordedManager<TRef extends ExtensionRef> {
26
- readonly manager: ExtensionManager<TRef, MaterializationFacts, ManagerRequirements>;
27
- /** Every surface the recipe touched, in call order. */
28
- readonly surfaces: ReadonlyArray<RecordedManagerSurface>;
29
- /** Targets currently declared in the recorder's settings. */
30
- readonly configured: ReadonlySet<string>;
31
- /** Targets currently observable as installed. */
32
- readonly installed: ReadonlySet<string>;
33
- }
34
- /**
35
- * A materialization that observed nothing and acquired nothing. It satisfies
36
- * every per-type facts shape, so a feature test that never asserts on content
37
- * identity uses one value for any manager.
38
- */
39
- export declare const NO_MATERIALIZATION_FACTS: {
40
- readonly observation: import("./manager-contract.js").MaterializationObservation;
41
- readonly treeIntegrity: Option.Option<never>;
42
- readonly sourceHash: Option.Option<never>;
43
- readonly acquired: Option.Option<never>;
44
- readonly removal: Option.Option<never>;
45
- };
46
- /**
47
- * A manager whose authoritative surfaces are in-memory sets. `materializable`
48
- * is what `listMaterializable` answers; anything installed through the
49
- * recorder becomes both configured and observable.
50
- */
51
- export declare const makeRecordedManager: <TRef extends ExtensionRef>(args: {
52
- readonly type: TRef["type"];
53
- readonly materializable: ReadonlyArray<TRef>;
54
- /** Targets already installed and declared before the recipe runs. */
55
- readonly installed?: ReadonlyArray<string>;
56
- }) => RecordedManager<TRef>;
57
- /** A retention policy that never retains a package for an installed Pack. */
58
- export declare const noUninstallRetention: UninstallRetentionPolicy;
59
- /** A retention policy that always retains, for the retained-by-pack settlement. */
60
- export declare const alwaysUninstallRetention: UninstallRetentionPolicy;
61
- /**
62
- * A structural serialization of a recipe's typed failure: the producing
63
- * family's own detail sentence under an `internal` category. Assertions bind
64
- * to this mapping, not to the application boundary's wording.
65
- */
66
- export declare const structuralStepFailure: <F>(failure: CallerStepFailure<F>) => StepFailure;
67
- /** A retention target's plan-step identity, for assertions on recorded steps. */
68
- export declare const recordedTargetName: (target: ExtensionTarget) => string;
69
3
  /** What an in-memory credential store recorded, and the layer that backs it. */
70
4
  export interface MemoryMcpSecretStore {
71
5
  readonly layer: Layer.Layer<McpSecretStore>;
@@ -1,96 +1,8 @@
1
- /**
2
- * In-memory materialization doubles for feature tests: a manager whose
3
- * surfaces are recorded rather than written, a retention policy that never
4
- * retains, and a structural serialization of a recipe's typed failure into the
5
- * plan-step vocabulary.
6
- *
7
- * These are deliberately behavioural, not mocks of a shape: a test asserts on
8
- * what the recorder observed, so a contract change that stops calling a
9
- * surface fails the test rather than passing silently.
10
- *
11
- * @experimental This API is unstable and may change without notice.
12
- * @packageDocumentation
13
- */
1
+ /** Deterministic credential storage for materialization consumers. */
14
2
  import * as Effect from "effect/Effect";
15
3
  import * as Layer from "effect/Layer";
16
4
  import * as Option from "effect/Option";
17
- import { StepFailure } from "@agentxm/workspace-operations";
18
- import { NO_MATERIALIZATION_OBSERVATION } from "./manager-contract.js";
19
- import { targetFromRef } from "./extensions/operations.js";
20
5
  import { McpSecretStore } from "./mcps/secret-store.js";
21
- /**
22
- * A materialization that observed nothing and acquired nothing. It satisfies
23
- * every per-type facts shape, so a feature test that never asserts on content
24
- * identity uses one value for any manager.
25
- */
26
- export const NO_MATERIALIZATION_FACTS = {
27
- observation: NO_MATERIALIZATION_OBSERVATION,
28
- treeIntegrity: Option.none(),
29
- sourceHash: Option.none(),
30
- acquired: Option.none(),
31
- removal: Option.none(),
32
- };
33
- const NO_FACTS = NO_MATERIALIZATION_FACTS;
34
- /**
35
- * A manager whose authoritative surfaces are in-memory sets. `materializable`
36
- * is what `listMaterializable` answers; anything installed through the
37
- * recorder becomes both configured and observable.
38
- */
39
- export const makeRecordedManager = (args) => {
40
- const surfaces = [];
41
- const configured = new Set(args.installed ?? []);
42
- const installed = new Set(args.installed ?? []);
43
- const record = (surface, effect) => Effect.sync(() => surfaces.push(surface)).pipe(Effect.andThen(effect));
44
- const manager = {
45
- type: args.type,
46
- isInstalled: ({ target }) => Effect.succeed(installed.has(target.name)),
47
- materializeInstall: ({ ref }) => record("materializeInstall", Effect.sync(() => {
48
- installed.add(targetFromRef(ref).name);
49
- return NO_FACTS;
50
- })),
51
- materializeUninstall: ({ target }) => record("materializeUninstall", Effect.sync(() => {
52
- installed.delete(target.name);
53
- return NO_FACTS;
54
- })),
55
- materializeDeactivate: () => record("materializeDeactivate", Effect.succeed(NO_FACTS)),
56
- getConfiguredSource: ({ target }) => Effect.succeed(configured.has(target.name) ? Option.some("workspace:") : Option.none()),
57
- isConfigured: ({ target }) => Effect.succeed(configured.has(target.name)),
58
- listMaterializable: () => record("listMaterializable", Effect.succeed(args.materializable)),
59
- upsertSettingsEntry: ({ ref }) => record("upsertSettingsEntry", Effect.sync(() => {
60
- configured.add(targetFromRef(ref).name);
61
- })),
62
- removeSettingsEntry: ({ target }) => record("removeSettingsEntry", Effect.sync(() => {
63
- configured.delete(target.name);
64
- })),
65
- upsertLockfileEntry: () => record("upsertLockfileEntry", Effect.void),
66
- removeLockfileEntry: () => record("removeLockfileEntry", Effect.void),
67
- };
68
- return { manager, surfaces, configured, installed };
69
- };
70
- /** A retention policy that never retains a package for an installed Pack. */
71
- export const noUninstallRetention = {
72
- isRequiredByInstalledPack: () => Effect.succeed(false),
73
- };
74
- /** A retention policy that always retains, for the retained-by-pack settlement. */
75
- export const alwaysUninstallRetention = {
76
- isRequiredByInstalledPack: () => Effect.succeed(true),
77
- };
78
- /**
79
- * A structural serialization of a recipe's typed failure: the producing
80
- * family's own detail sentence under an `internal` category. Assertions bind
81
- * to this mapping, not to the application boundary's wording.
82
- */
83
- export const structuralStepFailure = (failure) => {
84
- const detail = typeof failure === "object" &&
85
- failure !== null &&
86
- "detail" in failure &&
87
- typeof failure.detail === "string"
88
- ? failure.detail
89
- : String(failure);
90
- return new StepFailure({ category: "internal", detail, cause: failure });
91
- };
92
- /** A retention target's plan-step identity, for assertions on recorded steps. */
93
- export const recordedTargetName = (target) => target.name;
94
6
  /**
95
7
  * An in-memory credential store for MCP install tests.
96
8
  *
package/package.json CHANGED
@@ -4,16 +4,17 @@
4
4
  "url": "https://github.com/agentxm/axm/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@agentxm/agent-integration": "^0.29.4",
8
- "@agentxm/extension-content": "^0.29.4",
9
- "@agentxm/extension-model": "^0.29.4",
10
- "@agentxm/extension-resolution": "^0.29.4",
11
- "@agentxm/extension-sources": "^0.29.4",
12
- "@agentxm/registry-client": "^0.29.4",
13
- "@agentxm/workspace-operations": "^0.29.4",
14
- "@agentxm/workspace-projection": "^0.29.4",
15
- "@agentxm/workspace-state": "^0.29.4",
16
- "@agentxm/workspace-transactions": "^0.29.4",
7
+ "@agentxm/agent-integration": "^0.30.1",
8
+ "@agentxm/cli-maintenance": "^0.30.1",
9
+ "@agentxm/extension-content": "^0.30.1",
10
+ "@agentxm/extension-model": "^0.30.1",
11
+ "@agentxm/extension-resolution": "^0.30.1",
12
+ "@agentxm/extension-sources": "^0.30.1",
13
+ "@agentxm/registry-client": "^0.30.1",
14
+ "@agentxm/workspace-operations": "^0.30.1",
15
+ "@agentxm/workspace-projection": "^0.30.1",
16
+ "@agentxm/workspace-state": "^0.30.1",
17
+ "@agentxm/workspace-transactions": "^0.30.1",
17
18
  "@napi-rs/keyring": "^1.3.0",
18
19
  "effect": "4.0.0-rc.115"
19
20
  },
@@ -24,27 +25,23 @@
24
25
  "@fast-check/vitest": "^0.5.0",
25
26
  "@typescript/native": "npm:typescript@^7.0.2",
26
27
  "typescript": "npm:@typescript/typescript6@^6.0.2",
27
- "vitest": "^5.0.0",
28
- "yaml": "^2.9.0"
28
+ "vitest": "^5.0.0"
29
29
  },
30
30
  "engines": {
31
31
  "node": ">=22.19.0"
32
32
  },
33
33
  "exports": {
34
34
  ".": {
35
- "axm-source": "./src/index.ts",
36
- "default": "./dist/src/index.js",
37
- "types": "./dist/src/index.d.ts"
35
+ "types": "./dist/src/index.d.ts",
36
+ "default": "./dist/src/index.js"
38
37
  },
39
38
  "./live": {
40
- "axm-source": "./src/live.ts",
41
- "default": "./dist/src/live.js",
42
- "types": "./dist/src/live.d.ts"
39
+ "types": "./dist/src/live.d.ts",
40
+ "default": "./dist/src/live.js"
43
41
  },
44
42
  "./testing": {
45
- "axm-source": "./src/testing.ts",
46
- "default": "./dist/src/testing.js",
47
- "types": "./dist/src/testing.d.ts"
43
+ "types": "./dist/src/testing.d.ts",
44
+ "default": "./dist/src/testing.js"
48
45
  }
49
46
  },
50
47
  "files": [
@@ -67,5 +64,5 @@
67
64
  },
68
65
  "sideEffects": false,
69
66
  "type": "module",
70
- "version": "0.29.4"
67
+ "version": "0.30.1"
71
68
  }
@@ -1,22 +0,0 @@
1
- /**
2
- * Failures deciding a retained re-materialization.
3
- *
4
- * @experimental This API is unstable and may change without notice.
5
- */
6
- import * as Schema from "effect/Schema";
7
- declare const RetainedContentUnusable_base: Schema.Class<RetainedContentUnusable, Schema.TaggedStruct<"RetainedContentUnusable", {
8
- readonly extensionType: Schema.String;
9
- readonly name: Schema.String;
10
- /** The canonical observation status that made restoration impossible. */
11
- readonly status: Schema.String;
12
- }>, import("effect/Cause").YieldableError>;
13
- /**
14
- * A retained transition asked to restore content the workspace accepted, and
15
- * that content is not usable. The transition refuses rather than re-resolving
16
- * the source, because re-acquiring is a different decision than restoring.
17
- */
18
- export declare class RetainedContentUnusable extends RetainedContentUnusable_base {
19
- get detail(): string;
20
- }
21
- export {};
22
- //# sourceMappingURL=errors.d.ts.map
@@ -1,22 +0,0 @@
1
- /**
2
- * Failures deciding a retained re-materialization.
3
- *
4
- * @experimental This API is unstable and may change without notice.
5
- */
6
- import * as Schema from "effect/Schema";
7
- /**
8
- * A retained transition asked to restore content the workspace accepted, and
9
- * that content is not usable. The transition refuses rather than re-resolving
10
- * the source, because re-acquiring is a different decision than restoring.
11
- */
12
- export class RetainedContentUnusable extends Schema.TaggedError()("RetainedContentUnusable", {
13
- extensionType: Schema.String,
14
- name: Schema.String,
15
- /** The canonical observation status that made restoration impossible. */
16
- status: Schema.String,
17
- }) {
18
- get detail() {
19
- return `Cannot rematerialize retained ${this.extensionType} ${this.name}: canonical content is ${this.status}`;
20
- }
21
- }
22
- //# sourceMappingURL=errors.js.map