@ken-jo/agent-connector 0.4.91 → 0.4.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +301 -560
- package/dist/{action-L44DXFHT.js → action-CVIEPX4U.js} +14 -14
- package/dist/{amazon-q-B52EY2SV.js → amazon-q-TIT7FIW3.js} +5 -5
- package/dist/{amp-UXABVUKC.js → amp-NF3OAAUG.js} +5 -5
- package/dist/{antigravity-RZHN53VB.js → antigravity-7LPK7QOY.js} +6 -6
- package/dist/{antigravity-cli-JO6GUTV7.js → antigravity-cli-MDEMPPAH.js} +47 -16
- package/dist/antigravity-cli-MDEMPPAH.js.map +1 -0
- package/dist/{chunk-QKLJU4JX.js → chunk-2Y2MZRLP.js} +56 -2
- package/dist/chunk-2Y2MZRLP.js.map +1 -0
- package/dist/{chunk-UBB7T54N.js → chunk-3C5AASHM.js} +3 -3
- package/dist/{chunk-BLTVZACS.js → chunk-447JWFZO.js} +9 -9
- package/dist/{chunk-HORHRHNG.js → chunk-4NHXLXSD.js} +2 -2
- package/dist/chunk-5Z36KVU2.js +590 -0
- package/dist/chunk-5Z36KVU2.js.map +1 -0
- package/dist/{chunk-AY3RGRTT.js → chunk-6TF7MHG5.js} +2 -2
- package/dist/{chunk-R6LML2YS.js → chunk-7UT6OB52.js} +2 -2
- package/dist/{chunk-G4CEELKO.js → chunk-AY3VFNOH.js} +5 -5
- package/dist/{chunk-4HVQ7IUM.js → chunk-DI5S6TXJ.js} +17 -4
- package/dist/chunk-DI5S6TXJ.js.map +1 -0
- package/dist/{chunk-LAIITCMW.js → chunk-FBCBHEGB.js} +5 -5
- package/dist/{chunk-4NSU3KWX.js → chunk-FJCUKXGX.js} +2 -2
- package/dist/{chunk-ZMLVR4J7.js → chunk-FO5CEXXN.js} +2 -2
- package/dist/{chunk-IXOQDZWC.js → chunk-GZGLCCEE.js} +5 -1
- package/dist/chunk-GZGLCCEE.js.map +1 -0
- package/dist/{chunk-LF76VPGQ.js → chunk-IBLYVAWH.js} +28 -6
- package/dist/chunk-IBLYVAWH.js.map +1 -0
- package/dist/{chunk-4FWETID5.js → chunk-IVAWP6HH.js} +2 -2
- package/dist/{chunk-NBUEL74R.js → chunk-JFXL4HYA.js} +3 -3
- package/dist/{chunk-KIRCPLM4.js → chunk-JO2IM2JL.js} +538 -226
- package/dist/chunk-JO2IM2JL.js.map +1 -0
- package/dist/{chunk-NWLRJNXM.js → chunk-JVO6NBTT.js} +3 -3
- package/dist/{chunk-25CPWJA7.js → chunk-KA55FISM.js} +43 -43
- package/dist/{chunk-QARPXSIV.js → chunk-L26PSQTY.js} +4 -4
- package/dist/{chunk-YYNXIUR2.js → chunk-M2H7JURF.js} +2 -2
- package/dist/{chunk-56R2ER7K.js → chunk-NBYKLUF6.js} +2 -2
- package/dist/{chunk-VVFDU4IX.js → chunk-WFEHWTLM.js} +12 -5
- package/dist/{chunk-VVFDU4IX.js.map → chunk-WFEHWTLM.js.map} +1 -1
- package/dist/{chunk-LN76OGNR.js → chunk-Z2MRSS2I.js} +2 -2
- package/dist/{claude-code-WS4NAGZT.js → claude-code-7RS4YVGZ.js} +9 -9
- package/dist/cli/sdk.js +7 -7
- package/dist/cli.js +1 -1
- package/dist/{cline-NNMVCECA.js → cline-BZQAUYPC.js} +5 -5
- package/dist/{codebuddy-RBEZGXBG.js → codebuddy-G42IKGKB.js} +5 -5
- package/dist/{codebuff-RJIDSEU3.js → codebuff-5RLTLZAU.js} +5 -5
- package/dist/{codex-ZZ434GYR.js → codex-XHAMJILX.js} +11 -5
- package/dist/{codex-ZZ434GYR.js.map → codex-XHAMJILX.js.map} +1 -1
- package/dist/{continue-MNM7YVJY.js → continue-JLIB7R7X.js} +6 -6
- package/dist/{copilot-cli-SMTX5F65.js → copilot-cli-XZSUYNQZ.js} +5 -5
- package/dist/{crush-NYDBHIJE.js → crush-ESERLVLT.js} +5 -5
- package/dist/{cursor-AOELDNZU.js → cursor-FUDOV5VK.js} +6 -6
- package/dist/{detect-3S46RUMK.js → detect-Z5BDTY6B.js} +4 -4
- package/dist/{devin-PRJY2TTD.js → devin-Y7PWKVHY.js} +5 -5
- package/dist/{doctor-3CUBPQKU.js → doctor-GAP27PP2.js} +25 -21
- package/dist/doctor-GAP27PP2.js.map +1 -0
- package/dist/{droid-PTCH2K7Y.js → droid-DTO5POTK.js} +5 -5
- package/dist/{gemini-cli-QGLN2UMS.js → gemini-cli-RBIG6U2F.js} +5 -5
- package/dist/{goose-DQ6GSZ5O.js → goose-VGNOP5J2.js} +6 -6
- package/dist/{grok-cli-5QD235UB.js → grok-cli-2RFBK6J3.js} +5 -5
- package/dist/{hermes-E47IG63A.js → hermes-NUKFWZI5.js} +6 -6
- package/dist/{hook-P6EKDINW.js → hook-XPR3AHDI.js} +14 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/dist/install-O32TDIZP.js +382 -0
- package/dist/install-O32TDIZP.js.map +1 -0
- package/dist/{introspect-DYOIX8Ov.d.ts → introspect-BkId4LGP.d.ts} +1 -1
- package/dist/{jetbrains-copilot-T2EPKROP.js → jetbrains-copilot-FXZ5AOTS.js} +23 -7
- package/dist/jetbrains-copilot-FXZ5AOTS.js.map +1 -0
- package/dist/{junie-SQ4SDLGK.js → junie-TSXIZSCE.js} +5 -5
- package/dist/{kilo-OU2ZLZKB.js → kilo-JLH3KVZJ.js} +5 -5
- package/dist/{kilo-cli-NMWGYF4F.js → kilo-cli-5W36VJQZ.js} +5 -5
- package/dist/{kimi-Z7L2LEEI.js → kimi-R62W7HKZ.js} +5 -5
- package/dist/{kiro-4IN5IH46.js → kiro-AUJMGIBL.js} +5 -5
- package/dist/{leaderboard-LF5SP6X2.js → leaderboard-YWMOSJBC.js} +5 -5
- package/dist/{mimo-code-G2CBZ4M6.js → mimo-code-PGLFFVER.js} +5 -5
- package/dist/{mistral-vibe-TRQDHAWV.js → mistral-vibe-36CZVQNQ.js} +5 -5
- package/dist/{mux-JNM3F2NW.js → mux-HWL4N5KH.js} +5 -5
- package/dist/{nemoclaw-SHA4IUML.js → nemoclaw-QPHETUXM.js} +6 -6
- package/dist/{omp-OOVUNXME.js → omp-3TFMTJ5U.js} +5 -5
- package/dist/{open-interpreter-4PKL56AA.js → open-interpreter-UTBKE2EH.js} +5 -5
- package/dist/openclaw-RYFO5TLY.js +17 -0
- package/dist/{opencode-W2RK4M7G.js → opencode-JX7GBE5Q.js} +5 -5
- package/dist/{openhands-5LNH3BKB.js → openhands-AZW4PXJ3.js} +5 -5
- package/dist/{package-2EAIYSJ4.js → package-2KKUGZFS.js} +12 -12
- package/dist/{pi-BUADR5MJ.js → pi-MRI3EBWU.js} +5 -5
- package/dist/{qwen-code-TUJNHKNI.js → qwen-code-ISR6BEET.js} +6 -6
- package/dist/{roo-code-L5F7S6QH.js → roo-code-6TSCME4R.js} +5 -5
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +12 -12
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +10 -10
- package/dist/{serve-K62FW3V7.js → serve-EPRN7F2X.js} +14 -14
- package/dist/{status-E5MCFZM6.js → status-B2PG6YKR.js} +10 -10
- package/dist/{statusline-LIPF2KVP.js → statusline-5ERFMYSM.js} +13 -13
- package/dist/{telemetry-4OC56NTM.js → telemetry-ZMCAWBWB.js} +10 -10
- package/dist/{trae-Z7CQ2A2Q.js → trae-7KDCYIMN.js} +5 -5
- package/dist/{types-C4qMgbJn.d.ts → types-D0RqWxT8.d.ts} +43 -0
- package/dist/{uninstall-2YYKN5DX.js → uninstall-M76BHLTH.js} +35 -25
- package/dist/uninstall-M76BHLTH.js.map +1 -0
- package/dist/{upgrade-55AFPJEF.js → upgrade-JLSCNAQA.js} +23 -17
- package/dist/upgrade-JLSCNAQA.js.map +1 -0
- package/dist/{usage-3PB3WZSL.js → usage-5I72HWCR.js} +2 -2
- package/dist/{usage-event-KD5FW6W4.js → usage-event-HIX4ZI45.js} +13 -13
- package/dist/{vscode-copilot-LU5NC4ZS.js → vscode-copilot-LILHAPJI.js} +20 -5
- package/dist/vscode-copilot-LILHAPJI.js.map +1 -0
- package/dist/{warp-4PPG5LOM.js → warp-KJUCWEA3.js} +5 -5
- package/dist/{windsurf-3T3RVXKM.js → windsurf-5TGGQR5I.js} +5 -5
- package/dist/{zed-ZF2OQ75O.js → zed-EL3JCZ25.js} +5 -5
- package/package.json +1 -1
- package/dist/antigravity-cli-JO6GUTV7.js.map +0 -1
- package/dist/chunk-4HVQ7IUM.js.map +0 -1
- package/dist/chunk-7HUUINPB.js +0 -201
- package/dist/chunk-7HUUINPB.js.map +0 -1
- package/dist/chunk-IXOQDZWC.js.map +0 -1
- package/dist/chunk-KIRCPLM4.js.map +0 -1
- package/dist/chunk-LF76VPGQ.js.map +0 -1
- package/dist/chunk-QKLJU4JX.js.map +0 -1
- package/dist/doctor-3CUBPQKU.js.map +0 -1
- package/dist/install-7DMK53SB.js +0 -96
- package/dist/install-7DMK53SB.js.map +0 -1
- package/dist/jetbrains-copilot-T2EPKROP.js.map +0 -1
- package/dist/openclaw-BD56E5MV.js +0 -17
- package/dist/uninstall-2YYKN5DX.js.map +0 -1
- package/dist/upgrade-55AFPJEF.js.map +0 -1
- package/dist/vscode-copilot-LU5NC4ZS.js.map +0 -1
- /package/dist/{action-L44DXFHT.js.map → action-CVIEPX4U.js.map} +0 -0
- /package/dist/{amazon-q-B52EY2SV.js.map → amazon-q-TIT7FIW3.js.map} +0 -0
- /package/dist/{amp-UXABVUKC.js.map → amp-NF3OAAUG.js.map} +0 -0
- /package/dist/{antigravity-RZHN53VB.js.map → antigravity-7LPK7QOY.js.map} +0 -0
- /package/dist/{chunk-UBB7T54N.js.map → chunk-3C5AASHM.js.map} +0 -0
- /package/dist/{chunk-BLTVZACS.js.map → chunk-447JWFZO.js.map} +0 -0
- /package/dist/{chunk-HORHRHNG.js.map → chunk-4NHXLXSD.js.map} +0 -0
- /package/dist/{chunk-AY3RGRTT.js.map → chunk-6TF7MHG5.js.map} +0 -0
- /package/dist/{chunk-R6LML2YS.js.map → chunk-7UT6OB52.js.map} +0 -0
- /package/dist/{chunk-G4CEELKO.js.map → chunk-AY3VFNOH.js.map} +0 -0
- /package/dist/{chunk-LAIITCMW.js.map → chunk-FBCBHEGB.js.map} +0 -0
- /package/dist/{chunk-4NSU3KWX.js.map → chunk-FJCUKXGX.js.map} +0 -0
- /package/dist/{chunk-ZMLVR4J7.js.map → chunk-FO5CEXXN.js.map} +0 -0
- /package/dist/{chunk-4FWETID5.js.map → chunk-IVAWP6HH.js.map} +0 -0
- /package/dist/{chunk-NBUEL74R.js.map → chunk-JFXL4HYA.js.map} +0 -0
- /package/dist/{chunk-NWLRJNXM.js.map → chunk-JVO6NBTT.js.map} +0 -0
- /package/dist/{chunk-25CPWJA7.js.map → chunk-KA55FISM.js.map} +0 -0
- /package/dist/{chunk-QARPXSIV.js.map → chunk-L26PSQTY.js.map} +0 -0
- /package/dist/{chunk-YYNXIUR2.js.map → chunk-M2H7JURF.js.map} +0 -0
- /package/dist/{chunk-56R2ER7K.js.map → chunk-NBYKLUF6.js.map} +0 -0
- /package/dist/{chunk-LN76OGNR.js.map → chunk-Z2MRSS2I.js.map} +0 -0
- /package/dist/{claude-code-WS4NAGZT.js.map → claude-code-7RS4YVGZ.js.map} +0 -0
- /package/dist/{cline-NNMVCECA.js.map → cline-BZQAUYPC.js.map} +0 -0
- /package/dist/{codebuddy-RBEZGXBG.js.map → codebuddy-G42IKGKB.js.map} +0 -0
- /package/dist/{codebuff-RJIDSEU3.js.map → codebuff-5RLTLZAU.js.map} +0 -0
- /package/dist/{continue-MNM7YVJY.js.map → continue-JLIB7R7X.js.map} +0 -0
- /package/dist/{copilot-cli-SMTX5F65.js.map → copilot-cli-XZSUYNQZ.js.map} +0 -0
- /package/dist/{crush-NYDBHIJE.js.map → crush-ESERLVLT.js.map} +0 -0
- /package/dist/{cursor-AOELDNZU.js.map → cursor-FUDOV5VK.js.map} +0 -0
- /package/dist/{detect-3S46RUMK.js.map → detect-Z5BDTY6B.js.map} +0 -0
- /package/dist/{devin-PRJY2TTD.js.map → devin-Y7PWKVHY.js.map} +0 -0
- /package/dist/{droid-PTCH2K7Y.js.map → droid-DTO5POTK.js.map} +0 -0
- /package/dist/{gemini-cli-QGLN2UMS.js.map → gemini-cli-RBIG6U2F.js.map} +0 -0
- /package/dist/{goose-DQ6GSZ5O.js.map → goose-VGNOP5J2.js.map} +0 -0
- /package/dist/{grok-cli-5QD235UB.js.map → grok-cli-2RFBK6J3.js.map} +0 -0
- /package/dist/{hermes-E47IG63A.js.map → hermes-NUKFWZI5.js.map} +0 -0
- /package/dist/{hook-P6EKDINW.js.map → hook-XPR3AHDI.js.map} +0 -0
- /package/dist/{junie-SQ4SDLGK.js.map → junie-TSXIZSCE.js.map} +0 -0
- /package/dist/{kilo-OU2ZLZKB.js.map → kilo-JLH3KVZJ.js.map} +0 -0
- /package/dist/{kilo-cli-NMWGYF4F.js.map → kilo-cli-5W36VJQZ.js.map} +0 -0
- /package/dist/{kimi-Z7L2LEEI.js.map → kimi-R62W7HKZ.js.map} +0 -0
- /package/dist/{kiro-4IN5IH46.js.map → kiro-AUJMGIBL.js.map} +0 -0
- /package/dist/{leaderboard-LF5SP6X2.js.map → leaderboard-YWMOSJBC.js.map} +0 -0
- /package/dist/{mimo-code-G2CBZ4M6.js.map → mimo-code-PGLFFVER.js.map} +0 -0
- /package/dist/{mistral-vibe-TRQDHAWV.js.map → mistral-vibe-36CZVQNQ.js.map} +0 -0
- /package/dist/{mux-JNM3F2NW.js.map → mux-HWL4N5KH.js.map} +0 -0
- /package/dist/{nemoclaw-SHA4IUML.js.map → nemoclaw-QPHETUXM.js.map} +0 -0
- /package/dist/{omp-OOVUNXME.js.map → omp-3TFMTJ5U.js.map} +0 -0
- /package/dist/{open-interpreter-4PKL56AA.js.map → open-interpreter-UTBKE2EH.js.map} +0 -0
- /package/dist/{openclaw-BD56E5MV.js.map → openclaw-RYFO5TLY.js.map} +0 -0
- /package/dist/{opencode-W2RK4M7G.js.map → opencode-JX7GBE5Q.js.map} +0 -0
- /package/dist/{openhands-5LNH3BKB.js.map → openhands-AZW4PXJ3.js.map} +0 -0
- /package/dist/{package-2EAIYSJ4.js.map → package-2KKUGZFS.js.map} +0 -0
- /package/dist/{pi-BUADR5MJ.js.map → pi-MRI3EBWU.js.map} +0 -0
- /package/dist/{qwen-code-TUJNHKNI.js.map → qwen-code-ISR6BEET.js.map} +0 -0
- /package/dist/{roo-code-L5F7S6QH.js.map → roo-code-6TSCME4R.js.map} +0 -0
- /package/dist/{serve-K62FW3V7.js.map → serve-EPRN7F2X.js.map} +0 -0
- /package/dist/{status-E5MCFZM6.js.map → status-B2PG6YKR.js.map} +0 -0
- /package/dist/{statusline-LIPF2KVP.js.map → statusline-5ERFMYSM.js.map} +0 -0
- /package/dist/{telemetry-4OC56NTM.js.map → telemetry-ZMCAWBWB.js.map} +0 -0
- /package/dist/{trae-Z7CQ2A2Q.js.map → trae-7KDCYIMN.js.map} +0 -0
- /package/dist/{usage-3PB3WZSL.js.map → usage-5I72HWCR.js.map} +0 -0
- /package/dist/{usage-event-KD5FW6W4.js.map → usage-event-HIX4ZI45.js.map} +0 -0
- /package/dist/{warp-4PPG5LOM.js.map → warp-KJUCWEA3.js.map} +0 -0
- /package/dist/{windsurf-3T3RVXKM.js.map → windsurf-5TGGQR5I.js.map} +0 -0
- /package/dist/{zed-ZF2OQ75O.js.map → zed-EL3JCZ25.js.map} +0 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
installConnector,
|
|
4
|
+
installViaMarketplace,
|
|
5
|
+
parseInstallMethod
|
|
6
|
+
} from "./chunk-JO2IM2JL.js";
|
|
7
|
+
import "./chunk-IBLYVAWH.js";
|
|
8
|
+
import "./chunk-2Y2MZRLP.js";
|
|
9
|
+
import "./chunk-UM5S7DKK.js";
|
|
10
|
+
import "./chunk-JFXL4HYA.js";
|
|
11
|
+
import "./chunk-OPXAP3AC.js";
|
|
12
|
+
import {
|
|
13
|
+
buildConnectorSummary,
|
|
14
|
+
fail,
|
|
15
|
+
maybePrintBanner,
|
|
16
|
+
parseScope,
|
|
17
|
+
parseTargets,
|
|
18
|
+
print,
|
|
19
|
+
renderInstallResult
|
|
20
|
+
} from "./chunk-5Z36KVU2.js";
|
|
21
|
+
import "./chunk-Z2MRSS2I.js";
|
|
22
|
+
import "./chunk-FO5CEXXN.js";
|
|
23
|
+
import "./chunk-KHO5WNTP.js";
|
|
24
|
+
import {
|
|
25
|
+
findConnectorConfig,
|
|
26
|
+
loadConnectorFromPath
|
|
27
|
+
} from "./chunk-JVO6NBTT.js";
|
|
28
|
+
import "./chunk-AY3VFNOH.js";
|
|
29
|
+
import "./chunk-KA55FISM.js";
|
|
30
|
+
import "./chunk-NBYKLUF6.js";
|
|
31
|
+
import "./chunk-H53QZQJI.js";
|
|
32
|
+
import "./chunk-BEFVJ2OE.js";
|
|
33
|
+
import "./chunk-WFEHWTLM.js";
|
|
34
|
+
import "./chunk-4NHXLXSD.js";
|
|
35
|
+
import "./chunk-M2H7JURF.js";
|
|
36
|
+
import {
|
|
37
|
+
sourcesDir
|
|
38
|
+
} from "./chunk-GZGLCCEE.js";
|
|
39
|
+
|
|
40
|
+
// src/cli/commands/install.ts
|
|
41
|
+
import { parseArgs } from "util";
|
|
42
|
+
|
|
43
|
+
// src/core/fetch-source.ts
|
|
44
|
+
import { execFileSync } from "child_process";
|
|
45
|
+
import { createHash } from "crypto";
|
|
46
|
+
import {
|
|
47
|
+
existsSync,
|
|
48
|
+
mkdirSync,
|
|
49
|
+
readdirSync,
|
|
50
|
+
renameSync,
|
|
51
|
+
rmSync,
|
|
52
|
+
writeFileSync
|
|
53
|
+
} from "fs";
|
|
54
|
+
import { tmpdir } from "os";
|
|
55
|
+
import { isAbsolute, join, relative, resolve } from "path";
|
|
56
|
+
var GITHUB_SEG = /^[A-Za-z0-9._-]+$/;
|
|
57
|
+
function looksLocal(value) {
|
|
58
|
+
if (value === "") return true;
|
|
59
|
+
if (existsSync(value)) return true;
|
|
60
|
+
if (value.startsWith("./") || value.startsWith("../") || value === "." || value === ".." || value.startsWith("/") || value.startsWith("~") || value.startsWith("file://")) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (/^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) return true;
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
function parseRemoteSource(value) {
|
|
67
|
+
const raw = value.trim();
|
|
68
|
+
if (raw === "") return null;
|
|
69
|
+
const scp = raw.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
|
|
70
|
+
if (scp) {
|
|
71
|
+
return finalizeFromPath(scp[1], scp[2], void 0);
|
|
72
|
+
}
|
|
73
|
+
if (/^https?:\/\//i.test(raw) || raw.startsWith("git://")) {
|
|
74
|
+
let url;
|
|
75
|
+
try {
|
|
76
|
+
url = new URL(raw.replace(/^git:\/\//, "https://"));
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (!/(^|\.)github\.com$/i.test(url.hostname)) return null;
|
|
81
|
+
const segs2 = url.pathname.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
82
|
+
if (segs2.length < 2) return null;
|
|
83
|
+
const owner2 = segs2[0];
|
|
84
|
+
let repo2 = segs2[1].replace(/\.git$/, "");
|
|
85
|
+
let ref;
|
|
86
|
+
let subpath2;
|
|
87
|
+
if (segs2[2] === "tree" || segs2[2] === "blob") {
|
|
88
|
+
ref = segs2[3];
|
|
89
|
+
if (segs2.length > 4) subpath2 = segs2.slice(4).join("/");
|
|
90
|
+
} else if (segs2.length > 2) {
|
|
91
|
+
subpath2 = segs2.slice(2).join("/");
|
|
92
|
+
}
|
|
93
|
+
const hash = url.hash.replace(/^#/, "");
|
|
94
|
+
if (hash) ref = hash;
|
|
95
|
+
if (!GITHUB_SEG.test(owner2) || !GITHUB_SEG.test(repo2)) return null;
|
|
96
|
+
return cleanRemote({ owner: owner2, repo: repo2, ref, subpath: subpath2 });
|
|
97
|
+
}
|
|
98
|
+
const shorthand = raw.startsWith("github:") ? raw.slice("github:".length) : raw;
|
|
99
|
+
const [pathPart, refPart] = splitHash(shorthand);
|
|
100
|
+
const segs = pathPart.split("/").filter(Boolean);
|
|
101
|
+
if (segs.length < 2) return null;
|
|
102
|
+
const owner = segs[0];
|
|
103
|
+
const repo = segs[1].replace(/\.git$/, "");
|
|
104
|
+
const subpath = segs.length > 2 ? segs.slice(2).join("/") : void 0;
|
|
105
|
+
if (!GITHUB_SEG.test(owner) || !GITHUB_SEG.test(repo)) return null;
|
|
106
|
+
return cleanRemote({ owner, repo, ref: refPart, subpath });
|
|
107
|
+
}
|
|
108
|
+
function splitHash(value) {
|
|
109
|
+
const i = value.indexOf("#");
|
|
110
|
+
if (i === -1) return [value, void 0];
|
|
111
|
+
const ref = value.slice(i + 1).trim();
|
|
112
|
+
return [value.slice(0, i), ref === "" ? void 0 : ref];
|
|
113
|
+
}
|
|
114
|
+
function finalizeFromPath(owner, repoAndRest, _ref) {
|
|
115
|
+
const [pathPart, ref] = splitHash(repoAndRest);
|
|
116
|
+
const segs = pathPart.split("/").filter(Boolean);
|
|
117
|
+
const repo = (segs[0] ?? "").replace(/\.git$/, "");
|
|
118
|
+
const subpath = segs.length > 1 ? segs.slice(1).join("/") : void 0;
|
|
119
|
+
if (!GITHUB_SEG.test(owner) || !GITHUB_SEG.test(repo)) return null;
|
|
120
|
+
return cleanRemote({ owner, repo, ref, subpath });
|
|
121
|
+
}
|
|
122
|
+
var REF_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;
|
|
123
|
+
function isSafeRef(ref) {
|
|
124
|
+
return REF_RE.test(ref);
|
|
125
|
+
}
|
|
126
|
+
function cleanRemote(r) {
|
|
127
|
+
if (r.ref !== void 0 && !isSafeRef(r.ref)) return null;
|
|
128
|
+
const out = { owner: r.owner, repo: r.repo };
|
|
129
|
+
if (r.ref) out.ref = r.ref;
|
|
130
|
+
if (r.subpath && r.subpath !== "") out.subpath = r.subpath;
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
function parseGitUrl(value) {
|
|
134
|
+
const [urlPart, ref] = splitHash(value.trim());
|
|
135
|
+
const isScheme = urlPart.startsWith("file://") || urlPart.startsWith("ssh://") || urlPart.startsWith("git://") || /^https?:\/\//i.test(urlPart);
|
|
136
|
+
const isScp = /^[^@\s]+@[^:\s]+:.+/.test(urlPart) && !urlPart.startsWith("git@github.com:");
|
|
137
|
+
if (!isScheme && !isScp) return null;
|
|
138
|
+
if (ref !== void 0 && !isSafeRef(ref)) return null;
|
|
139
|
+
const stripped = urlPart.replace(/\.git$/, "").replace(/\/+$/, "");
|
|
140
|
+
const segs = stripped.split(/[/:]/).filter(Boolean);
|
|
141
|
+
const repo = segs[segs.length - 1] ?? "repo";
|
|
142
|
+
const owner = segs[segs.length - 2] ?? "git";
|
|
143
|
+
const out = { owner, repo, cloneUrl: urlPart };
|
|
144
|
+
if (ref) out.ref = ref;
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
function classifySource(value) {
|
|
148
|
+
const gitUrl = parseGitUrl(value);
|
|
149
|
+
if (gitUrl) return { kind: "remote", remote: gitUrl };
|
|
150
|
+
if (looksLocal(value)) return { kind: "local", value };
|
|
151
|
+
const remote = parseRemoteSource(value);
|
|
152
|
+
return remote ? { kind: "remote", remote } : null;
|
|
153
|
+
}
|
|
154
|
+
function cloneUrl(r) {
|
|
155
|
+
return r.cloneUrl ?? `https://github.com/${r.owner}/${r.repo}.git`;
|
|
156
|
+
}
|
|
157
|
+
function tarballUrl(r) {
|
|
158
|
+
const ref = r.ref ?? "HEAD";
|
|
159
|
+
return `https://codeload.github.com/${r.owner}/${r.repo}/tar.gz/${ref}`;
|
|
160
|
+
}
|
|
161
|
+
function sourceCacheDir(r) {
|
|
162
|
+
const safe = (s) => s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
163
|
+
const base = r.cloneUrl ? `${safe(r.owner)}__${safe(r.repo)}__${shortHash(r.cloneUrl)}` : `${safe(r.owner)}__${safe(r.repo)}`;
|
|
164
|
+
const name = r.ref ? `${base}__${safe(r.ref)}` : base;
|
|
165
|
+
return join(sourcesDir(), name);
|
|
166
|
+
}
|
|
167
|
+
function shortHash(value) {
|
|
168
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 8);
|
|
169
|
+
}
|
|
170
|
+
function gitAvailable() {
|
|
171
|
+
try {
|
|
172
|
+
execFileSync("git", ["--version"], { stdio: "ignore" });
|
|
173
|
+
return true;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function makeGitFetcher(urlFor = cloneUrl) {
|
|
179
|
+
return (remote, dest) => {
|
|
180
|
+
if (!gitAvailable()) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
"git is required to fetch a remote connector source but was not found on PATH. Install git, or pass a local --connector <path>."
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
rmSync(dest, { recursive: true, force: true });
|
|
186
|
+
mkdirSync(dest, { recursive: true });
|
|
187
|
+
const args = ["clone", "--depth", "1"];
|
|
188
|
+
if (remote.ref) args.push("--branch", remote.ref);
|
|
189
|
+
args.push(urlFor(remote), dest);
|
|
190
|
+
try {
|
|
191
|
+
execFileSync("git", args, { stdio: "ignore" });
|
|
192
|
+
} catch (err) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`failed to clone ${urlFor(remote)}${remote.ref ? ` (ref ${remote.ref})` : ""}: ${err instanceof Error ? err.message : String(err)}`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
async function tarballFetch(remote, dest) {
|
|
200
|
+
const url = tarballUrl(remote);
|
|
201
|
+
const res = await fetch(url);
|
|
202
|
+
if (!res.ok) {
|
|
203
|
+
throw new Error(`failed to download ${url}: HTTP ${res.status} ${res.statusText}`);
|
|
204
|
+
}
|
|
205
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
206
|
+
const work = join(tmpdir(), `ac-src-${process.pid}-${Date.now()}`);
|
|
207
|
+
mkdirSync(work, { recursive: true });
|
|
208
|
+
const tarPath = join(work, "source.tar.gz");
|
|
209
|
+
writeFileSync(tarPath, buf);
|
|
210
|
+
try {
|
|
211
|
+
execFileSync("tar", ["-xzf", tarPath, "-C", work], { stdio: "ignore" });
|
|
212
|
+
} catch (err) {
|
|
213
|
+
rmSync(work, { recursive: true, force: true });
|
|
214
|
+
throw new Error(
|
|
215
|
+
`neither git nor a usable \`tar\` is available to fetch a remote connector source (${err instanceof Error ? err.message : String(err)}). Install git or tar, or pass a local --connector <path>.`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const entries = readdirSync(work).filter((e) => e !== "source.tar.gz");
|
|
219
|
+
const top = entries.length === 1 ? join(work, entries[0]) : work;
|
|
220
|
+
rmSync(dest, { recursive: true, force: true });
|
|
221
|
+
renameSync(top, dest);
|
|
222
|
+
rmSync(work, { recursive: true, force: true });
|
|
223
|
+
}
|
|
224
|
+
var gitFetcher = async (remote, dest) => {
|
|
225
|
+
if (gitAvailable()) {
|
|
226
|
+
makeGitFetcher()(remote, dest);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (remote.cloneUrl) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`git is required to fetch ${remote.cloneUrl} but was not found on PATH. Install git, or pass a local --connector <path>.`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
await tarballFetch(remote, dest);
|
|
235
|
+
};
|
|
236
|
+
async function resolveRemoteSource(remote, opts = {}) {
|
|
237
|
+
const fetcher = opts.fetcher ?? gitFetcher;
|
|
238
|
+
const sourceDir = sourceCacheDir(remote);
|
|
239
|
+
mkdirSync(sourcesDir(), { recursive: true });
|
|
240
|
+
await fetcher(remote, sourceDir);
|
|
241
|
+
const label = describeRemote(remote);
|
|
242
|
+
if (!existsSync(sourceDir)) {
|
|
243
|
+
throw new Error(`failed to fetch ${label}: nothing was written to ${sourceDir}`);
|
|
244
|
+
}
|
|
245
|
+
const root = resolve(sourceDir);
|
|
246
|
+
const searchDir = remote.subpath ? resolve(root, remote.subpath) : root;
|
|
247
|
+
if (remote.subpath) {
|
|
248
|
+
const rel = relative(root, searchDir);
|
|
249
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
250
|
+
throw new Error(`subpath escapes the fetched source: ${remote.subpath}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (!existsSync(searchDir)) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
`${label}: subpath "${remote.subpath}" does not exist in the repository.`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
const configPath = findConfigWithin(searchDir);
|
|
259
|
+
if (!configPath) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`${label} is not an agent-connector connector \u2014 no agent-connector.config.{mjs,js,json} found in the repo` + (remote.subpath ? ` at subpath "${remote.subpath}"` : "") + ". The target must be a package built with agent-connector (defineConnector)."
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
let connector;
|
|
265
|
+
let modulePath;
|
|
266
|
+
try {
|
|
267
|
+
({ connector, modulePath } = await loadConnectorFromPath(configPath));
|
|
268
|
+
} catch (err) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`${label}: found ${configPath} but it failed to load as an agent-connector connector (${err instanceof Error ? err.message : String(err)}). The target must be a package built with agent-connector (defineConnector).`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
configPath,
|
|
275
|
+
sourceDir,
|
|
276
|
+
connectorDir: searchDir,
|
|
277
|
+
connector,
|
|
278
|
+
modulePath
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function findConfigWithin(dir) {
|
|
282
|
+
const hit = findConnectorConfig(dir);
|
|
283
|
+
if (!hit) return null;
|
|
284
|
+
const dirAbs = resolve(dir);
|
|
285
|
+
const hitDir = resolve(hit, "..");
|
|
286
|
+
return hitDir === dirAbs ? hit : null;
|
|
287
|
+
}
|
|
288
|
+
function describeRemote(r) {
|
|
289
|
+
let s = r.cloneUrl ?? `${r.owner}/${r.repo}`;
|
|
290
|
+
if (r.subpath) s += `/${r.subpath}`;
|
|
291
|
+
if (r.ref) s += `#${r.ref}`;
|
|
292
|
+
return s;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/cli/commands/install.ts
|
|
296
|
+
async function run(argv) {
|
|
297
|
+
const { values, positionals } = parseArgs({
|
|
298
|
+
args: argv,
|
|
299
|
+
options: {
|
|
300
|
+
method: { type: "string", default: "direct" },
|
|
301
|
+
scope: { type: "string", default: "user" },
|
|
302
|
+
targets: { type: "string" },
|
|
303
|
+
connector: { type: "string" },
|
|
304
|
+
project: { type: "string" },
|
|
305
|
+
"dry-run": { type: "boolean", default: false },
|
|
306
|
+
// Memory surface: overwrite USER-EDITED managed blocks (hash drift).
|
|
307
|
+
// Default behavior is warn-and-leave; --force backs the file up first.
|
|
308
|
+
force: { type: "boolean", default: false },
|
|
309
|
+
// Decorative-banner suppressor (no effect on command output bytes).
|
|
310
|
+
quiet: { type: "boolean", default: false }
|
|
311
|
+
},
|
|
312
|
+
// A single positional <source> (local path OR remote GitHub spec) is the
|
|
313
|
+
// ergonomic alias of --connector; either may be remote.
|
|
314
|
+
allowPositionals: true
|
|
315
|
+
});
|
|
316
|
+
maybePrintBanner({ quiet: values.quiet });
|
|
317
|
+
const method = parseInstallMethod(values.method);
|
|
318
|
+
if (method == null) {
|
|
319
|
+
return fail(`invalid --method "${values.method}" (use direct|marketplace)`);
|
|
320
|
+
}
|
|
321
|
+
const projectDir = values.project ?? process.cwd();
|
|
322
|
+
const positionalSource = positionals[0];
|
|
323
|
+
if (positionalSource != null && values.connector != null) {
|
|
324
|
+
return fail("pass a connector source as EITHER the positional <source> OR --connector, not both.");
|
|
325
|
+
}
|
|
326
|
+
const source = positionalSource ?? values.connector;
|
|
327
|
+
const scope = parseScope(values.scope);
|
|
328
|
+
if (scope == null) return fail(`invalid --scope "${values.scope}" (use user|project)`);
|
|
329
|
+
if (method === "marketplace" && scope !== "user") {
|
|
330
|
+
return fail(
|
|
331
|
+
"--method marketplace supports --scope user only (project-scope plugin installs are deferred)"
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
let connector;
|
|
335
|
+
let modulePath;
|
|
336
|
+
const spec = source != null ? classifySource(source) : null;
|
|
337
|
+
if (source != null && spec == null) {
|
|
338
|
+
return fail(
|
|
339
|
+
`"${source}" is not a local path or a recognizable GitHub source (owner/repo[/subpath][#ref], a github.com URL, git@github.com:\u2026, or github:owner/repo).`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
if (spec != null && spec.kind === "remote") {
|
|
343
|
+
try {
|
|
344
|
+
const resolved = await resolveRemoteSource(spec.remote);
|
|
345
|
+
({ connector, modulePath } = resolved);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
const configPath = source ?? findConnectorConfig(projectDir);
|
|
351
|
+
if (!configPath) {
|
|
352
|
+
return fail(
|
|
353
|
+
"no connector config found. Pass a <source> (local path or owner/repo) or --connector <path>, or add an agent-connector.config.{mjs,js,json} to your project."
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
({ connector, modulePath } = await loadConnectorFromPath(configPath));
|
|
357
|
+
}
|
|
358
|
+
const targets = parseTargets(values.targets);
|
|
359
|
+
const result = method === "marketplace" ? await installViaMarketplace({
|
|
360
|
+
connector,
|
|
361
|
+
modulePath,
|
|
362
|
+
scope,
|
|
363
|
+
projectDir,
|
|
364
|
+
dryRun: values["dry-run"],
|
|
365
|
+
...targets ? { targets } : {}
|
|
366
|
+
}) : await installConnector({
|
|
367
|
+
connector,
|
|
368
|
+
modulePath,
|
|
369
|
+
scope,
|
|
370
|
+
projectDir,
|
|
371
|
+
dryRun: values["dry-run"],
|
|
372
|
+
force: values.force,
|
|
373
|
+
...targets ? { targets } : {}
|
|
374
|
+
});
|
|
375
|
+
result.connector = buildConnectorSummary(connector);
|
|
376
|
+
print(renderInstallResult(result, "install"));
|
|
377
|
+
return result.changes.some((c) => c.action === "warn") ? 1 : 0;
|
|
378
|
+
}
|
|
379
|
+
export {
|
|
380
|
+
run
|
|
381
|
+
};
|
|
382
|
+
//# sourceMappingURL=install-O32TDIZP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/install.ts","../src/core/fetch-source.ts"],"sourcesContent":["/**\n * cli/commands/install — deploy a connector across its target platforms.\n *\n * Resolves the connector config (--connector <path>, else findConnectorConfig\n * walking up from the project dir), loads it into a live ResolvedConnector, and\n * hands it to the chosen DELIVERY METHOD's orchestration:\n *\n * --method direct (default) — the installer renders each host's native\n * MCP + hook + content config in place (zero behavior\n * change for existing scripts).\n * --method marketplace — stage the connector's plugin bundle under the\n * data-root and DRIVE the host's own plugin/marketplace\n * install flow (v1 driver: claude-code; other hosts get\n * never-silent skip/warn records with manual commands).\n *\n * Both methods emit the same ChangeRecords, rendered as a readable diff;\n * --dry-run renders the plan without writing or spawning. A double-install\n * guard (both directions) enforces exactly one method per (connector, host,\n * scope) — a refusal is a `warn` record, so the exit-1-on-warn convention\n * carries over.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { installConnector } from \"../../core/installer.js\";\nimport { installViaMarketplace, parseInstallMethod } from \"../../core/marketplace.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport { classifySource, resolveRemoteSource } from \"../../core/fetch-source.js\";\nimport {\n buildConnectorSummary,\n fail,\n maybePrintBanner,\n parseScope,\n parseTargets,\n print,\n renderInstallResult,\n} from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n method: { type: \"string\", default: \"direct\" },\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n // Memory surface: overwrite USER-EDITED managed blocks (hash drift).\n // Default behavior is warn-and-leave; --force backs the file up first.\n force: { type: \"boolean\", default: false },\n // Decorative-banner suppressor (no effect on command output bytes).\n quiet: { type: \"boolean\", default: false },\n },\n // A single positional <source> (local path OR remote GitHub spec) is the\n // ergonomic alias of --connector; either may be remote.\n allowPositionals: true,\n });\n\n maybePrintBanner({ quiet: values.quiet });\n\n const method = parseInstallMethod(values.method);\n if (method == null) {\n return fail(`invalid --method \"${values.method}\" (use direct|marketplace)`);\n }\n\n const projectDir = values.project ?? process.cwd();\n\n // A connector source may arrive as the first positional or via --connector,\n // and may be a LOCAL path (today's behavior) or a REMOTE GitHub spec\n // (owner/repo[/sub][#ref], a github URL, git@…, github:…). The positional and\n // the flag are equivalent; reject ambiguity when both name a source.\n const positionalSource = positionals[0];\n if (positionalSource != null && values.connector != null) {\n return fail(\"pass a connector source as EITHER the positional <source> OR --connector, not both.\");\n }\n const source = positionalSource ?? values.connector;\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n if (method === \"marketplace\" && scope !== \"user\") {\n return fail(\n \"--method marketplace supports --scope user only (project-scope plugin installs are deferred)\",\n );\n }\n\n // Resolve the source to a loadable connector. A REMOTE spec is fetched into a\n // STABLE cache dir under the data-root and GATED (must be an agent-connector\n // package) before handing off to the existing install flow. A LOCAL source —\n // or no source at all — keeps today's path-discovery behavior unchanged.\n let connector: Awaited<ReturnType<typeof loadConnectorFromPath>>[\"connector\"];\n let modulePath: string;\n const spec = source != null ? classifySource(source) : null;\n if (source != null && spec == null) {\n return fail(\n `\"${source}\" is not a local path or a recognizable GitHub source ` +\n \"(owner/repo[/subpath][#ref], a github.com URL, git@github.com:…, or github:owner/repo).\",\n );\n }\n if (spec != null && spec.kind === \"remote\") {\n try {\n const resolved = await resolveRemoteSource(spec.remote);\n ({ connector, modulePath } = resolved);\n } catch (err) {\n return fail(err instanceof Error ? err.message : String(err));\n }\n } else {\n const configPath = source ?? findConnectorConfig(projectDir);\n if (!configPath) {\n return fail(\n \"no connector config found. Pass a <source> (local path or owner/repo) or \" +\n \"--connector <path>, or add an agent-connector.config.{mjs,js,json} to your project.\",\n );\n }\n ({ connector, modulePath } = await loadConnectorFromPath(configPath));\n }\n\n const targets = parseTargets(values.targets);\n\n const result =\n method === \"marketplace\"\n ? await installViaMarketplace({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n ...(targets ? { targets } : {}),\n })\n : await installConnector({\n connector,\n modulePath,\n scope,\n projectDir,\n dryRun: values[\"dry-run\"],\n force: values.force,\n ...(targets ? { targets } : {}),\n });\n\n result.connector = buildConnectorSummary(connector);\n print(renderInstallResult(result, \"install\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n","/**\n * core/fetch-source — resolve an `install <source>` argument that may be a\n * LOCAL path OR a REMOTE GitHub spec into a local connector-config path.\n *\n * Responsibilities (MVP):\n * 1. CLASSIFY a source string as local-path vs. remote GitHub spec. A value\n * that exists on disk, or that looks like a filesystem path (starts with\n * `.`, `/`, `~`, a `file://` URL, or a Windows drive/UNC), stays LOCAL and\n * keeps today's behavior. Everything else is parsed as a remote spec.\n * 2. PARSE the supported GitHub forms into { owner, repo, ref?, subpath? }:\n * owner/repo · owner/repo#ref · owner/repo/sub · owner/repo/sub#ref\n * github:owner/repo · https://github.com/owner/repo[/tree/ref/sub]\n * git@github.com:owner/repo.git · the .git suffix on any of the above.\n * 3. FETCH + PERSIST the repo to a STABLE cache dir under the data-root\n * (`sources/<owner>__<repo>[__<ref>]/`), NOT a temp dir, so a connector\n * with a local stdio server keeps resolving after install. Re-fetch updates\n * it. `git clone --depth 1` is preferred; a codeload tarball is the\n * fallback when `git` is unavailable.\n * 4. GATE: the fetched (sub)dir MUST contain an `agent-connector.config.*`\n * that loads — otherwise the target is not an agent-connector connector.\n *\n * The actual fetch is injected via a {@link Fetcher} seam so tests can drive the\n * pipeline against a `file://` git fixture without any real network/GitHub hit.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n\nimport { findConnectorConfig, loadConnectorFromPath } from \"./load-connector.js\";\nimport { sourcesDir } from \"./paths.js\";\nimport type { ResolvedConnector } from \"./types.js\";\n\n/** A parsed remote source to fetch (a GitHub spec, or a raw git clone URL such\n * as `file://`/`ssh://`/`git@…`). `ref` is a branch/tag/sha; `subpath` is the\n * directory within the repo that holds the connector config. */\nexport interface RemoteSource {\n owner: string;\n repo: string;\n /** Branch / tag / commit. Undefined → the repo default branch. */\n ref?: string;\n /** Sub-directory inside the repo holding the connector config. */\n subpath?: string;\n /**\n * A raw clone URL (file://, ssh://, git@host:…, https://non-github) when the\n * source is NOT a github.com owner/repo we can derive a URL for. Present → the\n * tarball fallback is unavailable (we can only `git clone` it).\n */\n cloneUrl?: string;\n}\n\n/** The classification of an `install <source>` argument. */\nexport type SourceSpec =\n | { kind: \"local\"; value: string }\n | { kind: \"remote\"; remote: RemoteSource };\n\nconst GITHUB_SEG = /^[A-Za-z0-9._-]+$/;\n\n/**\n * True when `value` should be treated as a LOCAL path (existing behavior),\n * before any remote-spec parse is attempted. Conservative on purpose: a path\n * that exists wins, and the common path sigils (`.`, `/`, `~`, `file://`, a\n * Windows drive letter or UNC) are local even when nothing is on disk yet.\n */\nexport function looksLocal(value: string): boolean {\n if (value === \"\") return true;\n if (existsSync(value)) return true;\n if (\n value.startsWith(\"./\") ||\n value.startsWith(\"../\") ||\n value === \".\" ||\n value === \"..\" ||\n value.startsWith(\"/\") ||\n value.startsWith(\"~\") ||\n value.startsWith(\"file://\")\n ) {\n return true;\n }\n // Windows drive (C:\\ or C:/) or UNC (\\\\server\\share).\n if (/^[A-Za-z]:[\\\\/]/.test(value) || value.startsWith(\"\\\\\\\\\")) return true;\n return false;\n}\n\n/**\n * Parse a remote GitHub spec into a {@link RemoteSource}, or null when `value`\n * is not a recognizable GitHub source. Supports the bare `owner/repo[/sub][#ref]`\n * shorthand, `github:owner/repo`, full `https://github.com/...` (incl.\n * `/tree/<ref>/<subpath>`), and `git@github.com:owner/repo.git`.\n */\nexport function parseRemoteSource(value: string): RemoteSource | null {\n const raw = value.trim();\n if (raw === \"\") return null;\n\n // ── git@github.com:owner/repo(.git) ───────────────────────────────────────\n const scp = raw.match(/^git@github\\.com:([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (scp) {\n return finalizeFromPath(scp[1]!, scp[2]!, undefined);\n }\n\n // ── https://github.com/owner/repo[/tree/<ref>/<subpath>][.git][#ref] ───────\n if (/^https?:\\/\\//i.test(raw) || raw.startsWith(\"git://\")) {\n let url: URL;\n try {\n url = new URL(raw.replace(/^git:\\/\\//, \"https://\"));\n } catch {\n return null;\n }\n if (!/(^|\\.)github\\.com$/i.test(url.hostname)) return null;\n const segs = url.pathname.replace(/^\\/+/, \"\").split(\"/\").filter(Boolean);\n if (segs.length < 2) return null;\n const owner = segs[0]!;\n let repo = segs[1]!.replace(/\\.git$/, \"\");\n let ref: string | undefined;\n let subpath: string | undefined;\n // /tree/<ref>/<subpath...> selects a ref + sub-directory.\n if (segs[2] === \"tree\" || segs[2] === \"blob\") {\n ref = segs[3];\n if (segs.length > 4) subpath = segs.slice(4).join(\"/\");\n } else if (segs.length > 2) {\n subpath = segs.slice(2).join(\"/\");\n }\n const hash = url.hash.replace(/^#/, \"\");\n if (hash) ref = hash;\n if (!GITHUB_SEG.test(owner) || !GITHUB_SEG.test(repo)) return null;\n return cleanRemote({ owner, repo, ref, subpath });\n }\n\n // ── github:owner/repo[...] ────────────────────────────────────────────────\n const shorthand = raw.startsWith(\"github:\") ? raw.slice(\"github:\".length) : raw;\n\n // ── owner/repo[/subpath][#ref] ────────────────────────────────────────────\n // Reject anything that doesn't look like the bare `owner/repo` shape (a single\n // path segment, or a leading slash) so we never misread a stray token.\n const [pathPart, refPart] = splitHash(shorthand);\n const segs = pathPart.split(\"/\").filter(Boolean);\n if (segs.length < 2) return null;\n const owner = segs[0]!;\n const repo = segs[1]!.replace(/\\.git$/, \"\");\n const subpath = segs.length > 2 ? segs.slice(2).join(\"/\") : undefined;\n if (!GITHUB_SEG.test(owner) || !GITHUB_SEG.test(repo)) return null;\n return cleanRemote({ owner, repo, ref: refPart, subpath });\n}\n\n/** Split a \"<path>#<ref>\" into [path, ref?]. */\nfunction splitHash(value: string): [string, string | undefined] {\n const i = value.indexOf(\"#\");\n if (i === -1) return [value, undefined];\n const ref = value.slice(i + 1).trim();\n return [value.slice(0, i), ref === \"\" ? undefined : ref];\n}\n\n/** scp-form helper: the repo half may itself carry `/sub` and `#ref`. */\nfunction finalizeFromPath(owner: string, repoAndRest: string, _ref: undefined): RemoteSource | null {\n const [pathPart, ref] = splitHash(repoAndRest);\n const segs = pathPart.split(\"/\").filter(Boolean);\n const repo = (segs[0] ?? \"\").replace(/\\.git$/, \"\");\n const subpath = segs.length > 1 ? segs.slice(1).join(\"/\") : undefined;\n if (!GITHUB_SEG.test(owner) || !GITHUB_SEG.test(repo)) return null;\n return cleanRemote({ owner, repo, ref, subpath });\n}\n\n/**\n * A git-refname-safe ref charset: branch/tag/sha names plus the `/`, `.`, `_`,\n * `-` they may contain. A LEADING `-` is rejected so a ref can never be read as\n * a git flag (e.g. `--upload-pack=…`) when passed to `git clone --branch`, and\n * the constrained charset keeps cache-dir names clean. Empty is invalid.\n */\nconst REF_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;\n\n/** True when `ref` is a safe git refname (defense-in-depth before exec). */\nexport function isSafeRef(ref: string): boolean {\n return REF_RE.test(ref);\n}\n\n/**\n * Drop empty optional fields so equality/snapshot comparisons stay clean.\n * Returns null when a present `ref` is not git-refname-safe (defense-in-depth:\n * never pass an attacker-shaped ref to `git clone --branch`).\n */\nfunction cleanRemote(r: RemoteSource): RemoteSource | null {\n if (r.ref !== undefined && !isSafeRef(r.ref)) return null;\n const out: RemoteSource = { owner: r.owner, repo: r.repo };\n if (r.ref) out.ref = r.ref;\n if (r.subpath && r.subpath !== \"\") out.subpath = r.subpath;\n return out;\n}\n\n/**\n * Parse a RAW git clone URL (NOT a github.com owner/repo): `file://…`,\n * `ssh://…`, `git@host:owner/repo`, or `https://<non-github>/…`. These are\n * `git clone`-able directly. A trailing `#ref` selects a branch/tag/sha. These\n * forms point at a repo root (no in-URL subpath). Returns null for anything\n * that isn't a clone URL.\n */\nexport function parseGitUrl(value: string): RemoteSource | null {\n const [urlPart, ref] = splitHash(value.trim());\n const isScheme =\n urlPart.startsWith(\"file://\") ||\n urlPart.startsWith(\"ssh://\") ||\n urlPart.startsWith(\"git://\") ||\n /^https?:\\/\\//i.test(urlPart);\n const isScp = /^[^@\\s]+@[^:\\s]+:.+/.test(urlPart) && !urlPart.startsWith(\"git@github.com:\");\n if (!isScheme && !isScp) return null;\n // Reject an unsafe ref (e.g. a leading-dash flag) before it reaches git.\n if (ref !== undefined && !isSafeRef(ref)) return null;\n\n // Derive a stable owner/repo cache key from the URL's last two path segments.\n const stripped = urlPart.replace(/\\.git$/, \"\").replace(/\\/+$/, \"\");\n const segs = stripped.split(/[/:]/).filter(Boolean);\n const repo = segs[segs.length - 1] ?? \"repo\";\n const owner = segs[segs.length - 2] ?? \"git\";\n const out: RemoteSource = { owner, repo, cloneUrl: urlPart };\n if (ref) out.ref = ref;\n return out;\n}\n\n/**\n * Classify an `install <source>` argument. A raw git clone URL (file://, ssh://,\n * git@…) or a GitHub spec is REMOTE (a fetch); a local FILESYSTEM path (existing\n * or path-shaped, EXCLUDING file:// which is a clone URL) keeps today's\n * behavior. Returns null when a non-local value is NOT a recognizable remote.\n */\nexport function classifySource(value: string): SourceSpec | null {\n // A raw git clone URL (incl. file://) is always a FETCH, never a config path —\n // even though file:// is \"path-shaped\" it names a clonable repo, not a config.\n const gitUrl = parseGitUrl(value);\n if (gitUrl) return { kind: \"remote\", remote: gitUrl };\n if (looksLocal(value)) return { kind: \"local\", value };\n const remote = parseRemoteSource(value);\n return remote ? { kind: \"remote\", remote } : null;\n}\n\n/** The clone URL for a remote source (its raw cloneUrl, else the github URL). */\nexport function cloneUrl(r: RemoteSource): string {\n return r.cloneUrl ?? `https://github.com/${r.owner}/${r.repo}.git`;\n}\n\n/** The codeload tarball URL for a github source (default branch when no ref). */\nexport function tarballUrl(r: RemoteSource): string {\n const ref = r.ref ?? \"HEAD\";\n return `https://codeload.github.com/${r.owner}/${r.repo}/tar.gz/${ref}`;\n}\n\n/** The STABLE cache directory a remote source is fetched into. */\nexport function sourceCacheDir(r: RemoteSource): string {\n const safe = (s: string) => s.replace(/[^A-Za-z0-9._-]/g, \"-\");\n // A raw clone URL hashes its full URL into the key so two different file://\n // repos that share an owner/repo basename never collide in the cache.\n const base = r.cloneUrl\n ? `${safe(r.owner)}__${safe(r.repo)}__${shortHash(r.cloneUrl)}`\n : `${safe(r.owner)}__${safe(r.repo)}`;\n const name = r.ref ? `${base}__${safe(r.ref)}` : base;\n return join(sourcesDir(), name);\n}\n\n/** A short, filename-safe hash for disambiguating raw clone URLs in the cache. */\nfunction shortHash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 8);\n}\n\n/**\n * A fetcher fetches `remote` into the stable directory `dest`. Injected so tests\n * can drive the resolve pipeline against a `file://` git fixture (no network).\n * The default {@link gitFetcher} clones over HTTPS.\n */\nexport type Fetcher = (remote: RemoteSource, dest: string) => void | Promise<void>;\n\n/** True when a usable `git` is on PATH (probed once per process via a cheap call). */\nfunction gitAvailable(): boolean {\n try {\n execFileSync(\"git\", [\"--version\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The default fetcher: `git clone --depth 1 [--branch <ref>] <url> <dest>`.\n * Re-fetch replaces the cache dir so the clone reflects the requested ref. The\n * caller may override the clone URL via `urlFor` (tests pass a `file://` repo).\n */\nexport function makeGitFetcher(urlFor: (r: RemoteSource) => string = cloneUrl): Fetcher {\n return (remote, dest) => {\n if (!gitAvailable()) {\n throw new Error(\n \"git is required to fetch a remote connector source but was not found on PATH. \" +\n \"Install git, or pass a local --connector <path>.\",\n );\n }\n rmSync(dest, { recursive: true, force: true });\n mkdirSync(dest, { recursive: true });\n const args = [\"clone\", \"--depth\", \"1\"];\n if (remote.ref) args.push(\"--branch\", remote.ref);\n args.push(urlFor(remote), dest);\n try {\n execFileSync(\"git\", args, { stdio: \"ignore\" });\n } catch (err) {\n throw new Error(\n `failed to clone ${urlFor(remote)}${remote.ref ? ` (ref ${remote.ref})` : \"\"}: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n };\n}\n\n/**\n * Tarball fallback: download the GitHub codeload `tar.gz` and extract it with\n * the system `tar` (present on Linux, macOS, and Windows 10+). codeload nests\n * everything under a single `<repo>-<ref>/` top dir, which we flatten into\n * `dest`. Used only when `git` is unavailable.\n */\nasync function tarballFetch(remote: RemoteSource, dest: string): Promise<void> {\n const url = tarballUrl(remote);\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`failed to download ${url}: HTTP ${res.status} ${res.statusText}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n\n const work = join(tmpdir(), `ac-src-${process.pid}-${Date.now()}`);\n mkdirSync(work, { recursive: true });\n const tarPath = join(work, \"source.tar.gz\");\n writeFileSync(tarPath, buf);\n try {\n execFileSync(\"tar\", [\"-xzf\", tarPath, \"-C\", work], { stdio: \"ignore\" });\n } catch (err) {\n rmSync(work, { recursive: true, force: true });\n throw new Error(\n \"neither git nor a usable `tar` is available to fetch a remote connector \" +\n `source (${err instanceof Error ? err.message : String(err)}). Install git ` +\n \"or tar, or pass a local --connector <path>.\",\n );\n }\n // codeload nests under a single `<repo>-<ref>/` directory — flatten it.\n const entries = readdirSync(work).filter((e) => e !== \"source.tar.gz\");\n const top = entries.length === 1 ? join(work, entries[0]!) : work;\n rmSync(dest, { recursive: true, force: true });\n renameSync(top, dest);\n rmSync(work, { recursive: true, force: true });\n}\n\n/**\n * The default network fetcher: `git clone` when git is on PATH, otherwise the\n * codeload tarball fallback (github.com sources only — a raw clone URL can only\n * be `git clone`d, so it requires git). A clear error is thrown when neither\n * applicable path works.\n */\nexport const gitFetcher: Fetcher = async (remote, dest) => {\n if (gitAvailable()) {\n makeGitFetcher()(remote, dest);\n return;\n }\n if (remote.cloneUrl) {\n throw new Error(\n `git is required to fetch ${remote.cloneUrl} but was not found on PATH. ` +\n \"Install git, or pass a local --connector <path>.\",\n );\n }\n await tarballFetch(remote, dest);\n};\n\n/** The resolved output of {@link resolveRemoteSource}. */\nexport interface ResolvedSource {\n /** Absolute path to the agent-connector.config.* found inside the fetch. */\n configPath: string;\n /** The directory the source was fetched into (stable, under the data-root). */\n sourceDir: string;\n /** The (sub)directory the config was found in. */\n connectorDir: string;\n /** The live connector + its absolute module path (ready for the install flow). */\n connector: ResolvedConnector;\n modulePath: string;\n}\n\n/** Options for {@link resolveRemoteSource}. */\nexport interface ResolveOptions {\n /** Override the fetch (tests). Defaults to {@link gitFetcher}. */\n fetcher?: Fetcher;\n}\n\n/**\n * Fetch a remote source into its stable cache dir, honor the subpath, and GATE\n * it as a real agent-connector package: `findConnectorConfig` must locate an\n * `agent-connector.config.{mjs,js,json}` that `loadConnectorFromPath` can load.\n * Throws a clear, specific error when the target is not an agent-connector\n * connector. Returns everything the install flow needs.\n */\nexport async function resolveRemoteSource(\n remote: RemoteSource,\n opts: ResolveOptions = {},\n): Promise<ResolvedSource> {\n const fetcher = opts.fetcher ?? gitFetcher;\n const sourceDir = sourceCacheDir(remote);\n mkdirSync(sourcesDir(), { recursive: true });\n await fetcher(remote, sourceDir);\n\n const label = describeRemote(remote);\n if (!existsSync(sourceDir)) {\n throw new Error(`failed to fetch ${label}: nothing was written to ${sourceDir}`);\n }\n\n // Honor the subpath; guard against a `..` escape out of the fetched dir.\n // Containment is checked with path.relative (NOT a bare string prefix, which\n // a sibling dir sharing the cache-key prefix would defeat) — mirroring the\n // connectorDir() guard in paths.ts: reject when the relative path is empty,\n // starts with \"..\", or is absolute.\n const root = resolve(sourceDir);\n const searchDir = remote.subpath ? resolve(root, remote.subpath) : root;\n if (remote.subpath) {\n const rel = relative(root, searchDir);\n if (rel === \"\" || rel.startsWith(\"..\") || isAbsolute(rel)) {\n throw new Error(`subpath escapes the fetched source: ${remote.subpath}`);\n }\n }\n if (!existsSync(searchDir)) {\n throw new Error(\n `${label}: subpath \"${remote.subpath}\" does not exist in the repository.`,\n );\n }\n\n // ── PACKAGE GATE ──────────────────────────────────────────────────────────\n // Search only WITHIN the fetched (sub)dir. findConnectorConfig walks UPWARD to\n // the filesystem root, so confine the start dir and verify the hit is inside.\n const configPath = findConfigWithin(searchDir);\n if (!configPath) {\n throw new Error(\n `${label} is not an agent-connector connector — no ` +\n `agent-connector.config.{mjs,js,json} found in the repo` +\n (remote.subpath ? ` at subpath \"${remote.subpath}\"` : \"\") +\n \". The target must be a package built with agent-connector (defineConnector).\",\n );\n }\n\n let connector: ResolvedConnector;\n let modulePath: string;\n try {\n ({ connector, modulePath } = await loadConnectorFromPath(configPath));\n } catch (err) {\n throw new Error(\n `${label}: found ${configPath} but it failed to load as an agent-connector ` +\n `connector (${err instanceof Error ? err.message : String(err)}). The target ` +\n \"must be a package built with agent-connector (defineConnector).\",\n );\n }\n\n return {\n configPath,\n sourceDir,\n connectorDir: searchDir,\n connector,\n modulePath,\n };\n}\n\n/**\n * Locate `agent-connector.config.*` strictly within `dir` (not its ancestors).\n * `findConnectorConfig` walks upward, so we scope the result by asserting the\n * hit is in `dir` itself.\n */\nfunction findConfigWithin(dir: string): string | null {\n const hit = findConnectorConfig(dir);\n if (!hit) return null;\n // Must live directly in the (sub)dir we were pointed at — reject an ancestor\n // hit so a parent dir's config can't masquerade as the repo's.\n const dirAbs = resolve(dir);\n const hitDir = resolve(hit, \"..\");\n return hitDir === dirAbs ? hit : null;\n}\n\n/** A human label for a remote source used in error messages. */\nexport function describeRemote(r: RemoteSource): string {\n let s = r.cloneUrl ?? `${r.owner}/${r.repo}`;\n if (r.subpath) s += `/${r.subpath}`;\n if (r.ref) s += `#${r.ref}`;\n return s;\n}\n"],"mappings":"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","names":["segs","owner","repo","subpath"]}
|
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter,
|
|
7
7
|
renderSkillMd
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-WFEHWTLM.js";
|
|
9
9
|
import {
|
|
10
10
|
buildHomeBinHookCommand,
|
|
11
11
|
isHomeBinHookCommand
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-4NHXLXSD.js";
|
|
13
|
+
import "./chunk-M2H7JURF.js";
|
|
14
|
+
import "./chunk-GZGLCCEE.js";
|
|
15
15
|
|
|
16
16
|
// src/adapters/jetbrains-copilot/index.ts
|
|
17
17
|
import { existsSync } from "fs";
|
|
@@ -26,6 +26,7 @@ var EVENT_MAP = {
|
|
|
26
26
|
SessionEnd: "SessionEnd",
|
|
27
27
|
UserPromptSubmit: "UserPromptSubmit"
|
|
28
28
|
};
|
|
29
|
+
var WORKSPACE_SCOPE_DETAIL = "JetBrains Copilot hooks and content are workspace-scoped (.github); rerun with --scope project to install them.";
|
|
29
30
|
var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
30
31
|
id = HOST;
|
|
31
32
|
name = "JetBrains Copilot";
|
|
@@ -188,6 +189,9 @@ var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
|
188
189
|
}
|
|
189
190
|
];
|
|
190
191
|
}
|
|
192
|
+
if (ctx.scope === "user") {
|
|
193
|
+
return [{ platform: this.id, action: "warn", detail: WORKSPACE_SCOPE_DETAIL }];
|
|
194
|
+
}
|
|
191
195
|
const hooksPath = this.getHookConfigPath(ctx);
|
|
192
196
|
const symlink = this.symlinkPathWarning(hooksPath);
|
|
193
197
|
if (symlink) return [symlink];
|
|
@@ -392,6 +396,9 @@ var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
|
392
396
|
if (connector.commands.length === 0) {
|
|
393
397
|
return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
|
|
394
398
|
}
|
|
399
|
+
if (ctx.scope === "user") {
|
|
400
|
+
return [{ platform: this.id, action: "warn", detail: WORKSPACE_SCOPE_DETAIL }];
|
|
401
|
+
}
|
|
395
402
|
return connector.commands.map(
|
|
396
403
|
(cmd) => this.writeContentFile(
|
|
397
404
|
this.commandPath(ctx, cmd.name),
|
|
@@ -429,6 +436,9 @@ var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
|
429
436
|
if (connector.skills.length === 0) {
|
|
430
437
|
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
431
438
|
}
|
|
439
|
+
if (ctx.scope === "user") {
|
|
440
|
+
return [{ platform: this.id, action: "warn", detail: WORKSPACE_SCOPE_DETAIL }];
|
|
441
|
+
}
|
|
432
442
|
const changes = [];
|
|
433
443
|
for (const skill of connector.skills) {
|
|
434
444
|
const dir = this.skillDir(ctx, skill.name);
|
|
@@ -493,6 +503,12 @@ var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
|
493
503
|
if (hookEvents.length === 0) {
|
|
494
504
|
return { status: "OK", detail: "no hooks declared" };
|
|
495
505
|
}
|
|
506
|
+
if (ctx.scope === "user") {
|
|
507
|
+
return {
|
|
508
|
+
status: "OK",
|
|
509
|
+
detail: "hooks are workspace-scoped; install them with --scope project"
|
|
510
|
+
};
|
|
511
|
+
}
|
|
496
512
|
const file = this.readJson(hooksPath);
|
|
497
513
|
if (!file) return { status: "FAIL", detail: `not found: ${hooksPath}` };
|
|
498
514
|
if (file.version !== JETBRAINS_HOOKS_VERSION) {
|
|
@@ -514,14 +530,14 @@ var JetBrainsCopilotAdapter = class extends BaseAdapter {
|
|
|
514
530
|
const p = this.commandPath(ctx, cmd.name);
|
|
515
531
|
checks.push({
|
|
516
532
|
name: `${this.name}: command ${cmd.name} present`,
|
|
517
|
-
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
533
|
+
check: () => ctx.scope === "user" ? { status: "OK", detail: "commands are workspace-scoped; install them with --scope project" } : existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
518
534
|
});
|
|
519
535
|
}
|
|
520
536
|
for (const skill of ctx.connector.skills) {
|
|
521
537
|
const p = join(this.skillDir(ctx, skill.name), "SKILL.md");
|
|
522
538
|
checks.push({
|
|
523
539
|
name: `${this.name}: skill ${skill.name} present`,
|
|
524
|
-
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
540
|
+
check: () => ctx.scope === "user" ? { status: "OK", detail: "skills are workspace-scoped; install them with --scope project" } : existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
525
541
|
});
|
|
526
542
|
}
|
|
527
543
|
return checks;
|
|
@@ -694,4 +710,4 @@ export {
|
|
|
694
710
|
adapter,
|
|
695
711
|
jetbrains_copilot_default as default
|
|
696
712
|
};
|
|
697
|
-
//# sourceMappingURL=jetbrains-copilot-
|
|
713
|
+
//# sourceMappingURL=jetbrains-copilot-FXZ5AOTS.js.map
|