@ken-jo/agent-connector 0.3.0 → 0.3.1

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.
Files changed (36) hide show
  1. package/README.md +12 -8
  2. package/dist/{chunk-DS3LUFVN.js → chunk-3RBLIHPZ.js} +15 -15
  3. package/dist/{chunk-44HUXXC6.js → chunk-G5CQHVQG.js} +232 -5
  4. package/dist/chunk-G5CQHVQG.js.map +1 -0
  5. package/dist/{chunk-QADSG2JY.js → chunk-KMAKDD3Z.js} +1130 -109
  6. package/dist/chunk-KMAKDD3Z.js.map +1 -0
  7. package/dist/cli/sdk.js +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/{detect-MNDHGLSV.js → detect-U3E7NVNW.js} +2 -2
  10. package/dist/{doctor-N5KZDD55.js → doctor-DZTWED4O.js} +4 -4
  11. package/dist/{hook-7LUOKIXH.js → hook-EVY7LOUQ.js} +2 -2
  12. package/dist/{install-TQTT4F3I.js → install-OWAS5UIE.js} +4 -4
  13. package/dist/{leaderboard-MUJ7DURM.js → leaderboard-CSWHI4UY.js} +2 -2
  14. package/dist/{package-SYPA5POO.js → package-WFOS4QVU.js} +2 -2
  15. package/dist/{serve-XJOSA7BY.js → serve-3C2VFPAY.js} +2 -2
  16. package/dist/{status-DYSS6BOR.js → status-MKQYX5MW.js} +3 -3
  17. package/dist/{telemetry-IJ4GP2Q3.js → telemetry-3DN6XGYB.js} +2 -2
  18. package/dist/{uninstall-3DXIBRCV.js → uninstall-WG6PFWF3.js} +4 -4
  19. package/dist/{upgrade-GJEB3ITY.js → upgrade-32NC2RKI.js} +4 -4
  20. package/dist/{usage-2BJLM3GJ.js → usage-CJOM2WQM.js} +2 -2
  21. package/package.json +1 -1
  22. package/dist/chunk-44HUXXC6.js.map +0 -1
  23. package/dist/chunk-QADSG2JY.js.map +0 -1
  24. /package/dist/{chunk-DS3LUFVN.js.map → chunk-3RBLIHPZ.js.map} +0 -0
  25. /package/dist/{detect-MNDHGLSV.js.map → detect-U3E7NVNW.js.map} +0 -0
  26. /package/dist/{doctor-N5KZDD55.js.map → doctor-DZTWED4O.js.map} +0 -0
  27. /package/dist/{hook-7LUOKIXH.js.map → hook-EVY7LOUQ.js.map} +0 -0
  28. /package/dist/{install-TQTT4F3I.js.map → install-OWAS5UIE.js.map} +0 -0
  29. /package/dist/{leaderboard-MUJ7DURM.js.map → leaderboard-CSWHI4UY.js.map} +0 -0
  30. /package/dist/{package-SYPA5POO.js.map → package-WFOS4QVU.js.map} +0 -0
  31. /package/dist/{serve-XJOSA7BY.js.map → serve-3C2VFPAY.js.map} +0 -0
  32. /package/dist/{status-DYSS6BOR.js.map → status-MKQYX5MW.js.map} +0 -0
  33. /package/dist/{telemetry-IJ4GP2Q3.js.map → telemetry-3DN6XGYB.js.map} +0 -0
  34. /package/dist/{uninstall-3DXIBRCV.js.map → uninstall-WG6PFWF3.js.map} +0 -0
  35. /package/dist/{upgrade-GJEB3ITY.js.map → upgrade-32NC2RKI.js.map} +0 -0
  36. /package/dist/{usage-2BJLM3GJ.js.map → usage-CJOM2WQM.js.map} +0 -0
@@ -9,6 +9,7 @@ import {
9
9
  agyStagingRoot,
10
10
  anyClaudeAgentConnectorPlugins,
11
11
  anyCodexAgentConnectorPlugins,
12
+ anyDroidAgentConnectorPlugins,
12
13
  anyMarketplaceRecordsRemain,
13
14
  claudeKnownMarketplacePath,
14
15
  claudePluginInstalled,
@@ -19,12 +20,25 @@ 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-44HUXXC6.js";
41
+ } from "./chunk-G5CQHVQG.js";
28
42
  import {
29
43
  log,
30
44
  spawnChild
@@ -409,15 +423,15 @@ function errMessage(err) {
409
423
  }
410
424
 
411
425
  // src/core/marketplace.ts
412
- import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync3, rmSync as rmSync5 } from "fs";
413
- import { join as join6 } from "path";
426
+ import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync4, rmSync as rmSync9 } from "fs";
427
+ import { join as join10 } from "path";
414
428
 
415
429
  // src/core/marketplace-drivers/claude.ts
416
430
  import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync, rmSync as rmSync2, writeFileSync } from "fs";
417
431
  import { dirname as dirname2, join as join3 } from "path";
418
432
 
419
433
  // src/core/marketplace-drivers/shared.ts
420
- import { existsSync as existsSync2, statSync } from "fs";
434
+ import { existsSync as existsSync2, realpathSync, statSync } from "fs";
421
435
  import { delimiter, join as join2, resolve } from "path";
422
436
  var HOST_COMMAND_TIMEOUT_MS = 3e4;
423
437
  function findOnPath(command) {
@@ -437,7 +451,10 @@ function findOnPath(command) {
437
451
  }
438
452
  return null;
439
453
  }
440
- function runHostCommand(command, args, timeoutMs = HOST_COMMAND_TIMEOUT_MS) {
454
+ function runHostCommand(command, args, optionsOrTimeout = HOST_COMMAND_TIMEOUT_MS) {
455
+ const opts = typeof optionsOrTimeout === "number" ? { timeoutMs: optionsOrTimeout } : optionsOrTimeout;
456
+ const timeoutMs = opts.timeoutMs ?? HOST_COMMAND_TIMEOUT_MS;
457
+ const cwd = opts.cwd;
441
458
  return new Promise((resolvePromise) => {
442
459
  let stdout = "";
443
460
  let stderr = "";
@@ -453,7 +470,10 @@ function runHostCommand(command, args, timeoutMs = HOST_COMMAND_TIMEOUT_MS) {
453
470
  try {
454
471
  child = spawnChild(command, args, {
455
472
  stdio: ["ignore", "pipe", "pipe"],
456
- env: process.env
473
+ env: process.env,
474
+ // Only set cwd when a caller asked for it — omitting the key inherits
475
+ // the parent's cwd, keeping claude/codex/agy spawns byte-identical.
476
+ ...cwd != null ? { cwd } : {}
457
477
  });
458
478
  } catch (err) {
459
479
  const message = err instanceof Error ? err.message : String(err);
@@ -512,7 +532,11 @@ function samePath(a, b) {
512
532
  if (process.platform === "win32") {
513
533
  s = s.replace(/^\\\\\?\\UNC\\/, "\\\\").replace(/^\\\\\?\\/, "");
514
534
  }
515
- s = resolve(s);
535
+ try {
536
+ s = realpathSync.native(s);
537
+ } catch {
538
+ s = resolve(s);
539
+ }
516
540
  return process.platform === "win32" ? s.toLowerCase() : s;
517
541
  };
518
542
  return norm(a) === norm(b);
@@ -1192,25 +1216,326 @@ var codexDriver = {
1192
1216
  }
1193
1217
  };
1194
1218
 
1195
- // src/core/marketplace-drivers/agy.ts
1196
- import { existsSync as existsSync5, rmSync as rmSync4 } from "fs";
1219
+ // src/core/marketplace-drivers/droid.ts
1220
+ import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync3, rmSync as rmSync4, writeFileSync as writeFileSync3 } from "fs";
1197
1221
  import { join as join5 } from "path";
1198
- function agyBinary() {
1199
- return findOnPath("agy");
1222
+ var PLATFORM3 = "droid";
1223
+ function droidBinary() {
1224
+ return findOnPath("droid");
1225
+ }
1226
+ function droidManualInstallCommands(connectorId, stagingRoot) {
1227
+ return `droid plugin marketplace add ${stagingRoot} && droid plugin install ${droidPluginKey(connectorId)}`;
1200
1228
  }
1201
1229
  function errMessage4(err) {
1202
1230
  return err instanceof Error ? err.message : String(err);
1203
1231
  }
1232
+ function warn3(detail, path) {
1233
+ return { platform: PLATFORM3, action: "warn", detail, ...path ? { path } : {} };
1234
+ }
1204
1235
  function failDetail3(step, r) {
1205
1236
  if (r.timedOut) return `${step} timed out`;
1206
1237
  if (r.error) return `${step} failed to spawn: ${r.error}`;
1207
1238
  const line = firstLine(r.stderr) || firstLine(r.stdout);
1208
1239
  return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
1209
1240
  }
1210
- function stageAgyBundle(connector, platform, changes) {
1211
- const stagingRoot = agyStagingRoot();
1241
+ function stagedDroidPlugins(stagingRoot) {
1242
+ if (!existsSync5(stagingRoot)) return [];
1243
+ try {
1244
+ return readdirSync4(stagingRoot).filter(
1245
+ (name) => existsSync5(join5(stagingRoot, name, ".factory-plugin", "plugin.json"))
1246
+ ).sort();
1247
+ } catch {
1248
+ return [];
1249
+ }
1250
+ }
1251
+ function droidCatalogPath(stagingRoot) {
1252
+ return join5(stagingRoot, "marketplace.json");
1253
+ }
1254
+ function regenerateDroidCatalog(stagingRoot, changes) {
1255
+ const catalogPath = droidCatalogPath(stagingRoot);
1256
+ const plugins = stagedDroidPlugins(stagingRoot).map((name) => {
1257
+ let description = `${name} \u2014 connector emitted by agent-connector`;
1258
+ try {
1259
+ const manifest = JSON.parse(
1260
+ readFileSync3(join5(stagingRoot, name, ".factory-plugin", "plugin.json"), "utf8")
1261
+ );
1262
+ if (typeof manifest.description === "string") description = manifest.description;
1263
+ } catch {
1264
+ }
1265
+ return { name, source: `./${name}`, description };
1266
+ });
1267
+ const catalog = { name: MARKETPLACE_NAME, owner: { name: MARKETPLACE_NAME }, plugins };
1268
+ const serialized = `${JSON.stringify(catalog, null, 2)}
1269
+ `;
1270
+ let existing = null;
1271
+ try {
1272
+ existing = readFileSync3(catalogPath, "utf8");
1273
+ } catch {
1274
+ }
1275
+ if (existing === serialized) return;
1276
+ ensureDir(stagingRoot);
1277
+ writeFileSync3(catalogPath, serialized, "utf8");
1278
+ changes.push({
1279
+ platform: PLATFORM3,
1280
+ action: existing == null ? "create" : "update",
1281
+ path: catalogPath,
1282
+ detail: `regenerated shared marketplace catalog (${plugins.length} plugin(s))`
1283
+ });
1284
+ }
1285
+ function stageDroidBundle(connector, changes) {
1286
+ const stagingRoot = droidStagingRoot();
1212
1287
  const pluginDir = join5(stagingRoot, connector.id);
1213
1288
  const existed = existsSync5(pluginDir);
1289
+ const result = packageConnector(connector, { outDir: stagingRoot, format: "factory-plugin" });
1290
+ changes.push({
1291
+ platform: PLATFORM3,
1292
+ action: existed ? "update" : "create",
1293
+ path: pluginDir,
1294
+ detail: `staged marketplace bundle (${result.files.length} files, factory-plugin)`
1295
+ });
1296
+ regenerateDroidCatalog(stagingRoot, changes);
1297
+ return { pluginDir, contentHash: hashDirectory(pluginDir) };
1298
+ }
1299
+ async function driveInstall2(connectorId) {
1300
+ const stagingRoot = droidStagingRoot();
1301
+ const changes = [];
1302
+ const pluginKey = droidPluginKey(connectorId);
1303
+ const bin = droidBinary();
1304
+ if (!bin) {
1305
+ changes.push(
1306
+ warn3(
1307
+ `droid CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${droidManualInstallCommands(connectorId, stagingRoot)}`,
1308
+ stagingRoot
1309
+ )
1310
+ );
1311
+ return { changes, ok: false };
1312
+ }
1313
+ const registeredAt = droidMarketplaceSource(MARKETPLACE_NAME);
1314
+ if (samePath(registeredAt, stagingRoot)) {
1315
+ changes.push({
1316
+ platform: PLATFORM3,
1317
+ action: "skip",
1318
+ path: stagingRoot,
1319
+ detail: `marketplace "${MARKETPLACE_NAME}" already registered`
1320
+ });
1321
+ } else if (registeredAt != null) {
1322
+ changes.push(
1323
+ warn3(
1324
+ `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)
1325
+ )
1326
+ );
1327
+ return { changes, ok: false };
1328
+ } else {
1329
+ const add = await runHostCommand(bin, ["plugin", "marketplace", "add", stagingRoot]);
1330
+ if (!samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot)) {
1331
+ changes.push(
1332
+ warn3(
1333
+ `could not register the local marketplace \u2014 ` + failDetail3("droid plugin marketplace add", add) + `. Install manually: ${droidManualInstallCommands(connectorId, stagingRoot)}`,
1334
+ stagingRoot
1335
+ )
1336
+ );
1337
+ return { changes, ok: false };
1338
+ }
1339
+ changes.push({
1340
+ platform: PLATFORM3,
1341
+ action: "create",
1342
+ path: stagingRoot,
1343
+ detail: `registered local marketplace "${MARKETPLACE_NAME}" (droid plugin marketplace add)`
1344
+ });
1345
+ }
1346
+ if (droidPluginInstalled(connectorId)) {
1347
+ changes.push({
1348
+ platform: PLATFORM3,
1349
+ action: "skip",
1350
+ detail: `plugin ${pluginKey} already installed`
1351
+ });
1352
+ return { changes, ok: true };
1353
+ }
1354
+ const install = await runHostCommand(bin, ["plugin", "install", pluginKey]);
1355
+ if (!install.ok || !droidPluginInstalled(connectorId)) {
1356
+ changes.push(
1357
+ warn3(`plugin install did not complete \u2014 ` + failDetail3(`droid plugin install ${pluginKey}`, install))
1358
+ );
1359
+ return { changes, ok: false };
1360
+ }
1361
+ changes.push({
1362
+ platform: PLATFORM3,
1363
+ action: "create",
1364
+ detail: `installed plugin ${pluginKey} (scope user)`
1365
+ });
1366
+ return { changes, ok: true };
1367
+ }
1368
+ async function driveUninstall2(connectorId) {
1369
+ const changes = [];
1370
+ const pluginKey = droidPluginKey(connectorId);
1371
+ if (!droidPluginInstalled(connectorId)) {
1372
+ changes.push({
1373
+ platform: PLATFORM3,
1374
+ action: "skip",
1375
+ detail: `plugin ${pluginKey} not installed on droid`
1376
+ });
1377
+ return { changes, ok: true };
1378
+ }
1379
+ const bin = droidBinary();
1380
+ if (!bin) {
1381
+ changes.push(
1382
+ warn3(
1383
+ `droid CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: droid plugin uninstall ${pluginKey}`
1384
+ )
1385
+ );
1386
+ return { changes, ok: false };
1387
+ }
1388
+ const remove = await runHostCommand(bin, ["plugin", "uninstall", pluginKey]);
1389
+ if (!remove.ok || droidPluginInstalled(connectorId)) {
1390
+ changes.push(
1391
+ warn3(`plugin uninstall did not complete \u2014 ` + failDetail3(`droid plugin uninstall ${pluginKey}`, remove))
1392
+ );
1393
+ return { changes, ok: false };
1394
+ }
1395
+ changes.push({
1396
+ platform: PLATFORM3,
1397
+ action: "remove",
1398
+ detail: `uninstalled plugin ${pluginKey} (droid plugin uninstall)`
1399
+ });
1400
+ return { changes, ok: true };
1401
+ }
1402
+ async function driveMarketplaceRemove2(stagingRoot) {
1403
+ const bin = droidBinary();
1404
+ if (!bin) {
1405
+ return [
1406
+ warn3(
1407
+ `droid CLI not found on PATH \u2014 marketplace registration "${MARKETPLACE_NAME}" left behind. Run manually: droid plugin marketplace remove ${MARKETPLACE_NAME}`,
1408
+ stagingRoot
1409
+ )
1410
+ ];
1411
+ }
1412
+ const remove = await runHostCommand(bin, ["plugin", "marketplace", "remove", MARKETPLACE_NAME]);
1413
+ if (!remove.ok && droidMarketplaceSource(MARKETPLACE_NAME) != null) {
1414
+ return [
1415
+ warn3(
1416
+ `could not remove the marketplace registration \u2014 ` + failDetail3(`droid plugin marketplace remove ${MARKETPLACE_NAME}`, remove),
1417
+ stagingRoot
1418
+ )
1419
+ ];
1420
+ }
1421
+ return [
1422
+ {
1423
+ platform: PLATFORM3,
1424
+ action: "remove",
1425
+ path: stagingRoot,
1426
+ detail: `removed marketplace registration "${MARKETPLACE_NAME}" (no plugins remain)`
1427
+ }
1428
+ ];
1429
+ }
1430
+ var droidDriver = {
1431
+ platform: PLATFORM3,
1432
+ format: "factory-plugin",
1433
+ binary: droidBinary,
1434
+ stagingRoot: droidStagingRoot,
1435
+ pluginDir(id) {
1436
+ return join5(droidStagingRoot(), id);
1437
+ },
1438
+ installed: droidPluginInstalled,
1439
+ stage(connector, changes) {
1440
+ return stageDroidBundle(connector, changes).contentHash;
1441
+ },
1442
+ planInstall(connector, changes) {
1443
+ const stagingRoot = droidStagingRoot();
1444
+ const registered = samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot);
1445
+ changes.push({
1446
+ platform: PLATFORM3,
1447
+ action: registered ? "skip" : "create",
1448
+ path: stagingRoot,
1449
+ detail: registered ? `marketplace "${MARKETPLACE_NAME}" already registered` : `run: droid plugin marketplace add ${stagingRoot}`
1450
+ });
1451
+ changes.push({
1452
+ platform: PLATFORM3,
1453
+ action: droidPluginInstalled(connector.id) ? "skip" : "create",
1454
+ detail: droidPluginInstalled(connector.id) ? `plugin ${droidPluginKey(connector.id)} already installed` : `run: droid plugin install ${droidPluginKey(connector.id)}`
1455
+ });
1456
+ },
1457
+ planUninstall(id, changes) {
1458
+ const stagingRoot = droidStagingRoot();
1459
+ const pluginDir = join5(stagingRoot, id);
1460
+ const pluginKey = droidPluginKey(id);
1461
+ changes.push({
1462
+ platform: PLATFORM3,
1463
+ action: droidPluginInstalled(id) ? "remove" : "skip",
1464
+ detail: droidPluginInstalled(id) ? `run: droid plugin uninstall ${pluginKey}` : `plugin ${pluginKey} not installed on droid`
1465
+ });
1466
+ if (existsSync5(pluginDir)) {
1467
+ changes.push({
1468
+ platform: PLATFORM3,
1469
+ action: "remove",
1470
+ path: pluginDir,
1471
+ detail: "remove staged marketplace bundle"
1472
+ });
1473
+ }
1474
+ const othersStaged = stagedDroidPlugins(stagingRoot).some((n) => n !== id);
1475
+ if (!othersStaged && samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot)) {
1476
+ changes.push({
1477
+ platform: PLATFORM3,
1478
+ action: "remove",
1479
+ path: stagingRoot,
1480
+ detail: `run: droid plugin marketplace remove ${MARKETPLACE_NAME} (when no plugins remain)`
1481
+ });
1482
+ }
1483
+ },
1484
+ driveInstall: driveInstall2,
1485
+ driveUninstall: driveUninstall2,
1486
+ // droid has no documented `plugin update` verb — update IS re-stage (done by
1487
+ // the caller) + `plugin install`, assumed idempotent + version-cached (DOCS-only).
1488
+ async driveUpdate(id) {
1489
+ return driveInstall2(id);
1490
+ },
1491
+ async finishUninstall(id, changes) {
1492
+ const stagingRoot = droidStagingRoot();
1493
+ const pluginDir = join5(stagingRoot, id);
1494
+ if (existsSync5(pluginDir)) {
1495
+ try {
1496
+ rmSync4(pluginDir, { recursive: true, force: true });
1497
+ changes.push({
1498
+ platform: PLATFORM3,
1499
+ action: "remove",
1500
+ path: pluginDir,
1501
+ detail: "removed staged marketplace bundle"
1502
+ });
1503
+ } catch (err) {
1504
+ changes.push({
1505
+ platform: PLATFORM3,
1506
+ action: "warn",
1507
+ path: pluginDir,
1508
+ detail: `could not remove staged bundle: ${errMessage4(err)}`
1509
+ });
1510
+ }
1511
+ }
1512
+ if (existsSync5(stagingRoot)) regenerateDroidCatalog(stagingRoot, changes);
1513
+ const nothingStaged = stagedDroidPlugins(stagingRoot).length === 0;
1514
+ if (nothingStaged && !anyDroidAgentConnectorPlugins() && samePath(droidMarketplaceSource(MARKETPLACE_NAME), stagingRoot)) {
1515
+ changes.push(...await driveMarketplaceRemove2(stagingRoot));
1516
+ }
1517
+ }
1518
+ };
1519
+
1520
+ // src/core/marketplace-drivers/agy.ts
1521
+ import { existsSync as existsSync6, rmSync as rmSync5 } from "fs";
1522
+ import { join as join6 } from "path";
1523
+ function agyBinary() {
1524
+ return findOnPath("agy");
1525
+ }
1526
+ function errMessage5(err) {
1527
+ return err instanceof Error ? err.message : String(err);
1528
+ }
1529
+ function failDetail4(step, r) {
1530
+ if (r.timedOut) return `${step} timed out`;
1531
+ if (r.error) return `${step} failed to spawn: ${r.error}`;
1532
+ const line = firstLine(r.stderr) || firstLine(r.stdout);
1533
+ return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
1534
+ }
1535
+ function stageAgyBundle(connector, platform, changes) {
1536
+ const stagingRoot = agyStagingRoot();
1537
+ const pluginDir = join6(stagingRoot, connector.id);
1538
+ const existed = existsSync6(pluginDir);
1214
1539
  const result = packageConnector(connector, { outDir: stagingRoot, format: "agy-plugin" });
1215
1540
  changes.push({
1216
1541
  platform,
@@ -1221,27 +1546,27 @@ function stageAgyBundle(connector, platform, changes) {
1221
1546
  return { pluginDir, contentHash: hashDirectory(pluginDir) };
1222
1547
  }
1223
1548
  function makeAgyDriver(platform) {
1224
- const warn3 = (detail, path) => ({
1549
+ const warn6 = (detail, path) => ({
1225
1550
  platform,
1226
1551
  action: "warn",
1227
1552
  detail,
1228
1553
  ...path ? { path } : {}
1229
1554
  });
1230
- const manualInstall = (pluginDir) => `agy plugin install ${pluginDir}`;
1555
+ const manualInstall3 = (pluginDir) => `agy plugin install ${pluginDir}`;
1231
1556
  return {
1232
1557
  platform,
1233
1558
  format: "agy-plugin",
1234
1559
  binary: agyBinary,
1235
1560
  stagingRoot: agyStagingRoot,
1236
1561
  pluginDir(id) {
1237
- return join5(agyStagingRoot(), id);
1562
+ return join6(agyStagingRoot(), id);
1238
1563
  },
1239
1564
  installed: agyPluginInstalled,
1240
1565
  stage(connector, changes) {
1241
1566
  return stageAgyBundle(connector, platform, changes).contentHash;
1242
1567
  },
1243
1568
  planInstall(connector, changes) {
1244
- const pluginDir = join5(agyStagingRoot(), connector.id);
1569
+ const pluginDir = join6(agyStagingRoot(), connector.id);
1245
1570
  changes.push({
1246
1571
  platform,
1247
1572
  action: agyPluginInstalled(connector.id) ? "skip" : "create",
@@ -1249,13 +1574,13 @@ function makeAgyDriver(platform) {
1249
1574
  });
1250
1575
  },
1251
1576
  planUninstall(id, changes) {
1252
- const pluginDir = join5(agyStagingRoot(), id);
1577
+ const pluginDir = join6(agyStagingRoot(), id);
1253
1578
  changes.push({
1254
1579
  platform,
1255
1580
  action: agyPluginInstalled(id) ? "remove" : "skip",
1256
1581
  detail: agyPluginInstalled(id) ? `run: agy plugin uninstall ${id}` : `plugin ${id} not installed on ${platform}`
1257
1582
  });
1258
- if (existsSync5(pluginDir)) {
1583
+ if (existsSync6(pluginDir)) {
1259
1584
  changes.push({
1260
1585
  platform,
1261
1586
  action: "remove",
@@ -1266,12 +1591,12 @@ function makeAgyDriver(platform) {
1266
1591
  },
1267
1592
  async driveInstall(id) {
1268
1593
  const changes = [];
1269
- const pluginDir = join5(agyStagingRoot(), id);
1594
+ const pluginDir = join6(agyStagingRoot(), id);
1270
1595
  const bin = agyBinary();
1271
1596
  if (!bin) {
1272
1597
  changes.push(
1273
- warn3(
1274
- `agy CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall(pluginDir)}`,
1598
+ warn6(
1599
+ `agy CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall3(pluginDir)}`,
1275
1600
  pluginDir
1276
1601
  )
1277
1602
  );
@@ -1289,7 +1614,7 @@ function makeAgyDriver(platform) {
1289
1614
  const install = await runHostCommand(bin, ["plugin", "install", pluginDir]);
1290
1615
  if (!install.ok || !agyPluginInstalled(id)) {
1291
1616
  changes.push(
1292
- warn3(`plugin install did not complete \u2014 ` + failDetail3(`agy plugin install ${pluginDir}`, install))
1617
+ warn6(`plugin install did not complete \u2014 ` + failDetail4(`agy plugin install ${pluginDir}`, install))
1293
1618
  );
1294
1619
  return { changes, ok: false };
1295
1620
  }
@@ -1313,7 +1638,7 @@ function makeAgyDriver(platform) {
1313
1638
  const bin = agyBinary();
1314
1639
  if (!bin) {
1315
1640
  changes.push(
1316
- warn3(
1641
+ warn6(
1317
1642
  `agy CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: agy plugin uninstall ${id}`
1318
1643
  )
1319
1644
  );
@@ -1322,7 +1647,7 @@ function makeAgyDriver(platform) {
1322
1647
  const uninstall = await runHostCommand(bin, ["plugin", "uninstall", id]);
1323
1648
  if (!uninstall.ok || agyPluginInstalled(id)) {
1324
1649
  changes.push(
1325
- warn3(`plugin uninstall did not complete \u2014 ` + failDetail3(`agy plugin uninstall ${id}`, uninstall))
1650
+ warn6(`plugin uninstall did not complete \u2014 ` + failDetail4(`agy plugin uninstall ${id}`, uninstall))
1326
1651
  );
1327
1652
  return { changes, ok: false };
1328
1653
  }
@@ -1338,12 +1663,12 @@ function makeAgyDriver(platform) {
1338
1663
  // the probe already shows it present (the bundle on disk changed).
1339
1664
  async driveUpdate(id) {
1340
1665
  const changes = [];
1341
- const pluginDir = join5(agyStagingRoot(), id);
1666
+ const pluginDir = join6(agyStagingRoot(), id);
1342
1667
  const bin = agyBinary();
1343
1668
  if (!bin) {
1344
1669
  changes.push(
1345
- warn3(
1346
- `agy CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: ${manualInstall(pluginDir)}`,
1670
+ warn6(
1671
+ `agy CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: ${manualInstall3(pluginDir)}`,
1347
1672
  pluginDir
1348
1673
  )
1349
1674
  );
@@ -1352,7 +1677,7 @@ function makeAgyDriver(platform) {
1352
1677
  const install = await runHostCommand(bin, ["plugin", "install", pluginDir]);
1353
1678
  if (!install.ok || !agyPluginInstalled(id)) {
1354
1679
  changes.push(
1355
- warn3(`plugin install did not complete \u2014 ` + failDetail3(`agy plugin install ${pluginDir}`, install))
1680
+ warn6(`plugin install did not complete \u2014 ` + failDetail4(`agy plugin install ${pluginDir}`, install))
1356
1681
  );
1357
1682
  return { changes, ok: false };
1358
1683
  }
@@ -1366,10 +1691,10 @@ function makeAgyDriver(platform) {
1366
1691
  // Direct driver: no catalog, no marketplace de-registration. Cleanup is just
1367
1692
  // removing the staged bundle dir (the host copied it into its own store).
1368
1693
  async finishUninstall(id, changes) {
1369
- const pluginDir = join5(agyStagingRoot(), id);
1370
- if (existsSync5(pluginDir)) {
1694
+ const pluginDir = join6(agyStagingRoot(), id);
1695
+ if (existsSync6(pluginDir)) {
1371
1696
  try {
1372
- rmSync4(pluginDir, { recursive: true, force: true });
1697
+ rmSync5(pluginDir, { recursive: true, force: true });
1373
1698
  changes.push({
1374
1699
  platform,
1375
1700
  action: "remove",
@@ -1381,7 +1706,7 @@ function makeAgyDriver(platform) {
1381
1706
  platform,
1382
1707
  action: "warn",
1383
1708
  path: pluginDir,
1384
- detail: `could not remove staged bundle: ${errMessage4(err)}`
1709
+ detail: `could not remove staged bundle: ${errMessage5(err)}`
1385
1710
  });
1386
1711
  }
1387
1712
  }
@@ -1389,71 +1714,740 @@ function makeAgyDriver(platform) {
1389
1714
  };
1390
1715
  }
1391
1716
 
1392
- // src/core/marketplace-drivers/registry.ts
1393
- var agyDrivers = /* @__PURE__ */ new Map();
1394
- function agyDriver(platform) {
1395
- let driver = agyDrivers.get(platform);
1396
- if (!driver) {
1397
- driver = makeAgyDriver(platform);
1398
- agyDrivers.set(platform, driver);
1399
- }
1400
- return driver;
1717
+ // src/core/marketplace-drivers/gemini.ts
1718
+ import { existsSync as existsSync7, rmSync as rmSync6 } from "fs";
1719
+ import { join as join7 } from "path";
1720
+ var PLATFORM4 = "gemini-cli";
1721
+ function geminiBinary() {
1722
+ return findOnPath("gemini");
1723
+ }
1724
+ function errMessage6(err) {
1725
+ return err instanceof Error ? err.message : String(err);
1401
1726
  }
1402
- function getMarketplaceDriver(platform) {
1403
- switch (platform) {
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
- }
1727
+ function warn4(detail, path) {
1728
+ return { platform: PLATFORM4, action: "warn", detail, ...path ? { path } : {} };
1414
1729
  }
1415
-
1416
- // src/core/marketplace.ts
1417
- function parseInstallMethod(value) {
1418
- if (value == null || value === "direct" || value === "marketplace") {
1419
- return value ?? "direct";
1420
- }
1421
- return null;
1730
+ function failDetail5(step, r) {
1731
+ if (r.timedOut) return `${step} timed out`;
1732
+ if (r.error) return `${step} failed to spawn: ${r.error}`;
1733
+ const line = firstLine(r.stderr) || firstLine(r.stdout);
1734
+ return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
1422
1735
  }
1423
- function parseUninstallMethod(value) {
1424
- if (value == null || value === "auto" || value === "direct" || value === "marketplace") {
1425
- return value ?? "auto";
1426
- }
1427
- return null;
1736
+ function manualInstall(pluginDir) {
1737
+ return `gemini extensions install ${pluginDir} --consent`;
1428
1738
  }
1429
- var MARKETPLACE_FORMAT_BY_PLATFORM = {
1430
- "claude-code": "claude-plugin",
1431
- codex: "codex-plugin",
1432
- droid: "factory-plugin",
1433
- "gemini-cli": "gemini-extension",
1434
- "qwen-code": "qwen-extension",
1435
- antigravity: "agy-plugin",
1436
- "antigravity-cli": "agy-plugin",
1437
- cursor: "cursor-plugin",
1438
- kimi: "kimi-plugin",
1439
- opencode: "npm-plugin",
1440
- kilo: "npm-plugin",
1441
- "kilo-cli": "npm-plugin",
1442
- pi: "npm-plugin",
1443
- "vscode-copilot": "claude-plugin",
1444
- openclaw: "claude-plugin",
1445
- omp: "claude-plugin"
1446
- };
1447
- var DRIVABLE_MARKETPLACE_PLATFORMS = /* @__PURE__ */ new Set([
1448
- "claude-code",
1739
+ function stageGeminiBundle(connector, changes) {
1740
+ const stagingRoot = geminiStagingRoot();
1741
+ const pluginDir = join7(stagingRoot, connector.id);
1742
+ const existed = existsSync7(pluginDir);
1743
+ const result = packageConnector(connector, { outDir: stagingRoot, format: "gemini-extension" });
1744
+ changes.push({
1745
+ platform: PLATFORM4,
1746
+ action: existed ? "update" : "create",
1747
+ path: pluginDir,
1748
+ detail: `staged marketplace bundle (${result.files.length} files, gemini-extension)`
1749
+ });
1750
+ return { pluginDir, contentHash: hashDirectory(pluginDir) };
1751
+ }
1752
+ var geminiDriver = {
1753
+ platform: PLATFORM4,
1754
+ format: "gemini-extension",
1755
+ binary: geminiBinary,
1756
+ stagingRoot: geminiStagingRoot,
1757
+ pluginDir(id) {
1758
+ return join7(geminiStagingRoot(), id);
1759
+ },
1760
+ installed: geminiExtensionInstalled,
1761
+ stage(connector, changes) {
1762
+ return stageGeminiBundle(connector, changes).contentHash;
1763
+ },
1764
+ planInstall(connector, changes) {
1765
+ const pluginDir = join7(geminiStagingRoot(), connector.id);
1766
+ changes.push({
1767
+ platform: PLATFORM4,
1768
+ action: geminiExtensionInstalled(connector.id) ? "skip" : "create",
1769
+ detail: geminiExtensionInstalled(connector.id) ? `extension ${connector.id} already installed` : `run: ${manualInstall(pluginDir)}`
1770
+ });
1771
+ },
1772
+ planUninstall(id, changes) {
1773
+ const pluginDir = join7(geminiStagingRoot(), id);
1774
+ changes.push({
1775
+ platform: PLATFORM4,
1776
+ action: geminiExtensionInstalled(id) ? "remove" : "skip",
1777
+ detail: geminiExtensionInstalled(id) ? `run: gemini extensions uninstall ${id}` : `extension ${id} not installed on ${PLATFORM4}`
1778
+ });
1779
+ if (existsSync7(pluginDir)) {
1780
+ changes.push({
1781
+ platform: PLATFORM4,
1782
+ action: "remove",
1783
+ path: pluginDir,
1784
+ detail: "remove staged marketplace bundle"
1785
+ });
1786
+ }
1787
+ },
1788
+ async driveInstall(id) {
1789
+ const changes = [];
1790
+ const pluginDir = join7(geminiStagingRoot(), id);
1791
+ const bin = geminiBinary();
1792
+ if (!bin) {
1793
+ changes.push(
1794
+ warn4(
1795
+ `gemini CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall(pluginDir)}`,
1796
+ pluginDir
1797
+ )
1798
+ );
1799
+ return { changes, ok: false };
1800
+ }
1801
+ if (geminiExtensionInstalled(id)) {
1802
+ changes.push({
1803
+ platform: PLATFORM4,
1804
+ action: "skip",
1805
+ detail: `extension ${id} already installed`
1806
+ });
1807
+ return { changes, ok: true };
1808
+ }
1809
+ await runHostCommand(bin, ["extensions", "validate", pluginDir]);
1810
+ const install = await runHostCommand(bin, ["extensions", "install", pluginDir, "--consent"]);
1811
+ if (!geminiExtensionInstalled(id)) {
1812
+ const trustGated = /trust (the |this )?(files|folder)/i.test(
1813
+ `${install.stdout}
1814
+ ${install.stderr}`
1815
+ );
1816
+ changes.push(
1817
+ warn4(
1818
+ 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),
1819
+ pluginDir
1820
+ )
1821
+ );
1822
+ return { changes, ok: false };
1823
+ }
1824
+ changes.push({
1825
+ platform: PLATFORM4,
1826
+ action: "create",
1827
+ detail: `installed extension ${id} (scope user)`
1828
+ });
1829
+ return { changes, ok: true };
1830
+ },
1831
+ async driveUninstall(id) {
1832
+ const changes = [];
1833
+ if (!geminiExtensionInstalled(id)) {
1834
+ changes.push({
1835
+ platform: PLATFORM4,
1836
+ action: "skip",
1837
+ detail: `extension ${id} not installed on ${PLATFORM4}`
1838
+ });
1839
+ return { changes, ok: true };
1840
+ }
1841
+ const bin = geminiBinary();
1842
+ if (!bin) {
1843
+ changes.push(
1844
+ warn4(
1845
+ `gemini CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: gemini extensions uninstall ${id}`
1846
+ )
1847
+ );
1848
+ return { changes, ok: false };
1849
+ }
1850
+ const uninstall = await runHostCommand(bin, ["extensions", "uninstall", id]);
1851
+ if (geminiExtensionInstalled(id)) {
1852
+ changes.push(
1853
+ warn4(
1854
+ `extension uninstall did not complete \u2014 ` + failDetail5(`gemini extensions uninstall ${id}`, uninstall)
1855
+ )
1856
+ );
1857
+ return { changes, ok: false };
1858
+ }
1859
+ changes.push({
1860
+ platform: PLATFORM4,
1861
+ action: "remove",
1862
+ detail: `uninstalled extension ${id} (gemini extensions uninstall)`
1863
+ });
1864
+ return { changes, ok: true };
1865
+ },
1866
+ // gemini has NO overwrite-install (re-install REFUSES), so update is
1867
+ // uninstall-THEN-install. The bundle was already re-staged by the caller.
1868
+ async driveUpdate(id) {
1869
+ const changes = [];
1870
+ const pluginDir = join7(geminiStagingRoot(), id);
1871
+ const bin = geminiBinary();
1872
+ if (!bin) {
1873
+ changes.push(
1874
+ warn4(
1875
+ `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)}`,
1876
+ pluginDir
1877
+ )
1878
+ );
1879
+ return { changes, ok: false };
1880
+ }
1881
+ if (geminiExtensionInstalled(id)) {
1882
+ const uninstall = await runHostCommand(bin, ["extensions", "uninstall", id]);
1883
+ if (geminiExtensionInstalled(id)) {
1884
+ changes.push(
1885
+ warn4(
1886
+ `extension update could not remove the old copy \u2014 ` + failDetail5(`gemini extensions uninstall ${id}`, uninstall)
1887
+ )
1888
+ );
1889
+ return { changes, ok: false };
1890
+ }
1891
+ }
1892
+ await runHostCommand(bin, ["extensions", "validate", pluginDir]);
1893
+ const install = await runHostCommand(bin, ["extensions", "install", pluginDir, "--consent"]);
1894
+ if (!geminiExtensionInstalled(id)) {
1895
+ changes.push(
1896
+ warn4(
1897
+ `extension install did not complete \u2014 ` + failDetail5(`gemini extensions install ${pluginDir} --consent`, install)
1898
+ )
1899
+ );
1900
+ return { changes, ok: false };
1901
+ }
1902
+ changes.push({
1903
+ platform: PLATFORM4,
1904
+ action: "update",
1905
+ detail: `updated extension ${id} (gemini extensions uninstall + install)`
1906
+ });
1907
+ return { changes, ok: true };
1908
+ },
1909
+ // Direct driver: no catalog, no marketplace de-registration. Cleanup is just
1910
+ // removing the staged bundle dir (the host copied it into its own store).
1911
+ async finishUninstall(id, changes) {
1912
+ const pluginDir = join7(geminiStagingRoot(), id);
1913
+ if (existsSync7(pluginDir)) {
1914
+ try {
1915
+ rmSync6(pluginDir, { recursive: true, force: true });
1916
+ changes.push({
1917
+ platform: PLATFORM4,
1918
+ action: "remove",
1919
+ path: pluginDir,
1920
+ detail: "removed staged marketplace bundle"
1921
+ });
1922
+ } catch (err) {
1923
+ changes.push({
1924
+ platform: PLATFORM4,
1925
+ action: "warn",
1926
+ path: pluginDir,
1927
+ detail: `could not remove staged bundle: ${errMessage6(err)}`
1928
+ });
1929
+ }
1930
+ }
1931
+ }
1932
+ };
1933
+
1934
+ // src/core/marketplace-drivers/npm-local.ts
1935
+ import { existsSync as existsSync8, mkdirSync, rmSync as rmSync7, writeFileSync as writeFileSync4 } from "fs";
1936
+ import { dirname as dirname4, join as join8 } from "path";
1937
+ import { pathToFileURL } from "url";
1938
+ function errMessage7(err) {
1939
+ return err instanceof Error ? err.message : String(err);
1940
+ }
1941
+ function failDetail6(step, r) {
1942
+ if (r.timedOut) return `${step} timed out`;
1943
+ if (r.error) return `${step} failed to spawn: ${r.error}`;
1944
+ const line = firstLine(r.stderr) || firstLine(r.stdout);
1945
+ return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
1946
+ }
1947
+ function fileUrlFor(connectorId) {
1948
+ return pathToFileURL(join8(npmStagingRoot(), connectorId)).href;
1949
+ }
1950
+ function makeNpmLocalDriver(platform, opts) {
1951
+ const { binaryName } = opts;
1952
+ const binary = () => findOnPath(binaryName);
1953
+ const warn6 = (detail, path) => ({
1954
+ platform,
1955
+ action: "warn",
1956
+ detail,
1957
+ ...path ? { path } : {}
1958
+ });
1959
+ const manualInstall3 = (connectorId) => `${binaryName} plugin --global ${fileUrlFor(connectorId)}`;
1960
+ const stageBundle = (connector, changes) => {
1961
+ const stagingRoot = npmStagingRoot();
1962
+ const pluginDir = join8(stagingRoot, connector.id);
1963
+ const existed = existsSync8(pluginDir);
1964
+ const result = packageConnector(connector, { outDir: stagingRoot, format: "npm-plugin" });
1965
+ changes.push({
1966
+ platform,
1967
+ action: existed ? "update" : "create",
1968
+ path: pluginDir,
1969
+ detail: `staged marketplace bundle (${result.files.length} files, npm-plugin)`
1970
+ });
1971
+ return { pluginDir, contentHash: hashDirectory(pluginDir) };
1972
+ };
1973
+ const driveInstall3 = async (id) => {
1974
+ const changes = [];
1975
+ if (npmPluginInstalled(platform, id)) {
1976
+ changes.push({
1977
+ platform,
1978
+ action: "skip",
1979
+ detail: `plugin ${id} already installed`
1980
+ });
1981
+ return { changes, ok: true };
1982
+ }
1983
+ const bin = binary();
1984
+ if (!bin) {
1985
+ changes.push(
1986
+ warn6(
1987
+ `${binaryName} CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall3(id)}`,
1988
+ join8(npmStagingRoot(), id)
1989
+ )
1990
+ );
1991
+ return { changes, ok: false };
1992
+ }
1993
+ const stagingRoot = npmStagingRoot();
1994
+ try {
1995
+ mkdirSync(stagingRoot, { recursive: true });
1996
+ } catch {
1997
+ }
1998
+ const install = await runHostCommand(bin, ["plugin", "--global", fileUrlFor(id)], {
1999
+ cwd: stagingRoot
2000
+ });
2001
+ if (!npmPluginInstalled(platform, id)) {
2002
+ changes.push(
2003
+ warn6(`plugin install did not complete \u2014 ` + failDetail6(manualInstall3(id), install))
2004
+ );
2005
+ return { changes, ok: false };
2006
+ }
2007
+ changes.push({
2008
+ platform,
2009
+ action: "create",
2010
+ detail: `installed plugin ${id} (scope user)`
2011
+ });
2012
+ return { changes, ok: true };
2013
+ };
2014
+ return {
2015
+ platform,
2016
+ format: "npm-plugin",
2017
+ binary,
2018
+ stagingRoot: npmStagingRoot,
2019
+ pluginDir(id) {
2020
+ return join8(npmStagingRoot(), id);
2021
+ },
2022
+ installed: (id) => npmPluginInstalled(platform, id),
2023
+ stage(connector, changes) {
2024
+ return stageBundle(connector, changes).contentHash;
2025
+ },
2026
+ planInstall(connector, changes) {
2027
+ changes.push({
2028
+ platform,
2029
+ action: npmPluginInstalled(platform, connector.id) ? "skip" : "create",
2030
+ detail: npmPluginInstalled(platform, connector.id) ? `plugin ${connector.id} already installed` : `run: ${manualInstall3(connector.id)}`
2031
+ });
2032
+ },
2033
+ planUninstall(id, changes) {
2034
+ const pluginDir = join8(npmStagingRoot(), id);
2035
+ const present = npmPluginInstalled(platform, id);
2036
+ changes.push({
2037
+ platform,
2038
+ action: present ? "remove" : "skip",
2039
+ detail: present ? `edit ${npmConfigFilePath(platform)}: drop the file:// plugin entry for ${id}` : `plugin ${id} not installed on ${platform}`
2040
+ });
2041
+ if (existsSync8(pluginDir)) {
2042
+ changes.push({
2043
+ platform,
2044
+ action: "remove",
2045
+ path: pluginDir,
2046
+ detail: "remove staged marketplace bundle"
2047
+ });
2048
+ }
2049
+ },
2050
+ driveInstall: driveInstall3,
2051
+ // No host uninstall verb (`<bin> uninstall` removes the HOST). Removal is an
2052
+ // EDIT of the config `plugin` array: drop the entry referencing our staged
2053
+ // dir, delete the `plugin` key when empty, preserve every other key.
2054
+ async driveUninstall(id) {
2055
+ const changes = [];
2056
+ const entry = npmPluginArrayEntry(platform, id);
2057
+ if (entry == null) {
2058
+ changes.push({
2059
+ platform,
2060
+ action: "skip",
2061
+ detail: `plugin ${id} not installed on ${platform}`
2062
+ });
2063
+ return { changes, ok: true };
2064
+ }
2065
+ const configPath = npmConfigFilePath(platform);
2066
+ const cfg = readNpmConfig(platform);
2067
+ if (!cfg) {
2068
+ changes.push(
2069
+ warn6(
2070
+ `could not parse ${platform} config ${configPath} \u2014 leaving the plugin entry in place. Remove this entry from the "plugin" array by hand: ${entry}`,
2071
+ configPath
2072
+ )
2073
+ );
2074
+ return { changes, ok: false };
2075
+ }
2076
+ const arr = Array.isArray(cfg["plugin"]) ? cfg["plugin"] : [];
2077
+ const filtered = arr.filter((e) => e !== entry);
2078
+ if (filtered.length === 0) delete cfg["plugin"];
2079
+ else cfg["plugin"] = filtered;
2080
+ try {
2081
+ mkdirSync(dirname4(configPath), { recursive: true });
2082
+ writeFileSync4(configPath, `${JSON.stringify(cfg, null, 2)}
2083
+ `, "utf8");
2084
+ } catch (err) {
2085
+ changes.push(
2086
+ warn6(`could not rewrite ${platform} config: ${errMessage7(err)}`, configPath)
2087
+ );
2088
+ return { changes, ok: false };
2089
+ }
2090
+ if (npmPluginInstalled(platform, id)) {
2091
+ changes.push(
2092
+ warn6(`plugin entry persisted after the config edit \u2014 ${configPath}`, configPath)
2093
+ );
2094
+ return { changes, ok: false };
2095
+ }
2096
+ changes.push({
2097
+ platform,
2098
+ action: "remove",
2099
+ path: configPath,
2100
+ detail: `removed plugin ${id} from the ${platform} config "plugin" array`
2101
+ });
2102
+ return { changes, ok: true };
2103
+ },
2104
+ // The `file://` reference points at the LIVE staged dir, so an update is just
2105
+ // a re-run of install (the bundle was re-staged in place by the caller). When
2106
+ // the entry is already present, that is an idempotent `=` skip.
2107
+ async driveUpdate(id) {
2108
+ return driveInstall3(id);
2109
+ },
2110
+ // No catalog, no marketplace de-registration: cleanup is removing the staged
2111
+ // bundle dir (the host no longer references it after driveUninstall's edit).
2112
+ async finishUninstall(id, changes) {
2113
+ const pluginDir = join8(npmStagingRoot(), id);
2114
+ if (existsSync8(pluginDir)) {
2115
+ try {
2116
+ rmSync7(pluginDir, { recursive: true, force: true });
2117
+ changes.push({
2118
+ platform,
2119
+ action: "remove",
2120
+ path: pluginDir,
2121
+ detail: "removed staged marketplace bundle"
2122
+ });
2123
+ } catch (err) {
2124
+ changes.push({
2125
+ platform,
2126
+ action: "warn",
2127
+ path: pluginDir,
2128
+ detail: `could not remove staged bundle: ${errMessage7(err)}`
2129
+ });
2130
+ }
2131
+ }
2132
+ }
2133
+ };
2134
+ }
2135
+
2136
+ // src/core/marketplace-drivers/qwen.ts
2137
+ import { existsSync as existsSync9, rmSync as rmSync8 } from "fs";
2138
+ import { join as join9 } from "path";
2139
+ var PLATFORM5 = "qwen-code";
2140
+ function qwenBinary() {
2141
+ return findOnPath("qwen");
2142
+ }
2143
+ function errMessage8(err) {
2144
+ return err instanceof Error ? err.message : String(err);
2145
+ }
2146
+ function warn5(detail, path) {
2147
+ return { platform: PLATFORM5, action: "warn", detail, ...path ? { path } : {} };
2148
+ }
2149
+ function failDetail7(step, r) {
2150
+ if (r.timedOut) return `${step} timed out`;
2151
+ if (r.error) return `${step} failed to spawn: ${r.error}`;
2152
+ const line = firstLine(r.stderr) || firstLine(r.stdout);
2153
+ return `${step} exited ${r.code}${line ? `: ${line}` : ""}`;
2154
+ }
2155
+ function manualInstall2(pluginDir) {
2156
+ return `qwen extensions install ${pluginDir}`;
2157
+ }
2158
+ function stageQwenBundle(connector, changes) {
2159
+ const stagingRoot = qwenStagingRoot();
2160
+ const pluginDir = join9(stagingRoot, connector.id);
2161
+ const existed = existsSync9(pluginDir);
2162
+ const result = packageConnector(connector, { outDir: stagingRoot, format: "qwen-extension" });
2163
+ changes.push({
2164
+ platform: PLATFORM5,
2165
+ action: existed ? "update" : "create",
2166
+ path: pluginDir,
2167
+ detail: `staged marketplace bundle (${result.files.length} files, qwen-extension)`
2168
+ });
2169
+ return { pluginDir, contentHash: hashDirectory(pluginDir) };
2170
+ }
2171
+ var qwenDriver = {
2172
+ platform: PLATFORM5,
2173
+ format: "qwen-extension",
2174
+ binary: qwenBinary,
2175
+ stagingRoot: qwenStagingRoot,
2176
+ pluginDir(id) {
2177
+ return join9(qwenStagingRoot(), id);
2178
+ },
2179
+ installed: qwenExtensionInstalled,
2180
+ stage(connector, changes) {
2181
+ return stageQwenBundle(connector, changes).contentHash;
2182
+ },
2183
+ planInstall(connector, changes) {
2184
+ const pluginDir = join9(qwenStagingRoot(), connector.id);
2185
+ changes.push({
2186
+ platform: PLATFORM5,
2187
+ action: qwenExtensionInstalled(connector.id) ? "skip" : "create",
2188
+ detail: qwenExtensionInstalled(connector.id) ? `extension ${connector.id} already installed` : `run: ${manualInstall2(pluginDir)}`
2189
+ });
2190
+ },
2191
+ planUninstall(id, changes) {
2192
+ const pluginDir = join9(qwenStagingRoot(), id);
2193
+ changes.push({
2194
+ platform: PLATFORM5,
2195
+ action: qwenExtensionInstalled(id) ? "remove" : "skip",
2196
+ detail: qwenExtensionInstalled(id) ? `run: qwen extensions uninstall ${id}` : `extension ${id} not installed on ${PLATFORM5}`
2197
+ });
2198
+ if (existsSync9(pluginDir)) {
2199
+ changes.push({
2200
+ platform: PLATFORM5,
2201
+ action: "remove",
2202
+ path: pluginDir,
2203
+ detail: "remove staged marketplace bundle"
2204
+ });
2205
+ }
2206
+ },
2207
+ async driveInstall(id) {
2208
+ const changes = [];
2209
+ const pluginDir = join9(qwenStagingRoot(), id);
2210
+ const bin = qwenBinary();
2211
+ if (!bin) {
2212
+ changes.push(
2213
+ warn5(
2214
+ `qwen CLI not found on PATH \u2014 bundle staged but not installed. Install manually: ${manualInstall2(pluginDir)}`,
2215
+ pluginDir
2216
+ )
2217
+ );
2218
+ return { changes, ok: false };
2219
+ }
2220
+ if (qwenExtensionInstalled(id)) {
2221
+ changes.push({
2222
+ platform: PLATFORM5,
2223
+ action: "skip",
2224
+ detail: `extension ${id} already installed`
2225
+ });
2226
+ return { changes, ok: true };
2227
+ }
2228
+ const install = await runHostCommand(bin, ["extensions", "install", pluginDir]);
2229
+ if (!qwenExtensionInstalled(id)) {
2230
+ changes.push(
2231
+ warn5(
2232
+ `extension install did not complete \u2014 ` + failDetail7(`qwen extensions install ${pluginDir}`, install)
2233
+ )
2234
+ );
2235
+ return { changes, ok: false };
2236
+ }
2237
+ changes.push({
2238
+ platform: PLATFORM5,
2239
+ action: "create",
2240
+ detail: `installed extension ${id} (scope user)`
2241
+ });
2242
+ return { changes, ok: true };
2243
+ },
2244
+ async driveUninstall(id) {
2245
+ const changes = [];
2246
+ if (!qwenExtensionInstalled(id)) {
2247
+ changes.push({
2248
+ platform: PLATFORM5,
2249
+ action: "skip",
2250
+ detail: `extension ${id} not installed on ${PLATFORM5}`
2251
+ });
2252
+ return { changes, ok: true };
2253
+ }
2254
+ const bin = qwenBinary();
2255
+ if (!bin) {
2256
+ changes.push(
2257
+ warn5(
2258
+ `qwen CLI not found on PATH \u2014 cannot drive the uninstall. Run manually: qwen extensions uninstall ${id}`
2259
+ )
2260
+ );
2261
+ return { changes, ok: false };
2262
+ }
2263
+ const uninstall = await runHostCommand(bin, ["extensions", "uninstall", id]);
2264
+ if (qwenExtensionInstalled(id)) {
2265
+ changes.push(
2266
+ warn5(
2267
+ `extension uninstall did not complete \u2014 ` + failDetail7(`qwen extensions uninstall ${id}`, uninstall)
2268
+ )
2269
+ );
2270
+ return { changes, ok: false };
2271
+ }
2272
+ changes.push({
2273
+ platform: PLATFORM5,
2274
+ action: "remove",
2275
+ detail: `uninstalled extension ${id} (qwen extensions uninstall)`
2276
+ });
2277
+ return { changes, ok: true };
2278
+ },
2279
+ // qwen documents an `extensions update <id>` verb (UNLIKE gemini, which has no
2280
+ // overwrite path) — PREFER it when the extension is already installed, else
2281
+ // fall back to a fresh install. The bundle was already re-staged by the caller.
2282
+ // DOCS-only: the `update` verb + its exit semantics are unverified live.
2283
+ async driveUpdate(id) {
2284
+ const changes = [];
2285
+ const pluginDir = join9(qwenStagingRoot(), id);
2286
+ const bin = qwenBinary();
2287
+ if (!bin) {
2288
+ changes.push(
2289
+ warn5(
2290
+ `qwen CLI not found on PATH \u2014 bundle re-staged but the installed copy was not updated. Run manually: qwen extensions update ${id}`,
2291
+ pluginDir
2292
+ )
2293
+ );
2294
+ return { changes, ok: false };
2295
+ }
2296
+ if (qwenExtensionInstalled(id)) {
2297
+ const update = await runHostCommand(bin, ["extensions", "update", id]);
2298
+ if (!qwenExtensionInstalled(id)) {
2299
+ changes.push(
2300
+ warn5(
2301
+ `extension update did not complete \u2014 ` + failDetail7(`qwen extensions update ${id}`, update)
2302
+ )
2303
+ );
2304
+ return { changes, ok: false };
2305
+ }
2306
+ changes.push({
2307
+ platform: PLATFORM5,
2308
+ action: "update",
2309
+ detail: `updated extension ${id} (qwen extensions update)`
2310
+ });
2311
+ return { changes, ok: true };
2312
+ }
2313
+ const install = await runHostCommand(bin, ["extensions", "install", pluginDir]);
2314
+ if (!qwenExtensionInstalled(id)) {
2315
+ changes.push(
2316
+ warn5(
2317
+ `extension install did not complete \u2014 ` + failDetail7(`qwen extensions install ${pluginDir}`, install)
2318
+ )
2319
+ );
2320
+ return { changes, ok: false };
2321
+ }
2322
+ changes.push({
2323
+ platform: PLATFORM5,
2324
+ action: "update",
2325
+ detail: `updated extension ${id} (qwen extensions install)`
2326
+ });
2327
+ return { changes, ok: true };
2328
+ },
2329
+ // Direct driver: no catalog, no marketplace de-registration. Cleanup is just
2330
+ // removing the staged bundle dir (the host copied it into its own store).
2331
+ async finishUninstall(id, changes) {
2332
+ const pluginDir = join9(qwenStagingRoot(), id);
2333
+ if (existsSync9(pluginDir)) {
2334
+ try {
2335
+ rmSync8(pluginDir, { recursive: true, force: true });
2336
+ changes.push({
2337
+ platform: PLATFORM5,
2338
+ action: "remove",
2339
+ path: pluginDir,
2340
+ detail: "removed staged marketplace bundle"
2341
+ });
2342
+ } catch (err) {
2343
+ changes.push({
2344
+ platform: PLATFORM5,
2345
+ action: "warn",
2346
+ path: pluginDir,
2347
+ detail: `could not remove staged bundle: ${errMessage8(err)}`
2348
+ });
2349
+ }
2350
+ }
2351
+ }
2352
+ };
2353
+
2354
+ // src/core/marketplace-drivers/registry.ts
2355
+ var agyDrivers = /* @__PURE__ */ new Map();
2356
+ function agyDriver(platform) {
2357
+ let driver = agyDrivers.get(platform);
2358
+ if (!driver) {
2359
+ driver = makeAgyDriver(platform);
2360
+ agyDrivers.set(platform, driver);
2361
+ }
2362
+ return driver;
2363
+ }
2364
+ var NPM_LOCAL_BINARIES = {
2365
+ opencode: "opencode",
2366
+ kilo: "kilo",
2367
+ "kilo-cli": "kilo"
2368
+ };
2369
+ var npmLocalDrivers = /* @__PURE__ */ new Map();
2370
+ function npmLocalDriver(platform) {
2371
+ let driver = npmLocalDrivers.get(platform);
2372
+ if (!driver) {
2373
+ driver = makeNpmLocalDriver(platform, {
2374
+ binaryName: NPM_LOCAL_BINARIES[platform] ?? platform
2375
+ });
2376
+ npmLocalDrivers.set(platform, driver);
2377
+ }
2378
+ return driver;
2379
+ }
2380
+ function getMarketplaceDriver(platform) {
2381
+ switch (platform) {
2382
+ case "claude-code":
2383
+ return claudeDriver;
2384
+ case "codex":
2385
+ return codexDriver;
2386
+ case "antigravity":
2387
+ case "antigravity-cli":
2388
+ return agyDriver(platform);
2389
+ case "gemini-cli":
2390
+ return geminiDriver;
2391
+ case "qwen-code":
2392
+ return qwenDriver;
2393
+ case "droid":
2394
+ return droidDriver;
2395
+ case "opencode":
2396
+ case "kilo":
2397
+ case "kilo-cli":
2398
+ return npmLocalDriver(platform);
2399
+ default:
2400
+ return null;
2401
+ }
2402
+ }
2403
+
2404
+ // src/core/marketplace.ts
2405
+ function parseInstallMethod(value) {
2406
+ if (value == null || value === "direct" || value === "marketplace") {
2407
+ return value ?? "direct";
2408
+ }
2409
+ return null;
2410
+ }
2411
+ function parseUninstallMethod(value) {
2412
+ if (value == null || value === "auto" || value === "direct" || value === "marketplace") {
2413
+ return value ?? "auto";
2414
+ }
2415
+ return null;
2416
+ }
2417
+ var MARKETPLACE_FORMAT_BY_PLATFORM = {
2418
+ "claude-code": "claude-plugin",
2419
+ codex: "codex-plugin",
2420
+ droid: "factory-plugin",
2421
+ "gemini-cli": "gemini-extension",
2422
+ "qwen-code": "qwen-extension",
2423
+ antigravity: "agy-plugin",
2424
+ "antigravity-cli": "agy-plugin",
2425
+ cursor: "cursor-plugin",
2426
+ kimi: "kimi-plugin",
2427
+ opencode: "npm-plugin",
2428
+ kilo: "npm-plugin",
2429
+ "kilo-cli": "npm-plugin",
2430
+ pi: "npm-plugin",
2431
+ "vscode-copilot": "claude-plugin",
2432
+ openclaw: "claude-plugin",
2433
+ omp: "claude-plugin"
2434
+ };
2435
+ var DRIVABLE_MARKETPLACE_PLATFORMS = /* @__PURE__ */ new Set([
2436
+ "claude-code",
1449
2437
  "codex",
1450
2438
  "antigravity",
1451
- "antigravity-cli"
2439
+ "antigravity-cli",
2440
+ "gemini-cli",
2441
+ "qwen-code",
2442
+ "droid",
2443
+ "opencode",
2444
+ "kilo",
2445
+ "kilo-cli"
1452
2446
  ]);
1453
2447
  function newResult2(connectorId, dryRun) {
1454
2448
  return { connectorId, dryRun, changes: [], warnings: [] };
1455
2449
  }
1456
- function errMessage5(err) {
2450
+ function errMessage9(err) {
1457
2451
  return err instanceof Error ? err.message : String(err);
1458
2452
  }
1459
2453
  function manualHint(platform, format, id) {
@@ -1477,7 +2471,7 @@ async function directInstallPresent(connector, platform, scope, projectDir) {
1477
2471
  const hookCommand = new RegExp(`--connector\\s+${escaped}(?![\\w-])`);
1478
2472
  const matches = (path, re) => {
1479
2473
  try {
1480
- return re.test(readFileSync3(path, "utf8"));
2474
+ return re.test(readFileSync4(path, "utf8"));
1481
2475
  } catch {
1482
2476
  return false;
1483
2477
  }
@@ -1508,12 +2502,12 @@ async function installViaMarketplace(opts) {
1508
2502
  try {
1509
2503
  ensureHomeBin(resolveCliEntry());
1510
2504
  } catch (err) {
1511
- log.warn(`ensureHomeBin failed: ${errMessage5(err)}`);
2505
+ log.warn(`ensureHomeBin failed: ${errMessage9(err)}`);
1512
2506
  }
1513
2507
  try {
1514
2508
  registerConnector(connector, modulePath);
1515
2509
  } catch (err) {
1516
- log.warn(`registerConnector failed: ${errMessage5(err)}`);
2510
+ log.warn(`registerConnector failed: ${errMessage9(err)}`);
1517
2511
  }
1518
2512
  }
1519
2513
  const explicit = opts.targets != null && opts.targets.length > 0;
@@ -1663,16 +2657,16 @@ async function uninstallViaMarketplace(opts) {
1663
2657
  const root2 = driver.stagingRoot();
1664
2658
  if (seenRoots.has(root2)) continue;
1665
2659
  seenRoots.add(root2);
1666
- if (!existsSync6(root2)) continue;
2660
+ if (!existsSync10(root2)) continue;
1667
2661
  let bundleDirs;
1668
2662
  try {
1669
- bundleDirs = readdirSync4(root2).filter((n) => !n.startsWith("."));
2663
+ bundleDirs = readdirSync5(root2).filter((n) => !n.startsWith("."));
1670
2664
  } catch {
1671
2665
  bundleDirs = [];
1672
2666
  }
1673
2667
  if (bundleDirs.length > 0) continue;
1674
2668
  try {
1675
- rmSync5(root2, { recursive: true, force: true });
2669
+ rmSync9(root2, { recursive: true, force: true });
1676
2670
  result.changes.push({
1677
2671
  platform: id,
1678
2672
  action: "remove",
@@ -1680,13 +2674,13 @@ async function uninstallViaMarketplace(opts) {
1680
2674
  detail: "removed empty marketplace staging root (--purge)"
1681
2675
  });
1682
2676
  } catch (err) {
1683
- log.warn(`marketplace staging-root removal failed: ${errMessage5(err)}`);
2677
+ log.warn(`marketplace staging-root removal failed: ${errMessage9(err)}`);
1684
2678
  }
1685
2679
  }
1686
2680
  const root = marketplaceRoot();
1687
2681
  try {
1688
- if (existsSync6(root) && readdirSync4(root).length === 0) {
1689
- rmSync5(root, { recursive: true, force: true });
2682
+ if (existsSync10(root) && readdirSync5(root).length === 0) {
2683
+ rmSync9(root, { recursive: true, force: true });
1690
2684
  }
1691
2685
  } catch {
1692
2686
  }
@@ -1784,11 +2778,21 @@ async function marketplaceDoctorChecks(connector, scope, projectDir) {
1784
2778
  const claude = await claudeMarketplaceGroup(connector, scope, projectDir);
1785
2779
  if (claude) groups.push(claude);
1786
2780
  const seenHosts = /* @__PURE__ */ new Set();
1787
- const candidates = ["codex", "antigravity", "antigravity-cli"].sort((a, b) => recordRank(connector.id, a) - recordRank(connector.id, b));
2781
+ const candidates = [
2782
+ "codex",
2783
+ "droid",
2784
+ "antigravity",
2785
+ "antigravity-cli",
2786
+ "gemini-cli",
2787
+ "qwen-code",
2788
+ "opencode",
2789
+ "kilo",
2790
+ "kilo-cli"
2791
+ ].sort((a, b) => recordRank(connector.id, a) - recordRank(connector.id, b));
1788
2792
  for (const platform of candidates) {
1789
2793
  const driver = getMarketplaceDriver(platform);
1790
2794
  if (!driver) continue;
1791
- const hostKey = driver.stagingRoot();
2795
+ const hostKey = doctorHostKey(platform, driver.stagingRoot());
1792
2796
  if (seenHosts.has(hostKey)) continue;
1793
2797
  const group = await genericMarketplaceGroup(connector, platform, scope, projectDir);
1794
2798
  if (group) {
@@ -1799,11 +2803,28 @@ async function marketplaceDoctorChecks(connector, scope, projectDir) {
1799
2803
  groups.sort((a, b) => platformDoctorRank(a.platform) - platformDoctorRank(b.platform));
1800
2804
  return groups;
1801
2805
  }
2806
+ function doctorHostKey(platform, stagingRoot) {
2807
+ if (platform === "opencode" || platform === "kilo" || platform === "kilo-cli") {
2808
+ return npmConfigFilePath(platform);
2809
+ }
2810
+ return stagingRoot;
2811
+ }
1802
2812
  function recordRank(connectorId, platform) {
1803
2813
  return readMarketplaceInstalls(connectorId)[platform] ? 0 : 1;
1804
2814
  }
1805
2815
  function platformDoctorRank(platform) {
1806
- const order = ["claude-code", "codex", "antigravity", "antigravity-cli"];
2816
+ const order = [
2817
+ "claude-code",
2818
+ "codex",
2819
+ "droid",
2820
+ "antigravity",
2821
+ "antigravity-cli",
2822
+ "gemini-cli",
2823
+ "qwen-code",
2824
+ "opencode",
2825
+ "kilo",
2826
+ "kilo-cli"
2827
+ ];
1807
2828
  const i = order.indexOf(platform);
1808
2829
  return i === -1 ? order.length : i;
1809
2830
  }
@@ -1826,19 +2847,19 @@ async function claudeMarketplaceGroup(connector, scope, projectDir) {
1826
2847
  }
1827
2848
  if (record) {
1828
2849
  const registeredAt = claudeKnownMarketplacePath(MARKETPLACE_NAME);
1829
- const catalogPath = join6(stagingRoot, ".claude-plugin", "marketplace.json");
2850
+ const catalogPath = join10(stagingRoot, ".claude-plugin", "marketplace.json");
1830
2851
  let catalogListed = false;
1831
2852
  try {
1832
- const catalog = JSON.parse(readFileSync3(catalogPath, "utf8"));
2853
+ const catalog = JSON.parse(readFileSync4(catalogPath, "utf8"));
1833
2854
  catalogListed = (catalog.plugins ?? []).some((p) => p.name === id);
1834
2855
  } catch {
1835
2856
  catalogListed = false;
1836
2857
  }
1837
- const intact = registeredAt === stagingRoot && existsSync6(record.bundleDir) && catalogListed;
2858
+ const intact = registeredAt === stagingRoot && existsSync10(record.bundleDir) && catalogListed;
1838
2859
  results.push({
1839
2860
  check: `${id}: marketplace registration`,
1840
2861
  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 ${existsSync6(record.bundleDir) ? "present" : "missing"}, catalog ${catalogListed ? "lists it" : "does not list it"})`,
2862
+ 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
2863
  ...intact ? {} : { fix: `agent-connector install --method marketplace --targets claude-code` }
1843
2864
  });
1844
2865
  }
@@ -1865,7 +2886,7 @@ async function claudeMarketplaceGroup(connector, scope, projectDir) {
1865
2886
  message: `connector.version ${connector.version} \u2260 installed ${record.version}`,
1866
2887
  fix: `agent-connector upgrade --method marketplace --targets claude-code`
1867
2888
  });
1868
- } else if (existsSync6(record.bundleDir) && record.contentHash !== "" && hashDirectory(record.bundleDir) !== record.contentHash) {
2889
+ } else if (existsSync10(record.bundleDir) && record.contentHash !== "" && hashDirectory(record.bundleDir) !== record.contentHash) {
1869
2890
  results.push({
1870
2891
  check: `${id}: marketplace staleness`,
1871
2892
  status: "warn",
@@ -1874,7 +2895,7 @@ async function claudeMarketplaceGroup(connector, scope, projectDir) {
1874
2895
  });
1875
2896
  }
1876
2897
  }
1877
- if (pluginPresent && !existsSync6(homeBinPath())) {
2898
+ if (pluginPresent && !existsSync10(homeBinPath())) {
1878
2899
  results.push({
1879
2900
  check: `${id}: marketplace home-bin`,
1880
2901
  status: "fail",
@@ -1938,7 +2959,7 @@ async function genericMarketplaceGroup(connector, platform, scope, projectDir) {
1938
2959
  message: `connector.version ${connector.version} \u2260 installed ${record.version}`,
1939
2960
  fix: `agent-connector upgrade --method marketplace --targets ${platform}`
1940
2961
  });
1941
- } else if (existsSync6(record.bundleDir) && record.contentHash !== "" && hashDirectory(record.bundleDir) !== record.contentHash) {
2962
+ } else if (existsSync10(record.bundleDir) && record.contentHash !== "" && hashDirectory(record.bundleDir) !== record.contentHash) {
1942
2963
  results.push({
1943
2964
  check: `${id}: marketplace staleness`,
1944
2965
  status: "warn",
@@ -1947,7 +2968,7 @@ async function genericMarketplaceGroup(connector, platform, scope, projectDir) {
1947
2968
  });
1948
2969
  }
1949
2970
  }
1950
- if (installed && !existsSync6(homeBinPath())) {
2971
+ if (installed && !existsSync10(homeBinPath())) {
1951
2972
  results.push({
1952
2973
  check: `${id}: marketplace home-bin`,
1953
2974
  status: "fail",
@@ -1986,4 +3007,4 @@ export {
1986
3007
  upgradeViaMarketplace,
1987
3008
  marketplaceDoctorChecks
1988
3009
  };
1989
- //# sourceMappingURL=chunk-QADSG2JY.js.map
3010
+ //# sourceMappingURL=chunk-KMAKDD3Z.js.map