@agentxm/agent-integration 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 +9 -0
- package/dist/src/constants.d.ts +26 -0
- package/dist/src/constants.js +38 -0
- package/dist/src/descriptor-paths.d.ts +16 -0
- package/dist/src/descriptor-paths.js +31 -0
- package/dist/src/detection.d.ts +82 -0
- package/dist/src/detection.js +173 -0
- package/dist/src/environment.d.ts +14 -0
- package/dist/src/environment.js +16 -0
- package/dist/src/errors.d.ts +25 -0
- package/dist/src/errors.js +17 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.js +20 -0
- package/dist/src/live.d.ts +12 -0
- package/dist/src/live.js +12 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, MIT Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-MIT
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2025-2026 AgentXM, Inc.
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the MIT license that is effective on the second anniversary of the date we make
|
|
91
|
+
the Software available. On or after that date, you may use the Software under
|
|
92
|
+
the MIT license, in which case the following will apply:
|
|
93
|
+
|
|
94
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
95
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
96
|
+
the Software without restriction, including without limitation the rights to
|
|
97
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
98
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
99
|
+
so, subject to the following conditions:
|
|
100
|
+
|
|
101
|
+
The above copyright notice and this permission notice shall be included in all
|
|
102
|
+
copies or substantial portions of the Software.
|
|
103
|
+
|
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
105
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
106
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
107
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
108
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
109
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
110
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @agentxm/agent-integration
|
|
2
|
+
|
|
3
|
+
The AXM agent integration: effectful detection of installed AI coding agents
|
|
4
|
+
(project- and user-scope marker evidence, executable resolution) plus
|
|
5
|
+
native-surface path primitives (home and config directories, catalog-derived
|
|
6
|
+
agent install paths). The environment-backed executable resolver layer lives
|
|
7
|
+
behind `./live`.
|
|
8
|
+
|
|
9
|
+
Unstable and unsupported — use the [axm.sh](https://axm.sh) CLI.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effectful path helpers for agent configuration directories.
|
|
3
|
+
*
|
|
4
|
+
* All path computation uses `@effect/platform` Path service. Consumers
|
|
5
|
+
* must yield these in an Effect context.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import * as Path from "effect/Path";
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the user's home directory.
|
|
14
|
+
*
|
|
15
|
+
* @experimental This API is unstable and may change without notice.
|
|
16
|
+
*/
|
|
17
|
+
export declare const getHome: Effect.Effect<string, never, never>;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the XDG config home directory.
|
|
20
|
+
*
|
|
21
|
+
* Uses `XDG_CONFIG_HOME` environment variable if set, otherwise defaults to `~/.config`.
|
|
22
|
+
*
|
|
23
|
+
* @experimental This API is unstable and may change without notice.
|
|
24
|
+
*/
|
|
25
|
+
export declare const getConfigHome: Effect.Effect<string, never, Path.Path>;
|
|
26
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effectful path helpers for agent configuration directories.
|
|
3
|
+
*
|
|
4
|
+
* All path computation uses `@effect/platform` Path service. Consumers
|
|
5
|
+
* must yield these in an Effect context.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
// Intentional escape hatch: node:os homedir() has no @effect/platform equivalent.
|
|
11
|
+
// Wrapped in Effect.sync so execution is deferred — no eager module-level I/O.
|
|
12
|
+
import * as os from "node:os";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import * as Path from "effect/Path";
|
|
15
|
+
import * as Effect from "effect/Effect";
|
|
16
|
+
import { envOption } from "./environment.js";
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the user's home directory.
|
|
19
|
+
*
|
|
20
|
+
* @experimental This API is unstable and may change without notice.
|
|
21
|
+
*/
|
|
22
|
+
export const getHome = Effect.sync(() => os.homedir());
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the XDG config home directory.
|
|
25
|
+
*
|
|
26
|
+
* Uses `XDG_CONFIG_HOME` environment variable if set, otherwise defaults to `~/.config`.
|
|
27
|
+
*
|
|
28
|
+
* @experimental This API is unstable and may change without notice.
|
|
29
|
+
*/
|
|
30
|
+
export const getConfigHome = Effect.gen(function* () {
|
|
31
|
+
const p = yield* Path.Path;
|
|
32
|
+
const envOpt = yield* envOption("XDG_CONFIG_HOME");
|
|
33
|
+
if (Option.isSome(envOpt))
|
|
34
|
+
return envOpt.value;
|
|
35
|
+
const home = yield* getHome;
|
|
36
|
+
return p.join(home, ".config");
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog-derived agent path helpers.
|
|
3
|
+
*
|
|
4
|
+
* Agent service implementations can have custom runtime behavior, but their
|
|
5
|
+
* project-scope install paths should come from the capability catalog.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
import type { AgentId } from "@agentxm/extension-model/unstable/agents/types";
|
|
10
|
+
/** @experimental */
|
|
11
|
+
export declare const agentSkillsProjectDir: (agentId: AgentId) => string;
|
|
12
|
+
/** @experimental */
|
|
13
|
+
export declare const agentSubagentsProjectDirOptional: (agentId: AgentId) => string | undefined;
|
|
14
|
+
/** @experimental */
|
|
15
|
+
export declare const agentSubagentsProjectDir: (agentId: AgentId) => string;
|
|
16
|
+
//# sourceMappingURL=descriptor-paths.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog-derived agent path helpers.
|
|
3
|
+
*
|
|
4
|
+
* Agent service implementations can have custom runtime behavior, but their
|
|
5
|
+
* project-scope install paths should come from the capability catalog.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
|
|
10
|
+
const unsupportedCapability = (agentId, capability) => {
|
|
11
|
+
throw new Error(`Agent ${agentId} does not support ${capability}`);
|
|
12
|
+
};
|
|
13
|
+
/** @experimental */
|
|
14
|
+
export const agentSkillsProjectDir = (agentId) => {
|
|
15
|
+
const skills = AGENTS[agentId].skills;
|
|
16
|
+
if (skills === undefined) {
|
|
17
|
+
return unsupportedCapability(agentId, "skills");
|
|
18
|
+
}
|
|
19
|
+
return skills.dir;
|
|
20
|
+
};
|
|
21
|
+
/** @experimental */
|
|
22
|
+
export const agentSubagentsProjectDirOptional = (agentId) => AGENTS[agentId].subagents?.dir;
|
|
23
|
+
/** @experimental */
|
|
24
|
+
export const agentSubagentsProjectDir = (agentId) => {
|
|
25
|
+
const subagents = AGENTS[agentId].subagents;
|
|
26
|
+
if (subagents === undefined) {
|
|
27
|
+
return unsupportedCapability(agentId, "subagents");
|
|
28
|
+
}
|
|
29
|
+
return subagents.dir;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=descriptor-paths.js.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent detection functions for identifying installed AI coding agents.
|
|
3
|
+
*
|
|
4
|
+
* Detection is effectful and separated from the pure descriptor registry.
|
|
5
|
+
* Uses FileSystem service for testability.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import * as FileSystem from "effect/FileSystem";
|
|
11
|
+
import * as Path from "effect/Path";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Layer from "effect/Layer";
|
|
14
|
+
import * as ServiceMap from "effect/Context";
|
|
15
|
+
import { AgentDetectionFailed } from "./errors.js";
|
|
16
|
+
import type { AgentDescriptor } from "@agentxm/extension-model/unstable/agents/types";
|
|
17
|
+
export interface AgentExecutableResolverService {
|
|
18
|
+
readonly exists: (name: string) => Effect.Effect<boolean>;
|
|
19
|
+
}
|
|
20
|
+
declare const AgentExecutableResolver_base: ServiceMap.ServiceClass<AgentExecutableResolver, "@agentxm/agent-integration/detection/AgentExecutableResolver", AgentExecutableResolverService>;
|
|
21
|
+
export declare class AgentExecutableResolver extends AgentExecutableResolver_base {
|
|
22
|
+
}
|
|
23
|
+
export declare const AgentExecutableResolverLive: Layer.Layer<AgentExecutableResolver, never, Path.Path | FileSystem.FileSystem>;
|
|
24
|
+
/**
|
|
25
|
+
* Check whether an agent can be detected from a single filesystem root.
|
|
26
|
+
*
|
|
27
|
+
* Uses the first segment of the agent's skills, MCP servers, and subagents
|
|
28
|
+
* descriptors.
|
|
29
|
+
*/
|
|
30
|
+
export declare const detectAgentInRoot: (agent: AgentDescriptor, rootDir: string) => Effect.Effect<boolean, AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
31
|
+
export interface AgentScopeDetection {
|
|
32
|
+
readonly agent: AgentDescriptor;
|
|
33
|
+
readonly project: boolean;
|
|
34
|
+
readonly user: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Detect project and user evidence independently for one agent. */
|
|
37
|
+
export declare const detectAgentScopes: (agent: AgentDescriptor, projectDir: string) => Effect.Effect<{
|
|
38
|
+
agent: AgentDescriptor;
|
|
39
|
+
project: boolean;
|
|
40
|
+
user: boolean;
|
|
41
|
+
}, AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a specific agent is installed by checking project-level and
|
|
44
|
+
* user-scope roots.
|
|
45
|
+
*
|
|
46
|
+
* Returns `true` if any supported location exists.
|
|
47
|
+
*
|
|
48
|
+
* @param agent - The agent descriptor to check
|
|
49
|
+
* @param projectDir - The project directory to check for agent config
|
|
50
|
+
* @returns Effect that resolves to boolean indicating detection status
|
|
51
|
+
*
|
|
52
|
+
* @experimental This API is unstable and may change without notice.
|
|
53
|
+
*/
|
|
54
|
+
export declare const detectAgent: (agent: AgentDescriptor, projectDir: string) => Effect.Effect<boolean, AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
55
|
+
/**
|
|
56
|
+
* Detect all installed agents from a single filesystem root.
|
|
57
|
+
*
|
|
58
|
+
* @experimental This API is unstable and may change without notice.
|
|
59
|
+
*/
|
|
60
|
+
export declare const detectAgentsInRoot: (rootDir: string) => Effect.Effect<AgentDescriptor[], AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
61
|
+
/**
|
|
62
|
+
* Detect all installed agents concurrently.
|
|
63
|
+
*
|
|
64
|
+
* Checks all registered agents and returns descriptors for those
|
|
65
|
+
* that appear to be installed on the system.
|
|
66
|
+
*
|
|
67
|
+
* @param projectDir - The project directory to check for agent config
|
|
68
|
+
* @returns Effect that resolves to array of detected agent descriptors
|
|
69
|
+
*
|
|
70
|
+
* @experimental This API is unstable and may change without notice.
|
|
71
|
+
*/
|
|
72
|
+
export declare const detectAgents: (projectDir: string) => Effect.Effect<AgentDescriptor[], AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
73
|
+
/** Detect all agents while retaining the scope that supplied each signal. */
|
|
74
|
+
export declare const detectAgentScopeResults: (projectDir: string) => Effect.Effect<{
|
|
75
|
+
agent: AgentDescriptor;
|
|
76
|
+
project: boolean;
|
|
77
|
+
user: boolean;
|
|
78
|
+
}[], AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
79
|
+
/** Detect agents whose structured evidence satisfies one selected scope. */
|
|
80
|
+
export declare const detectAgentsForScope: (projectDir: string, scope: "project" | "user") => Effect.Effect<AgentDescriptor[], AgentDetectionFailed, Path.Path | FileSystem.FileSystem>;
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=detection.d.ts.map
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent detection functions for identifying installed AI coding agents.
|
|
3
|
+
*
|
|
4
|
+
* Detection is effectful and separated from the pure descriptor registry.
|
|
5
|
+
* Uses FileSystem service for testability.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import * as FileSystem from "effect/FileSystem";
|
|
11
|
+
import * as Path from "effect/Path";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Layer from "effect/Layer";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import * as ServiceMap from "effect/Context";
|
|
16
|
+
import { envOption } from "./environment.js";
|
|
17
|
+
import { AgentDetectionFailed } from "./errors.js";
|
|
18
|
+
import { getConfigHome, getHome } from "./constants.js";
|
|
19
|
+
import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
|
|
20
|
+
// -----------------------------------------------------------------------------
|
|
21
|
+
// Detection Functions
|
|
22
|
+
// -----------------------------------------------------------------------------
|
|
23
|
+
const wrapDetectionError = (message) => (error) => new AgentDetectionFailed({ detail: message, cause: error });
|
|
24
|
+
export class AgentExecutableResolver extends ServiceMap.Service()("@agentxm/agent-integration/detection/AgentExecutableResolver") {
|
|
25
|
+
}
|
|
26
|
+
const hasPathSeparator = (command) => command.includes("/") || command.includes("\\");
|
|
27
|
+
const getExecutableCandidates = (command, pathExt) => {
|
|
28
|
+
if (process.platform !== "win32")
|
|
29
|
+
return [command];
|
|
30
|
+
const lower = command.toLowerCase();
|
|
31
|
+
if (lower.endsWith(".exe") || lower.endsWith(".cmd"))
|
|
32
|
+
return [command];
|
|
33
|
+
const extensions = pathExt
|
|
34
|
+
.split(";")
|
|
35
|
+
.map((segment) => segment.trim().toLowerCase())
|
|
36
|
+
.filter((segment) => segment.length > 0);
|
|
37
|
+
return [command, ...extensions.map((extension) => `${command}${extension}`)];
|
|
38
|
+
};
|
|
39
|
+
const makeAgentExecutableResolver = Effect.gen(function* () {
|
|
40
|
+
const fs = yield* FileSystem.FileSystem;
|
|
41
|
+
const p = yield* Path.Path;
|
|
42
|
+
return {
|
|
43
|
+
exists: (command) => Effect.gen(function* () {
|
|
44
|
+
if (command.trim().length === 0)
|
|
45
|
+
return false;
|
|
46
|
+
const pathExtOpt = yield* envOption("PATHEXT");
|
|
47
|
+
const pathExt = Option.getOrElse(pathExtOpt, () => ".EXE;.CMD;.BAT;.COM");
|
|
48
|
+
const candidates = getExecutableCandidates(command, pathExt);
|
|
49
|
+
if (p.isAbsolute(command) || hasPathSeparator(command)) {
|
|
50
|
+
const checks = yield* Effect.forEach(candidates, (candidate) => fs.exists(candidate).pipe(Effect.catch(() => Effect.succeed(false))), { concurrency: "unbounded" });
|
|
51
|
+
return checks.some(Boolean);
|
|
52
|
+
}
|
|
53
|
+
const rawPathOpt = yield* envOption("PATH");
|
|
54
|
+
const rawPath = Option.getOrElse(rawPathOpt, () => "");
|
|
55
|
+
if (rawPath.trim().length === 0)
|
|
56
|
+
return false;
|
|
57
|
+
const delimiter = process.platform === "win32" ? ";" : ":";
|
|
58
|
+
const dirs = rawPath
|
|
59
|
+
.split(delimiter)
|
|
60
|
+
.map((segment) => segment.trim())
|
|
61
|
+
.filter((segment) => segment.length > 0);
|
|
62
|
+
const checks = yield* Effect.forEach(dirs, (dir) => Effect.forEach(candidates, (candidate) => fs.exists(p.join(dir, candidate)).pipe(Effect.catch(() => Effect.succeed(false))), { concurrency: "unbounded" }).pipe(Effect.map((results) => results.some(Boolean))), { concurrency: "unbounded" });
|
|
63
|
+
return checks.some(Boolean);
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
export const AgentExecutableResolverLive = Layer.effect(AgentExecutableResolver, makeAgentExecutableResolver);
|
|
68
|
+
const markerKey = (marker) => marker.kind === "executable" ? `executable:${marker.name}` : `${marker.kind}:${marker.path}`;
|
|
69
|
+
const detectAgentInRootRaw = (agent, rootDir) => detectScopeRaw(agent.detection.project, rootDir, "project");
|
|
70
|
+
const resolveUserDetectionPath = (marker) => Effect.gen(function* () {
|
|
71
|
+
const p = yield* Path.Path;
|
|
72
|
+
if (marker === "$XDG_CONFIG_HOME")
|
|
73
|
+
return yield* getConfigHome;
|
|
74
|
+
if (marker.startsWith("$XDG_CONFIG_HOME/")) {
|
|
75
|
+
const configHome = yield* getConfigHome;
|
|
76
|
+
return p.join(configHome, marker.slice("$XDG_CONFIG_HOME/".length));
|
|
77
|
+
}
|
|
78
|
+
const home = yield* getHome;
|
|
79
|
+
if (marker === "~")
|
|
80
|
+
return home;
|
|
81
|
+
if (marker.startsWith("~/"))
|
|
82
|
+
return p.join(home, marker.slice("~/".length));
|
|
83
|
+
return p.join(home, marker);
|
|
84
|
+
});
|
|
85
|
+
const resolveProjectPath = (marker, rootDir) => Effect.gen(function* () {
|
|
86
|
+
const p = yield* Path.Path;
|
|
87
|
+
return p.join(rootDir, marker);
|
|
88
|
+
});
|
|
89
|
+
const resolvePathMarker = (marker, rootDir, scope) => scope === "project"
|
|
90
|
+
? resolveProjectPath(marker.path, rootDir)
|
|
91
|
+
: resolveUserDetectionPath(marker.path);
|
|
92
|
+
const resolveMarker = (marker, rootDir, scope) => Effect.gen(function* () {
|
|
93
|
+
const fs = yield* FileSystem.FileSystem;
|
|
94
|
+
if (marker.kind === "executable") {
|
|
95
|
+
const resolverOption = yield* Effect.serviceOption(AgentExecutableResolver);
|
|
96
|
+
if (Option.isSome(resolverOption)) {
|
|
97
|
+
return yield* resolverOption.value.exists(marker.name);
|
|
98
|
+
}
|
|
99
|
+
const resolver = yield* makeAgentExecutableResolver;
|
|
100
|
+
return yield* resolver.exists(marker.name);
|
|
101
|
+
}
|
|
102
|
+
const resolvedPath = yield* resolvePathMarker(marker, rootDir, scope);
|
|
103
|
+
return yield* fs.exists(resolvedPath);
|
|
104
|
+
});
|
|
105
|
+
const isScopeDetected = (markers) => {
|
|
106
|
+
const resolvedMarkers = markers.filter((entry) => entry.resolved);
|
|
107
|
+
if (resolvedMarkers.some((entry) => entry.marker.signal === "definitive"))
|
|
108
|
+
return true;
|
|
109
|
+
const corroborating = new Set(resolvedMarkers
|
|
110
|
+
.filter((entry) => entry.marker.signal === "supporting" || entry.marker.signal === "ambiguous")
|
|
111
|
+
.map((entry) => markerKey(entry.marker)));
|
|
112
|
+
return corroborating.size >= 2;
|
|
113
|
+
};
|
|
114
|
+
const detectScopeRaw = (detection, rootDir, scope) => Effect.gen(function* () {
|
|
115
|
+
const results = yield* Effect.forEach(detection.markers, (marker) => resolveMarker(marker, rootDir, scope).pipe(Effect.map((resolved) => ({
|
|
116
|
+
marker,
|
|
117
|
+
resolved,
|
|
118
|
+
}))), { concurrency: "unbounded" });
|
|
119
|
+
return isScopeDetected(results);
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* Check whether an agent can be detected from a single filesystem root.
|
|
123
|
+
*
|
|
124
|
+
* Uses the first segment of the agent's skills, MCP servers, and subagents
|
|
125
|
+
* descriptors.
|
|
126
|
+
*/
|
|
127
|
+
export const detectAgentInRoot = (agent, rootDir) => detectAgentInRootRaw(agent, rootDir).pipe(Effect.mapError(wrapDetectionError(`Failed to detect ${agent.name}`)));
|
|
128
|
+
/** Detect project and user evidence independently for one agent. */
|
|
129
|
+
export const detectAgentScopes = (agent, projectDir) => Effect.gen(function* () {
|
|
130
|
+
const home = yield* getHome;
|
|
131
|
+
const [project, user] = yield* Effect.all([detectAgentInRootRaw(agent, projectDir), detectScopeRaw(agent.detection.user, home, "user")], { concurrency: "unbounded" });
|
|
132
|
+
return { agent, project, user };
|
|
133
|
+
}).pipe(Effect.mapError(wrapDetectionError(`Failed to detect ${agent.name}`)));
|
|
134
|
+
/**
|
|
135
|
+
* Check if a specific agent is installed by checking project-level and
|
|
136
|
+
* user-scope roots.
|
|
137
|
+
*
|
|
138
|
+
* Returns `true` if any supported location exists.
|
|
139
|
+
*
|
|
140
|
+
* @param agent - The agent descriptor to check
|
|
141
|
+
* @param projectDir - The project directory to check for agent config
|
|
142
|
+
* @returns Effect that resolves to boolean indicating detection status
|
|
143
|
+
*
|
|
144
|
+
* @experimental This API is unstable and may change without notice.
|
|
145
|
+
*/
|
|
146
|
+
export const detectAgent = (agent, projectDir) => detectAgentScopes(agent, projectDir).pipe(Effect.map((detection) => detection.project || detection.user));
|
|
147
|
+
/**
|
|
148
|
+
* Detect all installed agents from a single filesystem root.
|
|
149
|
+
*
|
|
150
|
+
* @experimental This API is unstable and may change without notice.
|
|
151
|
+
*/
|
|
152
|
+
export const detectAgentsInRoot = (rootDir) => Effect.filter(Object.values(AGENTS), (agent) => detectAgentInRootRaw(agent, rootDir), {
|
|
153
|
+
concurrency: "unbounded",
|
|
154
|
+
}).pipe(Effect.mapError(wrapDetectionError(`Failed to detect installed agents in ${rootDir}`)));
|
|
155
|
+
/**
|
|
156
|
+
* Detect all installed agents concurrently.
|
|
157
|
+
*
|
|
158
|
+
* Checks all registered agents and returns descriptors for those
|
|
159
|
+
* that appear to be installed on the system.
|
|
160
|
+
*
|
|
161
|
+
* @param projectDir - The project directory to check for agent config
|
|
162
|
+
* @returns Effect that resolves to array of detected agent descriptors
|
|
163
|
+
*
|
|
164
|
+
* @experimental This API is unstable and may change without notice.
|
|
165
|
+
*/
|
|
166
|
+
export const detectAgents = (projectDir) => detectAgentScopeResults(projectDir).pipe(Effect.map((detections) => detections.map((detection) => detection.agent)));
|
|
167
|
+
/** Detect all agents while retaining the scope that supplied each signal. */
|
|
168
|
+
export const detectAgentScopeResults = (projectDir) => Effect.forEach(Object.values(AGENTS), (agent) => detectAgentScopes(agent, projectDir), {
|
|
169
|
+
concurrency: "unbounded",
|
|
170
|
+
}).pipe(Effect.map((detections) => detections.filter(({ project, user }) => project || user)));
|
|
171
|
+
/** Detect agents whose structured evidence satisfies one selected scope. */
|
|
172
|
+
export const detectAgentsForScope = (projectDir, scope) => detectAgentScopeResults(projectDir).pipe(Effect.map((detections) => detections.flatMap((detection) => (detection[scope] ? [detection.agent] : []))));
|
|
173
|
+
//# sourceMappingURL=detection.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private environment helpers for agent-integration.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately duplicated from the CLI-destined environment module: the
|
|
5
|
+
* integration may not depend on application utilities, and these helpers are
|
|
6
|
+
* within the sanctioned duplication budget for small pure functions.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This API is unstable and may change without notice.
|
|
9
|
+
*/
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
12
|
+
/** Read an optional env var. Centralized access point for process.env. */
|
|
13
|
+
export declare const envOption: (name: string) => Effect.Effect<Option.Option<string>>;
|
|
14
|
+
//# sourceMappingURL=environment.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private environment helpers for agent-integration.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately duplicated from the CLI-destined environment module: the
|
|
5
|
+
* integration may not depend on application utilities, and these helpers are
|
|
6
|
+
* within the sanctioned duplication budget for small pure functions.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This API is unstable and may change without notice.
|
|
9
|
+
*/
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
12
|
+
// eslint-disable-next-line no-restricted-properties -- Centralized env var access point; all callers use these helpers
|
|
13
|
+
const readEnv = (name) => process.env[name];
|
|
14
|
+
/** Read an optional env var. Centralized access point for process.env. */
|
|
15
|
+
export const envOption = (name) => Effect.sync(() => Option.fromUndefinedOr(readEnv(name)));
|
|
16
|
+
//# sourceMappingURL=environment.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure vocabulary for the agent-integration layer.
|
|
3
|
+
*
|
|
4
|
+
* Fields are domain facts; the application boundary owns the mapping into
|
|
5
|
+
* the CLI-facing error envelope.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
declare const AgentDetectionFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
10
|
+
readonly _tag: "AgentDetectionFailed";
|
|
11
|
+
} & Readonly<A>;
|
|
12
|
+
/**
|
|
13
|
+
* Filesystem evidence gathering for agent detection failed. `detail` is the
|
|
14
|
+
* fact sentence naming what was being detected; `cause` retains the
|
|
15
|
+
* originating platform failure.
|
|
16
|
+
*/
|
|
17
|
+
export declare class AgentDetectionFailed extends AgentDetectionFailed_base<{
|
|
18
|
+
readonly detail: string;
|
|
19
|
+
readonly cause: unknown;
|
|
20
|
+
}> {
|
|
21
|
+
}
|
|
22
|
+
/** Every typed failure the agent-integration modules construct. */
|
|
23
|
+
export type AgentIntegrationError = AgentDetectionFailed;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure vocabulary for the agent-integration layer.
|
|
3
|
+
*
|
|
4
|
+
* Fields are domain facts; the application boundary owns the mapping into
|
|
5
|
+
* the CLI-facing error envelope.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
import * as Data from "effect/Data";
|
|
10
|
+
/**
|
|
11
|
+
* Filesystem evidence gathering for agent detection failed. `detail` is the
|
|
12
|
+
* fact sentence naming what was being detected; `cause` retains the
|
|
13
|
+
* originating platform failure.
|
|
14
|
+
*/
|
|
15
|
+
export class AgentDetectionFailed extends Data.TaggedError("AgentDetectionFailed") {
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentxm/agent-integration public API.
|
|
3
|
+
*
|
|
4
|
+
* Effectful detection of installed AI coding agents plus native-surface path
|
|
5
|
+
* primitives (home and config directories, catalog-derived agent install
|
|
6
|
+
* paths). The environment-backed executable resolver layer lives behind
|
|
7
|
+
* `./live`.
|
|
8
|
+
*
|
|
9
|
+
* @experimental This API is unstable and may change without notice.
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
export { AgentExecutableResolver, detectAgent, detectAgentInRoot, detectAgentScopeResults, detectAgentScopes, detectAgents, detectAgentsForScope, detectAgentsInRoot, type AgentScopeDetection, type AgentExecutableResolverService, } from "./detection.js";
|
|
13
|
+
export { AgentDetectionFailed, type AgentIntegrationError } from "./errors.js";
|
|
14
|
+
export { getHome, getConfigHome } from "./constants.js";
|
|
15
|
+
export { agentSkillsProjectDir, agentSubagentsProjectDir, agentSubagentsProjectDirOptional, } from "./descriptor-paths.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentxm/agent-integration public API.
|
|
3
|
+
*
|
|
4
|
+
* Effectful detection of installed AI coding agents plus native-surface path
|
|
5
|
+
* primitives (home and config directories, catalog-derived agent install
|
|
6
|
+
* paths). The environment-backed executable resolver layer lives behind
|
|
7
|
+
* `./live`.
|
|
8
|
+
*
|
|
9
|
+
* @experimental This API is unstable and may change without notice.
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
// Detection (effectful)
|
|
13
|
+
export { AgentExecutableResolver, detectAgent, detectAgentInRoot, detectAgentScopeResults, detectAgentScopes, detectAgents, detectAgentsForScope, detectAgentsInRoot, } from "./detection.js";
|
|
14
|
+
// Failure vocabulary
|
|
15
|
+
export { AgentDetectionFailed } from "./errors.js";
|
|
16
|
+
// Constants (path helpers)
|
|
17
|
+
export { getHome, getConfigHome } from "./constants.js";
|
|
18
|
+
// Catalog-derived agent path helpers
|
|
19
|
+
export { agentSkillsProjectDir, agentSubagentsProjectDir, agentSubagentsProjectDirOptional, } from "./descriptor-paths.js";
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentxm/agent-integration environment-backed composition.
|
|
3
|
+
*
|
|
4
|
+
* The PATH-probing executable resolver layer. Only application composition
|
|
5
|
+
* roots import this module; feature logic resolves `AgentExecutableResolver`
|
|
6
|
+
* from its Effect environment.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This API is unstable and may change without notice.
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export { AgentExecutableResolverLive } from "./detection.js";
|
|
12
|
+
//# sourceMappingURL=live.d.ts.map
|
package/dist/src/live.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentxm/agent-integration environment-backed composition.
|
|
3
|
+
*
|
|
4
|
+
* The PATH-probing executable resolver layer. Only application composition
|
|
5
|
+
* roots import this module; feature logic resolves `AgentExecutableResolver`
|
|
6
|
+
* from its Effect environment.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This API is unstable and may change without notice.
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export { AgentExecutableResolverLive } from "./detection.js";
|
|
12
|
+
//# sourceMappingURL=live.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentxm/agent-integration",
|
|
3
|
+
"version": "0.28.4-bootstrap.0",
|
|
4
|
+
"description": "AXM agent integration: effectful detection of installed AI coding agents and native-surface path primitives for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "FSL-1.1-MIT",
|
|
7
|
+
"homepage": "https://axm.sh",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/agentxm/axm/issues"
|
|
10
|
+
},
|
|
11
|
+
"author": "AgentXM <hello@agentxm.ai> (https://agentxm.ai)",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/agentxm/axm.git",
|
|
15
|
+
"directory": "packages/agent-integration"
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/src/index.d.ts",
|
|
21
|
+
"default": "./dist/src/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./live": {
|
|
24
|
+
"types": "./dist/src/live.d.ts",
|
|
25
|
+
"default": "./dist/src/live.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/src/",
|
|
30
|
+
"!**/*.map"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=22.19.0"
|
|
37
|
+
},
|
|
38
|
+
"nx": {
|
|
39
|
+
"includedScripts": []
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"effect": "4.0.0-rc.112",
|
|
43
|
+
"@agentxm/extension-model": "^0.28.4-bootstrap.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@effect/platform-node": "4.0.0-rc.112",
|
|
47
|
+
"@effect/vitest": "4.0.0-rc.112",
|
|
48
|
+
"@typescript/native": "npm:typescript@^7.0.2",
|
|
49
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
50
|
+
"vitest": "^4.1.10"
|
|
51
|
+
}
|
|
52
|
+
}
|