@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,633 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
BaseAdapter
|
|
4
|
+
} from "./chunk-TIIP3RG2.js";
|
|
5
|
+
import "./chunk-7L6ITC4T.js";
|
|
6
|
+
import {
|
|
7
|
+
buildHomeBinHookCommand,
|
|
8
|
+
isHomeBinHookCommand
|
|
9
|
+
} from "./chunk-MEH7GC7R.js";
|
|
10
|
+
import "./chunk-TRQKHP7D.js";
|
|
11
|
+
|
|
12
|
+
// src/adapters/jetbrains-copilot/index.ts
|
|
13
|
+
import { existsSync, rmSync } from "fs";
|
|
14
|
+
import { dirname, join } from "path";
|
|
15
|
+
var HOST = "jetbrains-copilot";
|
|
16
|
+
var JETBRAINS_HOOKS_VERSION = 1;
|
|
17
|
+
var EVENT_MAP = {
|
|
18
|
+
PreToolUse: "PreToolUse",
|
|
19
|
+
PostToolUse: "PostToolUse",
|
|
20
|
+
PreCompact: "PreCompact",
|
|
21
|
+
SessionStart: "SessionStart"
|
|
22
|
+
};
|
|
23
|
+
var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
24
|
+
id = HOST;
|
|
25
|
+
name = "JetBrains Copilot";
|
|
26
|
+
paradigm = "json-stdio";
|
|
27
|
+
capabilities = {
|
|
28
|
+
// JetBrains Copilot's Preview hooks runtime delivers Pre/PostToolUse,
|
|
29
|
+
// PreCompact, and SessionStart (the four events its schema documents) —
|
|
30
|
+
// same surface as VS Code Copilot.
|
|
31
|
+
preToolUse: true,
|
|
32
|
+
postToolUse: true,
|
|
33
|
+
preCompact: true,
|
|
34
|
+
sessionStart: true,
|
|
35
|
+
sessionEnd: false,
|
|
36
|
+
userPromptSubmit: false,
|
|
37
|
+
stop: false,
|
|
38
|
+
notification: false,
|
|
39
|
+
// Per the JetBrains spec this host is deny/ask-only: a PreToolUse hook
|
|
40
|
+
// CANNOT rewrite tool input, and PostToolUse cannot rewrite tool output.
|
|
41
|
+
canModifyArgs: false,
|
|
42
|
+
canModifyOutput: false,
|
|
43
|
+
canInjectSessionContext: true,
|
|
44
|
+
// MCP is managed via the IDE Settings UI; the only transport that surfaces
|
|
45
|
+
// there is a local stdio server.
|
|
46
|
+
transports: ["stdio"],
|
|
47
|
+
// Content surfaces: JetBrains Copilot consumes the GitHub Copilot .github/
|
|
48
|
+
// files (it has no distinct authoring location), so it is an ALIAS of the
|
|
49
|
+
// vscode-copilot writer for prompt files and Agent Skills. It has no native
|
|
50
|
+
// subagent/chat-mode surface, so subagents stay unsupported (BaseAdapter
|
|
51
|
+
// returns the skip/warn default).
|
|
52
|
+
supportsCommands: true,
|
|
53
|
+
supportsSkills: true,
|
|
54
|
+
supportsSubagents: false
|
|
55
|
+
};
|
|
56
|
+
// ── Detection ────────────────────────────────────────────────────────────
|
|
57
|
+
detectInstalled(projectDir) {
|
|
58
|
+
const githubDir = join(projectDir, ".github");
|
|
59
|
+
const hooksDir = join(githubDir, "hooks");
|
|
60
|
+
const installed = existsSync(hooksDir) || existsSync(githubDir);
|
|
61
|
+
const configPath = hooksDir;
|
|
62
|
+
return {
|
|
63
|
+
id: this.id,
|
|
64
|
+
name: this.name,
|
|
65
|
+
installed,
|
|
66
|
+
paradigm: this.paradigm,
|
|
67
|
+
capabilities: this.capabilities,
|
|
68
|
+
configPath,
|
|
69
|
+
scope: "project",
|
|
70
|
+
reason: installed ? `found JetBrains Copilot hooks tree at ${hooksDir}` : `no JetBrains Copilot hooks tree at ${hooksDir}`,
|
|
71
|
+
confidence: installed ? "medium" : "low"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// ── Native paths ─────────────────────────────────────────────────────────
|
|
75
|
+
/** Hooks live under the workspace .github tree for both scopes. */
|
|
76
|
+
getConfigDir(ctx) {
|
|
77
|
+
return join(ctx.projectDir, ".github");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* MCP server registration has NO writable file on JetBrains — the IDE owns it
|
|
81
|
+
* behind the Settings UI. We still return a stable path (the hooks file) so the
|
|
82
|
+
* base-adapter `doctor`/`backupSettings` helpers have a sensible target rather
|
|
83
|
+
* than a nonexistent/bogus MCP path. `installServer` never writes here.
|
|
84
|
+
*/
|
|
85
|
+
getServerConfigPath(ctx) {
|
|
86
|
+
return this.getHookConfigPath(ctx);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Hook registration lives in the workspace-discovered .github/hooks tree, which
|
|
90
|
+
* JetBrains Copilot scans for *.json hook files. We write one file per connector
|
|
91
|
+
* so installs/uninstalls never clobber another connector's hooks. Anchored on
|
|
92
|
+
* projectDir for both scopes — .github/hooks is a workspace concept (there is no
|
|
93
|
+
* user-profile equivalent in the Copilot hooks schema).
|
|
94
|
+
*/
|
|
95
|
+
getHookConfigPath(ctx) {
|
|
96
|
+
return join(ctx.projectDir, ".github", "hooks", `${ctx.connector.id}.json`);
|
|
97
|
+
}
|
|
98
|
+
// ── MCP server install / uninstall ───────────────────────────────────────
|
|
99
|
+
/**
|
|
100
|
+
* JetBrains MCP registration is UI-only. We never write a file: a bogus file is
|
|
101
|
+
* ignored at best and corrupts real UI-managed state at worst. Emit a "warn"
|
|
102
|
+
* ChangeRecord that tells the user exactly where to add the server by hand.
|
|
103
|
+
*/
|
|
104
|
+
installServer(ctx) {
|
|
105
|
+
const { connector } = ctx;
|
|
106
|
+
const override = connector.platforms[HOST]?.server;
|
|
107
|
+
if (!connector.server || override === false) {
|
|
108
|
+
return [
|
|
109
|
+
{
|
|
110
|
+
platform: this.id,
|
|
111
|
+
action: "skip",
|
|
112
|
+
detail: connector.server ? "server registration disabled for jetbrains-copilot" : "connector declares no MCP server"
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
platform: this.id,
|
|
119
|
+
action: "warn",
|
|
120
|
+
detail: `JetBrains Copilot manages MCP servers via the IDE Settings UI \u2014 add "${connector.id}" manually under Settings > Tools > GitHub Copilot > MCP > Configure (no file is written here).`
|
|
121
|
+
}
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Nothing was written for the MCP server, so there is nothing to remove. Mirror
|
|
126
|
+
* the install-time guidance as a "warn" so an uninstall report is honest about
|
|
127
|
+
* the UI-managed entry the user may still want to remove by hand.
|
|
128
|
+
*/
|
|
129
|
+
uninstallServer(ctx) {
|
|
130
|
+
const { connector } = ctx;
|
|
131
|
+
if (!connector.server || connector.platforms[HOST]?.server === false) {
|
|
132
|
+
return [
|
|
133
|
+
{
|
|
134
|
+
platform: this.id,
|
|
135
|
+
action: "skip",
|
|
136
|
+
detail: "no MCP server was registered for jetbrains-copilot"
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
{
|
|
142
|
+
platform: this.id,
|
|
143
|
+
action: "warn",
|
|
144
|
+
detail: `JetBrains Copilot MCP servers are UI-managed \u2014 if "${connector.id}" was added manually, remove it under Settings > Tools > GitHub Copilot > MCP.`
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
// ── Hook install / uninstall ─────────────────────────────────────────────
|
|
149
|
+
installHooks(ctx) {
|
|
150
|
+
const { connector } = ctx;
|
|
151
|
+
if (connector.platforms[HOST]?.hooks === false) {
|
|
152
|
+
return [
|
|
153
|
+
{ platform: this.id, action: "skip", detail: "hooks disabled for jetbrains-copilot" }
|
|
154
|
+
];
|
|
155
|
+
}
|
|
156
|
+
if (connector.hookEvents.length === 0) {
|
|
157
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no hooks" }];
|
|
158
|
+
}
|
|
159
|
+
const hooksPath = this.getHookConfigPath(ctx);
|
|
160
|
+
const file = this.readJson(hooksPath) ?? {};
|
|
161
|
+
const hooks = file.hooks ??= {};
|
|
162
|
+
const changes = [];
|
|
163
|
+
let mutated = false;
|
|
164
|
+
for (const event of connector.hookEvents) {
|
|
165
|
+
const jetbrainsEvent = EVENT_MAP[event];
|
|
166
|
+
if (!jetbrainsEvent) {
|
|
167
|
+
changes.push({
|
|
168
|
+
platform: this.id,
|
|
169
|
+
action: "warn",
|
|
170
|
+
path: hooksPath,
|
|
171
|
+
detail: `${event} has no JetBrains Copilot hook equivalent \u2014 skipped`
|
|
172
|
+
});
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
|
|
176
|
+
const entry = { type: "command", command };
|
|
177
|
+
const bucket = hooks[jetbrainsEvent] ??= [];
|
|
178
|
+
const existingIdx = bucket.findIndex((e) => this.isOurCommand(e.command, ctx));
|
|
179
|
+
if (existingIdx >= 0) {
|
|
180
|
+
if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
|
|
181
|
+
changes.push({
|
|
182
|
+
platform: this.id,
|
|
183
|
+
action: "skip",
|
|
184
|
+
path: hooksPath,
|
|
185
|
+
detail: `hooks.${jetbrainsEvent} already registered`
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
bucket[existingIdx] = entry;
|
|
190
|
+
changes.push({
|
|
191
|
+
platform: this.id,
|
|
192
|
+
action: "update",
|
|
193
|
+
path: hooksPath,
|
|
194
|
+
detail: `hooks.${jetbrainsEvent}`
|
|
195
|
+
});
|
|
196
|
+
} else {
|
|
197
|
+
bucket.push(entry);
|
|
198
|
+
changes.push({
|
|
199
|
+
platform: this.id,
|
|
200
|
+
action: "create",
|
|
201
|
+
path: hooksPath,
|
|
202
|
+
detail: `hooks.${jetbrainsEvent}`
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
mutated = true;
|
|
206
|
+
}
|
|
207
|
+
if (mutated) {
|
|
208
|
+
file.version = JETBRAINS_HOOKS_VERSION;
|
|
209
|
+
this.writeJson(hooksPath, file, ctx.dryRun);
|
|
210
|
+
}
|
|
211
|
+
return changes;
|
|
212
|
+
}
|
|
213
|
+
uninstallHooks(ctx) {
|
|
214
|
+
const hooksPath = this.getHookConfigPath(ctx);
|
|
215
|
+
const file = this.readJson(hooksPath);
|
|
216
|
+
const hooks = file?.hooks;
|
|
217
|
+
if (!file || !hooks) {
|
|
218
|
+
return [
|
|
219
|
+
{
|
|
220
|
+
platform: this.id,
|
|
221
|
+
action: "skip",
|
|
222
|
+
path: hooksPath,
|
|
223
|
+
detail: "no hooks section present"
|
|
224
|
+
}
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
const changes = [];
|
|
228
|
+
let mutated = false;
|
|
229
|
+
for (const jetbrainsEvent of Object.keys(hooks)) {
|
|
230
|
+
const bucket = hooks[jetbrainsEvent];
|
|
231
|
+
if (!Array.isArray(bucket)) continue;
|
|
232
|
+
const before = bucket.length;
|
|
233
|
+
const next = bucket.filter((e) => !this.isOurCommand(e.command, ctx));
|
|
234
|
+
const removed = before - next.length;
|
|
235
|
+
if (removed > 0) {
|
|
236
|
+
if (next.length > 0) hooks[jetbrainsEvent] = next;
|
|
237
|
+
else delete hooks[jetbrainsEvent];
|
|
238
|
+
changes.push({
|
|
239
|
+
platform: this.id,
|
|
240
|
+
action: "remove",
|
|
241
|
+
path: hooksPath,
|
|
242
|
+
detail: `hooks.${jetbrainsEvent} (${removed})`
|
|
243
|
+
});
|
|
244
|
+
mutated = true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (mutated) {
|
|
248
|
+
if (Object.keys(hooks).length === 0) {
|
|
249
|
+
if (!ctx.dryRun) rmSync(hooksPath, { force: true });
|
|
250
|
+
changes.push({
|
|
251
|
+
platform: this.id,
|
|
252
|
+
action: "remove",
|
|
253
|
+
path: hooksPath,
|
|
254
|
+
detail: "removed empty connector hooks file"
|
|
255
|
+
});
|
|
256
|
+
changes.push(this.removeDirIfEmpty(dirname(hooksPath), ctx.dryRun));
|
|
257
|
+
} else {
|
|
258
|
+
this.writeJson(hooksPath, file, ctx.dryRun);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (changes.length === 0) {
|
|
262
|
+
changes.push({
|
|
263
|
+
platform: this.id,
|
|
264
|
+
action: "skip",
|
|
265
|
+
path: hooksPath,
|
|
266
|
+
detail: "no matching hook entries"
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return changes;
|
|
270
|
+
}
|
|
271
|
+
/** True when a hook command references our home binary AND this connector id
|
|
272
|
+
* (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */
|
|
273
|
+
isOurCommand(command, ctx) {
|
|
274
|
+
return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
|
|
275
|
+
}
|
|
276
|
+
// ── Content surfaces: commands / skills ──────────────────────────────────
|
|
277
|
+
// CONTENT-ONLY: pure native-file writers under the workspace .github/ tree
|
|
278
|
+
// ({prompts,skills}). No runtime dispatch, no home-bin pointer, no telemetry
|
|
279
|
+
// wrap. Each method is idempotent (byte-identical → skip) via
|
|
280
|
+
// BaseAdapter.writeContentFile and reversible via removeContentFile. Honors
|
|
281
|
+
// platforms["jetbrains-copilot"] per-surface false to skip.
|
|
282
|
+
//
|
|
283
|
+
// ALIAS of vscode-copilot: JetBrains consumes the GitHub Copilot .github/
|
|
284
|
+
// files and has no distinct authoring location, so the rendered content +
|
|
285
|
+
// paths here are IDENTICAL to the vscode-copilot writer.
|
|
286
|
+
//
|
|
287
|
+
// SHARED .github TREE: vscode-copilot, copilot-cli, and jetbrains-copilot all
|
|
288
|
+
// write under the SAME project <projectDir>/.github tree. The rendered content
|
|
289
|
+
// is identical and idempotent across those connectors, and uninstall here only
|
|
290
|
+
// removes the files THIS connector declared — never another writer's files.
|
|
291
|
+
//
|
|
292
|
+
// SCOPE NOTE: .github is a workspace concept and this adapter is project-
|
|
293
|
+
// scoped (no user-profile .github authoring location exists in the Copilot
|
|
294
|
+
// prompt/skill discovery), so the content root is always the project .github
|
|
295
|
+
// tree — the same dir getConfigDir already anchors on.
|
|
296
|
+
/** Root of the content tree — the project .github tree (see getConfigDir). */
|
|
297
|
+
contentRootDir(ctx) {
|
|
298
|
+
return this.getConfigDir(ctx);
|
|
299
|
+
}
|
|
300
|
+
promptsDir(ctx) {
|
|
301
|
+
return join(this.contentRootDir(ctx), "prompts");
|
|
302
|
+
}
|
|
303
|
+
skillsDir(ctx) {
|
|
304
|
+
return join(this.contentRootDir(ctx), "skills");
|
|
305
|
+
}
|
|
306
|
+
/** Native command file path: <ghDir>/prompts/<name>.prompt.md. */
|
|
307
|
+
commandPath(ctx, name) {
|
|
308
|
+
return join(this.promptsDir(ctx), `${name}.prompt.md`);
|
|
309
|
+
}
|
|
310
|
+
/** Native skill dir: <ghDir>/skills/<name>. */
|
|
311
|
+
skillDir(ctx, name) {
|
|
312
|
+
return join(this.skillsDir(ctx), name);
|
|
313
|
+
}
|
|
314
|
+
// ── Commands ──────────────────────────────────────────────────────────────
|
|
315
|
+
installCommands(ctx) {
|
|
316
|
+
const { connector } = ctx;
|
|
317
|
+
if (connector.platforms[HOST]?.commands === false) {
|
|
318
|
+
return [{ platform: this.id, action: "skip", detail: "commands disabled for jetbrains-copilot" }];
|
|
319
|
+
}
|
|
320
|
+
if (connector.commands.length === 0) {
|
|
321
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
|
|
322
|
+
}
|
|
323
|
+
return connector.commands.map(
|
|
324
|
+
(cmd) => this.writeContentFile(
|
|
325
|
+
this.commandPath(ctx, cmd.name),
|
|
326
|
+
this.renderCommand(cmd),
|
|
327
|
+
ctx.dryRun
|
|
328
|
+
)
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
uninstallCommands(ctx) {
|
|
332
|
+
const { connector } = ctx;
|
|
333
|
+
if (connector.commands.length === 0) {
|
|
334
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
|
|
335
|
+
}
|
|
336
|
+
return connector.commands.map(
|
|
337
|
+
(cmd) => this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun)
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
/** Render a Copilot prompt file: md+frontmatter(description, tools, model, argument-hint). */
|
|
341
|
+
renderCommand(cmd) {
|
|
342
|
+
const frontmatter = {};
|
|
343
|
+
if (cmd.description !== void 0) frontmatter.description = cmd.description;
|
|
344
|
+
const allow = cmd.tools?.allow;
|
|
345
|
+
if (allow && allow.length > 0) frontmatter.tools = [...allow];
|
|
346
|
+
if (cmd.model !== void 0) frontmatter.model = cmd.model;
|
|
347
|
+
if (cmd.argumentHint !== void 0) frontmatter["argument-hint"] = cmd.argumentHint;
|
|
348
|
+
if (cmd.extra) Object.assign(frontmatter, cmd.extra);
|
|
349
|
+
return this.renderFrontmatterMd(frontmatter, cmd.prompt);
|
|
350
|
+
}
|
|
351
|
+
// ── Skills ────────────────────────────────────────────────────────────────
|
|
352
|
+
installSkills(ctx) {
|
|
353
|
+
const { connector } = ctx;
|
|
354
|
+
if (connector.platforms[HOST]?.skills === false) {
|
|
355
|
+
return [{ platform: this.id, action: "skip", detail: "skills disabled for jetbrains-copilot" }];
|
|
356
|
+
}
|
|
357
|
+
if (connector.skills.length === 0) {
|
|
358
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
359
|
+
}
|
|
360
|
+
const changes = [];
|
|
361
|
+
for (const skill of connector.skills) {
|
|
362
|
+
const dir = this.skillDir(ctx, skill.name);
|
|
363
|
+
changes.push(
|
|
364
|
+
this.writeContentFile(join(dir, "SKILL.md"), this.renderSkill(skill), ctx.dryRun)
|
|
365
|
+
);
|
|
366
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
367
|
+
const target = this.resolveWithin(dir, rel);
|
|
368
|
+
if (target === null) {
|
|
369
|
+
changes.push({
|
|
370
|
+
platform: this.id,
|
|
371
|
+
action: "warn",
|
|
372
|
+
detail: `skill resource "${rel}" escapes the skill dir; skipped`
|
|
373
|
+
});
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
changes.push(this.writeContentFile(target, contents, ctx.dryRun));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return changes;
|
|
380
|
+
}
|
|
381
|
+
uninstallSkills(ctx) {
|
|
382
|
+
const { connector } = ctx;
|
|
383
|
+
if (connector.skills.length === 0) {
|
|
384
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
385
|
+
}
|
|
386
|
+
const changes = [];
|
|
387
|
+
for (const skill of connector.skills) {
|
|
388
|
+
const dir = this.skillDir(ctx, skill.name);
|
|
389
|
+
changes.push(this.removeContentFile(join(dir, "SKILL.md"), ctx.dryRun));
|
|
390
|
+
for (const rel of Object.keys(skill.resources ?? {})) {
|
|
391
|
+
const target = this.resolveWithin(dir, rel);
|
|
392
|
+
if (target === null) continue;
|
|
393
|
+
changes.push(this.removeContentFile(target, ctx.dryRun));
|
|
394
|
+
}
|
|
395
|
+
changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));
|
|
396
|
+
}
|
|
397
|
+
return changes;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Render a skill's SKILL.md — the uniform Agent Skills format: frontmatter
|
|
401
|
+
* (name, description + optional model, allowed-tools, disable-model-invocation)
|
|
402
|
+
* + body. Byte-identical to the other .github-sharing connectors so a shared
|
|
403
|
+
* skill folder never thrashes.
|
|
404
|
+
*/
|
|
405
|
+
renderSkill(skill) {
|
|
406
|
+
const frontmatter = {
|
|
407
|
+
name: skill.name,
|
|
408
|
+
description: skill.description
|
|
409
|
+
};
|
|
410
|
+
if (skill.model !== void 0) frontmatter.model = skill.model;
|
|
411
|
+
const allow = skill.tools?.allow;
|
|
412
|
+
if (allow && allow.length > 0) frontmatter["allowed-tools"] = allow.join(", ");
|
|
413
|
+
if (skill.disableModelInvocation !== void 0) {
|
|
414
|
+
frontmatter["disable-model-invocation"] = skill.disableModelInvocation;
|
|
415
|
+
}
|
|
416
|
+
if (skill.extra) Object.assign(frontmatter, skill.extra);
|
|
417
|
+
return this.renderFrontmatterMd(frontmatter, skill.body);
|
|
418
|
+
}
|
|
419
|
+
// ── Diagnostics ──────────────────────────────────────────────────────────
|
|
420
|
+
getHealthChecks(ctx) {
|
|
421
|
+
const hooksPath = this.getHookConfigPath(ctx);
|
|
422
|
+
const connectorId = ctx.connector.id;
|
|
423
|
+
const homeBin = ctx.homeBinPath;
|
|
424
|
+
const hookEvents = ctx.connector.hookEvents;
|
|
425
|
+
const hasServer = ctx.connector.server != null && ctx.connector.platforms[HOST]?.server !== false;
|
|
426
|
+
const checks = [
|
|
427
|
+
{
|
|
428
|
+
// MCP cannot be verified from disk — JetBrains owns it behind the UI.
|
|
429
|
+
// BaseAdapter.doctor maps != OK to a hard FAIL, but an unverifiable
|
|
430
|
+
// UI-managed surface must NOT hard-fail doctor (that contradicts the
|
|
431
|
+
// install-time WARN). Return OK with a verify-in-UI detail instead.
|
|
432
|
+
name: `${this.name}: MCP server (UI-managed)`,
|
|
433
|
+
check: () => hasServer ? {
|
|
434
|
+
status: "OK",
|
|
435
|
+
detail: "MCP is UI-managed \u2014 verify in Settings > Tools > GitHub Copilot > MCP"
|
|
436
|
+
} : { status: "OK", detail: "connector declares no MCP server" }
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
name: `${this.name}: hook command registered`,
|
|
440
|
+
check: () => {
|
|
441
|
+
if (hookEvents.length === 0) {
|
|
442
|
+
return { status: "OK", detail: "no hooks declared" };
|
|
443
|
+
}
|
|
444
|
+
const file = this.readJson(hooksPath);
|
|
445
|
+
if (!file) return { status: "FAIL", detail: `not found: ${hooksPath}` };
|
|
446
|
+
if (file.version !== JETBRAINS_HOOKS_VERSION) {
|
|
447
|
+
return {
|
|
448
|
+
status: "FAIL",
|
|
449
|
+
detail: `${hooksPath} missing required "version": ${JETBRAINS_HOOKS_VERSION} \u2014 Copilot rejects it`
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
const registered = Object.values(file.hooks ?? {}).some(
|
|
453
|
+
(entries) => (entries ?? []).some(
|
|
454
|
+
(e) => isHomeBinHookCommand(e.command, homeBin, connectorId)
|
|
455
|
+
)
|
|
456
|
+
);
|
|
457
|
+
return registered ? { status: "OK", detail: "hook command present" } : { status: "FAIL", detail: `no hook for ${connectorId} in ${hooksPath}` };
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
];
|
|
461
|
+
for (const cmd of ctx.connector.commands) {
|
|
462
|
+
const p = this.commandPath(ctx, cmd.name);
|
|
463
|
+
checks.push({
|
|
464
|
+
name: `${this.name}: command ${cmd.name} present`,
|
|
465
|
+
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
for (const skill of ctx.connector.skills) {
|
|
469
|
+
const p = join(this.skillDir(ctx, skill.name), "SKILL.md");
|
|
470
|
+
checks.push({
|
|
471
|
+
name: `${this.name}: skill ${skill.name} present`,
|
|
472
|
+
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
return checks;
|
|
476
|
+
}
|
|
477
|
+
// ── Runtime: parse JetBrains Copilot stdin JSON → normalized event ────────
|
|
478
|
+
parseEvent(event, raw) {
|
|
479
|
+
const input = raw ?? {};
|
|
480
|
+
const connectorId = typeof input.connector === "string" ? input.connector : "";
|
|
481
|
+
const sessionId = extractSessionId(input);
|
|
482
|
+
const projectDir = this.getProjectDir(input);
|
|
483
|
+
const base = {
|
|
484
|
+
hostPlatform: HOST,
|
|
485
|
+
connectorId,
|
|
486
|
+
sessionId,
|
|
487
|
+
raw,
|
|
488
|
+
...projectDir !== void 0 ? { projectDir } : {}
|
|
489
|
+
};
|
|
490
|
+
switch (event) {
|
|
491
|
+
case "PreToolUse": {
|
|
492
|
+
const ev = {
|
|
493
|
+
...base,
|
|
494
|
+
toolName: input.tool_name ?? "",
|
|
495
|
+
toolInput: input.tool_input ?? {}
|
|
496
|
+
};
|
|
497
|
+
return ev;
|
|
498
|
+
}
|
|
499
|
+
case "PostToolUse": {
|
|
500
|
+
const toolOutput = toolResponseToString(input.tool_response) ?? input.tool_output ?? input.error_message;
|
|
501
|
+
const ev = {
|
|
502
|
+
...base,
|
|
503
|
+
toolName: input.tool_name ?? "",
|
|
504
|
+
toolInput: input.tool_input ?? {},
|
|
505
|
+
...toolOutput !== void 0 ? { toolOutput } : {},
|
|
506
|
+
...input.error_message ? { isError: true } : {}
|
|
507
|
+
};
|
|
508
|
+
return ev;
|
|
509
|
+
}
|
|
510
|
+
case "PreCompact": {
|
|
511
|
+
const ev = {
|
|
512
|
+
...base,
|
|
513
|
+
...input.trigger === "auto" || input.trigger === "manual" ? { trigger: input.trigger } : {}
|
|
514
|
+
};
|
|
515
|
+
return ev;
|
|
516
|
+
}
|
|
517
|
+
case "SessionStart": {
|
|
518
|
+
const ev = {
|
|
519
|
+
...base,
|
|
520
|
+
source: normalizeSessionSource(input.source ?? input.trigger)
|
|
521
|
+
};
|
|
522
|
+
return ev;
|
|
523
|
+
}
|
|
524
|
+
case "SessionEnd": {
|
|
525
|
+
const ev = {
|
|
526
|
+
...base,
|
|
527
|
+
...typeof input.reason === "string" ? { reason: input.reason } : {}
|
|
528
|
+
};
|
|
529
|
+
return ev;
|
|
530
|
+
}
|
|
531
|
+
case "UserPromptSubmit": {
|
|
532
|
+
const ev = {
|
|
533
|
+
...base,
|
|
534
|
+
prompt: typeof input.prompt === "string" ? input.prompt : ""
|
|
535
|
+
};
|
|
536
|
+
return ev;
|
|
537
|
+
}
|
|
538
|
+
case "Stop": {
|
|
539
|
+
const ev = {
|
|
540
|
+
...base,
|
|
541
|
+
...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
|
|
542
|
+
};
|
|
543
|
+
return ev;
|
|
544
|
+
}
|
|
545
|
+
case "Notification": {
|
|
546
|
+
const ev = {
|
|
547
|
+
...base,
|
|
548
|
+
message: typeof input.message === "string" ? input.message : ""
|
|
549
|
+
};
|
|
550
|
+
return ev;
|
|
551
|
+
}
|
|
552
|
+
default: {
|
|
553
|
+
const _never = event;
|
|
554
|
+
throw new Error(`unsupported jetbrains-copilot hook event: ${String(_never)}`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/** Resolve the project dir from the wire payload, preferring the explicit cwd. */
|
|
559
|
+
getProjectDir(input) {
|
|
560
|
+
return input.cwd ?? input.workspace_roots?.[0] ?? void 0;
|
|
561
|
+
}
|
|
562
|
+
// ── Runtime: normalized response → JetBrains Copilot native hook reply ────
|
|
563
|
+
formatReply(event, response) {
|
|
564
|
+
const hookEventName = event;
|
|
565
|
+
const decision = response.decision ?? "allow";
|
|
566
|
+
if (decision === "deny") {
|
|
567
|
+
return this.stdout({
|
|
568
|
+
hookSpecificOutput: {
|
|
569
|
+
hookEventName,
|
|
570
|
+
permissionDecision: "deny",
|
|
571
|
+
permissionDecisionReason: response.reason ?? "Blocked by hook"
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
if (decision === "ask") {
|
|
576
|
+
return this.stdout({
|
|
577
|
+
hookSpecificOutput: {
|
|
578
|
+
hookEventName,
|
|
579
|
+
permissionDecision: "ask",
|
|
580
|
+
permissionDecisionReason: response.reason ?? "Confirmation required by hook"
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
if (decision === "context" && response.additionalContext) {
|
|
585
|
+
return this.stdout({
|
|
586
|
+
hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext }
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
return { exitCode: 0 };
|
|
590
|
+
}
|
|
591
|
+
stdout(payload) {
|
|
592
|
+
return { exitCode: 0, stdout: JSON.stringify(payload) };
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
function extractSessionId(input) {
|
|
596
|
+
if (typeof input.transcript_path === "string") {
|
|
597
|
+
const m = input.transcript_path.match(/([a-f0-9-]{36})\.jsonl$/);
|
|
598
|
+
if (m && m[1]) return m[1];
|
|
599
|
+
}
|
|
600
|
+
if (typeof input.session_id === "string" && input.session_id !== "") {
|
|
601
|
+
return input.session_id;
|
|
602
|
+
}
|
|
603
|
+
return "";
|
|
604
|
+
}
|
|
605
|
+
function toolResponseToString(value) {
|
|
606
|
+
if (value == null) return void 0;
|
|
607
|
+
if (typeof value === "string") return value;
|
|
608
|
+
try {
|
|
609
|
+
return JSON.stringify(value);
|
|
610
|
+
} catch {
|
|
611
|
+
return String(value);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
function normalizeSessionSource(source) {
|
|
615
|
+
switch (source) {
|
|
616
|
+
case "compact":
|
|
617
|
+
return "compact";
|
|
618
|
+
case "resume":
|
|
619
|
+
return "resume";
|
|
620
|
+
case "clear":
|
|
621
|
+
return "clear";
|
|
622
|
+
default:
|
|
623
|
+
return "startup";
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
var adapter = new JetBrainsCopilotAdapter();
|
|
627
|
+
var jetbrains_copilot_default = adapter;
|
|
628
|
+
export {
|
|
629
|
+
JetBrainsCopilotAdapter,
|
|
630
|
+
adapter,
|
|
631
|
+
jetbrains_copilot_default as default
|
|
632
|
+
};
|
|
633
|
+
//# sourceMappingURL=jetbrains-copilot-HWA3DMH7.js.map
|