@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,622 @@
|
|
|
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
|
+
buildHomeBinHookCommand,
|
|
11
|
+
buildServeWrapperCommand,
|
|
12
|
+
isHomeBinHookCommand,
|
|
13
|
+
shouldWrapForTelemetry
|
|
14
|
+
} from "./chunk-MEH7GC7R.js";
|
|
15
|
+
import "./chunk-TRQKHP7D.js";
|
|
16
|
+
|
|
17
|
+
// src/adapters/copilot-cli/index.ts
|
|
18
|
+
import { existsSync } from "fs";
|
|
19
|
+
import { homedir } from "os";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
var HOST = "copilot-cli";
|
|
22
|
+
var MCP_ROOT_KEY = "mcpServers";
|
|
23
|
+
var COPILOT_HOOKS_VERSION = 1;
|
|
24
|
+
var CopilotCliAdapter = class extends BaseAdapter {
|
|
25
|
+
id = HOST;
|
|
26
|
+
name = "GitHub Copilot CLI";
|
|
27
|
+
paradigm = "json-stdio";
|
|
28
|
+
capabilities = {
|
|
29
|
+
// Copilot CLI delivers the full Claude-compatible lifecycle event set.
|
|
30
|
+
preToolUse: true,
|
|
31
|
+
postToolUse: true,
|
|
32
|
+
preCompact: true,
|
|
33
|
+
sessionStart: true,
|
|
34
|
+
sessionEnd: true,
|
|
35
|
+
userPromptSubmit: true,
|
|
36
|
+
stop: true,
|
|
37
|
+
notification: true,
|
|
38
|
+
// PreToolUse is fail-closed and can rewrite tool input (updatedInput); a
|
|
39
|
+
// PostToolUse hook cannot rewrite already-emitted tool output.
|
|
40
|
+
canModifyArgs: true,
|
|
41
|
+
canModifyOutput: false,
|
|
42
|
+
canInjectSessionContext: true,
|
|
43
|
+
transports: ["stdio", "http"],
|
|
44
|
+
// Content surfaces: Copilot CLI exposes skills + subagents, but has no
|
|
45
|
+
// prompt-file command surface, so commands stay false (inherits BaseAdapter
|
|
46
|
+
// skip/warn).
|
|
47
|
+
supportsCommands: false,
|
|
48
|
+
supportsSkills: true,
|
|
49
|
+
supportsSubagents: true
|
|
50
|
+
};
|
|
51
|
+
// ── Detection ────────────────────────────────────────────────────────────
|
|
52
|
+
detectInstalled(_projectDir) {
|
|
53
|
+
const userDir = join(homedir(), ".copilot");
|
|
54
|
+
const mcpConfig = join(userDir, "mcp-config.json");
|
|
55
|
+
const hooksDir = join(userDir, "hooks");
|
|
56
|
+
const installed = existsSync(userDir) || existsSync(mcpConfig) || existsSync(hooksDir);
|
|
57
|
+
return {
|
|
58
|
+
id: this.id,
|
|
59
|
+
name: this.name,
|
|
60
|
+
installed,
|
|
61
|
+
paradigm: this.paradigm,
|
|
62
|
+
capabilities: this.capabilities,
|
|
63
|
+
configPath: mcpConfig,
|
|
64
|
+
scope: "user",
|
|
65
|
+
reason: installed ? `found GitHub Copilot CLI config under ${userDir}` : `no GitHub Copilot CLI config at ${userDir}`,
|
|
66
|
+
confidence: installed ? "high" : "low"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// ── Native paths ─────────────────────────────────────────────────────────
|
|
70
|
+
/** Copilot CLI is user/global only — scope is ignored. */
|
|
71
|
+
getConfigDir(_ctx) {
|
|
72
|
+
return join(homedir(), ".copilot");
|
|
73
|
+
}
|
|
74
|
+
getServerConfigPath(ctx) {
|
|
75
|
+
return join(this.getConfigDir(ctx), "mcp-config.json");
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Copilot CLI discovers hooks from any `~/.copilot/hooks/*.json`. We write a
|
|
79
|
+
* single dedicated file so we never disturb the user's own hook files and
|
|
80
|
+
* uninstall is a clean, scoped operation.
|
|
81
|
+
*/
|
|
82
|
+
getHookConfigPath(ctx) {
|
|
83
|
+
return join(this.getConfigDir(ctx), "hooks", "agent-connector.json");
|
|
84
|
+
}
|
|
85
|
+
// ── MCP server install / uninstall ───────────────────────────────────────
|
|
86
|
+
installServer(ctx) {
|
|
87
|
+
const { connector } = ctx;
|
|
88
|
+
const override = connector.platforms[HOST]?.server;
|
|
89
|
+
if (!connector.server || override === false) {
|
|
90
|
+
return [
|
|
91
|
+
{
|
|
92
|
+
platform: this.id,
|
|
93
|
+
action: "skip",
|
|
94
|
+
detail: connector.server ? "server registration disabled for copilot-cli" : "connector declares no MCP server"
|
|
95
|
+
}
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
const server = override && typeof override === "object" ? { ...connector.server, ...override } : connector.server;
|
|
99
|
+
const serverPath = this.getServerConfigPath(ctx);
|
|
100
|
+
const entry = this.renderServerEntry(ctx, server);
|
|
101
|
+
return [
|
|
102
|
+
this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun)
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
uninstallServer(ctx) {
|
|
106
|
+
const serverPath = this.getServerConfigPath(ctx);
|
|
107
|
+
return [
|
|
108
|
+
this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun)
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
/** Render a normalized ServerDef into Copilot CLI's native mcpServers entry. */
|
|
112
|
+
renderServerEntry(ctx, server) {
|
|
113
|
+
const transport = server.transport;
|
|
114
|
+
const tools = this.renderTools(server);
|
|
115
|
+
if (transport === "stdio") {
|
|
116
|
+
let command = server.command ?? "";
|
|
117
|
+
let args = [...server.args ?? []];
|
|
118
|
+
if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
|
|
119
|
+
const wrapped = buildServeWrapperCommand(
|
|
120
|
+
ctx.homeBinPath,
|
|
121
|
+
ctx.connector.id,
|
|
122
|
+
command,
|
|
123
|
+
args,
|
|
124
|
+
ctx.scope,
|
|
125
|
+
this.id
|
|
126
|
+
);
|
|
127
|
+
command = wrapped.command;
|
|
128
|
+
args = wrapped.args;
|
|
129
|
+
}
|
|
130
|
+
const entry2 = {
|
|
131
|
+
type: "local",
|
|
132
|
+
command: resolveEnvRefsDeep(command),
|
|
133
|
+
tools
|
|
134
|
+
};
|
|
135
|
+
if (args.length > 0) entry2.args = args.map((a) => resolveEnvRefsDeep(a));
|
|
136
|
+
const env = this.renderEnv(server.env);
|
|
137
|
+
if (env) entry2.env = env;
|
|
138
|
+
if (server.cwd) entry2.cwd = resolveEnvRefsDeep(server.cwd);
|
|
139
|
+
return entry2;
|
|
140
|
+
}
|
|
141
|
+
const entry = {
|
|
142
|
+
type: "http",
|
|
143
|
+
url: resolveEnvRefsDeep(server.url ?? ""),
|
|
144
|
+
tools
|
|
145
|
+
};
|
|
146
|
+
const headers = this.renderEnv(server.headers);
|
|
147
|
+
if (headers) entry.headers = headers;
|
|
148
|
+
return entry;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Render env/header values. Copilot CLI is not documented to support native
|
|
152
|
+
* `${env:VAR}` interpolation in mcp-config.json, so refs resolve to literals
|
|
153
|
+
* at install time (the safe default for a no-native-interp host).
|
|
154
|
+
*/
|
|
155
|
+
renderEnv(env) {
|
|
156
|
+
if (!env || Object.keys(env).length === 0) return void 0;
|
|
157
|
+
return resolveEnvRefsDeep({ ...env });
|
|
158
|
+
}
|
|
159
|
+
/** Render the tool allow-list. Copilot CLI expects `tools` on every entry; default ["*"]. */
|
|
160
|
+
renderTools(server) {
|
|
161
|
+
const include = server.tools?.include;
|
|
162
|
+
return include && include.length > 0 ? [...include] : ["*"];
|
|
163
|
+
}
|
|
164
|
+
// ── Hook install / uninstall ─────────────────────────────────────────────
|
|
165
|
+
installHooks(ctx) {
|
|
166
|
+
const { connector } = ctx;
|
|
167
|
+
if (connector.platforms[HOST]?.hooks === false) {
|
|
168
|
+
return [
|
|
169
|
+
{ platform: this.id, action: "skip", detail: "hooks disabled for copilot-cli" }
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
if (connector.hookEvents.length === 0) {
|
|
173
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no hooks" }];
|
|
174
|
+
}
|
|
175
|
+
const hooksPath = this.getHookConfigPath(ctx);
|
|
176
|
+
const file = this.readJson(hooksPath) ?? {};
|
|
177
|
+
const hooks = file.hooks ??= {};
|
|
178
|
+
const changes = [];
|
|
179
|
+
let mutated = false;
|
|
180
|
+
for (const event of connector.hookEvents) {
|
|
181
|
+
const copilotEvent = event;
|
|
182
|
+
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
|
|
183
|
+
const matcher = connector.hooks[event]?.matcher ?? "";
|
|
184
|
+
const entry = {
|
|
185
|
+
matcher,
|
|
186
|
+
hooks: [{ type: "command", command }]
|
|
187
|
+
};
|
|
188
|
+
const bucket = hooks[copilotEvent] ??= [];
|
|
189
|
+
const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));
|
|
190
|
+
if (existingIdx >= 0) {
|
|
191
|
+
if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
|
|
192
|
+
changes.push({
|
|
193
|
+
platform: this.id,
|
|
194
|
+
action: "skip",
|
|
195
|
+
path: hooksPath,
|
|
196
|
+
detail: `hooks.${copilotEvent} already registered`
|
|
197
|
+
});
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
bucket[existingIdx] = entry;
|
|
201
|
+
changes.push({
|
|
202
|
+
platform: this.id,
|
|
203
|
+
action: "update",
|
|
204
|
+
path: hooksPath,
|
|
205
|
+
detail: `hooks.${copilotEvent}`
|
|
206
|
+
});
|
|
207
|
+
} else {
|
|
208
|
+
bucket.push(entry);
|
|
209
|
+
changes.push({
|
|
210
|
+
platform: this.id,
|
|
211
|
+
action: "create",
|
|
212
|
+
path: hooksPath,
|
|
213
|
+
detail: `hooks.${copilotEvent}`
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
mutated = true;
|
|
217
|
+
}
|
|
218
|
+
if (mutated) {
|
|
219
|
+
file.version = COPILOT_HOOKS_VERSION;
|
|
220
|
+
this.writeJson(hooksPath, file, ctx.dryRun);
|
|
221
|
+
}
|
|
222
|
+
return changes;
|
|
223
|
+
}
|
|
224
|
+
uninstallHooks(ctx) {
|
|
225
|
+
const hooksPath = this.getHookConfigPath(ctx);
|
|
226
|
+
const file = this.readJson(hooksPath);
|
|
227
|
+
const hooks = file?.hooks;
|
|
228
|
+
if (!file || !hooks) {
|
|
229
|
+
return [
|
|
230
|
+
{
|
|
231
|
+
platform: this.id,
|
|
232
|
+
action: "skip",
|
|
233
|
+
path: hooksPath,
|
|
234
|
+
detail: "no hooks section present"
|
|
235
|
+
}
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
const changes = [];
|
|
239
|
+
let mutated = false;
|
|
240
|
+
for (const copilotEvent of Object.keys(hooks)) {
|
|
241
|
+
const bucket = hooks[copilotEvent];
|
|
242
|
+
if (!Array.isArray(bucket)) continue;
|
|
243
|
+
const next = [];
|
|
244
|
+
let removed = 0;
|
|
245
|
+
for (const e of bucket) {
|
|
246
|
+
const innerBefore = e.hooks?.length ?? 0;
|
|
247
|
+
const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));
|
|
248
|
+
removed += innerBefore - inner.length;
|
|
249
|
+
if (inner.length > 0) next.push({ matcher: e.matcher ?? "", hooks: inner });
|
|
250
|
+
}
|
|
251
|
+
if (removed > 0) {
|
|
252
|
+
if (next.length > 0) hooks[copilotEvent] = next;
|
|
253
|
+
else delete hooks[copilotEvent];
|
|
254
|
+
changes.push({
|
|
255
|
+
platform: this.id,
|
|
256
|
+
action: "remove",
|
|
257
|
+
path: hooksPath,
|
|
258
|
+
detail: `hooks.${copilotEvent} (${removed})`
|
|
259
|
+
});
|
|
260
|
+
mutated = true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (mutated) this.writeJson(hooksPath, file, ctx.dryRun);
|
|
264
|
+
if (changes.length === 0) {
|
|
265
|
+
changes.push({
|
|
266
|
+
platform: this.id,
|
|
267
|
+
action: "skip",
|
|
268
|
+
path: hooksPath,
|
|
269
|
+
detail: "no matching hook entries"
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return changes;
|
|
273
|
+
}
|
|
274
|
+
entryHasOurCommand(entry, ctx) {
|
|
275
|
+
return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));
|
|
276
|
+
}
|
|
277
|
+
/** True when a hook command references our home binary AND this connector id
|
|
278
|
+
* (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */
|
|
279
|
+
isOurCommand(command, ctx) {
|
|
280
|
+
return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
|
|
281
|
+
}
|
|
282
|
+
// ── Content surfaces: skills / subagents ─────────────────────────────────
|
|
283
|
+
// CONTENT-ONLY: pure native-file writers. No runtime dispatch, no home-bin
|
|
284
|
+
// pointer, no telemetry wrap. Each method is idempotent (byte-identical →
|
|
285
|
+
// skip) via BaseAdapter.writeContentFile and reversible via removeContentFile.
|
|
286
|
+
// Honors platforms["copilot-cli"] per-surface false to skip. Commands are
|
|
287
|
+
// unsupported here — they inherit the BaseAdapter skip/warn default.
|
|
288
|
+
//
|
|
289
|
+
// Path scoping: user scope lives under ~/.copilot (getConfigDir); project
|
|
290
|
+
// scope lives under the shared <projectDir>/.github tree (the same files
|
|
291
|
+
// vscode-copilot / jetbrains-copilot would write). We write identical content
|
|
292
|
+
// and on uninstall remove only the files this connector wrote.
|
|
293
|
+
/** Root dir for content surfaces: ~/.copilot (user) or <projectDir>/.github (project). */
|
|
294
|
+
contentDir(ctx) {
|
|
295
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".github") : this.getConfigDir(ctx);
|
|
296
|
+
}
|
|
297
|
+
skillsDir(ctx) {
|
|
298
|
+
return join(this.contentDir(ctx), "skills");
|
|
299
|
+
}
|
|
300
|
+
agentsDir(ctx) {
|
|
301
|
+
return join(this.contentDir(ctx), "agents");
|
|
302
|
+
}
|
|
303
|
+
/** Native skill dir: <contentDir>/skills/<name>. */
|
|
304
|
+
skillDir(ctx, name) {
|
|
305
|
+
return join(this.skillsDir(ctx), name);
|
|
306
|
+
}
|
|
307
|
+
/** Native subagent file path: <contentDir>/agents/<name>.agent.md. */
|
|
308
|
+
subagentPath(ctx, name) {
|
|
309
|
+
return join(this.agentsDir(ctx), `${name}.agent.md`);
|
|
310
|
+
}
|
|
311
|
+
// ── Skills ────────────────────────────────────────────────────────────────
|
|
312
|
+
installSkills(ctx) {
|
|
313
|
+
const { connector } = ctx;
|
|
314
|
+
if (connector.platforms[HOST]?.skills === false) {
|
|
315
|
+
return [{ platform: this.id, action: "skip", detail: "skills disabled for copilot-cli" }];
|
|
316
|
+
}
|
|
317
|
+
if (connector.skills.length === 0) {
|
|
318
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
319
|
+
}
|
|
320
|
+
const changes = [];
|
|
321
|
+
for (const skill of connector.skills) {
|
|
322
|
+
const dir = this.skillDir(ctx, skill.name);
|
|
323
|
+
changes.push(
|
|
324
|
+
this.writeContentFile(join(dir, "SKILL.md"), this.renderSkill(skill), ctx.dryRun)
|
|
325
|
+
);
|
|
326
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
327
|
+
const target = this.resolveWithin(dir, rel);
|
|
328
|
+
if (target === null) {
|
|
329
|
+
changes.push({
|
|
330
|
+
platform: this.id,
|
|
331
|
+
action: "warn",
|
|
332
|
+
detail: `skill resource "${rel}" escapes the skill dir; skipped`
|
|
333
|
+
});
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
changes.push(this.writeContentFile(target, contents, ctx.dryRun));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return changes;
|
|
340
|
+
}
|
|
341
|
+
uninstallSkills(ctx) {
|
|
342
|
+
const { connector } = ctx;
|
|
343
|
+
if (connector.skills.length === 0) {
|
|
344
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
345
|
+
}
|
|
346
|
+
const changes = [];
|
|
347
|
+
for (const skill of connector.skills) {
|
|
348
|
+
const dir = this.skillDir(ctx, skill.name);
|
|
349
|
+
changes.push(this.removeContentFile(join(dir, "SKILL.md"), ctx.dryRun));
|
|
350
|
+
for (const rel of Object.keys(skill.resources ?? {})) {
|
|
351
|
+
const target = this.resolveWithin(dir, rel);
|
|
352
|
+
if (target === null) continue;
|
|
353
|
+
changes.push(this.removeContentFile(target, ctx.dryRun));
|
|
354
|
+
}
|
|
355
|
+
changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));
|
|
356
|
+
}
|
|
357
|
+
return changes;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Render a skill's SKILL.md: frontmatter (name, description + optional model,
|
|
361
|
+
* allowed-tools, disable-model-invocation) + body. Uniform Agent Skills shape
|
|
362
|
+
* shared across every skill-supporting connector.
|
|
363
|
+
*/
|
|
364
|
+
renderSkill(skill) {
|
|
365
|
+
const frontmatter = {
|
|
366
|
+
name: skill.name,
|
|
367
|
+
description: skill.description
|
|
368
|
+
};
|
|
369
|
+
if (skill.model !== void 0) frontmatter.model = skill.model;
|
|
370
|
+
const allow = skill.tools?.allow;
|
|
371
|
+
if (allow && allow.length > 0) frontmatter["allowed-tools"] = allow.join(", ");
|
|
372
|
+
if (skill.disableModelInvocation !== void 0) {
|
|
373
|
+
frontmatter["disable-model-invocation"] = skill.disableModelInvocation;
|
|
374
|
+
}
|
|
375
|
+
if (skill.extra) Object.assign(frontmatter, skill.extra);
|
|
376
|
+
return this.renderFrontmatterMd(frontmatter, skill.body);
|
|
377
|
+
}
|
|
378
|
+
// ── Subagents ───────────────────────────────────────────────────────────────
|
|
379
|
+
installSubagents(ctx) {
|
|
380
|
+
const { connector } = ctx;
|
|
381
|
+
if (connector.platforms[HOST]?.subagents === false) {
|
|
382
|
+
return [{ platform: this.id, action: "skip", detail: "subagents disabled for copilot-cli" }];
|
|
383
|
+
}
|
|
384
|
+
if (connector.subagents.length === 0) {
|
|
385
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no subagents" }];
|
|
386
|
+
}
|
|
387
|
+
return connector.subagents.map(
|
|
388
|
+
(agent) => this.writeContentFile(
|
|
389
|
+
this.subagentPath(ctx, agent.name),
|
|
390
|
+
this.renderSubagent(agent),
|
|
391
|
+
ctx.dryRun
|
|
392
|
+
)
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
uninstallSubagents(ctx) {
|
|
396
|
+
const { connector } = ctx;
|
|
397
|
+
if (connector.subagents.length === 0) {
|
|
398
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no subagents" }];
|
|
399
|
+
}
|
|
400
|
+
return connector.subagents.map(
|
|
401
|
+
(agent) => this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun)
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
/** Render a subagent to md+frontmatter (name, description, tools, model) + prompt body. */
|
|
405
|
+
renderSubagent(agent) {
|
|
406
|
+
const frontmatter = {
|
|
407
|
+
name: agent.name,
|
|
408
|
+
description: agent.description
|
|
409
|
+
};
|
|
410
|
+
const allow = agent.tools?.allow;
|
|
411
|
+
if (allow && allow.length > 0) frontmatter.tools = allow.join(", ");
|
|
412
|
+
if (agent.model !== void 0) frontmatter.model = agent.model;
|
|
413
|
+
if (agent.extra) Object.assign(frontmatter, agent.extra);
|
|
414
|
+
return this.renderFrontmatterMd(frontmatter, agent.prompt);
|
|
415
|
+
}
|
|
416
|
+
// ── Diagnostics ──────────────────────────────────────────────────────────
|
|
417
|
+
getHealthChecks(ctx) {
|
|
418
|
+
const mcpPath = this.getServerConfigPath(ctx);
|
|
419
|
+
const hooksPath = this.getHookConfigPath(ctx);
|
|
420
|
+
const connectorId = ctx.connector.id;
|
|
421
|
+
const homeBin = ctx.homeBinPath;
|
|
422
|
+
const hookEvents = ctx.connector.hookEvents;
|
|
423
|
+
const checks = [
|
|
424
|
+
{
|
|
425
|
+
name: `${this.name}: mcp-config.json present`,
|
|
426
|
+
check: () => existsSync(mcpPath) ? { status: "OK", detail: mcpPath } : { status: "FAIL", detail: `not found: ${mcpPath}` }
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
name: `${this.name}: hook command registered`,
|
|
430
|
+
check: () => {
|
|
431
|
+
if (hookEvents.length === 0) {
|
|
432
|
+
return { status: "OK", detail: "no hooks declared" };
|
|
433
|
+
}
|
|
434
|
+
const file = this.readJson(hooksPath);
|
|
435
|
+
if (!file) return { status: "FAIL", detail: `cannot read ${hooksPath}` };
|
|
436
|
+
const hooks = file.hooks ?? {};
|
|
437
|
+
const registered = Object.values(hooks).some(
|
|
438
|
+
(entries) => (entries ?? []).some(
|
|
439
|
+
(e) => (e.hooks ?? []).some(
|
|
440
|
+
(h) => isHomeBinHookCommand(h.command, homeBin, connectorId)
|
|
441
|
+
)
|
|
442
|
+
)
|
|
443
|
+
);
|
|
444
|
+
return registered ? { status: "OK", detail: "hook command present" } : { status: "FAIL", detail: `no hook for ${connectorId} in ${hooksPath}` };
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
];
|
|
448
|
+
for (const skill of ctx.connector.skills) {
|
|
449
|
+
const p = join(this.skillDir(ctx, skill.name), "SKILL.md");
|
|
450
|
+
checks.push({
|
|
451
|
+
name: `${this.name}: skill ${skill.name} present`,
|
|
452
|
+
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
for (const agent of ctx.connector.subagents) {
|
|
456
|
+
const p = this.subagentPath(ctx, agent.name);
|
|
457
|
+
checks.push({
|
|
458
|
+
name: `${this.name}: subagent ${agent.name} present`,
|
|
459
|
+
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return checks;
|
|
463
|
+
}
|
|
464
|
+
// ── Runtime: parse Copilot CLI stdin JSON → normalized event ─────────────
|
|
465
|
+
parseEvent(event, raw) {
|
|
466
|
+
const input = raw ?? {};
|
|
467
|
+
const connectorId = typeof input.connector === "string" ? input.connector : "";
|
|
468
|
+
const sessionId = extractSessionId(input);
|
|
469
|
+
const projectDir = typeof input.cwd === "string" ? input.cwd : void 0;
|
|
470
|
+
const base = {
|
|
471
|
+
hostPlatform: HOST,
|
|
472
|
+
connectorId,
|
|
473
|
+
sessionId,
|
|
474
|
+
raw,
|
|
475
|
+
...projectDir !== void 0 ? { projectDir } : {}
|
|
476
|
+
};
|
|
477
|
+
switch (event) {
|
|
478
|
+
case "PreToolUse": {
|
|
479
|
+
const ev = {
|
|
480
|
+
...base,
|
|
481
|
+
toolName: input.tool_name ?? "",
|
|
482
|
+
toolInput: input.tool_input ?? {}
|
|
483
|
+
};
|
|
484
|
+
return ev;
|
|
485
|
+
}
|
|
486
|
+
case "PostToolUse": {
|
|
487
|
+
const toolOutput = toolResponseToString(input.tool_response);
|
|
488
|
+
const ev = {
|
|
489
|
+
...base,
|
|
490
|
+
toolName: input.tool_name ?? "",
|
|
491
|
+
toolInput: input.tool_input ?? {},
|
|
492
|
+
...toolOutput !== void 0 ? { toolOutput } : {}
|
|
493
|
+
};
|
|
494
|
+
return ev;
|
|
495
|
+
}
|
|
496
|
+
case "SessionStart": {
|
|
497
|
+
const ev = {
|
|
498
|
+
...base,
|
|
499
|
+
source: normalizeSessionSource(input.source)
|
|
500
|
+
};
|
|
501
|
+
return ev;
|
|
502
|
+
}
|
|
503
|
+
case "SessionEnd": {
|
|
504
|
+
const ev = {
|
|
505
|
+
...base,
|
|
506
|
+
...typeof input.reason === "string" ? { reason: input.reason } : {}
|
|
507
|
+
};
|
|
508
|
+
return ev;
|
|
509
|
+
}
|
|
510
|
+
case "UserPromptSubmit": {
|
|
511
|
+
const ev = {
|
|
512
|
+
...base,
|
|
513
|
+
prompt: typeof input.prompt === "string" ? input.prompt : ""
|
|
514
|
+
};
|
|
515
|
+
return ev;
|
|
516
|
+
}
|
|
517
|
+
case "PreCompact": {
|
|
518
|
+
const ev = {
|
|
519
|
+
...base,
|
|
520
|
+
...input.trigger === "auto" || input.trigger === "manual" ? { trigger: input.trigger } : {}
|
|
521
|
+
};
|
|
522
|
+
return ev;
|
|
523
|
+
}
|
|
524
|
+
case "Stop": {
|
|
525
|
+
const ev = {
|
|
526
|
+
...base,
|
|
527
|
+
...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
|
|
528
|
+
};
|
|
529
|
+
return ev;
|
|
530
|
+
}
|
|
531
|
+
case "Notification": {
|
|
532
|
+
const ev = {
|
|
533
|
+
...base,
|
|
534
|
+
message: typeof input.message === "string" ? input.message : ""
|
|
535
|
+
};
|
|
536
|
+
return ev;
|
|
537
|
+
}
|
|
538
|
+
default: {
|
|
539
|
+
const _never = event;
|
|
540
|
+
throw new Error(`unsupported copilot-cli hook event: ${String(_never)}`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
// ── Runtime: normalized response → Copilot CLI native hook reply ─────────
|
|
545
|
+
formatReply(event, response) {
|
|
546
|
+
const hookEventName = event;
|
|
547
|
+
const decision = response.decision ?? "allow";
|
|
548
|
+
if (decision === "deny") {
|
|
549
|
+
return this.stdout({
|
|
550
|
+
hookSpecificOutput: {
|
|
551
|
+
hookEventName,
|
|
552
|
+
permissionDecision: "deny",
|
|
553
|
+
permissionDecisionReason: response.reason ?? "Blocked by hook"
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
if (decision === "ask") {
|
|
558
|
+
return this.stdout({
|
|
559
|
+
hookSpecificOutput: {
|
|
560
|
+
hookEventName,
|
|
561
|
+
permissionDecision: "ask",
|
|
562
|
+
permissionDecisionReason: response.reason ?? "Confirmation required by hook"
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
if (decision === "modify") {
|
|
567
|
+
if (event === "PreToolUse" && response.updatedInput) {
|
|
568
|
+
return this.stdout({
|
|
569
|
+
hookSpecificOutput: { hookEventName, updatedInput: response.updatedInput }
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (decision === "context" && response.additionalContext) {
|
|
574
|
+
return this.stdout({
|
|
575
|
+
hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext }
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
return { exitCode: 0 };
|
|
579
|
+
}
|
|
580
|
+
stdout(payload) {
|
|
581
|
+
return { exitCode: 0, stdout: JSON.stringify(payload) };
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
function extractSessionId(input) {
|
|
585
|
+
if (typeof input.transcript_path === "string") {
|
|
586
|
+
const m = input.transcript_path.match(/([a-f0-9-]{36})\.jsonl$/);
|
|
587
|
+
if (m && m[1]) return m[1];
|
|
588
|
+
}
|
|
589
|
+
if (typeof input.session_id === "string" && input.session_id !== "") {
|
|
590
|
+
return input.session_id;
|
|
591
|
+
}
|
|
592
|
+
return "";
|
|
593
|
+
}
|
|
594
|
+
function toolResponseToString(value) {
|
|
595
|
+
if (value == null) return void 0;
|
|
596
|
+
if (typeof value === "string") return value;
|
|
597
|
+
try {
|
|
598
|
+
return JSON.stringify(value);
|
|
599
|
+
} catch {
|
|
600
|
+
return String(value);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function normalizeSessionSource(source) {
|
|
604
|
+
switch (source) {
|
|
605
|
+
case "compact":
|
|
606
|
+
return "compact";
|
|
607
|
+
case "resume":
|
|
608
|
+
return "resume";
|
|
609
|
+
case "clear":
|
|
610
|
+
return "clear";
|
|
611
|
+
default:
|
|
612
|
+
return "startup";
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
var adapter = new CopilotCliAdapter();
|
|
616
|
+
var copilot_cli_default = adapter;
|
|
617
|
+
export {
|
|
618
|
+
CopilotCliAdapter,
|
|
619
|
+
adapter,
|
|
620
|
+
copilot_cli_default as default
|
|
621
|
+
};
|
|
622
|
+
//# sourceMappingURL=copilot-cli-MTCGHZ2T.js.map
|