@ken-jo/agent-connector 0.1.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 +202 -0
- package/NOTICE +6 -0
- package/README.md +348 -0
- package/dist/amp-QSFH2V7Y.js +217 -0
- package/dist/amp-QSFH2V7Y.js.map +1 -0
- package/dist/amp-TULUPXXL.js +237 -0
- package/dist/amp-TULUPXXL.js.map +1 -0
- package/dist/antigravity-CX2YLSY7.js +17 -0
- package/dist/antigravity-CX2YLSY7.js.map +1 -0
- package/dist/antigravity-STHZWMP3.js +171 -0
- package/dist/antigravity-STHZWMP3.js.map +1 -0
- package/dist/antigravity-cli-P6HADOAO.js +121 -0
- package/dist/antigravity-cli-P6HADOAO.js.map +1 -0
- package/dist/antigravity-cli-YQDFVV4U.js +86 -0
- package/dist/antigravity-cli-YQDFVV4U.js.map +1 -0
- package/dist/chunk-54EMKTTX.js +191 -0
- package/dist/chunk-54EMKTTX.js.map +1 -0
- package/dist/chunk-7L6ITC4T.js +54 -0
- package/dist/chunk-7L6ITC4T.js.map +1 -0
- package/dist/chunk-7MSDGHJW.js +316 -0
- package/dist/chunk-7MSDGHJW.js.map +1 -0
- package/dist/chunk-BCHWFTV4.js +196 -0
- package/dist/chunk-BCHWFTV4.js.map +1 -0
- package/dist/chunk-DBQMX75U.js +36 -0
- package/dist/chunk-DBQMX75U.js.map +1 -0
- package/dist/chunk-EXLS7BSI.js +29 -0
- package/dist/chunk-EXLS7BSI.js.map +1 -0
- package/dist/chunk-JNM3TPLX.js +593 -0
- package/dist/chunk-JNM3TPLX.js.map +1 -0
- package/dist/chunk-JWNT5KW7.js +197 -0
- package/dist/chunk-JWNT5KW7.js.map +1 -0
- package/dist/chunk-KHO5WNTP.js +30 -0
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/chunk-LTT56GI3.js +155 -0
- package/dist/chunk-LTT56GI3.js.map +1 -0
- package/dist/chunk-MEH7GC7R.js +111 -0
- package/dist/chunk-MEH7GC7R.js.map +1 -0
- package/dist/chunk-MQPNU2CY.js +64 -0
- package/dist/chunk-MQPNU2CY.js.map +1 -0
- package/dist/chunk-OPXAP3AC.js +12 -0
- package/dist/chunk-OPXAP3AC.js.map +1 -0
- package/dist/chunk-RK6VBLXP.js +50 -0
- package/dist/chunk-RK6VBLXP.js.map +1 -0
- package/dist/chunk-TIIP3RG2.js +420 -0
- package/dist/chunk-TIIP3RG2.js.map +1 -0
- package/dist/chunk-TRKWUNO4.js +702 -0
- package/dist/chunk-TRKWUNO4.js.map +1 -0
- package/dist/chunk-TRQKHP7D.js +93 -0
- package/dist/chunk-TRQKHP7D.js.map +1 -0
- package/dist/chunk-WCETQWWK.js +59 -0
- package/dist/chunk-WCETQWWK.js.map +1 -0
- package/dist/chunk-WV63X7IK.js +357 -0
- package/dist/chunk-WV63X7IK.js.map +1 -0
- package/dist/chunk-XD7MY6HB.js +343 -0
- package/dist/chunk-XD7MY6HB.js.map +1 -0
- package/dist/chunk-XNAM7F35.js +276 -0
- package/dist/chunk-XNAM7F35.js.map +1 -0
- package/dist/chunk-XUCWLJY5.js +238 -0
- package/dist/chunk-XUCWLJY5.js.map +1 -0
- package/dist/chunk-YNZU6PAV.js +800 -0
- package/dist/chunk-YNZU6PAV.js.map +1 -0
- package/dist/chunk-YT43MUSJ.js +146 -0
- package/dist/chunk-YT43MUSJ.js.map +1 -0
- package/dist/claude-code-HKDV7T32.js +637 -0
- package/dist/claude-code-HKDV7T32.js.map +1 -0
- package/dist/claude-code-W74MNTAC.js +652 -0
- package/dist/claude-code-W74MNTAC.js.map +1 -0
- package/dist/cli/sdk.d.ts +54 -0
- package/dist/cli/sdk.js +82 -0
- package/dist/cli/sdk.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -0
- package/dist/codebuff-3PMZJJHP.js +307 -0
- package/dist/codebuff-3PMZJJHP.js.map +1 -0
- package/dist/codebuff-QX57FJDN.js +220 -0
- package/dist/codebuff-QX57FJDN.js.map +1 -0
- package/dist/codex-JFQTS6LU.js +593 -0
- package/dist/codex-JFQTS6LU.js.map +1 -0
- package/dist/codex-Q3ATRRX3.js +364 -0
- package/dist/codex-Q3ATRRX3.js.map +1 -0
- package/dist/copilot-cli-MTCGHZ2T.js +622 -0
- package/dist/copilot-cli-MTCGHZ2T.js.map +1 -0
- package/dist/copilot-cli-SJGIXVSD.js +369 -0
- package/dist/copilot-cli-SJGIXVSD.js.map +1 -0
- package/dist/crush-I7PK3FGI.js +360 -0
- package/dist/crush-I7PK3FGI.js.map +1 -0
- package/dist/crush-LN5QFFR2.js +183 -0
- package/dist/crush-LN5QFFR2.js.map +1 -0
- package/dist/cursor-4TMXKJOZ.js +603 -0
- package/dist/cursor-4TMXKJOZ.js.map +1 -0
- package/dist/cursor-QZ6MTO74.js +194 -0
- package/dist/cursor-QZ6MTO74.js.map +1 -0
- package/dist/detect-WIAGVYS4.js +68 -0
- package/dist/detect-WIAGVYS4.js.map +1 -0
- package/dist/doctor-EZW2K4NI.js +372 -0
- package/dist/doctor-EZW2K4NI.js.map +1 -0
- package/dist/droid-KN6VRMMT.js +424 -0
- package/dist/droid-KN6VRMMT.js.map +1 -0
- package/dist/droid-W5WF5XEX.js +224 -0
- package/dist/droid-W5WF5XEX.js.map +1 -0
- package/dist/gemini-cli-CIRW37TU.js +369 -0
- package/dist/gemini-cli-CIRW37TU.js.map +1 -0
- package/dist/gemini-cli-Y35FFK4M.js +705 -0
- package/dist/gemini-cli-Y35FFK4M.js.map +1 -0
- package/dist/goose-A3M5GODH.js +212 -0
- package/dist/goose-A3M5GODH.js.map +1 -0
- package/dist/goose-ZTGTSUFJ.js +480 -0
- package/dist/goose-ZTGTSUFJ.js.map +1 -0
- package/dist/hermes-H2KV44GK.js +470 -0
- package/dist/hermes-H2KV44GK.js.map +1 -0
- package/dist/hermes-ZYLMOFLZ.js +196 -0
- package/dist/hermes-ZYLMOFLZ.js.map +1 -0
- package/dist/hook-YVDILAMZ.js +75 -0
- package/dist/hook-YVDILAMZ.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/install-HQRYZOQ2.js +60 -0
- package/dist/install-HQRYZOQ2.js.map +1 -0
- package/dist/jetbrains-copilot-HWA3DMH7.js +633 -0
- package/dist/jetbrains-copilot-HWA3DMH7.js.map +1 -0
- package/dist/kilo-NSWAVP6P.js +235 -0
- package/dist/kilo-NSWAVP6P.js.map +1 -0
- package/dist/kilo-QXJRCSLT.js +384 -0
- package/dist/kilo-QXJRCSLT.js.map +1 -0
- package/dist/kilo-cli-EAQTHXUW.js +587 -0
- package/dist/kilo-cli-EAQTHXUW.js.map +1 -0
- package/dist/kilo-cli-EVBKUODA.js +160 -0
- package/dist/kilo-cli-EVBKUODA.js.map +1 -0
- package/dist/kimi-EI3UM3ZV.js +155 -0
- package/dist/kimi-EI3UM3ZV.js.map +1 -0
- package/dist/kimi-GQ7VXNYT.js +423 -0
- package/dist/kimi-GQ7VXNYT.js.map +1 -0
- package/dist/kiro-UCLSLBW2.js +217 -0
- package/dist/kiro-UCLSLBW2.js.map +1 -0
- package/dist/kiro-VQTT6LO2.js +451 -0
- package/dist/kiro-VQTT6LO2.js.map +1 -0
- package/dist/leaderboard-K6ON3SWW.js +137 -0
- package/dist/leaderboard-K6ON3SWW.js.map +1 -0
- package/dist/mux-T2TV4CIQ.js +211 -0
- package/dist/mux-T2TV4CIQ.js.map +1 -0
- package/dist/mux-ZMLVAXOO.js +96 -0
- package/dist/mux-ZMLVAXOO.js.map +1 -0
- package/dist/omp-PB4VDKS6.js +586 -0
- package/dist/omp-PB4VDKS6.js.map +1 -0
- package/dist/openclaw-ETN2M63O.js +751 -0
- package/dist/openclaw-ETN2M63O.js.map +1 -0
- package/dist/openclaw-IYA7ASL6.js +150 -0
- package/dist/openclaw-IYA7ASL6.js.map +1 -0
- package/dist/opencode-FZ33JKUZ.js +734 -0
- package/dist/opencode-FZ33JKUZ.js.map +1 -0
- package/dist/opencode-HWT3RSMN.js +216 -0
- package/dist/opencode-HWT3RSMN.js.map +1 -0
- package/dist/package-DLOVE2E4.js +1132 -0
- package/dist/package-DLOVE2E4.js.map +1 -0
- package/dist/pi-CIU2QHT4.js +208 -0
- package/dist/pi-CIU2QHT4.js.map +1 -0
- package/dist/pi-UFX2OYFV.js +139 -0
- package/dist/pi-UFX2OYFV.js.map +1 -0
- package/dist/qwen-code-5POCNU6P.js +573 -0
- package/dist/qwen-code-5POCNU6P.js.map +1 -0
- package/dist/qwen-code-W7NUCDEN.js +134 -0
- package/dist/qwen-code-W7NUCDEN.js.map +1 -0
- package/dist/roo-code-IOIUXRDE.js +242 -0
- package/dist/roo-code-IOIUXRDE.js.map +1 -0
- package/dist/roo-code-ZLKH4A7N.js +229 -0
- package/dist/roo-code-ZLKH4A7N.js.map +1 -0
- package/dist/runtime/index.d.ts +157 -0
- package/dist/runtime/index.js +20 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/serve-HVWWY4B6.js +65 -0
- package/dist/serve-HVWWY4B6.js.map +1 -0
- package/dist/status-FE7TECZD.js +128 -0
- package/dist/status-FE7TECZD.js.map +1 -0
- package/dist/synthetic-UKR6SMGS.js +178 -0
- package/dist/synthetic-UKR6SMGS.js.map +1 -0
- package/dist/telemetry-36GESKQQ.js +349 -0
- package/dist/telemetry-36GESKQQ.js.map +1 -0
- package/dist/trae-JSNDZFKL.js +204 -0
- package/dist/trae-JSNDZFKL.js.map +1 -0
- package/dist/trae-PA26DPBW.js +157 -0
- package/dist/trae-PA26DPBW.js.map +1 -0
- package/dist/types-CYUB1OTr.d.ts +427 -0
- package/dist/uninstall-IGCKNOSF.js +72 -0
- package/dist/uninstall-IGCKNOSF.js.map +1 -0
- package/dist/upgrade-JV2VK242.js +104 -0
- package/dist/upgrade-JV2VK242.js.map +1 -0
- package/dist/usage-6ER6EMEY.js +324 -0
- package/dist/usage-6ER6EMEY.js.map +1 -0
- package/dist/usage-event-JKBI6XCF.js +48 -0
- package/dist/usage-event-JKBI6XCF.js.map +1 -0
- package/dist/vscode-copilot-CK3NO54M.js +715 -0
- package/dist/vscode-copilot-CK3NO54M.js.map +1 -0
- package/dist/warp-JNQA7PBU.js +126 -0
- package/dist/warp-JNQA7PBU.js.map +1 -0
- package/dist/warp-QNVDXOG4.js +199 -0
- package/dist/warp-QNVDXOG4.js.map +1 -0
- package/dist/zed-NNNX5MNT.js +272 -0
- package/dist/zed-NNNX5MNT.js.map +1 -0
- package/dist/zed-VRJKWYUR.js +209 -0
- package/dist/zed-VRJKWYUR.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,1132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
fail,
|
|
4
|
+
print
|
|
5
|
+
} from "./chunk-54EMKTTX.js";
|
|
6
|
+
import {
|
|
7
|
+
findConnectorConfig,
|
|
8
|
+
loadConnectorFromPath
|
|
9
|
+
} from "./chunk-LTT56GI3.js";
|
|
10
|
+
import {
|
|
11
|
+
MCPB_MANIFEST_VERSION,
|
|
12
|
+
MCP_SERVER_SCHEMA_URL,
|
|
13
|
+
NPM_REGISTRY_BASE_URL,
|
|
14
|
+
REGISTRY_NAME_RE,
|
|
15
|
+
isConcreteSemver,
|
|
16
|
+
isPlaceholderVersion,
|
|
17
|
+
registryTransportType
|
|
18
|
+
} from "./chunk-XNAM7F35.js";
|
|
19
|
+
import {
|
|
20
|
+
writeTomlString
|
|
21
|
+
} from "./chunk-OPXAP3AC.js";
|
|
22
|
+
import {
|
|
23
|
+
renderCommandMd,
|
|
24
|
+
renderSkillMd,
|
|
25
|
+
renderSubagentMd
|
|
26
|
+
} from "./chunk-7L6ITC4T.js";
|
|
27
|
+
import {
|
|
28
|
+
buildHomeBinHookCommand,
|
|
29
|
+
buildServeWrapperCommand,
|
|
30
|
+
shouldWrapForTelemetry
|
|
31
|
+
} from "./chunk-MEH7GC7R.js";
|
|
32
|
+
import {
|
|
33
|
+
ensureDir,
|
|
34
|
+
homeBinPath
|
|
35
|
+
} from "./chunk-TRQKHP7D.js";
|
|
36
|
+
|
|
37
|
+
// src/cli/commands/package.ts
|
|
38
|
+
import { parseArgs } from "util";
|
|
39
|
+
import { join as join7, relative as relative2 } from "path";
|
|
40
|
+
|
|
41
|
+
// src/core/package.ts
|
|
42
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
43
|
+
import { resolve as resolve4 } from "path";
|
|
44
|
+
|
|
45
|
+
// src/core/package-formats/claude-family.ts
|
|
46
|
+
import { join } from "path";
|
|
47
|
+
|
|
48
|
+
// src/core/package-formats/shared.ts
|
|
49
|
+
import { dirname, relative, resolve, sep } from "path";
|
|
50
|
+
import { writeFileSync } from "fs";
|
|
51
|
+
function createEmitter(dryRun) {
|
|
52
|
+
const files = [];
|
|
53
|
+
return {
|
|
54
|
+
files,
|
|
55
|
+
emit(path, contents) {
|
|
56
|
+
if (!dryRun) {
|
|
57
|
+
ensureDir(dirname(path));
|
|
58
|
+
writeFileSync(path, contents, "utf8");
|
|
59
|
+
}
|
|
60
|
+
files.push(path);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function json(value) {
|
|
65
|
+
return `${JSON.stringify(value, null, 2)}
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
function resolveWithin(baseDir, rel) {
|
|
69
|
+
const base = resolve(baseDir);
|
|
70
|
+
const target = resolve(base, rel);
|
|
71
|
+
if (target === base) return null;
|
|
72
|
+
const rind = relative(base, target);
|
|
73
|
+
if (rind === "" || rind.startsWith("..") || resolve(base, rind) !== target) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (rind === ".." || rind.startsWith(`..${sep}`)) return null;
|
|
77
|
+
return target;
|
|
78
|
+
}
|
|
79
|
+
function renderEnv(env) {
|
|
80
|
+
if (!env || Object.keys(env).length === 0) return void 0;
|
|
81
|
+
return { ...env };
|
|
82
|
+
}
|
|
83
|
+
var CLAUDE_MAPPED_EVENTS = /* @__PURE__ */ new Set([
|
|
84
|
+
"PreToolUse",
|
|
85
|
+
"PostToolUse",
|
|
86
|
+
"PreCompact",
|
|
87
|
+
"SessionStart",
|
|
88
|
+
"SessionEnd",
|
|
89
|
+
"UserPromptSubmit",
|
|
90
|
+
"Stop",
|
|
91
|
+
"Notification"
|
|
92
|
+
]);
|
|
93
|
+
function buildClaudeHooksJson(connector, homeBin, platformId) {
|
|
94
|
+
const events = connector.hookEvents.filter((e) => CLAUDE_MAPPED_EVENTS.has(e));
|
|
95
|
+
if (events.length === 0) return null;
|
|
96
|
+
const hooks = {};
|
|
97
|
+
for (const event of events) {
|
|
98
|
+
const matcher = connector.hooks[event]?.matcher ?? "";
|
|
99
|
+
const command = {
|
|
100
|
+
type: "command",
|
|
101
|
+
command: buildHomeBinHookCommand(homeBin, platformId, event, connector.id)
|
|
102
|
+
};
|
|
103
|
+
hooks[event] = [matcher ? { matcher, hooks: [command] } : { hooks: [command] }];
|
|
104
|
+
}
|
|
105
|
+
return { hooks };
|
|
106
|
+
}
|
|
107
|
+
function buildMcpEntry(connector, homeBin, platformId) {
|
|
108
|
+
const server = connector.server;
|
|
109
|
+
if (!server) return null;
|
|
110
|
+
if (server.transport !== "stdio") return null;
|
|
111
|
+
const realCommand = server.command ?? "";
|
|
112
|
+
if (realCommand === "") return null;
|
|
113
|
+
const realArgs = [...server.args ?? []];
|
|
114
|
+
let entry;
|
|
115
|
+
if (shouldWrapForTelemetry(server, connector.telemetry)) {
|
|
116
|
+
const wrapped = buildServeWrapperCommand(
|
|
117
|
+
homeBin,
|
|
118
|
+
connector.id,
|
|
119
|
+
realCommand,
|
|
120
|
+
realArgs,
|
|
121
|
+
void 0,
|
|
122
|
+
platformId
|
|
123
|
+
);
|
|
124
|
+
entry = { command: wrapped.command, args: wrapped.args };
|
|
125
|
+
} else {
|
|
126
|
+
entry = { command: realCommand, args: realArgs };
|
|
127
|
+
}
|
|
128
|
+
const env = renderEnv(server.env);
|
|
129
|
+
if (env) entry.env = env;
|
|
130
|
+
if (server.cwd) entry.cwd = server.cwd;
|
|
131
|
+
return { serverName: connector.id, entry };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/core/package-formats/claude-family.ts
|
|
135
|
+
var SPECS = {
|
|
136
|
+
"claude-plugin": {
|
|
137
|
+
platformId: "claude-code",
|
|
138
|
+
manifestDir: ".claude-plugin",
|
|
139
|
+
subagentDir: "agents",
|
|
140
|
+
mcpFile: ".mcp.json",
|
|
141
|
+
schemaUrl: "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
142
|
+
marketplace: { dir: ".claude-plugin", file: "marketplace.json", shape: "claude" }
|
|
143
|
+
},
|
|
144
|
+
"codex-plugin": {
|
|
145
|
+
platformId: "codex",
|
|
146
|
+
manifestDir: ".codex-plugin",
|
|
147
|
+
subagentDir: "agents",
|
|
148
|
+
mcpFile: ".mcp.json",
|
|
149
|
+
marketplace: { dir: ".codex-plugin", file: "marketplace.json", shape: "claude" }
|
|
150
|
+
},
|
|
151
|
+
"factory-plugin": {
|
|
152
|
+
platformId: "droid",
|
|
153
|
+
manifestDir: ".factory-plugin",
|
|
154
|
+
subagentDir: "droids",
|
|
155
|
+
mcpFile: "mcp.json",
|
|
156
|
+
requireVersion: true,
|
|
157
|
+
alwaysAuthor: true,
|
|
158
|
+
// droid marketplaces are Git-repo catalogs; the catalog sits at the repo root.
|
|
159
|
+
marketplace: { dir: null, file: "marketplace.json", shape: "factory" }
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
function buildManifest(connector, spec) {
|
|
163
|
+
const manifest = {};
|
|
164
|
+
if (spec.schemaUrl) manifest.$schema = spec.schemaUrl;
|
|
165
|
+
manifest.name = connector.id;
|
|
166
|
+
manifest.description = `${connector.displayName} \u2014 connector emitted by agent-connector`;
|
|
167
|
+
const hasRealVersion = connector.version && connector.version !== "0.0.0";
|
|
168
|
+
if (hasRealVersion) {
|
|
169
|
+
manifest.version = connector.version;
|
|
170
|
+
} else if (spec.requireVersion) {
|
|
171
|
+
manifest.version = "0.0.1";
|
|
172
|
+
}
|
|
173
|
+
if (spec.alwaysAuthor) {
|
|
174
|
+
manifest.author = { name: connector.publish?.author?.name ?? "agent-connector" };
|
|
175
|
+
}
|
|
176
|
+
return manifest;
|
|
177
|
+
}
|
|
178
|
+
function buildMarketplace(connector) {
|
|
179
|
+
return {
|
|
180
|
+
name: "agent-connector",
|
|
181
|
+
owner: { name: connector.publish?.author?.name ?? "agent-connector" },
|
|
182
|
+
plugins: [
|
|
183
|
+
{
|
|
184
|
+
name: connector.id,
|
|
185
|
+
source: `./${connector.id}`,
|
|
186
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function emitClaudeFamily(connector, ctx, format) {
|
|
192
|
+
const spec = SPECS[format];
|
|
193
|
+
if (!spec) throw new Error(`unknown claude-family format: ${format}`);
|
|
194
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
195
|
+
const pluginDir = join(ctx.outDir, connector.id);
|
|
196
|
+
emit(
|
|
197
|
+
join(pluginDir, spec.manifestDir, "plugin.json"),
|
|
198
|
+
json(buildManifest(connector, spec))
|
|
199
|
+
);
|
|
200
|
+
for (const cmd of connector.commands) {
|
|
201
|
+
emit(join(pluginDir, "commands", `${cmd.name}.md`), renderCommandMd(cmd));
|
|
202
|
+
}
|
|
203
|
+
for (const agent of connector.subagents) {
|
|
204
|
+
emit(
|
|
205
|
+
join(pluginDir, spec.subagentDir, `${agent.name}.md`),
|
|
206
|
+
renderSubagentMd(agent)
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
for (const skill of connector.skills) {
|
|
210
|
+
const skillDir = join(pluginDir, "skills", skill.name);
|
|
211
|
+
emit(join(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
212
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
213
|
+
const target = resolveWithin(skillDir, rel);
|
|
214
|
+
if (target === null) continue;
|
|
215
|
+
emit(target, contents);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, spec.platformId);
|
|
219
|
+
if (hooksJson) emit(join(pluginDir, "hooks", "hooks.json"), json(hooksJson));
|
|
220
|
+
const mcp = buildMcpEntry(connector, ctx.homeBinPath, spec.platformId);
|
|
221
|
+
if (mcp) {
|
|
222
|
+
emit(
|
|
223
|
+
join(pluginDir, spec.mcpFile),
|
|
224
|
+
json({ mcpServers: { [mcp.serverName]: mcp.entry } })
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const marketplacePath = spec.marketplace.dir ? join(ctx.outDir, spec.marketplace.dir, spec.marketplace.file) : join(ctx.outDir, spec.marketplace.file);
|
|
228
|
+
emit(marketplacePath, json(buildMarketplace(connector)));
|
|
229
|
+
return { files, pluginDir, marketplacePath };
|
|
230
|
+
}
|
|
231
|
+
var emitClaudePlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "claude-plugin");
|
|
232
|
+
var emitCodexPlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "codex-plugin");
|
|
233
|
+
var emitFactoryPlugin = (connector, ctx) => emitClaudeFamily(connector, ctx, "factory-plugin");
|
|
234
|
+
|
|
235
|
+
// src/core/package-formats/cursor.ts
|
|
236
|
+
import { existsSync } from "fs";
|
|
237
|
+
import { join as join2 } from "path";
|
|
238
|
+
var PLATFORM = "cursor";
|
|
239
|
+
function buildManifest2(connector, has) {
|
|
240
|
+
const manifest = {
|
|
241
|
+
name: connector.id,
|
|
242
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
243
|
+
};
|
|
244
|
+
if (connector.version && connector.version !== "0.0.0") {
|
|
245
|
+
manifest.version = connector.version;
|
|
246
|
+
}
|
|
247
|
+
if (has.commands) manifest.commands = "./commands/";
|
|
248
|
+
if (has.agents) manifest.agents = "./agents/";
|
|
249
|
+
if (has.skills) manifest.skills = "./skills/";
|
|
250
|
+
if (has.hooks) manifest.hooks = "./hooks/hooks.json";
|
|
251
|
+
if (has.mcp) manifest.mcpServers = "./mcp.json";
|
|
252
|
+
return manifest;
|
|
253
|
+
}
|
|
254
|
+
function buildMarketplace2(connector) {
|
|
255
|
+
return {
|
|
256
|
+
name: "agent-connector",
|
|
257
|
+
owner: { name: connector.publish?.author?.name ?? "agent-connector" },
|
|
258
|
+
plugins: [
|
|
259
|
+
{
|
|
260
|
+
name: connector.id,
|
|
261
|
+
source: `./${connector.id}`,
|
|
262
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
263
|
+
}
|
|
264
|
+
]
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
var emitCursorPlugin = (connector, ctx) => {
|
|
268
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
269
|
+
const pluginDir = join2(ctx.outDir, connector.id);
|
|
270
|
+
const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, PLATFORM);
|
|
271
|
+
const mcp = buildMcpEntry(connector, ctx.homeBinPath, PLATFORM);
|
|
272
|
+
const has = {
|
|
273
|
+
commands: connector.commands.length > 0,
|
|
274
|
+
agents: connector.subagents.length > 0,
|
|
275
|
+
skills: connector.skills.length > 0,
|
|
276
|
+
hooks: hooksJson !== null,
|
|
277
|
+
mcp: mcp !== null
|
|
278
|
+
};
|
|
279
|
+
emit(
|
|
280
|
+
join2(pluginDir, ".cursor-plugin", "plugin.json"),
|
|
281
|
+
json(buildManifest2(connector, has))
|
|
282
|
+
);
|
|
283
|
+
for (const cmd of connector.commands) {
|
|
284
|
+
emit(join2(pluginDir, "commands", `${cmd.name}.md`), renderCommandMd(cmd));
|
|
285
|
+
}
|
|
286
|
+
for (const agent of connector.subagents) {
|
|
287
|
+
emit(join2(pluginDir, "agents", `${agent.name}.md`), renderSubagentMd(agent));
|
|
288
|
+
}
|
|
289
|
+
for (const skill of connector.skills) {
|
|
290
|
+
const skillDir = join2(pluginDir, "skills", skill.name);
|
|
291
|
+
emit(join2(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
292
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
293
|
+
const target = resolveWithin(skillDir, rel);
|
|
294
|
+
if (target === null) continue;
|
|
295
|
+
emit(target, contents);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (hooksJson) emit(join2(pluginDir, "hooks", "hooks.json"), json(hooksJson));
|
|
299
|
+
if (mcp) {
|
|
300
|
+
emit(
|
|
301
|
+
join2(pluginDir, "mcp.json"),
|
|
302
|
+
json({ mcpServers: { [mcp.serverName]: mcp.entry } })
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
const marketplacePath = join2(ctx.outDir, ".cursor-plugin", "marketplace.json");
|
|
306
|
+
emit(marketplacePath, json(buildMarketplace2(connector)));
|
|
307
|
+
return { files, pluginDir, marketplacePath };
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// src/core/package-formats/gemini.ts
|
|
311
|
+
import { join as join3 } from "path";
|
|
312
|
+
var SPECS2 = {
|
|
313
|
+
"gemini-extension": {
|
|
314
|
+
platformId: "gemini-cli",
|
|
315
|
+
manifestFile: "gemini-extension.json",
|
|
316
|
+
contextFile: "GEMINI.md",
|
|
317
|
+
commandFormat: "toml"
|
|
318
|
+
},
|
|
319
|
+
"qwen-extension": {
|
|
320
|
+
platformId: "qwen-code",
|
|
321
|
+
manifestFile: "qwen-extension.json",
|
|
322
|
+
contextFile: "QWEN.md",
|
|
323
|
+
commandFormat: "md"
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
function renderCommandToml(cmd) {
|
|
327
|
+
const obj = {};
|
|
328
|
+
if (cmd.description !== void 0) obj.description = cmd.description;
|
|
329
|
+
obj.prompt = cmd.prompt;
|
|
330
|
+
return writeTomlString(obj);
|
|
331
|
+
}
|
|
332
|
+
function buildManifest3(connector, spec, homeBin) {
|
|
333
|
+
const manifest = {
|
|
334
|
+
name: connector.id,
|
|
335
|
+
// gemini requires a version; default a placeholder to a real semver.
|
|
336
|
+
version: connector.version && connector.version !== "0.0.0" ? connector.version : "0.0.1",
|
|
337
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
338
|
+
};
|
|
339
|
+
const mcp = buildMcpEntry(connector, homeBin, spec.platformId);
|
|
340
|
+
if (mcp) {
|
|
341
|
+
manifest.mcpServers = { [mcp.serverName]: mcp.entry };
|
|
342
|
+
}
|
|
343
|
+
manifest.contextFileName = spec.contextFile;
|
|
344
|
+
return manifest;
|
|
345
|
+
}
|
|
346
|
+
function emitGeminiFamily(connector, ctx, format) {
|
|
347
|
+
const spec = SPECS2[format];
|
|
348
|
+
if (!spec) throw new Error(`unknown gemini-family format: ${format}`);
|
|
349
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
350
|
+
const pluginDir = join3(ctx.outDir, connector.id);
|
|
351
|
+
emit(
|
|
352
|
+
join3(pluginDir, spec.manifestFile),
|
|
353
|
+
json(buildManifest3(connector, spec, ctx.homeBinPath))
|
|
354
|
+
);
|
|
355
|
+
emit(
|
|
356
|
+
join3(pluginDir, spec.contextFile),
|
|
357
|
+
`# ${connector.displayName}
|
|
358
|
+
|
|
359
|
+
Connector context emitted by agent-connector.
|
|
360
|
+
`
|
|
361
|
+
);
|
|
362
|
+
for (const cmd of connector.commands) {
|
|
363
|
+
if (spec.commandFormat === "toml") {
|
|
364
|
+
emit(join3(pluginDir, "commands", `${cmd.name}.toml`), renderCommandToml(cmd));
|
|
365
|
+
} else {
|
|
366
|
+
emit(join3(pluginDir, "commands", `${cmd.name}.md`), renderCommandMd(cmd));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (const agent of connector.subagents) {
|
|
370
|
+
emit(join3(pluginDir, "agents", `${agent.name}.md`), renderSubagentMd(agent));
|
|
371
|
+
}
|
|
372
|
+
for (const skill of connector.skills) {
|
|
373
|
+
const skillDir = join3(pluginDir, "skills", skill.name);
|
|
374
|
+
emit(join3(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
375
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
376
|
+
const target = resolveWithin(skillDir, rel);
|
|
377
|
+
if (target === null) continue;
|
|
378
|
+
emit(target, contents);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, spec.platformId);
|
|
382
|
+
if (hooksJson) emit(join3(pluginDir, "hooks", "hooks.json"), json(hooksJson));
|
|
383
|
+
return { files, pluginDir };
|
|
384
|
+
}
|
|
385
|
+
var emitGeminiExtension = (connector, ctx) => emitGeminiFamily(connector, ctx, "gemini-extension");
|
|
386
|
+
var emitQwenExtension = (connector, ctx) => emitGeminiFamily(connector, ctx, "qwen-extension");
|
|
387
|
+
|
|
388
|
+
// src/core/package-formats/agy.ts
|
|
389
|
+
import { join as join4 } from "path";
|
|
390
|
+
var PLATFORM2 = "antigravity-cli";
|
|
391
|
+
function buildManifest4(connector) {
|
|
392
|
+
return {
|
|
393
|
+
name: connector.id,
|
|
394
|
+
// agy expects a version on the marker; default a placeholder to a real semver.
|
|
395
|
+
version: connector.version && connector.version !== "0.0.0" ? connector.version : "0.0.1",
|
|
396
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
var emitAgyPlugin = (connector, ctx) => {
|
|
400
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
401
|
+
const pluginDir = join4(ctx.outDir, connector.id);
|
|
402
|
+
emit(join4(pluginDir, "plugin.json"), json(buildManifest4(connector)));
|
|
403
|
+
for (const cmd of connector.commands) {
|
|
404
|
+
emit(join4(pluginDir, "commands", `${cmd.name}.md`), renderCommandMd(cmd));
|
|
405
|
+
}
|
|
406
|
+
for (const agent of connector.subagents) {
|
|
407
|
+
emit(join4(pluginDir, "agents", `${agent.name}.md`), renderSubagentMd(agent));
|
|
408
|
+
}
|
|
409
|
+
for (const skill of connector.skills) {
|
|
410
|
+
const skillDir = join4(pluginDir, "skills", skill.name);
|
|
411
|
+
emit(join4(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
412
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
413
|
+
const target = resolveWithin(skillDir, rel);
|
|
414
|
+
if (target === null) continue;
|
|
415
|
+
emit(target, contents);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const hooksJson = buildClaudeHooksJson(connector, ctx.homeBinPath, PLATFORM2);
|
|
419
|
+
if (hooksJson) emit(join4(pluginDir, "hooks", "hooks.json"), json(hooksJson));
|
|
420
|
+
const mcp = buildMcpEntry(connector, ctx.homeBinPath, PLATFORM2);
|
|
421
|
+
if (mcp) {
|
|
422
|
+
emit(
|
|
423
|
+
join4(pluginDir, "mcp_config.json"),
|
|
424
|
+
json({ mcpServers: { [mcp.serverName]: mcp.entry } })
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
return { files, pluginDir };
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
// src/core/package-formats/kimi.ts
|
|
431
|
+
import { join as join5 } from "path";
|
|
432
|
+
var PLATFORM3 = "kimi";
|
|
433
|
+
function buildManifest5(connector, hasSkills, homeBin) {
|
|
434
|
+
const manifest = {
|
|
435
|
+
name: connector.id,
|
|
436
|
+
version: connector.version && connector.version !== "0.0.0" ? connector.version : "0.0.1",
|
|
437
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`
|
|
438
|
+
};
|
|
439
|
+
if (hasSkills) manifest.skills = "./skills/";
|
|
440
|
+
const mcp = buildMcpEntry(connector, homeBin, PLATFORM3);
|
|
441
|
+
if (mcp) manifest.mcpServers = { [mcp.serverName]: mcp.entry };
|
|
442
|
+
return manifest;
|
|
443
|
+
}
|
|
444
|
+
var emitKimiPlugin = (connector, ctx) => {
|
|
445
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
446
|
+
const pluginDir = join5(ctx.outDir, connector.id);
|
|
447
|
+
const notes = [];
|
|
448
|
+
const hasSkills = connector.skills.length > 0;
|
|
449
|
+
emit(join5(pluginDir, "kimi.plugin.json"), json(buildManifest5(connector, hasSkills, ctx.homeBinPath)));
|
|
450
|
+
for (const skill of connector.skills) {
|
|
451
|
+
const skillDir = join5(pluginDir, "skills", skill.name);
|
|
452
|
+
emit(join5(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
453
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
454
|
+
const target = resolveWithin(skillDir, rel);
|
|
455
|
+
if (target === null) continue;
|
|
456
|
+
emit(target, contents);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (connector.commands.length > 0) {
|
|
460
|
+
notes.push(
|
|
461
|
+
`kimi-plugin: dropped ${connector.commands.length} command(s) \u2014 Kimi plugins ignore commands`
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
if (connector.subagents.length > 0) {
|
|
465
|
+
notes.push(
|
|
466
|
+
`kimi-plugin: dropped ${connector.subagents.length} subagent(s) \u2014 Kimi plugins ignore subagents`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
if (connector.hookEvents.length > 0) {
|
|
470
|
+
notes.push(
|
|
471
|
+
`kimi-plugin: dropped ${connector.hookEvents.length} hook event(s) \u2014 Kimi plugins ignore hooks`
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
return { files, pluginDir, ...notes.length > 0 ? { notes } : {} };
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
// src/core/package-formats/npm.ts
|
|
478
|
+
import { join as join6 } from "path";
|
|
479
|
+
var EVENT_TO_OPENCODE = {
|
|
480
|
+
PreToolUse: "tool.execute.before",
|
|
481
|
+
PostToolUse: "tool.execute.after",
|
|
482
|
+
SessionStart: "experimental.chat.system.transform"
|
|
483
|
+
};
|
|
484
|
+
function buildPackageJson(connector) {
|
|
485
|
+
const pkgName = connector.id.startsWith("opencode-") ? connector.id : `opencode-${connector.id}`;
|
|
486
|
+
const version = connector.version && connector.version !== "0.0.0" ? connector.version : "0.0.1";
|
|
487
|
+
const pkg = {
|
|
488
|
+
name: pkgName,
|
|
489
|
+
version,
|
|
490
|
+
description: `${connector.displayName} \u2014 connector emitted by agent-connector`,
|
|
491
|
+
type: "module",
|
|
492
|
+
main: "index.js",
|
|
493
|
+
exports: { ".": "./index.js" },
|
|
494
|
+
keywords: ["opencode", "opencode-plugin", "pi-package", "agent-connector"],
|
|
495
|
+
// pi reads skills/prompts/themes/extensions from the package.json "pi" key.
|
|
496
|
+
pi: { extensions: ["./index.js"], skills: ["./skills"] },
|
|
497
|
+
engines: { node: ">=18.17", opencode: ">=1.0.0" }
|
|
498
|
+
// NOTE: no hardcoded license — this is the DEVELOPER'S publishable package
|
|
499
|
+
// and agent-connector has no authority to license it. The emitter returns a
|
|
500
|
+
// note telling the dev to set license (and author) before `npm publish`.
|
|
501
|
+
};
|
|
502
|
+
if (connector.publish?.author?.name) {
|
|
503
|
+
pkg.author = connector.publish.author.name;
|
|
504
|
+
}
|
|
505
|
+
return pkg;
|
|
506
|
+
}
|
|
507
|
+
function buildIndexJs(connector) {
|
|
508
|
+
const homeBin = JSON.stringify("agent-connector");
|
|
509
|
+
const connectorId = JSON.stringify(connector.id);
|
|
510
|
+
const events = connector.hookEvents.filter(
|
|
511
|
+
(e) => EVENT_TO_OPENCODE[e] !== void 0
|
|
512
|
+
);
|
|
513
|
+
const has = (e) => events.includes(e);
|
|
514
|
+
const header = `/**
|
|
515
|
+
* AUTO-GENERATED by agent-connector \u2014 DO NOT EDIT.
|
|
516
|
+
*
|
|
517
|
+
* Publishable OpenCode/Kilo/Pi plugin for connector ${connector.id}. It imports
|
|
518
|
+
* nothing from agent-connector: every hook invocation shells out to the stable
|
|
519
|
+
* home binary's universal entrypoint and JSON-parses the normalized response.
|
|
520
|
+
* Fail-open: any bridge error degrades to "allow".
|
|
521
|
+
*/
|
|
522
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
523
|
+
|
|
524
|
+
const HOME_BIN = ${homeBin};
|
|
525
|
+
const CONNECTOR_ID = ${connectorId};
|
|
526
|
+
|
|
527
|
+
function bridge(event, payload) {
|
|
528
|
+
try {
|
|
529
|
+
// The published bridge resolves HOME_BIN by bare name via the consumer's
|
|
530
|
+
// PATH, where on Windows it is agent-connector.cmd. Node cannot execFile a
|
|
531
|
+
// .cmd, and shell+args is deprecated (DEP0190), so on Windows run one quoted
|
|
532
|
+
// command line via a shell (cmd.exe applies PATHEXT). POSIX keeps execFile.
|
|
533
|
+
const args = ["hook", "opencode", event, "--connector", CONNECTOR_ID];
|
|
534
|
+
const opts = { input: JSON.stringify(payload), encoding: "utf8" };
|
|
535
|
+
const stdout =
|
|
536
|
+
process.platform === "win32"
|
|
537
|
+
? execSync([HOME_BIN, ...args].map((a) => '"' + a + '"').join(" "), opts)
|
|
538
|
+
: execFileSync(HOME_BIN, args, opts);
|
|
539
|
+
const text = (stdout || "").trim();
|
|
540
|
+
if (text === "") return { decision: "allow" };
|
|
541
|
+
return JSON.parse(text);
|
|
542
|
+
} catch {
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
`;
|
|
547
|
+
const handlers = [];
|
|
548
|
+
if (has("PreToolUse")) {
|
|
549
|
+
handlers.push(` "tool.execute.before": async (input, output) => {
|
|
550
|
+
const res = bridge("PreToolUse", {
|
|
551
|
+
toolName: input.tool ?? "",
|
|
552
|
+
toolInput: (output && output.args) ?? {},
|
|
553
|
+
sessionId: input.sessionID ?? "",
|
|
554
|
+
projectDir: PROJECT_DIR,
|
|
555
|
+
});
|
|
556
|
+
if (!res) return;
|
|
557
|
+
if (res.decision === "deny" || res.decision === "ask") {
|
|
558
|
+
throw new Error(res.reason || "Blocked by ${connector.id}");
|
|
559
|
+
}
|
|
560
|
+
if (res.updatedInput && output && output.args) Object.assign(output.args, res.updatedInput);
|
|
561
|
+
},`);
|
|
562
|
+
}
|
|
563
|
+
if (has("PostToolUse")) {
|
|
564
|
+
handlers.push(` "tool.execute.after": async (input, output) => {
|
|
565
|
+
const res = bridge("PostToolUse", {
|
|
566
|
+
toolName: input.tool ?? "",
|
|
567
|
+
toolInput: input.args ?? {},
|
|
568
|
+
toolOutput: output ? output.output : undefined,
|
|
569
|
+
sessionId: input.sessionID ?? "",
|
|
570
|
+
projectDir: PROJECT_DIR,
|
|
571
|
+
});
|
|
572
|
+
if (!res) return;
|
|
573
|
+
if (typeof res.updatedOutput === "string" && output) output.output = res.updatedOutput;
|
|
574
|
+
},`);
|
|
575
|
+
}
|
|
576
|
+
if (has("SessionStart")) {
|
|
577
|
+
handlers.push(` "experimental.chat.system.transform": async (input, output) => {
|
|
578
|
+
const res = bridge("SessionStart", {
|
|
579
|
+
sessionId: (input && input.sessionID) ?? "",
|
|
580
|
+
projectDir: PROJECT_DIR,
|
|
581
|
+
});
|
|
582
|
+
if (!res) return;
|
|
583
|
+
if (res.additionalContext && output && Array.isArray(output.system)) {
|
|
584
|
+
output.system.splice(1, 0, res.additionalContext);
|
|
585
|
+
}
|
|
586
|
+
},`);
|
|
587
|
+
}
|
|
588
|
+
const factory = `
|
|
589
|
+
export default async function (ctx) {
|
|
590
|
+
const PROJECT_DIR =
|
|
591
|
+
(ctx && (ctx.directory || (ctx.worktree && ctx.worktree.path))) || process.cwd();
|
|
592
|
+
return {
|
|
593
|
+
${handlers.join("\n")}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
`;
|
|
597
|
+
return header + factory;
|
|
598
|
+
}
|
|
599
|
+
var emitNpmPlugin = (connector, ctx) => {
|
|
600
|
+
const { emit, files } = createEmitter(ctx.dryRun);
|
|
601
|
+
const pluginDir = join6(ctx.outDir, connector.id);
|
|
602
|
+
const notes = [];
|
|
603
|
+
emit(join6(pluginDir, "package.json"), json(buildPackageJson(connector)));
|
|
604
|
+
emit(join6(pluginDir, "index.js"), buildIndexJs(connector));
|
|
605
|
+
for (const skill of connector.skills) {
|
|
606
|
+
const skillDir = join6(pluginDir, "skills", skill.name);
|
|
607
|
+
emit(join6(skillDir, "SKILL.md"), renderSkillMd(skill));
|
|
608
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
609
|
+
const target = resolveWithin(skillDir, rel);
|
|
610
|
+
if (target === null) continue;
|
|
611
|
+
emit(target, contents);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
emit(
|
|
615
|
+
join6(pluginDir, "README.md"),
|
|
616
|
+
`# ${connector.displayName}
|
|
617
|
+
|
|
618
|
+
OpenCode / Kilo / Pi plugin package emitted by agent-connector.
|
|
619
|
+
|
|
620
|
+
Install with \`opencode plugin install <pkg>\` / \`kilo plugin <pkg>\` / \`pi install <pkg>\`.
|
|
621
|
+
|
|
622
|
+
## Prerequisite
|
|
623
|
+
|
|
624
|
+
Hooks shell out to the \`agent-connector\` CLI resolved from the consumer's PATH \u2014
|
|
625
|
+
the consumer machine needs \`npm i -g @ken-jo/agent-connector\` (hooks silently no-op,
|
|
626
|
+
fail-open, without it).
|
|
627
|
+
|
|
628
|
+
## Before you publish
|
|
629
|
+
|
|
630
|
+
The emitted package.json carries **no \`license\` and no \`author\`** unless your
|
|
631
|
+
connector declared \`publish.author\` \u2014 set them to YOUR terms before \`npm publish\`.
|
|
632
|
+
`
|
|
633
|
+
);
|
|
634
|
+
notes.push(
|
|
635
|
+
"npm-plugin: hooks require `npm i -g @ken-jo/agent-connector` on the consumer machine (bridge resolves the CLI by name on PATH; silently fail-open without it)"
|
|
636
|
+
);
|
|
637
|
+
notes.push(
|
|
638
|
+
"npm-plugin: set license/author in the emitted package.json before `npm publish` \u2014 agent-connector does not license your plugin for you"
|
|
639
|
+
);
|
|
640
|
+
if (connector.commands.length > 0) {
|
|
641
|
+
notes.push(
|
|
642
|
+
`npm-plugin: ${connector.commands.length} command(s) NOT bundled \u2014 opencode/kilo commands are native host dirs`
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
if (connector.subagents.length > 0) {
|
|
646
|
+
notes.push(
|
|
647
|
+
`npm-plugin: ${connector.subagents.length} subagent(s) NOT bundled \u2014 opencode/kilo subagents are native host dirs`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
if (connector.server) {
|
|
651
|
+
notes.push(
|
|
652
|
+
`npm-plugin: MCP server NOT bundled inside the package \u2014 register it via the opencode.json "mcp" key`
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
return { files, pluginDir, ...notes.length > 0 ? { notes } : {} };
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
// src/core/package-formats/mcp-server.ts
|
|
659
|
+
import { resolve as resolve2 } from "path";
|
|
660
|
+
function buildEnvVars(server) {
|
|
661
|
+
const vars = [];
|
|
662
|
+
const byName = /* @__PURE__ */ new Map();
|
|
663
|
+
for (const key of Object.keys(server.env ?? {})) {
|
|
664
|
+
const v = { name: key };
|
|
665
|
+
vars.push(v);
|
|
666
|
+
byName.set(key, v);
|
|
667
|
+
}
|
|
668
|
+
if (server.auth?.type === "bearerEnv" && server.auth.bearerEnvVar) {
|
|
669
|
+
const name = server.auth.bearerEnvVar;
|
|
670
|
+
const existing = byName.get(name);
|
|
671
|
+
if (existing) {
|
|
672
|
+
existing.isSecret = true;
|
|
673
|
+
existing.isRequired = true;
|
|
674
|
+
} else {
|
|
675
|
+
vars.push({ name, isSecret: true, isRequired: true });
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return vars;
|
|
679
|
+
}
|
|
680
|
+
function buildServerJson(connector, notes) {
|
|
681
|
+
const publish = connector.publish ?? {};
|
|
682
|
+
if (!publish.registryNamespace) {
|
|
683
|
+
throw new Error(
|
|
684
|
+
'package --format mcp-server-json needs publish.registryNamespace \u2014 a reverse-DNS namespace you OWN (e.g. "io.github.<your-handle>" or "com.<your-domain>"). agent-connector never publishes under a namespace it owns; set it in your connector config.'
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
const name = `${publish.registryNamespace}/${connector.id}`;
|
|
688
|
+
if (!REGISTRY_NAME_RE.test(name)) {
|
|
689
|
+
throw new Error(
|
|
690
|
+
`server.json name "${name}" must match ${REGISTRY_NAME_RE} (exactly one "/").`
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
if (!isConcreteSemver(connector.version)) {
|
|
694
|
+
throw new Error(
|
|
695
|
+
`server.json version must be a concrete SemVer (the registry rejects ranges); got "${connector.version}".`
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
if (isPlaceholderVersion(connector.version)) {
|
|
699
|
+
notes.push(
|
|
700
|
+
'version is the unset placeholder "0.0.0" \u2014 set a real version before publishing to the registry.'
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
const out = {
|
|
704
|
+
$schema: MCP_SERVER_SCHEMA_URL,
|
|
705
|
+
name,
|
|
706
|
+
description: connector.displayName,
|
|
707
|
+
version: connector.version
|
|
708
|
+
};
|
|
709
|
+
const server = connector.server;
|
|
710
|
+
if (!server) {
|
|
711
|
+
notes.push(
|
|
712
|
+
"connector declares no server \u2014 emitted server.json carries neither packages nor remotes (a hooks/commands-only connector is not a registry server)."
|
|
713
|
+
);
|
|
714
|
+
return out;
|
|
715
|
+
}
|
|
716
|
+
const tt = registryTransportType(server.transport);
|
|
717
|
+
if (tt === null) {
|
|
718
|
+
notes.push(
|
|
719
|
+
`transport "${server.transport}" is not an MCP spec transport and cannot be represented in server.json; emitted server metadata without a package/remote entry.`
|
|
720
|
+
);
|
|
721
|
+
return out;
|
|
722
|
+
}
|
|
723
|
+
if (server.transport === "stdio") {
|
|
724
|
+
if (!publish.packageName) {
|
|
725
|
+
throw new Error(
|
|
726
|
+
`package --format mcp-server-json needs publish.packageName \u2014 your REAL published npm package that runs the MCP server (e.g. "@acme/acme-db-mcp"). The registry runs that package directly, not agent-connector's serve wrapper.`
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
const pkg = {
|
|
730
|
+
registryType: "npm",
|
|
731
|
+
registryBaseUrl: publish.registryBaseUrl ?? NPM_REGISTRY_BASE_URL,
|
|
732
|
+
identifier: publish.packageName,
|
|
733
|
+
version: connector.version,
|
|
734
|
+
transport: { type: "stdio" }
|
|
735
|
+
};
|
|
736
|
+
const envVars = buildEnvVars(server);
|
|
737
|
+
if (envVars.length > 0) pkg.environmentVariables = envVars;
|
|
738
|
+
out.packages = [pkg];
|
|
739
|
+
} else {
|
|
740
|
+
const remote = { type: tt, url: server.url };
|
|
741
|
+
const headers = Object.keys(server.headers ?? {}).map((k) => ({ name: k }));
|
|
742
|
+
if (headers.length > 0) remote.headers = headers;
|
|
743
|
+
if (server.auth && server.auth.type !== "none") {
|
|
744
|
+
notes.push(
|
|
745
|
+
`remote server uses auth "${server.auth.type}" \u2014 add the credential header (isSecret) to the emitted remotes[].headers before publishing.`
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
out.remotes = [remote];
|
|
749
|
+
}
|
|
750
|
+
return out;
|
|
751
|
+
}
|
|
752
|
+
var emitMcpServerJson = (connector, ctx) => {
|
|
753
|
+
const emitter = createEmitter(ctx.dryRun);
|
|
754
|
+
const notes = [];
|
|
755
|
+
const serverJson = buildServerJson(connector, notes);
|
|
756
|
+
const path = resolve2(ctx.outDir, "server.json");
|
|
757
|
+
emitter.emit(path, json(serverJson));
|
|
758
|
+
return {
|
|
759
|
+
files: emitter.files,
|
|
760
|
+
pluginDir: ctx.outDir,
|
|
761
|
+
...notes.length > 0 ? { notes } : {}
|
|
762
|
+
};
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
// src/core/package-formats/mcpb.ts
|
|
766
|
+
import { resolve as resolve3 } from "path";
|
|
767
|
+
function titleize(s) {
|
|
768
|
+
return s.toLowerCase().split(/[_-]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
|
|
769
|
+
}
|
|
770
|
+
function secretEnvNames(server) {
|
|
771
|
+
const names = /* @__PURE__ */ new Set();
|
|
772
|
+
if (server.auth?.type === "bearerEnv" && server.auth.bearerEnvVar) {
|
|
773
|
+
names.add(server.auth.bearerEnvVar);
|
|
774
|
+
}
|
|
775
|
+
return names;
|
|
776
|
+
}
|
|
777
|
+
function recipeReadme(connector) {
|
|
778
|
+
return `# ${connector.displayName} \u2014 MCPB bundle
|
|
779
|
+
|
|
780
|
+
\`agent-connector package --format mcpb\` emitted the conformant **manifest.json**
|
|
781
|
+
(manifest_version ${MCPB_MANIFEST_VERSION}) for this connector. It does NOT build
|
|
782
|
+
the \`.mcpb\` zip \u2014 that step vendors your server and is yours to run, so the
|
|
783
|
+
bundle stays self-contained and signable.
|
|
784
|
+
|
|
785
|
+
## Finish the bundle
|
|
786
|
+
|
|
787
|
+
1. Put your built, self-contained MCP server at \`server/index.js\`
|
|
788
|
+
(the manifest's \`entry_point\` / \`mcp_config\`).
|
|
789
|
+
2. Vendor production dependencies into the bundle:
|
|
790
|
+
|
|
791
|
+
\`\`\`bash
|
|
792
|
+
cd server && npm install --omit=dev && cd ..
|
|
793
|
+
\`\`\`
|
|
794
|
+
|
|
795
|
+
3. Pack (and optionally sign) with the official MCPB CLI:
|
|
796
|
+
|
|
797
|
+
\`\`\`bash
|
|
798
|
+
npx @anthropic-ai/mcpb pack . # \u2192 ${connector.id}.mcpb
|
|
799
|
+
npx @anthropic-ai/mcpb sign ${connector.id}.mcpb
|
|
800
|
+
\`\`\`
|
|
801
|
+
|
|
802
|
+
The resulting \`.mcpb\` installs one-click into Claude Desktop and any MCPB host.
|
|
803
|
+
Secrets are declared under \`user_config\` and collected by the host keychain at
|
|
804
|
+
install time \u2014 never inline them in the manifest.
|
|
805
|
+
`;
|
|
806
|
+
}
|
|
807
|
+
var emitMcpbBundle = (connector, ctx) => {
|
|
808
|
+
const publish = connector.publish ?? {};
|
|
809
|
+
if (!publish.author?.name) {
|
|
810
|
+
throw new Error(
|
|
811
|
+
"package --format mcpb needs publish.author.name \u2014 the MCPB manifest requires an author."
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
if (!isConcreteSemver(connector.version)) {
|
|
815
|
+
throw new Error(
|
|
816
|
+
`mcpb manifest version must be a concrete SemVer; got "${connector.version}".`
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
const server = connector.server;
|
|
820
|
+
if (!server) {
|
|
821
|
+
throw new Error("package --format mcpb needs a server (an MCPB bundle packages an MCP server).");
|
|
822
|
+
}
|
|
823
|
+
if (server.transport !== "stdio") {
|
|
824
|
+
throw new Error(
|
|
825
|
+
`package --format mcpb supports stdio servers; "${server.transport}" is a remote server \u2014 publish it via the registry (--format mcp-server-json) instead.`
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
const notes = [];
|
|
829
|
+
if (isPlaceholderVersion(connector.version)) {
|
|
830
|
+
notes.push('version is the unset placeholder "0.0.0" \u2014 set a real version before packing.');
|
|
831
|
+
}
|
|
832
|
+
const secrets = secretEnvNames(server);
|
|
833
|
+
const env = {};
|
|
834
|
+
const userConfig = {};
|
|
835
|
+
for (const [k, v] of Object.entries(server.env ?? {})) {
|
|
836
|
+
if (secrets.has(k)) {
|
|
837
|
+
const key = k.toLowerCase();
|
|
838
|
+
userConfig[key] = {
|
|
839
|
+
type: "string",
|
|
840
|
+
title: titleize(k),
|
|
841
|
+
description: `Value for ${k}`,
|
|
842
|
+
sensitive: true,
|
|
843
|
+
required: true
|
|
844
|
+
};
|
|
845
|
+
env[k] = `\${user_config.${key}}`;
|
|
846
|
+
} else {
|
|
847
|
+
env[k] = v;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
for (const name of secrets) {
|
|
851
|
+
if (!(name in env)) {
|
|
852
|
+
const key = name.toLowerCase();
|
|
853
|
+
userConfig[key] = {
|
|
854
|
+
type: "string",
|
|
855
|
+
title: titleize(name),
|
|
856
|
+
description: `Value for ${name}`,
|
|
857
|
+
sensitive: true,
|
|
858
|
+
required: true
|
|
859
|
+
};
|
|
860
|
+
env[name] = `\${user_config.${key}}`;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const author = { name: publish.author.name };
|
|
864
|
+
if (publish.author.email) author.email = publish.author.email;
|
|
865
|
+
if (publish.author.url) author.url = publish.author.url;
|
|
866
|
+
const mcpConfig = {
|
|
867
|
+
command: "node",
|
|
868
|
+
args: ["${__dirname}/server/index.js"]
|
|
869
|
+
};
|
|
870
|
+
if (Object.keys(env).length > 0) mcpConfig.env = env;
|
|
871
|
+
const manifest = {
|
|
872
|
+
manifest_version: MCPB_MANIFEST_VERSION,
|
|
873
|
+
name: connector.id,
|
|
874
|
+
version: connector.version,
|
|
875
|
+
description: connector.displayName,
|
|
876
|
+
author,
|
|
877
|
+
server: {
|
|
878
|
+
type: "node",
|
|
879
|
+
entry_point: "server/index.js",
|
|
880
|
+
mcp_config: mcpConfig
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
if (Object.keys(userConfig).length > 0) manifest.user_config = userConfig;
|
|
884
|
+
if (server.command && !/\b(node|npx)\b/.test(server.command)) {
|
|
885
|
+
notes.push(
|
|
886
|
+
`your server command is "${server.command}" \u2014 the emitted manifest assumes a node server (server.type:node); adjust server.type/entry_point for your runtime (python|binary).`
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
notes.push(
|
|
890
|
+
"emitted manifest.json + README recipe; this format does NOT build the .mcpb zip. Place your self-contained server at server/index.js, vendor deps, then run `mcpb pack` (see README)."
|
|
891
|
+
);
|
|
892
|
+
const emitter = createEmitter(ctx.dryRun);
|
|
893
|
+
emitter.emit(resolve3(ctx.outDir, "manifest.json"), json(manifest));
|
|
894
|
+
emitter.emit(resolve3(ctx.outDir, "README.md"), recipeReadme(connector));
|
|
895
|
+
return { files: emitter.files, pluginDir: ctx.outDir, notes };
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// src/core/package.ts
|
|
899
|
+
var EMITTERS = {
|
|
900
|
+
"claude-plugin": emitClaudePlugin,
|
|
901
|
+
"codex-plugin": emitCodexPlugin,
|
|
902
|
+
"factory-plugin": emitFactoryPlugin,
|
|
903
|
+
"gemini-extension": emitGeminiExtension,
|
|
904
|
+
"qwen-extension": emitQwenExtension,
|
|
905
|
+
"agy-plugin": emitAgyPlugin,
|
|
906
|
+
"cursor-plugin": emitCursorPlugin,
|
|
907
|
+
"kimi-plugin": emitKimiPlugin,
|
|
908
|
+
"npm-plugin": emitNpmPlugin,
|
|
909
|
+
"mcp-server-json": emitMcpServerJson,
|
|
910
|
+
mcpb: emitMcpbBundle
|
|
911
|
+
};
|
|
912
|
+
var ALL_FORMATS = [
|
|
913
|
+
"claude-plugin",
|
|
914
|
+
"codex-plugin",
|
|
915
|
+
"factory-plugin",
|
|
916
|
+
"gemini-extension",
|
|
917
|
+
"qwen-extension",
|
|
918
|
+
"agy-plugin",
|
|
919
|
+
"cursor-plugin",
|
|
920
|
+
"kimi-plugin",
|
|
921
|
+
"npm-plugin",
|
|
922
|
+
"mcp-server-json",
|
|
923
|
+
"mcpb"
|
|
924
|
+
];
|
|
925
|
+
var FEASIBLE_FORMATS = [
|
|
926
|
+
"claude-plugin",
|
|
927
|
+
"codex-plugin",
|
|
928
|
+
"factory-plugin",
|
|
929
|
+
"gemini-extension",
|
|
930
|
+
"qwen-extension",
|
|
931
|
+
"agy-plugin",
|
|
932
|
+
"cursor-plugin",
|
|
933
|
+
"kimi-plugin",
|
|
934
|
+
"npm-plugin"
|
|
935
|
+
];
|
|
936
|
+
function isPackageFormat(s) {
|
|
937
|
+
return Object.prototype.hasOwnProperty.call(EMITTERS, s);
|
|
938
|
+
}
|
|
939
|
+
var HOME_BIN_EMBED_FORMATS = /* @__PURE__ */ new Set([
|
|
940
|
+
"claude-plugin",
|
|
941
|
+
"codex-plugin",
|
|
942
|
+
"factory-plugin",
|
|
943
|
+
"gemini-extension",
|
|
944
|
+
"qwen-extension",
|
|
945
|
+
"agy-plugin",
|
|
946
|
+
"cursor-plugin",
|
|
947
|
+
"kimi-plugin"
|
|
948
|
+
]);
|
|
949
|
+
function packageConnector(connector, opts) {
|
|
950
|
+
const format = opts.format ?? "claude-plugin";
|
|
951
|
+
const emitter = EMITTERS[format];
|
|
952
|
+
if (!emitter) {
|
|
953
|
+
throw new Error(`unsupported package format: ${format}`);
|
|
954
|
+
}
|
|
955
|
+
const ctx = {
|
|
956
|
+
outDir: resolve4(opts.outDir),
|
|
957
|
+
homeBinPath: opts.homeBinPath ?? homeBinPath(),
|
|
958
|
+
dryRun: opts.dryRun ?? false
|
|
959
|
+
};
|
|
960
|
+
const result = emitter(connector, ctx);
|
|
961
|
+
if (HOME_BIN_EMBED_FORMATS.has(format)) {
|
|
962
|
+
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`;
|
|
963
|
+
result.notes = [...result.notes ?? [], note];
|
|
964
|
+
}
|
|
965
|
+
return result;
|
|
966
|
+
}
|
|
967
|
+
function packageConnectorAll(connector, opts) {
|
|
968
|
+
const base = resolve4(opts.outDir);
|
|
969
|
+
const homeBin = opts.homeBinPath ?? homeBinPath();
|
|
970
|
+
const dryRun = opts.dryRun ?? false;
|
|
971
|
+
return FEASIBLE_FORMATS.map((format) => ({
|
|
972
|
+
format,
|
|
973
|
+
result: packageConnector(connector, {
|
|
974
|
+
outDir: resolve4(base, format),
|
|
975
|
+
format,
|
|
976
|
+
homeBinPath: homeBin,
|
|
977
|
+
dryRun
|
|
978
|
+
})
|
|
979
|
+
}));
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// src/cli/commands/package.ts
|
|
983
|
+
var HELP = `agent-connector package \u2014 emit a plugin/extension/marketplace bundle.
|
|
984
|
+
|
|
985
|
+
usage: agent-connector package [flags]
|
|
986
|
+
|
|
987
|
+
flags:
|
|
988
|
+
--connector <path> Connector config to package (else auto-discovered).
|
|
989
|
+
--format <fmt> Output format (default: claude-plugin). One of:
|
|
990
|
+
${ALL_FORMATS.join(", ")}
|
|
991
|
+
or "all" to emit every feasible format into <out>/<fmt>/.
|
|
992
|
+
--out <dir> Output directory. Default: <cwd>/dist-plugin.
|
|
993
|
+
--project <dir> Project root for connector discovery (default: cwd).
|
|
994
|
+
--dry-run Compute the file tree without writing anything.
|
|
995
|
+
--help Show this help.`;
|
|
996
|
+
function printFormatResult(format, connectorId, outDir, result) {
|
|
997
|
+
print(` pluginDir: ${result.pluginDir}`);
|
|
998
|
+
if (result.marketplacePath) {
|
|
999
|
+
print(` marketplace: ${relative2(outDir, result.marketplacePath)}`);
|
|
1000
|
+
}
|
|
1001
|
+
print(" emitted files:");
|
|
1002
|
+
for (const f of result.files) {
|
|
1003
|
+
print(` + ${relative2(outDir, f)}`);
|
|
1004
|
+
}
|
|
1005
|
+
if (result.notes && result.notes.length > 0) {
|
|
1006
|
+
print(" notes:");
|
|
1007
|
+
for (const n of result.notes) print(` ! ${n}`);
|
|
1008
|
+
}
|
|
1009
|
+
print(" install:");
|
|
1010
|
+
for (const line of installInstructions(format, connectorId, outDir)) {
|
|
1011
|
+
print(` ${line}`);
|
|
1012
|
+
}
|
|
1013
|
+
print("");
|
|
1014
|
+
}
|
|
1015
|
+
function installInstructions(format, id, outDir) {
|
|
1016
|
+
switch (format) {
|
|
1017
|
+
case "claude-plugin":
|
|
1018
|
+
return [
|
|
1019
|
+
`/plugin marketplace add ${outDir}`,
|
|
1020
|
+
`/plugin install ${id}@agent-connector`,
|
|
1021
|
+
`(CLI: claude plugin marketplace add ${outDir} && claude plugin install ${id}@agent-connector)`
|
|
1022
|
+
];
|
|
1023
|
+
case "codex-plugin":
|
|
1024
|
+
return [
|
|
1025
|
+
`codex plugin marketplace add ${outDir}`,
|
|
1026
|
+
`codex plugin add ${id}@agent-connector`
|
|
1027
|
+
];
|
|
1028
|
+
case "factory-plugin":
|
|
1029
|
+
return [
|
|
1030
|
+
`droid plugin marketplace add ${outDir}`,
|
|
1031
|
+
`droid plugin install ${id}@agent-connector`
|
|
1032
|
+
];
|
|
1033
|
+
case "gemini-extension":
|
|
1034
|
+
return [`gemini extensions install ${join7(outDir, id)}`];
|
|
1035
|
+
case "qwen-extension":
|
|
1036
|
+
return [`qwen extensions install ${join7(outDir, id)}`];
|
|
1037
|
+
case "agy-plugin":
|
|
1038
|
+
return [
|
|
1039
|
+
`agy plugin install ${join7(outDir, id)}`,
|
|
1040
|
+
`(validate: agy plugin validate ${join7(outDir, id)})`
|
|
1041
|
+
];
|
|
1042
|
+
case "cursor-plugin":
|
|
1043
|
+
return [
|
|
1044
|
+
`link ${join7(outDir, id)} into ~/.cursor/plugins/local/${id}/ then Developer: Reload Window`,
|
|
1045
|
+
`(or publish ${outDir} as a Cursor marketplace repo)`
|
|
1046
|
+
];
|
|
1047
|
+
case "kimi-plugin":
|
|
1048
|
+
return [`kimi plugin install ${join7(outDir, id)}`];
|
|
1049
|
+
case "npm-plugin":
|
|
1050
|
+
return [
|
|
1051
|
+
`npm publish ${join7(outDir, id)} (then: opencode plugin install <pkg> | kilo plugin <pkg> | pi install npm:<pkg>)`
|
|
1052
|
+
];
|
|
1053
|
+
case "mcp-server-json":
|
|
1054
|
+
return [
|
|
1055
|
+
`mcp-publisher login <github|dns|http> (prove ownership of your namespace once)`,
|
|
1056
|
+
`cd ${outDir} && mcp-publisher publish (uploads server.json to the official MCP Registry)`
|
|
1057
|
+
];
|
|
1058
|
+
case "mcpb":
|
|
1059
|
+
return [
|
|
1060
|
+
`vendor your built server under ${join7(outDir, "server")}/ (see the emitted README)`,
|
|
1061
|
+
`npx @anthropic-ai/mcpb pack ${outDir} (then optionally: mcpb sign)`
|
|
1062
|
+
];
|
|
1063
|
+
default:
|
|
1064
|
+
return [];
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
async function run(argv) {
|
|
1068
|
+
const { values } = parseArgs({
|
|
1069
|
+
args: argv,
|
|
1070
|
+
options: {
|
|
1071
|
+
connector: { type: "string" },
|
|
1072
|
+
format: { type: "string", default: "claude-plugin" },
|
|
1073
|
+
out: { type: "string" },
|
|
1074
|
+
project: { type: "string" },
|
|
1075
|
+
"dry-run": { type: "boolean", default: false },
|
|
1076
|
+
help: { type: "boolean", default: false }
|
|
1077
|
+
},
|
|
1078
|
+
allowPositionals: false
|
|
1079
|
+
});
|
|
1080
|
+
if (values.help) {
|
|
1081
|
+
print(HELP);
|
|
1082
|
+
return 0;
|
|
1083
|
+
}
|
|
1084
|
+
const formatArg = values.format ?? "claude-plugin";
|
|
1085
|
+
const isAll = formatArg === "all";
|
|
1086
|
+
if (!isAll && !isPackageFormat(formatArg)) {
|
|
1087
|
+
return fail(
|
|
1088
|
+
`invalid --format "${formatArg}" (expected one of: ${ALL_FORMATS.join(", ")}, or "all")`
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
const projectDir = values.project ?? process.cwd();
|
|
1092
|
+
const configPath = values.connector ?? findConnectorConfig(projectDir);
|
|
1093
|
+
if (!configPath) {
|
|
1094
|
+
return fail(
|
|
1095
|
+
"no connector config found. Pass --connector <path> or add an agent-connector.config.{mjs,js,json} to your project."
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
const outDir = values.out ?? `${process.cwd()}/dist-plugin`;
|
|
1099
|
+
const dryRun = values["dry-run"];
|
|
1100
|
+
const mode = dryRun ? " (dry-run \u2014 nothing written)" : "";
|
|
1101
|
+
const { connector } = await loadConnectorFromPath(configPath);
|
|
1102
|
+
if (isAll) {
|
|
1103
|
+
print(`package "${connector.id}" \u2192 all formats${mode}`);
|
|
1104
|
+
print(` outDir: ${outDir}`);
|
|
1105
|
+
print("");
|
|
1106
|
+
const results = packageConnectorAll(connector, { outDir, dryRun });
|
|
1107
|
+
for (const { format: format2, result: result2 } of results) {
|
|
1108
|
+
const formatOut = join7(outDir, format2);
|
|
1109
|
+
print(`\u2500\u2500 ${format2} \u2500\u2500`);
|
|
1110
|
+
printFormatResult(format2, connector.id, formatOut, result2);
|
|
1111
|
+
}
|
|
1112
|
+
print(`emitted ${results.length} formats: ${FEASIBLE_FORMATS.join(", ")}`);
|
|
1113
|
+
return 0;
|
|
1114
|
+
}
|
|
1115
|
+
const format = formatArg;
|
|
1116
|
+
let result;
|
|
1117
|
+
try {
|
|
1118
|
+
result = packageConnector(connector, { outDir, format, dryRun });
|
|
1119
|
+
} catch (err) {
|
|
1120
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1121
|
+
return fail(message);
|
|
1122
|
+
}
|
|
1123
|
+
print(`package "${connector.id}" \u2192 ${format}${mode}`);
|
|
1124
|
+
print(` outDir: ${outDir}`);
|
|
1125
|
+
print("");
|
|
1126
|
+
printFormatResult(format, connector.id, outDir, result);
|
|
1127
|
+
return 0;
|
|
1128
|
+
}
|
|
1129
|
+
export {
|
|
1130
|
+
run
|
|
1131
|
+
};
|
|
1132
|
+
//# sourceMappingURL=package-DLOVE2E4.js.map
|