@agentxm/extension-lifecycle 0.30.1 → 0.30.2

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 (56) hide show
  1. package/dist/src/index.d.ts +0 -3
  2. package/dist/src/index.js +0 -2
  3. package/dist/src/install/install-extensions.d.ts +5 -5
  4. package/dist/src/install/install-extensions.js +2 -1
  5. package/dist/src/mcps/install/plan.d.ts +1 -1
  6. package/dist/src/mcps/install/plan.js +58 -1
  7. package/dist/src/packs/uninstall/plan.js +1 -1
  8. package/dist/src/skills/application/index.d.ts +42 -0
  9. package/dist/src/skills/application/index.js +37 -0
  10. package/dist/src/skills/domain/selection.d.ts +22 -0
  11. package/dist/src/skills/domain/selection.js +18 -0
  12. package/dist/src/skills/install/artifact.d.ts +4 -0
  13. package/dist/src/skills/install/artifact.js +29 -0
  14. package/dist/src/skills/install/plan.d.ts +15 -4
  15. package/dist/src/skills/install/plan.js +112 -96
  16. package/dist/src/skills/uninstall/plan.js +9 -2
  17. package/dist/src/step-failure.js +12 -0
  18. package/dist/src/subagents/application/index.d.ts +42 -0
  19. package/dist/src/subagents/application/index.js +37 -0
  20. package/dist/src/subagents/domain/selection.d.ts +22 -0
  21. package/dist/src/subagents/domain/selection.js +18 -0
  22. package/dist/src/subagents/install/plan.d.ts +2 -2
  23. package/dist/src/subagents/install/plan.js +1 -2
  24. package/dist/src/subagents/uninstall/plan.js +1 -1
  25. package/dist/src/testing.d.ts +3 -2
  26. package/dist/src/testing.js +7 -5
  27. package/dist/src/uninstall/root-intent.d.ts +1 -0
  28. package/dist/src/uninstall/root-intent.js +1 -0
  29. package/dist/src/uninstall/undesired-target.d.ts +26 -0
  30. package/dist/src/uninstall/undesired-target.js +56 -0
  31. package/dist/src/uninstall/uninstall-extensions.js +30 -6
  32. package/dist/src/update/selective/plan.d.ts +2 -3
  33. package/dist/src/update/selective/plan.js +2 -2
  34. package/dist/src/update/selective/requirements.d.ts +2 -6
  35. package/dist/src/update/selective/requirements.js +1 -3
  36. package/dist/src/update/selective/selection.js +1 -1
  37. package/dist/src/update/selective/skills.d.ts +2 -4
  38. package/dist/src/update/selective/skills.js +22 -26
  39. package/dist/src/update/selective/subagents.d.ts +1 -2
  40. package/dist/src/update/selective/subagents.js +9 -8
  41. package/dist/src/update/selective/use-case.d.ts +7 -7
  42. package/dist/src/update/selective/vocabulary.d.ts +1 -1
  43. package/dist/src/update/selector.js +1 -1
  44. package/package.json +24 -16
  45. package/dist/src/glob.d.ts +0 -35
  46. package/dist/src/glob.js +0 -75
  47. package/dist/src/install/selection-interaction.d.ts +0 -46
  48. package/dist/src/install/selection-interaction.js +0 -22
  49. package/dist/src/skills/install/selection.d.ts +0 -26
  50. package/dist/src/skills/install/selection.js +0 -41
  51. package/dist/src/skills/operations/install-result.d.ts +0 -33
  52. package/dist/src/skills/operations/install-result.js +0 -10
  53. package/dist/src/skills/operations/install.d.ts +0 -66
  54. package/dist/src/skills/operations/install.js +0 -582
  55. package/dist/src/subagents/install/selection.d.ts +0 -26
  56. package/dist/src/subagents/install/selection.js +0 -37
@@ -15,7 +15,6 @@ export type { SetActivationExecutionFailure } from "./activation/errors.js";
15
15
  export { PUBLISHER_CHANGE_CONDITION_ID, publisherChangeRiskCondition, withPublisherTrust, withPublisherTrustConditions, } from "./publisher-binding.js";
16
16
  export { InstallExtensions, prepareInstallExtensions, previewOrApplyInstallExtensions, type InstallDiagnostics, type InstallExtensionsCandidate, type InstallExtensionsFailure, type InstallExtensionsRequest, type InstallSubject, } from "./install/install-extensions.js";
17
17
  export { installRefused, type HookInstallIntent, type InstallStepRequirements, type KnowledgeInstallIntent, type McpServerInstallIntent, type PackInstallIntent, type PackRecoveryDependencyResolver, type PrepareInstallRequirements, type ResolveInstallRequirements, type RuleInstallIntent, type SkillInstallIntent, type SubagentInstallIntent, } from "./install/vocabulary.js";
18
- export { ExtensionSelectionCancelled, ExtensionSelectionInteraction, type ExtensionSelectionFailure, type ExtensionSelectionInteractionService, } from "./install/selection-interaction.js";
19
18
  export { resolveRootInstallIntent, rootInstallableTypeSegments, RootInstallableTypeSegmentSchema, type RootInstallIntent, type RootInstallableType, type RootInstallableTypeSegment, } from "./install/root-intent.js";
20
19
  export { installCommandFor, perTypeInstallPluralSegments } from "./install/per-type-install.js";
21
20
  export { buildConfiguredInstallPlan, buildConfiguredPackInstallPlan, type ConfiguredInstallPlanResult, type ConfiguredInstallRequirements, type ConfiguredInstallableType, } from "./install/configured.js";
@@ -38,8 +37,6 @@ export { resolveRootUninstallIntent, rootUninstallableTypeSegments, type RootUni
38
37
  export { PACK_UNINSTALL_GRAPH_BLOCKER_ID, packUninstallRecoveryIdentifiers, planPackUninstallGraphReadiness, type PackRetirement, type PackUninstallGraphReadiness, } from "./packs/uninstall/readiness.js";
39
38
  export { type PackUninstallIntent, type PackUninstallRequirements, type ResolvedPackUninstallTarget, } from "./packs/uninstall/plan.js";
40
39
  export { getSkillDisplayName } from "./skills/utils.js";
41
- export { gitHostedSkillArtifactSource, installSkill, type InstallSkillOperation, type InstallSkillOperationArgs, } from "./skills/operations/install.js";
42
- export type { InstallResult } from "./skills/operations/install-result.js";
43
40
  export { enableSkill, type EnableSkillOperation } from "./skills/operations/enable.js";
44
41
  export { disableSkill, type DisableSkillOperation } from "./skills/operations/disable.js";
45
42
  export { uninstallMcpServer, type UninstallMcpServerOperation, type UninstallMcpServerOperationArgs, } from "./mcps/operations/uninstall.js";
package/dist/src/index.js CHANGED
@@ -17,7 +17,6 @@ export { PUBLISHER_CHANGE_CONDITION_ID, publisherChangeRiskCondition, withPublis
17
17
  // already declares, as one use case behind every command spelling.
18
18
  export { InstallExtensions, prepareInstallExtensions, previewOrApplyInstallExtensions, } from "./install/install-extensions.js";
19
19
  export { installRefused, } from "./install/vocabulary.js";
20
- export { ExtensionSelectionCancelled, ExtensionSelectionInteraction, } from "./install/selection-interaction.js";
21
20
  export { resolveRootInstallIntent, rootInstallableTypeSegments, RootInstallableTypeSegmentSchema, } from "./install/root-intent.js";
22
21
  export { installCommandFor, perTypeInstallPluralSegments } from "./install/per-type-install.js";
23
22
  export { buildConfiguredInstallPlan, buildConfiguredPackInstallPlan, } from "./install/configured.js";
@@ -45,7 +44,6 @@ export { PACK_UNINSTALL_GRAPH_BLOCKER_ID, packUninstallRecoveryIdentifiers, plan
45
44
  export {} from "./packs/uninstall/plan.js";
46
45
  // Skill lifecycle operations
47
46
  export { getSkillDisplayName } from "./skills/utils.js";
48
- export { gitHostedSkillArtifactSource, installSkill, } from "./skills/operations/install.js";
49
47
  export { enableSkill } from "./skills/operations/enable.js";
50
48
  export { disableSkill } from "./skills/operations/disable.js";
51
49
  // MCP server lifecycle operations. Installation itself is a materialization
@@ -23,8 +23,8 @@ import type { ExtensionResolutionFailed } from "@agentxm/extension-resolution";
23
23
  import type { ExtensionLifecycleFailed } from "../errors.js";
24
24
  import { BundledAxmSkillAsset } from "../skills/install/bundled.js";
25
25
  import { type ConfiguredInstallRequirements } from "./configured.js";
26
- import type { ExtensionSelectionCancelled } from "./selection-interaction.js";
27
- import { ExtensionSelectionInteraction } from "./selection-interaction.js";
26
+ import { SkillSelectionInteraction, type SkillSelectionFailure } from "../skills/application/index.js";
27
+ import { SubagentSelectionInteraction, type SubagentSelectionFailure } from "../subagents/application/index.js";
28
28
  import { type InstallExecutionFailure, type InstallStepRequirements, type PrepareInstallRequirements } from "./vocabulary.js";
29
29
  /**
30
30
  * What the request installs: the extensions the workspace already declares,
@@ -91,9 +91,9 @@ export interface InstallExtensionsCandidate {
91
91
  * A configured entry's resolution refusal travels with its own category and
92
92
  * sentence rather than as this feature's generic refusal.
93
93
  */
94
- export type InstallExtensionsFailure = ExtensionLifecycleFailed | ExtensionResolutionFailed | ExtensionSelectionCancelled | InstallExecutionFailure;
94
+ export type InstallExtensionsFailure = ExtensionLifecycleFailed | ExtensionResolutionFailed | SkillSelectionFailure | SubagentSelectionFailure | InstallExecutionFailure;
95
95
  /** Settle an install without writing anything. */
96
- export declare const prepareInstallExtensions: (request: InstallExtensionsRequest) => Effect.Effect<InstallExtensionsCandidate, InstallExtensionsFailure, PrepareInstallRequirements | ConfiguredInstallRequirements | ExtensionSelectionInteraction | BundledAxmSkillAsset>;
96
+ export declare const prepareInstallExtensions: (request: InstallExtensionsRequest) => Effect.Effect<InstallExtensionsCandidate, InstallExtensionsFailure, PrepareInstallRequirements | ConfiguredInstallRequirements | SkillSelectionInteraction | SubagentSelectionInteraction | BundledAxmSkillAsset>;
97
97
  /**
98
98
  * Everything resolving a settled install writes through: the candidate's own
99
99
  * step requirements plus the operation boundary that presents, journals, and
@@ -104,7 +104,7 @@ export type ResolveInstallExtensionsRequirements = PrepareInstallRequirements |
104
104
  export declare const previewOrApplyInstallExtensions: (candidate: InstallExtensionsCandidate, execution: PlanExecution) => Effect.Effect<OperationResolution, InstallExtensionsFailure, ResolveInstallExtensionsRequirements>;
105
105
  /** The install use case: settle a request, then preview or apply it. */
106
106
  export declare const InstallExtensions: {
107
- readonly prepare: (request: InstallExtensionsRequest) => Effect.Effect<InstallExtensionsCandidate, InstallExtensionsFailure, PrepareInstallRequirements | ConfiguredInstallRequirements | ExtensionSelectionInteraction | BundledAxmSkillAsset>;
107
+ readonly prepare: (request: InstallExtensionsRequest) => Effect.Effect<InstallExtensionsCandidate, InstallExtensionsFailure, PrepareInstallRequirements | ConfiguredInstallRequirements | SkillSelectionInteraction | SubagentSelectionInteraction | BundledAxmSkillAsset>;
108
108
  readonly previewOrApply: (candidate: InstallExtensionsCandidate, execution: PlanExecution) => Effect.Effect<OperationResolution, InstallExtensionsFailure, ResolveInstallExtensionsRequirements>;
109
109
  };
110
110
  //# sourceMappingURL=install-extensions.d.ts.map
@@ -31,7 +31,8 @@ import { BundledAxmSkillAsset, planBundledAxmSkillInstall } from "../skills/inst
31
31
  import { buildConfiguredInstallPlan } from "./configured.js";
32
32
  import { formatRegistryProbe } from "./registry-source-resolution.js";
33
33
  import { resolveRootInstallIntent } from "./root-intent.js";
34
- import { ExtensionSelectionInteraction } from "./selection-interaction.js";
34
+ import { SkillSelectionInteraction, } from "../skills/application/index.js";
35
+ import { SubagentSelectionInteraction, } from "../subagents/application/index.js";
35
36
  import { installRefused, } from "./vocabulary.js";
36
37
  const EMPTY_DIAGNOSTICS = { resolutionLines: [], companionPackages: [] };
37
38
  const emptyPlan = (request) => ({
@@ -14,7 +14,7 @@ import { type ExtensionName, type Handle } from "@agentxm/extension-model/unstab
14
14
  import type { McpServerExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/mcp-server";
15
15
  import type { RegistrySource } from "@agentxm/extension-model/unstable/sources/types";
16
16
  import { type Plan } from "@agentxm/workspace-operations";
17
- import type { ExtensionLifecycleFailed } from "../../errors.js";
17
+ import { ExtensionLifecycleFailed } from "../../errors.js";
18
18
  import { type InstallStepRequirements, type McpServerInstallIntent, type ResolveInstallRequirements } from "../../install/vocabulary.js";
19
19
  /** An MCP install request after grammar parsing, before anything is discovered. */
20
20
  export interface ParsedMcpServerInstallRequest {
@@ -9,16 +9,21 @@
9
9
  * @experimental This API is unstable and may change without notice.
10
10
  */
11
11
  import * as Effect from "effect/Effect";
12
+ import * as FileSystem from "effect/FileSystem";
13
+ import * as Path from "effect/Path";
12
14
  import * as Option from "effect/Option";
13
15
  import * as Result from "effect/Result";
14
16
  import * as Schema from "effect/Schema";
15
- import { installMcpServer } from "@agentxm/workspace-reconciliation";
17
+ import { installMcpServer, readMcpServerManifest } from "@agentxm/workspace-reconciliation";
18
+ import { materializeRegistryPackage } from "@agentxm/extension-materialization";
19
+ import { validateManifestMcpServerTargets } from "@agentxm/agent-integration";
16
20
  import { CONFIGURABLE_AGENTS_BY_ID, } from "@agentxm/extension-model/unstable/agent-capabilities";
17
21
  import { ExtensionNameSchema, } from "@agentxm/extension-model/unstable/extensions";
18
22
  import { intersectVersionConstraints } from "@agentxm/extension-model/unstable/version-constraints";
19
23
  import { SourceHostProviders, resolveSource } from "@agentxm/extension-sources";
20
24
  import { operationPresentation } from "@agentxm/workspace-operations";
21
25
  import { WorkspaceMutations, mcpRegistryResolutionKey } from "@agentxm/workspace-state";
26
+ import { ExtensionLifecycleFailed } from "../../errors.js";
22
27
  import { lifecycleStepFailure } from "../../step-failure.js";
23
28
  import { registryLoginSuggestions } from "../../install/registry-login-suggestion.js";
24
29
  import { parseRegistryInstallTarget } from "../../install/registry-install-target.js";
@@ -267,6 +272,58 @@ export const planMcpServerInstall = Effect.fn("InstallExtensions.planMcpServer")
267
272
  });
268
273
  }
269
274
  }
275
+ yield* Effect.scoped(Effect.gen(function* () {
276
+ const fs = yield* FileSystem.FileSystem;
277
+ const path = yield* Path.Path;
278
+ const ref = intent.ref;
279
+ // Inspect verified package bytes outside the workspace. A fresh install
280
+ // has no canonical manifest for the usual projection inspection to read.
281
+ const manifestPath = ref.refType === "registry"
282
+ ? yield* Effect.gen(function* () {
283
+ const scratch = yield* fs.makeTempDirectoryScoped({ prefix: "axm-mcp-preflight-" });
284
+ return yield* materializeRegistryPackage({
285
+ baseDir: scratch,
286
+ destinationPath: path.join(scratch, "package"),
287
+ sourceLocation: ref.source.location,
288
+ owner: ref.owner,
289
+ type: "mcp-server",
290
+ name: ref.name,
291
+ version: ref.version,
292
+ integrity: ref.integrity,
293
+ messages: {
294
+ integrityMismatchDetail: `Integrity mismatch for ${ref.name}@${ref.version}`,
295
+ },
296
+ });
297
+ })
298
+ : ref.location;
299
+ const manifest = yield* readMcpServerManifest(manifestPath);
300
+ if (Option.isNone(manifest)) {
301
+ return yield* installRefused({
302
+ category: "validation",
303
+ detail: `Cannot read MCP manifest for ${intent.localName}`,
304
+ });
305
+ }
306
+ const entries = yield* ws.getConfiguredMcpServerEntries();
307
+ yield* validateManifestMcpServerTargets({
308
+ manifest: manifest.value,
309
+ agentIds: yield* ws.getConfiguredAgents(),
310
+ scope: ws.scope,
311
+ serverName: intent.localName,
312
+ values: { ...entries[intent.localName]?.env, ...intent.env },
313
+ enabled: entries[intent.localName]?.enabled ?? true,
314
+ }).pipe(Effect.mapError((cause) => installRefused({
315
+ category: "conflict",
316
+ detail: cause.reason,
317
+ recover: "Use an MCP package whose transport and symbolic inputs are supported by every configured reader of the shared target.",
318
+ cause,
319
+ })));
320
+ })).pipe(Effect.mapError((cause) => cause instanceof ExtensionLifecycleFailed
321
+ ? cause
322
+ : installRefused({
323
+ category: "validation",
324
+ detail: `Cannot inspect MCP package ${intent.localName}`,
325
+ cause,
326
+ })));
270
327
  return {
271
328
  _tag: "Plan",
272
329
  name: "Install MCP server",
@@ -19,7 +19,7 @@ import { buildUninstallOperation, prepareUninstallArtifact, collectCleanupStep,
19
19
  import { parseExtensionFqnParts, } from "@agentxm/extension-model/unstable/extensions";
20
20
  import { operationPresentation, } from "@agentxm/workspace-operations";
21
21
  import { WorkspaceMutations, decodeDesiredExtensionIdentity, } from "@agentxm/workspace-state";
22
- import { expandGlob } from "../../glob.js";
22
+ import { expandGlob } from "@agentxm/extension-model/unstable/extensions/name-patterns";
23
23
  import { lifecycleStepFailure } from "../../step-failure.js";
24
24
  import { buildAggregateProjectionStep } from "../../install/aggregate-projection-step.js";
25
25
  import { installRefused } from "../../install/vocabulary.js";
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Skills selection application contract and workflow.
3
+ * @experimental This API is unstable and may change without notice.
4
+ */
5
+ import * as Array from "effect/Array";
6
+ import * as Context from "effect/Context";
7
+ import * as Effect from "effect/Effect";
8
+ import type { SkillExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/skill";
9
+ import { type SkillSelectionRequest } from "../domain/selection.js";
10
+ declare const SkillSelectionNotFound_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 & {
11
+ readonly _tag: "SkillSelectionNotFound";
12
+ } & Readonly<A>;
13
+ export declare class SkillSelectionNotFound extends SkillSelectionNotFound_base<{
14
+ readonly requested: ReadonlyArray<string>;
15
+ readonly available: ReadonlyArray<string>;
16
+ }> {
17
+ }
18
+ declare const SkillSelectionCancelled_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 & {
19
+ readonly _tag: "SkillSelectionCancelled";
20
+ } & Readonly<A>;
21
+ export declare class SkillSelectionCancelled extends SkillSelectionCancelled_base<{
22
+ readonly message: string;
23
+ }> {
24
+ }
25
+ declare const SkillSelectionUnavailable_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 & {
26
+ readonly _tag: "SkillSelectionUnavailable";
27
+ } & Readonly<A>;
28
+ /** The interface could not obtain a choice; this is distinct from cancellation. */
29
+ export declare class SkillSelectionUnavailable extends SkillSelectionUnavailable_base<{
30
+ readonly cause?: unknown;
31
+ }> {
32
+ }
33
+ declare const SkillSelectionInteraction_base: Context.ServiceClass<SkillSelectionInteraction, "@agentxm/extension-lifecycle/skills/SkillSelectionInteraction", {
34
+ readonly select: (candidates: Array.NonEmptyReadonlyArray<SkillExtensionRef>) => Effect.Effect<ReadonlyArray<SkillExtensionRef>, SkillSelectionCancelled | SkillSelectionUnavailable>;
35
+ }>;
36
+ export declare class SkillSelectionInteraction extends SkillSelectionInteraction_base {
37
+ }
38
+ export type SkillSelectionFailure = SkillSelectionNotFound | SkillSelectionCancelled | SkillSelectionUnavailable;
39
+ /** Resolve the skill-owned decision through this capability's interaction port. */
40
+ export declare const determineSkillsToInstall: (candidates: readonly [SkillExtensionRef, ...SkillExtensionRef[]], request: SkillSelectionRequest) => Effect.Effect<readonly SkillExtensionRef[], SkillSelectionFailure, SkillSelectionInteraction>;
41
+ export {};
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Skills selection application contract and workflow.
3
+ * @experimental This API is unstable and may change without notice.
4
+ */
5
+ import * as Array from "effect/Array";
6
+ import * as Context from "effect/Context";
7
+ import * as Data from "effect/Data";
8
+ import * as Effect from "effect/Effect";
9
+ import { decideSkillSelection } from "../domain/selection.js";
10
+ export class SkillSelectionNotFound extends Data.TaggedError("SkillSelectionNotFound") {
11
+ }
12
+ export class SkillSelectionCancelled extends Data.TaggedError("SkillSelectionCancelled") {
13
+ }
14
+ /** The interface could not obtain a choice; this is distinct from cancellation. */
15
+ export class SkillSelectionUnavailable extends Data.TaggedError("SkillSelectionUnavailable") {
16
+ }
17
+ export class SkillSelectionInteraction extends Context.Service()("@agentxm/extension-lifecycle/skills/SkillSelectionInteraction") {
18
+ }
19
+ /** Resolve the skill-owned decision through this capability's interaction port. */
20
+ export const determineSkillsToInstall = Effect.fn("Skills.determineSelection")(function* (candidates, request) {
21
+ const names = Array.map(candidates, (ref) => ref.skill.name);
22
+ const decision = decideSkillSelection(names, request);
23
+ switch (decision.kind) {
24
+ case "selected":
25
+ return candidates.filter((ref) => decision.names.includes(ref.skill.name));
26
+ case "unmatched":
27
+ return yield* new SkillSelectionNotFound({
28
+ requested: request.requestedSkills,
29
+ available: names,
30
+ });
31
+ case "choice-required": {
32
+ const interaction = yield* SkillSelectionInteraction;
33
+ return yield* interaction.select(candidates);
34
+ }
35
+ }
36
+ });
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,22 @@
1
+ import type * as Array from "effect/Array";
2
+ export interface SkillSelectionRequest {
3
+ readonly requestedSkills: ReadonlyArray<string>;
4
+ readonly all: boolean;
5
+ readonly nonInteractive: boolean;
6
+ }
7
+ export type SkillSelectionDecision = {
8
+ readonly kind: "selected";
9
+ readonly names: ReadonlyArray<string>;
10
+ } | {
11
+ readonly kind: "choice-required";
12
+ } | {
13
+ readonly kind: "unmatched";
14
+ };
15
+ /**
16
+ * Select this request's skills, preserving source order.
17
+ * Named patterns take precedence over all/unattended selection. The existing
18
+ * union-of-matches behavior is retained; unresolved selector requirements remain
19
+ * explicit in the installation specification.
20
+ */
21
+ export declare const decideSkillSelection: (names: Array.NonEmptyReadonlyArray<string>, request: SkillSelectionRequest) => SkillSelectionDecision;
22
+ //# sourceMappingURL=selection.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { expandGlobs } from "@agentxm/extension-model/unstable/extensions/name-patterns";
2
+ /**
3
+ * Select this request's skills, preserving source order.
4
+ * Named patterns take precedence over all/unattended selection. The existing
5
+ * union-of-matches behavior is retained; unresolved selector requirements remain
6
+ * explicit in the installation specification.
7
+ */
8
+ export const decideSkillSelection = (names, request) => {
9
+ if (request.requestedSkills.length > 0) {
10
+ const matched = expandGlobs(request.requestedSkills, names);
11
+ return matched.length === 0 ? { kind: "unmatched" } : { kind: "selected", names: matched };
12
+ }
13
+ if (request.all || request.nonInteractive || names.length === 1) {
14
+ return { kind: "selected", names };
15
+ }
16
+ return { kind: "choice-required" };
17
+ };
18
+ //# sourceMappingURL=selection.js.map
@@ -0,0 +1,4 @@
1
+ import type { SkillExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/skill";
2
+ import type { JobStepArtifactSource } from "@agentxm/workspace-operations";
3
+ export declare const gitHostedSkillArtifactSource: (ref: SkillExtensionRef) => JobStepArtifactSource | undefined;
4
+ //# sourceMappingURL=artifact.d.ts.map
@@ -0,0 +1,29 @@
1
+ import * as Option from "effect/Option";
2
+ const gitHostedSourceOrigin = (ref) => {
3
+ const source = ref.source;
4
+ switch (source.type) {
5
+ case "github":
6
+ case "gitlab":
7
+ case "bitbucket":
8
+ return `${source.url.origin}/${source.owner}/${source.repo}`;
9
+ case "azurerepos":
10
+ return `${source.url.origin}/${source.organization}/${source.project}/_git/${source.repo}`;
11
+ case "git":
12
+ return source.url.href;
13
+ }
14
+ };
15
+ export const gitHostedSkillArtifactSource = (ref) => {
16
+ if (ref.refType !== "git-hosted")
17
+ return undefined;
18
+ const gitTreeHash = ref.gitTreeSha;
19
+ const gitRef = Option.getOrUndefined(ref.source.ref);
20
+ const directory = ref.sourcePath === undefined || ref.sourcePath.length === 0 ? "." : ref.sourcePath;
21
+ return {
22
+ type: ref.source.type,
23
+ origin: gitHostedSourceOrigin(ref),
24
+ ...(gitRef !== undefined ? { ref: gitRef } : {}),
25
+ directory,
26
+ gitTreeHash,
27
+ };
28
+ };
29
+ //# sourceMappingURL=artifact.js.map
@@ -21,12 +21,11 @@ import { type PackageUrlParts } from "@agentxm/extension-model/unstable/packagin
21
21
  import type { Source } from "@agentxm/extension-model/unstable/sources/types";
22
22
  import type { VersionRange } from "@agentxm/extension-model/unstable/version-constraints";
23
23
  import { type SourceResolutionFailure } from "@agentxm/extension-sources";
24
- import { type Plan } from "@agentxm/workspace-operations";
24
+ import { type Plan, type PlannedJobStep } from "@agentxm/workspace-operations";
25
25
  import type { ExtensionLifecycleFailed } from "../../errors.js";
26
26
  import type { RegistryLookupProbe } from "../../install/registry-source-resolution.js";
27
- import type { ExtensionSelectionCancelled } from "../../install/selection-interaction.js";
28
- import { ExtensionSelectionInteraction } from "../../install/selection-interaction.js";
29
27
  import { type InstallStepRequirements, type ResolveInstallRequirements, type SkillInstallIntent } from "../../install/vocabulary.js";
28
+ import { SkillSelectionInteraction, type SkillSelectionFailure } from "../application/index.js";
30
29
  /** A skill source after grammar parsing, before anything is discovered. */
31
30
  export interface ParsedSkillInstallRequest {
32
31
  readonly source: Source;
@@ -66,7 +65,19 @@ export declare const parseSkillInstallRequest: (args: SkillInstallArgs) => Effec
66
65
  /** Discover the skills the parsed source offers, or refuse when it has none. */
67
66
  export declare const discoverSkillRefs: (request: ParsedSkillInstallRequest) => Effect.Effect<ReadonlyArray<SkillExtensionRef>, ExtensionLifecycleFailed, ResolveInstallRequirements>;
68
67
  /** Settle which of the discovered skills this request installs. */
69
- export declare const finalizeSkillInstallIntent: (request: ParsedSkillInstallRequest, discovered: ReadonlyArray<SkillExtensionRef>) => Effect.Effect<SkillInstallIntent, ExtensionLifecycleFailed | ExtensionSelectionCancelled, ExtensionSelectionInteraction>;
68
+ export declare const finalizeSkillInstallIntent: (request: ParsedSkillInstallRequest, discovered: ReadonlyArray<SkillExtensionRef>) => Effect.Effect<SkillInstallIntent, ExtensionLifecycleFailed | SkillSelectionFailure, SkillSelectionInteraction>;
69
+ /** Installing declares intent; an update advances the resolution of existing intent. */
70
+ export type SkillInstallationStepInput = {
71
+ readonly ref: SkillExtensionRef;
72
+ readonly force: boolean;
73
+ } & ({
74
+ readonly operation: "install";
75
+ readonly versionRange: Option.Option<VersionRange>;
76
+ } | {
77
+ readonly operation: "update";
78
+ });
79
+ /** One skill-owned application step, shared by install and selective update. */
80
+ export declare const planSkillInstallationStep: (input: SkillInstallationStepInput) => Effect.Effect<PlannedJobStep<InstallStepRequirements>, ExtensionLifecycleFailed, InstallStepRequirements | SkillManager | FileSystem.FileSystem | Path.Path | HttpClient.HttpClient>;
70
81
  /** The closures a settled skill intent becomes. */
71
82
  export declare const planSkillInstall: (intent: SkillInstallIntent) => Effect.Effect<Plan<InstallStepRequirements>, ExtensionLifecycleFailed, InstallStepRequirements | SkillManager | FileSystem.FileSystem | Path.Path | HttpClient.HttpClient>;
72
83
  //# sourceMappingURL=plan.d.ts.map
@@ -28,11 +28,10 @@ import { createRegistryClient } from "@agentxm/registry-client";
28
28
  import { operationPresentation, } from "@agentxm/workspace-operations";
29
29
  import { CodingAgentRepository } from "@agentxm/workspace-projection";
30
30
  import { WorkspaceMutations, sanitizeName } from "@agentxm/workspace-state";
31
- import { gitHostedSkillArtifactSource } from "../operations/install.js";
31
+ import { gitHostedSkillArtifactSource } from "./artifact.js";
32
32
  import { lifecycleStepFailure } from "../../step-failure.js";
33
- import { ExtensionSelectionInteraction } from "../../install/selection-interaction.js";
34
33
  import { installRefused, } from "../../install/vocabulary.js";
35
- import { determineSkillsToInstall } from "./selection.js";
34
+ import { determineSkillsToInstall, SkillSelectionInteraction, } from "../application/index.js";
36
35
  import { resolveSkillInstallSource } from "./source.js";
37
36
  const noSkillsFoundHowToFix = (source) => {
38
37
  if (source.type === "registry") {
@@ -317,104 +316,121 @@ const targetChangeBeforeInstall = (args) => Effect.gen(function* () {
317
316
  const exists = yield* fs.exists(args.linkPath).pipe(Effect.catch(() => Effect.succeed(false)));
318
317
  return exists ? "updated" : "created";
319
318
  });
320
- /** The closures a settled skill intent becomes. */
321
- export const planSkillInstall = Effect.fn("InstallExtensions.planSkills")(function* (intent) {
319
+ /** One skill-owned application step, shared by install and selective update. */
320
+ export const planSkillInstallationStep = (input) => Effect.gen(function* () {
322
321
  const ws = yield* WorkspaceMutations;
323
322
  const skillManager = yield* SkillManager;
324
323
  const agentRepo = yield* CodingAgentRepository;
325
324
  const fs = yield* FileSystem.FileSystem;
326
325
  const path = yield* Path.Path;
327
- const steps = yield* Effect.forEach(intent.skillsToInstall, (entry) => Effect.gen(function* () {
328
- const ref = entry.ref;
329
- const previousLockEntry = yield* ws
330
- .getLockedSkill(ref.skill.name)
331
- .pipe(Effect.catch(() => Effect.succeed(Option.none())));
332
- const previousVersion = Option.match(previousLockEntry, {
333
- onNone: () => undefined,
334
- onSome: previousResolvedVersion,
335
- });
336
- const { skillSrcPath } = yield* ws.getSkillDir(ref.skill.name, skillPathSourceFor(ref));
337
- const sourceHashBeforeInstall = Option.match(previousLockEntry, {
338
- onNone: () => undefined,
339
- onSome: previousSourceHash,
340
- }) ??
341
- (yield* Effect.gen(function* () {
342
- const exists = yield* fs
343
- .exists(skillSrcPath)
344
- .pipe(Effect.catch(() => Effect.succeed(false)));
345
- if (!exists)
346
- return undefined;
347
- return yield* computeSkillSourceHash(skillSrcPath);
348
- }));
349
- const configuredAgents = yield* agentRepo.getMaterializationAgents();
350
- const resolvedAgents = yield* Effect.forEach(configuredAgents, (agent) => agent
351
- .resolveEffectiveSkillsDir({ workspaceRoot: ws.baseDir })
352
- .pipe(Effect.map((outcome) => ({ agentId: agent.id, outcome }))), { concurrency: "unbounded" });
353
- const sanitizedName = sanitizeName(ref.skill.name);
354
- const installableTargets = resolvedAgents.flatMap(({ agentId, outcome }) => outcome._tag === "supported"
355
- ? [{ agentId, targetDir: path.normalize(outcome.dir) }]
356
- : []);
357
- const targetLocations = yield* groupInstallTargetsByDirectory(installableTargets, ws.baseDir);
358
- const artifactAgents = artifactAgentIdsFromTargets(installableTargets);
359
- const targets = yield* Effect.forEach(targetLocations, (location) => {
360
- const linkPath = path.join(location.targetDir, sanitizedName);
361
- return targetChangeBeforeInstall({
362
- linkPath,
363
- canonicalSkillSrcPath: skillSrcPath,
364
- }).pipe(Effect.map((change) => {
365
- const agentIds = artifactTargetAgentIds(location.agentIds);
366
- return {
367
- path: path.relative(ws.baseDir, linkPath),
368
- change,
369
- ...(agentIds.length > 0 ? { agentIds } : {}),
370
- };
371
- }));
372
- }, { concurrency: "unbounded" });
373
- const firstTarget = targets[0];
374
- const rawDisplayPath = firstTarget === undefined ? path.relative(ws.baseDir, skillSrcPath) : firstTarget.path;
375
- const version = ref.refType === "registry" ? ref.version : undefined;
376
- const installedBefore = yield* skillManager
377
- .isInstalled({ target: { type: "skill", name: ref.skill.name } })
378
- .pipe(Effect.catch(() => Effect.succeed(false)));
379
- const releaseAgeWarning = yield* brandNewReleaseAgeWarning(ref, installedBefore);
380
- return withPlanWarning(buildInstallOperation(skillManager, {
381
- toStepFailure: lifecycleStepFailure,
382
- ref,
383
- declaration: { name: ref.skill.name, versionRange: entry.versionRange },
384
- force: intent.force === true,
385
- installedBefore: Effect.succeed(installedBefore),
386
- buildArtifact: ({ installedBefore }) => Effect.gen(function* () {
387
- const fileCount = yield* countFiles(fs, path, skillSrcPath);
388
- const currentSourceHash = yield* computeSkillSourceHash(skillSrcPath);
389
- const sameVersion = previousVersion === version;
390
- const sameSource = sourceHashBeforeInstall === currentSourceHash;
391
- const fallbackChange = !installedBefore
392
- ? "created"
393
- : sameVersion && sameSource
394
- ? "unchanged"
395
- : "updated";
396
- const artifactChange = artifactChangeFromTargets(fallbackChange, targets);
397
- const sourceDetails = gitHostedSkillArtifactSource(ref);
398
- return {
399
- path: rawDisplayPath.length === 0 ? "." : rawDisplayPath,
400
- scope: ws.scope,
401
- agents: artifactAgents,
402
- ...(version !== undefined ? { version } : {}),
403
- change: artifactChange,
404
- ...(previousVersion !== undefined && previousVersion !== version
405
- ? { previousVersion }
406
- : {}),
407
- fileCount,
408
- ...(targets.length > 0 ? { targets } : {}),
409
- ...(sourceDetails !== undefined ? { source: sourceDetails } : {}),
410
- };
411
- }),
412
- }), releaseAgeWarning);
413
- }).pipe(Effect.mapError((cause) => installRefused({
414
- category: "internal",
415
- detail: `Skill install planning failed for ${entry.ref.skill.name}`,
416
- cause,
417
- }))), { concurrency: 1 });
326
+ const ref = input.ref;
327
+ const previousLockEntry = yield* ws
328
+ .getLockedSkill(ref.skill.name)
329
+ .pipe(Effect.catch(() => Effect.succeed(Option.none())));
330
+ const previousVersion = Option.match(previousLockEntry, {
331
+ onNone: () => undefined,
332
+ onSome: previousResolvedVersion,
333
+ });
334
+ const { skillSrcPath } = yield* ws.getSkillDir(ref.skill.name, skillPathSourceFor(ref));
335
+ const sourceHashBeforeInstall = Option.match(previousLockEntry, {
336
+ onNone: () => undefined,
337
+ onSome: previousSourceHash,
338
+ }) ??
339
+ (yield* Effect.gen(function* () {
340
+ const exists = yield* fs
341
+ .exists(skillSrcPath)
342
+ .pipe(Effect.catch(() => Effect.succeed(false)));
343
+ if (!exists)
344
+ return undefined;
345
+ return yield* computeSkillSourceHash(skillSrcPath);
346
+ }));
347
+ const configuredAgents = yield* agentRepo.getMaterializationAgents();
348
+ const resolvedAgents = yield* Effect.forEach(configuredAgents, (agent) => agent
349
+ .resolveEffectiveSkillsDir({ workspaceRoot: ws.baseDir })
350
+ .pipe(Effect.map((outcome) => ({ agentId: agent.id, outcome }))), { concurrency: "unbounded" });
351
+ const unknownAgents = yield* agentRepo.getUnknownConfiguredAgentIds();
352
+ const skippedAgents = resolvedAgents.flatMap(({ agentId, outcome }) => outcome._tag === "unsupported" || outcome._tag === "disabled"
353
+ ? [`${agentId}: ${outcome.reason}`]
354
+ : []);
355
+ const warnings = [
356
+ ...(unknownAgents.length === 0
357
+ ? []
358
+ : [`Skipping unknown configured agents: ${unknownAgents.join(", ")}`]),
359
+ ...(skippedAgents.length === 0
360
+ ? []
361
+ : [`Skipping non-installable configured agents: ${skippedAgents.join(", ")}`]),
362
+ ];
363
+ const sanitizedName = sanitizeName(ref.skill.name);
364
+ const installableTargets = resolvedAgents.flatMap(({ agentId, outcome }) => outcome._tag === "supported" ? [{ agentId, targetDir: path.normalize(outcome.dir) }] : []);
365
+ const targetLocations = yield* groupInstallTargetsByDirectory(installableTargets, ws.baseDir);
366
+ const artifactAgents = artifactAgentIdsFromTargets(installableTargets);
367
+ const targets = yield* Effect.forEach(targetLocations, (location) => {
368
+ const linkPath = path.join(location.targetDir, sanitizedName);
369
+ return targetChangeBeforeInstall({
370
+ linkPath,
371
+ canonicalSkillSrcPath: skillSrcPath,
372
+ }).pipe(Effect.map((change) => {
373
+ const agentIds = artifactTargetAgentIds(location.agentIds);
374
+ return {
375
+ path: path.relative(ws.baseDir, linkPath),
376
+ change,
377
+ ...(agentIds.length > 0 ? { agentIds } : {}),
378
+ };
379
+ }));
380
+ }, { concurrency: "unbounded" });
381
+ const firstTarget = targets[0];
382
+ const rawDisplayPath = firstTarget === undefined ? path.relative(ws.baseDir, skillSrcPath) : firstTarget.path;
383
+ const version = ref.refType === "registry" ? ref.version : undefined;
384
+ const installedBefore = yield* skillManager
385
+ .isInstalled({ target: { type: "skill", name: ref.skill.name } })
386
+ .pipe(Effect.catch(() => Effect.succeed(false)));
387
+ const releaseAgeWarning = input.operation === "install"
388
+ ? yield* brandNewReleaseAgeWarning(ref, installedBefore)
389
+ : Option.none();
390
+ const step = withPlanWarning(buildInstallOperation(skillManager, {
391
+ toStepFailure: lifecycleStepFailure,
392
+ ref,
393
+ ...(input.operation === "install"
394
+ ? { declaration: { name: ref.skill.name, versionRange: input.versionRange } }
395
+ : {}),
396
+ force: input.force,
397
+ installedBefore: Effect.succeed(installedBefore),
398
+ buildArtifact: ({ installedBefore }) => Effect.gen(function* () {
399
+ const fileCount = yield* countFiles(fs, path, skillSrcPath);
400
+ const currentSourceHash = yield* computeSkillSourceHash(skillSrcPath);
401
+ const sameVersion = previousVersion === version;
402
+ const sameSource = sourceHashBeforeInstall === currentSourceHash;
403
+ const fallbackChange = !installedBefore
404
+ ? "created"
405
+ : sameVersion && sameSource
406
+ ? "unchanged"
407
+ : "updated";
408
+ const artifactChange = artifactChangeFromTargets(fallbackChange, targets);
409
+ const sourceDetails = gitHostedSkillArtifactSource(ref);
410
+ return {
411
+ path: rawDisplayPath.length === 0 ? "." : rawDisplayPath,
412
+ scope: ws.scope,
413
+ agents: artifactAgents,
414
+ ...(version !== undefined ? { version } : {}),
415
+ change: artifactChange,
416
+ ...(previousVersion !== undefined && previousVersion !== version
417
+ ? { previousVersion }
418
+ : {}),
419
+ fileCount,
420
+ ...(targets.length > 0 ? { targets } : {}),
421
+ ...(sourceDetails !== undefined ? { source: sourceDetails } : {}),
422
+ };
423
+ }),
424
+ }), releaseAgeWarning);
425
+ return warnings.length === 0 ? step : withPlanWarning(step, Option.some(warnings.join("; ")));
426
+ }).pipe(Effect.mapError((cause) => installRefused({
427
+ category: "internal",
428
+ detail: `Skill install planning failed for ${input.ref.skill.name}`,
429
+ cause,
430
+ })), Effect.withSpan("SkillInstallation.planStep"));
431
+ /** The closures a settled skill intent becomes. */
432
+ export const planSkillInstall = Effect.fn("InstallExtensions.planSkills")(function* (intent) {
433
+ const steps = yield* Effect.forEach(intent.skillsToInstall, (entry) => planSkillInstallationStep({ ...entry, operation: "install", force: intent.force === true }), { concurrency: 1 });
418
434
  return {
419
435
  _tag: "Plan",
420
436
  name: intent.skillsToInstall.length === 0