@ken-jo/agent-connector 0.3.0 → 0.4.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/README.md +188 -20
- package/dist/action-PLZW5BGX.js +54 -0
- package/dist/action-PLZW5BGX.js.map +1 -0
- package/dist/{amp-YGV66GJT.js → amp-B524U6LO.js} +81 -5
- package/dist/amp-B524U6LO.js.map +1 -0
- package/dist/{antigravity-7IBYFO6P.js → antigravity-ANDKF3K7.js} +4 -4
- package/dist/{antigravity-cli-JEOUP2VN.js → antigravity-cli-LLRPDDOT.js} +4 -4
- package/dist/chunk-22Y24V7O.js +21 -0
- package/dist/chunk-22Y24V7O.js.map +1 -0
- package/dist/chunk-3PFFTFCU.js +190 -0
- package/dist/chunk-3PFFTFCU.js.map +1 -0
- package/dist/{chunk-SCVBYSF7.js → chunk-6XHB6BE3.js} +1 -1
- package/dist/chunk-76FUSVIA.js +43 -0
- package/dist/chunk-76FUSVIA.js.map +1 -0
- package/dist/{chunk-GSGDG2BV.js → chunk-ADTHT2FN.js} +109 -16
- package/dist/chunk-ADTHT2FN.js.map +1 -0
- package/dist/{chunk-ZAM4M7LI.js → chunk-BHUCB6LY.js} +135 -296
- package/dist/chunk-BHUCB6LY.js.map +1 -0
- package/dist/{chunk-MEH7GC7R.js → chunk-BXGFUENQ.js} +20 -3
- package/dist/chunk-BXGFUENQ.js.map +1 -0
- package/dist/chunk-CIRDOY2V.js +351 -0
- package/dist/chunk-CIRDOY2V.js.map +1 -0
- package/dist/{chunk-QADSG2JY.js → chunk-G3ER4SY5.js} +1152 -106
- package/dist/chunk-G3ER4SY5.js.map +1 -0
- package/dist/{chunk-44HUXXC6.js → chunk-G5CQHVQG.js} +232 -5
- package/dist/chunk-G5CQHVQG.js.map +1 -0
- package/dist/{chunk-PD4VFEBY.js → chunk-IW77FFNX.js} +39 -1
- package/dist/chunk-IW77FFNX.js.map +1 -0
- package/dist/chunk-J3D5W5T2.js +83 -0
- package/dist/chunk-J3D5W5T2.js.map +1 -0
- package/dist/{openclaw-UZ5BMCGQ.js → chunk-KGGBNKI4.js} +125 -33
- package/dist/chunk-KGGBNKI4.js.map +1 -0
- package/dist/{chunk-3JCRUROU.js → chunk-KGJWE6A2.js} +13 -4
- package/dist/chunk-KGJWE6A2.js.map +1 -0
- package/dist/{chunk-DS3LUFVN.js → chunk-KGXDYGNJ.js} +26 -16
- package/dist/chunk-KGXDYGNJ.js.map +1 -0
- package/dist/{chunk-KVAAFYRR.js → chunk-KHO5WNTP.js} +2 -18
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/{chunk-KQSNDFBN.js → chunk-LL4OBGRU.js} +3 -3
- package/dist/{chunk-WNREHWKL.js → chunk-MAH6QQTO.js} +3 -3
- package/dist/{claude-code-4275HQU4.js → claude-code-MLWS7CW6.js} +180 -28
- package/dist/claude-code-MLWS7CW6.js.map +1 -0
- package/dist/cli/sdk.js +4 -3
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/{codebuff-LE3KBZGM.js → codebuff-SH2S3QAN.js} +102 -5
- package/dist/codebuff-SH2S3QAN.js.map +1 -0
- package/dist/{codex-4BY2ZJIW.js → codex-BXA4FIF4.js} +3 -3
- package/dist/{copilot-cli-IPISKO3V.js → copilot-cli-ROIBTTDT.js} +3 -3
- package/dist/{crush-X3E25EQG.js → crush-QLEFLHUC.js} +3 -3
- package/dist/{cursor-UH3W622V.js → cursor-ASJPWZ4R.js} +6 -3
- package/dist/cursor-ASJPWZ4R.js.map +1 -0
- package/dist/{detect-MNDHGLSV.js → detect-ZIIS55LD.js} +4 -3
- package/dist/{detect-MNDHGLSV.js.map → detect-ZIIS55LD.js.map} +1 -1
- package/dist/{doctor-N5KZDD55.js → doctor-TJUGSQ5C.js} +17 -13
- package/dist/doctor-TJUGSQ5C.js.map +1 -0
- package/dist/{droid-T5VBRXZF.js → droid-NCSS3B5Y.js} +170 -4
- package/dist/droid-NCSS3B5Y.js.map +1 -0
- package/dist/{gemini-cli-ZSUK55UA.js → gemini-cli-SLVWLXJW.js} +3 -3
- package/dist/{goose-M3RR3CZG.js → goose-PBA7KTE5.js} +100 -5
- package/dist/goose-PBA7KTE5.js.map +1 -0
- package/dist/{hermes-CUNKIAR5.js → hermes-ONDCECP2.js} +3 -3
- package/dist/{hook-7LUOKIXH.js → hook-OU522ABV.js} +12 -9
- package/dist/{hook-7LUOKIXH.js.map → hook-OU522ABV.js.map} +1 -1
- package/dist/index.d.ts +71 -3
- package/dist/index.js +22 -3
- package/dist/{install-TQTT4F3I.js → install-UDCBL7HP.js} +12 -10
- package/dist/{install-TQTT4F3I.js.map → install-UDCBL7HP.js.map} +1 -1
- package/dist/introspect-DuZSPSHB.d.ts +53 -0
- package/dist/{jetbrains-copilot-C3HDGGML.js → jetbrains-copilot-YABZ3HFA.js} +3 -3
- package/dist/{kilo-PKAJCWPX.js → kilo-F3ZDZKCT.js} +3 -3
- package/dist/{kilo-cli-QWUVXG2O.js → kilo-cli-3HWPWBY4.js} +3 -3
- package/dist/{kimi-EVD7YKXS.js → kimi-NV72FVAO.js} +3 -3
- package/dist/{kiro-UQRY6EIO.js → kiro-C5W6AGDR.js} +3 -3
- package/dist/{leaderboard-MUJ7DURM.js → leaderboard-TIBVONVT.js} +3 -3
- package/dist/mimo-code-IMM5YM3M.js +754 -0
- package/dist/mimo-code-IMM5YM3M.js.map +1 -0
- package/dist/{mux-5CI5FP2W.js → mux-DSSH4AFS.js} +3 -3
- package/dist/nemoclaw-3EVNKD3I.js +58 -0
- package/dist/nemoclaw-3EVNKD3I.js.map +1 -0
- package/dist/{omp-AXA7XY22.js → omp-Z6FRNDPN.js} +3 -3
- package/dist/openclaw-7G437NT7.js +18 -0
- package/dist/openclaw-7G437NT7.js.map +1 -0
- package/dist/{opencode-NZBRLJN3.js → opencode-Q6KBSAKW.js} +3 -3
- package/dist/{package-SYPA5POO.js → package-RMPN57YZ.js} +7 -6
- package/dist/{package-SYPA5POO.js.map → package-RMPN57YZ.js.map} +1 -1
- package/dist/{pi-WMTUX6ES.js → pi-LZT6WWAZ.js} +2 -2
- package/dist/{qwen-code-MRRIUQ3P.js → qwen-code-WQBKRPWJ.js} +3 -3
- package/dist/{roo-code-NI5UU6JB.js → roo-code-GWSNU3OW.js} +137 -4
- package/dist/roo-code-GWSNU3OW.js.map +1 -0
- package/dist/runtime/index.d.ts +96 -2
- package/dist/runtime/index.js +18 -10
- package/dist/sdk/index.d.ts +52 -0
- package/dist/sdk/index.js +81 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/test.d.ts +74 -0
- package/dist/sdk/test.js +291 -0
- package/dist/sdk/test.js.map +1 -0
- package/dist/{serve-XJOSA7BY.js → serve-D3GO36UT.js} +12 -9
- package/dist/{serve-XJOSA7BY.js.map → serve-D3GO36UT.js.map} +1 -1
- package/dist/{status-DYSS6BOR.js → status-KOSKCETC.js} +10 -8
- package/dist/{status-DYSS6BOR.js.map → status-KOSKCETC.js.map} +1 -1
- package/dist/statusline-ZNTCL5YC.js +59 -0
- package/dist/statusline-ZNTCL5YC.js.map +1 -0
- package/dist/{telemetry-IJ4GP2Q3.js → telemetry-XIKUUGTQ.js} +5 -4
- package/dist/{telemetry-IJ4GP2Q3.js.map → telemetry-XIKUUGTQ.js.map} +1 -1
- package/dist/{trae-CQC72RHH.js → trae-NWT3TMSZ.js} +99 -5
- package/dist/trae-NWT3TMSZ.js.map +1 -0
- package/dist/{types-CNigfEuR.d.ts → types-BEKsAium.d.ts} +268 -6
- package/dist/{uninstall-3DXIBRCV.js → uninstall-2LBLQVFA.js} +12 -10
- package/dist/{uninstall-3DXIBRCV.js.map → uninstall-2LBLQVFA.js.map} +1 -1
- package/dist/{upgrade-GJEB3ITY.js → upgrade-ZC2S7VRN.js} +12 -10
- package/dist/{upgrade-GJEB3ITY.js.map → upgrade-ZC2S7VRN.js.map} +1 -1
- package/dist/{usage-2BJLM3GJ.js → usage-E2A4O2CY.js} +3 -3
- package/dist/{usage-event-472X3DOY.js → usage-event-JKMC4QC4.js} +11 -8
- package/dist/{usage-event-472X3DOY.js.map → usage-event-JKMC4QC4.js.map} +1 -1
- package/dist/{vscode-copilot-4RVRTCKV.js → vscode-copilot-ALV45XF6.js} +3 -3
- package/dist/{warp-X6MB67NT.js → warp-H6IX4U3J.js} +3 -3
- package/dist/{zed-NTCYW4V2.js → zed-RH34TNSW.js} +3 -3
- package/package.json +9 -1
- package/dist/amp-YGV66GJT.js.map +0 -1
- package/dist/chunk-3JCRUROU.js.map +0 -1
- package/dist/chunk-44HUXXC6.js.map +0 -1
- package/dist/chunk-DS3LUFVN.js.map +0 -1
- package/dist/chunk-GSGDG2BV.js.map +0 -1
- package/dist/chunk-KVAAFYRR.js.map +0 -1
- package/dist/chunk-MEH7GC7R.js.map +0 -1
- package/dist/chunk-NJU275US.js +0 -238
- package/dist/chunk-NJU275US.js.map +0 -1
- package/dist/chunk-PD4VFEBY.js.map +0 -1
- package/dist/chunk-QADSG2JY.js.map +0 -1
- package/dist/chunk-ZAM4M7LI.js.map +0 -1
- package/dist/claude-code-4275HQU4.js.map +0 -1
- package/dist/codebuff-LE3KBZGM.js.map +0 -1
- package/dist/cursor-UH3W622V.js.map +0 -1
- package/dist/doctor-N5KZDD55.js.map +0 -1
- package/dist/droid-T5VBRXZF.js.map +0 -1
- package/dist/goose-M3RR3CZG.js.map +0 -1
- package/dist/openclaw-UZ5BMCGQ.js.map +0 -1
- package/dist/roo-code-NI5UU6JB.js.map +0 -1
- package/dist/trae-CQC72RHH.js.map +0 -1
- /package/dist/{antigravity-7IBYFO6P.js.map → antigravity-ANDKF3K7.js.map} +0 -0
- /package/dist/{antigravity-cli-JEOUP2VN.js.map → antigravity-cli-LLRPDDOT.js.map} +0 -0
- /package/dist/{chunk-SCVBYSF7.js.map → chunk-6XHB6BE3.js.map} +0 -0
- /package/dist/{chunk-KQSNDFBN.js.map → chunk-LL4OBGRU.js.map} +0 -0
- /package/dist/{chunk-WNREHWKL.js.map → chunk-MAH6QQTO.js.map} +0 -0
- /package/dist/{codex-4BY2ZJIW.js.map → codex-BXA4FIF4.js.map} +0 -0
- /package/dist/{copilot-cli-IPISKO3V.js.map → copilot-cli-ROIBTTDT.js.map} +0 -0
- /package/dist/{crush-X3E25EQG.js.map → crush-QLEFLHUC.js.map} +0 -0
- /package/dist/{gemini-cli-ZSUK55UA.js.map → gemini-cli-SLVWLXJW.js.map} +0 -0
- /package/dist/{hermes-CUNKIAR5.js.map → hermes-ONDCECP2.js.map} +0 -0
- /package/dist/{jetbrains-copilot-C3HDGGML.js.map → jetbrains-copilot-YABZ3HFA.js.map} +0 -0
- /package/dist/{kilo-PKAJCWPX.js.map → kilo-F3ZDZKCT.js.map} +0 -0
- /package/dist/{kilo-cli-QWUVXG2O.js.map → kilo-cli-3HWPWBY4.js.map} +0 -0
- /package/dist/{kimi-EVD7YKXS.js.map → kimi-NV72FVAO.js.map} +0 -0
- /package/dist/{kiro-UQRY6EIO.js.map → kiro-C5W6AGDR.js.map} +0 -0
- /package/dist/{leaderboard-MUJ7DURM.js.map → leaderboard-TIBVONVT.js.map} +0 -0
- /package/dist/{mux-5CI5FP2W.js.map → mux-DSSH4AFS.js.map} +0 -0
- /package/dist/{omp-AXA7XY22.js.map → omp-Z6FRNDPN.js.map} +0 -0
- /package/dist/{opencode-NZBRLJN3.js.map → opencode-Q6KBSAKW.js.map} +0 -0
- /package/dist/{pi-WMTUX6ES.js.map → pi-LZT6WWAZ.js.map} +0 -0
- /package/dist/{qwen-code-MRRIUQ3P.js.map → qwen-code-WQBKRPWJ.js.map} +0 -0
- /package/dist/{usage-2BJLM3GJ.js.map → usage-E2A4O2CY.js.map} +0 -0
- /package/dist/{vscode-copilot-4RVRTCKV.js.map → vscode-copilot-ALV45XF6.js.map} +0 -0
- /package/dist/{warp-X6MB67NT.js.map → warp-H6IX4U3J.js.map} +0 -0
- /package/dist/{zed-NTCYW4V2.js.map → zed-RH34TNSW.js.map} +0 -0
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
installInstructions,
|
|
4
4
|
packageConnector
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-MAH6QQTO.js";
|
|
6
6
|
import {
|
|
7
7
|
MARKETPLACE_NAME,
|
|
8
8
|
agyPluginInstalled,
|
|
9
9
|
agyStagingRoot,
|
|
10
10
|
anyClaudeAgentConnectorPlugins,
|
|
11
11
|
anyCodexAgentConnectorPlugins,
|
|
12
|
+
anyDroidAgentConnectorPlugins,
|
|
12
13
|
anyMarketplaceRecordsRemain,
|
|
13
14
|
claudeKnownMarketplacePath,
|
|
14
15
|
claudePluginInstalled,
|
|
@@ -19,29 +20,46 @@ import {
|
|
|
19
20
|
codexPluginKey,
|
|
20
21
|
codexStagingRoot,
|
|
21
22
|
connectorHasMarketplaceRecords,
|
|
23
|
+
droidMarketplaceSource,
|
|
24
|
+
droidPluginInstalled,
|
|
25
|
+
droidPluginKey,
|
|
26
|
+
droidStagingRoot,
|
|
27
|
+
geminiExtensionInstalled,
|
|
28
|
+
geminiStagingRoot,
|
|
22
29
|
hashDirectory,
|
|
23
30
|
marketplaceEvidence,
|
|
24
31
|
marketplaceRoot,
|
|
32
|
+
npmConfigFilePath,
|
|
33
|
+
npmPluginArrayEntry,
|
|
34
|
+
npmPluginInstalled,
|
|
35
|
+
npmStagingRoot,
|
|
36
|
+
qwenExtensionInstalled,
|
|
37
|
+
qwenStagingRoot,
|
|
25
38
|
readMarketplaceInstalls,
|
|
39
|
+
readNpmConfig,
|
|
26
40
|
writeMarketplaceInstalls
|
|
27
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-G5CQHVQG.js";
|
|
28
42
|
import {
|
|
29
|
-
log,
|
|
30
43
|
spawnChild
|
|
31
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-22Y24V7O.js";
|
|
32
45
|
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
detectInstalledPlatforms
|
|
47
|
+
} from "./chunk-J3D5W5T2.js";
|
|
48
|
+
import {
|
|
49
|
+
log
|
|
50
|
+
} from "./chunk-KHO5WNTP.js";
|
|
37
51
|
import {
|
|
38
52
|
deregisterConnector,
|
|
39
53
|
loadRegisteredConnector,
|
|
40
54
|
registerConnector
|
|
41
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-KGJWE6A2.js";
|
|
42
56
|
import {
|
|
43
57
|
configPatchManualEdit
|
|
44
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-ADTHT2FN.js";
|
|
59
|
+
import {
|
|
60
|
+
REGISTERED_PLATFORM_IDS,
|
|
61
|
+
loadAdapter
|
|
62
|
+
} from "./chunk-3PFFTFCU.js";
|
|
45
63
|
import {
|
|
46
64
|
hasMemoryLedger
|
|
47
65
|
} from "./chunk-N6HH7K6P.js";
|
|
@@ -67,7 +85,7 @@ async function installConnector(opts) {
|
|
|
67
85
|
log.warn(`ensureHomeBin failed: ${errMessage(err)}`);
|
|
68
86
|
}
|
|
69
87
|
try {
|
|
70
|
-
registerConnector(connector, modulePath);
|
|
88
|
+
registerConnector(connector, modulePath, scope);
|
|
71
89
|
} catch (err) {
|
|
72
90
|
log.warn(`registerConnector failed: ${errMessage(err)}`);
|
|
73
91
|
}
|
|
@@ -160,6 +178,16 @@ async function installConnector(opts) {
|
|
|
160
178
|
}
|
|
161
179
|
}
|
|
162
180
|
}
|
|
181
|
+
if (connector.statusline != null) {
|
|
182
|
+
runStep(id, "installStatusline", result, () => {
|
|
183
|
+
pushAll(result.changes, adapter.installStatusline(ctx));
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if ((connector.actions ?? []).length) {
|
|
187
|
+
runStep(id, "installActions", result, () => {
|
|
188
|
+
pushAll(result.changes, adapter.installActions(ctx));
|
|
189
|
+
});
|
|
190
|
+
}
|
|
163
191
|
}
|
|
164
192
|
return result;
|
|
165
193
|
}
|
|
@@ -182,6 +210,16 @@ async function uninstallConnector(opts) {
|
|
|
182
210
|
const adapter = await tryLoadAdapter(id, result);
|
|
183
211
|
if (!adapter) continue;
|
|
184
212
|
const ctx = buildContext(connector, id, scope, projectDir, dryRun);
|
|
213
|
+
if ((connector.actions ?? []).length) {
|
|
214
|
+
runStep(id, "uninstallActions", result, () => {
|
|
215
|
+
pushAll(result.changes, adapter.uninstallActions(ctx));
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (adapter.capabilities.supportsStatusline ?? false) {
|
|
219
|
+
runStep(id, "uninstallStatusline", result, () => {
|
|
220
|
+
pushAll(result.changes, adapter.uninstallStatusline(ctx));
|
|
221
|
+
});
|
|
222
|
+
}
|
|
185
223
|
if (adapter.capabilities.supportsConfigPatch ?? false) {
|
|
186
224
|
runStep(id, "uninstallConfigPatches", result, () => {
|
|
187
225
|
pushAll(result.changes, adapter.uninstallConfigPatches(ctx));
|
|
@@ -394,6 +432,7 @@ function syntheticConnector(id) {
|
|
|
394
432
|
skills: [],
|
|
395
433
|
subagents: [],
|
|
396
434
|
memory: [],
|
|
435
|
+
actions: [],
|
|
397
436
|
platforms: {},
|
|
398
437
|
targets: "auto"
|
|
399
438
|
};
|
|
@@ -409,15 +448,15 @@ function errMessage(err) {
|
|
|
409
448
|
}
|
|
410
449
|
|
|
411
450
|
// src/core/marketplace.ts
|
|
412
|
-
import { existsSync as
|
|
413
|
-
import { join as
|
|
451
|
+
import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync4, rmSync as rmSync9 } from "fs";
|
|
452
|
+
import { join as join10 } from "path";
|
|
414
453
|
|
|
415
454
|
// src/core/marketplace-drivers/claude.ts
|
|
416
455
|
import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync, rmSync as rmSync2, writeFileSync } from "fs";
|
|
417
456
|
import { dirname as dirname2, join as join3 } from "path";
|
|
418
457
|
|
|
419
458
|
// src/core/marketplace-drivers/shared.ts
|
|
420
|
-
import { existsSync as existsSync2, statSync } from "fs";
|
|
459
|
+
import { existsSync as existsSync2, realpathSync, statSync } from "fs";
|
|
421
460
|
import { delimiter, join as join2, resolve } from "path";
|
|
422
461
|
var HOST_COMMAND_TIMEOUT_MS = 3e4;
|
|
423
462
|
function findOnPath(command) {
|
|
@@ -437,7 +476,10 @@ function findOnPath(command) {
|
|
|
437
476
|
}
|
|
438
477
|
return null;
|
|
439
478
|
}
|
|
440
|
-
function runHostCommand(command, args,
|
|
479
|
+
function runHostCommand(command, args, optionsOrTimeout = HOST_COMMAND_TIMEOUT_MS) {
|
|
480
|
+
const opts = typeof optionsOrTimeout === "number" ? { timeoutMs: optionsOrTimeout } : optionsOrTimeout;
|
|
481
|
+
const timeoutMs = opts.timeoutMs ?? HOST_COMMAND_TIMEOUT_MS;
|
|
482
|
+
const cwd = opts.cwd;
|
|
441
483
|
return new Promise((resolvePromise) => {
|
|
442
484
|
let stdout = "";
|
|
443
485
|
let stderr = "";
|
|
@@ -453,7 +495,10 @@ function runHostCommand(command, args, timeoutMs = HOST_COMMAND_TIMEOUT_MS) {
|
|
|
453
495
|
try {
|
|
454
496
|
child = spawnChild(command, args, {
|
|
455
497
|
stdio: ["ignore", "pipe", "pipe"],
|
|
456
|
-
env: process.env
|
|
498
|
+
env: process.env,
|
|
499
|
+
// Only set cwd when a caller asked for it — omitting the key inherits
|
|
500
|
+
// the parent's cwd, keeping claude/codex/agy spawns byte-identical.
|
|
501
|
+
...cwd != null ? { cwd } : {}
|
|
457
502
|
});
|
|
458
503
|
} catch (err) {
|
|
459
504
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -512,7 +557,11 @@ function samePath(a, b) {
|
|
|
512
557
|
if (process.platform === "win32") {
|
|
513
558
|
s = s.replace(/^\\\\\?\\UNC\\/, "\\\\").replace(/^\\\\\?\\/, "");
|
|
514
559
|
}
|
|
515
|
-
|
|
560
|
+
try {
|
|
561
|
+
s = realpathSync.native(s);
|
|
562
|
+
} catch {
|
|
563
|
+
s = resolve(s);
|
|
564
|
+
}
|
|
516
565
|
return process.platform === "win32" ? s.toLowerCase() : s;
|
|
517
566
|
};
|
|
518
567
|
return norm(a) === norm(b);
|
|
@@ -1192,25 +1241,326 @@ var codexDriver = {
|
|
|
1192
1241
|
}
|
|
1193
1242
|
};
|
|
1194
1243
|
|
|
1195
|
-
// src/core/marketplace-drivers/
|
|
1196
|
-
import { existsSync as existsSync5, rmSync as rmSync4 } from "fs";
|
|
1244
|
+
// src/core/marketplace-drivers/droid.ts
|
|
1245
|
+
import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync3, rmSync as rmSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1197
1246
|
import { join as join5 } from "path";
|
|
1198
|
-
|
|
1199
|
-
|
|
1247
|
+
var PLATFORM3 = "droid";
|
|
1248
|
+
function droidBinary() {
|
|
1249
|
+
return findOnPath("droid");
|
|
1250
|
+
}
|
|
1251
|
+
function droidManualInstallCommands(connectorId, stagingRoot) {
|
|
1252
|
+
return `droid plugin marketplace add ${stagingRoot} && droid plugin install ${droidPluginKey(connectorId)}`;
|
|
1200
1253
|
}
|
|
1201
1254
|
function errMessage4(err) {
|
|
1202
1255
|
return err instanceof Error ? err.message : String(err);
|
|
1203
1256
|
}
|
|
1257
|
+
function warn3(detail, path) {
|
|
1258
|
+
return { platform: PLATFORM3, action: "warn", detail, ...path ? { path } : {} };
|
|
1259
|
+
}
|
|
1204
1260
|
function failDetail3(step, r) {
|
|
1205
1261
|
if (r.timedOut) return `${step} timed out`;
|
|
1206
1262
|
if (r.error) return `${step} failed to spawn: ${r.error}`;
|
|
1207
1263
|
const line = firstLine(r.stderr) || firstLine(r.stdout);
|
|
1208
1264
|
return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
|
|
1209
1265
|
}
|
|
1210
|
-
function
|
|
1211
|
-
|
|
1266
|
+
function stagedDroidPlugins(stagingRoot) {
|
|
1267
|
+
if (!existsSync5(stagingRoot)) return [];
|
|
1268
|
+
try {
|
|
1269
|
+
return readdirSync4(stagingRoot).filter(
|
|
1270
|
+
(name) => existsSync5(join5(stagingRoot, name, ".factory-plugin", "plugin.json"))
|
|
1271
|
+
).sort();
|
|
1272
|
+
} catch {
|
|
1273
|
+
return [];
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
function droidCatalogPath(stagingRoot) {
|
|
1277
|
+
return join5(stagingRoot, "marketplace.json");
|
|
1278
|
+
}
|
|
1279
|
+
function regenerateDroidCatalog(stagingRoot, changes) {
|
|
1280
|
+
const catalogPath = droidCatalogPath(stagingRoot);
|
|
1281
|
+
const plugins = stagedDroidPlugins(stagingRoot).map((name) => {
|
|
1282
|
+
let description = `${name} \u2014 connector emitted by agent-connector`;
|
|
1283
|
+
try {
|
|
1284
|
+
const manifest = JSON.parse(
|
|
1285
|
+
readFileSync3(join5(stagingRoot, name, ".factory-plugin", "plugin.json"), "utf8")
|
|
1286
|
+
);
|
|
1287
|
+
if (typeof manifest.description === "string") description = manifest.description;
|
|
1288
|
+
} catch {
|
|
1289
|
+
}
|
|
1290
|
+
return { name, source: `./${name}`, description };
|
|
1291
|
+
});
|
|
1292
|
+
const catalog = { name: MARKETPLACE_NAME, owner: { name: MARKETPLACE_NAME }, plugins };
|
|
1293
|
+
const serialized = `${JSON.stringify(catalog, null, 2)}
|
|
1294
|
+
`;
|
|
1295
|
+
let existing = null;
|
|
1296
|
+
try {
|
|
1297
|
+
existing = readFileSync3(catalogPath, "utf8");
|
|
1298
|
+
} catch {
|
|
1299
|
+
}
|
|
1300
|
+
if (existing === serialized) return;
|
|
1301
|
+
ensureDir(stagingRoot);
|
|
1302
|
+
writeFileSync3(catalogPath, serialized, "utf8");
|
|
1303
|
+
changes.push({
|
|
1304
|
+
platform: PLATFORM3,
|
|
1305
|
+
action: existing == null ? "create" : "update",
|
|
1306
|
+
path: catalogPath,
|
|
1307
|
+
detail: `regenerated shared marketplace catalog (${plugins.length} plugin(s))`
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
function stageDroidBundle(connector, changes) {
|
|
1311
|
+
const stagingRoot = droidStagingRoot();
|
|
1212
1312
|
const pluginDir = join5(stagingRoot, connector.id);
|
|
1213
1313
|
const existed = existsSync5(pluginDir);
|
|
1314
|
+
const result = packageConnector(connector, { outDir: stagingRoot, format: "factory-plugin" });
|
|
1315
|
+
changes.push({
|
|
1316
|
+
platform: PLATFORM3,
|
|
1317
|
+
action: existed ? "update" : "create",
|
|
1318
|
+
path: pluginDir,
|
|
1319
|
+
detail: `staged marketplace bundle (${result.files.length} files, factory-plugin)`
|
|
1320
|
+
});
|
|
1321
|
+
regenerateDroidCatalog(stagingRoot, changes);
|
|
1322
|
+
return { pluginDir, contentHash: hashDirectory(pluginDir) };
|
|
1323
|
+
}
|
|
1324
|
+
async function driveInstall2(connectorId) {
|
|
1325
|
+
const stagingRoot = droidStagingRoot();
|
|
1326
|
+
const changes = [];
|
|
1327
|
+
const pluginKey = droidPluginKey(connectorId);
|
|
1328
|
+
const bin = droidBinary();
|
|
1329
|
+
if (!bin) {
|
|
1330
|
+
changes.push(
|
|
1331
|
+
warn3(
|
|
1332
|
+
`droid CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${droidManualInstallCommands(connectorId, stagingRoot)}`,
|
|
1333
|
+
stagingRoot
|
|
1334
|
+
)
|
|
1335
|
+
);
|
|
1336
|
+
return { changes, ok: false };
|
|
1337
|
+
}
|
|
1338
|
+
const registeredAt = droidMarketplaceSource(MARKETPLACE_NAME);
|
|
1339
|
+
if (samePath(registeredAt, stagingRoot)) {
|
|
1340
|
+
changes.push({
|
|
1341
|
+
platform: PLATFORM3,
|
|
1342
|
+
action: "skip",
|
|
1343
|
+
path: stagingRoot,
|
|
1344
|
+
detail: `marketplace "${MARKETPLACE_NAME}" already registered`
|
|
1345
|
+
});
|
|
1346
|
+
} else if (registeredAt != null) {
|
|
1347
|
+
changes.push(
|
|
1348
|
+
warn3(
|
|
1349
|
+
`a marketplace named "${MARKETPLACE_NAME}" is already registered at ${registeredAt} (not ours) \u2014 refusing to touch it. Remove it first (droid plugin marketplace remove ${MARKETPLACE_NAME}) or install manually: ` + droidManualInstallCommands(connectorId, stagingRoot)
|
|
1350
|
+
)
|
|
1351
|
+
);
|
|
1352
|
+
return { changes, ok: false };
|
|
1353
|
+
} else {
|
|
1354
|
+
const add = await runHostCommand(bin, ["plugin", "marketplace", "add", stagingRoot]);
|
|
1355
|
+
if (!samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot)) {
|
|
1356
|
+
changes.push(
|
|
1357
|
+
warn3(
|
|
1358
|
+
`could not register the local marketplace \u2014 ` + failDetail3("droid plugin marketplace add", add) + `. Install manually: ${droidManualInstallCommands(connectorId, stagingRoot)}`,
|
|
1359
|
+
stagingRoot
|
|
1360
|
+
)
|
|
1361
|
+
);
|
|
1362
|
+
return { changes, ok: false };
|
|
1363
|
+
}
|
|
1364
|
+
changes.push({
|
|
1365
|
+
platform: PLATFORM3,
|
|
1366
|
+
action: "create",
|
|
1367
|
+
path: stagingRoot,
|
|
1368
|
+
detail: `registered local marketplace "${MARKETPLACE_NAME}" (droid plugin marketplace add)`
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
if (droidPluginInstalled(connectorId)) {
|
|
1372
|
+
changes.push({
|
|
1373
|
+
platform: PLATFORM3,
|
|
1374
|
+
action: "skip",
|
|
1375
|
+
detail: `plugin ${pluginKey} already installed`
|
|
1376
|
+
});
|
|
1377
|
+
return { changes, ok: true };
|
|
1378
|
+
}
|
|
1379
|
+
const install = await runHostCommand(bin, ["plugin", "install", pluginKey]);
|
|
1380
|
+
if (!install.ok || !droidPluginInstalled(connectorId)) {
|
|
1381
|
+
changes.push(
|
|
1382
|
+
warn3(`plugin install did not complete \u2014 ` + failDetail3(`droid plugin install ${pluginKey}`, install))
|
|
1383
|
+
);
|
|
1384
|
+
return { changes, ok: false };
|
|
1385
|
+
}
|
|
1386
|
+
changes.push({
|
|
1387
|
+
platform: PLATFORM3,
|
|
1388
|
+
action: "create",
|
|
1389
|
+
detail: `installed plugin ${pluginKey} (scope user)`
|
|
1390
|
+
});
|
|
1391
|
+
return { changes, ok: true };
|
|
1392
|
+
}
|
|
1393
|
+
async function driveUninstall2(connectorId) {
|
|
1394
|
+
const changes = [];
|
|
1395
|
+
const pluginKey = droidPluginKey(connectorId);
|
|
1396
|
+
if (!droidPluginInstalled(connectorId)) {
|
|
1397
|
+
changes.push({
|
|
1398
|
+
platform: PLATFORM3,
|
|
1399
|
+
action: "skip",
|
|
1400
|
+
detail: `plugin ${pluginKey} not installed on droid`
|
|
1401
|
+
});
|
|
1402
|
+
return { changes, ok: true };
|
|
1403
|
+
}
|
|
1404
|
+
const bin = droidBinary();
|
|
1405
|
+
if (!bin) {
|
|
1406
|
+
changes.push(
|
|
1407
|
+
warn3(
|
|
1408
|
+
`droid CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: droid plugin uninstall ${pluginKey}`
|
|
1409
|
+
)
|
|
1410
|
+
);
|
|
1411
|
+
return { changes, ok: false };
|
|
1412
|
+
}
|
|
1413
|
+
const remove = await runHostCommand(bin, ["plugin", "uninstall", pluginKey]);
|
|
1414
|
+
if (!remove.ok || droidPluginInstalled(connectorId)) {
|
|
1415
|
+
changes.push(
|
|
1416
|
+
warn3(`plugin uninstall did not complete \u2014 ` + failDetail3(`droid plugin uninstall ${pluginKey}`, remove))
|
|
1417
|
+
);
|
|
1418
|
+
return { changes, ok: false };
|
|
1419
|
+
}
|
|
1420
|
+
changes.push({
|
|
1421
|
+
platform: PLATFORM3,
|
|
1422
|
+
action: "remove",
|
|
1423
|
+
detail: `uninstalled plugin ${pluginKey} (droid plugin uninstall)`
|
|
1424
|
+
});
|
|
1425
|
+
return { changes, ok: true };
|
|
1426
|
+
}
|
|
1427
|
+
async function driveMarketplaceRemove2(stagingRoot) {
|
|
1428
|
+
const bin = droidBinary();
|
|
1429
|
+
if (!bin) {
|
|
1430
|
+
return [
|
|
1431
|
+
warn3(
|
|
1432
|
+
`droid CLI not found on PATH \u2014 marketplace registration "${MARKETPLACE_NAME}" left behind. Run manually: droid plugin marketplace remove ${MARKETPLACE_NAME}`,
|
|
1433
|
+
stagingRoot
|
|
1434
|
+
)
|
|
1435
|
+
];
|
|
1436
|
+
}
|
|
1437
|
+
const remove = await runHostCommand(bin, ["plugin", "marketplace", "remove", MARKETPLACE_NAME]);
|
|
1438
|
+
if (!remove.ok && droidMarketplaceSource(MARKETPLACE_NAME) != null) {
|
|
1439
|
+
return [
|
|
1440
|
+
warn3(
|
|
1441
|
+
`could not remove the marketplace registration \u2014 ` + failDetail3(`droid plugin marketplace remove ${MARKETPLACE_NAME}`, remove),
|
|
1442
|
+
stagingRoot
|
|
1443
|
+
)
|
|
1444
|
+
];
|
|
1445
|
+
}
|
|
1446
|
+
return [
|
|
1447
|
+
{
|
|
1448
|
+
platform: PLATFORM3,
|
|
1449
|
+
action: "remove",
|
|
1450
|
+
path: stagingRoot,
|
|
1451
|
+
detail: `removed marketplace registration "${MARKETPLACE_NAME}" (no plugins remain)`
|
|
1452
|
+
}
|
|
1453
|
+
];
|
|
1454
|
+
}
|
|
1455
|
+
var droidDriver = {
|
|
1456
|
+
platform: PLATFORM3,
|
|
1457
|
+
format: "factory-plugin",
|
|
1458
|
+
binary: droidBinary,
|
|
1459
|
+
stagingRoot: droidStagingRoot,
|
|
1460
|
+
pluginDir(id) {
|
|
1461
|
+
return join5(droidStagingRoot(), id);
|
|
1462
|
+
},
|
|
1463
|
+
installed: droidPluginInstalled,
|
|
1464
|
+
stage(connector, changes) {
|
|
1465
|
+
return stageDroidBundle(connector, changes).contentHash;
|
|
1466
|
+
},
|
|
1467
|
+
planInstall(connector, changes) {
|
|
1468
|
+
const stagingRoot = droidStagingRoot();
|
|
1469
|
+
const registered = samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot);
|
|
1470
|
+
changes.push({
|
|
1471
|
+
platform: PLATFORM3,
|
|
1472
|
+
action: registered ? "skip" : "create",
|
|
1473
|
+
path: stagingRoot,
|
|
1474
|
+
detail: registered ? `marketplace "${MARKETPLACE_NAME}" already registered` : `run: droid plugin marketplace add ${stagingRoot}`
|
|
1475
|
+
});
|
|
1476
|
+
changes.push({
|
|
1477
|
+
platform: PLATFORM3,
|
|
1478
|
+
action: droidPluginInstalled(connector.id) ? "skip" : "create",
|
|
1479
|
+
detail: droidPluginInstalled(connector.id) ? `plugin ${droidPluginKey(connector.id)} already installed` : `run: droid plugin install ${droidPluginKey(connector.id)}`
|
|
1480
|
+
});
|
|
1481
|
+
},
|
|
1482
|
+
planUninstall(id, changes) {
|
|
1483
|
+
const stagingRoot = droidStagingRoot();
|
|
1484
|
+
const pluginDir = join5(stagingRoot, id);
|
|
1485
|
+
const pluginKey = droidPluginKey(id);
|
|
1486
|
+
changes.push({
|
|
1487
|
+
platform: PLATFORM3,
|
|
1488
|
+
action: droidPluginInstalled(id) ? "remove" : "skip",
|
|
1489
|
+
detail: droidPluginInstalled(id) ? `run: droid plugin uninstall ${pluginKey}` : `plugin ${pluginKey} not installed on droid`
|
|
1490
|
+
});
|
|
1491
|
+
if (existsSync5(pluginDir)) {
|
|
1492
|
+
changes.push({
|
|
1493
|
+
platform: PLATFORM3,
|
|
1494
|
+
action: "remove",
|
|
1495
|
+
path: pluginDir,
|
|
1496
|
+
detail: "remove staged marketplace bundle"
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
const othersStaged = stagedDroidPlugins(stagingRoot).some((n) => n !== id);
|
|
1500
|
+
if (!othersStaged && samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot)) {
|
|
1501
|
+
changes.push({
|
|
1502
|
+
platform: PLATFORM3,
|
|
1503
|
+
action: "remove",
|
|
1504
|
+
path: stagingRoot,
|
|
1505
|
+
detail: `run: droid plugin marketplace remove ${MARKETPLACE_NAME} (when no plugins remain)`
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
},
|
|
1509
|
+
driveInstall: driveInstall2,
|
|
1510
|
+
driveUninstall: driveUninstall2,
|
|
1511
|
+
// droid has no documented `plugin update` verb — update IS re-stage (done by
|
|
1512
|
+
// the caller) + `plugin install`, assumed idempotent + version-cached (DOCS-only).
|
|
1513
|
+
async driveUpdate(id) {
|
|
1514
|
+
return driveInstall2(id);
|
|
1515
|
+
},
|
|
1516
|
+
async finishUninstall(id, changes) {
|
|
1517
|
+
const stagingRoot = droidStagingRoot();
|
|
1518
|
+
const pluginDir = join5(stagingRoot, id);
|
|
1519
|
+
if (existsSync5(pluginDir)) {
|
|
1520
|
+
try {
|
|
1521
|
+
rmSync4(pluginDir, { recursive: true, force: true });
|
|
1522
|
+
changes.push({
|
|
1523
|
+
platform: PLATFORM3,
|
|
1524
|
+
action: "remove",
|
|
1525
|
+
path: pluginDir,
|
|
1526
|
+
detail: "removed staged marketplace bundle"
|
|
1527
|
+
});
|
|
1528
|
+
} catch (err) {
|
|
1529
|
+
changes.push({
|
|
1530
|
+
platform: PLATFORM3,
|
|
1531
|
+
action: "warn",
|
|
1532
|
+
path: pluginDir,
|
|
1533
|
+
detail: `could not remove staged bundle: ${errMessage4(err)}`
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
if (existsSync5(stagingRoot)) regenerateDroidCatalog(stagingRoot, changes);
|
|
1538
|
+
const nothingStaged = stagedDroidPlugins(stagingRoot).length === 0;
|
|
1539
|
+
if (nothingStaged && !anyDroidAgentConnectorPlugins() && samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot)) {
|
|
1540
|
+
changes.push(...await driveMarketplaceRemove2(stagingRoot));
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
};
|
|
1544
|
+
|
|
1545
|
+
// src/core/marketplace-drivers/agy.ts
|
|
1546
|
+
import { existsSync as existsSync6, rmSync as rmSync5 } from "fs";
|
|
1547
|
+
import { join as join6 } from "path";
|
|
1548
|
+
function agyBinary() {
|
|
1549
|
+
return findOnPath("agy");
|
|
1550
|
+
}
|
|
1551
|
+
function errMessage5(err) {
|
|
1552
|
+
return err instanceof Error ? err.message : String(err);
|
|
1553
|
+
}
|
|
1554
|
+
function failDetail4(step, r) {
|
|
1555
|
+
if (r.timedOut) return `${step} timed out`;
|
|
1556
|
+
if (r.error) return `${step} failed to spawn: ${r.error}`;
|
|
1557
|
+
const line = firstLine(r.stderr) || firstLine(r.stdout);
|
|
1558
|
+
return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
|
|
1559
|
+
}
|
|
1560
|
+
function stageAgyBundle(connector, platform, changes) {
|
|
1561
|
+
const stagingRoot = agyStagingRoot();
|
|
1562
|
+
const pluginDir = join6(stagingRoot, connector.id);
|
|
1563
|
+
const existed = existsSync6(pluginDir);
|
|
1214
1564
|
const result = packageConnector(connector, { outDir: stagingRoot, format: "agy-plugin" });
|
|
1215
1565
|
changes.push({
|
|
1216
1566
|
platform,
|
|
@@ -1221,27 +1571,27 @@ function stageAgyBundle(connector, platform, changes) {
|
|
|
1221
1571
|
return { pluginDir, contentHash: hashDirectory(pluginDir) };
|
|
1222
1572
|
}
|
|
1223
1573
|
function makeAgyDriver(platform) {
|
|
1224
|
-
const
|
|
1574
|
+
const warn6 = (detail, path) => ({
|
|
1225
1575
|
platform,
|
|
1226
1576
|
action: "warn",
|
|
1227
1577
|
detail,
|
|
1228
1578
|
...path ? { path } : {}
|
|
1229
1579
|
});
|
|
1230
|
-
const
|
|
1580
|
+
const manualInstall3 = (pluginDir) => `agy plugin install ${pluginDir}`;
|
|
1231
1581
|
return {
|
|
1232
1582
|
platform,
|
|
1233
1583
|
format: "agy-plugin",
|
|
1234
1584
|
binary: agyBinary,
|
|
1235
1585
|
stagingRoot: agyStagingRoot,
|
|
1236
1586
|
pluginDir(id) {
|
|
1237
|
-
return
|
|
1587
|
+
return join6(agyStagingRoot(), id);
|
|
1238
1588
|
},
|
|
1239
1589
|
installed: agyPluginInstalled,
|
|
1240
1590
|
stage(connector, changes) {
|
|
1241
1591
|
return stageAgyBundle(connector, platform, changes).contentHash;
|
|
1242
1592
|
},
|
|
1243
1593
|
planInstall(connector, changes) {
|
|
1244
|
-
const pluginDir =
|
|
1594
|
+
const pluginDir = join6(agyStagingRoot(), connector.id);
|
|
1245
1595
|
changes.push({
|
|
1246
1596
|
platform,
|
|
1247
1597
|
action: agyPluginInstalled(connector.id) ? "skip" : "create",
|
|
@@ -1249,13 +1599,13 @@ function makeAgyDriver(platform) {
|
|
|
1249
1599
|
});
|
|
1250
1600
|
},
|
|
1251
1601
|
planUninstall(id, changes) {
|
|
1252
|
-
const pluginDir =
|
|
1602
|
+
const pluginDir = join6(agyStagingRoot(), id);
|
|
1253
1603
|
changes.push({
|
|
1254
1604
|
platform,
|
|
1255
1605
|
action: agyPluginInstalled(id) ? "remove" : "skip",
|
|
1256
1606
|
detail: agyPluginInstalled(id) ? `run: agy plugin uninstall ${id}` : `plugin ${id} not installed on ${platform}`
|
|
1257
1607
|
});
|
|
1258
|
-
if (
|
|
1608
|
+
if (existsSync6(pluginDir)) {
|
|
1259
1609
|
changes.push({
|
|
1260
1610
|
platform,
|
|
1261
1611
|
action: "remove",
|
|
@@ -1266,12 +1616,12 @@ function makeAgyDriver(platform) {
|
|
|
1266
1616
|
},
|
|
1267
1617
|
async driveInstall(id) {
|
|
1268
1618
|
const changes = [];
|
|
1269
|
-
const pluginDir =
|
|
1619
|
+
const pluginDir = join6(agyStagingRoot(), id);
|
|
1270
1620
|
const bin = agyBinary();
|
|
1271
1621
|
if (!bin) {
|
|
1272
1622
|
changes.push(
|
|
1273
|
-
|
|
1274
|
-
`agy CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${
|
|
1623
|
+
warn6(
|
|
1624
|
+
`agy CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall3(pluginDir)}`,
|
|
1275
1625
|
pluginDir
|
|
1276
1626
|
)
|
|
1277
1627
|
);
|
|
@@ -1289,7 +1639,7 @@ function makeAgyDriver(platform) {
|
|
|
1289
1639
|
const install = await runHostCommand(bin, ["plugin", "install", pluginDir]);
|
|
1290
1640
|
if (!install.ok || !agyPluginInstalled(id)) {
|
|
1291
1641
|
changes.push(
|
|
1292
|
-
|
|
1642
|
+
warn6(`plugin install did not complete \u2014 ` + failDetail4(`agy plugin install ${pluginDir}`, install))
|
|
1293
1643
|
);
|
|
1294
1644
|
return { changes, ok: false };
|
|
1295
1645
|
}
|
|
@@ -1313,7 +1663,7 @@ function makeAgyDriver(platform) {
|
|
|
1313
1663
|
const bin = agyBinary();
|
|
1314
1664
|
if (!bin) {
|
|
1315
1665
|
changes.push(
|
|
1316
|
-
|
|
1666
|
+
warn6(
|
|
1317
1667
|
`agy CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: agy plugin uninstall ${id}`
|
|
1318
1668
|
)
|
|
1319
1669
|
);
|
|
@@ -1322,7 +1672,7 @@ function makeAgyDriver(platform) {
|
|
|
1322
1672
|
const uninstall = await runHostCommand(bin, ["plugin", "uninstall", id]);
|
|
1323
1673
|
if (!uninstall.ok || agyPluginInstalled(id)) {
|
|
1324
1674
|
changes.push(
|
|
1325
|
-
|
|
1675
|
+
warn6(`plugin uninstall did not complete \u2014 ` + failDetail4(`agy plugin uninstall ${id}`, uninstall))
|
|
1326
1676
|
);
|
|
1327
1677
|
return { changes, ok: false };
|
|
1328
1678
|
}
|
|
@@ -1338,12 +1688,12 @@ function makeAgyDriver(platform) {
|
|
|
1338
1688
|
// the probe already shows it present (the bundle on disk changed).
|
|
1339
1689
|
async driveUpdate(id) {
|
|
1340
1690
|
const changes = [];
|
|
1341
|
-
const pluginDir =
|
|
1691
|
+
const pluginDir = join6(agyStagingRoot(), id);
|
|
1342
1692
|
const bin = agyBinary();
|
|
1343
1693
|
if (!bin) {
|
|
1344
1694
|
changes.push(
|
|
1345
|
-
|
|
1346
|
-
`agy CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: ${
|
|
1695
|
+
warn6(
|
|
1696
|
+
`agy CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: ${manualInstall3(pluginDir)}`,
|
|
1347
1697
|
pluginDir
|
|
1348
1698
|
)
|
|
1349
1699
|
);
|
|
@@ -1352,7 +1702,7 @@ function makeAgyDriver(platform) {
|
|
|
1352
1702
|
const install = await runHostCommand(bin, ["plugin", "install", pluginDir]);
|
|
1353
1703
|
if (!install.ok || !agyPluginInstalled(id)) {
|
|
1354
1704
|
changes.push(
|
|
1355
|
-
|
|
1705
|
+
warn6(`plugin install did not complete \u2014 ` + failDetail4(`agy plugin install ${pluginDir}`, install))
|
|
1356
1706
|
);
|
|
1357
1707
|
return { changes, ok: false };
|
|
1358
1708
|
}
|
|
@@ -1366,10 +1716,10 @@ function makeAgyDriver(platform) {
|
|
|
1366
1716
|
// Direct driver: no catalog, no marketplace de-registration. Cleanup is just
|
|
1367
1717
|
// removing the staged bundle dir (the host copied it into its own store).
|
|
1368
1718
|
async finishUninstall(id, changes) {
|
|
1369
|
-
const pluginDir =
|
|
1370
|
-
if (
|
|
1719
|
+
const pluginDir = join6(agyStagingRoot(), id);
|
|
1720
|
+
if (existsSync6(pluginDir)) {
|
|
1371
1721
|
try {
|
|
1372
|
-
|
|
1722
|
+
rmSync5(pluginDir, { recursive: true, force: true });
|
|
1373
1723
|
changes.push({
|
|
1374
1724
|
platform,
|
|
1375
1725
|
action: "remove",
|
|
@@ -1381,7 +1731,7 @@ function makeAgyDriver(platform) {
|
|
|
1381
1731
|
platform,
|
|
1382
1732
|
action: "warn",
|
|
1383
1733
|
path: pluginDir,
|
|
1384
|
-
detail: `could not remove staged bundle: ${
|
|
1734
|
+
detail: `could not remove staged bundle: ${errMessage5(err)}`
|
|
1385
1735
|
});
|
|
1386
1736
|
}
|
|
1387
1737
|
}
|
|
@@ -1389,49 +1739,712 @@ function makeAgyDriver(platform) {
|
|
|
1389
1739
|
};
|
|
1390
1740
|
}
|
|
1391
1741
|
|
|
1392
|
-
// src/core/marketplace-drivers/
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
return
|
|
1742
|
+
// src/core/marketplace-drivers/gemini.ts
|
|
1743
|
+
import { existsSync as existsSync7, rmSync as rmSync6 } from "fs";
|
|
1744
|
+
import { join as join7 } from "path";
|
|
1745
|
+
var PLATFORM4 = "gemini-cli";
|
|
1746
|
+
function geminiBinary() {
|
|
1747
|
+
return findOnPath("gemini");
|
|
1748
|
+
}
|
|
1749
|
+
function errMessage6(err) {
|
|
1750
|
+
return err instanceof Error ? err.message : String(err);
|
|
1401
1751
|
}
|
|
1402
|
-
function
|
|
1403
|
-
|
|
1404
|
-
case "claude-code":
|
|
1405
|
-
return claudeDriver;
|
|
1406
|
-
case "codex":
|
|
1407
|
-
return codexDriver;
|
|
1408
|
-
case "antigravity":
|
|
1409
|
-
case "antigravity-cli":
|
|
1410
|
-
return agyDriver(platform);
|
|
1411
|
-
default:
|
|
1412
|
-
return null;
|
|
1413
|
-
}
|
|
1752
|
+
function warn4(detail, path) {
|
|
1753
|
+
return { platform: PLATFORM4, action: "warn", detail, ...path ? { path } : {} };
|
|
1414
1754
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
return null;
|
|
1755
|
+
function failDetail5(step, r) {
|
|
1756
|
+
if (r.timedOut) return `${step} timed out`;
|
|
1757
|
+
if (r.error) return `${step} failed to spawn: ${r.error}`;
|
|
1758
|
+
const line = firstLine(r.stderr) || firstLine(r.stdout);
|
|
1759
|
+
return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
|
|
1422
1760
|
}
|
|
1423
|
-
function
|
|
1424
|
-
|
|
1425
|
-
return value ?? "auto";
|
|
1426
|
-
}
|
|
1427
|
-
return null;
|
|
1761
|
+
function manualInstall(pluginDir) {
|
|
1762
|
+
return `gemini extensions install ${pluginDir} --consent`;
|
|
1428
1763
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1764
|
+
function stageGeminiBundle(connector, changes) {
|
|
1765
|
+
const stagingRoot = geminiStagingRoot();
|
|
1766
|
+
const pluginDir = join7(stagingRoot, connector.id);
|
|
1767
|
+
const existed = existsSync7(pluginDir);
|
|
1768
|
+
const result = packageConnector(connector, { outDir: stagingRoot, format: "gemini-extension" });
|
|
1769
|
+
changes.push({
|
|
1770
|
+
platform: PLATFORM4,
|
|
1771
|
+
action: existed ? "update" : "create",
|
|
1772
|
+
path: pluginDir,
|
|
1773
|
+
detail: `staged marketplace bundle (${result.files.length} files, gemini-extension)`
|
|
1774
|
+
});
|
|
1775
|
+
return { pluginDir, contentHash: hashDirectory(pluginDir) };
|
|
1776
|
+
}
|
|
1777
|
+
var geminiDriver = {
|
|
1778
|
+
platform: PLATFORM4,
|
|
1779
|
+
format: "gemini-extension",
|
|
1780
|
+
binary: geminiBinary,
|
|
1781
|
+
stagingRoot: geminiStagingRoot,
|
|
1782
|
+
pluginDir(id) {
|
|
1783
|
+
return join7(geminiStagingRoot(), id);
|
|
1784
|
+
},
|
|
1785
|
+
installed: geminiExtensionInstalled,
|
|
1786
|
+
stage(connector, changes) {
|
|
1787
|
+
return stageGeminiBundle(connector, changes).contentHash;
|
|
1788
|
+
},
|
|
1789
|
+
planInstall(connector, changes) {
|
|
1790
|
+
const pluginDir = join7(geminiStagingRoot(), connector.id);
|
|
1791
|
+
changes.push({
|
|
1792
|
+
platform: PLATFORM4,
|
|
1793
|
+
action: geminiExtensionInstalled(connector.id) ? "skip" : "create",
|
|
1794
|
+
detail: geminiExtensionInstalled(connector.id) ? `extension ${connector.id} already installed` : `run: ${manualInstall(pluginDir)}`
|
|
1795
|
+
});
|
|
1796
|
+
},
|
|
1797
|
+
planUninstall(id, changes) {
|
|
1798
|
+
const pluginDir = join7(geminiStagingRoot(), id);
|
|
1799
|
+
changes.push({
|
|
1800
|
+
platform: PLATFORM4,
|
|
1801
|
+
action: geminiExtensionInstalled(id) ? "remove" : "skip",
|
|
1802
|
+
detail: geminiExtensionInstalled(id) ? `run: gemini extensions uninstall ${id}` : `extension ${id} not installed on ${PLATFORM4}`
|
|
1803
|
+
});
|
|
1804
|
+
if (existsSync7(pluginDir)) {
|
|
1805
|
+
changes.push({
|
|
1806
|
+
platform: PLATFORM4,
|
|
1807
|
+
action: "remove",
|
|
1808
|
+
path: pluginDir,
|
|
1809
|
+
detail: "remove staged marketplace bundle"
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
},
|
|
1813
|
+
async driveInstall(id) {
|
|
1814
|
+
const changes = [];
|
|
1815
|
+
const pluginDir = join7(geminiStagingRoot(), id);
|
|
1816
|
+
const bin = geminiBinary();
|
|
1817
|
+
if (!bin) {
|
|
1818
|
+
changes.push(
|
|
1819
|
+
warn4(
|
|
1820
|
+
`gemini CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall(pluginDir)}`,
|
|
1821
|
+
pluginDir
|
|
1822
|
+
)
|
|
1823
|
+
);
|
|
1824
|
+
return { changes, ok: false };
|
|
1825
|
+
}
|
|
1826
|
+
if (geminiExtensionInstalled(id)) {
|
|
1827
|
+
changes.push({
|
|
1828
|
+
platform: PLATFORM4,
|
|
1829
|
+
action: "skip",
|
|
1830
|
+
detail: `extension ${id} already installed`
|
|
1831
|
+
});
|
|
1832
|
+
return { changes, ok: true };
|
|
1833
|
+
}
|
|
1834
|
+
await runHostCommand(bin, ["extensions", "validate", pluginDir]);
|
|
1835
|
+
const install = await runHostCommand(bin, ["extensions", "install", pluginDir, "--consent"]);
|
|
1836
|
+
if (!geminiExtensionInstalled(id)) {
|
|
1837
|
+
const trustGated = /trust (the |this )?(files|folder)/i.test(
|
|
1838
|
+
`${install.stdout}
|
|
1839
|
+
${install.stderr}`
|
|
1840
|
+
);
|
|
1841
|
+
changes.push(
|
|
1842
|
+
warn4(
|
|
1843
|
+
trustGated ? `extension install blocked by gemini's folder-trust prompt (newer gemini gates local-path installs and --consent does not bypass it). Trust the folder once, then re-run: run \`gemini extensions install ${pluginDir} --consent\` interactively (answer "y" to trust), or set \`security.folderTrust.enabled: false\` in ~/.gemini/settings.json. The bundle is staged and ready.` : `extension install did not complete \u2014 ` + failDetail5(`gemini extensions install ${pluginDir} --consent`, install),
|
|
1844
|
+
pluginDir
|
|
1845
|
+
)
|
|
1846
|
+
);
|
|
1847
|
+
return { changes, ok: false };
|
|
1848
|
+
}
|
|
1849
|
+
changes.push({
|
|
1850
|
+
platform: PLATFORM4,
|
|
1851
|
+
action: "create",
|
|
1852
|
+
detail: `installed extension ${id} (scope user)`
|
|
1853
|
+
});
|
|
1854
|
+
return { changes, ok: true };
|
|
1855
|
+
},
|
|
1856
|
+
async driveUninstall(id) {
|
|
1857
|
+
const changes = [];
|
|
1858
|
+
if (!geminiExtensionInstalled(id)) {
|
|
1859
|
+
changes.push({
|
|
1860
|
+
platform: PLATFORM4,
|
|
1861
|
+
action: "skip",
|
|
1862
|
+
detail: `extension ${id} not installed on ${PLATFORM4}`
|
|
1863
|
+
});
|
|
1864
|
+
return { changes, ok: true };
|
|
1865
|
+
}
|
|
1866
|
+
const bin = geminiBinary();
|
|
1867
|
+
if (!bin) {
|
|
1868
|
+
changes.push(
|
|
1869
|
+
warn4(
|
|
1870
|
+
`gemini CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: gemini extensions uninstall ${id}`
|
|
1871
|
+
)
|
|
1872
|
+
);
|
|
1873
|
+
return { changes, ok: false };
|
|
1874
|
+
}
|
|
1875
|
+
const uninstall = await runHostCommand(bin, ["extensions", "uninstall", id]);
|
|
1876
|
+
if (geminiExtensionInstalled(id)) {
|
|
1877
|
+
changes.push(
|
|
1878
|
+
warn4(
|
|
1879
|
+
`extension uninstall did not complete \u2014 ` + failDetail5(`gemini extensions uninstall ${id}`, uninstall)
|
|
1880
|
+
)
|
|
1881
|
+
);
|
|
1882
|
+
return { changes, ok: false };
|
|
1883
|
+
}
|
|
1884
|
+
changes.push({
|
|
1885
|
+
platform: PLATFORM4,
|
|
1886
|
+
action: "remove",
|
|
1887
|
+
detail: `uninstalled extension ${id} (gemini extensions uninstall)`
|
|
1888
|
+
});
|
|
1889
|
+
return { changes, ok: true };
|
|
1890
|
+
},
|
|
1891
|
+
// gemini has NO overwrite-install (re-install REFUSES), so update is
|
|
1892
|
+
// uninstall-THEN-install. The bundle was already re-staged by the caller.
|
|
1893
|
+
async driveUpdate(id) {
|
|
1894
|
+
const changes = [];
|
|
1895
|
+
const pluginDir = join7(geminiStagingRoot(), id);
|
|
1896
|
+
const bin = geminiBinary();
|
|
1897
|
+
if (!bin) {
|
|
1898
|
+
changes.push(
|
|
1899
|
+
warn4(
|
|
1900
|
+
`gemini CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: gemini extensions uninstall ${id} && ${manualInstall(pluginDir)}`,
|
|
1901
|
+
pluginDir
|
|
1902
|
+
)
|
|
1903
|
+
);
|
|
1904
|
+
return { changes, ok: false };
|
|
1905
|
+
}
|
|
1906
|
+
if (geminiExtensionInstalled(id)) {
|
|
1907
|
+
const uninstall = await runHostCommand(bin, ["extensions", "uninstall", id]);
|
|
1908
|
+
if (geminiExtensionInstalled(id)) {
|
|
1909
|
+
changes.push(
|
|
1910
|
+
warn4(
|
|
1911
|
+
`extension update could not remove the old copy \u2014 ` + failDetail5(`gemini extensions uninstall ${id}`, uninstall)
|
|
1912
|
+
)
|
|
1913
|
+
);
|
|
1914
|
+
return { changes, ok: false };
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
await runHostCommand(bin, ["extensions", "validate", pluginDir]);
|
|
1918
|
+
const install = await runHostCommand(bin, ["extensions", "install", pluginDir, "--consent"]);
|
|
1919
|
+
if (!geminiExtensionInstalled(id)) {
|
|
1920
|
+
changes.push(
|
|
1921
|
+
warn4(
|
|
1922
|
+
`extension install did not complete \u2014 ` + failDetail5(`gemini extensions install ${pluginDir} --consent`, install)
|
|
1923
|
+
)
|
|
1924
|
+
);
|
|
1925
|
+
return { changes, ok: false };
|
|
1926
|
+
}
|
|
1927
|
+
changes.push({
|
|
1928
|
+
platform: PLATFORM4,
|
|
1929
|
+
action: "update",
|
|
1930
|
+
detail: `updated extension ${id} (gemini extensions uninstall + install)`
|
|
1931
|
+
});
|
|
1932
|
+
return { changes, ok: true };
|
|
1933
|
+
},
|
|
1934
|
+
// Direct driver: no catalog, no marketplace de-registration. Cleanup is just
|
|
1935
|
+
// removing the staged bundle dir (the host copied it into its own store).
|
|
1936
|
+
async finishUninstall(id, changes) {
|
|
1937
|
+
const pluginDir = join7(geminiStagingRoot(), id);
|
|
1938
|
+
if (existsSync7(pluginDir)) {
|
|
1939
|
+
try {
|
|
1940
|
+
rmSync6(pluginDir, { recursive: true, force: true });
|
|
1941
|
+
changes.push({
|
|
1942
|
+
platform: PLATFORM4,
|
|
1943
|
+
action: "remove",
|
|
1944
|
+
path: pluginDir,
|
|
1945
|
+
detail: "removed staged marketplace bundle"
|
|
1946
|
+
});
|
|
1947
|
+
} catch (err) {
|
|
1948
|
+
changes.push({
|
|
1949
|
+
platform: PLATFORM4,
|
|
1950
|
+
action: "warn",
|
|
1951
|
+
path: pluginDir,
|
|
1952
|
+
detail: `could not remove staged bundle: ${errMessage6(err)}`
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
|
|
1959
|
+
// src/core/marketplace-drivers/npm-local.ts
|
|
1960
|
+
import { existsSync as existsSync8, mkdirSync, rmSync as rmSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
1961
|
+
import { dirname as dirname4, join as join8 } from "path";
|
|
1962
|
+
import { pathToFileURL } from "url";
|
|
1963
|
+
function errMessage7(err) {
|
|
1964
|
+
return err instanceof Error ? err.message : String(err);
|
|
1965
|
+
}
|
|
1966
|
+
function failDetail6(step, r) {
|
|
1967
|
+
if (r.timedOut) return `${step} timed out`;
|
|
1968
|
+
if (r.error) return `${step} failed to spawn: ${r.error}`;
|
|
1969
|
+
const line = firstLine(r.stderr) || firstLine(r.stdout);
|
|
1970
|
+
return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
|
|
1971
|
+
}
|
|
1972
|
+
function fileUrlFor(connectorId) {
|
|
1973
|
+
return pathToFileURL(join8(npmStagingRoot(), connectorId)).href;
|
|
1974
|
+
}
|
|
1975
|
+
function makeNpmLocalDriver(platform, opts) {
|
|
1976
|
+
const { binaryName } = opts;
|
|
1977
|
+
const binary = () => findOnPath(binaryName);
|
|
1978
|
+
const warn6 = (detail, path) => ({
|
|
1979
|
+
platform,
|
|
1980
|
+
action: "warn",
|
|
1981
|
+
detail,
|
|
1982
|
+
...path ? { path } : {}
|
|
1983
|
+
});
|
|
1984
|
+
const manualInstall3 = (connectorId) => `${binaryName} plugin --global ${fileUrlFor(connectorId)}`;
|
|
1985
|
+
const stageBundle = (connector, changes) => {
|
|
1986
|
+
const stagingRoot = npmStagingRoot();
|
|
1987
|
+
const pluginDir = join8(stagingRoot, connector.id);
|
|
1988
|
+
const existed = existsSync8(pluginDir);
|
|
1989
|
+
const result = packageConnector(connector, { outDir: stagingRoot, format: "npm-plugin" });
|
|
1990
|
+
changes.push({
|
|
1991
|
+
platform,
|
|
1992
|
+
action: existed ? "update" : "create",
|
|
1993
|
+
path: pluginDir,
|
|
1994
|
+
detail: `staged marketplace bundle (${result.files.length} files, npm-plugin)`
|
|
1995
|
+
});
|
|
1996
|
+
return { pluginDir, contentHash: hashDirectory(pluginDir) };
|
|
1997
|
+
};
|
|
1998
|
+
const driveInstall3 = async (id) => {
|
|
1999
|
+
const changes = [];
|
|
2000
|
+
if (npmPluginInstalled(platform, id)) {
|
|
2001
|
+
changes.push({
|
|
2002
|
+
platform,
|
|
2003
|
+
action: "skip",
|
|
2004
|
+
detail: `plugin ${id} already installed`
|
|
2005
|
+
});
|
|
2006
|
+
return { changes, ok: true };
|
|
2007
|
+
}
|
|
2008
|
+
const bin = binary();
|
|
2009
|
+
if (!bin) {
|
|
2010
|
+
changes.push(
|
|
2011
|
+
warn6(
|
|
2012
|
+
`${binaryName} CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall3(id)}`,
|
|
2013
|
+
join8(npmStagingRoot(), id)
|
|
2014
|
+
)
|
|
2015
|
+
);
|
|
2016
|
+
return { changes, ok: false };
|
|
2017
|
+
}
|
|
2018
|
+
const stagingRoot = npmStagingRoot();
|
|
2019
|
+
try {
|
|
2020
|
+
mkdirSync(stagingRoot, { recursive: true });
|
|
2021
|
+
} catch {
|
|
2022
|
+
}
|
|
2023
|
+
const install = await runHostCommand(bin, ["plugin", "--global", fileUrlFor(id)], {
|
|
2024
|
+
cwd: stagingRoot
|
|
2025
|
+
});
|
|
2026
|
+
if (!npmPluginInstalled(platform, id)) {
|
|
2027
|
+
changes.push(
|
|
2028
|
+
warn6(`plugin install did not complete \u2014 ` + failDetail6(manualInstall3(id), install))
|
|
2029
|
+
);
|
|
2030
|
+
return { changes, ok: false };
|
|
2031
|
+
}
|
|
2032
|
+
changes.push({
|
|
2033
|
+
platform,
|
|
2034
|
+
action: "create",
|
|
2035
|
+
detail: `installed plugin ${id} (scope user)`
|
|
2036
|
+
});
|
|
2037
|
+
return { changes, ok: true };
|
|
2038
|
+
};
|
|
2039
|
+
return {
|
|
2040
|
+
platform,
|
|
2041
|
+
format: "npm-plugin",
|
|
2042
|
+
binary,
|
|
2043
|
+
stagingRoot: npmStagingRoot,
|
|
2044
|
+
pluginDir(id) {
|
|
2045
|
+
return join8(npmStagingRoot(), id);
|
|
2046
|
+
},
|
|
2047
|
+
installed: (id) => npmPluginInstalled(platform, id),
|
|
2048
|
+
stage(connector, changes) {
|
|
2049
|
+
return stageBundle(connector, changes).contentHash;
|
|
2050
|
+
},
|
|
2051
|
+
planInstall(connector, changes) {
|
|
2052
|
+
changes.push({
|
|
2053
|
+
platform,
|
|
2054
|
+
action: npmPluginInstalled(platform, connector.id) ? "skip" : "create",
|
|
2055
|
+
detail: npmPluginInstalled(platform, connector.id) ? `plugin ${connector.id} already installed` : `run: ${manualInstall3(connector.id)}`
|
|
2056
|
+
});
|
|
2057
|
+
},
|
|
2058
|
+
planUninstall(id, changes) {
|
|
2059
|
+
const pluginDir = join8(npmStagingRoot(), id);
|
|
2060
|
+
const present = npmPluginInstalled(platform, id);
|
|
2061
|
+
changes.push({
|
|
2062
|
+
platform,
|
|
2063
|
+
action: present ? "remove" : "skip",
|
|
2064
|
+
detail: present ? `edit ${npmConfigFilePath(platform)}: drop the file:// plugin entry for ${id}` : `plugin ${id} not installed on ${platform}`
|
|
2065
|
+
});
|
|
2066
|
+
if (existsSync8(pluginDir)) {
|
|
2067
|
+
changes.push({
|
|
2068
|
+
platform,
|
|
2069
|
+
action: "remove",
|
|
2070
|
+
path: pluginDir,
|
|
2071
|
+
detail: "remove staged marketplace bundle"
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
},
|
|
2075
|
+
driveInstall: driveInstall3,
|
|
2076
|
+
// No host uninstall verb (`<bin> uninstall` removes the HOST). Removal is an
|
|
2077
|
+
// EDIT of the config `plugin` array: drop the entry referencing our staged
|
|
2078
|
+
// dir, delete the `plugin` key when empty, preserve every other key.
|
|
2079
|
+
async driveUninstall(id) {
|
|
2080
|
+
const changes = [];
|
|
2081
|
+
const entry = npmPluginArrayEntry(platform, id);
|
|
2082
|
+
if (entry == null) {
|
|
2083
|
+
changes.push({
|
|
2084
|
+
platform,
|
|
2085
|
+
action: "skip",
|
|
2086
|
+
detail: `plugin ${id} not installed on ${platform}`
|
|
2087
|
+
});
|
|
2088
|
+
return { changes, ok: true };
|
|
2089
|
+
}
|
|
2090
|
+
const configPath = npmConfigFilePath(platform);
|
|
2091
|
+
const cfg = readNpmConfig(platform);
|
|
2092
|
+
if (!cfg) {
|
|
2093
|
+
changes.push(
|
|
2094
|
+
warn6(
|
|
2095
|
+
`could not parse ${platform} config ${configPath} \u2014 leaving the plugin entry in place. Remove this entry from the "plugin" array by hand: ${entry}`,
|
|
2096
|
+
configPath
|
|
2097
|
+
)
|
|
2098
|
+
);
|
|
2099
|
+
return { changes, ok: false };
|
|
2100
|
+
}
|
|
2101
|
+
const arr = Array.isArray(cfg["plugin"]) ? cfg["plugin"] : [];
|
|
2102
|
+
const filtered = arr.filter((e) => e !== entry);
|
|
2103
|
+
if (filtered.length === 0) delete cfg["plugin"];
|
|
2104
|
+
else cfg["plugin"] = filtered;
|
|
2105
|
+
try {
|
|
2106
|
+
mkdirSync(dirname4(configPath), { recursive: true });
|
|
2107
|
+
writeFileSync4(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
2108
|
+
`, "utf8");
|
|
2109
|
+
} catch (err) {
|
|
2110
|
+
changes.push(
|
|
2111
|
+
warn6(`could not rewrite ${platform} config: ${errMessage7(err)}`, configPath)
|
|
2112
|
+
);
|
|
2113
|
+
return { changes, ok: false };
|
|
2114
|
+
}
|
|
2115
|
+
if (npmPluginInstalled(platform, id)) {
|
|
2116
|
+
changes.push(
|
|
2117
|
+
warn6(`plugin entry persisted after the config edit \u2014 ${configPath}`, configPath)
|
|
2118
|
+
);
|
|
2119
|
+
return { changes, ok: false };
|
|
2120
|
+
}
|
|
2121
|
+
changes.push({
|
|
2122
|
+
platform,
|
|
2123
|
+
action: "remove",
|
|
2124
|
+
path: configPath,
|
|
2125
|
+
detail: `removed plugin ${id} from the ${platform} config "plugin" array`
|
|
2126
|
+
});
|
|
2127
|
+
return { changes, ok: true };
|
|
2128
|
+
},
|
|
2129
|
+
// The `file://` reference points at the LIVE staged dir, so an update is just
|
|
2130
|
+
// a re-run of install (the bundle was re-staged in place by the caller). When
|
|
2131
|
+
// the entry is already present, that is an idempotent `=` skip.
|
|
2132
|
+
async driveUpdate(id) {
|
|
2133
|
+
return driveInstall3(id);
|
|
2134
|
+
},
|
|
2135
|
+
// No catalog, no marketplace de-registration: cleanup is removing the staged
|
|
2136
|
+
// bundle dir (the host no longer references it after driveUninstall's edit).
|
|
2137
|
+
async finishUninstall(id, changes) {
|
|
2138
|
+
const pluginDir = join8(npmStagingRoot(), id);
|
|
2139
|
+
if (existsSync8(pluginDir)) {
|
|
2140
|
+
try {
|
|
2141
|
+
rmSync7(pluginDir, { recursive: true, force: true });
|
|
2142
|
+
changes.push({
|
|
2143
|
+
platform,
|
|
2144
|
+
action: "remove",
|
|
2145
|
+
path: pluginDir,
|
|
2146
|
+
detail: "removed staged marketplace bundle"
|
|
2147
|
+
});
|
|
2148
|
+
} catch (err) {
|
|
2149
|
+
changes.push({
|
|
2150
|
+
platform,
|
|
2151
|
+
action: "warn",
|
|
2152
|
+
path: pluginDir,
|
|
2153
|
+
detail: `could not remove staged bundle: ${errMessage7(err)}`
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
// src/core/marketplace-drivers/qwen.ts
|
|
2162
|
+
import { existsSync as existsSync9, rmSync as rmSync8 } from "fs";
|
|
2163
|
+
import { join as join9 } from "path";
|
|
2164
|
+
var PLATFORM5 = "qwen-code";
|
|
2165
|
+
function qwenBinary() {
|
|
2166
|
+
return findOnPath("qwen");
|
|
2167
|
+
}
|
|
2168
|
+
function errMessage8(err) {
|
|
2169
|
+
return err instanceof Error ? err.message : String(err);
|
|
2170
|
+
}
|
|
2171
|
+
function warn5(detail, path) {
|
|
2172
|
+
return { platform: PLATFORM5, action: "warn", detail, ...path ? { path } : {} };
|
|
2173
|
+
}
|
|
2174
|
+
function failDetail7(step, r) {
|
|
2175
|
+
if (r.timedOut) return `${step} timed out`;
|
|
2176
|
+
if (r.error) return `${step} failed to spawn: ${r.error}`;
|
|
2177
|
+
const line = firstLine(r.stderr) || firstLine(r.stdout);
|
|
2178
|
+
return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
|
|
2179
|
+
}
|
|
2180
|
+
function manualInstall2(pluginDir) {
|
|
2181
|
+
return `qwen extensions install ${pluginDir}`;
|
|
2182
|
+
}
|
|
2183
|
+
function stageQwenBundle(connector, changes) {
|
|
2184
|
+
const stagingRoot = qwenStagingRoot();
|
|
2185
|
+
const pluginDir = join9(stagingRoot, connector.id);
|
|
2186
|
+
const existed = existsSync9(pluginDir);
|
|
2187
|
+
const result = packageConnector(connector, { outDir: stagingRoot, format: "qwen-extension" });
|
|
2188
|
+
changes.push({
|
|
2189
|
+
platform: PLATFORM5,
|
|
2190
|
+
action: existed ? "update" : "create",
|
|
2191
|
+
path: pluginDir,
|
|
2192
|
+
detail: `staged marketplace bundle (${result.files.length} files, qwen-extension)`
|
|
2193
|
+
});
|
|
2194
|
+
return { pluginDir, contentHash: hashDirectory(pluginDir) };
|
|
2195
|
+
}
|
|
2196
|
+
var qwenDriver = {
|
|
2197
|
+
platform: PLATFORM5,
|
|
2198
|
+
format: "qwen-extension",
|
|
2199
|
+
binary: qwenBinary,
|
|
2200
|
+
stagingRoot: qwenStagingRoot,
|
|
2201
|
+
pluginDir(id) {
|
|
2202
|
+
return join9(qwenStagingRoot(), id);
|
|
2203
|
+
},
|
|
2204
|
+
installed: qwenExtensionInstalled,
|
|
2205
|
+
stage(connector, changes) {
|
|
2206
|
+
return stageQwenBundle(connector, changes).contentHash;
|
|
2207
|
+
},
|
|
2208
|
+
planInstall(connector, changes) {
|
|
2209
|
+
const pluginDir = join9(qwenStagingRoot(), connector.id);
|
|
2210
|
+
changes.push({
|
|
2211
|
+
platform: PLATFORM5,
|
|
2212
|
+
action: qwenExtensionInstalled(connector.id) ? "skip" : "create",
|
|
2213
|
+
detail: qwenExtensionInstalled(connector.id) ? `extension ${connector.id} already installed` : `run: ${manualInstall2(pluginDir)}`
|
|
2214
|
+
});
|
|
2215
|
+
},
|
|
2216
|
+
planUninstall(id, changes) {
|
|
2217
|
+
const pluginDir = join9(qwenStagingRoot(), id);
|
|
2218
|
+
changes.push({
|
|
2219
|
+
platform: PLATFORM5,
|
|
2220
|
+
action: qwenExtensionInstalled(id) ? "remove" : "skip",
|
|
2221
|
+
detail: qwenExtensionInstalled(id) ? `run: qwen extensions uninstall ${id}` : `extension ${id} not installed on ${PLATFORM5}`
|
|
2222
|
+
});
|
|
2223
|
+
if (existsSync9(pluginDir)) {
|
|
2224
|
+
changes.push({
|
|
2225
|
+
platform: PLATFORM5,
|
|
2226
|
+
action: "remove",
|
|
2227
|
+
path: pluginDir,
|
|
2228
|
+
detail: "remove staged marketplace bundle"
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
},
|
|
2232
|
+
async driveInstall(id) {
|
|
2233
|
+
const changes = [];
|
|
2234
|
+
const pluginDir = join9(qwenStagingRoot(), id);
|
|
2235
|
+
const bin = qwenBinary();
|
|
2236
|
+
if (!bin) {
|
|
2237
|
+
changes.push(
|
|
2238
|
+
warn5(
|
|
2239
|
+
`qwen CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall2(pluginDir)}`,
|
|
2240
|
+
pluginDir
|
|
2241
|
+
)
|
|
2242
|
+
);
|
|
2243
|
+
return { changes, ok: false };
|
|
2244
|
+
}
|
|
2245
|
+
if (qwenExtensionInstalled(id)) {
|
|
2246
|
+
changes.push({
|
|
2247
|
+
platform: PLATFORM5,
|
|
2248
|
+
action: "skip",
|
|
2249
|
+
detail: `extension ${id} already installed`
|
|
2250
|
+
});
|
|
2251
|
+
return { changes, ok: true };
|
|
2252
|
+
}
|
|
2253
|
+
const install = await runHostCommand(bin, ["extensions", "install", pluginDir]);
|
|
2254
|
+
if (!qwenExtensionInstalled(id)) {
|
|
2255
|
+
changes.push(
|
|
2256
|
+
warn5(
|
|
2257
|
+
`extension install did not complete \u2014 ` + failDetail7(`qwen extensions install ${pluginDir}`, install)
|
|
2258
|
+
)
|
|
2259
|
+
);
|
|
2260
|
+
return { changes, ok: false };
|
|
2261
|
+
}
|
|
2262
|
+
changes.push({
|
|
2263
|
+
platform: PLATFORM5,
|
|
2264
|
+
action: "create",
|
|
2265
|
+
detail: `installed extension ${id} (scope user)`
|
|
2266
|
+
});
|
|
2267
|
+
return { changes, ok: true };
|
|
2268
|
+
},
|
|
2269
|
+
async driveUninstall(id) {
|
|
2270
|
+
const changes = [];
|
|
2271
|
+
if (!qwenExtensionInstalled(id)) {
|
|
2272
|
+
changes.push({
|
|
2273
|
+
platform: PLATFORM5,
|
|
2274
|
+
action: "skip",
|
|
2275
|
+
detail: `extension ${id} not installed on ${PLATFORM5}`
|
|
2276
|
+
});
|
|
2277
|
+
return { changes, ok: true };
|
|
2278
|
+
}
|
|
2279
|
+
const bin = qwenBinary();
|
|
2280
|
+
if (!bin) {
|
|
2281
|
+
changes.push(
|
|
2282
|
+
warn5(
|
|
2283
|
+
`qwen CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: qwen extensions uninstall ${id}`
|
|
2284
|
+
)
|
|
2285
|
+
);
|
|
2286
|
+
return { changes, ok: false };
|
|
2287
|
+
}
|
|
2288
|
+
const uninstall = await runHostCommand(bin, ["extensions", "uninstall", id]);
|
|
2289
|
+
if (qwenExtensionInstalled(id)) {
|
|
2290
|
+
changes.push(
|
|
2291
|
+
warn5(
|
|
2292
|
+
`extension uninstall did not complete \u2014 ` + failDetail7(`qwen extensions uninstall ${id}`, uninstall)
|
|
2293
|
+
)
|
|
2294
|
+
);
|
|
2295
|
+
return { changes, ok: false };
|
|
2296
|
+
}
|
|
2297
|
+
changes.push({
|
|
2298
|
+
platform: PLATFORM5,
|
|
2299
|
+
action: "remove",
|
|
2300
|
+
detail: `uninstalled extension ${id} (qwen extensions uninstall)`
|
|
2301
|
+
});
|
|
2302
|
+
return { changes, ok: true };
|
|
2303
|
+
},
|
|
2304
|
+
// qwen documents an `extensions update <id>` verb (UNLIKE gemini, which has no
|
|
2305
|
+
// overwrite path) — PREFER it when the extension is already installed, else
|
|
2306
|
+
// fall back to a fresh install. The bundle was already re-staged by the caller.
|
|
2307
|
+
// DOCS-only: the `update` verb + its exit semantics are unverified live.
|
|
2308
|
+
async driveUpdate(id) {
|
|
2309
|
+
const changes = [];
|
|
2310
|
+
const pluginDir = join9(qwenStagingRoot(), id);
|
|
2311
|
+
const bin = qwenBinary();
|
|
2312
|
+
if (!bin) {
|
|
2313
|
+
changes.push(
|
|
2314
|
+
warn5(
|
|
2315
|
+
`qwen CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: qwen extensions update ${id}`,
|
|
2316
|
+
pluginDir
|
|
2317
|
+
)
|
|
2318
|
+
);
|
|
2319
|
+
return { changes, ok: false };
|
|
2320
|
+
}
|
|
2321
|
+
if (qwenExtensionInstalled(id)) {
|
|
2322
|
+
const update = await runHostCommand(bin, ["extensions", "update", id]);
|
|
2323
|
+
if (!qwenExtensionInstalled(id)) {
|
|
2324
|
+
changes.push(
|
|
2325
|
+
warn5(
|
|
2326
|
+
`extension update did not complete \u2014 ` + failDetail7(`qwen extensions update ${id}`, update)
|
|
2327
|
+
)
|
|
2328
|
+
);
|
|
2329
|
+
return { changes, ok: false };
|
|
2330
|
+
}
|
|
2331
|
+
changes.push({
|
|
2332
|
+
platform: PLATFORM5,
|
|
2333
|
+
action: "update",
|
|
2334
|
+
detail: `updated extension ${id} (qwen extensions update)`
|
|
2335
|
+
});
|
|
2336
|
+
return { changes, ok: true };
|
|
2337
|
+
}
|
|
2338
|
+
const install = await runHostCommand(bin, ["extensions", "install", pluginDir]);
|
|
2339
|
+
if (!qwenExtensionInstalled(id)) {
|
|
2340
|
+
changes.push(
|
|
2341
|
+
warn5(
|
|
2342
|
+
`extension install did not complete \u2014 ` + failDetail7(`qwen extensions install ${pluginDir}`, install)
|
|
2343
|
+
)
|
|
2344
|
+
);
|
|
2345
|
+
return { changes, ok: false };
|
|
2346
|
+
}
|
|
2347
|
+
changes.push({
|
|
2348
|
+
platform: PLATFORM5,
|
|
2349
|
+
action: "update",
|
|
2350
|
+
detail: `updated extension ${id} (qwen extensions install)`
|
|
2351
|
+
});
|
|
2352
|
+
return { changes, ok: true };
|
|
2353
|
+
},
|
|
2354
|
+
// Direct driver: no catalog, no marketplace de-registration. Cleanup is just
|
|
2355
|
+
// removing the staged bundle dir (the host copied it into its own store).
|
|
2356
|
+
async finishUninstall(id, changes) {
|
|
2357
|
+
const pluginDir = join9(qwenStagingRoot(), id);
|
|
2358
|
+
if (existsSync9(pluginDir)) {
|
|
2359
|
+
try {
|
|
2360
|
+
rmSync8(pluginDir, { recursive: true, force: true });
|
|
2361
|
+
changes.push({
|
|
2362
|
+
platform: PLATFORM5,
|
|
2363
|
+
action: "remove",
|
|
2364
|
+
path: pluginDir,
|
|
2365
|
+
detail: "removed staged marketplace bundle"
|
|
2366
|
+
});
|
|
2367
|
+
} catch (err) {
|
|
2368
|
+
changes.push({
|
|
2369
|
+
platform: PLATFORM5,
|
|
2370
|
+
action: "warn",
|
|
2371
|
+
path: pluginDir,
|
|
2372
|
+
detail: `could not remove staged bundle: ${errMessage8(err)}`
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
};
|
|
2378
|
+
|
|
2379
|
+
// src/core/marketplace-drivers/registry.ts
|
|
2380
|
+
var agyDrivers = /* @__PURE__ */ new Map();
|
|
2381
|
+
function agyDriver(platform) {
|
|
2382
|
+
let driver = agyDrivers.get(platform);
|
|
2383
|
+
if (!driver) {
|
|
2384
|
+
driver = makeAgyDriver(platform);
|
|
2385
|
+
agyDrivers.set(platform, driver);
|
|
2386
|
+
}
|
|
2387
|
+
return driver;
|
|
2388
|
+
}
|
|
2389
|
+
var NPM_LOCAL_BINARIES = {
|
|
2390
|
+
opencode: "opencode",
|
|
2391
|
+
kilo: "kilo",
|
|
2392
|
+
"kilo-cli": "kilo"
|
|
2393
|
+
};
|
|
2394
|
+
var npmLocalDrivers = /* @__PURE__ */ new Map();
|
|
2395
|
+
function npmLocalDriver(platform) {
|
|
2396
|
+
let driver = npmLocalDrivers.get(platform);
|
|
2397
|
+
if (!driver) {
|
|
2398
|
+
driver = makeNpmLocalDriver(platform, {
|
|
2399
|
+
binaryName: NPM_LOCAL_BINARIES[platform] ?? platform
|
|
2400
|
+
});
|
|
2401
|
+
npmLocalDrivers.set(platform, driver);
|
|
2402
|
+
}
|
|
2403
|
+
return driver;
|
|
2404
|
+
}
|
|
2405
|
+
function getMarketplaceDriver(platform) {
|
|
2406
|
+
switch (platform) {
|
|
2407
|
+
case "claude-code":
|
|
2408
|
+
return claudeDriver;
|
|
2409
|
+
case "codex":
|
|
2410
|
+
return codexDriver;
|
|
2411
|
+
case "antigravity":
|
|
2412
|
+
case "antigravity-cli":
|
|
2413
|
+
return agyDriver(platform);
|
|
2414
|
+
case "gemini-cli":
|
|
2415
|
+
return geminiDriver;
|
|
2416
|
+
case "qwen-code":
|
|
2417
|
+
return qwenDriver;
|
|
2418
|
+
case "droid":
|
|
2419
|
+
return droidDriver;
|
|
2420
|
+
case "opencode":
|
|
2421
|
+
case "kilo":
|
|
2422
|
+
case "kilo-cli":
|
|
2423
|
+
return npmLocalDriver(platform);
|
|
2424
|
+
default:
|
|
2425
|
+
return null;
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
// src/core/marketplace.ts
|
|
2430
|
+
function parseInstallMethod(value) {
|
|
2431
|
+
if (value == null || value === "direct" || value === "marketplace") {
|
|
2432
|
+
return value ?? "direct";
|
|
2433
|
+
}
|
|
2434
|
+
return null;
|
|
2435
|
+
}
|
|
2436
|
+
function parseUninstallMethod(value) {
|
|
2437
|
+
if (value == null || value === "auto" || value === "direct" || value === "marketplace") {
|
|
2438
|
+
return value ?? "auto";
|
|
2439
|
+
}
|
|
2440
|
+
return null;
|
|
2441
|
+
}
|
|
2442
|
+
var MARKETPLACE_FORMAT_BY_PLATFORM = {
|
|
2443
|
+
"claude-code": "claude-plugin",
|
|
2444
|
+
codex: "codex-plugin",
|
|
2445
|
+
droid: "factory-plugin",
|
|
2446
|
+
"gemini-cli": "gemini-extension",
|
|
2447
|
+
"qwen-code": "qwen-extension",
|
|
1435
2448
|
antigravity: "agy-plugin",
|
|
1436
2449
|
"antigravity-cli": "agy-plugin",
|
|
1437
2450
|
cursor: "cursor-plugin",
|
|
@@ -1448,12 +2461,18 @@ var DRIVABLE_MARKETPLACE_PLATFORMS = /* @__PURE__ */ new Set([
|
|
|
1448
2461
|
"claude-code",
|
|
1449
2462
|
"codex",
|
|
1450
2463
|
"antigravity",
|
|
1451
|
-
"antigravity-cli"
|
|
2464
|
+
"antigravity-cli",
|
|
2465
|
+
"gemini-cli",
|
|
2466
|
+
"qwen-code",
|
|
2467
|
+
"droid",
|
|
2468
|
+
"opencode",
|
|
2469
|
+
"kilo",
|
|
2470
|
+
"kilo-cli"
|
|
1452
2471
|
]);
|
|
1453
2472
|
function newResult2(connectorId, dryRun) {
|
|
1454
2473
|
return { connectorId, dryRun, changes: [], warnings: [] };
|
|
1455
2474
|
}
|
|
1456
|
-
function
|
|
2475
|
+
function errMessage9(err) {
|
|
1457
2476
|
return err instanceof Error ? err.message : String(err);
|
|
1458
2477
|
}
|
|
1459
2478
|
function manualHint(platform, format, id) {
|
|
@@ -1477,7 +2496,7 @@ async function directInstallPresent(connector, platform, scope, projectDir) {
|
|
|
1477
2496
|
const hookCommand = new RegExp(`--connector\\s+${escaped}(?![\\w-])`);
|
|
1478
2497
|
const matches = (path, re) => {
|
|
1479
2498
|
try {
|
|
1480
|
-
return re.test(
|
|
2499
|
+
return re.test(readFileSync4(path, "utf8"));
|
|
1481
2500
|
} catch {
|
|
1482
2501
|
return false;
|
|
1483
2502
|
}
|
|
@@ -1508,12 +2527,12 @@ async function installViaMarketplace(opts) {
|
|
|
1508
2527
|
try {
|
|
1509
2528
|
ensureHomeBin(resolveCliEntry());
|
|
1510
2529
|
} catch (err) {
|
|
1511
|
-
log.warn(`ensureHomeBin failed: ${
|
|
2530
|
+
log.warn(`ensureHomeBin failed: ${errMessage9(err)}`);
|
|
1512
2531
|
}
|
|
1513
2532
|
try {
|
|
1514
|
-
registerConnector(connector, modulePath);
|
|
2533
|
+
registerConnector(connector, modulePath, scope);
|
|
1515
2534
|
} catch (err) {
|
|
1516
|
-
log.warn(`registerConnector failed: ${
|
|
2535
|
+
log.warn(`registerConnector failed: ${errMessage9(err)}`);
|
|
1517
2536
|
}
|
|
1518
2537
|
}
|
|
1519
2538
|
const explicit = opts.targets != null && opts.targets.length > 0;
|
|
@@ -1663,16 +2682,16 @@ async function uninstallViaMarketplace(opts) {
|
|
|
1663
2682
|
const root2 = driver.stagingRoot();
|
|
1664
2683
|
if (seenRoots.has(root2)) continue;
|
|
1665
2684
|
seenRoots.add(root2);
|
|
1666
|
-
if (!
|
|
2685
|
+
if (!existsSync10(root2)) continue;
|
|
1667
2686
|
let bundleDirs;
|
|
1668
2687
|
try {
|
|
1669
|
-
bundleDirs =
|
|
2688
|
+
bundleDirs = readdirSync5(root2).filter((n) => !n.startsWith("."));
|
|
1670
2689
|
} catch {
|
|
1671
2690
|
bundleDirs = [];
|
|
1672
2691
|
}
|
|
1673
2692
|
if (bundleDirs.length > 0) continue;
|
|
1674
2693
|
try {
|
|
1675
|
-
|
|
2694
|
+
rmSync9(root2, { recursive: true, force: true });
|
|
1676
2695
|
result.changes.push({
|
|
1677
2696
|
platform: id,
|
|
1678
2697
|
action: "remove",
|
|
@@ -1680,13 +2699,13 @@ async function uninstallViaMarketplace(opts) {
|
|
|
1680
2699
|
detail: "removed empty marketplace staging root (--purge)"
|
|
1681
2700
|
});
|
|
1682
2701
|
} catch (err) {
|
|
1683
|
-
log.warn(`marketplace staging-root removal failed: ${
|
|
2702
|
+
log.warn(`marketplace staging-root removal failed: ${errMessage9(err)}`);
|
|
1684
2703
|
}
|
|
1685
2704
|
}
|
|
1686
2705
|
const root = marketplaceRoot();
|
|
1687
2706
|
try {
|
|
1688
|
-
if (
|
|
1689
|
-
|
|
2707
|
+
if (existsSync10(root) && readdirSync5(root).length === 0) {
|
|
2708
|
+
rmSync9(root, { recursive: true, force: true });
|
|
1690
2709
|
}
|
|
1691
2710
|
} catch {
|
|
1692
2711
|
}
|
|
@@ -1784,11 +2803,21 @@ async function marketplaceDoctorChecks(connector, scope, projectDir) {
|
|
|
1784
2803
|
const claude = await claudeMarketplaceGroup(connector, scope, projectDir);
|
|
1785
2804
|
if (claude) groups.push(claude);
|
|
1786
2805
|
const seenHosts = /* @__PURE__ */ new Set();
|
|
1787
|
-
const candidates = [
|
|
2806
|
+
const candidates = [
|
|
2807
|
+
"codex",
|
|
2808
|
+
"droid",
|
|
2809
|
+
"antigravity",
|
|
2810
|
+
"antigravity-cli",
|
|
2811
|
+
"gemini-cli",
|
|
2812
|
+
"qwen-code",
|
|
2813
|
+
"opencode",
|
|
2814
|
+
"kilo",
|
|
2815
|
+
"kilo-cli"
|
|
2816
|
+
].sort((a, b) => recordRank(connector.id, a) - recordRank(connector.id, b));
|
|
1788
2817
|
for (const platform of candidates) {
|
|
1789
2818
|
const driver = getMarketplaceDriver(platform);
|
|
1790
2819
|
if (!driver) continue;
|
|
1791
|
-
const hostKey = driver.stagingRoot();
|
|
2820
|
+
const hostKey = doctorHostKey(platform, driver.stagingRoot());
|
|
1792
2821
|
if (seenHosts.has(hostKey)) continue;
|
|
1793
2822
|
const group = await genericMarketplaceGroup(connector, platform, scope, projectDir);
|
|
1794
2823
|
if (group) {
|
|
@@ -1799,11 +2828,28 @@ async function marketplaceDoctorChecks(connector, scope, projectDir) {
|
|
|
1799
2828
|
groups.sort((a, b) => platformDoctorRank(a.platform) - platformDoctorRank(b.platform));
|
|
1800
2829
|
return groups;
|
|
1801
2830
|
}
|
|
2831
|
+
function doctorHostKey(platform, stagingRoot) {
|
|
2832
|
+
if (platform === "opencode" || platform === "kilo" || platform === "kilo-cli") {
|
|
2833
|
+
return npmConfigFilePath(platform);
|
|
2834
|
+
}
|
|
2835
|
+
return stagingRoot;
|
|
2836
|
+
}
|
|
1802
2837
|
function recordRank(connectorId, platform) {
|
|
1803
2838
|
return readMarketplaceInstalls(connectorId)[platform] ? 0 : 1;
|
|
1804
2839
|
}
|
|
1805
2840
|
function platformDoctorRank(platform) {
|
|
1806
|
-
const order = [
|
|
2841
|
+
const order = [
|
|
2842
|
+
"claude-code",
|
|
2843
|
+
"codex",
|
|
2844
|
+
"droid",
|
|
2845
|
+
"antigravity",
|
|
2846
|
+
"antigravity-cli",
|
|
2847
|
+
"gemini-cli",
|
|
2848
|
+
"qwen-code",
|
|
2849
|
+
"opencode",
|
|
2850
|
+
"kilo",
|
|
2851
|
+
"kilo-cli"
|
|
2852
|
+
];
|
|
1807
2853
|
const i = order.indexOf(platform);
|
|
1808
2854
|
return i === -1 ? order.length : i;
|
|
1809
2855
|
}
|
|
@@ -1826,19 +2872,19 @@ async function claudeMarketplaceGroup(connector, scope, projectDir) {
|
|
|
1826
2872
|
}
|
|
1827
2873
|
if (record) {
|
|
1828
2874
|
const registeredAt = claudeKnownMarketplacePath(MARKETPLACE_NAME);
|
|
1829
|
-
const catalogPath =
|
|
2875
|
+
const catalogPath = join10(stagingRoot, ".claude-plugin", "marketplace.json");
|
|
1830
2876
|
let catalogListed = false;
|
|
1831
2877
|
try {
|
|
1832
|
-
const catalog = JSON.parse(
|
|
2878
|
+
const catalog = JSON.parse(readFileSync4(catalogPath, "utf8"));
|
|
1833
2879
|
catalogListed = (catalog.plugins ?? []).some((p) => p.name === id);
|
|
1834
2880
|
} catch {
|
|
1835
2881
|
catalogListed = false;
|
|
1836
2882
|
}
|
|
1837
|
-
const intact = registeredAt === stagingRoot &&
|
|
2883
|
+
const intact = registeredAt === stagingRoot && existsSync10(record.bundleDir) && catalogListed;
|
|
1838
2884
|
results.push({
|
|
1839
2885
|
check: `${id}: marketplace registration`,
|
|
1840
2886
|
status: intact ? "pass" : "fail",
|
|
1841
|
-
message: intact ? `local marketplace "${MARKETPLACE_NAME}" registered at ${stagingRoot}, bundle staged + cataloged` : `marketplace registration broken (registered at ${registeredAt ?? "nowhere"}, bundle ${
|
|
2887
|
+
message: intact ? `local marketplace "${MARKETPLACE_NAME}" registered at ${stagingRoot}, bundle staged + cataloged` : `marketplace registration broken (registered at ${registeredAt ?? "nowhere"}, bundle ${existsSync10(record.bundleDir) ? "present" : "missing"}, catalog ${catalogListed ? "lists it" : "does not list it"})`,
|
|
1842
2888
|
...intact ? {} : { fix: `agent-connector install --method marketplace --targets claude-code` }
|
|
1843
2889
|
});
|
|
1844
2890
|
}
|
|
@@ -1865,7 +2911,7 @@ async function claudeMarketplaceGroup(connector, scope, projectDir) {
|
|
|
1865
2911
|
message: `connector.version ${connector.version} \u2260 installed ${record.version}`,
|
|
1866
2912
|
fix: `agent-connector upgrade --method marketplace --targets claude-code`
|
|
1867
2913
|
});
|
|
1868
|
-
} else if (
|
|
2914
|
+
} else if (existsSync10(record.bundleDir) && record.contentHash !== "" && hashDirectory(record.bundleDir) !== record.contentHash) {
|
|
1869
2915
|
results.push({
|
|
1870
2916
|
check: `${id}: marketplace staleness`,
|
|
1871
2917
|
status: "warn",
|
|
@@ -1874,7 +2920,7 @@ async function claudeMarketplaceGroup(connector, scope, projectDir) {
|
|
|
1874
2920
|
});
|
|
1875
2921
|
}
|
|
1876
2922
|
}
|
|
1877
|
-
if (pluginPresent && !
|
|
2923
|
+
if (pluginPresent && !existsSync10(homeBinPath())) {
|
|
1878
2924
|
results.push({
|
|
1879
2925
|
check: `${id}: marketplace home-bin`,
|
|
1880
2926
|
status: "fail",
|
|
@@ -1938,7 +2984,7 @@ async function genericMarketplaceGroup(connector, platform, scope, projectDir) {
|
|
|
1938
2984
|
message: `connector.version ${connector.version} \u2260 installed ${record.version}`,
|
|
1939
2985
|
fix: `agent-connector upgrade --method marketplace --targets ${platform}`
|
|
1940
2986
|
});
|
|
1941
|
-
} else if (
|
|
2987
|
+
} else if (existsSync10(record.bundleDir) && record.contentHash !== "" && hashDirectory(record.bundleDir) !== record.contentHash) {
|
|
1942
2988
|
results.push({
|
|
1943
2989
|
check: `${id}: marketplace staleness`,
|
|
1944
2990
|
status: "warn",
|
|
@@ -1947,7 +2993,7 @@ async function genericMarketplaceGroup(connector, platform, scope, projectDir) {
|
|
|
1947
2993
|
});
|
|
1948
2994
|
}
|
|
1949
2995
|
}
|
|
1950
|
-
if (installed && !
|
|
2996
|
+
if (installed && !existsSync10(homeBinPath())) {
|
|
1951
2997
|
results.push({
|
|
1952
2998
|
check: `${id}: marketplace home-bin`,
|
|
1953
2999
|
status: "fail",
|
|
@@ -1986,4 +3032,4 @@ export {
|
|
|
1986
3032
|
upgradeViaMarketplace,
|
|
1987
3033
|
marketplaceDoctorChecks
|
|
1988
3034
|
};
|
|
1989
|
-
//# sourceMappingURL=chunk-
|
|
3035
|
+
//# sourceMappingURL=chunk-G3ER4SY5.js.map
|