@agentxm/extension-lifecycle 0.28.11 → 0.28.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/activation/display-paths.d.ts +25 -0
- package/dist/src/activation/display-paths.js +25 -0
- package/dist/src/activation/errors.d.ts +16 -0
- package/dist/src/activation/errors.js +7 -0
- package/dist/src/activation/set-activation.d.ts +134 -0
- package/dist/src/activation/set-activation.js +772 -0
- package/dist/src/demote/demote-to-external-source.d.ts +82 -0
- package/dist/src/demote/demote-to-external-source.js +233 -0
- package/dist/src/errors.d.ts +0 -8
- package/dist/src/errors.js +0 -8
- package/dist/src/glob.d.ts +35 -0
- package/dist/src/glob.js +75 -0
- package/dist/src/hooks/configured-agent-outcomes-provider.d.ts +7 -3
- package/dist/src/hooks/configured-agent-outcomes-provider.js +11 -4
- package/dist/src/hooks/install/plan.d.ts +45 -0
- package/dist/src/hooks/install/plan.js +224 -0
- package/dist/src/hooks/uninstall/plan.d.ts +20 -0
- package/dist/src/hooks/uninstall/plan.js +77 -0
- package/dist/src/index.d.ts +48 -16
- package/dist/src/index.js +60 -17
- package/dist/src/install/aggregate-projection-step.d.ts +16 -0
- package/dist/src/install/aggregate-projection-step.js +49 -0
- package/dist/src/install/configured.d.ts +65 -0
- package/dist/src/install/configured.js +406 -0
- package/dist/src/install/inline-mcp-operation.d.ts +4 -0
- package/dist/src/install/inline-mcp-operation.js +25 -0
- package/dist/src/install/install-extensions.d.ts +110 -0
- package/dist/src/install/install-extensions.js +282 -0
- package/dist/src/install/per-type-install.d.ts +12 -0
- package/dist/src/install/per-type-install.js +12 -0
- package/dist/src/install/registry-install-target.d.ts +35 -0
- package/dist/src/install/registry-install-target.js +66 -0
- package/dist/src/install/registry-login-suggestion.d.ts +21 -0
- package/dist/src/install/registry-login-suggestion.js +34 -0
- package/dist/src/install/registry-source-resolution.d.ts +54 -0
- package/dist/src/install/registry-source-resolution.js +216 -0
- package/dist/src/install/root-intent.d.ts +19 -0
- package/dist/src/install/root-intent.js +122 -0
- package/dist/src/install/selection-interaction.d.ts +46 -0
- package/dist/src/install/selection-interaction.js +22 -0
- package/dist/src/install/vocabulary.d.ts +143 -0
- package/dist/src/install/vocabulary.js +29 -0
- package/dist/src/knowledge/install/plan.d.ts +35 -0
- package/dist/src/knowledge/install/plan.js +128 -0
- package/dist/src/knowledge/uninstall/plan.d.ts +23 -0
- package/dist/src/knowledge/uninstall/plan.js +140 -0
- package/dist/src/live.d.ts +4 -11
- package/dist/src/live.js +4 -11
- package/dist/src/mcps/install/plan.d.ts +65 -0
- package/dist/src/mcps/install/plan.js +301 -0
- package/dist/src/mcps/operations/disable.d.ts +5 -3
- package/dist/src/mcps/operations/disable.js +6 -4
- package/dist/src/mcps/operations/enable.d.ts +5 -3
- package/dist/src/mcps/operations/enable.js +8 -6
- package/dist/src/mcps/operations/sync-outcome.d.ts +1 -1
- package/dist/src/mcps/operations/uninstall.d.ts +5 -3
- package/dist/src/mcps/operations/uninstall.js +4 -4
- package/dist/src/mcps/uninstall/plan.d.ts +24 -0
- package/dist/src/mcps/uninstall/plan.js +109 -0
- package/dist/src/packs/artifact.d.ts +21 -0
- package/dist/src/packs/artifact.js +32 -0
- package/dist/src/packs/constraint-gate.d.ts +30 -0
- package/dist/src/packs/constraint-gate.js +76 -0
- package/dist/src/packs/expansion.d.ts +13 -14
- package/dist/src/packs/expansion.js +1 -2
- package/dist/src/packs/graph-transition.d.ts +64 -0
- package/dist/src/packs/graph-transition.js +219 -0
- package/dist/src/packs/install/plan.d.ts +95 -0
- package/dist/src/packs/install/plan.js +845 -0
- package/dist/src/packs/member-install-step.d.ts +29 -0
- package/dist/src/packs/member-install-step.js +156 -0
- package/dist/src/packs/operations/install.d.ts +3 -3
- package/dist/src/packs/operations/install.js +5 -5
- package/dist/src/packs/promote-authored-pack.d.ts +86 -0
- package/dist/src/packs/promote-authored-pack.js +239 -0
- package/dist/src/packs/resolved-dependency.d.ts +9 -26
- package/dist/src/packs/resolved-dependency.js +8 -20
- package/dist/src/packs/uninstall/plan.d.ts +66 -0
- package/dist/src/packs/uninstall/plan.js +344 -0
- package/dist/src/packs/uninstall/readiness.d.ts +50 -0
- package/dist/src/packs/uninstall/readiness.js +130 -0
- package/dist/src/publisher-binding.d.ts +8 -40
- package/dist/src/publisher-binding.js +8 -46
- package/dist/src/rules/install/plan.d.ts +35 -0
- package/dist/src/rules/install/plan.js +133 -0
- package/dist/src/rules/uninstall/plan.d.ts +19 -0
- package/dist/src/rules/uninstall/plan.js +54 -0
- package/dist/src/skills/install/bundled.d.ts +73 -0
- package/dist/src/skills/install/bundled.js +244 -0
- package/dist/src/skills/install/plan.d.ts +72 -0
- package/dist/src/skills/install/plan.js +429 -0
- package/dist/src/skills/install/selection.d.ts +26 -0
- package/dist/src/skills/install/selection.js +41 -0
- package/dist/src/skills/install/source.d.ts +21 -0
- package/dist/src/skills/install/source.js +76 -0
- package/dist/src/skills/operations/disable.d.ts +3 -2
- package/dist/src/skills/operations/disable.js +7 -11
- package/dist/src/skills/operations/enable.d.ts +3 -2
- package/dist/src/skills/operations/enable.js +6 -8
- package/dist/src/skills/operations/install.d.ts +4 -4
- package/dist/src/skills/operations/install.js +13 -12
- package/dist/src/skills/uninstall/plan.d.ts +23 -0
- package/dist/src/skills/uninstall/plan.js +165 -0
- package/dist/src/skills/utils.js +1 -1
- package/dist/src/step-failure-conversion.d.ts +44 -0
- package/dist/src/step-failure-conversion.js +26 -0
- package/dist/src/step-failure.d.ts +29 -0
- package/dist/src/step-failure.js +130 -0
- package/dist/src/subagents/install/plan.d.ts +49 -0
- package/dist/src/subagents/install/plan.js +270 -0
- package/dist/src/subagents/install/selection.d.ts +26 -0
- package/dist/src/subagents/install/selection.js +37 -0
- package/dist/src/subagents/install/source.d.ts +18 -0
- package/dist/src/subagents/install/source.js +72 -0
- package/dist/src/subagents/operations/disable.d.ts +5 -3
- package/dist/src/subagents/operations/disable.js +5 -3
- package/dist/src/subagents/operations/enable.d.ts +5 -3
- package/dist/src/subagents/operations/enable.js +17 -12
- package/dist/src/subagents/uninstall/plan.d.ts +20 -0
- package/dist/src/subagents/uninstall/plan.js +142 -0
- package/dist/src/test-packages.d.ts +34 -0
- package/dist/src/test-packages.js +111 -0
- package/dist/src/test-registry.d.ts +78 -0
- package/dist/src/test-registry.js +223 -0
- package/dist/src/testing.d.ts +108 -0
- package/dist/src/testing.js +241 -0
- package/dist/src/uninstall/retention-policy.d.ts +21 -0
- package/dist/src/uninstall/retention-policy.js +28 -0
- package/dist/src/uninstall/root-intent.d.ts +17 -0
- package/dist/src/uninstall/root-intent.js +101 -0
- package/dist/src/uninstall/uninstall-extensions.d.ts +61 -0
- package/dist/src/uninstall/uninstall-extensions.js +127 -0
- package/dist/src/uninstall/vocabulary.d.ts +40 -0
- package/dist/src/uninstall/vocabulary.js +14 -0
- package/dist/src/update/atomicity.d.ts +22 -0
- package/dist/src/update/atomicity.js +23 -0
- package/dist/src/update/blockers.d.ts +31 -0
- package/dist/src/update/blockers.js +78 -0
- package/dist/src/update/configured.d.ts +78 -0
- package/dist/src/update/configured.js +546 -0
- package/dist/src/update/root-request.d.ts +39 -0
- package/dist/src/update/root-request.js +117 -0
- package/dist/src/update/selective/plan.d.ts +45 -0
- package/dist/src/update/selective/plan.js +61 -0
- package/dist/src/update/selective/requirements.d.ts +17 -0
- package/dist/src/update/selective/requirements.js +14 -0
- package/dist/src/update/selective/selection.d.ts +63 -0
- package/dist/src/update/selective/selection.js +85 -0
- package/dist/src/update/selective/skills.d.ts +55 -0
- package/dist/src/update/selective/skills.js +596 -0
- package/dist/src/update/selective/subagents.d.ts +52 -0
- package/dist/src/update/selective/subagents.js +331 -0
- package/dist/src/update/selective/use-case.d.ts +121 -0
- package/dist/src/update/selective/use-case.js +28 -0
- package/dist/src/update/selective/vocabulary.d.ts +43 -0
- package/dist/src/update/selective/vocabulary.js +28 -0
- package/dist/src/update/selector.d.ts +72 -0
- package/dist/src/update/selector.js +120 -0
- package/dist/src/update/targeted-plan.d.ts +30 -0
- package/dist/src/update/targeted-plan.js +113 -0
- package/dist/src/update/update-extensions.d.ts +164 -0
- package/dist/src/update/update-extensions.js +579 -0
- package/dist/src/workspace-paths.d.ts +31 -0
- package/dist/src/workspace-paths.js +46 -0
- package/package.json +22 -12
- package/dist/src/configured-entry-resolution.d.ts +0 -111
- package/dist/src/configured-entry-resolution.js +0 -731
- package/dist/src/failure-adapter.d.ts +0 -35
- package/dist/src/failure-adapter.js +0 -23
- package/dist/src/hooks/manager.d.ts +0 -15
- package/dist/src/hooks/manager.js +0 -769
- package/dist/src/internal/fs-helpers.d.ts +0 -12
- package/dist/src/internal/fs-helpers.js +0 -13
- package/dist/src/internal/integrity.d.ts +0 -13
- package/dist/src/internal/integrity.js +0 -17
- package/dist/src/knowledge/manager.d.ts +0 -11
- package/dist/src/knowledge/manager.js +0 -711
- package/dist/src/mcps/manager.d.ts +0 -16
- package/dist/src/mcps/manager.js +0 -247
- package/dist/src/mcps/operations/artifact.d.ts +0 -24
- package/dist/src/mcps/operations/artifact.js +0 -74
- package/dist/src/mcps/operations/install.d.ts +0 -78
- package/dist/src/mcps/operations/install.js +0 -596
- package/dist/src/packs/dependency-resolution.d.ts +0 -65
- package/dist/src/packs/dependency-resolution.js +0 -414
- package/dist/src/packs/manager.d.ts +0 -16
- package/dist/src/packs/manager.js +0 -181
- package/dist/src/registry-materialization.d.ts +0 -52
- package/dist/src/registry-materialization.js +0 -72
- package/dist/src/release-age-posture.d.ts +0 -23
- package/dist/src/release-age-posture.js +0 -15
- package/dist/src/resolution-timeout.d.ts +0 -5
- package/dist/src/resolution-timeout.js +0 -11
- package/dist/src/rules/manager.d.ts +0 -20
- package/dist/src/rules/manager.js +0 -480
- package/dist/src/skills/manager.d.ts +0 -18
- package/dist/src/skills/manager.js +0 -346
- package/dist/src/skills/materialization.d.ts +0 -54
- package/dist/src/skills/materialization.js +0 -158
- package/dist/src/skills/operations/source-hash.d.ts +0 -2
- package/dist/src/skills/operations/source-hash.js +0 -6
- package/dist/src/subagents/manager.d.ts +0 -18
- package/dist/src/subagents/manager.js +0 -722
- package/dist/src/workflows/install-command/workflow.d.ts +0 -56
- package/dist/src/workflows/install-command/workflow.js +0 -46
- package/dist/src/workflows/uninstall-command/workflow.d.ts +0 -42
- package/dist/src/workflows/uninstall-command/workflow.js +0 -29
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installing skills.
|
|
3
|
+
*
|
|
4
|
+
* A skill is acquired once into the canonical tree and then projected into
|
|
5
|
+
* every configured agent's skills directory, so this decides which source
|
|
6
|
+
* supplies it, which of that source's skills the request wants, what each
|
|
7
|
+
* projection target's change will be before anything is written, and whether
|
|
8
|
+
* a version this new deserves a release-age warning.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as FileSystem from "effect/FileSystem";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import * as Path from "effect/Path";
|
|
16
|
+
import type * as HttpClient from "effect/unstable/http/HttpClient";
|
|
17
|
+
import { SkillManager } from "@agentxm/extension-materialization";
|
|
18
|
+
import { type Handle } from "@agentxm/extension-model/unstable/extensions";
|
|
19
|
+
import type { SkillExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/skill";
|
|
20
|
+
import { type PackageUrlParts } from "@agentxm/extension-model/unstable/packaging";
|
|
21
|
+
import type { Source } from "@agentxm/extension-model/unstable/sources/types";
|
|
22
|
+
import type { VersionRange } from "@agentxm/extension-model/unstable/version-constraints";
|
|
23
|
+
import { type SourceResolutionFailure } from "@agentxm/extension-sources";
|
|
24
|
+
import { type Plan } from "@agentxm/workspace-operations";
|
|
25
|
+
import type { ExtensionLifecycleFailed } from "../../errors.js";
|
|
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
|
+
import { type InstallStepRequirements, type ResolveInstallRequirements, type SkillInstallIntent } from "../../install/vocabulary.js";
|
|
30
|
+
/** A skill source after grammar parsing, before anything is discovered. */
|
|
31
|
+
export interface ParsedSkillInstallRequest {
|
|
32
|
+
readonly source: Source;
|
|
33
|
+
readonly versionRange: Option.Option<VersionRange>;
|
|
34
|
+
readonly requestedSkills: ReadonlyArray<string>;
|
|
35
|
+
readonly requestedOwner: Option.Option<Handle>;
|
|
36
|
+
/** Which configured registry hosts were consulted, and what each answered. */
|
|
37
|
+
readonly resolutionProbes: ReadonlyArray<RegistryLookupProbe>;
|
|
38
|
+
readonly all: boolean;
|
|
39
|
+
readonly force: boolean;
|
|
40
|
+
readonly nonInteractive: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The packages a skill declares itself compatible with. Registry refs carry
|
|
44
|
+
* them as a typed field; a local or git-hosted skill may declare them in its
|
|
45
|
+
* generic metadata bag, where an invalid entry is skipped rather than
|
|
46
|
+
* failing the whole install.
|
|
47
|
+
*/
|
|
48
|
+
export declare const getCompanionPackages: (ref: SkillExtensionRef) => ReadonlyArray<PackageUrlParts>;
|
|
49
|
+
/** Companion-package orientation the application renders beside the preview. */
|
|
50
|
+
export interface CompanionPackagesSection {
|
|
51
|
+
readonly title: string;
|
|
52
|
+
readonly items: ReadonlyArray<string>;
|
|
53
|
+
}
|
|
54
|
+
/** The deduplicated compatible-package list a set of skill refs declares. */
|
|
55
|
+
export declare const buildCompanionPackagesSection: (refs: ReadonlyArray<SkillExtensionRef>) => CompanionPackagesSection | undefined;
|
|
56
|
+
/** What a skill install command supplies before anything is parsed. */
|
|
57
|
+
export interface SkillInstallArgs {
|
|
58
|
+
readonly source: string;
|
|
59
|
+
readonly skills: ReadonlyArray<string>;
|
|
60
|
+
readonly all: boolean;
|
|
61
|
+
readonly force: boolean;
|
|
62
|
+
readonly nonInteractive: boolean;
|
|
63
|
+
}
|
|
64
|
+
/** Read the skill source grammar and route it to the source that serves it. */
|
|
65
|
+
export declare const parseSkillInstallRequest: (args: SkillInstallArgs) => Effect.Effect<ParsedSkillInstallRequest, ExtensionLifecycleFailed | SourceResolutionFailure, ResolveInstallRequirements>;
|
|
66
|
+
/** Discover the skills the parsed source offers, or refuse when it has none. */
|
|
67
|
+
export declare const discoverSkillRefs: (request: ParsedSkillInstallRequest) => Effect.Effect<ReadonlyArray<SkillExtensionRef>, ExtensionLifecycleFailed, ResolveInstallRequirements>;
|
|
68
|
+
/** 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>;
|
|
70
|
+
/** The closures a settled skill intent becomes. */
|
|
71
|
+
export declare const planSkillInstall: (intent: SkillInstallIntent) => Effect.Effect<Plan<InstallStepRequirements>, ExtensionLifecycleFailed, InstallStepRequirements | SkillManager | FileSystem.FileSystem | Path.Path | HttpClient.HttpClient>;
|
|
72
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installing skills.
|
|
3
|
+
*
|
|
4
|
+
* A skill is acquired once into the canonical tree and then projected into
|
|
5
|
+
* every configured agent's skills directory, so this decides which source
|
|
6
|
+
* supplies it, which of that source's skills the request wants, what each
|
|
7
|
+
* projection target's change will be before anything is written, and whether
|
|
8
|
+
* a version this new deserves a release-age warning.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Array from "effect/Array";
|
|
13
|
+
import * as Duration from "effect/Duration";
|
|
14
|
+
import * as Effect from "effect/Effect";
|
|
15
|
+
import * as FileSystem from "effect/FileSystem";
|
|
16
|
+
import * as Option from "effect/Option";
|
|
17
|
+
import * as Path from "effect/Path";
|
|
18
|
+
import * as Result from "effect/Result";
|
|
19
|
+
import * as Schema from "effect/Schema";
|
|
20
|
+
import { SkillManager, artifactAgentIdsFromTargets, artifactTargetAgentIds, buildInstallOperation, computeSkillSourceHash, groupInstallTargetsByDirectory, } from "@agentxm/extension-materialization";
|
|
21
|
+
import { matchesReleaseAgeExcludePattern, } from "@agentxm/extension-model/unstable/extensions";
|
|
22
|
+
import { PackageUrlPartsSchema, formatPackageDisplay, } from "@agentxm/extension-model/unstable/packaging";
|
|
23
|
+
import { parseInputPattern, } from "@agentxm/extension-model/unstable/sources/parser";
|
|
24
|
+
import { isVersionEntryMature, parseMinimumReleaseAge } from "@agentxm/extension-resolution";
|
|
25
|
+
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
26
|
+
import { createRegistryClient } from "@agentxm/registry-client";
|
|
27
|
+
import { operationPresentation, } from "@agentxm/workspace-operations";
|
|
28
|
+
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
29
|
+
import { WorkspaceMutations, sanitizeName } from "@agentxm/workspace-state";
|
|
30
|
+
import { gitHostedSkillArtifactSource } from "../operations/install.js";
|
|
31
|
+
import { lifecycleStepFailure } from "../../step-failure.js";
|
|
32
|
+
import { ExtensionSelectionInteraction } from "../../install/selection-interaction.js";
|
|
33
|
+
import { installRefused, } from "../../install/vocabulary.js";
|
|
34
|
+
import { determineSkillsToInstall } from "./selection.js";
|
|
35
|
+
import { resolveSkillInstallSource } from "./source.js";
|
|
36
|
+
const noSkillsFoundHowToFix = (source) => {
|
|
37
|
+
if (source.type === "registry") {
|
|
38
|
+
return "Verify the owner and skill name exist in the configured registry";
|
|
39
|
+
}
|
|
40
|
+
if (source.type === "local") {
|
|
41
|
+
return "Verify the source path contains directories with SKILL.md files";
|
|
42
|
+
}
|
|
43
|
+
return "Verify the source contains skill directories with SKILL.md files";
|
|
44
|
+
};
|
|
45
|
+
const decodePackageUrlParts = Schema.decodeUnknownResult(Schema.toType(PackageUrlPartsSchema));
|
|
46
|
+
const countFiles = (fs, path, dir) => Effect.gen(function* () {
|
|
47
|
+
const entries = yield* fs.readDirectory(dir).pipe(Effect.catch(() => Effect.succeed([])));
|
|
48
|
+
let total = 0;
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const fullPath = path.join(dir, entry);
|
|
51
|
+
const statOption = yield* fs.stat(fullPath).pipe(Effect.option);
|
|
52
|
+
if (Option.isNone(statOption))
|
|
53
|
+
continue;
|
|
54
|
+
if (statOption.value.type === "Directory") {
|
|
55
|
+
total += yield* countFiles(fs, path, fullPath);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
total += 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return total;
|
|
62
|
+
});
|
|
63
|
+
const skillPathSourceFor = (ref) => {
|
|
64
|
+
switch (ref.refType) {
|
|
65
|
+
case "registry":
|
|
66
|
+
return { refType: "registry", owner: ref.owner, source: ref.source };
|
|
67
|
+
case "git-hosted":
|
|
68
|
+
return {
|
|
69
|
+
refType: "git-hosted",
|
|
70
|
+
source: ref.source,
|
|
71
|
+
...(ref.sourcePath === undefined ? {} : { sourcePath: ref.sourcePath }),
|
|
72
|
+
...(ref.portable === undefined ? {} : { portable: ref.portable }),
|
|
73
|
+
};
|
|
74
|
+
case "local":
|
|
75
|
+
return {
|
|
76
|
+
refType: "local",
|
|
77
|
+
source: ref.source,
|
|
78
|
+
...(ref.sourcePath === undefined ? {} : { sourcePath: ref.sourcePath }),
|
|
79
|
+
...(ref.portable === undefined ? {} : { portable: ref.portable }),
|
|
80
|
+
};
|
|
81
|
+
case "workspace":
|
|
82
|
+
return { refType: "workspace", owner: ref.owner };
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const previousResolvedVersion = (entry) => {
|
|
86
|
+
if (typeof entry !== "object" || entry === null)
|
|
87
|
+
return undefined;
|
|
88
|
+
if (!("type" in entry) || entry.type !== "registry")
|
|
89
|
+
return undefined;
|
|
90
|
+
if (!("resolvedVersion" in entry) || typeof entry.resolvedVersion !== "string")
|
|
91
|
+
return undefined;
|
|
92
|
+
return entry.resolvedVersion;
|
|
93
|
+
};
|
|
94
|
+
const previousSourceHash = (entry) => {
|
|
95
|
+
if (typeof entry !== "object" || entry === null)
|
|
96
|
+
return undefined;
|
|
97
|
+
if (!("sourceHash" in entry) || typeof entry.sourceHash !== "string")
|
|
98
|
+
return undefined;
|
|
99
|
+
return entry.sourceHash;
|
|
100
|
+
};
|
|
101
|
+
const artifactChangeFromTargets = (fallback, targets) => {
|
|
102
|
+
if (targets.length === 0)
|
|
103
|
+
return fallback;
|
|
104
|
+
if (targets.some((target) => target.change === "created"))
|
|
105
|
+
return "created";
|
|
106
|
+
if (targets.some((target) => target.change === "updated" || target.change === undefined)) {
|
|
107
|
+
return "updated";
|
|
108
|
+
}
|
|
109
|
+
return fallback === "updated" ? "updated" : "unchanged";
|
|
110
|
+
};
|
|
111
|
+
const appendWarningToResult = (warning) => (result) => {
|
|
112
|
+
if (result.result === "error")
|
|
113
|
+
return result;
|
|
114
|
+
return {
|
|
115
|
+
...result,
|
|
116
|
+
warnings: [...(result.warnings ?? []), warning],
|
|
117
|
+
message: result.message.length === 0 ? warning : `${result.message}; ${warning}`,
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
const withPlanWarning = (step, warning) => {
|
|
121
|
+
if (Option.isNone(warning) || step.readiness === "error")
|
|
122
|
+
return step;
|
|
123
|
+
if (step.readiness === "warn") {
|
|
124
|
+
return { ...step, run: step.run.pipe(Effect.map(appendWarningToResult(warning.value))) };
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
...step,
|
|
128
|
+
message: warning.value,
|
|
129
|
+
run: step.run.pipe(Effect.map(appendWarningToResult(warning.value))),
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* The packages a skill declares itself compatible with. Registry refs carry
|
|
134
|
+
* them as a typed field; a local or git-hosted skill may declare them in its
|
|
135
|
+
* generic metadata bag, where an invalid entry is skipped rather than
|
|
136
|
+
* failing the whole install.
|
|
137
|
+
*/
|
|
138
|
+
export const getCompanionPackages = (ref) => {
|
|
139
|
+
if (ref.refType === "registry")
|
|
140
|
+
return ref.packages ?? [];
|
|
141
|
+
return Option.match(ref.skill.metadata, {
|
|
142
|
+
onNone: () => [],
|
|
143
|
+
onSome: (metadata) => {
|
|
144
|
+
const raw = metadata["packages"];
|
|
145
|
+
if (!globalThis.Array.isArray(raw))
|
|
146
|
+
return [];
|
|
147
|
+
return raw.flatMap((entry) => {
|
|
148
|
+
const decoded = decodePackageUrlParts(entry);
|
|
149
|
+
return Result.isSuccess(decoded) ? [decoded.success] : [];
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
/** The deduplicated compatible-package list a set of skill refs declares. */
|
|
155
|
+
export const buildCompanionPackagesSection = (refs) => {
|
|
156
|
+
const allPackages = refs.flatMap((ref) => getCompanionPackages(ref));
|
|
157
|
+
if (allPackages.length === 0)
|
|
158
|
+
return undefined;
|
|
159
|
+
const seen = new Set();
|
|
160
|
+
const items = [];
|
|
161
|
+
for (const pkg of allPackages) {
|
|
162
|
+
const formatted = formatPackageDisplay(pkg);
|
|
163
|
+
if (!seen.has(formatted)) {
|
|
164
|
+
seen.add(formatted);
|
|
165
|
+
items.push(formatted);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { title: "Compatible packages", items };
|
|
169
|
+
};
|
|
170
|
+
const extractRequestedSkills = (argSkills, parsedSource) => argSkills.length > 0
|
|
171
|
+
? argSkills
|
|
172
|
+
: parsedSource.pattern.pattern === "name-input"
|
|
173
|
+
? [parsedSource.pattern.name]
|
|
174
|
+
: parsedSource.pattern.pattern === "registry-pattern-input"
|
|
175
|
+
? Option.isSome(parsedSource.pattern.name)
|
|
176
|
+
? [parsedSource.pattern.name.value]
|
|
177
|
+
: []
|
|
178
|
+
: [];
|
|
179
|
+
const extractRequestedOwner = (parsedSource, source) => parsedSource.pattern.pattern === "registry-pattern-input"
|
|
180
|
+
? Option.some(parsedSource.pattern.owner)
|
|
181
|
+
: source.type === "registry"
|
|
182
|
+
? source.owner
|
|
183
|
+
: Option.none();
|
|
184
|
+
/** Read the skill source grammar and route it to the source that serves it. */
|
|
185
|
+
export const parseSkillInstallRequest = Effect.fn("InstallExtensions.parseSkillRequest")(function* (args) {
|
|
186
|
+
const parsedSourceOption = parseInputPattern(args.source.trim());
|
|
187
|
+
if (Option.isNone(parsedSourceOption)) {
|
|
188
|
+
return yield* installRefused({
|
|
189
|
+
category: "validation",
|
|
190
|
+
detail: "Invalid source: Unable to parse source",
|
|
191
|
+
recover: "Valid formats: local path, github:owner/repo, gitlab:owner/repo, or https://example.com",
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const parsedSource = parsedSourceOption.value;
|
|
195
|
+
const versionRange = parsedSource.pattern.pattern === "registry-pattern-input"
|
|
196
|
+
? parsedSource.pattern.versionRange
|
|
197
|
+
: Option.none();
|
|
198
|
+
const resolutionProbes = [];
|
|
199
|
+
const source = yield* resolveSkillInstallSource(parsedSource, {
|
|
200
|
+
onRegistryProbe: (probe) => {
|
|
201
|
+
resolutionProbes.push(probe);
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
return {
|
|
205
|
+
source,
|
|
206
|
+
versionRange,
|
|
207
|
+
requestedSkills: extractRequestedSkills(args.skills, parsedSource),
|
|
208
|
+
requestedOwner: extractRequestedOwner(parsedSource, source),
|
|
209
|
+
resolutionProbes,
|
|
210
|
+
all: args.all,
|
|
211
|
+
force: args.force,
|
|
212
|
+
nonInteractive: args.nonInteractive,
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
/** Discover the skills the parsed source offers, or refuse when it has none. */
|
|
216
|
+
export const discoverSkillRefs = Effect.fn("InstallExtensions.discoverSkills")(function* (request) {
|
|
217
|
+
const sources = yield* SourceHostProviders;
|
|
218
|
+
const discovered = yield* sources
|
|
219
|
+
.find(request.source, {
|
|
220
|
+
names: request.source.type === "registry" ? request.requestedSkills : [],
|
|
221
|
+
type: "skill",
|
|
222
|
+
owner: request.requestedOwner,
|
|
223
|
+
versionRange: request.versionRange,
|
|
224
|
+
})
|
|
225
|
+
.pipe(Effect.mapError((cause) => installRefused({
|
|
226
|
+
category: "network",
|
|
227
|
+
detail: "Skills could not be discovered from the source",
|
|
228
|
+
cause,
|
|
229
|
+
})), Effect.map(Array.filter((ref) => ref.type === "skill")));
|
|
230
|
+
if (Array.isReadonlyArrayEmpty(discovered)) {
|
|
231
|
+
return yield* installRefused({
|
|
232
|
+
category: "not_found",
|
|
233
|
+
detail: "No skills found in source",
|
|
234
|
+
recover: noSkillsFoundHowToFix(request.source),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return discovered;
|
|
238
|
+
});
|
|
239
|
+
/** Settle which of the discovered skills this request installs. */
|
|
240
|
+
export const finalizeSkillInstallIntent = Effect.fn("InstallExtensions.finalizeSkillIntent")(function* (request, discovered) {
|
|
241
|
+
const [first, ...rest] = discovered;
|
|
242
|
+
if (first === undefined) {
|
|
243
|
+
return yield* installRefused({ category: "not_found", detail: "No skills found in source" });
|
|
244
|
+
}
|
|
245
|
+
const candidates = [first, ...rest];
|
|
246
|
+
const selected = yield* determineSkillsToInstall(candidates, {
|
|
247
|
+
requestedSkills: request.requestedSkills,
|
|
248
|
+
all: request.all,
|
|
249
|
+
nonInteractive: request.nonInteractive,
|
|
250
|
+
});
|
|
251
|
+
if (Array.isReadonlyArrayEmpty(selected)) {
|
|
252
|
+
return { skillsToInstall: [] };
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
skillsToInstall: selected.map((ref) => ({
|
|
256
|
+
ref,
|
|
257
|
+
versionRange: ref.refType === "registry" ? request.versionRange : Option.none(),
|
|
258
|
+
})),
|
|
259
|
+
force: request.force,
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
/**
|
|
263
|
+
* Warn when a registry version this install accepts is younger than the
|
|
264
|
+
* workspace's minimum release age. The version was requested explicitly, so
|
|
265
|
+
* the policy does not hold it back — it only says so.
|
|
266
|
+
*/
|
|
267
|
+
const brandNewReleaseAgeWarning = (ref, installedBefore) => Effect.gen(function* () {
|
|
268
|
+
if (installedBefore || ref.refType !== "registry")
|
|
269
|
+
return Option.none();
|
|
270
|
+
const ws = yield* WorkspaceMutations;
|
|
271
|
+
const excluded = (yield* ws.getMinimumReleaseAgeExclude()).some(({ pattern }) => matchesReleaseAgeExcludePattern(pattern, {
|
|
272
|
+
owner: ref.owner,
|
|
273
|
+
type: "skill",
|
|
274
|
+
name: ref.name,
|
|
275
|
+
}));
|
|
276
|
+
if (excluded)
|
|
277
|
+
return Option.none();
|
|
278
|
+
const minimumReleaseAge = yield* ws.getMinimumReleaseAge();
|
|
279
|
+
const minimumAge = parseMinimumReleaseAge(minimumReleaseAge);
|
|
280
|
+
if (Option.isNone(minimumAge) ||
|
|
281
|
+
Duration.isLessThanOrEqualTo(minimumAge.value, Duration.zero)) {
|
|
282
|
+
return Option.none();
|
|
283
|
+
}
|
|
284
|
+
const location = ref.source.location.protocol === "file:"
|
|
285
|
+
? ref.source.location.pathname
|
|
286
|
+
: ref.source.location.href;
|
|
287
|
+
const client = yield* createRegistryClient(location);
|
|
288
|
+
const index = yield* client.getExtensionIndex({
|
|
289
|
+
owner: ref.owner,
|
|
290
|
+
type: "skill",
|
|
291
|
+
name: ref.name,
|
|
292
|
+
});
|
|
293
|
+
if (Option.isNone(index))
|
|
294
|
+
return Option.none();
|
|
295
|
+
const versionEntry = index.value.versions.find((entry) => entry.version === ref.version);
|
|
296
|
+
if (versionEntry === undefined)
|
|
297
|
+
return Option.none();
|
|
298
|
+
if (yield* isVersionEntryMature(versionEntry, minimumAge.value))
|
|
299
|
+
return Option.none();
|
|
300
|
+
return Option.some(`${ref.owner}/skills/${ref.name}@${ref.version} was published less than ${minimumReleaseAge} ago — installing it because you requested this version explicitly`);
|
|
301
|
+
}).pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
302
|
+
const targetChangeBeforeInstall = (args) => Effect.gen(function* () {
|
|
303
|
+
const fs = yield* FileSystem.FileSystem;
|
|
304
|
+
const path = yield* Path.Path;
|
|
305
|
+
const linkTarget = yield* fs.readLink(args.linkPath).pipe(Effect.option);
|
|
306
|
+
if (Option.isSome(linkTarget)) {
|
|
307
|
+
const currentAbsoluteTarget = path.resolve(path.dirname(args.linkPath), linkTarget.value);
|
|
308
|
+
const resolvedCurrentTarget = yield* fs
|
|
309
|
+
.realPath(currentAbsoluteTarget)
|
|
310
|
+
.pipe(Effect.catch(() => Effect.succeed(currentAbsoluteTarget)));
|
|
311
|
+
const resolvedExpectedTarget = yield* fs
|
|
312
|
+
.realPath(args.canonicalSkillSrcPath)
|
|
313
|
+
.pipe(Effect.catch(() => Effect.succeed(args.canonicalSkillSrcPath)));
|
|
314
|
+
return resolvedCurrentTarget === resolvedExpectedTarget ? "unchanged" : "updated";
|
|
315
|
+
}
|
|
316
|
+
const exists = yield* fs.exists(args.linkPath).pipe(Effect.catch(() => Effect.succeed(false)));
|
|
317
|
+
return exists ? "updated" : "created";
|
|
318
|
+
});
|
|
319
|
+
/** The closures a settled skill intent becomes. */
|
|
320
|
+
export const planSkillInstall = Effect.fn("InstallExtensions.planSkills")(function* (intent) {
|
|
321
|
+
const ws = yield* WorkspaceMutations;
|
|
322
|
+
const skillManager = yield* SkillManager;
|
|
323
|
+
const agentRepo = yield* CodingAgentRepository;
|
|
324
|
+
const fs = yield* FileSystem.FileSystem;
|
|
325
|
+
const path = yield* Path.Path;
|
|
326
|
+
const steps = yield* Effect.forEach(intent.skillsToInstall, (entry) => Effect.gen(function* () {
|
|
327
|
+
const ref = entry.ref;
|
|
328
|
+
const previousLockEntry = yield* ws
|
|
329
|
+
.getLockedSkill(ref.skill.name)
|
|
330
|
+
.pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
331
|
+
const previousVersion = Option.match(previousLockEntry, {
|
|
332
|
+
onNone: () => undefined,
|
|
333
|
+
onSome: previousResolvedVersion,
|
|
334
|
+
});
|
|
335
|
+
const { skillSrcPath } = yield* ws.getSkillDir(ref.skill.name, skillPathSourceFor(ref));
|
|
336
|
+
const sourceHashBeforeInstall = Option.match(previousLockEntry, {
|
|
337
|
+
onNone: () => undefined,
|
|
338
|
+
onSome: previousSourceHash,
|
|
339
|
+
}) ??
|
|
340
|
+
(yield* Effect.gen(function* () {
|
|
341
|
+
const exists = yield* fs
|
|
342
|
+
.exists(skillSrcPath)
|
|
343
|
+
.pipe(Effect.catch(() => Effect.succeed(false)));
|
|
344
|
+
if (!exists)
|
|
345
|
+
return undefined;
|
|
346
|
+
return yield* computeSkillSourceHash(skillSrcPath);
|
|
347
|
+
}));
|
|
348
|
+
const configuredAgents = yield* agentRepo.getMaterializationAgents();
|
|
349
|
+
const resolvedAgents = yield* Effect.forEach(configuredAgents, (agent) => agent
|
|
350
|
+
.resolveEffectiveSkillsDir({ workspaceRoot: ws.baseDir })
|
|
351
|
+
.pipe(Effect.map((outcome) => ({ agentId: agent.id, outcome }))), { concurrency: "unbounded" });
|
|
352
|
+
const sanitizedName = sanitizeName(ref.skill.name);
|
|
353
|
+
const installableTargets = resolvedAgents.flatMap(({ agentId, outcome }) => outcome._tag === "supported"
|
|
354
|
+
? [{ agentId, targetDir: path.normalize(outcome.dir) }]
|
|
355
|
+
: []);
|
|
356
|
+
const targetLocations = yield* groupInstallTargetsByDirectory(installableTargets, ws.baseDir);
|
|
357
|
+
const artifactAgents = artifactAgentIdsFromTargets(installableTargets);
|
|
358
|
+
const targets = yield* Effect.forEach(targetLocations, (location) => {
|
|
359
|
+
const linkPath = path.join(location.targetDir, sanitizedName);
|
|
360
|
+
return targetChangeBeforeInstall({
|
|
361
|
+
linkPath,
|
|
362
|
+
canonicalSkillSrcPath: skillSrcPath,
|
|
363
|
+
}).pipe(Effect.map((change) => {
|
|
364
|
+
const agentIds = artifactTargetAgentIds(location.agentIds);
|
|
365
|
+
return {
|
|
366
|
+
path: path.relative(ws.baseDir, linkPath),
|
|
367
|
+
change,
|
|
368
|
+
...(agentIds.length > 0 ? { agentIds } : {}),
|
|
369
|
+
};
|
|
370
|
+
}));
|
|
371
|
+
}, { concurrency: "unbounded" });
|
|
372
|
+
const firstTarget = targets[0];
|
|
373
|
+
const rawDisplayPath = firstTarget === undefined ? path.relative(ws.baseDir, skillSrcPath) : firstTarget.path;
|
|
374
|
+
const version = ref.refType === "registry" ? ref.version : undefined;
|
|
375
|
+
const installedBefore = yield* skillManager
|
|
376
|
+
.isInstalled({ target: { type: "skill", name: ref.skill.name } })
|
|
377
|
+
.pipe(Effect.catch(() => Effect.succeed(false)));
|
|
378
|
+
const releaseAgeWarning = yield* brandNewReleaseAgeWarning(ref, installedBefore);
|
|
379
|
+
return withPlanWarning(buildInstallOperation(skillManager, {
|
|
380
|
+
toStepFailure: lifecycleStepFailure,
|
|
381
|
+
ref,
|
|
382
|
+
versionRange: entry.versionRange,
|
|
383
|
+
force: intent.force === true,
|
|
384
|
+
installedBefore: Effect.succeed(installedBefore),
|
|
385
|
+
buildArtifact: ({ installedBefore }) => Effect.gen(function* () {
|
|
386
|
+
const fileCount = yield* countFiles(fs, path, skillSrcPath);
|
|
387
|
+
const currentSourceHash = yield* computeSkillSourceHash(skillSrcPath);
|
|
388
|
+
const sameVersion = previousVersion === version;
|
|
389
|
+
const sameSource = sourceHashBeforeInstall === currentSourceHash;
|
|
390
|
+
const fallbackChange = !installedBefore
|
|
391
|
+
? "created"
|
|
392
|
+
: sameVersion && sameSource
|
|
393
|
+
? "unchanged"
|
|
394
|
+
: "updated";
|
|
395
|
+
const artifactChange = artifactChangeFromTargets(fallbackChange, targets);
|
|
396
|
+
const sourceDetails = gitHostedSkillArtifactSource(ref);
|
|
397
|
+
return {
|
|
398
|
+
path: rawDisplayPath.length === 0 ? "." : rawDisplayPath,
|
|
399
|
+
scope: ws.scope,
|
|
400
|
+
agents: artifactAgents,
|
|
401
|
+
...(version !== undefined ? { version } : {}),
|
|
402
|
+
change: artifactChange,
|
|
403
|
+
...(previousVersion !== undefined && previousVersion !== version
|
|
404
|
+
? { previousVersion }
|
|
405
|
+
: {}),
|
|
406
|
+
fileCount,
|
|
407
|
+
...(targets.length > 0 ? { targets } : {}),
|
|
408
|
+
...(sourceDetails !== undefined ? { source: sourceDetails } : {}),
|
|
409
|
+
};
|
|
410
|
+
}),
|
|
411
|
+
}), releaseAgeWarning);
|
|
412
|
+
}).pipe(Effect.mapError((cause) => installRefused({
|
|
413
|
+
category: "internal",
|
|
414
|
+
detail: `Skill install planning failed for ${entry.ref.skill.name}`,
|
|
415
|
+
cause,
|
|
416
|
+
}))), { concurrency: 1 });
|
|
417
|
+
return {
|
|
418
|
+
_tag: "Plan",
|
|
419
|
+
name: intent.skillsToInstall.length === 0
|
|
420
|
+
? "Install skills"
|
|
421
|
+
: intent.skillsToInstall.length === 1
|
|
422
|
+
? "Install skill"
|
|
423
|
+
: `Install ${intent.skillsToInstall.length} skills`,
|
|
424
|
+
description: Option.none(),
|
|
425
|
+
presentation: operationPresentation({ imperative: "install", past: "Installed", gerund: "Installing" }, "skill"),
|
|
426
|
+
jobs: [{ concurrency: 1, steps }],
|
|
427
|
+
};
|
|
428
|
+
});
|
|
429
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which of a source's skills this request installs.
|
|
3
|
+
*
|
|
4
|
+
* Named skills are matched by glob and every named pattern must match
|
|
5
|
+
* something; `--all` and an unattended invocation take everything; a source
|
|
6
|
+
* offering exactly one skill needs no decision; anything else is a choice
|
|
7
|
+
* only a person can make.
|
|
8
|
+
*
|
|
9
|
+
* @experimental This API is unstable and may change without notice.
|
|
10
|
+
*/
|
|
11
|
+
import * as Array from "effect/Array";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import type { SkillExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/skill";
|
|
14
|
+
import type { ExtensionLifecycleFailed } from "../../errors.js";
|
|
15
|
+
import { ExtensionSelectionInteraction, type ExtensionSelectionCancelled } from "../../install/selection-interaction.js";
|
|
16
|
+
export interface SkillSelectionRequest {
|
|
17
|
+
/** Names or glob patterns the request named explicitly. */
|
|
18
|
+
readonly requestedSkills: ReadonlyArray<string>;
|
|
19
|
+
/** Take everything the source offers without asking. */
|
|
20
|
+
readonly all: boolean;
|
|
21
|
+
/** No prompt can open in this invocation. */
|
|
22
|
+
readonly nonInteractive: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Settle which discovered skills this request installs. */
|
|
25
|
+
export declare const determineSkillsToInstall: (skills: Array.NonEmptyReadonlyArray<SkillExtensionRef>, request: SkillSelectionRequest) => Effect.Effect<ReadonlyArray<SkillExtensionRef>, ExtensionLifecycleFailed | ExtensionSelectionCancelled, ExtensionSelectionInteraction>;
|
|
26
|
+
//# sourceMappingURL=selection.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which of a source's skills this request installs.
|
|
3
|
+
*
|
|
4
|
+
* Named skills are matched by glob and every named pattern must match
|
|
5
|
+
* something; `--all` and an unattended invocation take everything; a source
|
|
6
|
+
* offering exactly one skill needs no decision; anything else is a choice
|
|
7
|
+
* only a person can make.
|
|
8
|
+
*
|
|
9
|
+
* @experimental This API is unstable and may change without notice.
|
|
10
|
+
*/
|
|
11
|
+
import * as Array from "effect/Array";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import { expandGlobs } from "../../glob.js";
|
|
14
|
+
import { ExtensionSelectionInteraction, } from "../../install/selection-interaction.js";
|
|
15
|
+
import { installRefused } from "../../install/vocabulary.js";
|
|
16
|
+
/** Settle which discovered skills this request installs. */
|
|
17
|
+
export const determineSkillsToInstall = Effect.fn("InstallExtensions.determineSkillsToInstall")(function* (skills, request) {
|
|
18
|
+
if (request.requestedSkills.length > 0) {
|
|
19
|
+
const allNames = Array.map(skills, (skill) => skill.skill.name);
|
|
20
|
+
const matched = expandGlobs(request.requestedSkills, allNames);
|
|
21
|
+
if (matched.length === 0) {
|
|
22
|
+
return yield* installRefused({
|
|
23
|
+
category: "not_found",
|
|
24
|
+
detail: `No skills matched: ${request.requestedSkills.join(", ")}. Source contains: ${[
|
|
25
|
+
...allNames,
|
|
26
|
+
]
|
|
27
|
+
.sort((left, right) => left.localeCompare(right))
|
|
28
|
+
.join(", ")}`,
|
|
29
|
+
recover: "Check the skill names or patterns and try again",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return Array.filter(skills, (skill) => matched.includes(skill.skill.name));
|
|
33
|
+
}
|
|
34
|
+
if (request.all || request.nonInteractive)
|
|
35
|
+
return skills;
|
|
36
|
+
if (skills.length === 1)
|
|
37
|
+
return skills;
|
|
38
|
+
const interaction = yield* ExtensionSelectionInteraction;
|
|
39
|
+
return yield* interaction.selectSkills(skills);
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which source a skill install request names.
|
|
3
|
+
*
|
|
4
|
+
* Every locator grammar the product accepts routes here: a registry pattern,
|
|
5
|
+
* a provider shorthand, an owner/repo slash, a bare name, a URL, an SCP
|
|
6
|
+
* address, or a local path. A workspace locator is refused because a
|
|
7
|
+
* workspace package is locally authoritative and installing over it would
|
|
8
|
+
* discard the author's own content.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import type { InputParseResult } from "@agentxm/extension-model/unstable/sources/parser";
|
|
14
|
+
import type { Source } from "@agentxm/extension-model/unstable/sources/types";
|
|
15
|
+
import { type SourceResolutionFailure } from "@agentxm/extension-sources";
|
|
16
|
+
import type { ExtensionLifecycleFailed } from "../../errors.js";
|
|
17
|
+
import { type RegistryResolutionOptions } from "../../install/registry-source-resolution.js";
|
|
18
|
+
import { type ResolveInstallRequirements } from "../../install/vocabulary.js";
|
|
19
|
+
/** Route one parsed skill locator to the source that serves it. */
|
|
20
|
+
export declare const resolveSkillInstallSource: (parseResult: InputParseResult, options?: RegistryResolutionOptions) => Effect.Effect<Source, ExtensionLifecycleFailed | SourceResolutionFailure, ResolveInstallRequirements>;
|
|
21
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which source a skill install request names.
|
|
3
|
+
*
|
|
4
|
+
* Every locator grammar the product accepts routes here: a registry pattern,
|
|
5
|
+
* a provider shorthand, an owner/repo slash, a bare name, a URL, an SCP
|
|
6
|
+
* address, or a local path. A workspace locator is refused because a
|
|
7
|
+
* workspace package is locally authoritative and installing over it would
|
|
8
|
+
* discard the author's own content.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import { resolveShorthandInputSource, resolveSlashInputSource, routeScpInput, routeUrlInput, } from "@agentxm/extension-sources";
|
|
15
|
+
import { resolveConfiguredRegistrySource, resolveDefaultRegistrySourceByName, } from "../../install/registry-source-resolution.js";
|
|
16
|
+
import { installRefused } from "../../install/vocabulary.js";
|
|
17
|
+
const resolveSkillRegistrySource = (pattern, options) => Effect.gen(function* () {
|
|
18
|
+
if (Option.isSome(pattern.type) && pattern.type.value !== "skills") {
|
|
19
|
+
return yield* installRefused({
|
|
20
|
+
category: "usage",
|
|
21
|
+
detail: `Cannot install "${pattern.type.value}" extensions with "skills install"`,
|
|
22
|
+
recover: `Use the "${pattern.type.value}" command instead, or remove the type qualifier to install as a skill`,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return yield* resolveConfiguredRegistrySource({
|
|
26
|
+
sourceName: pattern.sourceName,
|
|
27
|
+
owner: pattern.owner,
|
|
28
|
+
extensionType: "skill",
|
|
29
|
+
extensionName: pattern.name,
|
|
30
|
+
options,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
/** Route one parsed skill locator to the source that serves it. */
|
|
34
|
+
export const resolveSkillInstallSource = Effect.fn("InstallExtensions.resolveSkillSource")(function* (parseResult, options) {
|
|
35
|
+
const resolutionOptions = Option.fromUndefinedOr(options);
|
|
36
|
+
const pattern = parseResult.pattern;
|
|
37
|
+
switch (pattern.pattern) {
|
|
38
|
+
case "registry-pattern-input":
|
|
39
|
+
return yield* resolveSkillRegistrySource(pattern, resolutionOptions);
|
|
40
|
+
case "shorthand-input":
|
|
41
|
+
return yield* resolveShorthandInputSource({
|
|
42
|
+
pattern,
|
|
43
|
+
originalInput: parseResult.originalInput,
|
|
44
|
+
});
|
|
45
|
+
case "slash-pattern":
|
|
46
|
+
return yield* resolveSlashInputSource(pattern, parseResult.originalInput);
|
|
47
|
+
case "name-input":
|
|
48
|
+
return yield* resolveDefaultRegistrySourceByName({
|
|
49
|
+
name: pattern.name,
|
|
50
|
+
extensionType: "skill",
|
|
51
|
+
options: resolutionOptions,
|
|
52
|
+
});
|
|
53
|
+
case "url-input":
|
|
54
|
+
return yield* routeUrlInput(pattern.url, parseResult.originalInput);
|
|
55
|
+
case "git-scp-address":
|
|
56
|
+
return yield* routeScpInput(pattern, parseResult.originalInput);
|
|
57
|
+
case "file-path-pattern":
|
|
58
|
+
return { type: "local", path: pattern.path };
|
|
59
|
+
case "workspace-pattern-input":
|
|
60
|
+
return yield* installRefused({
|
|
61
|
+
category: "conflict",
|
|
62
|
+
detail: `Workspace source "${parseResult.originalInput}" is locally authoritative and cannot be installed over`,
|
|
63
|
+
suggestions: [
|
|
64
|
+
{ description: "Sync the workspace package", cmd: "axm sync" },
|
|
65
|
+
{ description: "Enable the workspace skill", cmd: "axm skills enable <name>" },
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
case "glob-input":
|
|
69
|
+
return yield* installRefused({
|
|
70
|
+
category: "usage",
|
|
71
|
+
detail: `Input pattern "${pattern.pattern}" is not supported for skill installation`,
|
|
72
|
+
recover: "Use a registry reference (e.g., @owner/skill-name), a URL, or a shorthand (owner/repo) instead",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=source.js.map
|