@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,587 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveEnvRefsDeep
|
|
4
|
+
} from "./chunk-DBQMX75U.js";
|
|
5
|
+
import {
|
|
6
|
+
BaseAdapter
|
|
7
|
+
} from "./chunk-TIIP3RG2.js";
|
|
8
|
+
import "./chunk-7L6ITC4T.js";
|
|
9
|
+
import {
|
|
10
|
+
buildServeWrapperCommand,
|
|
11
|
+
shouldWrapForTelemetry
|
|
12
|
+
} from "./chunk-MEH7GC7R.js";
|
|
13
|
+
import "./chunk-TRQKHP7D.js";
|
|
14
|
+
|
|
15
|
+
// src/adapters/kilo-cli/index.ts
|
|
16
|
+
import {
|
|
17
|
+
chmodSync,
|
|
18
|
+
existsSync,
|
|
19
|
+
mkdirSync,
|
|
20
|
+
readFileSync,
|
|
21
|
+
rmSync,
|
|
22
|
+
writeFileSync
|
|
23
|
+
} from "fs";
|
|
24
|
+
import { homedir } from "os";
|
|
25
|
+
import { dirname, join } from "path";
|
|
26
|
+
var HOST = "kilo-cli";
|
|
27
|
+
var MCP_ROOT_KEY = "mcp";
|
|
28
|
+
var PLUGIN_ARRAY_KEY = "plugin";
|
|
29
|
+
var CONFIG_FILE = "kilo.jsonc";
|
|
30
|
+
var CLI_DB_RELPATH = [".local", "share", "kilo", "kilo.db"];
|
|
31
|
+
var EVENT_TO_KILO = {
|
|
32
|
+
PreToolUse: "tool.execute.before",
|
|
33
|
+
PostToolUse: "tool.execute.after",
|
|
34
|
+
SessionStart: "experimental.chat.system.transform"
|
|
35
|
+
};
|
|
36
|
+
var KiloCliAdapter = class extends BaseAdapter {
|
|
37
|
+
id = HOST;
|
|
38
|
+
name = "Kilo CLI";
|
|
39
|
+
paradigm = "ts-plugin";
|
|
40
|
+
capabilities = {
|
|
41
|
+
// Matches the OpenCode capability surface — the fork inherits its plugin
|
|
42
|
+
// event model.
|
|
43
|
+
preToolUse: true,
|
|
44
|
+
postToolUse: true,
|
|
45
|
+
// The fork's compaction hook is experimental and not wired here.
|
|
46
|
+
preCompact: false,
|
|
47
|
+
sessionStart: true,
|
|
48
|
+
sessionEnd: false,
|
|
49
|
+
userPromptSubmit: false,
|
|
50
|
+
stop: false,
|
|
51
|
+
notification: false,
|
|
52
|
+
// tool.execute.before mutates output.args → input rewrite supported.
|
|
53
|
+
canModifyArgs: true,
|
|
54
|
+
// tool.execute.after mutates output.output → output rewrite supported.
|
|
55
|
+
canModifyOutput: true,
|
|
56
|
+
// injected via the system-prompt transform at session start.
|
|
57
|
+
canInjectSessionContext: true,
|
|
58
|
+
// The Kilo CLI registers stdio (local), SSE, and Streamable HTTP MCP servers.
|
|
59
|
+
transports: ["stdio", "sse", "http"],
|
|
60
|
+
// No confirmed CLI content surface — these inherit the BaseAdapter warn/skip.
|
|
61
|
+
supportsCommands: false,
|
|
62
|
+
supportsSkills: false,
|
|
63
|
+
supportsSubagents: false
|
|
64
|
+
};
|
|
65
|
+
// ── Detection ────────────────────────────────────────────────────────────
|
|
66
|
+
detectInstalled(projectDir) {
|
|
67
|
+
const userDir = join(homedir(), ".config", "kilo");
|
|
68
|
+
const userConfig = join(userDir, CONFIG_FILE);
|
|
69
|
+
const projectConfig = join(projectDir, ".kilo", CONFIG_FILE);
|
|
70
|
+
const cliDb = join(homedir(), ...CLI_DB_RELPATH);
|
|
71
|
+
const userInstalled = existsSync(userDir) || existsSync(cliDb);
|
|
72
|
+
const projInstalled = existsSync(projectConfig);
|
|
73
|
+
const installed = userInstalled || projInstalled;
|
|
74
|
+
const scope = projInstalled && !userInstalled ? "project" : "user";
|
|
75
|
+
const configPath = scope === "project" ? projectConfig : userConfig;
|
|
76
|
+
return {
|
|
77
|
+
id: this.id,
|
|
78
|
+
name: this.name,
|
|
79
|
+
installed,
|
|
80
|
+
paradigm: this.paradigm,
|
|
81
|
+
capabilities: this.capabilities,
|
|
82
|
+
configPath,
|
|
83
|
+
scope,
|
|
84
|
+
reason: installed ? scope === "project" ? `found project Kilo CLI config at ${projectConfig}` : existsSync(cliDb) ? `found Kilo CLI session store at ${cliDb}` : `found Kilo CLI config under ${userDir}` : `no Kilo CLI config at ${userDir} or session store at ${cliDb}`,
|
|
85
|
+
confidence: installed ? "high" : "low"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// ── Native paths ─────────────────────────────────────────────────────────
|
|
89
|
+
getConfigDir(ctx) {
|
|
90
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".kilo") : join(homedir(), ".config", "kilo");
|
|
91
|
+
}
|
|
92
|
+
getServerConfigPath(ctx) {
|
|
93
|
+
return join(this.getConfigDir(ctx), CONFIG_FILE);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* For ts-plugin hosts the "hook config path" is the generated plugin FILE.
|
|
97
|
+
* Unlike OpenCode, writing the file is NOT sufficient: the fork loads only the
|
|
98
|
+
* module paths listed in kilo.jsonc's `plugin` array, so installHooks also
|
|
99
|
+
* registers this path there.
|
|
100
|
+
*/
|
|
101
|
+
getHookConfigPath(ctx) {
|
|
102
|
+
return join(this.pluginDir(ctx), this.pluginFileName(ctx));
|
|
103
|
+
}
|
|
104
|
+
/** Plugin directory the synthesized module is written into, per scope. */
|
|
105
|
+
pluginDir(ctx) {
|
|
106
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".kilo", "plugin") : join(homedir(), ".config", "kilo", "plugin");
|
|
107
|
+
}
|
|
108
|
+
/** Plugin module file name (one per connector, kebab-case id). */
|
|
109
|
+
pluginFileName(ctx) {
|
|
110
|
+
return `${ctx.connector.id}.js`;
|
|
111
|
+
}
|
|
112
|
+
// ── MCP server install / uninstall ───────────────────────────────────────
|
|
113
|
+
installServer(ctx) {
|
|
114
|
+
const { connector } = ctx;
|
|
115
|
+
const override = connector.platforms[HOST]?.server;
|
|
116
|
+
if (!connector.server || override === false) {
|
|
117
|
+
return [
|
|
118
|
+
{
|
|
119
|
+
platform: this.id,
|
|
120
|
+
action: "skip",
|
|
121
|
+
detail: connector.server ? "server registration disabled for kilo-cli" : "connector declares no MCP server"
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
const server = override && typeof override === "object" ? { ...connector.server, ...override } : connector.server;
|
|
126
|
+
const serverPath = this.getServerConfigPath(ctx);
|
|
127
|
+
const entry = this.renderServerEntry(ctx, server);
|
|
128
|
+
return [
|
|
129
|
+
this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun)
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
uninstallServer(ctx) {
|
|
133
|
+
const serverPath = this.getServerConfigPath(ctx);
|
|
134
|
+
return [
|
|
135
|
+
this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun)
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
/** Render a normalized ServerDef into the Kilo CLI's new-gen `mcp` entry. */
|
|
139
|
+
renderServerEntry(ctx, server) {
|
|
140
|
+
const transport = server.transport;
|
|
141
|
+
if (transport === "stdio") {
|
|
142
|
+
let command = server.command ?? "";
|
|
143
|
+
let args = [...server.args ?? []];
|
|
144
|
+
if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
|
|
145
|
+
const wrapped = buildServeWrapperCommand(
|
|
146
|
+
ctx.homeBinPath,
|
|
147
|
+
ctx.connector.id,
|
|
148
|
+
command,
|
|
149
|
+
args,
|
|
150
|
+
ctx.scope,
|
|
151
|
+
this.id
|
|
152
|
+
);
|
|
153
|
+
command = wrapped.command;
|
|
154
|
+
args = wrapped.args;
|
|
155
|
+
}
|
|
156
|
+
const entry2 = {
|
|
157
|
+
type: "local",
|
|
158
|
+
command: resolveEnvRefsDeep([command, ...args])
|
|
159
|
+
};
|
|
160
|
+
const env = this.renderEnv(server.env);
|
|
161
|
+
if (env) entry2.environment = env;
|
|
162
|
+
return entry2;
|
|
163
|
+
}
|
|
164
|
+
const entry = {
|
|
165
|
+
type: "remote",
|
|
166
|
+
url: resolveEnvRefsDeep(server.url ?? "")
|
|
167
|
+
};
|
|
168
|
+
return entry;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Render env values. The Kilo CLI documents no native interpolation token, so
|
|
172
|
+
* resolve `${env:VAR}` references to literals at install time.
|
|
173
|
+
*/
|
|
174
|
+
renderEnv(env) {
|
|
175
|
+
if (!env || Object.keys(env).length === 0) return void 0;
|
|
176
|
+
return resolveEnvRefsDeep({ ...env });
|
|
177
|
+
}
|
|
178
|
+
// ── Hook install / uninstall (ts-plugin + explicit `plugin` array) ────────
|
|
179
|
+
installHooks(ctx) {
|
|
180
|
+
const pluginPath = this.getHookConfigPath(ctx);
|
|
181
|
+
const configPath = this.getServerConfigPath(ctx);
|
|
182
|
+
if (ctx.connector.platforms[HOST]?.hooks === false) {
|
|
183
|
+
return [
|
|
184
|
+
{ platform: this.id, action: "skip", path: pluginPath, detail: "hooks disabled for kilo-cli" }
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
if (ctx.connector.hookEvents.length === 0) {
|
|
188
|
+
return [
|
|
189
|
+
{ platform: this.id, action: "skip", path: pluginPath, detail: "connector declares no hooks" }
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
const changes = [];
|
|
193
|
+
for (const file of this.synthesizePlugin(ctx)) {
|
|
194
|
+
const before = existsSync(file.path) ? this.safeRead(file.path) : void 0;
|
|
195
|
+
let action;
|
|
196
|
+
if (before === void 0) action = "create";
|
|
197
|
+
else if (before === file.contents) action = "skip";
|
|
198
|
+
else action = "update";
|
|
199
|
+
if (action !== "skip" && !ctx.dryRun) {
|
|
200
|
+
ensureDir(dirname(file.path));
|
|
201
|
+
writeFileSync(file.path, file.contents, "utf8");
|
|
202
|
+
chmodSync(file.path, file.executable ? 493 : 420);
|
|
203
|
+
}
|
|
204
|
+
changes.push({
|
|
205
|
+
platform: this.id,
|
|
206
|
+
action,
|
|
207
|
+
path: file.path,
|
|
208
|
+
detail: `kilo plugin module (${this.hookDetail(ctx)})`
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
changes.push(this.upsertPluginInArray(configPath, pluginPath, ctx.dryRun));
|
|
212
|
+
return changes;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Human-facing summary of which declared events the synthesized module ACTUALLY
|
|
216
|
+
* wires. Only events present in EVENT_TO_KILO are mapped/wired; any declared
|
|
217
|
+
* event with no Kilo mapping is reported separately as "unsupported here" so
|
|
218
|
+
* the detail never overstates coverage.
|
|
219
|
+
*/
|
|
220
|
+
hookDetail(ctx) {
|
|
221
|
+
const declared = ctx.connector.hookEvents;
|
|
222
|
+
const mapped = declared.filter((e) => EVENT_TO_KILO[e] !== void 0);
|
|
223
|
+
const unsupported = declared.filter((e) => EVENT_TO_KILO[e] === void 0);
|
|
224
|
+
const base = mapped.join(",");
|
|
225
|
+
return unsupported.length > 0 ? `${base}; unsupported here: ${unsupported.join(",")}` : base;
|
|
226
|
+
}
|
|
227
|
+
uninstallHooks(ctx) {
|
|
228
|
+
const pluginPath = this.getHookConfigPath(ctx);
|
|
229
|
+
const configPath = this.getServerConfigPath(ctx);
|
|
230
|
+
const changes = [];
|
|
231
|
+
changes.push(this.removePluginFromArray(configPath, pluginPath, ctx.dryRun));
|
|
232
|
+
if (existsSync(pluginPath)) {
|
|
233
|
+
if (!ctx.dryRun) rmSync(pluginPath, { force: true });
|
|
234
|
+
changes.push({
|
|
235
|
+
platform: this.id,
|
|
236
|
+
action: "remove",
|
|
237
|
+
path: pluginPath,
|
|
238
|
+
detail: "kilo plugin module"
|
|
239
|
+
});
|
|
240
|
+
} else {
|
|
241
|
+
changes.push({
|
|
242
|
+
platform: this.id,
|
|
243
|
+
action: "skip",
|
|
244
|
+
path: pluginPath,
|
|
245
|
+
detail: "no kilo plugin module present"
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
changes.push(this.removeDirIfEmpty(this.pluginDir(ctx), ctx.dryRun));
|
|
249
|
+
return changes;
|
|
250
|
+
}
|
|
251
|
+
/** Upsert the module path into kilo.jsonc's top-level `plugin` array (idempotent). */
|
|
252
|
+
upsertPluginInArray(configPath, modulePath, dryRun) {
|
|
253
|
+
if (this.isPresentButUnparseable(configPath)) {
|
|
254
|
+
return {
|
|
255
|
+
platform: this.id,
|
|
256
|
+
action: "warn",
|
|
257
|
+
path: configPath,
|
|
258
|
+
detail: `existing ${configPath} is not parseable; left untouched (back it up / fix it, then re-run)`
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const cfg = this.readJson(configPath) ?? {};
|
|
262
|
+
const plugins = this.pluginArrayBucket(cfg);
|
|
263
|
+
if (plugins.includes(modulePath)) {
|
|
264
|
+
return {
|
|
265
|
+
platform: this.id,
|
|
266
|
+
action: "skip",
|
|
267
|
+
path: configPath,
|
|
268
|
+
detail: `${PLUGIN_ARRAY_KEY}[] already includes module`
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
plugins.push(modulePath);
|
|
272
|
+
this.writeJson(configPath, cfg, dryRun);
|
|
273
|
+
return {
|
|
274
|
+
platform: this.id,
|
|
275
|
+
action: "create",
|
|
276
|
+
path: configPath,
|
|
277
|
+
detail: `${PLUGIN_ARRAY_KEY}[] += module`
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/** Remove the module path from kilo.jsonc's `plugin` array. */
|
|
281
|
+
removePluginFromArray(configPath, modulePath, dryRun) {
|
|
282
|
+
if (this.isPresentButUnparseable(configPath)) {
|
|
283
|
+
return {
|
|
284
|
+
platform: this.id,
|
|
285
|
+
action: "warn",
|
|
286
|
+
path: configPath,
|
|
287
|
+
detail: `existing ${configPath} is not parseable; left untouched (back it up / fix it, then re-run)`
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const cfg = this.readJson(configPath);
|
|
291
|
+
const raw = cfg?.[PLUGIN_ARRAY_KEY];
|
|
292
|
+
const plugins = Array.isArray(raw) ? raw : void 0;
|
|
293
|
+
const idx = plugins ? plugins.indexOf(modulePath) : -1;
|
|
294
|
+
if (!cfg || !plugins || idx < 0) {
|
|
295
|
+
return {
|
|
296
|
+
platform: this.id,
|
|
297
|
+
action: "skip",
|
|
298
|
+
path: configPath,
|
|
299
|
+
detail: `${PLUGIN_ARRAY_KEY}[] does not include module`
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
plugins.splice(idx, 1);
|
|
303
|
+
this.writeJson(configPath, cfg, dryRun);
|
|
304
|
+
return {
|
|
305
|
+
platform: this.id,
|
|
306
|
+
action: "remove",
|
|
307
|
+
path: configPath,
|
|
308
|
+
detail: `${PLUGIN_ARRAY_KEY}[] -= module`
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/** Get-or-create the top-level `plugin` array as a mutable string array. */
|
|
312
|
+
pluginArrayBucket(cfg) {
|
|
313
|
+
const existing = cfg[PLUGIN_ARRAY_KEY];
|
|
314
|
+
const plugins = Array.isArray(existing) ? existing.filter((p) => typeof p === "string") : [];
|
|
315
|
+
cfg[PLUGIN_ARRAY_KEY] = plugins;
|
|
316
|
+
return plugins;
|
|
317
|
+
}
|
|
318
|
+
// ── ts-plugin synthesis ────────────────────────────────────────────────
|
|
319
|
+
/**
|
|
320
|
+
* Build ONE self-contained ESM plugin module for the Kilo CLI fork.
|
|
321
|
+
*
|
|
322
|
+
* The module imports nothing from agent-connector. It embeds two constants
|
|
323
|
+
* (the absolute home-bin path and the connector id) and a `bridge()` helper
|
|
324
|
+
* that shells out to the universal hook entrypoint via execFileSync, feeding
|
|
325
|
+
* the Kilo payload on stdin and JSON.parsing the normalized HookResponse back
|
|
326
|
+
* from stdout (fail-open: any error → null). Its default export is the
|
|
327
|
+
* `@kilocode/plugin` PluginModule shape — { id, server: async (input) =>
|
|
328
|
+
* ({ "tool.execute.before": …, "tool.execute.after": …, … }) } — keyed only by
|
|
329
|
+
* the fork event names for the events this connector actually declares.
|
|
330
|
+
*/
|
|
331
|
+
synthesizePlugin(ctx) {
|
|
332
|
+
const path = this.getHookConfigPath(ctx);
|
|
333
|
+
const contents = this.buildPluginSource(ctx);
|
|
334
|
+
return [{ path, contents, executable: false }];
|
|
335
|
+
}
|
|
336
|
+
/** Compose the generated plugin source with plain string concatenation. */
|
|
337
|
+
buildPluginSource(ctx) {
|
|
338
|
+
const homeBin = JSON.stringify(ctx.homeBinPath);
|
|
339
|
+
const connectorId = JSON.stringify(ctx.connector.id);
|
|
340
|
+
const events = ctx.connector.hookEvents.filter(
|
|
341
|
+
(e) => EVENT_TO_KILO[e] !== void 0
|
|
342
|
+
);
|
|
343
|
+
const has = (e) => events.includes(e);
|
|
344
|
+
const header = `/**
|
|
345
|
+
* AUTO-GENERATED by agent-connector \u2014 DO NOT EDIT.
|
|
346
|
+
*
|
|
347
|
+
* Self-contained Kilo CLI plugin bridge for connector ${ctx.connector.id}.
|
|
348
|
+
* It imports nothing from agent-connector: every hook invocation shells out to
|
|
349
|
+
* the stable home binary's universal entrypoint and JSON-parses the normalized
|
|
350
|
+
* response. Fail-open: any bridge error degrades to "allow".
|
|
351
|
+
*
|
|
352
|
+
* Default export is the @kilocode/plugin PluginModule shape
|
|
353
|
+
* ({ id, server: async (input) => Hooks }); the fork loads it because its path
|
|
354
|
+
* is registered in kilo.jsonc's "plugin" array.
|
|
355
|
+
*/
|
|
356
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
357
|
+
|
|
358
|
+
const HOME_BIN = ${homeBin};
|
|
359
|
+
const CONNECTOR_ID = ${connectorId};
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Invoke the universal hook entrypoint for one event.
|
|
363
|
+
* @param {string} event canonical event name (PreToolUse|PostToolUse|SessionStart)
|
|
364
|
+
* @param {object} payload Kilo-shaped payload posted on stdin
|
|
365
|
+
* @returns {object|null} normalized HookResponse, or null on any failure
|
|
366
|
+
*/
|
|
367
|
+
function bridge(event, payload) {
|
|
368
|
+
try {
|
|
369
|
+
// On Windows HOME_BIN is the agent-connector.cmd launcher: Node cannot
|
|
370
|
+
// execFile a batch file, and shell+args is deprecated (DEP0190), so run one
|
|
371
|
+
// quoted command line via a shell. POSIX keeps the direct execFile (no shell).
|
|
372
|
+
const args = ["hook", "kilo-cli", event, "--connector", CONNECTOR_ID];
|
|
373
|
+
const opts = { input: JSON.stringify(payload), encoding: "utf8" };
|
|
374
|
+
const stdout =
|
|
375
|
+
process.platform === "win32"
|
|
376
|
+
? execSync([HOME_BIN, ...args].map((a) => '"' + a + '"').join(" "), opts)
|
|
377
|
+
: execFileSync(HOME_BIN, args, opts);
|
|
378
|
+
const text = (stdout || "").trim();
|
|
379
|
+
if (text === "") return { decision: "allow" };
|
|
380
|
+
return JSON.parse(text);
|
|
381
|
+
} catch {
|
|
382
|
+
// Fail-open \u2014 never wedge a tool call on a bridge error.
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
`;
|
|
387
|
+
const handlers = [];
|
|
388
|
+
if (has("PreToolUse")) {
|
|
389
|
+
handlers.push(` // PreToolUse \u2192 block (throw) / rewrite args (mutate output.args).
|
|
390
|
+
"tool.execute.before": async (input, output) => {
|
|
391
|
+
const payload = {
|
|
392
|
+
toolName: input.tool ?? "",
|
|
393
|
+
toolInput: (output && output.args) ?? {},
|
|
394
|
+
sessionId: input.sessionID ?? "",
|
|
395
|
+
projectDir: PROJECT_DIR,
|
|
396
|
+
};
|
|
397
|
+
const res = bridge("PreToolUse", payload);
|
|
398
|
+
if (!res) return;
|
|
399
|
+
// Kilo has no "ask" gate \u2014 degrade "ask" to a block (safe direction).
|
|
400
|
+
if (res.decision === "deny" || res.decision === "ask") {
|
|
401
|
+
throw new Error(res.reason || "Blocked by ${ctx.connector.id}");
|
|
402
|
+
}
|
|
403
|
+
if (res.updatedInput && output && output.args) {
|
|
404
|
+
Object.assign(output.args, res.updatedInput);
|
|
405
|
+
}
|
|
406
|
+
},`);
|
|
407
|
+
}
|
|
408
|
+
if (has("PostToolUse")) {
|
|
409
|
+
handlers.push(` // PostToolUse \u2192 observe / rewrite tool output (mutate output.output).
|
|
410
|
+
"tool.execute.after": async (input, output) => {
|
|
411
|
+
const payload = {
|
|
412
|
+
toolName: input.tool ?? "",
|
|
413
|
+
toolInput: input.args ?? {},
|
|
414
|
+
toolOutput: output ? output.output : undefined,
|
|
415
|
+
sessionId: input.sessionID ?? "",
|
|
416
|
+
projectDir: PROJECT_DIR,
|
|
417
|
+
};
|
|
418
|
+
const res = bridge("PostToolUse", payload);
|
|
419
|
+
if (!res) return;
|
|
420
|
+
if (typeof res.updatedOutput === "string" && output) {
|
|
421
|
+
output.output = res.updatedOutput;
|
|
422
|
+
}
|
|
423
|
+
},`);
|
|
424
|
+
}
|
|
425
|
+
if (has("SessionStart")) {
|
|
426
|
+
handlers.push(` // SessionStart surrogate \u2192 inject context into the system prompt.
|
|
427
|
+
// The fork has no real SessionStart hook; the system-prompt transform is the
|
|
428
|
+
// verified injection point (mirrors OpenCode).
|
|
429
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
430
|
+
const payload = {
|
|
431
|
+
sessionId: (input && input.sessionID) ?? "",
|
|
432
|
+
projectDir: PROJECT_DIR,
|
|
433
|
+
};
|
|
434
|
+
const res = bridge("SessionStart", payload);
|
|
435
|
+
if (!res) return;
|
|
436
|
+
if (res.additionalContext && output && Array.isArray(output.system)) {
|
|
437
|
+
// Insert at index 1 (after the header) to preserve the prompt-cache fold
|
|
438
|
+
// (header must remain system[0]).
|
|
439
|
+
output.system.splice(1, 0, res.additionalContext);
|
|
440
|
+
}
|
|
441
|
+
},`);
|
|
442
|
+
}
|
|
443
|
+
const definition = `
|
|
444
|
+
const plugin = {
|
|
445
|
+
id: CONNECTOR_ID,
|
|
446
|
+
// @kilocode/plugin PluginModule: server(input) returns the Hooks object keyed
|
|
447
|
+
// by the fork's event names. ctx.directory is the project root; fall back to cwd.
|
|
448
|
+
server: async (input) => {
|
|
449
|
+
const PROJECT_DIR =
|
|
450
|
+
(input && (input.directory || (input.worktree && input.worktree.path))) ||
|
|
451
|
+
process.cwd();
|
|
452
|
+
|
|
453
|
+
return {
|
|
454
|
+
${handlers.join("\n")}
|
|
455
|
+
};
|
|
456
|
+
},
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
export default plugin;
|
|
460
|
+
`;
|
|
461
|
+
return header + definition;
|
|
462
|
+
}
|
|
463
|
+
// ── Runtime: parse OUR bridge payload → normalized event ───────────────
|
|
464
|
+
/**
|
|
465
|
+
* `raw` is the payload OUR generated plugin posts (NOT a host-native shape):
|
|
466
|
+
* { toolName, toolInput, toolOutput?, isError?, sessionId, projectDir }
|
|
467
|
+
* so this maps straight through.
|
|
468
|
+
*/
|
|
469
|
+
parseEvent(event, raw) {
|
|
470
|
+
const input = raw ?? {};
|
|
471
|
+
const base = {
|
|
472
|
+
hostPlatform: HOST,
|
|
473
|
+
connectorId: "",
|
|
474
|
+
sessionId: typeof input.sessionId === "string" ? input.sessionId : "",
|
|
475
|
+
raw,
|
|
476
|
+
...typeof input.projectDir === "string" ? { projectDir: input.projectDir } : {}
|
|
477
|
+
};
|
|
478
|
+
switch (event) {
|
|
479
|
+
case "PreToolUse": {
|
|
480
|
+
const ev = {
|
|
481
|
+
...base,
|
|
482
|
+
toolName: input.toolName ?? "",
|
|
483
|
+
toolInput: input.toolInput ?? {}
|
|
484
|
+
};
|
|
485
|
+
return ev;
|
|
486
|
+
}
|
|
487
|
+
case "PostToolUse": {
|
|
488
|
+
const ev = {
|
|
489
|
+
...base,
|
|
490
|
+
toolName: input.toolName ?? "",
|
|
491
|
+
toolInput: input.toolInput ?? {},
|
|
492
|
+
...typeof input.toolOutput === "string" ? { toolOutput: input.toolOutput } : {},
|
|
493
|
+
...typeof input.isError === "boolean" ? { isError: input.isError } : {}
|
|
494
|
+
};
|
|
495
|
+
return ev;
|
|
496
|
+
}
|
|
497
|
+
case "SessionStart": {
|
|
498
|
+
const ev = { ...base, source: "startup" };
|
|
499
|
+
return ev;
|
|
500
|
+
}
|
|
501
|
+
default:
|
|
502
|
+
return { ...base, source: "startup" };
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// ── Runtime: normalized response → reply the generated bridge parses ───
|
|
506
|
+
/**
|
|
507
|
+
* Unlike json-stdio hosts (whose reply is the host's NATIVE control payload),
|
|
508
|
+
* OUR generated bridge consumes this stdout directly. So the reply body is the
|
|
509
|
+
* NORMALIZED HookResponse itself — the bridge JSON.parses it and reads
|
|
510
|
+
* decision / updatedInput / updatedOutput / additionalContext.
|
|
511
|
+
*/
|
|
512
|
+
formatReply(_event, response) {
|
|
513
|
+
return {
|
|
514
|
+
exitCode: 0,
|
|
515
|
+
stdout: JSON.stringify(response ?? { decision: "allow" })
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
// ── Diagnostics ──────────────────────────────────────────────────────────
|
|
519
|
+
getHealthChecks(ctx) {
|
|
520
|
+
const configPath = this.getServerConfigPath(ctx);
|
|
521
|
+
const pluginPath = this.getHookConfigPath(ctx);
|
|
522
|
+
const connectorId = ctx.connector.id;
|
|
523
|
+
const hasHooks = ctx.connector.hookEvents.length > 0;
|
|
524
|
+
return [
|
|
525
|
+
{
|
|
526
|
+
name: `${this.name}: ${CONFIG_FILE} present`,
|
|
527
|
+
check: () => existsSync(configPath) ? { status: "OK", detail: configPath } : { status: "FAIL", detail: `not found: ${configPath}` }
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: `${this.name}: server entry registered`,
|
|
531
|
+
check: () => {
|
|
532
|
+
if (!ctx.connector.server) {
|
|
533
|
+
return { status: "OK", detail: "no MCP server declared" };
|
|
534
|
+
}
|
|
535
|
+
const cfg = this.readJson(configPath);
|
|
536
|
+
const bucket = cfg?.[MCP_ROOT_KEY];
|
|
537
|
+
if (!cfg || !bucket) {
|
|
538
|
+
return { status: "FAIL", detail: `no ${MCP_ROOT_KEY} in ${configPath}` };
|
|
539
|
+
}
|
|
540
|
+
return connectorId in bucket ? { status: "OK", detail: `${MCP_ROOT_KEY}.${connectorId} present` } : {
|
|
541
|
+
status: "FAIL",
|
|
542
|
+
detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${configPath}`
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
name: `${this.name}: plugin module present`,
|
|
548
|
+
check: () => {
|
|
549
|
+
if (!hasHooks) return { status: "OK", detail: "no hooks declared" };
|
|
550
|
+
return existsSync(pluginPath) ? { status: "OK", detail: pluginPath } : { status: "FAIL", detail: `not found: ${pluginPath}` };
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
name: `${this.name}: plugin registered in ${PLUGIN_ARRAY_KEY}[]`,
|
|
555
|
+
check: () => {
|
|
556
|
+
if (!hasHooks) return { status: "OK", detail: "no hooks declared" };
|
|
557
|
+
const cfg = this.readJson(configPath);
|
|
558
|
+
const raw = cfg?.[PLUGIN_ARRAY_KEY];
|
|
559
|
+
const plugins = Array.isArray(raw) ? raw : void 0;
|
|
560
|
+
return plugins && plugins.includes(pluginPath) ? { status: "OK", detail: `${PLUGIN_ARRAY_KEY}[] includes module` } : {
|
|
561
|
+
status: "FAIL",
|
|
562
|
+
detail: `module not in ${PLUGIN_ARRAY_KEY}[] of ${configPath} (fork will not load it)`
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
];
|
|
567
|
+
}
|
|
568
|
+
/** Read a file, returning undefined on any error (idempotency compare). */
|
|
569
|
+
safeRead(path) {
|
|
570
|
+
try {
|
|
571
|
+
return readFileSync(path, "utf8");
|
|
572
|
+
} catch {
|
|
573
|
+
return void 0;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
function ensureDir(dir) {
|
|
578
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
579
|
+
}
|
|
580
|
+
var adapter = new KiloCliAdapter();
|
|
581
|
+
var kilo_cli_default = adapter;
|
|
582
|
+
export {
|
|
583
|
+
KiloCliAdapter,
|
|
584
|
+
adapter,
|
|
585
|
+
kilo_cli_default as default
|
|
586
|
+
};
|
|
587
|
+
//# sourceMappingURL=kilo-cli-EAQTHXUW.js.map
|