@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.
- package/dist/src/index.d.ts +0 -3
- package/dist/src/index.js +0 -2
- package/dist/src/install/install-extensions.d.ts +5 -5
- package/dist/src/install/install-extensions.js +2 -1
- package/dist/src/mcps/install/plan.d.ts +1 -1
- package/dist/src/mcps/install/plan.js +58 -1
- package/dist/src/packs/uninstall/plan.js +1 -1
- package/dist/src/skills/application/index.d.ts +42 -0
- package/dist/src/skills/application/index.js +37 -0
- package/dist/src/skills/domain/selection.d.ts +22 -0
- package/dist/src/skills/domain/selection.js +18 -0
- package/dist/src/skills/install/artifact.d.ts +4 -0
- package/dist/src/skills/install/artifact.js +29 -0
- package/dist/src/skills/install/plan.d.ts +15 -4
- package/dist/src/skills/install/plan.js +112 -96
- package/dist/src/skills/uninstall/plan.js +9 -2
- package/dist/src/step-failure.js +12 -0
- package/dist/src/subagents/application/index.d.ts +42 -0
- package/dist/src/subagents/application/index.js +37 -0
- package/dist/src/subagents/domain/selection.d.ts +22 -0
- package/dist/src/subagents/domain/selection.js +18 -0
- package/dist/src/subagents/install/plan.d.ts +2 -2
- package/dist/src/subagents/install/plan.js +1 -2
- package/dist/src/subagents/uninstall/plan.js +1 -1
- package/dist/src/testing.d.ts +3 -2
- package/dist/src/testing.js +7 -5
- package/dist/src/uninstall/root-intent.d.ts +1 -0
- package/dist/src/uninstall/root-intent.js +1 -0
- package/dist/src/uninstall/undesired-target.d.ts +26 -0
- package/dist/src/uninstall/undesired-target.js +56 -0
- package/dist/src/uninstall/uninstall-extensions.js +30 -6
- package/dist/src/update/selective/plan.d.ts +2 -3
- package/dist/src/update/selective/plan.js +2 -2
- package/dist/src/update/selective/requirements.d.ts +2 -6
- package/dist/src/update/selective/requirements.js +1 -3
- package/dist/src/update/selective/selection.js +1 -1
- package/dist/src/update/selective/skills.d.ts +2 -4
- package/dist/src/update/selective/skills.js +22 -26
- package/dist/src/update/selective/subagents.d.ts +1 -2
- package/dist/src/update/selective/subagents.js +9 -8
- package/dist/src/update/selective/use-case.d.ts +7 -7
- package/dist/src/update/selective/vocabulary.d.ts +1 -1
- package/dist/src/update/selector.js +1 -1
- package/package.json +24 -16
- package/dist/src/glob.d.ts +0 -35
- package/dist/src/glob.js +0 -75
- package/dist/src/install/selection-interaction.d.ts +0 -46
- package/dist/src/install/selection-interaction.js +0 -22
- package/dist/src/skills/install/selection.d.ts +0 -26
- package/dist/src/skills/install/selection.js +0 -41
- package/dist/src/skills/operations/install-result.d.ts +0 -33
- package/dist/src/skills/operations/install-result.js +0 -10
- package/dist/src/skills/operations/install.d.ts +0 -66
- package/dist/src/skills/operations/install.js +0 -582
- package/dist/src/subagents/install/selection.d.ts +0 -26
- package/dist/src/subagents/install/selection.js +0 -37
|
@@ -15,9 +15,10 @@ import * as Path from "effect/Path";
|
|
|
15
15
|
import { SkillManager, skillArtifactFromTargets, } from "@agentxm/extension-materialization";
|
|
16
16
|
import { buildUninstallOperation } from "@agentxm/workspace-reconciliation";
|
|
17
17
|
import { resolveInstalledIdentifierNameOrInput } from "@agentxm/extension-sources";
|
|
18
|
+
import { parseExtensionFqnParts } from "@agentxm/extension-model/unstable/extensions";
|
|
18
19
|
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
19
20
|
import { WorkspaceMutations, acquiredExtensionDisplayPathFromLockEntry, installedRowsByName, sanitizeName, } from "@agentxm/workspace-state";
|
|
20
|
-
import { expandGlob } from "
|
|
21
|
+
import { expandGlob } from "@agentxm/extension-model/unstable/extensions/name-patterns";
|
|
21
22
|
import { lifecycleStepFailure } from "../../step-failure.js";
|
|
22
23
|
import { installRefused, } from "../../install/vocabulary.js";
|
|
23
24
|
import { makeWorkspaceRetentionPolicy } from "@agentxm/workspace-reconciliation";
|
|
@@ -48,13 +49,19 @@ export const parseSkillUninstallRequest = Effect.fn("UninstallExtensions.parseSk
|
|
|
48
49
|
if (selector.includes("*") && matched.length === 0) {
|
|
49
50
|
return { targets: [] };
|
|
50
51
|
}
|
|
52
|
+
// An identifier nothing installed answers to still names one skill: its
|
|
53
|
+
// extension name, never the fully qualified spelling as a name.
|
|
54
|
+
const unresolvedName = (input) => {
|
|
55
|
+
const fqn = parseExtensionFqnParts(input);
|
|
56
|
+
return fqn?.type === "skill" ? fqn.name : input;
|
|
57
|
+
};
|
|
51
58
|
const names = matched.length > 0
|
|
52
59
|
? matched
|
|
53
60
|
: [
|
|
54
61
|
yield* resolveInstalledIdentifierNameOrInput({
|
|
55
62
|
input: selector,
|
|
56
63
|
resourceType: "skill",
|
|
57
|
-
}).pipe(Effect.mapError((cause) => installRefused({
|
|
64
|
+
}).pipe(Effect.map((name) => (name === selector.trim() ? unresolvedName(name) : name)), Effect.mapError((cause) => installRefused({
|
|
58
65
|
category: "not_found",
|
|
59
66
|
detail: `Skill "${selector}" could not be resolved`,
|
|
60
67
|
cause,
|
package/dist/src/step-failure.js
CHANGED
|
@@ -85,6 +85,18 @@ const carriedFailure = (failure) => {
|
|
|
85
85
|
export const lifecycleStepFailure = (failure) => {
|
|
86
86
|
if (failure instanceof StepFailure)
|
|
87
87
|
return failure;
|
|
88
|
+
if (failure._tag === "McpSharedTargetConflict") {
|
|
89
|
+
return new StepFailure({
|
|
90
|
+
category: "conflict",
|
|
91
|
+
detail: failure.reason,
|
|
92
|
+
suggestions: [
|
|
93
|
+
{
|
|
94
|
+
description: "Use an MCP package whose transport and symbolic inputs are supported by every configured reader of the shared target.",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
cause: failure,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
88
100
|
if (failure instanceof ExtensionLifecycleFailed) {
|
|
89
101
|
return new StepFailure({
|
|
90
102
|
category: failure.category,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagents 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 { SubagentExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/subagent";
|
|
9
|
+
import { type SubagentSelectionRequest } from "../domain/selection.js";
|
|
10
|
+
declare const SubagentSelectionNotFound_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: "SubagentSelectionNotFound";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
export declare class SubagentSelectionNotFound extends SubagentSelectionNotFound_base<{
|
|
14
|
+
readonly requested: ReadonlyArray<string>;
|
|
15
|
+
readonly available: ReadonlyArray<string>;
|
|
16
|
+
}> {
|
|
17
|
+
}
|
|
18
|
+
declare const SubagentSelectionCancelled_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: "SubagentSelectionCancelled";
|
|
20
|
+
} & Readonly<A>;
|
|
21
|
+
export declare class SubagentSelectionCancelled extends SubagentSelectionCancelled_base<{
|
|
22
|
+
readonly message: string;
|
|
23
|
+
}> {
|
|
24
|
+
}
|
|
25
|
+
declare const SubagentSelectionUnavailable_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: "SubagentSelectionUnavailable";
|
|
27
|
+
} & Readonly<A>;
|
|
28
|
+
/** The interface could not obtain a choice; this is distinct from cancellation. */
|
|
29
|
+
export declare class SubagentSelectionUnavailable extends SubagentSelectionUnavailable_base<{
|
|
30
|
+
readonly cause?: unknown;
|
|
31
|
+
}> {
|
|
32
|
+
}
|
|
33
|
+
declare const SubagentSelectionInteraction_base: Context.ServiceClass<SubagentSelectionInteraction, "@agentxm/extension-lifecycle/subagents/SubagentSelectionInteraction", {
|
|
34
|
+
readonly select: (candidates: Array.NonEmptyReadonlyArray<SubagentExtensionRef>) => Effect.Effect<ReadonlyArray<SubagentExtensionRef>, SubagentSelectionCancelled | SubagentSelectionUnavailable>;
|
|
35
|
+
}>;
|
|
36
|
+
export declare class SubagentSelectionInteraction extends SubagentSelectionInteraction_base {
|
|
37
|
+
}
|
|
38
|
+
export type SubagentSelectionFailure = SubagentSelectionNotFound | SubagentSelectionCancelled | SubagentSelectionUnavailable;
|
|
39
|
+
/** Resolve the subagent-owned decision through this capability's interaction port. */
|
|
40
|
+
export declare const determineSubagentsToInstall: (candidates: readonly [SubagentExtensionRef, ...SubagentExtensionRef[]], request: SubagentSelectionRequest) => Effect.Effect<readonly SubagentExtensionRef[], SubagentSelectionFailure, SubagentSelectionInteraction>;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagents 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 { decideSubagentSelection } from "../domain/selection.js";
|
|
10
|
+
export class SubagentSelectionNotFound extends Data.TaggedError("SubagentSelectionNotFound") {
|
|
11
|
+
}
|
|
12
|
+
export class SubagentSelectionCancelled extends Data.TaggedError("SubagentSelectionCancelled") {
|
|
13
|
+
}
|
|
14
|
+
/** The interface could not obtain a choice; this is distinct from cancellation. */
|
|
15
|
+
export class SubagentSelectionUnavailable extends Data.TaggedError("SubagentSelectionUnavailable") {
|
|
16
|
+
}
|
|
17
|
+
export class SubagentSelectionInteraction extends Context.Service()("@agentxm/extension-lifecycle/subagents/SubagentSelectionInteraction") {
|
|
18
|
+
}
|
|
19
|
+
/** Resolve the subagent-owned decision through this capability's interaction port. */
|
|
20
|
+
export const determineSubagentsToInstall = Effect.fn("Subagents.determineSelection")(function* (candidates, request) {
|
|
21
|
+
const names = Array.map(candidates, (ref) => ref.subagent.name);
|
|
22
|
+
const decision = decideSubagentSelection(names, request);
|
|
23
|
+
switch (decision.kind) {
|
|
24
|
+
case "selected":
|
|
25
|
+
return candidates.filter((ref) => decision.names.includes(ref.subagent.name));
|
|
26
|
+
case "unmatched":
|
|
27
|
+
return yield* new SubagentSelectionNotFound({
|
|
28
|
+
requested: request.requestedSubagents,
|
|
29
|
+
available: names,
|
|
30
|
+
});
|
|
31
|
+
case "choice-required": {
|
|
32
|
+
const interaction = yield* SubagentSelectionInteraction;
|
|
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 SubagentSelectionRequest {
|
|
3
|
+
readonly requestedSubagents: ReadonlyArray<string>;
|
|
4
|
+
readonly all: boolean;
|
|
5
|
+
readonly nonInteractive: boolean;
|
|
6
|
+
}
|
|
7
|
+
export type SubagentSelectionDecision = {
|
|
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 subagents, 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 decideSubagentSelection: (names: Array.NonEmptyReadonlyArray<string>, request: SubagentSelectionRequest) => SubagentSelectionDecision;
|
|
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 subagents, 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 decideSubagentSelection = (names, request) => {
|
|
9
|
+
if (request.requestedSubagents.length > 0) {
|
|
10
|
+
const matched = expandGlobs(request.requestedSubagents, 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
|
|
@@ -18,8 +18,8 @@ import { type SourceResolutionFailure } from "@agentxm/extension-sources";
|
|
|
18
18
|
import { type Plan } from "@agentxm/workspace-operations";
|
|
19
19
|
import type { ExtensionLifecycleFailed } from "../../errors.js";
|
|
20
20
|
import { type RegistryLookupProbe } from "../../install/registry-source-resolution.js";
|
|
21
|
-
import { ExtensionSelectionInteraction, type ExtensionSelectionCancelled } from "../../install/selection-interaction.js";
|
|
22
21
|
import { type InstallStepRequirements, type ResolveInstallRequirements, type SubagentInstallIntent } from "../../install/vocabulary.js";
|
|
22
|
+
import { SubagentSelectionInteraction, type SubagentSelectionFailure } from "../application/index.js";
|
|
23
23
|
/** A subagent source after grammar parsing, before anything is discovered. */
|
|
24
24
|
export interface ParsedSubagentInstallRequest {
|
|
25
25
|
readonly source: Source;
|
|
@@ -43,7 +43,7 @@ export declare const parseSubagentInstallRequest: (args: SubagentInstallArgs) =>
|
|
|
43
43
|
/** Discover the subagents the parsed source offers, or refuse when it has none. */
|
|
44
44
|
export declare const discoverSubagentRefs: (request: ParsedSubagentInstallRequest) => Effect.Effect<ReadonlyArray<SubagentExtensionRef>, ExtensionLifecycleFailed, ResolveInstallRequirements>;
|
|
45
45
|
/** Settle which of the discovered subagents this request installs. */
|
|
46
|
-
export declare const finalizeSubagentInstallIntent: (request: ParsedSubagentInstallRequest, discovered: ReadonlyArray<SubagentExtensionRef>) => Effect.Effect<SubagentInstallIntent, ExtensionLifecycleFailed |
|
|
46
|
+
export declare const finalizeSubagentInstallIntent: (request: ParsedSubagentInstallRequest, discovered: ReadonlyArray<SubagentExtensionRef>) => Effect.Effect<SubagentInstallIntent, ExtensionLifecycleFailed | SubagentSelectionFailure, SubagentSelectionInteraction>;
|
|
47
47
|
/** The closures a settled subagent intent becomes. */
|
|
48
48
|
export declare const planSubagentInstall: (intent: SubagentInstallIntent) => Effect.Effect<Plan<InstallStepRequirements>, ExtensionLifecycleFailed, InstallStepRequirements | SubagentManager>;
|
|
49
49
|
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -19,9 +19,8 @@ import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
|
19
19
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
20
20
|
import { lifecycleStepFailure } from "../../step-failure.js";
|
|
21
21
|
import { sourceFailureDetail, } from "../../install/registry-source-resolution.js";
|
|
22
|
-
import { ExtensionSelectionInteraction, } from "../../install/selection-interaction.js";
|
|
23
22
|
import { installRefused, } from "../../install/vocabulary.js";
|
|
24
|
-
import { determineSubagentsToInstall } from "
|
|
23
|
+
import { determineSubagentsToInstall, SubagentSelectionInteraction, } from "../application/index.js";
|
|
25
24
|
import { resolveSubagentInstallSource } from "./source.js";
|
|
26
25
|
const isRemoteReadNotImplemented = (error) => sourceFailureDetail(error).includes("not implemented");
|
|
27
26
|
const discoverHowToFix = (source, error) => {
|
|
@@ -13,7 +13,7 @@ import { NO_MATERIALIZATION_OBSERVATION, SubagentManager, } from "@agentxm/exten
|
|
|
13
13
|
import { buildUninstallOperation } from "@agentxm/workspace-reconciliation";
|
|
14
14
|
import { parseExtensionFqnParts } from "@agentxm/extension-model/unstable/extensions";
|
|
15
15
|
import { WorkspaceMutations, acquiredExtensionDisplayPathFromLockEntry, } from "@agentxm/workspace-state";
|
|
16
|
-
import { expandGlob } from "
|
|
16
|
+
import { expandGlob } from "@agentxm/extension-model/unstable/extensions/name-patterns";
|
|
17
17
|
import { lifecycleStepFailure } from "../../step-failure.js";
|
|
18
18
|
import { installRefused } from "../../install/vocabulary.js";
|
|
19
19
|
import { makeWorkspaceRetentionPolicy } from "@agentxm/workspace-reconciliation";
|
package/dist/src/testing.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace
|
|
|
18
18
|
import { ReleaseAgePosture } from "@agentxm/extension-resolution";
|
|
19
19
|
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
20
20
|
import { type ResolvePlanInteractionTestState } from "@agentxm/workspace-operations/testing";
|
|
21
|
-
import {
|
|
21
|
+
import { SkillSelectionInteraction } from "./skills/application/index.js";
|
|
22
|
+
import { SubagentSelectionInteraction } from "./subagents/application/index.js";
|
|
22
23
|
import { BundledAxmSkillAsset } from "./skills/install/bundled.js";
|
|
23
24
|
import { StepFailureConversion } from "./step-failure-conversion.js";
|
|
24
25
|
/**
|
|
@@ -99,7 +100,7 @@ export declare const makeLifecycleFixture: (options?: LifecycleFixtureOptions) =
|
|
|
99
100
|
readonly type: "skill" | "subagent";
|
|
100
101
|
readonly offered: ReadonlyArray<string>;
|
|
101
102
|
}>;
|
|
102
|
-
provide: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | import("@agentxm/workspace-state").WorkspaceMutationsError, import("effect/FileSystem").FileSystem | import("effect/Path").Path | Exclude<R, StepFailureConversion | import("@agentxm/workspace-state").WorkspaceMutations | import("@agentxm/workspace-transactions").WorkspaceTransactionScope | import("@agentxm/workspace-projection").CodingAgentRepository | import("@agentxm/agent-integration").NativeWriteAuthority | HttpClient.HttpClient | import("@agentxm/workspace-state").ConfiguredAgentOutcomesProvider | import("@agentxm/extension-materialization").ExtensionManagers | import("@agentxm/extension-materialization").HookManager | import("@agentxm/extension-materialization").SkillManager | import("@agentxm/extension-materialization").RuleManager | import("@agentxm/extension-materialization").KnowledgeManager | import("@agentxm/extension-materialization").PackManager | import("@agentxm/extension-materialization").McpServerManager | import("@agentxm/workspace-transactions").FootprintRecorder | import("@agentxm/workspace-operations").OperationJournal | import("@agentxm/extension-materialization").McpSecretStore | ReleaseAgePosture | import("@agentxm/workspace-operations").ResolvePlanInteraction | SourceHostProviders | import("@agentxm/extension-materialization").SubagentManager | import("@agentxm/extension-sources").WorkspaceCatalog | import("@agentxm/workspace-projection").WorkspaceInvariantFacts |
|
|
103
|
+
provide: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | import("@agentxm/workspace-state").WorkspaceMutationsError, import("effect/FileSystem").FileSystem | import("effect/Path").Path | Exclude<R, StepFailureConversion | import("@agentxm/workspace-state").WorkspaceMutations | import("@agentxm/workspace-transactions").WorkspaceTransactionScope | import("@agentxm/workspace-projection").CodingAgentRepository | import("@agentxm/agent-integration").NativeWriteAuthority | HttpClient.HttpClient | import("@agentxm/workspace-state").ConfiguredAgentOutcomesProvider | import("@agentxm/extension-materialization").ExtensionManagers | import("@agentxm/extension-materialization").HookManager | import("@agentxm/extension-materialization").SkillManager | import("@agentxm/extension-materialization").RuleManager | import("@agentxm/extension-materialization").KnowledgeManager | import("@agentxm/extension-materialization").PackManager | import("@agentxm/extension-materialization").McpServerManager | import("@agentxm/workspace-transactions").FootprintRecorder | import("@agentxm/workspace-operations").OperationJournal | import("@agentxm/extension-materialization").McpSecretStore | ReleaseAgePosture | import("@agentxm/workspace-operations").ResolvePlanInteraction | SourceHostProviders | import("@agentxm/extension-materialization").SubagentManager | import("@agentxm/extension-sources").WorkspaceCatalog | import("@agentxm/workspace-projection").WorkspaceInvariantFacts | SkillSelectionInteraction | SubagentSelectionInteraction | BundledAxmSkillAsset | AgentExecutableResolver | import("@agentxm/workspace-state/live").WorkspaceStateServices | import("@agentxm/workspace-projection").ProjectionParticipants>>;
|
|
103
104
|
cleanup: () => void;
|
|
104
105
|
};
|
|
105
106
|
export type LifecycleFixture = ReturnType<typeof makeLifecycleFixture>;
|
package/dist/src/testing.js
CHANGED
|
@@ -31,7 +31,8 @@ import { PlanInvocationTest, ResolvePlanInteractionTest, } from "@agentxm/worksp
|
|
|
31
31
|
import { CodingAgentRepositoryLive, NativeWriteAuthorityLive, WorkspaceCatalogLive, WorkspaceInvariantFactsLive, } from "@agentxm/workspace-projection/live";
|
|
32
32
|
import { layer as WorkspaceLayerLive } from "@agentxm/workspace-state/live";
|
|
33
33
|
import { ExtensionLifecycleFailed } from "./errors.js";
|
|
34
|
-
import {
|
|
34
|
+
import { SkillSelectionInteraction } from "./skills/application/index.js";
|
|
35
|
+
import { SubagentSelectionInteraction } from "./subagents/application/index.js";
|
|
35
36
|
import { BundledAxmSkillAsset } from "./skills/install/bundled.js";
|
|
36
37
|
import { StepFailureConversion } from "./step-failure-conversion.js";
|
|
37
38
|
/**
|
|
@@ -156,19 +157,20 @@ export const makeLifecycleFixture = (options = {}) => {
|
|
|
156
157
|
}),
|
|
157
158
|
});
|
|
158
159
|
const selectionCalls = [];
|
|
159
|
-
const selection = Layer.succeed(
|
|
160
|
-
|
|
160
|
+
const selection = Layer.mergeAll(Layer.succeed(SkillSelectionInteraction, {
|
|
161
|
+
select: (candidates) => {
|
|
161
162
|
selectionCalls.push({ type: "skill", offered: candidates.map((ref) => ref.skill.name) });
|
|
162
163
|
return Effect.succeed(options.select === "none" ? [] : candidates);
|
|
163
164
|
},
|
|
164
|
-
|
|
165
|
+
}), Layer.succeed(SubagentSelectionInteraction, {
|
|
166
|
+
select: (candidates) => {
|
|
165
167
|
selectionCalls.push({
|
|
166
168
|
type: "subagent",
|
|
167
169
|
offered: candidates.map((ref) => ref.subagent.name),
|
|
168
170
|
});
|
|
169
171
|
return Effect.succeed(options.select === "none" ? [] : candidates);
|
|
170
172
|
},
|
|
171
|
-
});
|
|
173
|
+
}));
|
|
172
174
|
const environment = ConfigProvider.layer(ConfigProvider.fromEnv({ env: { AXM_USER_HOME: home } }));
|
|
173
175
|
// Activation never fetches a source: it turns on what the workspace already
|
|
174
176
|
// acquired. A fixture that could fetch would be describing installation.
|
|
@@ -5,6 +5,7 @@ export declare const rootUninstallableTypeSegments: readonly ("knowledge" | "rul
|
|
|
5
5
|
export type RootUninstallableType = InstallableExtensionType;
|
|
6
6
|
export interface RootUninstallIntent {
|
|
7
7
|
readonly source: string;
|
|
8
|
+
readonly owner: string;
|
|
8
9
|
readonly type: RootUninstallableType;
|
|
9
10
|
readonly name: string;
|
|
10
11
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refusing to uninstall an installed package the workspace does not configure.
|
|
3
|
+
*
|
|
4
|
+
* Uninstall withdraws desired intent. An installed package that no desired
|
|
5
|
+
* route reaches is not intent to withdraw; sync reconciles it, so uninstall
|
|
6
|
+
* refuses before planning rather than reporting a removal it cannot own.
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import type { InstallableExtensionType } from "@agentxm/extension-model/unstable/extensions/installable-types";
|
|
10
|
+
import { LockfileReader, WorkspaceMutations } from "@agentxm/workspace-state";
|
|
11
|
+
import { ExtensionLifecycleFailed } from "../errors.js";
|
|
12
|
+
/** The single extension a literal uninstall selector names. */
|
|
13
|
+
export interface UninstallSubject {
|
|
14
|
+
readonly type: InstallableExtensionType;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
/** The owner handle, when the selector spelled a fully qualified name. */
|
|
17
|
+
readonly owner: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** The subject a typed selector names, or none for a glob. */
|
|
20
|
+
export declare const typedUninstallSubject: (type: InstallableExtensionType, selector: string) => UninstallSubject | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Fail when no desired route reaches the subject while an installed package
|
|
23
|
+
* for it sits in the install root.
|
|
24
|
+
*/
|
|
25
|
+
export declare const refuseUndesiredInstalledTarget: (subject: UninstallSubject) => Effect.Effect<undefined, ExtensionLifecycleFailed, import("effect/FileSystem").FileSystem | import("effect/Path").Path | WorkspaceMutations | LockfileReader>;
|
|
26
|
+
//# sourceMappingURL=undesired-target.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refusing to uninstall an installed package the workspace does not configure.
|
|
3
|
+
*
|
|
4
|
+
* Uninstall withdraws desired intent. An installed package that no desired
|
|
5
|
+
* route reaches is not intent to withdraw; sync reconciles it, so uninstall
|
|
6
|
+
* refuses before planning rather than reporting a removal it cannot own.
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import { parseExtensionFqnParts, toExtensionTypePlural, } from "@agentxm/extension-model/unstable/extensions";
|
|
10
|
+
import { LockfileReader, WorkspaceMutations, observeInstallRoot } from "@agentxm/workspace-state";
|
|
11
|
+
import { ExtensionLifecycleFailed } from "../errors.js";
|
|
12
|
+
/** The subject a typed selector names, or none for a glob. */
|
|
13
|
+
export const typedUninstallSubject = (type, selector) => {
|
|
14
|
+
const trimmed = selector.trim();
|
|
15
|
+
if (trimmed.includes("*"))
|
|
16
|
+
return undefined;
|
|
17
|
+
const fqn = parseExtensionFqnParts(trimmed);
|
|
18
|
+
return fqn !== undefined && fqn.type === type
|
|
19
|
+
? { type, name: fqn.name, owner: fqn.owner }
|
|
20
|
+
: { type, name: trimmed, owner: undefined };
|
|
21
|
+
};
|
|
22
|
+
const readFailed = (cause) => new ExtensionLifecycleFailed({
|
|
23
|
+
category: "internal",
|
|
24
|
+
detail: "Installed packages could not be observed",
|
|
25
|
+
cause,
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Fail when no desired route reaches the subject while an installed package
|
|
29
|
+
* for it sits in the install root.
|
|
30
|
+
*/
|
|
31
|
+
export const refuseUndesiredInstalledTarget = Effect.fn("UninstallExtensions.refuseUndesiredInstalledTarget")(function* (subject) {
|
|
32
|
+
const ws = yield* WorkspaceMutations;
|
|
33
|
+
const graph = yield* ws.getDesiredStateGraph().pipe(Effect.mapError(readFailed));
|
|
34
|
+
if (graph.nodes.some((node) => node.type === subject.type && node.name === subject.name))
|
|
35
|
+
return;
|
|
36
|
+
const inventory = yield* observeInstallRoot({
|
|
37
|
+
layout: ws.layout,
|
|
38
|
+
graph,
|
|
39
|
+
locks: yield* LockfileReader,
|
|
40
|
+
}).pipe(Effect.mapError(readFailed));
|
|
41
|
+
const installed = inventory.leftovers.some((entry) => entry.type === subject.type &&
|
|
42
|
+
entry.name === subject.name &&
|
|
43
|
+
(subject.owner === undefined || entry.owner === subject.owner));
|
|
44
|
+
if (!installed)
|
|
45
|
+
return;
|
|
46
|
+
const identity = subject.owner === undefined
|
|
47
|
+
? subject.name
|
|
48
|
+
: `${subject.owner}/${toExtensionTypePlural(subject.type)}/${subject.name}`;
|
|
49
|
+
return yield* new ExtensionLifecycleFailed({
|
|
50
|
+
category: "conflict",
|
|
51
|
+
title: "Extension is not configured",
|
|
52
|
+
detail: `${subject.type} ${identity} is installed but not configured; axm sync removes installed packages that are not configured.`,
|
|
53
|
+
cmd: "axm sync",
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=undesired-target.js.map
|
|
@@ -23,6 +23,7 @@ import { parseRuleUninstallRequest, planRuleUninstall } from "../rules/uninstall
|
|
|
23
23
|
import { parseSkillUninstallRequest, planSkillUninstall } from "../skills/uninstall/plan.js";
|
|
24
24
|
import { parseSubagentUninstallRequest, planSubagentUninstall, } from "../subagents/uninstall/plan.js";
|
|
25
25
|
import { resolveRootUninstallIntent } from "./root-intent.js";
|
|
26
|
+
import { refuseUndesiredInstalledTarget, typedUninstallSubject } from "./undesired-target.js";
|
|
26
27
|
const planForType = (type, selector) => {
|
|
27
28
|
switch (type) {
|
|
28
29
|
case "skill":
|
|
@@ -90,9 +91,21 @@ const planForType = (type, selector) => {
|
|
|
90
91
|
/** Settle a removal without writing anything. */
|
|
91
92
|
export const prepareUninstallExtensions = Effect.fn("UninstallExtensions.prepare")(function* (request) {
|
|
92
93
|
const resolved = yield* Option.match(request.type, {
|
|
93
|
-
onSome: (type) => Effect.succeed({
|
|
94
|
-
|
|
94
|
+
onSome: (type) => Effect.succeed({
|
|
95
|
+
type,
|
|
96
|
+
selector: request.selector,
|
|
97
|
+
subject: typedUninstallSubject(type, request.selector),
|
|
98
|
+
}),
|
|
99
|
+
onNone: () => resolveRootUninstallIntent(request.selector).pipe(Effect.map((intent) => ({
|
|
100
|
+
type: intent.type,
|
|
101
|
+
selector: intent.name,
|
|
102
|
+
subject: { type: intent.type, name: intent.name, owner: intent.owner },
|
|
103
|
+
}))),
|
|
95
104
|
});
|
|
105
|
+
// An installed package no desired route reaches is sync's to reconcile, not
|
|
106
|
+
// intent this removal can withdraw.
|
|
107
|
+
if (resolved.type !== "pack" && resolved.subject !== undefined)
|
|
108
|
+
yield* refuseUndesiredInstalledTarget(resolved.subject);
|
|
96
109
|
const planned = yield* planForType(resolved.type, resolved.selector);
|
|
97
110
|
const proposal = yield* proposeDesiredState(planned.names.map((name) => ({ kind: "remove", type: resolved.type, name }))).pipe(Effect.mapError((cause) => new ExtensionLifecycleFailed({
|
|
98
111
|
category: "conflict",
|
|
@@ -126,11 +139,22 @@ export const prepareUninstallExtensions = Effect.fn("UninstallExtensions.prepare
|
|
|
126
139
|
const jobs = yield* Effect.forEach(planned.plan.jobs, (job) => Effect.gen(function* () {
|
|
127
140
|
const steps = yield* Effect.forEach(job.steps, (step) => Effect.gen(function* () {
|
|
128
141
|
const artifact = artifactByName.get(step.label ?? "");
|
|
129
|
-
if (artifact === undefined ||
|
|
130
|
-
step.readiness === "error" ||
|
|
131
|
-
leafType === undefined ||
|
|
132
|
-
((artifact.targets?.length ?? 0) === 0 && (artifact.references?.length ?? 0) === 0))
|
|
142
|
+
if (artifact === undefined || step.readiness === "error" || leafType === undefined)
|
|
133
143
|
return step;
|
|
144
|
+
if ((artifact.targets?.length ?? 0) === 0 && (artifact.references?.length ?? 0) === 0) {
|
|
145
|
+
// Nothing exists to withdraw: the planner's descriptive artifact
|
|
146
|
+
// would name paths that are neither present nor changed, so the
|
|
147
|
+
// step declares none, and a result that changed nothing reports
|
|
148
|
+
// the empty evidence instead.
|
|
149
|
+
const { artifact: _descriptive, ...withoutArtifact } = step;
|
|
150
|
+
return {
|
|
151
|
+
...withoutArtifact,
|
|
152
|
+
run: step.run.pipe(Effect.map((result) => result.result === "success" &&
|
|
153
|
+
(result.disposition === "unchanged" || result.artifact?.change === "unchanged")
|
|
154
|
+
? { ...result, artifact }
|
|
155
|
+
: result)),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
134
158
|
const cleanup = yield* collectCleanupStep({
|
|
135
159
|
expectedSkillNames: activeNames("skill"),
|
|
136
160
|
expectedSubagentNames: activeNames("subagent"),
|
|
@@ -10,9 +10,8 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @experimental This API is unstable and may change without notice.
|
|
12
12
|
*/
|
|
13
|
-
import * as Effect from "effect/Effect";
|
|
14
13
|
import type * as Option from "effect/Option";
|
|
15
|
-
import type {
|
|
14
|
+
import type { Plan, PlannedJobStep } from "@agentxm/workspace-operations";
|
|
16
15
|
import type { SkillExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/skill";
|
|
17
16
|
import type { SubagentExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/subagent";
|
|
18
17
|
import type { SkillLockEntry, SubagentLockEntry } from "@agentxm/workspace-state";
|
|
@@ -40,6 +39,6 @@ export interface SelectiveUpdateUnit<TOperation> {
|
|
|
40
39
|
* steps are the selected entries, each either unchanged or dispatched to the
|
|
41
40
|
* install operation that advances it.
|
|
42
41
|
*/
|
|
43
|
-
export declare const buildSelectiveUpdatePlan: <TOperation, R>(units: ReadonlyArray<SelectiveUpdateUnit<TOperation>>, acceptedResolutions: Readonly<Record<string, AcceptedEntry | undefined>>, name: string, description: Option.Option<string>,
|
|
42
|
+
export declare const buildSelectiveUpdatePlan: <TOperation, R>(units: ReadonlyArray<SelectiveUpdateUnit<TOperation>>, acceptedResolutions: Readonly<Record<string, AcceptedEntry | undefined>>, name: string, description: Option.Option<string>, makeStep: (operation: TOperation) => PlannedJobStep<R>) => Plan<R>;
|
|
44
43
|
export {};
|
|
45
44
|
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -41,7 +41,7 @@ const unchangedStep = (label) => ({
|
|
|
41
41
|
* steps are the selected entries, each either unchanged or dispatched to the
|
|
42
42
|
* install operation that advances it.
|
|
43
43
|
*/
|
|
44
|
-
export const buildSelectiveUpdatePlan = (units, acceptedResolutions, name, description,
|
|
44
|
+
export const buildSelectiveUpdatePlan = (units, acceptedResolutions, name, description, makeStep) => ({
|
|
45
45
|
_tag: "Plan",
|
|
46
46
|
name,
|
|
47
47
|
description,
|
|
@@ -52,7 +52,7 @@ export const buildSelectiveUpdatePlan = (units, acceptedResolutions, name, descr
|
|
|
52
52
|
const accepted = acceptedResolutions[unit.name];
|
|
53
53
|
const needsUpdate = accepted === undefined || unit.force || hasChanged(unit.ref, accepted);
|
|
54
54
|
return needsUpdate
|
|
55
|
-
? {
|
|
55
|
+
? { ...makeStep(unit.operation), label: unit.name }
|
|
56
56
|
: unchangedStep(unit.name);
|
|
57
57
|
}),
|
|
58
58
|
},
|
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
* What a selective update's plan steps declare at execution time.
|
|
3
3
|
*
|
|
4
4
|
* A selective advance runs the same install operation the install routes run,
|
|
5
|
-
* so its steps carry the install step requirements
|
|
6
|
-
* operation reaches for directly: the source providers it re-fetches through,
|
|
7
|
-
* and the boundary's failure conversion. Those requirements travel with the
|
|
5
|
+
* so its steps carry the install step requirements. Those requirements travel with the
|
|
8
6
|
* step and are composed once at the application's runtime boundary — nothing
|
|
9
7
|
* is captured into a step's closure on the way.
|
|
10
8
|
*
|
|
11
9
|
* @experimental This API is unstable and may change without notice.
|
|
12
10
|
*/
|
|
13
|
-
import type { SourceHostProviders } from "@agentxm/extension-sources";
|
|
14
11
|
import type { InstallStepRequirements } from "../../install/vocabulary.js";
|
|
15
|
-
|
|
16
|
-
export type SelectiveUpdateStepRequirements = InstallStepRequirements | SourceHostProviders | StepFailureConversion;
|
|
12
|
+
export type SelectiveUpdateStepRequirements = InstallStepRequirements;
|
|
17
13
|
//# sourceMappingURL=requirements.d.ts.map
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
* What a selective update's plan steps declare at execution time.
|
|
3
3
|
*
|
|
4
4
|
* A selective advance runs the same install operation the install routes run,
|
|
5
|
-
* so its steps carry the install step requirements
|
|
6
|
-
* operation reaches for directly: the source providers it re-fetches through,
|
|
7
|
-
* and the boundary's failure conversion. Those requirements travel with the
|
|
5
|
+
* so its steps carry the install step requirements. Those requirements travel with the
|
|
8
6
|
* step and are composed once at the application's runtime boundary — nothing
|
|
9
7
|
* is captured into a step's closure on the way.
|
|
10
8
|
*
|
|
@@ -14,7 +14,7 @@ import * as Effect from "effect/Effect";
|
|
|
14
14
|
import * as Option from "effect/Option";
|
|
15
15
|
import { parseSourceQualifiedRegistrySourcePatternParts } from "@agentxm/extension-model/unstable/extensions";
|
|
16
16
|
import { resolveInstalledIdentifierNameOrInput, resolveSource, SourceHostProviders, } from "@agentxm/extension-sources";
|
|
17
|
-
import { expandGlobs } from "
|
|
17
|
+
import { expandGlobs } from "@agentxm/extension-model/unstable/extensions/name-patterns";
|
|
18
18
|
/**
|
|
19
19
|
* Whether a positional selector names the same origin an entry declares.
|
|
20
20
|
* Two Registry patterns compare by their parsed parts; anything else
|
|
@@ -16,9 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import * as Effect from "effect/Effect";
|
|
18
18
|
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
19
|
-
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
20
19
|
import { ExtensionLifecycleFailed } from "../../errors.js";
|
|
21
|
-
import type { SelectiveUpdateStepRequirements } from "./requirements.js";
|
|
22
20
|
import { type SelectiveUpdateSelectors } from "./selection.js";
|
|
23
21
|
/** Everything `skills update` needs beyond the workspace it runs in. */
|
|
24
22
|
export interface SelectiveSkillUpdateRequest extends SelectiveUpdateSelectors {
|
|
@@ -47,9 +45,9 @@ export declare const prepareSelectiveSkillUpdate: (request: SelectiveSkillUpdate
|
|
|
47
45
|
outcome: "planned";
|
|
48
46
|
subjectType: "skill";
|
|
49
47
|
planName: string;
|
|
50
|
-
execution: import("@agentxm/workspace-operations").ExecutionCandidate<
|
|
48
|
+
execution: import("@agentxm/workspace-operations").ExecutionCandidate<import("../../index.ts").InstallStepRequirements, never>;
|
|
51
49
|
reason?: never;
|
|
52
50
|
message?: never;
|
|
53
51
|
planDescription?: never;
|
|
54
|
-
}, ExtensionLifecycleFailed | import("@agentxm/extension-sources").SourceSyntaxInvalid | import("@agentxm/extension-sources").SourceHostNotConfigured | import("@agentxm/extension-sources").SourceNotResolvable | import("@agentxm/extension-sources").SourceNetworkFailure | import("@agentxm/extension-sources").GitOperationFailed | import("@agentxm/extension-sources").WorkspaceCatalogUnavailable | import("@agentxm/extension-sources").AxmSkillGateUnavailable | import("@agentxm/registry-client").RegistryProblem | import("@agentxm/registry-client").RegistryRequestFailed | import("@agentxm/registry-client").RegistryOperationFailed | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileValidationError | import("@agentxm/extension-resolution").ExtensionResolutionFailed | import("@agentxm/workspace-operations").CandidateFingerprintFailed, import("
|
|
52
|
+
}, ExtensionLifecycleFailed | import("@agentxm/extension-sources").SourceSyntaxInvalid | import("@agentxm/extension-sources").SourceHostNotConfigured | import("@agentxm/extension-sources").SourceNotResolvable | import("@agentxm/extension-sources").SourceNetworkFailure | import("@agentxm/extension-sources").GitOperationFailed | import("@agentxm/extension-sources").WorkspaceCatalogUnavailable | import("@agentxm/extension-sources").AxmSkillGateUnavailable | import("@agentxm/registry-client").RegistryProblem | import("@agentxm/registry-client").RegistryRequestFailed | import("@agentxm/registry-client").RegistryOperationFailed | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileValidationError | import("@agentxm/extension-resolution").ExtensionResolutionFailed | import("@agentxm/workspace-operations").CandidateFingerprintFailed, import("@agentxm/workspace-state").ConfiguredAgentOutcomesProvider | import("@agentxm/extension-materialization").SkillManager | import("@agentxm/extension-resolution").ReleaseAgePosture | import("effect/Scope").Scope | SourceHostProviders | import("@agentxm/extension-sources").WorkspaceCatalog | import("../../index.ts").InstallStepRequirements>;
|
|
55
53
|
//# sourceMappingURL=skills.d.ts.map
|