@ken-jo/agent-connector 0.4.99 → 0.5.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/README.md +28 -7
- package/dist/{action-5OEM3QC4.js → action-LEYTHNIU.js} +2 -2
- package/dist/{audit-BO7JQYIH.js → audit-HPKCUCES.js} +2 -2
- package/dist/{chunk-BV5WK6VQ.js → chunk-T5AI3AW3.js} +18 -18
- package/dist/chunk-T5AI3AW3.js.map +1 -0
- package/dist/{chunk-N4STCQGP.js → chunk-U2XJWG7N.js} +448 -70
- package/dist/chunk-U2XJWG7N.js.map +1 -0
- package/dist/{chunk-KLZBRNFP.js → chunk-WZMSSIDN.js} +51 -34
- package/dist/chunk-WZMSSIDN.js.map +1 -0
- package/dist/cli/sdk.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/{detect-ALP4G7WG.js → detect-USP5JMWM.js} +2 -2
- package/dist/{doctor-YEQWCWZJ.js → doctor-VSW5KHBM.js} +4 -4
- package/dist/{hook-F63I3SD5.js → hook-QRW3ON6C.js} +2 -2
- package/dist/{install-23WRRFBY.js → install-ASTAUZKB.js} +4 -4
- package/dist/{leaderboard-YBD3IKC2.js → leaderboard-3XSVSGAJ.js} +2 -2
- package/dist/{package-TAUTPP7Z.js → package-VWBPHCLA.js} +20 -12
- package/dist/package-VWBPHCLA.js.map +1 -0
- package/dist/{serve-6MDLRQS2.js → serve-IQGHE4SJ.js} +2 -2
- package/dist/{status-IUP75XHP.js → status-BVLY6XDL.js} +2 -2
- package/dist/{telemetry-X4PLZEDB.js → telemetry-UU4SHJ23.js} +2 -2
- package/dist/{uninstall-BSIJ4QXN.js → uninstall-WI5YLDCT.js} +4 -4
- package/dist/{upgrade-ZSICU3NE.js → upgrade-L45BTG6X.js} +4 -4
- package/dist/{usage-EQUNVSCT.js → usage-K3NQTAJP.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-BV5WK6VQ.js.map +0 -1
- package/dist/chunk-KLZBRNFP.js.map +0 -1
- package/dist/chunk-N4STCQGP.js.map +0 -1
- package/dist/package-TAUTPP7Z.js.map +0 -1
- /package/dist/{action-5OEM3QC4.js.map → action-LEYTHNIU.js.map} +0 -0
- /package/dist/{audit-BO7JQYIH.js.map → audit-HPKCUCES.js.map} +0 -0
- /package/dist/{detect-ALP4G7WG.js.map → detect-USP5JMWM.js.map} +0 -0
- /package/dist/{doctor-YEQWCWZJ.js.map → doctor-VSW5KHBM.js.map} +0 -0
- /package/dist/{hook-F63I3SD5.js.map → hook-QRW3ON6C.js.map} +0 -0
- /package/dist/{install-23WRRFBY.js.map → install-ASTAUZKB.js.map} +0 -0
- /package/dist/{leaderboard-YBD3IKC2.js.map → leaderboard-3XSVSGAJ.js.map} +0 -0
- /package/dist/{serve-6MDLRQS2.js.map → serve-IQGHE4SJ.js.map} +0 -0
- /package/dist/{status-IUP75XHP.js.map → status-BVLY6XDL.js.map} +0 -0
- /package/dist/{telemetry-X4PLZEDB.js.map → telemetry-UU4SHJ23.js.map} +0 -0
- /package/dist/{uninstall-BSIJ4QXN.js.map → uninstall-WI5YLDCT.js.map} +0 -0
- /package/dist/{upgrade-ZSICU3NE.js.map → upgrade-L45BTG6X.js.map} +0 -0
- /package/dist/{usage-EQUNVSCT.js.map → usage-K3NQTAJP.js.map} +0 -0
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
|
|
34
34
|
// src/core/package.ts
|
|
35
35
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
36
|
-
import { join as
|
|
36
|
+
import { join as join8, resolve as resolve4 } from "path";
|
|
37
37
|
|
|
38
38
|
// src/core/package-formats/claude-family.ts
|
|
39
39
|
import { join } from "path";
|
|
@@ -41,6 +41,21 @@ import { join } from "path";
|
|
|
41
41
|
// src/core/package-formats/shared.ts
|
|
42
42
|
import { dirname, relative, resolve, sep } from "path";
|
|
43
43
|
import { writeFileSync } from "fs";
|
|
44
|
+
import { createRequire } from "module";
|
|
45
|
+
var AGENT_CONNECTOR_PACKAGE_NAME = "@ken-jo/agent-connector";
|
|
46
|
+
function resolveFrameworkDependencyRange() {
|
|
47
|
+
const req = createRequire(import.meta.url);
|
|
48
|
+
for (const rel of ["../../../package.json", "../../package.json", "../package.json"]) {
|
|
49
|
+
try {
|
|
50
|
+
const pkg = req(rel);
|
|
51
|
+
if (pkg.name === AGENT_CONNECTOR_PACKAGE_NAME && typeof pkg.version === "string" && /^\d+\.\d+\.\d+/.test(pkg.version)) {
|
|
52
|
+
return `^${pkg.version}`;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return "*";
|
|
58
|
+
}
|
|
44
59
|
function createEmitter(dryRun) {
|
|
45
60
|
const files = [];
|
|
46
61
|
return {
|
|
@@ -143,29 +158,6 @@ var SPECS = {
|
|
|
143
158
|
schemaUrl: "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
144
159
|
marketplace: { dir: ".claude-plugin", file: "marketplace.json", shape: "claude" }
|
|
145
160
|
},
|
|
146
|
-
"codex-plugin": {
|
|
147
|
-
platformId: "codex",
|
|
148
|
-
manifestDir: ".codex-plugin",
|
|
149
|
-
subagentDir: "agents",
|
|
150
|
-
mcpFile: ".mcp.json",
|
|
151
|
-
marketplace: {
|
|
152
|
-
dir: join(".agents", "plugins"),
|
|
153
|
-
file: "marketplace.json",
|
|
154
|
-
shape: "claude"
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
"copilot-plugin": {
|
|
158
|
-
// copilot-cli accepts a Claude-shaped bundle as-is; the ONLY difference from
|
|
159
|
-
// claude-plugin is the --host stamp so the wrapped MCP + hook commands route
|
|
160
|
-
// telemetry to the copilot host. Same `.claude-plugin/` manifest dir + schema
|
|
161
|
-
// + `.claude-plugin/marketplace.json` catalog (live-verified on CLI 1.0.63).
|
|
162
|
-
platformId: "copilot-cli",
|
|
163
|
-
manifestDir: ".claude-plugin",
|
|
164
|
-
subagentDir: "agents",
|
|
165
|
-
mcpFile: ".mcp.json",
|
|
166
|
-
schemaUrl: "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
167
|
-
marketplace: { dir: ".claude-plugin", file: "marketplace.json", shape: "claude" }
|
|
168
|
-
},
|
|
169
161
|
"factory-plugin": {
|
|
170
162
|
platformId: "droid",
|
|
171
163
|
manifestDir: ".factory-plugin",
|
|
@@ -247,9 +239,7 @@ function emitClaudeFamily(connector, ctx, format) {
|
|
|
247
239
|
return { files, pluginDir, marketplacePath };
|
|
248
240
|
}
|
|
249
241
|
var emitClaudePlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "claude-plugin");
|
|
250
|
-
var emitCodexPlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "codex-plugin");
|
|
251
242
|
var emitFactoryPlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "factory-plugin");
|
|
252
|
-
var emitCopilotPlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "copilot-plugin");
|
|
253
243
|
|
|
254
244
|
// src/core/package-formats/cursor.ts
|
|
255
245
|
import { existsSync } from "fs";
|
|
@@ -506,27 +496,12 @@ var emitKimiPlugin = (connector, ctx) => {
|
|
|
506
496
|
};
|
|
507
497
|
|
|
508
498
|
// src/core/package-formats/npm.ts
|
|
509
|
-
import { createRequire } from "module";
|
|
510
499
|
import { join as join6 } from "path";
|
|
511
|
-
var AGENT_CONNECTOR_PACKAGE_NAME = "@ken-jo/agent-connector";
|
|
512
500
|
var EVENT_TO_OPENCODE = {
|
|
513
501
|
PreToolUse: "tool.execute.before",
|
|
514
502
|
PostToolUse: "tool.execute.after",
|
|
515
503
|
SessionStart: "experimental.chat.system.transform"
|
|
516
504
|
};
|
|
517
|
-
function resolveFrameworkDependencyRange() {
|
|
518
|
-
const req = createRequire(import.meta.url);
|
|
519
|
-
for (const rel of ["../../../package.json", "../../package.json", "../package.json"]) {
|
|
520
|
-
try {
|
|
521
|
-
const pkg = req(rel);
|
|
522
|
-
if (pkg.name === AGENT_CONNECTOR_PACKAGE_NAME && typeof pkg.version === "string" && /^\d+\.\d+\.\d+/.test(pkg.version)) {
|
|
523
|
-
return `^${pkg.version}`;
|
|
524
|
-
}
|
|
525
|
-
} catch {
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
return "*";
|
|
529
|
-
}
|
|
530
505
|
function buildPackageJson(connector) {
|
|
531
506
|
const pkgName = connector.id.startsWith("opencode-") ? connector.id : `opencode-${connector.id}`;
|
|
532
507
|
const version = connector.version && connector.version !== "0.0.0" ? connector.version : "0.0.1";
|
|
@@ -719,6 +694,400 @@ connector declared \`publish.author\` \u2014 set them to YOUR terms before \`npm
|
|
|
719
694
|
return { files, pluginDir, ...notes.length > 0 ? { notes } : {} };
|
|
720
695
|
};
|
|
721
696
|
|
|
697
|
+
// src/core/package-formats/agent-plugin.ts
|
|
698
|
+
import { join as join7 } from "path";
|
|
699
|
+
var AGENT_PLUGIN_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
|
|
700
|
+
var AGENT_PLUGIN_MCP_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
|
|
701
|
+
var AGENT_PLUGIN_SPEC_VERSION = "1.0.0";
|
|
702
|
+
var AGENT_PLUGIN_LAUNCHER = "bin/agent-connector.mjs";
|
|
703
|
+
var CATALOG_NAME = "agent-connector";
|
|
704
|
+
var CLIENT_NAMESPACES = [
|
|
705
|
+
{
|
|
706
|
+
namespace: "com.github.copilot",
|
|
707
|
+
label: "GitHub Copilot (CLI, VS Code, JetBrains)",
|
|
708
|
+
platform: "copilot-cli",
|
|
709
|
+
readers: ["copilot-cli", "vscode-copilot", "jetbrains-copilot"],
|
|
710
|
+
hookStyle: "plugin-root-launcher",
|
|
711
|
+
agentFile: (name) => `${name}.agent.md`,
|
|
712
|
+
commandFile: (name) => `${name}.md`,
|
|
713
|
+
manifestExtension: null
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
namespace: "com.openai",
|
|
717
|
+
label: "Codex / ChatGPT",
|
|
718
|
+
platform: "codex",
|
|
719
|
+
readers: ["codex"],
|
|
720
|
+
hookStyle: "home-bin",
|
|
721
|
+
agentFile: null,
|
|
722
|
+
commandFile: null,
|
|
723
|
+
manifestExtension: ({ hooks }) => hooks ? { hooks } : {}
|
|
724
|
+
}
|
|
725
|
+
];
|
|
726
|
+
var RESERVED_ENV_KEYS = /* @__PURE__ */ new Set(["PLUGIN_ROOT", "PLUGIN_DATA"]);
|
|
727
|
+
function toAgentPluginName(id) {
|
|
728
|
+
let name = id.trim().toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/-{2,}/g, "-").replace(/\.{2,}/g, ".").replace(/(?:-\.|\.-)+/g, "-").replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, "");
|
|
729
|
+
if (name.length > 64) {
|
|
730
|
+
name = name.slice(0, 64).replace(/[^a-z0-9]+$/g, "");
|
|
731
|
+
}
|
|
732
|
+
return name.length > 0 ? name : "connector";
|
|
733
|
+
}
|
|
734
|
+
function isConformantCwd(cwd) {
|
|
735
|
+
return cwd.startsWith("./") || cwd === "${PLUGIN_ROOT}" || cwd.startsWith("${PLUGIN_ROOT}/") || cwd === "${PLUGIN_DATA}" || cwd.startsWith("${PLUGIN_DATA}/");
|
|
736
|
+
}
|
|
737
|
+
function isConformantCommand(command) {
|
|
738
|
+
if (command.startsWith("./")) return true;
|
|
739
|
+
return !command.includes("/") && !command.includes("\\");
|
|
740
|
+
}
|
|
741
|
+
var LAUNCHER_AT_ROOT = `\${PLUGIN_ROOT}/${AGENT_PLUGIN_LAUNCHER}`;
|
|
742
|
+
function hookCommand(style, homeBin, platform, event, connectorId) {
|
|
743
|
+
if (style === "home-bin") {
|
|
744
|
+
return buildHomeBinHookCommand(homeBin, platform, event, connectorId);
|
|
745
|
+
}
|
|
746
|
+
return `node "${LAUNCHER_AT_ROOT}" hook ${platform} ${event} --connector ${connectorId}`;
|
|
747
|
+
}
|
|
748
|
+
function buildServerEntry(connector, hostHint, notes) {
|
|
749
|
+
const server = connector.server;
|
|
750
|
+
if (!server) return null;
|
|
751
|
+
const serverName = connector.id;
|
|
752
|
+
if (server.transport === "stdio") {
|
|
753
|
+
const realCommand = server.command ?? "";
|
|
754
|
+
if (realCommand === "") return null;
|
|
755
|
+
const realArgs = [...server.args ?? []];
|
|
756
|
+
let entry2;
|
|
757
|
+
let wrapped = false;
|
|
758
|
+
if (shouldWrapForTelemetry(server, connector.telemetry)) {
|
|
759
|
+
const flags = ["serve", "--connector", connector.id];
|
|
760
|
+
if (hostHint !== void 0) flags.push("--host", hostHint);
|
|
761
|
+
entry2 = {
|
|
762
|
+
type: "stdio",
|
|
763
|
+
command: "node",
|
|
764
|
+
args: [LAUNCHER_AT_ROOT, ...flags, "--", realCommand, ...realArgs]
|
|
765
|
+
};
|
|
766
|
+
wrapped = true;
|
|
767
|
+
} else {
|
|
768
|
+
entry2 = { type: "stdio", command: realCommand };
|
|
769
|
+
if (realArgs.length > 0) entry2.args = realArgs;
|
|
770
|
+
if (!isConformantCommand(realCommand)) {
|
|
771
|
+
notes.push(
|
|
772
|
+
`agent-plugin: server command "${realCommand}" is neither a bare executable name nor a plugin-relative ./ path \u2014 conforming clients may reject it (spec \xA77.2.1)`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
const env = renderEnv(server.env);
|
|
777
|
+
if (env) {
|
|
778
|
+
const kept = {};
|
|
779
|
+
for (const [key, value] of Object.entries(env)) {
|
|
780
|
+
if (RESERVED_ENV_KEYS.has(key)) {
|
|
781
|
+
notes.push(
|
|
782
|
+
`agent-plugin: dropped env "${key}" \u2014 PLUGIN_ROOT / PLUGIN_DATA are reserved runtime variables a plugin cannot set`
|
|
783
|
+
);
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
kept[key] = value;
|
|
787
|
+
}
|
|
788
|
+
if (Object.keys(kept).length > 0) entry2.env = kept;
|
|
789
|
+
}
|
|
790
|
+
if (server.cwd) {
|
|
791
|
+
if (isConformantCwd(server.cwd)) {
|
|
792
|
+
entry2.cwd = server.cwd;
|
|
793
|
+
} else {
|
|
794
|
+
notes.push(
|
|
795
|
+
`agent-plugin: dropped cwd "${server.cwd}" \u2014 must be ./-relative, \${PLUGIN_ROOT}\u2026 or \${PLUGIN_DATA}\u2026 (the plugin root is used instead)`
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return { serverName, entry: entry2, wrapped };
|
|
800
|
+
}
|
|
801
|
+
const url = server.url ?? "";
|
|
802
|
+
if (url === "") return null;
|
|
803
|
+
if (server.transport === "ws") {
|
|
804
|
+
notes.push(
|
|
805
|
+
`agent-plugin: dropped the "ws" server \u2014 Agent Plugins 1.0.0 defines only stdio, streamable-http and (legacy) sse transports`
|
|
806
|
+
);
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
const entry = {
|
|
810
|
+
type: server.transport === "sse" ? "sse" : "streamable-http",
|
|
811
|
+
url
|
|
812
|
+
};
|
|
813
|
+
const headers = renderEnv(server.headers);
|
|
814
|
+
if (headers) entry.headers = headers;
|
|
815
|
+
if (server.auth) {
|
|
816
|
+
notes.push(
|
|
817
|
+
`agent-plugin: the server's \`auth\` block is not portable \u2014 Agent Plugins carries only literal HTTP headers; the client handles authentication`
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
if (!/^https:\/\//i.test(url) && !/^http:\/\/(localhost|127\.\d+\.\d+\.\d+|\[::1\])(?:[:/]|$)/i.test(url)) {
|
|
821
|
+
notes.push(
|
|
822
|
+
`agent-plugin: remote url "${url}" is not HTTPS \u2014 the spec requires HTTPS for non-loopback endpoints`
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
return { serverName, entry, wrapped: false };
|
|
826
|
+
}
|
|
827
|
+
function buildNamespaceHooks(connector, ns, platform, homeBin) {
|
|
828
|
+
const events = connector.hookEvents.filter((e) => CLAUDE_MAPPED_EVENTS.has(e));
|
|
829
|
+
if (events.length === 0) return null;
|
|
830
|
+
const hooks = {};
|
|
831
|
+
for (const event of events) {
|
|
832
|
+
const matcher = connector.hooks[event]?.matcher ?? "";
|
|
833
|
+
const command = {
|
|
834
|
+
type: "command",
|
|
835
|
+
command: hookCommand(ns.hookStyle, homeBin, platform, event, connector.id)
|
|
836
|
+
};
|
|
837
|
+
hooks[event] = [matcher ? { matcher, hooks: [command] } : { hooks: [command] }];
|
|
838
|
+
}
|
|
839
|
+
return { hooks };
|
|
840
|
+
}
|
|
841
|
+
function buildManifest6(connector, extensions) {
|
|
842
|
+
const manifest = {
|
|
843
|
+
$schema: AGENT_PLUGIN_SCHEMA,
|
|
844
|
+
name: toAgentPluginName(connector.id)
|
|
845
|
+
};
|
|
846
|
+
if (connector.version && connector.version !== "0.0.0") {
|
|
847
|
+
manifest.version = connector.version;
|
|
848
|
+
}
|
|
849
|
+
manifest.description = `${connector.displayName} \u2014 connector emitted by agent-connector`;
|
|
850
|
+
const author = connector.publish?.author;
|
|
851
|
+
if (author?.name) {
|
|
852
|
+
const a = { name: author.name };
|
|
853
|
+
if (author.email) a.email = author.email;
|
|
854
|
+
if (author.url) a.url = author.url;
|
|
855
|
+
manifest.author = a;
|
|
856
|
+
}
|
|
857
|
+
if (Object.keys(extensions).length > 0) manifest.extensions = extensions;
|
|
858
|
+
return manifest;
|
|
859
|
+
}
|
|
860
|
+
function renderLauncher() {
|
|
861
|
+
const range = resolveFrameworkDependencyRange();
|
|
862
|
+
const spec = range === "*" ? AGENT_CONNECTOR_PACKAGE_NAME : `${AGENT_CONNECTOR_PACKAGE_NAME}@${range}`;
|
|
863
|
+
return `#!/usr/bin/env node
|
|
864
|
+
/**
|
|
865
|
+
* AUTO-GENERATED by agent-connector \u2014 DO NOT EDIT.
|
|
866
|
+
*
|
|
867
|
+
* Portable launcher for the agent-connector runtime. Agent Plugins packages
|
|
868
|
+
* must not embed absolute paths, so this file resolves the runtime at run time:
|
|
869
|
+
* 1. $AGENT_CONNECTOR_HOME_BIN (explicit override)
|
|
870
|
+
* 2. <$AGENT_CONNECTOR_DATA_DIR | ~/.agent-connector>/bin/agent-connector (the stable home binary)
|
|
871
|
+
* 3. \`agent-connector\` on PATH (a global install)
|
|
872
|
+
* 4. npx -y ${spec} (network; last resort)
|
|
873
|
+
* stdio is inherited so the MCP stdio proxy and hook JSON pass straight through.
|
|
874
|
+
*/
|
|
875
|
+
import { spawn } from "node:child_process";
|
|
876
|
+
import { existsSync } from "node:fs";
|
|
877
|
+
import { homedir } from "node:os";
|
|
878
|
+
import { delimiter, join } from "node:path";
|
|
879
|
+
|
|
880
|
+
const win = process.platform === "win32";
|
|
881
|
+
const argv = process.argv.slice(2);
|
|
882
|
+
|
|
883
|
+
function onPath(name) {
|
|
884
|
+
const exts = win ? [".cmd", ".exe", ".bat", ""] : [""];
|
|
885
|
+
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
886
|
+
if (!dir) continue;
|
|
887
|
+
for (const ext of exts) {
|
|
888
|
+
const candidate = join(dir, name + ext);
|
|
889
|
+
if (existsSync(candidate)) return candidate;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
const dataRoot = process.env.AGENT_CONNECTOR_DATA_DIR || join(homedir(), ".agent-connector");
|
|
896
|
+
const homeBin = join(dataRoot, "bin", win ? "agent-connector.cmd" : "agent-connector");
|
|
897
|
+
const explicit = process.env.AGENT_CONNECTOR_HOME_BIN;
|
|
898
|
+
|
|
899
|
+
let command;
|
|
900
|
+
let args;
|
|
901
|
+
const local = [explicit, homeBin].find((p) => p && existsSync(p)) ?? onPath("agent-connector");
|
|
902
|
+
if (local) {
|
|
903
|
+
command = local;
|
|
904
|
+
args = argv;
|
|
905
|
+
} else {
|
|
906
|
+
command = win ? "npx.cmd" : "npx";
|
|
907
|
+
args = ["-y", ${JSON.stringify(spec)}, ...argv];
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// .cmd/.bat wrappers need the shell on Windows; everything else spawns directly.
|
|
911
|
+
const shell = win && /\\.(cmd|bat)$/i.test(command);
|
|
912
|
+
const child = spawn(command, args, { stdio: "inherit", windowsHide: true, shell });
|
|
913
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
914
|
+
process.on(signal, () => child.kill(signal));
|
|
915
|
+
}
|
|
916
|
+
child.on("error", (err) => {
|
|
917
|
+
process.stderr.write(\`agent-connector launcher: cannot start \${command}: \${err.message}\\n\`);
|
|
918
|
+
process.exit(1);
|
|
919
|
+
});
|
|
920
|
+
child.on("exit", (code, signal) => {
|
|
921
|
+
if (signal) process.kill(process.pid, signal);
|
|
922
|
+
process.exit(code ?? 1);
|
|
923
|
+
});
|
|
924
|
+
`;
|
|
925
|
+
}
|
|
926
|
+
function buildCatalog(connector) {
|
|
927
|
+
return {
|
|
928
|
+
name: CATALOG_NAME,
|
|
929
|
+
owner: { name: connector.publish?.author?.name ?? CATALOG_NAME },
|
|
930
|
+
plugins: [
|
|
931
|
+
{
|
|
932
|
+
name: connector.id,
|
|
933
|
+
source: `./${connector.id}`,
|
|
934
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
935
|
+
}
|
|
936
|
+
]
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
function buildReadme(connector, has) {
|
|
940
|
+
const lines = [
|
|
941
|
+
`# ${connector.displayName} \u2014 Agent Plugin`,
|
|
942
|
+
"",
|
|
943
|
+
`An [Agent Plugins ${AGENT_PLUGIN_SPEC_VERSION}](https://agent-plugins.org) package for the`,
|
|
944
|
+
`\`${connector.id}\` connector, emitted by agent-connector.`,
|
|
945
|
+
"",
|
|
946
|
+
"## Contents",
|
|
947
|
+
"",
|
|
948
|
+
"- `plugin.json` \u2014 the plugin manifest"
|
|
949
|
+
];
|
|
950
|
+
if (has.mcp) lines.push("- `mcp.json` \u2014 the MCP server entry");
|
|
951
|
+
if (has.skills) lines.push("- `skills/<name>/SKILL.md` \u2014 Agent Skills");
|
|
952
|
+
for (const ns of has.namespaces) {
|
|
953
|
+
lines.push(
|
|
954
|
+
`- \`${ns.namespace}/\` \u2014 client extension namespace for ${ns.label} (other clients ignore it)`
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
if (has.launcher) {
|
|
958
|
+
lines.push(
|
|
959
|
+
`- \`${AGENT_PLUGIN_LAUNCHER}\` \u2014 portable launcher that locates the agent-connector runtime (home binary \u2192 PATH \u2192 npx) so per-tool token telemetry carries through without any absolute path in the bundle`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
lines.push(
|
|
963
|
+
"",
|
|
964
|
+
"## Install",
|
|
965
|
+
"",
|
|
966
|
+
"Locally, the directory ABOVE this one is a marketplace root \u2014 register it and",
|
|
967
|
+
`install by name: \`copilot plugin marketplace add <root> && copilot plugin install ${connector.id}@${CATALOG_NAME}\``,
|
|
968
|
+
`or \`codex plugin marketplace add <root> && codex plugin add ${connector.id}@${CATALOG_NAME}\`.`,
|
|
969
|
+
"",
|
|
970
|
+
"To share it, push this directory to a git repository and install it from",
|
|
971
|
+
"source with your client's plugin flow \u2014 in VS Code run **Chat: Install Plugin",
|
|
972
|
+
"From Source** from the Command Palette and enter the repository URL. Every",
|
|
973
|
+
"Agent Plugins client has an equivalent: https://agent-plugins.org/compatible-clients",
|
|
974
|
+
""
|
|
975
|
+
);
|
|
976
|
+
return lines.join("\n");
|
|
977
|
+
}
|
|
978
|
+
function readAgentPluginManifest(manifestJson) {
|
|
979
|
+
try {
|
|
980
|
+
const parsed = JSON.parse(manifestJson);
|
|
981
|
+
if (parsed.$schema !== AGENT_PLUGIN_SCHEMA) return null;
|
|
982
|
+
return parsed;
|
|
983
|
+
} catch {
|
|
984
|
+
return null;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
var emitAgentPlugin = (connector, ctx) => {
|
|
988
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
989
|
+
const pluginDir = join7(ctx.outDir, connector.id);
|
|
990
|
+
const notes = [];
|
|
991
|
+
const hostHint = ctx.hostHint;
|
|
992
|
+
const hasHooks = connector.hookEvents.some((e) => CLAUDE_MAPPED_EVENTS.has(e));
|
|
993
|
+
const populated = [];
|
|
994
|
+
const extensions = {};
|
|
995
|
+
const namespaceFiles = [];
|
|
996
|
+
let launcherHooks = false;
|
|
997
|
+
let homeBinHooks = false;
|
|
998
|
+
for (const ns of CLIENT_NAMESPACES) {
|
|
999
|
+
const extDir = join7(pluginDir, ns.namespace);
|
|
1000
|
+
const platform = hostHint !== void 0 && ns.readers.includes(hostHint) ? hostHint : ns.platform;
|
|
1001
|
+
const hooksRel = `${ns.namespace}/hooks/hooks.json`;
|
|
1002
|
+
let wrote = false;
|
|
1003
|
+
const hooksJson = hasHooks ? buildNamespaceHooks(connector, ns, platform, ctx.homeBinPath) : null;
|
|
1004
|
+
if (hooksJson) {
|
|
1005
|
+
namespaceFiles.push({ path: join7(extDir, "hooks", "hooks.json"), contents: json(hooksJson) });
|
|
1006
|
+
if (ns.hookStyle === "plugin-root-launcher") launcherHooks = true;
|
|
1007
|
+
else homeBinHooks = true;
|
|
1008
|
+
wrote = true;
|
|
1009
|
+
}
|
|
1010
|
+
if (ns.commandFile) {
|
|
1011
|
+
for (const cmd of connector.commands) {
|
|
1012
|
+
namespaceFiles.push({
|
|
1013
|
+
path: join7(extDir, "commands", ns.commandFile(cmd.name)),
|
|
1014
|
+
contents: renderCommandMd(cmd)
|
|
1015
|
+
});
|
|
1016
|
+
wrote = true;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (ns.agentFile) {
|
|
1020
|
+
for (const agent of connector.subagents) {
|
|
1021
|
+
namespaceFiles.push({
|
|
1022
|
+
path: join7(extDir, "agents", ns.agentFile(agent.name)),
|
|
1023
|
+
contents: renderSubagentMd(agent)
|
|
1024
|
+
});
|
|
1025
|
+
wrote = true;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
if (!wrote) continue;
|
|
1029
|
+
populated.push(ns);
|
|
1030
|
+
if (ns.manifestExtension) {
|
|
1031
|
+
const ext = ns.manifestExtension({ hooks: hooksJson ? `./${hooksRel}` : void 0 });
|
|
1032
|
+
if (Object.keys(ext).length > 0) extensions[ns.namespace] = ext;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
emit(join7(pluginDir, "plugin.json"), json(buildManifest6(connector, extensions)));
|
|
1036
|
+
const mcp = buildServerEntry(connector, hostHint, notes);
|
|
1037
|
+
if (mcp) {
|
|
1038
|
+
emit(
|
|
1039
|
+
join7(pluginDir, "mcp.json"),
|
|
1040
|
+
json({
|
|
1041
|
+
$schema: AGENT_PLUGIN_MCP_SCHEMA,
|
|
1042
|
+
mcpServers: { [mcp.serverName]: mcp.entry }
|
|
1043
|
+
})
|
|
1044
|
+
);
|
|
1045
|
+
}
|
|
1046
|
+
for (const skill of connector.skills) {
|
|
1047
|
+
const skillDir = join7(pluginDir, "skills", skill.name);
|
|
1048
|
+
emit(join7(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
1049
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
1050
|
+
const target = resolveWithin(skillDir, rel);
|
|
1051
|
+
if (target === null) continue;
|
|
1052
|
+
emit(target, contents);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
for (const f of namespaceFiles) emit(f.path, f.contents);
|
|
1056
|
+
if (populated.length > 0) {
|
|
1057
|
+
notes.push(
|
|
1058
|
+
`agent-plugin: hooks/commands/subagents are not portable Agent Plugins 1.0 components \u2014 emitted under the ${populated.map((ns) => `${ns.namespace}/`).join(", ")} client extension namespace(s); clients ignore namespaces they do not own`
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
const launcher = launcherHooks || mcp !== null && mcp.wrapped;
|
|
1062
|
+
if (launcher) {
|
|
1063
|
+
emit(join7(pluginDir, AGENT_PLUGIN_LAUNCHER), renderLauncher());
|
|
1064
|
+
notes.push(
|
|
1065
|
+
`agent-plugin: the MCP entry${launcherHooks ? " and Copilot hooks" : ""} run through the bundled launcher ${AGENT_PLUGIN_LAUNCHER} (no absolute path \u2014 resolves the home binary, then PATH, then npx ${AGENT_CONNECTOR_PACKAGE_NAME})`
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
if (homeBinHooks) {
|
|
1069
|
+
notes.push(
|
|
1070
|
+
`agent-plugin: com.openai/ hooks call this machine's agent-connector launcher (${ctx.homeBinPath}) \u2014 Codex documents no plugin-root token for hook commands; valid for a local install, re-run \`package\` per machine to share`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
emit(
|
|
1074
|
+
join7(pluginDir, "README.md"),
|
|
1075
|
+
buildReadme(connector, {
|
|
1076
|
+
mcp: mcp !== null,
|
|
1077
|
+
skills: connector.skills.length > 0,
|
|
1078
|
+
namespaces: populated,
|
|
1079
|
+
launcher
|
|
1080
|
+
})
|
|
1081
|
+
);
|
|
1082
|
+
const catalog = json(buildCatalog(connector));
|
|
1083
|
+
const marketplacePath = join7(ctx.outDir, ".claude-plugin", "marketplace.json");
|
|
1084
|
+
emit(marketplacePath, catalog);
|
|
1085
|
+
emit(join7(ctx.outDir, ".agents", "plugins", "marketplace.json"), catalog);
|
|
1086
|
+
const result = { files, pluginDir, marketplacePath };
|
|
1087
|
+
if (notes.length > 0) result.notes = notes;
|
|
1088
|
+
return result;
|
|
1089
|
+
};
|
|
1090
|
+
|
|
722
1091
|
// src/core/package-formats/mcp-server.ts
|
|
723
1092
|
import { resolve as resolve2 } from "path";
|
|
724
1093
|
function buildEnvVars(server) {
|
|
@@ -960,10 +1329,14 @@ var emitMcpbBundle = (connector, ctx) => {
|
|
|
960
1329
|
};
|
|
961
1330
|
|
|
962
1331
|
// src/core/package.ts
|
|
1332
|
+
var DEFAULT_PACKAGE_FORMAT = "agent-plugin";
|
|
1333
|
+
var LEGACY_FORMAT_ALIASES = {
|
|
1334
|
+
"codex-plugin": "agent-plugin",
|
|
1335
|
+
"copilot-plugin": "agent-plugin"
|
|
1336
|
+
};
|
|
963
1337
|
var EMITTERS = {
|
|
1338
|
+
"agent-plugin": emitAgentPlugin,
|
|
964
1339
|
"claude-plugin": emitClaudePlugin,
|
|
965
|
-
"codex-plugin": emitCodexPlugin,
|
|
966
|
-
"copilot-plugin": emitCopilotPlugin,
|
|
967
1340
|
"factory-plugin": emitFactoryPlugin,
|
|
968
1341
|
"gemini-extension": emitGeminiExtension,
|
|
969
1342
|
"qwen-extension": emitQwenExtension,
|
|
@@ -975,9 +1348,8 @@ var EMITTERS = {
|
|
|
975
1348
|
mcpb: emitMcpbBundle
|
|
976
1349
|
};
|
|
977
1350
|
var ALL_FORMATS = [
|
|
1351
|
+
"agent-plugin",
|
|
978
1352
|
"claude-plugin",
|
|
979
|
-
"codex-plugin",
|
|
980
|
-
"copilot-plugin",
|
|
981
1353
|
"factory-plugin",
|
|
982
1354
|
"gemini-extension",
|
|
983
1355
|
"qwen-extension",
|
|
@@ -989,9 +1361,8 @@ var ALL_FORMATS = [
|
|
|
989
1361
|
"mcpb"
|
|
990
1362
|
];
|
|
991
1363
|
var FEASIBLE_FORMATS = [
|
|
1364
|
+
"agent-plugin",
|
|
992
1365
|
"claude-plugin",
|
|
993
|
-
"codex-plugin",
|
|
994
|
-
"copilot-plugin",
|
|
995
1366
|
"factory-plugin",
|
|
996
1367
|
"gemini-extension",
|
|
997
1368
|
"qwen-extension",
|
|
@@ -1003,10 +1374,17 @@ var FEASIBLE_FORMATS = [
|
|
|
1003
1374
|
function isPackageFormat(s) {
|
|
1004
1375
|
return Object.prototype.hasOwnProperty.call(EMITTERS, s);
|
|
1005
1376
|
}
|
|
1377
|
+
function resolvePackageFormat(s) {
|
|
1378
|
+
if (isPackageFormat(s)) return { format: s };
|
|
1379
|
+
const replacement = Object.prototype.hasOwnProperty.call(LEGACY_FORMAT_ALIASES, s) ? LEGACY_FORMAT_ALIASES[s] : void 0;
|
|
1380
|
+
if (replacement === void 0) return null;
|
|
1381
|
+
return {
|
|
1382
|
+
format: replacement,
|
|
1383
|
+
deprecation: `--format ${s} is retired \u2014 emitting ${replacement} instead (the Agent Plugins 1.0.0 bundle both Codex and GitHub Copilot install natively)`
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1006
1386
|
var HOME_BIN_EMBED_FORMATS = /* @__PURE__ */ new Set([
|
|
1007
1387
|
"claude-plugin",
|
|
1008
|
-
"codex-plugin",
|
|
1009
|
-
"copilot-plugin",
|
|
1010
1388
|
"factory-plugin",
|
|
1011
1389
|
"gemini-extension",
|
|
1012
1390
|
"qwen-extension",
|
|
@@ -1015,7 +1393,7 @@ var HOME_BIN_EMBED_FORMATS = /* @__PURE__ */ new Set([
|
|
|
1015
1393
|
"kimi-plugin"
|
|
1016
1394
|
]);
|
|
1017
1395
|
function packageConnector(connector, opts) {
|
|
1018
|
-
const format = opts.format ??
|
|
1396
|
+
const format = opts.format ?? DEFAULT_PACKAGE_FORMAT;
|
|
1019
1397
|
const emitter = EMITTERS[format];
|
|
1020
1398
|
if (!emitter) {
|
|
1021
1399
|
throw new Error(`unsupported package format: ${format}`);
|
|
@@ -1025,6 +1403,7 @@ function packageConnector(connector, opts) {
|
|
|
1025
1403
|
homeBinPath: opts.homeBinPath ?? homeBinPath(),
|
|
1026
1404
|
dryRun: opts.dryRun ?? false
|
|
1027
1405
|
};
|
|
1406
|
+
if (opts.hostHint !== void 0) ctx.hostHint = opts.hostHint;
|
|
1028
1407
|
const result = emitter(connector, ctx);
|
|
1029
1408
|
if (HOME_BIN_EMBED_FORMATS.has(format)) {
|
|
1030
1409
|
const note = `bundle embeds this machine's agent-connector launcher path (${ctx.homeBinPath}) \u2014 valid for LOCAL install; for a shared marketplace, consumers need agent-connector at the same home path (run \`agent-connector upgrade\` there) or re-run \`package\` per machine`;
|
|
@@ -1048,46 +1427,43 @@ function packageConnectorAll(connector, opts) {
|
|
|
1048
1427
|
}
|
|
1049
1428
|
function installInstructions(format, id, outDir) {
|
|
1050
1429
|
switch (format) {
|
|
1430
|
+
case "agent-plugin":
|
|
1431
|
+
return [
|
|
1432
|
+
`copilot plugin marketplace add ${outDir} && copilot plugin install ${id}@agent-connector`,
|
|
1433
|
+
`codex plugin marketplace add ${outDir} && codex plugin add ${id}@agent-connector`,
|
|
1434
|
+
`(share: push ${join8(outDir, id)} to a git repo, then VS Code \u2192 "Chat: Install Plugin From Source" <repo url>;`,
|
|
1435
|
+
` Kiro / Hermes / Cursor / other clients: https://agent-plugins.org/compatible-clients)`
|
|
1436
|
+
];
|
|
1051
1437
|
case "claude-plugin":
|
|
1052
1438
|
return [
|
|
1053
1439
|
`/plugin marketplace add ${outDir}`,
|
|
1054
1440
|
`/plugin install ${id}@agent-connector`,
|
|
1055
1441
|
`(CLI: claude plugin marketplace add ${outDir} && claude plugin install ${id}@agent-connector)`
|
|
1056
1442
|
];
|
|
1057
|
-
case "codex-plugin":
|
|
1058
|
-
return [
|
|
1059
|
-
`codex plugin marketplace add ${outDir}`,
|
|
1060
|
-
`codex plugin add ${id}@agent-connector`
|
|
1061
|
-
];
|
|
1062
|
-
case "copilot-plugin":
|
|
1063
|
-
return [
|
|
1064
|
-
`copilot plugin marketplace add ${outDir}`,
|
|
1065
|
-
`copilot plugin install ${id}@agent-connector`
|
|
1066
|
-
];
|
|
1067
1443
|
case "factory-plugin":
|
|
1068
1444
|
return [
|
|
1069
1445
|
`droid plugin marketplace add ${outDir}`,
|
|
1070
1446
|
`droid plugin install ${id}@agent-connector`
|
|
1071
1447
|
];
|
|
1072
1448
|
case "gemini-extension":
|
|
1073
|
-
return [`gemini extensions install ${
|
|
1449
|
+
return [`gemini extensions install ${join8(outDir, id)}`];
|
|
1074
1450
|
case "qwen-extension":
|
|
1075
|
-
return [`qwen extensions install ${
|
|
1451
|
+
return [`qwen extensions install ${join8(outDir, id)}`];
|
|
1076
1452
|
case "agy-plugin":
|
|
1077
1453
|
return [
|
|
1078
|
-
`agy plugin install ${
|
|
1079
|
-
`(validate: agy plugin validate ${
|
|
1454
|
+
`agy plugin install ${join8(outDir, id)}`,
|
|
1455
|
+
`(validate: agy plugin validate ${join8(outDir, id)})`
|
|
1080
1456
|
];
|
|
1081
1457
|
case "cursor-plugin":
|
|
1082
1458
|
return [
|
|
1083
|
-
`link ${
|
|
1459
|
+
`link ${join8(outDir, id)} into ~/.cursor/plugins/local/${id}/ then Developer: Reload Window`,
|
|
1084
1460
|
`(or publish ${outDir} as a Cursor marketplace repo)`
|
|
1085
1461
|
];
|
|
1086
1462
|
case "kimi-plugin":
|
|
1087
|
-
return [`kimi plugin install ${
|
|
1463
|
+
return [`kimi plugin install ${join8(outDir, id)}`];
|
|
1088
1464
|
case "npm-plugin":
|
|
1089
1465
|
return [
|
|
1090
|
-
`npm publish ${
|
|
1466
|
+
`npm publish ${join8(outDir, id)} (then: opencode plugin install <pkg> | kilo plugin <pkg> | pi install npm:<pkg>)`
|
|
1091
1467
|
];
|
|
1092
1468
|
case "mcp-server-json":
|
|
1093
1469
|
return [
|
|
@@ -1096,7 +1472,7 @@ function installInstructions(format, id, outDir) {
|
|
|
1096
1472
|
];
|
|
1097
1473
|
case "mcpb":
|
|
1098
1474
|
return [
|
|
1099
|
-
`vendor your built server under ${
|
|
1475
|
+
`vendor your built server under ${join8(outDir, "server")}/ (see the emitted README)`,
|
|
1100
1476
|
`npx @anthropic-ai/mcpb pack ${outDir} (then optionally: mcpb sign)`
|
|
1101
1477
|
];
|
|
1102
1478
|
default:
|
|
@@ -1105,11 +1481,13 @@ function installInstructions(format, id, outDir) {
|
|
|
1105
1481
|
}
|
|
1106
1482
|
|
|
1107
1483
|
export {
|
|
1484
|
+
readAgentPluginManifest,
|
|
1485
|
+
DEFAULT_PACKAGE_FORMAT,
|
|
1108
1486
|
ALL_FORMATS,
|
|
1109
1487
|
FEASIBLE_FORMATS,
|
|
1110
|
-
|
|
1488
|
+
resolvePackageFormat,
|
|
1111
1489
|
packageConnector,
|
|
1112
1490
|
packageConnectorAll,
|
|
1113
1491
|
installInstructions
|
|
1114
1492
|
};
|
|
1115
|
-
//# sourceMappingURL=chunk-
|
|
1493
|
+
//# sourceMappingURL=chunk-U2XJWG7N.js.map
|