@agentxm/workspace-state 0.28.4-bootstrap.0
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/LICENSE +110 -0
- package/README.md +11 -0
- package/dist/src/index.d.ts +72 -0
- package/dist/src/index.js +88 -0
- package/dist/src/knowledge/discovery-config.d.ts +12 -0
- package/dist/src/knowledge/discovery-config.js +9 -0
- package/dist/src/lockfile/accepted-registry-version.d.ts +12 -0
- package/dist/src/lockfile/accepted-registry-version.js +13 -0
- package/dist/src/lockfile/entry-fields.d.ts +189 -0
- package/dist/src/lockfile/entry-fields.js +89 -0
- package/dist/src/lockfile/errors.d.ts +48 -0
- package/dist/src/lockfile/errors.js +27 -0
- package/dist/src/lockfile/index.d.ts +18 -0
- package/dist/src/lockfile/index.js +16 -0
- package/dist/src/lockfile/lockfile.d.ts +2255 -0
- package/dist/src/lockfile/lockfile.js +235 -0
- package/dist/src/lockfile/resolved-version.d.ts +4 -0
- package/dist/src/lockfile/resolved-version.js +7 -0
- package/dist/src/lockfile/schema.d.ts +3062 -0
- package/dist/src/lockfile/schema.js +406 -0
- package/dist/src/schema/index.d.ts +3 -0
- package/dist/src/schema/index.js +2 -0
- package/dist/src/schema/read-and-validate-json-file.d.ts +20 -0
- package/dist/src/schema/read-and-validate-json-file.js +85 -0
- package/dist/src/schema/types.d.ts +26 -0
- package/dist/src/schema/types.js +2 -0
- package/dist/src/settings/errors.d.ts +22 -0
- package/dist/src/settings/errors.js +15 -0
- package/dist/src/settings/format-preserving-json.d.ts +40 -0
- package/dist/src/settings/format-preserving-json.js +80 -0
- package/dist/src/settings/index.d.ts +15 -0
- package/dist/src/settings/index.js +14 -0
- package/dist/src/settings/schema.d.ts +687 -0
- package/dist/src/settings/schema.js +977 -0
- package/dist/src/settings/settings.d.ts +38 -0
- package/dist/src/settings/settings.js +213 -0
- package/dist/src/testing.d.ts +17 -0
- package/dist/src/testing.js +17 -0
- package/dist/src/utils/atomic-write.d.ts +67 -0
- package/dist/src/utils/atomic-write.js +71 -0
- package/dist/src/utils/environment.d.ts +16 -0
- package/dist/src/utils/environment.js +19 -0
- package/dist/src/utils/path-safety.d.ts +25 -0
- package/dist/src/utils/path-safety.js +34 -0
- package/dist/src/utils/resolve-parent-symlinks.d.ts +16 -0
- package/dist/src/utils/resolve-parent-symlinks.js +36 -0
- package/dist/src/workspace/accepted-canonical-ref.d.ts +58 -0
- package/dist/src/workspace/accepted-canonical-ref.js +229 -0
- package/dist/src/workspace/artifact-change.d.ts +14 -0
- package/dist/src/workspace/artifact-change.js +18 -0
- package/dist/src/workspace/canonical-observation.d.ts +39 -0
- package/dist/src/workspace/canonical-observation.js +307 -0
- package/dist/src/workspace/configured-agent-outcome.d.ts +22 -0
- package/dist/src/workspace/configured-agent-outcome.js +33 -0
- package/dist/src/workspace/configured-agent-outcomes-provider.d.ts +50 -0
- package/dist/src/workspace/configured-agent-outcomes-provider.js +26 -0
- package/dist/src/workspace/configured-agent-outcomes.d.ts +48 -0
- package/dist/src/workspace/configured-agent-outcomes.js +113 -0
- package/dist/src/workspace/configured-entry-resolution/types.d.ts +32 -0
- package/dist/src/workspace/configured-entry-resolution/types.js +2 -0
- package/dist/src/workspace/configured-entry-resolution/workspace-ref.d.ts +32 -0
- package/dist/src/workspace/configured-entry-resolution/workspace-ref.js +176 -0
- package/dist/src/workspace/constants.d.ts +6 -0
- package/dist/src/workspace/constants.js +6 -0
- package/dist/src/workspace/create-symlink.d.ts +26 -0
- package/dist/src/workspace/create-symlink.js +87 -0
- package/dist/src/workspace/desired-pack-lock.d.ts +18 -0
- package/dist/src/workspace/desired-pack-lock.js +132 -0
- package/dist/src/workspace/desired-state-enabled.d.ts +18 -0
- package/dist/src/workspace/desired-state-enabled.js +16 -0
- package/dist/src/workspace/desired-state-graph.d.ts +114 -0
- package/dist/src/workspace/desired-state-graph.js +384 -0
- package/dist/src/workspace/desired-state-problem-text.d.ts +6 -0
- package/dist/src/workspace/desired-state-problem-text.js +27 -0
- package/dist/src/workspace/errors.d.ts +184 -0
- package/dist/src/workspace/errors.js +79 -0
- package/dist/src/workspace/extension-name.d.ts +28 -0
- package/dist/src/workspace/extension-name.js +66 -0
- package/dist/src/workspace/extension-paths.d.ts +82 -0
- package/dist/src/workspace/extension-paths.js +172 -0
- package/dist/src/workspace/footprint-recorder.d.ts +30 -0
- package/dist/src/workspace/footprint-recorder.js +32 -0
- package/dist/src/workspace/layout.d.ts +43 -0
- package/dist/src/workspace/layout.js +164 -0
- package/dist/src/workspace/lock-entry-to-ref.d.ts +40 -0
- package/dist/src/workspace/lock-entry-to-ref.js +433 -0
- package/dist/src/workspace/lock-entry-to-source-params.d.ts +26 -0
- package/dist/src/workspace/lock-entry-to-source-params.js +81 -0
- package/dist/src/workspace/locked-entries.d.ts +30 -0
- package/dist/src/workspace/locked-entries.js +34 -0
- package/dist/src/workspace/materialized-file-target.d.ts +14 -0
- package/dist/src/workspace/materialized-file-target.js +14 -0
- package/dist/src/workspace/materialized-tree.d.ts +23 -0
- package/dist/src/workspace/materialized-tree.js +90 -0
- package/dist/src/workspace/mcp-entry-semantics.d.ts +31 -0
- package/dist/src/workspace/mcp-entry-semantics.js +60 -0
- package/dist/src/workspace/observed-installed.d.ts +9 -0
- package/dist/src/workspace/observed-installed.js +9 -0
- package/dist/src/workspace/pack-manifest-content-identity.d.ts +12 -0
- package/dist/src/workspace/pack-manifest-content-identity.js +20 -0
- package/dist/src/workspace/pack-paths.d.ts +24 -0
- package/dist/src/workspace/pack-paths.js +16 -0
- package/dist/src/workspace/package-hash.d.ts +25 -0
- package/dist/src/workspace/package-hash.js +45 -0
- package/dist/src/workspace/paths.d.ts +24 -0
- package/dist/src/workspace/paths.js +52 -0
- package/dist/src/workspace/read-model/__fixtures__/builder.d.ts +199 -0
- package/dist/src/workspace/read-model/__fixtures__/builder.js +588 -0
- package/dist/src/workspace/read-model/__fixtures__/decoders.d.ts +15 -0
- package/dist/src/workspace/read-model/__fixtures__/decoders.js +15 -0
- package/dist/src/workspace/read-model/__fixtures__/occurrences.d.ts +72 -0
- package/dist/src/workspace/read-model/__fixtures__/occurrences.js +134 -0
- package/dist/src/workspace/read-model/__fixtures__/scenario-harness.d.ts +99 -0
- package/dist/src/workspace/read-model/__fixtures__/scenario-harness.js +142 -0
- package/dist/src/workspace/read-model/__fixtures__/test-layer.d.ts +60 -0
- package/dist/src/workspace/read-model/__fixtures__/test-layer.js +57 -0
- package/dist/src/workspace/read-model/agent-presence.d.ts +32 -0
- package/dist/src/workspace/read-model/agent-presence.js +21 -0
- package/dist/src/workspace/read-model/agent-root-resolver.d.ts +38 -0
- package/dist/src/workspace/read-model/agent-root-resolver.js +35 -0
- package/dist/src/workspace/read-model/agents/index.d.ts +38 -0
- package/dist/src/workspace/read-model/agents/index.js +45 -0
- package/dist/src/workspace/read-model/agents/shared.d.ts +27 -0
- package/dist/src/workspace/read-model/agents/shared.js +63 -0
- package/dist/src/workspace/read-model/agents/types.d.ts +133 -0
- package/dist/src/workspace/read-model/agents/types.js +51 -0
- package/dist/src/workspace/read-model/diagnostics.d.ts +18 -0
- package/dist/src/workspace/read-model/diagnostics.js +14 -0
- package/dist/src/workspace/read-model/discovery/index.d.ts +5 -0
- package/dist/src/workspace/read-model/discovery/index.js +5 -0
- package/dist/src/workspace/read-model/discovery/plugin-manifests.d.ts +16 -0
- package/dist/src/workspace/read-model/discovery/plugin-manifests.js +168 -0
- package/dist/src/workspace/read-model/discovery/skills.d.ts +58 -0
- package/dist/src/workspace/read-model/discovery/skills.js +263 -0
- package/dist/src/workspace/read-model/discovery/subagents.d.ts +37 -0
- package/dist/src/workspace/read-model/discovery/subagents.js +48 -0
- package/dist/src/workspace/read-model/errors.d.ts +93 -0
- package/dist/src/workspace/read-model/errors.js +30 -0
- package/dist/src/workspace/read-model/extensions/actual-helpers.d.ts +4 -0
- package/dist/src/workspace/read-model/extensions/actual-helpers.js +4 -0
- package/dist/src/workspace/read-model/extensions/hook.d.ts +104 -0
- package/dist/src/workspace/read-model/extensions/hook.js +119 -0
- package/dist/src/workspace/read-model/extensions/index.d.ts +19 -0
- package/dist/src/workspace/read-model/extensions/index.js +43 -0
- package/dist/src/workspace/read-model/extensions/indexByName.d.ts +31 -0
- package/dist/src/workspace/read-model/extensions/indexByName.js +30 -0
- package/dist/src/workspace/read-model/extensions/inventory.d.ts +99 -0
- package/dist/src/workspace/read-model/extensions/inventory.js +111 -0
- package/dist/src/workspace/read-model/extensions/knowledge.d.ts +101 -0
- package/dist/src/workspace/read-model/extensions/knowledge.js +121 -0
- package/dist/src/workspace/read-model/extensions/mcp-server.d.ts +106 -0
- package/dist/src/workspace/read-model/extensions/mcp-server.js +122 -0
- package/dist/src/workspace/read-model/extensions/pack.d.ts +104 -0
- package/dist/src/workspace/read-model/extensions/pack.js +123 -0
- package/dist/src/workspace/read-model/extensions/package-root.d.ts +39 -0
- package/dist/src/workspace/read-model/extensions/package-root.js +48 -0
- package/dist/src/workspace/read-model/extensions/projection.d.ts +137 -0
- package/dist/src/workspace/read-model/extensions/projection.js +180 -0
- package/dist/src/workspace/read-model/extensions/rule.d.ts +104 -0
- package/dist/src/workspace/read-model/extensions/rule.js +113 -0
- package/dist/src/workspace/read-model/extensions/skill.d.ts +170 -0
- package/dist/src/workspace/read-model/extensions/skill.js +148 -0
- package/dist/src/workspace/read-model/extensions/subagent.d.ts +97 -0
- package/dist/src/workspace/read-model/extensions/subagent.js +120 -0
- package/dist/src/workspace/read-model/scanners/agent-dir.d.ts +49 -0
- package/dist/src/workspace/read-model/scanners/agent-dir.js +180 -0
- package/dist/src/workspace/read-model/scanners/agent-root.d.ts +73 -0
- package/dist/src/workspace/read-model/scanners/agent-root.js +148 -0
- package/dist/src/workspace/read-model/scanners/agent-settings.d.ts +43 -0
- package/dist/src/workspace/read-model/scanners/agent-settings.js +54 -0
- package/dist/src/workspace/read-model/scanners/canonical-extensions.d.ts +48 -0
- package/dist/src/workspace/read-model/scanners/canonical-extensions.js +237 -0
- package/dist/src/workspace/read-model/scanners/fs-helpers.d.ts +63 -0
- package/dist/src/workspace/read-model/scanners/fs-helpers.js +106 -0
- package/dist/src/workspace/read-model/scanners/index.d.ts +15 -0
- package/dist/src/workspace/read-model/scanners/index.js +34 -0
- package/dist/src/workspace/read-model/scanners/mcp-config.d.ts +47 -0
- package/dist/src/workspace/read-model/scanners/mcp-config.js +212 -0
- package/dist/src/workspace/read-model/scanners/types.d.ts +170 -0
- package/dist/src/workspace/read-model/scanners/types.js +86 -0
- package/dist/src/workspace/read-model/service.d.ts +103 -0
- package/dist/src/workspace/read-model/service.js +391 -0
- package/dist/src/workspace/read-model/state.d.ts +35 -0
- package/dist/src/workspace/read-model/state.js +97 -0
- package/dist/src/workspace/read-model/types.d.ts +75 -0
- package/dist/src/workspace/read-model/types.js +26 -0
- package/dist/src/workspace/read-model-record-readers.d.ts +34 -0
- package/dist/src/workspace/read-model-record-readers.js +467 -0
- package/dist/src/workspace/read-model-record-rows.d.ts +45 -0
- package/dist/src/workspace/read-model-record-rows.js +33 -0
- package/dist/src/workspace/read-model-record-types.d.ts +45 -0
- package/dist/src/workspace/read-model-record-types.js +13 -0
- package/dist/src/workspace/remove-if-exists.d.ts +13 -0
- package/dist/src/workspace/remove-if-exists.js +26 -0
- package/dist/src/workspace/rendered-files.d.ts +53 -0
- package/dist/src/workspace/rendered-files.js +50 -0
- package/dist/src/workspace/scope-refusal.d.ts +26 -0
- package/dist/src/workspace/scope-refusal.js +29 -0
- package/dist/src/workspace/service-interface.d.ts +479 -0
- package/dist/src/workspace/service-interface.js +27 -0
- package/dist/src/workspace/service.d.ts +1665 -0
- package/dist/src/workspace/service.js +1263 -0
- package/dist/src/workspace/setup-scope-support.d.ts +27 -0
- package/dist/src/workspace/setup-scope-support.js +299 -0
- package/dist/src/workspace/skill-paths.d.ts +33 -0
- package/dist/src/workspace/skill-paths.js +14 -0
- package/dist/src/workspace/source-metadata.d.ts +7 -0
- package/dist/src/workspace/source-metadata.js +10 -0
- package/dist/src/workspace/source-to-lock-entry.d.ts +32 -0
- package/dist/src/workspace/source-to-lock-entry.js +68 -0
- package/dist/src/workspace/test-stubs.d.ts +144 -0
- package/dist/src/workspace/test-stubs.js +412 -0
- package/dist/src/workspace/transaction.d.ts +218 -0
- package/dist/src/workspace/transaction.js +177 -0
- package/package.json +57 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill discovery algorithm (3-phase: direct match, priority scan, recursive fallback).
|
|
3
|
+
*
|
|
4
|
+
* The `skillsInDir` function is used by source providers (local, git-hosting)
|
|
5
|
+
* to discover skills within a directory structure.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
import * as FileSystem from "effect/FileSystem";
|
|
10
|
+
import * as Path from "effect/Path";
|
|
11
|
+
import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
|
|
12
|
+
import { AGENT_IDS } from "@agentxm/extension-model/unstable/agents/types";
|
|
13
|
+
import { parsePluginManifests } from "./plugin-manifests.js";
|
|
14
|
+
import { parseSkillMd } from "@agentxm/registry-protocol/unstable/content/skill-content";
|
|
15
|
+
import * as Array from "effect/Array";
|
|
16
|
+
import * as Effect from "effect/Effect";
|
|
17
|
+
import * as Option from "effect/Option";
|
|
18
|
+
import { SkillDiscoveryRootInvalid } from "../errors.js";
|
|
19
|
+
import { DISCOVERY_MAX_DEPTH, DISCOVERY_SKIPPED_DIRECTORIES, } from "@agentxm/extension-model/unstable/discovery-walk";
|
|
20
|
+
import { envOption } from "../../../utils/environment.js";
|
|
21
|
+
/**
|
|
22
|
+
* Build a DiscoveredSkill from a skill and its directory path.
|
|
23
|
+
*/
|
|
24
|
+
const makeDiscoveredSkill = (skill, fullPath) => ({
|
|
25
|
+
type: "skill",
|
|
26
|
+
skill,
|
|
27
|
+
location: `file://${fullPath}`,
|
|
28
|
+
});
|
|
29
|
+
// -----------------------------------------------------------------------------
|
|
30
|
+
// Constants
|
|
31
|
+
// -----------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Exact filename for skill definition files.
|
|
34
|
+
*/
|
|
35
|
+
const SKILL_FILENAME = "SKILL.md";
|
|
36
|
+
/**
|
|
37
|
+
* Canonical skill container directories for Phase 2 priority scan.
|
|
38
|
+
*/
|
|
39
|
+
const STATIC_PRIORITY_DIRECTORIES = [
|
|
40
|
+
"skills",
|
|
41
|
+
"skills/.curated",
|
|
42
|
+
"skills/.experimental",
|
|
43
|
+
"skills/.system",
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Derive the full Phase 2 priority directory list.
|
|
47
|
+
*
|
|
48
|
+
* Composition:
|
|
49
|
+
* 1. `.` (searchPath root) — always first, highest priority
|
|
50
|
+
* 2. Non-agent static dirs: skills, skills/.curated, skills/.experimental, skills/.system
|
|
51
|
+
* 3. Agent dirs: unique primary and additional read paths from the AgentDescriptor registry
|
|
52
|
+
*/
|
|
53
|
+
export const getPriorityDirectories = () => {
|
|
54
|
+
const agentDirs = Array.dedupe(AGENT_IDS.flatMap((id) => {
|
|
55
|
+
const skills = AGENTS[id].skills;
|
|
56
|
+
return skills === undefined
|
|
57
|
+
? []
|
|
58
|
+
: [skills.dir, ...skills.additionalReadPaths.map(({ path }) => path)];
|
|
59
|
+
}));
|
|
60
|
+
return Array.dedupe([".", ...STATIC_PRIORITY_DIRECTORIES, ...agentDirs]);
|
|
61
|
+
};
|
|
62
|
+
// -----------------------------------------------------------------------------
|
|
63
|
+
// Internal Skill Filtering
|
|
64
|
+
// -----------------------------------------------------------------------------
|
|
65
|
+
const isInternalSkill = (skill) => Option.match(skill.metadata, {
|
|
66
|
+
onNone: () => false,
|
|
67
|
+
onSome: (metadata) => metadata["internal"] === "true",
|
|
68
|
+
});
|
|
69
|
+
const shouldIncludeSkill = (skill, options, installInternalSkills) => {
|
|
70
|
+
if (!isInternalSkill(skill))
|
|
71
|
+
return true;
|
|
72
|
+
const envVal = Option.getOrUndefined(installInternalSkills);
|
|
73
|
+
return options.includeInternal || envVal === "1" || envVal === "true";
|
|
74
|
+
};
|
|
75
|
+
// -----------------------------------------------------------------------------
|
|
76
|
+
// Phase Helpers
|
|
77
|
+
// -----------------------------------------------------------------------------
|
|
78
|
+
/**
|
|
79
|
+
* Try to find and parse a SKILL.md in a given directory.
|
|
80
|
+
* Returns Option.some(Skill) if found and valid, Option.none() otherwise.
|
|
81
|
+
* All errors are silently swallowed.
|
|
82
|
+
*/
|
|
83
|
+
const tryParseSkillInDir = (dir) => Effect.gen(function* () {
|
|
84
|
+
const fs = yield* FileSystem.FileSystem;
|
|
85
|
+
const path = yield* Path.Path;
|
|
86
|
+
const entries = yield* fs.readDirectory(dir).pipe(Effect.option);
|
|
87
|
+
if (Option.isNone(entries))
|
|
88
|
+
return Option.none();
|
|
89
|
+
if (!entries.value.includes(SKILL_FILENAME))
|
|
90
|
+
return Option.none();
|
|
91
|
+
const fullPath = path.join(dir, SKILL_FILENAME);
|
|
92
|
+
const content = yield* fs.readFileString(fullPath).pipe(Effect.option);
|
|
93
|
+
if (Option.isNone(content))
|
|
94
|
+
return Option.none();
|
|
95
|
+
return parseSkillMd(content.value, path.basename(dir));
|
|
96
|
+
});
|
|
97
|
+
const discoverSkillInDir = (dir, options, installInternalSkills) => Effect.gen(function* () {
|
|
98
|
+
const skill = yield* tryParseSkillInDir(dir);
|
|
99
|
+
if (Option.isNone(skill))
|
|
100
|
+
return { foundSkillDir: false, skills: [] };
|
|
101
|
+
if (!shouldIncludeSkill(skill.value, options, installInternalSkills)) {
|
|
102
|
+
return { foundSkillDir: true, skills: [] };
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
foundSkillDir: true,
|
|
106
|
+
skills: [makeDiscoveredSkill(skill.value, dir)],
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
/**
|
|
110
|
+
* Scan one level of children in a directory for skills.
|
|
111
|
+
* Each immediate subdirectory is checked for a SKILL.md.
|
|
112
|
+
*/
|
|
113
|
+
const scanDirectory = (dir, options, installInternalSkills) => Effect.gen(function* () {
|
|
114
|
+
const fs = yield* FileSystem.FileSystem;
|
|
115
|
+
const path = yield* Path.Path;
|
|
116
|
+
const entries = yield* fs.readDirectory(dir).pipe(Effect.option);
|
|
117
|
+
if (Option.isNone(entries))
|
|
118
|
+
return [];
|
|
119
|
+
return yield* Effect.forEach(entries.value, (entry) => Effect.gen(function* () {
|
|
120
|
+
const fullPath = path.join(dir, entry);
|
|
121
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect.option);
|
|
122
|
+
if (Option.isNone(stat) || stat.value.type !== "Directory")
|
|
123
|
+
return [];
|
|
124
|
+
const discovered = yield* discoverSkillInDir(fullPath, options, installInternalSkills);
|
|
125
|
+
return discovered.skills;
|
|
126
|
+
}), { concurrency: "unbounded" }).pipe(Effect.map((results) => Array.flatten(results)));
|
|
127
|
+
});
|
|
128
|
+
/**
|
|
129
|
+
* Scan canonical skill containers. Each direct child may be either a skill
|
|
130
|
+
* directory or a category that contains skill directories one level deeper.
|
|
131
|
+
*/
|
|
132
|
+
const scanSkillContainerDirectory = (dir, options, installInternalSkills) => Effect.gen(function* () {
|
|
133
|
+
const fs = yield* FileSystem.FileSystem;
|
|
134
|
+
const path = yield* Path.Path;
|
|
135
|
+
const entries = yield* fs.readDirectory(dir).pipe(Effect.option);
|
|
136
|
+
if (Option.isNone(entries))
|
|
137
|
+
return [];
|
|
138
|
+
return yield* Effect.forEach(entries.value, (entry) => Effect.gen(function* () {
|
|
139
|
+
if (DISCOVERY_SKIPPED_DIRECTORIES.has(entry))
|
|
140
|
+
return [];
|
|
141
|
+
const fullPath = path.join(dir, entry);
|
|
142
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect.option);
|
|
143
|
+
if (Option.isNone(stat) || stat.value.type !== "Directory")
|
|
144
|
+
return [];
|
|
145
|
+
const discovered = yield* discoverSkillInDir(fullPath, options, installInternalSkills);
|
|
146
|
+
if (discovered.foundSkillDir)
|
|
147
|
+
return discovered.skills;
|
|
148
|
+
const childEntries = yield* fs.readDirectory(fullPath).pipe(Effect.option);
|
|
149
|
+
if (Option.isNone(childEntries))
|
|
150
|
+
return [];
|
|
151
|
+
return yield* Effect.forEach(childEntries.value, (childEntry) => Effect.gen(function* () {
|
|
152
|
+
if (DISCOVERY_SKIPPED_DIRECTORIES.has(childEntry))
|
|
153
|
+
return [];
|
|
154
|
+
const childPath = path.join(fullPath, childEntry);
|
|
155
|
+
const childStat = yield* fs.stat(childPath).pipe(Effect.option);
|
|
156
|
+
if (Option.isNone(childStat) || childStat.value.type !== "Directory")
|
|
157
|
+
return [];
|
|
158
|
+
const childDiscovered = yield* discoverSkillInDir(childPath, options, installInternalSkills);
|
|
159
|
+
return childDiscovered.skills;
|
|
160
|
+
}), { concurrency: "unbounded" }).pipe(Effect.map((results) => Array.flatten(results)));
|
|
161
|
+
}), { concurrency: "unbounded" }).pipe(Effect.map((results) => Array.flatten(results)));
|
|
162
|
+
});
|
|
163
|
+
const scanPriorityDirectory = (priorityDir, fullDir, options, installInternalSkills) => priorityDir === "."
|
|
164
|
+
? scanDirectory(fullDir, options, installInternalSkills)
|
|
165
|
+
: scanSkillContainerDirectory(fullDir, options, installInternalSkills);
|
|
166
|
+
/**
|
|
167
|
+
* Recursive DFS scan with depth limit.
|
|
168
|
+
* Skips well-known non-skill directories.
|
|
169
|
+
*/
|
|
170
|
+
const recursiveScan = (dir, options, depth, installInternalSkills) => Effect.gen(function* () {
|
|
171
|
+
if (depth > DISCOVERY_MAX_DEPTH)
|
|
172
|
+
return [];
|
|
173
|
+
const fs = yield* FileSystem.FileSystem;
|
|
174
|
+
const path = yield* Path.Path;
|
|
175
|
+
const entries = yield* fs.readDirectory(dir).pipe(Effect.option);
|
|
176
|
+
if (Option.isNone(entries))
|
|
177
|
+
return [];
|
|
178
|
+
return yield* Effect.forEach(entries.value, (entry) => Effect.gen(function* () {
|
|
179
|
+
if (DISCOVERY_SKIPPED_DIRECTORIES.has(entry))
|
|
180
|
+
return [];
|
|
181
|
+
const fullPath = path.join(dir, entry);
|
|
182
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect.option);
|
|
183
|
+
if (Option.isNone(stat) || stat.value.type !== "Directory")
|
|
184
|
+
return [];
|
|
185
|
+
const discovered = yield* discoverSkillInDir(fullPath, options, installInternalSkills);
|
|
186
|
+
if (discovered.foundSkillDir)
|
|
187
|
+
return discovered.skills;
|
|
188
|
+
// Recurse into subdirectories
|
|
189
|
+
const subResults = yield* recursiveScan(fullPath, options, depth + 1, installInternalSkills);
|
|
190
|
+
return subResults;
|
|
191
|
+
}), { concurrency: "unbounded" }).pipe(Effect.map((results) => Array.flatten(results)));
|
|
192
|
+
});
|
|
193
|
+
// -----------------------------------------------------------------------------
|
|
194
|
+
// 3-Phase Discovery
|
|
195
|
+
// -----------------------------------------------------------------------------
|
|
196
|
+
/**
|
|
197
|
+
* Discover skills in a directory using a 3-phase algorithm:
|
|
198
|
+
*
|
|
199
|
+
* Phase 1 — Direct match: check if search root itself contains SKILL.md
|
|
200
|
+
* Phase 2 — Priority directory scan: scan well-known directories one level deep
|
|
201
|
+
* Phase 3 — Recursive fallback: bounded DFS when prior phases find nothing or fullDepth is true
|
|
202
|
+
*
|
|
203
|
+
* Skills are deduplicated by name (first-found wins). Internal skills are
|
|
204
|
+
* filtered unless opted in.
|
|
205
|
+
*
|
|
206
|
+
* @experimental This API is unstable and may change without notice.
|
|
207
|
+
*/
|
|
208
|
+
export const skillsInDir = (basePath, subPath, options) => Effect.gen(function* () {
|
|
209
|
+
const fs = yield* FileSystem.FileSystem;
|
|
210
|
+
const path = yield* Path.Path;
|
|
211
|
+
const installInternalSkills = yield* envOption("INSTALL_INTERNAL_SKILLS");
|
|
212
|
+
// Compute effective search root
|
|
213
|
+
const searchRoot = Option.match(subPath, {
|
|
214
|
+
onNone: () => basePath,
|
|
215
|
+
onSome: (p) => path.join(basePath, p),
|
|
216
|
+
});
|
|
217
|
+
// Verify the search root exists and is a directory
|
|
218
|
+
const stat = yield* fs
|
|
219
|
+
.stat(searchRoot)
|
|
220
|
+
.pipe(Effect.mapError((error) => new SkillDiscoveryRootInvalid({ searchRoot, problem: "inaccessible", cause: error })));
|
|
221
|
+
if (stat.type !== "Directory") {
|
|
222
|
+
return yield* new SkillDiscoveryRootInvalid({ searchRoot, problem: "not-directory" });
|
|
223
|
+
}
|
|
224
|
+
// ── Phase 1: Direct Match ──────────────────────────────────────────
|
|
225
|
+
const rootSkill = yield* tryParseSkillInDir(searchRoot);
|
|
226
|
+
const phase1Skills = Option.isSome(rootSkill) &&
|
|
227
|
+
shouldIncludeSkill(rootSkill.value, options, installInternalSkills)
|
|
228
|
+
? [makeDiscoveredSkill(rootSkill.value, searchRoot)]
|
|
229
|
+
: [];
|
|
230
|
+
if (phase1Skills.length > 0 && !options.fullDepth) {
|
|
231
|
+
return phase1Skills;
|
|
232
|
+
}
|
|
233
|
+
// ── Phase 2: Priority Directory Scan ───────────────────────────────
|
|
234
|
+
// Collect manifest-declared directories to append to priority scan
|
|
235
|
+
const manifestDirs = yield* parsePluginManifests(searchRoot);
|
|
236
|
+
// Build full list of directories to scan: derived priority dirs + manifest dirs
|
|
237
|
+
const priorityDirs = getPriorityDirectories();
|
|
238
|
+
const priorityFullDirs = priorityDirs.map((priorityDir) => priorityDir === "." ? searchRoot : path.join(searchRoot, priorityDir));
|
|
239
|
+
// Deduplicate manifest dirs against static priority dirs
|
|
240
|
+
const manifestDirsToAdd = manifestDirs.filter((d) => !priorityFullDirs.includes(d));
|
|
241
|
+
const priorityEntries = [
|
|
242
|
+
...priorityDirs.map((priorityDir) => ({
|
|
243
|
+
priorityDir,
|
|
244
|
+
fullDir: priorityDir === "." ? searchRoot : path.join(searchRoot, priorityDir),
|
|
245
|
+
})),
|
|
246
|
+
...manifestDirsToAdd.map((fullDir) => ({ priorityDir: ".", fullDir })),
|
|
247
|
+
];
|
|
248
|
+
const phase2Skills = yield* Effect.forEach(priorityEntries, ({ priorityDir, fullDir }) => scanPriorityDirectory(priorityDir, fullDir, options, installInternalSkills), { concurrency: "unbounded" }).pipe(Effect.map((results) => Array.flatten(results)));
|
|
249
|
+
// ── Phase 3: Recursive Fallback ────────────────────────────────────
|
|
250
|
+
const shouldRunPhase3 = (phase1Skills.length === 0 && phase2Skills.length === 0) || options.fullDepth;
|
|
251
|
+
const phase3Skills = shouldRunPhase3
|
|
252
|
+
? yield* recursiveScan(searchRoot, options, 0, installInternalSkills)
|
|
253
|
+
: [];
|
|
254
|
+
// Deduplicate by name (first-found wins across phases)
|
|
255
|
+
const seen = new Set();
|
|
256
|
+
return [...phase1Skills, ...phase2Skills, ...phase3Skills].filter(({ skill: { name } }) => {
|
|
257
|
+
if (seen.has(name))
|
|
258
|
+
return false;
|
|
259
|
+
seen.add(name);
|
|
260
|
+
return true;
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkspaceReadModel discovery capability for agent subagent files.
|
|
3
|
+
*/
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as FileSystem from "effect/FileSystem";
|
|
6
|
+
import * as Path from "effect/Path";
|
|
7
|
+
import { SubagentScanFailed } from "../errors.js";
|
|
8
|
+
export interface DetectedSubagentFile {
|
|
9
|
+
/** File path relative to the project directory */
|
|
10
|
+
readonly path: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AgentSubagentSummary {
|
|
13
|
+
/** Agent identifier */
|
|
14
|
+
readonly agentId: string;
|
|
15
|
+
/** Agent display name */
|
|
16
|
+
readonly agentName: string;
|
|
17
|
+
/** Subagent directory path relative to project */
|
|
18
|
+
readonly subagentDir: string;
|
|
19
|
+
/** Detected subagent files */
|
|
20
|
+
readonly files: ReadonlyArray<DetectedSubagentFile>;
|
|
21
|
+
}
|
|
22
|
+
export declare const scanAgentSubagentFiles: (agentId: string, projectDir: string) => Effect.Effect<{
|
|
23
|
+
path: string;
|
|
24
|
+
}[] | readonly [{
|
|
25
|
+
readonly path: string;
|
|
26
|
+
}], SubagentScanFailed, FileSystem.FileSystem | Path.Path> | Effect.Effect<readonly DetectedSubagentFile[], never, never>;
|
|
27
|
+
export declare const scanAllSubagentFiles: (projectDir: string) => Effect.Effect<{
|
|
28
|
+
agentId: "adal" | "aider-desk" | "amp" | "antigravity" | "antigravity-cli" | "augment" | "claude-code" | "cline" | "codearts-agent" | "codebuddy" | "codemaker" | "codestudio" | "codex" | "command-code" | "continue" | "cortex" | "crush" | "cursor" | "deepagents" | "devin" | "dexto" | "droid" | "firebender" | "forgecode" | "gemini-cli" | "github-copilot-cli" | "goose" | "grok-cli" | "hermes" | "ibm-bob" | "iflow-cli" | "junie" | "lingma" | "kilo" | "kimi-cli" | "kiro-cli" | "kode" | "mcpjam" | "minimax-code" | "mistral-vibe" | "mux" | "neovate" | "openclaw" | "opencode" | "openhands" | "ona" | "pi" | "pochi" | "qoder" | "qoder-cn" | "qwen-code" | "replit" | "roo" | "rovodev" | "tabnine-cli" | "trae-cn" | "trae" | "warp" | "windsurf" | "zencoder" | "zed" | "zenflow" | "universal";
|
|
29
|
+
agentName: string;
|
|
30
|
+
subagentDir: string;
|
|
31
|
+
files: {
|
|
32
|
+
path: string;
|
|
33
|
+
}[] | readonly [{
|
|
34
|
+
readonly path: string;
|
|
35
|
+
}];
|
|
36
|
+
}[], SubagentScanFailed, FileSystem.FileSystem | Path.Path>;
|
|
37
|
+
//# sourceMappingURL=subagents.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkspaceReadModel discovery capability for agent subagent files.
|
|
3
|
+
*/
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as FileSystem from "effect/FileSystem";
|
|
6
|
+
import * as Path from "effect/Path";
|
|
7
|
+
import { SubagentScanFailed } from "../errors.js";
|
|
8
|
+
import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
|
|
9
|
+
const isKnownAgentId = (id) => Object.hasOwn(AGENTS, id);
|
|
10
|
+
const scanKnownAgentSubagentFiles = (agent, projectDir) => Effect.gen(function* () {
|
|
11
|
+
const subagents = agent.subagents;
|
|
12
|
+
if (subagents === undefined)
|
|
13
|
+
return [];
|
|
14
|
+
const fs = yield* FileSystem.FileSystem;
|
|
15
|
+
const p = yield* Path.Path;
|
|
16
|
+
const subagentPath = p.resolve(projectDir, subagents.dir);
|
|
17
|
+
const exists = yield* fs.exists(subagentPath);
|
|
18
|
+
if (!exists)
|
|
19
|
+
return [];
|
|
20
|
+
if (subagents.isFile === true) {
|
|
21
|
+
return [{ path: subagents.dir }];
|
|
22
|
+
}
|
|
23
|
+
const entries = yield* fs.readDirectory(subagentPath);
|
|
24
|
+
const files = yield* Effect.filter(entries, (entry) => Effect.gen(function* () {
|
|
25
|
+
const stat = yield* fs.stat(p.join(subagentPath, entry));
|
|
26
|
+
return stat.type === "File";
|
|
27
|
+
}), { concurrency: "unbounded" });
|
|
28
|
+
return yield* Effect.forEach(files, (file) => Effect.succeed({
|
|
29
|
+
path: p.join(subagents.dir, file),
|
|
30
|
+
}), { concurrency: "unbounded" });
|
|
31
|
+
}).pipe(Effect.mapError((error) => new SubagentScanFailed({ agentName: agent.name, cause: error })));
|
|
32
|
+
export const scanAgentSubagentFiles = (agentId, projectDir) => isKnownAgentId(agentId)
|
|
33
|
+
? scanKnownAgentSubagentFiles(AGENTS[agentId], projectDir)
|
|
34
|
+
: Effect.succeed([]);
|
|
35
|
+
export const scanAllSubagentFiles = (projectDir) => Effect.gen(function* () {
|
|
36
|
+
const agentsWithSubagents = Object.values(AGENTS).filter((agent) => agent.subagents !== undefined);
|
|
37
|
+
const results = yield* Effect.forEach(agentsWithSubagents, (agent) => Effect.gen(function* () {
|
|
38
|
+
const files = yield* scanKnownAgentSubagentFiles(agent, projectDir);
|
|
39
|
+
return {
|
|
40
|
+
agentId: agent.id,
|
|
41
|
+
agentName: agent.name,
|
|
42
|
+
subagentDir: agent.subagents?.dir ?? "",
|
|
43
|
+
files,
|
|
44
|
+
};
|
|
45
|
+
}), { concurrency: "unbounded" });
|
|
46
|
+
return results.filter((result) => result.files.length > 0);
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=subagents.js.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Per-source tagged error families for WorkspaceReadModel source-backed cells. */
|
|
2
|
+
declare const SettingsIoError_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 & {
|
|
3
|
+
readonly _tag: "SettingsIoError";
|
|
4
|
+
} & Readonly<A>;
|
|
5
|
+
/** Settings file IO failure (unreadable, permission denied, lower-level error). */
|
|
6
|
+
export declare class SettingsIoError extends SettingsIoError_base<{
|
|
7
|
+
readonly path: string;
|
|
8
|
+
readonly cause: unknown;
|
|
9
|
+
}> {
|
|
10
|
+
}
|
|
11
|
+
declare const SettingsParseError_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 & {
|
|
12
|
+
readonly _tag: "SettingsParseError";
|
|
13
|
+
} & Readonly<A>;
|
|
14
|
+
/** Settings JSON parse failure; `raw` carries the unparsed text. */
|
|
15
|
+
export declare class SettingsParseError extends SettingsParseError_base<{
|
|
16
|
+
readonly path: string;
|
|
17
|
+
readonly raw: string;
|
|
18
|
+
readonly cause: unknown;
|
|
19
|
+
}> {
|
|
20
|
+
}
|
|
21
|
+
declare const SettingsDecodeError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
22
|
+
readonly _tag: "SettingsDecodeError";
|
|
23
|
+
} & Readonly<A>;
|
|
24
|
+
/** Settings schema decode failure; `raw` carries the parsed value. */
|
|
25
|
+
export declare class SettingsDecodeError extends SettingsDecodeError_base<{
|
|
26
|
+
readonly path: string;
|
|
27
|
+
readonly issues: ReadonlyArray<string>;
|
|
28
|
+
readonly raw: unknown;
|
|
29
|
+
}> {
|
|
30
|
+
}
|
|
31
|
+
/** Settings-read failure union (IO, parse, decode). */
|
|
32
|
+
export type SettingsReadError = SettingsIoError | SettingsParseError | SettingsDecodeError;
|
|
33
|
+
declare const LockfileIoError_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 & {
|
|
34
|
+
readonly _tag: "LockfileIoError";
|
|
35
|
+
} & Readonly<A>;
|
|
36
|
+
/** Lockfile IO failure. */
|
|
37
|
+
export declare class LockfileIoError extends LockfileIoError_base<{
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly cause: unknown;
|
|
40
|
+
}> {
|
|
41
|
+
}
|
|
42
|
+
declare const LockfileParseError_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 & {
|
|
43
|
+
readonly _tag: "LockfileParseError";
|
|
44
|
+
} & Readonly<A>;
|
|
45
|
+
/** Lockfile YAML parse failure; `raw` carries the unparsed text. */
|
|
46
|
+
export declare class LockfileParseError extends LockfileParseError_base<{
|
|
47
|
+
readonly path: string;
|
|
48
|
+
readonly raw: string;
|
|
49
|
+
readonly cause: unknown;
|
|
50
|
+
}> {
|
|
51
|
+
}
|
|
52
|
+
declare const LockfileDecodeError_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 & {
|
|
53
|
+
readonly _tag: "LockfileDecodeError";
|
|
54
|
+
} & Readonly<A>;
|
|
55
|
+
/** Lockfile schema decode failure; `raw` carries the parsed value. */
|
|
56
|
+
export declare class LockfileDecodeError extends LockfileDecodeError_base<{
|
|
57
|
+
readonly path: string;
|
|
58
|
+
readonly issues: ReadonlyArray<string>;
|
|
59
|
+
readonly raw: unknown;
|
|
60
|
+
}> {
|
|
61
|
+
}
|
|
62
|
+
/** Lockfile-read failure union (IO, parse, decode). */
|
|
63
|
+
export type LockfileReadError = LockfileIoError | LockfileParseError | LockfileDecodeError;
|
|
64
|
+
declare const WorkspaceRootEscape_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 & {
|
|
65
|
+
readonly _tag: "WorkspaceRootEscape";
|
|
66
|
+
} & Readonly<A>;
|
|
67
|
+
/** Provider-construction error: workspace root escapes the configured allowed root. */
|
|
68
|
+
export declare class WorkspaceRootEscape extends WorkspaceRootEscape_base<{
|
|
69
|
+
readonly workspaceRoot: string;
|
|
70
|
+
readonly allowedRoot: string;
|
|
71
|
+
}> {
|
|
72
|
+
}
|
|
73
|
+
declare const SkillDiscoveryRootInvalid_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 & {
|
|
74
|
+
readonly _tag: "SkillDiscoveryRootInvalid";
|
|
75
|
+
} & Readonly<A>;
|
|
76
|
+
/** The skill discovery search root is missing, inaccessible, or not a directory. */
|
|
77
|
+
export declare class SkillDiscoveryRootInvalid extends SkillDiscoveryRootInvalid_base<{
|
|
78
|
+
readonly searchRoot: string;
|
|
79
|
+
readonly problem: "inaccessible" | "not-directory";
|
|
80
|
+
readonly cause?: unknown;
|
|
81
|
+
}> {
|
|
82
|
+
}
|
|
83
|
+
declare const SubagentScanFailed_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 & {
|
|
84
|
+
readonly _tag: "SubagentScanFailed";
|
|
85
|
+
} & Readonly<A>;
|
|
86
|
+
/** Scanning an agent's subagent files failed. */
|
|
87
|
+
export declare class SubagentScanFailed extends SubagentScanFailed_base<{
|
|
88
|
+
readonly agentName: string;
|
|
89
|
+
readonly cause: unknown;
|
|
90
|
+
}> {
|
|
91
|
+
}
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Per-source tagged error families for WorkspaceReadModel source-backed cells. */
|
|
2
|
+
import * as Data from "effect/Data";
|
|
3
|
+
/** Settings file IO failure (unreadable, permission denied, lower-level error). */
|
|
4
|
+
export class SettingsIoError extends Data.TaggedError("SettingsIoError") {
|
|
5
|
+
}
|
|
6
|
+
/** Settings JSON parse failure; `raw` carries the unparsed text. */
|
|
7
|
+
export class SettingsParseError extends Data.TaggedError("SettingsParseError") {
|
|
8
|
+
}
|
|
9
|
+
/** Settings schema decode failure; `raw` carries the parsed value. */
|
|
10
|
+
export class SettingsDecodeError extends Data.TaggedError("SettingsDecodeError") {
|
|
11
|
+
}
|
|
12
|
+
/** Lockfile IO failure. */
|
|
13
|
+
export class LockfileIoError extends Data.TaggedError("LockfileIoError") {
|
|
14
|
+
}
|
|
15
|
+
/** Lockfile YAML parse failure; `raw` carries the unparsed text. */
|
|
16
|
+
export class LockfileParseError extends Data.TaggedError("LockfileParseError") {
|
|
17
|
+
}
|
|
18
|
+
/** Lockfile schema decode failure; `raw` carries the parsed value. */
|
|
19
|
+
export class LockfileDecodeError extends Data.TaggedError("LockfileDecodeError") {
|
|
20
|
+
}
|
|
21
|
+
/** Provider-construction error: workspace root escapes the configured allowed root. */
|
|
22
|
+
export class WorkspaceRootEscape extends Data.TaggedError("WorkspaceRootEscape") {
|
|
23
|
+
}
|
|
24
|
+
/** The skill discovery search root is missing, inaccessible, or not a directory. */
|
|
25
|
+
export class SkillDiscoveryRootInvalid extends Data.TaggedError("SkillDiscoveryRootInvalid") {
|
|
26
|
+
}
|
|
27
|
+
/** Scanning an agent's subagent files failed. */
|
|
28
|
+
export class SubagentScanFailed extends Data.TaggedError("SubagentScanFailed") {
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as Array from "effect/Array";
|
|
2
|
+
import * as Option from "effect/Option";
|
|
3
|
+
export const filterMapOccurrences = (occurrences, type, map) => Array.getSomes(occurrences.map((occurrence) => occurrence.type === type ? Option.some(map(occurrence)) : Option.none()));
|
|
4
|
+
//# sourceMappingURL=actual-helpers.js.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook subject module: declared/resolved/actual payloads, scanner composition,
|
|
3
|
+
* and projections via the shared helper.
|
|
4
|
+
*
|
|
5
|
+
* Declared hooks come from `settings.hooks`; resolved hooks come from
|
|
6
|
+
* `axm-lock.yaml` `hooks`. Actual occurrences come exclusively from the
|
|
7
|
+
* canonical-extensions scanner (`type === "hook"`), which enumerates
|
|
8
|
+
* project-authored `hooks/<name>/src`, project-acquired
|
|
9
|
+
* `agent_extensions/<source>/<source-full-name>`, and user-scope packages.
|
|
10
|
+
*
|
|
11
|
+
* The hook installer also writes agent-side derived artifacts — managed hook
|
|
12
|
+
* groups inside agent settings files and the advisory-rule fallback region.
|
|
13
|
+
* Those are renderings of an installed hook, not separate materializations, so
|
|
14
|
+
* they are deliberately NOT occurrences: the family derives `actual` from the
|
|
15
|
+
* canonical scanner alone and an agent-side rendering never produces an
|
|
16
|
+
* unmanaged row.
|
|
17
|
+
*/
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as Option from "effect/Option";
|
|
20
|
+
import { type ExtensionName } from "@agentxm/extension-model/unstable/extensions/common";
|
|
21
|
+
import type { HookLockEntry, Lockfile } from "../../../lockfile/schema.js";
|
|
22
|
+
import type { HookEntry, Settings } from "../../../settings/schema.js";
|
|
23
|
+
import type { Diagnostics } from "../diagnostics.js";
|
|
24
|
+
import type { LockfileReadError, SettingsReadError } from "../errors.js";
|
|
25
|
+
import type { CanonicalExtensionOccurrence } from "../scanners/types.js";
|
|
26
|
+
import type { ActivationState, ExtensionKey, InstallationOrigin, InstalledPackRef, Scope } from "../types.js";
|
|
27
|
+
export type HookDetectionOrigin = {
|
|
28
|
+
readonly _tag: "canonical-axm-hook";
|
|
29
|
+
} | {
|
|
30
|
+
readonly _tag: "external-axm-hook";
|
|
31
|
+
};
|
|
32
|
+
export interface DeclaredHook {
|
|
33
|
+
readonly name: ExtensionName;
|
|
34
|
+
readonly entry: HookEntry;
|
|
35
|
+
}
|
|
36
|
+
export type DeclaredHooks = ReadonlyArray<DeclaredHook>;
|
|
37
|
+
export interface ResolvedHook {
|
|
38
|
+
readonly name: ExtensionName;
|
|
39
|
+
readonly lockEntry: HookLockEntry;
|
|
40
|
+
}
|
|
41
|
+
export type ResolvedHooks = ReadonlyArray<ResolvedHook>;
|
|
42
|
+
export interface ActualHook {
|
|
43
|
+
readonly key: ExtensionKey<"hook">;
|
|
44
|
+
readonly origin: HookDetectionOrigin;
|
|
45
|
+
readonly contentRoot: string;
|
|
46
|
+
readonly packageRoot: string | null;
|
|
47
|
+
}
|
|
48
|
+
export type ActualHooks = ReadonlyArray<ActualHook>;
|
|
49
|
+
export interface HookPackMember {
|
|
50
|
+
readonly name: ExtensionName;
|
|
51
|
+
readonly providingPack: InstalledPackRef;
|
|
52
|
+
}
|
|
53
|
+
export interface InstalledHook {
|
|
54
|
+
readonly key: ExtensionKey<"hook">;
|
|
55
|
+
readonly installationOrigin: InstallationOrigin<DeclaredHook, HookPackMember>;
|
|
56
|
+
readonly activation: ActivationState;
|
|
57
|
+
readonly resolved: Option.Option<ResolvedHook>;
|
|
58
|
+
readonly actual: ReadonlyArray<ActualHook>;
|
|
59
|
+
readonly providingPacks: ReadonlyArray<InstalledPackRef>;
|
|
60
|
+
}
|
|
61
|
+
export interface UnmanagedHook {
|
|
62
|
+
readonly key: ExtensionKey<"hook">;
|
|
63
|
+
readonly actual: ActualHook;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Hook scanners. Hook packages materialize only in canonical package roots,
|
|
67
|
+
* so the canonical scanner is the sole input; agent-side managed hook groups are
|
|
68
|
+
* renderings of an installed hook rather than independent materializations.
|
|
69
|
+
*/
|
|
70
|
+
export interface HookScanners {
|
|
71
|
+
readonly canonical: Effect.Effect<ReadonlyArray<CanonicalExtensionOccurrence>>;
|
|
72
|
+
}
|
|
73
|
+
export interface HookScopedLoaders {
|
|
74
|
+
readonly settings: Effect.Effect<Option.Option<Settings>, SettingsReadError>;
|
|
75
|
+
readonly lockfile: Effect.Effect<Option.Option<Lockfile>, LockfileReadError>;
|
|
76
|
+
}
|
|
77
|
+
export interface InstalledPackForHooks {
|
|
78
|
+
readonly ref: InstalledPackRef;
|
|
79
|
+
readonly hooks: ReadonlyArray<HookPackMember>;
|
|
80
|
+
}
|
|
81
|
+
export interface HookExtensionsApiDeps {
|
|
82
|
+
readonly scope: Scope;
|
|
83
|
+
readonly loaders: HookScopedLoaders;
|
|
84
|
+
readonly scanners: HookScanners;
|
|
85
|
+
readonly installedPacks: Effect.Effect<ReadonlyArray<InstalledPackForHooks>, SettingsReadError | LockfileReadError>;
|
|
86
|
+
readonly diagnostics: Diagnostics;
|
|
87
|
+
}
|
|
88
|
+
export interface HookExtensionsApi {
|
|
89
|
+
readonly declared: Effect.Effect<Option.Option<DeclaredHooks>, SettingsReadError>;
|
|
90
|
+
readonly resolved: Effect.Effect<Option.Option<ResolvedHooks>, LockfileReadError>;
|
|
91
|
+
readonly actual: Effect.Effect<ActualHooks>;
|
|
92
|
+
readonly installed: Effect.Effect<ReadonlyArray<InstalledHook>, SettingsReadError | LockfileReadError>;
|
|
93
|
+
readonly byName: (name: string) => Effect.Effect<Option.Option<InstalledHook>, SettingsReadError | LockfileReadError>;
|
|
94
|
+
readonly declaredByName: (name: string) => Effect.Effect<Option.Option<DeclaredHook>, SettingsReadError>;
|
|
95
|
+
readonly active: Effect.Effect<ReadonlyArray<InstalledHook>, SettingsReadError | LockfileReadError>;
|
|
96
|
+
readonly unmanaged: Effect.Effect<ReadonlyArray<UnmanagedHook>, SettingsReadError | LockfileReadError>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Build the hook subject API. Returns an `Effect` because the projection
|
|
100
|
+
* cell is wrapped in `Effect.cached` so the four derived cells share one
|
|
101
|
+
* in-flight execution per scope, mirroring `state.ts`.
|
|
102
|
+
*/
|
|
103
|
+
export declare const makeHookExtensionsApi: (deps: HookExtensionsApiDeps) => Effect.Effect<HookExtensionsApi>;
|
|
104
|
+
//# sourceMappingURL=hook.d.ts.map
|