@tonyclaw/agent-inspector 2.1.7 → 2.1.8

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 (34) hide show
  1. package/.output/cli.js +274 -140
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-BLS7CVvA.js → CompareDrawer-CHkT7kun.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-BFZ1WG07.js → ProxyViewerContainer-BiZ2_tMC.js} +21 -21
  5. package/.output/public/assets/{ReplayDialog-DIGF807X.js → ReplayDialog-C85cakjx.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-C3Nlvp9P.js → RequestAnatomy-Dn_pMMoX.js} +1 -1
  7. package/.output/public/assets/{ResponseView-BbZywqHe.js → ResponseView-DzcxCUBf.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-Dk27PfPn.js → StreamingChunkSequence-BamtvkgZ.js} +1 -1
  9. package/.output/public/assets/_sessionId-xBBbFH1M.js +1 -0
  10. package/.output/public/assets/index-6udjwQO1.js +1 -0
  11. package/.output/public/assets/{main-BxHXMs6B.js → main-Dc2qVWpb.js} +2 -2
  12. package/.output/server/{_sessionId-D5HNwb9A.mjs → _sessionId-BnimGger.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-QNk1twf8.mjs → CompareDrawer-CwVFykVF.mjs} +2 -2
  14. package/.output/server/_ssr/{ProxyViewerContainer-DGhc2le_.mjs → ProxyViewerContainer-X3S2TWBJ.mjs} +205 -132
  15. package/.output/server/_ssr/{ReplayDialog-D8wg4VNL.mjs → ReplayDialog-BxC12XUj.mjs} +3 -3
  16. package/.output/server/_ssr/{RequestAnatomy-BtJHKVl2.mjs → RequestAnatomy-CWWS8Qh7.mjs} +2 -2
  17. package/.output/server/_ssr/{ResponseView-CndDItiU.mjs → ResponseView-BewErHF-.mjs} +2 -2
  18. package/.output/server/_ssr/{StreamingChunkSequence-D5Ywpbr7.mjs → StreamingChunkSequence-BlmCVryW.mjs} +2 -2
  19. package/.output/server/_ssr/{index-DtcUTHAX.mjs → index-5qbGuoFX.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-C0apgqfC.mjs → router-s78S54MU.mjs} +16 -7
  22. package/.output/server/{_tanstack-start-manifest_v-BoTPaB-V.mjs → _tanstack-start-manifest_v-DTxpr3KE.mjs} +1 -1
  23. package/.output/server/index.mjs +63 -63
  24. package/README.md +10 -6
  25. package/package.json +1 -1
  26. package/src/cli/detect-tools.ts +2 -1
  27. package/src/cli/onboard.ts +334 -167
  28. package/src/components/providers/SettingsDialog.tsx +47 -0
  29. package/src/components/proxy-viewer/ConversationGroup.tsx +28 -0
  30. package/src/components/proxy-viewer/ConversationHeader.tsx +34 -0
  31. package/src/components/proxy-viewer/LogEntryHeader.tsx +3 -12
  32. package/src/mcp/server.ts +18 -4
  33. package/.output/public/assets/_sessionId-BHpX8AVf.js +0 -1
  34. package/.output/public/assets/index-BXHM9OMb.js +0 -1
package/.output/cli.js CHANGED
@@ -52,7 +52,7 @@ function detectOpenCode() {
52
52
  return { found: true, path: configDir ?? bin ?? "" };
53
53
  }
54
54
  function detectMiMo() {
55
- const configDir = tryDir(join(homedir(), ".mimo"));
55
+ const configDir = tryDir(join(homedir(), ".config", "mimocode")) ?? tryDir(join(homedir(), ".mimocode"));
56
56
  const bin = which("mimo");
57
57
  if (configDir === null && bin === null) return { found: false };
58
58
  return { found: true, path: configDir ?? bin ?? "" };
@@ -943,6 +943,11 @@ function parseFlags(argv) {
943
943
  opencodeConfig: null,
944
944
  opencodeTransport: "local",
945
945
  opencodeMcpUrl: DEFAULT_MCP_URL,
946
+ mimo: false,
947
+ mimoOnly: false,
948
+ mimoConfig: null,
949
+ mimoTransport: "local",
950
+ mimoMcpUrl: DEFAULT_MCP_URL,
946
951
  uninstall: false,
947
952
  status: false,
948
953
  json: false,
@@ -1024,6 +1029,54 @@ function parseFlags(argv) {
1024
1029
  i++;
1025
1030
  break;
1026
1031
  }
1032
+ case "--mimo":
1033
+ flags.mimo = true;
1034
+ break;
1035
+ case "--mimo-only":
1036
+ flags.mimo = true;
1037
+ flags.mimoOnly = true;
1038
+ break;
1039
+ case "--mimo-config": {
1040
+ const next = argv[i + 1];
1041
+ if (next === void 0) {
1042
+ process.stderr.write("agent-inspector onboard: --mimo-config requires a path argument\n");
1043
+ process.exit(2);
1044
+ }
1045
+ flags.mimoConfig = next;
1046
+ i++;
1047
+ break;
1048
+ }
1049
+ case "--mimo-transport": {
1050
+ const next = argv[i + 1];
1051
+ if (next === void 0) {
1052
+ process.stderr.write(
1053
+ "agent-inspector onboard: --mimo-transport requires local or remote\n"
1054
+ );
1055
+ process.exit(2);
1056
+ }
1057
+ switch (next) {
1058
+ case "local":
1059
+ case "remote":
1060
+ flags.mimoTransport = next;
1061
+ break;
1062
+ default:
1063
+ process.stderr.write(`agent-inspector onboard: invalid --mimo-transport: ${next}
1064
+ `);
1065
+ process.exit(2);
1066
+ }
1067
+ i++;
1068
+ break;
1069
+ }
1070
+ case "--mimo-mcp-url": {
1071
+ const next = argv[i + 1];
1072
+ if (next === void 0) {
1073
+ process.stderr.write("agent-inspector onboard: --mimo-mcp-url requires a URL\n");
1074
+ process.exit(2);
1075
+ }
1076
+ flags.mimoMcpUrl = next;
1077
+ i++;
1078
+ break;
1079
+ }
1027
1080
  case "--uninstall":
1028
1081
  flags.uninstall = true;
1029
1082
  break;
@@ -1087,6 +1140,12 @@ Options:
1087
1140
  --opencode-transport <local|remote>
1088
1141
  OpenCode MCP transport to write (default: local)
1089
1142
  --opencode-mcp-url <url> Agent Inspector MCP endpoint for OpenCode
1143
+ --mimo Also configure MiMo Code MCP in mimocode.json/jsonc
1144
+ --mimo-only Configure only MiMo Code MCP
1145
+ --mimo-config <path> Override MiMo config path (default: ~/.config/mimocode/mimocode.jsonc)
1146
+ --mimo-transport <local|remote>
1147
+ MiMo Code MCP transport to write (default: local)
1148
+ --mimo-mcp-url <url> Agent Inspector MCP endpoint for MiMo Code
1090
1149
  --uninstall Remove generated files whose version matches this package
1091
1150
  --status Show installed onboarding file versions and suggested action
1092
1151
  --json Emit machine-readable JSON with --status
@@ -1118,6 +1177,12 @@ function isObject(value) {
1118
1177
  function isOpenCodeEnabled(flags) {
1119
1178
  return flags.opencode || flags.opencodeOnly;
1120
1179
  }
1180
+ function isMiMoEnabled(flags) {
1181
+ return flags.mimo || flags.mimoOnly;
1182
+ }
1183
+ function hasOnlyAgentMcpTarget(flags) {
1184
+ return flags.opencodeOnly || flags.mimoOnly;
1185
+ }
1121
1186
  function resolveOpenCodeConfigPath(flags) {
1122
1187
  if (flags.opencodeConfig !== null) {
1123
1188
  return flags.opencodeConfig;
@@ -1129,6 +1194,60 @@ function resolveOpenCodeConfigPath(flags) {
1129
1194
  }
1130
1195
  return join2(configDir, "opencode.json");
1131
1196
  }
1197
+ function resolveMiMoConfigPath(flags) {
1198
+ if (flags.mimoConfig !== null) {
1199
+ return flags.mimoConfig;
1200
+ }
1201
+ const configDir = join2(homedir2(), ".config", "mimocode");
1202
+ const jsoncPath = join2(configDir, "mimocode.jsonc");
1203
+ if (existsSync2(jsoncPath)) {
1204
+ return jsoncPath;
1205
+ }
1206
+ const jsonPath = join2(configDir, "mimocode.json");
1207
+ if (existsSync2(jsonPath)) {
1208
+ return jsonPath;
1209
+ }
1210
+ const legacyDir = join2(homedir2(), ".mimocode");
1211
+ const legacyJsoncPath = join2(legacyDir, "config.jsonc");
1212
+ if (existsSync2(legacyJsoncPath)) {
1213
+ return legacyJsoncPath;
1214
+ }
1215
+ const legacyJsonPath = join2(legacyDir, "config.json");
1216
+ if (existsSync2(legacyJsonPath)) {
1217
+ return legacyJsonPath;
1218
+ }
1219
+ return jsoncPath;
1220
+ }
1221
+ function openCodeTarget(flags) {
1222
+ return {
1223
+ label: "OpenCode",
1224
+ configLabel: "OpenCode MCP config",
1225
+ configPath: resolveOpenCodeConfigPath(flags),
1226
+ transport: flags.opencodeTransport,
1227
+ endpoint: flags.opencodeMcpUrl,
1228
+ setupAction: "agent-inspector onboard --opencode-only",
1229
+ forceAction: "agent-inspector onboard --opencode-only --force",
1230
+ verifyCommand: "opencode mcp list",
1231
+ invalidAction: "fix OpenCode JSON/JSONC, then rerun agent-inspector onboard --opencode-only",
1232
+ configObjectName: "mcp.agent-inspector",
1233
+ defaultSchema: "https://opencode.ai/config.json"
1234
+ };
1235
+ }
1236
+ function miMoTarget(flags) {
1237
+ return {
1238
+ label: "MiMo Code",
1239
+ configLabel: "MiMo Code MCP config",
1240
+ configPath: resolveMiMoConfigPath(flags),
1241
+ transport: flags.mimoTransport,
1242
+ endpoint: flags.mimoMcpUrl,
1243
+ setupAction: "agent-inspector onboard --mimo-only",
1244
+ forceAction: "agent-inspector onboard --mimo-only --force",
1245
+ verifyCommand: "mimo mcp list",
1246
+ invalidAction: "fix MiMo Code JSON/JSONC, then rerun agent-inspector onboard --mimo-only",
1247
+ configObjectName: "mcp.agent-inspector",
1248
+ defaultSchema: "https://mimo.xiaomi.com/mimocode/config.json"
1249
+ };
1250
+ }
1132
1251
  function stripJsoncComments(raw) {
1133
1252
  let result = "";
1134
1253
  let index = 0;
@@ -1177,7 +1296,7 @@ function stripJsoncComments(raw) {
1177
1296
  }
1178
1297
  return result;
1179
1298
  }
1180
- function readOpenCodeConfig(path) {
1299
+ function readAgentConfig(path, target) {
1181
1300
  if (!existsSync2(path)) {
1182
1301
  return { ok: true, exists: false, config: {} };
1183
1302
  }
@@ -1193,7 +1312,7 @@ function readOpenCodeConfig(path) {
1193
1312
  return {
1194
1313
  ok: false,
1195
1314
  exists: true,
1196
- message: "OpenCode config root must be a JSON object"
1315
+ message: `${target.label} config root must be a JSON object`
1197
1316
  };
1198
1317
  } catch (err) {
1199
1318
  const message = err instanceof Error ? err.message : String(err);
@@ -1204,7 +1323,7 @@ function readOpenCodeConfig(path) {
1204
1323
  };
1205
1324
  }
1206
1325
  }
1207
- function buildOpenCodeMcpEntry(transport, endpoint) {
1326
+ function buildAgentMcpEntry(transport, endpoint) {
1208
1327
  switch (transport) {
1209
1328
  case "local":
1210
1329
  return {
@@ -1232,7 +1351,7 @@ function stringArrayEquals(value, expected) {
1232
1351
  }
1233
1352
  return value.every((item, index) => item === expected[index]);
1234
1353
  }
1235
- function isOpenCodeLocalEntry(value, endpoint, ignoreEnabled) {
1354
+ function isAgentLocalEntry(value, endpoint, ignoreEnabled) {
1236
1355
  if (!isObject(value)) {
1237
1356
  return false;
1238
1357
  }
@@ -1250,7 +1369,7 @@ function isOpenCodeLocalEntry(value, endpoint, ignoreEnabled) {
1250
1369
  const usesEnv = stringArrayEquals(value["command"], ["agent-inspector-mcp", "stdio"]) && isObject(env) && env["AGENT_INSPECTOR_MCP_URL"] === endpoint;
1251
1370
  return value["type"] === "local" && (usesUrlArg || usesEnv);
1252
1371
  }
1253
- function isOpenCodeRemoteEntry(value, endpoint, ignoreEnabled) {
1372
+ function isAgentRemoteEntry(value, endpoint, ignoreEnabled) {
1254
1373
  if (!isObject(value)) {
1255
1374
  return false;
1256
1375
  }
@@ -1260,10 +1379,10 @@ function isOpenCodeRemoteEntry(value, endpoint, ignoreEnabled) {
1260
1379
  }
1261
1380
  return value["type"] === "remote" && value["url"] === endpoint;
1262
1381
  }
1263
- function isKnownOpenCodeEntry(value, endpoint, ignoreEnabled) {
1264
- return isOpenCodeLocalEntry(value, endpoint, ignoreEnabled) || isOpenCodeRemoteEntry(value, endpoint, ignoreEnabled);
1382
+ function isKnownAgentEntry(value, endpoint, ignoreEnabled) {
1383
+ return isAgentLocalEntry(value, endpoint, ignoreEnabled) || isAgentRemoteEntry(value, endpoint, ignoreEnabled);
1265
1384
  }
1266
- function detectOpenCodeTransport(value) {
1385
+ function detectAgentTransport(value) {
1267
1386
  if (!isObject(value)) {
1268
1387
  return "unknown";
1269
1388
  }
@@ -1276,45 +1395,47 @@ function detectOpenCodeTransport(value) {
1276
1395
  return "unknown";
1277
1396
  }
1278
1397
  }
1279
- function openCodeActionForStatus(status) {
1398
+ function agentActionForStatus(target, status) {
1280
1399
  switch (status.state) {
1281
1400
  case "missing":
1282
- return "agent-inspector onboard --opencode-only";
1401
+ return target.setupAction;
1283
1402
  case "configured":
1284
- return "opencode mcp list";
1403
+ return target.verifyCommand;
1285
1404
  case "disabled":
1286
1405
  case "custom":
1287
- return "agent-inspector onboard --opencode-only --force";
1406
+ return target.forceAction;
1288
1407
  case "invalid":
1289
- return "fix OpenCode JSON/JSONC, then rerun agent-inspector onboard --opencode-only";
1408
+ return target.invalidAction;
1290
1409
  default:
1291
- return "agent-inspector onboard --opencode-only";
1410
+ return target.setupAction;
1292
1411
  }
1293
1412
  }
1294
- function makeOpenCodeStatus(path, state, transport, endpoint, detail) {
1413
+ function makeAgentStatus(target, state, transport, detail) {
1295
1414
  const status = {
1296
- label: "OpenCode MCP config",
1297
- path,
1415
+ label: target.configLabel,
1416
+ path: target.configPath,
1298
1417
  state,
1299
1418
  transport,
1300
- endpoint,
1301
- action: "agent-inspector onboard --opencode-only",
1419
+ endpoint: target.endpoint,
1420
+ action: target.setupAction,
1421
+ forceAction: target.forceAction,
1422
+ verifyCommand: target.verifyCommand,
1302
1423
  detail
1303
1424
  };
1304
1425
  return {
1305
1426
  ...status,
1306
- action: openCodeActionForStatus(status)
1427
+ action: agentActionForStatus(target, status)
1307
1428
  };
1308
1429
  }
1309
- function getOpenCodeEntry(config) {
1430
+ function getAgentEntry(config) {
1310
1431
  const mcp = config["mcp"];
1311
1432
  if (!isObject(mcp)) {
1312
1433
  return void 0;
1313
1434
  }
1314
1435
  return mcp["agent-inspector"];
1315
1436
  }
1316
- function buildOpenCodeConfig(config, transport, endpoint) {
1317
- const schema = typeof config["$schema"] === "string" ? config["$schema"] : "https://opencode.ai/config.json";
1437
+ function buildAgentConfig(config, target) {
1438
+ const schema = typeof config["$schema"] === "string" ? config["$schema"] : target.defaultSchema;
1318
1439
  const nextConfig = {
1319
1440
  $schema: schema
1320
1441
  };
@@ -1325,15 +1446,15 @@ function buildOpenCodeConfig(config, transport, endpoint) {
1325
1446
  }
1326
1447
  const currentMcp = config["mcp"];
1327
1448
  const nextMcp = isObject(currentMcp) ? { ...currentMcp } : {};
1328
- nextMcp["agent-inspector"] = buildOpenCodeMcpEntry(transport, endpoint);
1449
+ nextMcp["agent-inspector"] = buildAgentMcpEntry(target.transport, target.endpoint);
1329
1450
  nextConfig["mcp"] = nextMcp;
1330
1451
  return nextConfig;
1331
1452
  }
1332
- function formatOpenCodeConfig(config) {
1453
+ function formatAgentConfig(config) {
1333
1454
  return `${JSON.stringify(config, null, 2)}
1334
1455
  `;
1335
1456
  }
1336
- function removeOpenCodeEntry(config) {
1457
+ function removeAgentEntry(config) {
1337
1458
  const nextConfig = {};
1338
1459
  for (const [key, value] of Object.entries(config)) {
1339
1460
  if (key !== "mcp") {
@@ -1355,70 +1476,63 @@ function removeOpenCodeEntry(config) {
1355
1476
  }
1356
1477
  return nextConfig;
1357
1478
  }
1358
- function readOpenCodeStatus(flags) {
1359
- const path = resolveOpenCodeConfigPath(flags);
1360
- const read = readOpenCodeConfig(path);
1479
+ function readAgentStatus(target) {
1480
+ const read = readAgentConfig(target.configPath, target);
1361
1481
  if (!read.ok) {
1362
- return makeOpenCodeStatus(path, "invalid", "unknown", flags.opencodeMcpUrl, read.message);
1482
+ return makeAgentStatus(target, "invalid", "unknown", read.message);
1363
1483
  }
1364
- const entry = getOpenCodeEntry(read.config);
1484
+ const entry = getAgentEntry(read.config);
1365
1485
  if (entry === void 0) {
1366
- const detail = read.exists ? "OpenCode config has no mcp.agent-inspector entry" : "Missing file";
1367
- return makeOpenCodeStatus(path, "missing", "unknown", flags.opencodeMcpUrl, detail);
1486
+ const detail = read.exists ? `${target.label} config has no ${target.configObjectName}` : "Missing file";
1487
+ return makeAgentStatus(target, "missing", "unknown", detail);
1368
1488
  }
1369
- const transport = detectOpenCodeTransport(entry);
1489
+ const transport = detectAgentTransport(entry);
1370
1490
  if (isObject(entry) && entry["enabled"] === false) {
1371
- return makeOpenCodeStatus(
1372
- path,
1491
+ return makeAgentStatus(
1492
+ target,
1373
1493
  "disabled",
1374
1494
  transport,
1375
- flags.opencodeMcpUrl,
1376
- "mcp.agent-inspector is present but disabled"
1495
+ `${target.configObjectName} is present but disabled`
1377
1496
  );
1378
1497
  }
1379
- if (isKnownOpenCodeEntry(entry, flags.opencodeMcpUrl, false)) {
1380
- return makeOpenCodeStatus(
1381
- path,
1498
+ if (isKnownAgentEntry(entry, target.endpoint, false)) {
1499
+ return makeAgentStatus(
1500
+ target,
1382
1501
  "configured",
1383
1502
  transport,
1384
- flags.opencodeMcpUrl,
1385
- "mcp.agent-inspector points at Agent Inspector MCP"
1503
+ `${target.configObjectName} points at Agent Inspector MCP`
1386
1504
  );
1387
1505
  }
1388
- return makeOpenCodeStatus(
1389
- path,
1506
+ return makeAgentStatus(
1507
+ target,
1390
1508
  "custom",
1391
1509
  transport,
1392
- flags.opencodeMcpUrl,
1393
- "mcp.agent-inspector exists but does not match Agent Inspector defaults"
1510
+ `${target.configObjectName} exists but does not match Agent Inspector defaults`
1394
1511
  );
1395
1512
  }
1396
- function buildOpenCodePlan(flags) {
1397
- const path = resolveOpenCodeConfigPath(flags);
1398
- const read = readOpenCodeConfig(path);
1513
+ function buildAgentPlan(target, uninstall, force) {
1514
+ const read = readAgentConfig(target.configPath, target);
1399
1515
  if (!read.ok) {
1400
1516
  return {
1401
- status: makeOpenCodeStatus(path, "invalid", "unknown", flags.opencodeMcpUrl, read.message),
1517
+ status: makeAgentStatus(target, "invalid", "unknown", read.message),
1402
1518
  body: null,
1403
1519
  shouldWrite: false,
1404
1520
  shouldRemove: false,
1405
- blockedMessage: `OpenCode config is invalid: ${read.message}`
1521
+ blockedMessage: `${target.label} config is invalid: ${read.message}`
1406
1522
  };
1407
1523
  }
1408
- const status = readOpenCodeStatus(flags);
1409
- const entry = getOpenCodeEntry(read.config);
1410
- const nextBody = formatOpenCodeConfig(
1411
- buildOpenCodeConfig(read.config, flags.opencodeTransport, flags.opencodeMcpUrl)
1412
- );
1413
- if (flags.uninstall) {
1414
- const shouldRemove = entry !== void 0 && isKnownOpenCodeEntry(entry, flags.opencodeMcpUrl, true);
1415
- const removeBody = shouldRemove ? formatOpenCodeConfig(removeOpenCodeEntry(read.config)) : null;
1524
+ const status = readAgentStatus(target);
1525
+ const entry = getAgentEntry(read.config);
1526
+ const nextBody = formatAgentConfig(buildAgentConfig(read.config, target));
1527
+ if (uninstall) {
1528
+ const shouldRemove = entry !== void 0 && isKnownAgentEntry(entry, target.endpoint, true);
1529
+ const removeBody = shouldRemove ? formatAgentConfig(removeAgentEntry(read.config)) : null;
1416
1530
  return {
1417
1531
  status,
1418
1532
  body: removeBody,
1419
1533
  shouldWrite: false,
1420
1534
  shouldRemove,
1421
- blockedMessage: shouldRemove ? null : "OpenCode mcp.agent-inspector is missing or custom; preserved"
1535
+ blockedMessage: shouldRemove ? null : `${target.label} ${target.configObjectName} is missing or custom; preserved`
1422
1536
  };
1423
1537
  }
1424
1538
  switch (status.state) {
@@ -1426,7 +1540,7 @@ function buildOpenCodePlan(flags) {
1426
1540
  return {
1427
1541
  status,
1428
1542
  body: nextBody,
1429
- shouldWrite: flags.force,
1543
+ shouldWrite: force,
1430
1544
  shouldRemove: false,
1431
1545
  blockedMessage: null
1432
1546
  };
@@ -1443,9 +1557,9 @@ function buildOpenCodePlan(flags) {
1443
1557
  return {
1444
1558
  status,
1445
1559
  body: nextBody,
1446
- shouldWrite: flags.force,
1560
+ shouldWrite: force,
1447
1561
  shouldRemove: false,
1448
- blockedMessage: flags.force ? null : "OpenCode mcp.agent-inspector is custom or disabled; use --force to replace"
1562
+ blockedMessage: force ? null : `${target.label} ${target.configObjectName} is custom or disabled; use --force to replace`
1449
1563
  };
1450
1564
  case "invalid":
1451
1565
  return {
@@ -1453,7 +1567,7 @@ function buildOpenCodePlan(flags) {
1453
1567
  body: null,
1454
1568
  shouldWrite: false,
1455
1569
  shouldRemove: false,
1456
- blockedMessage: "OpenCode config is invalid"
1570
+ blockedMessage: `${target.label} config is invalid`
1457
1571
  };
1458
1572
  default:
1459
1573
  return {
@@ -1461,7 +1575,7 @@ function buildOpenCodePlan(flags) {
1461
1575
  body: null,
1462
1576
  shouldWrite: false,
1463
1577
  shouldRemove: false,
1464
- blockedMessage: "OpenCode config state is unknown"
1578
+ blockedMessage: `${target.label} config state is unknown`
1465
1579
  };
1466
1580
  }
1467
1581
  }
@@ -1643,8 +1757,8 @@ function readGeneratedFileStatus(file, currentVersion) {
1643
1757
  }
1644
1758
  }
1645
1759
  function buildPlannedFiles(flags, targets, version) {
1646
- const installClaude = !flags.codexOnly && !flags.opencodeOnly;
1647
- const installCodex = !flags.skipCodexSkill && !flags.opencodeOnly;
1760
+ const installClaude = !flags.codexOnly && !hasOnlyAgentMcpTarget(flags);
1761
+ const installCodex = !flags.skipCodexSkill && !hasOnlyAgentMcpTarget(flags);
1648
1762
  const detectedSummary = installClaude ? buildDetectedSummary() : "";
1649
1763
  const claudeSkillBody = installClaude ? renderSkillOnboard({
1650
1764
  version,
@@ -1702,7 +1816,7 @@ function removeEmptyDirectory(path) {
1702
1816
  } catch {
1703
1817
  }
1704
1818
  }
1705
- function runUninstall(plannedFiles, currentVersion, dryRun, openCodePlan) {
1819
+ function runUninstall(plannedFiles, currentVersion, dryRun, agentPlans) {
1706
1820
  const enabledFiles = plannedFiles.filter((file) => file.enabled);
1707
1821
  const filesToRemove = enabledFiles.filter((file) => shouldUninstall(file, currentVersion));
1708
1822
  if (dryRun) {
@@ -1714,14 +1828,12 @@ function runUninstall(plannedFiles, currentVersion, dryRun, openCodePlan) {
1714
1828
  process.stdout.write(`${file.label}: ${file.path} (${status})
1715
1829
  `);
1716
1830
  }
1717
- if (openCodePlan !== null) {
1718
- const status = openCodePlan.shouldRemove ? "matching" : "skipped";
1719
- process.stdout.write(
1720
- `${openCodePlan.status.label}: ${openCodePlan.status.path} (${status})
1721
- `
1722
- );
1723
- if (openCodePlan.blockedMessage !== null) {
1724
- process.stdout.write(` ${openCodePlan.blockedMessage}
1831
+ for (const plan of agentPlans) {
1832
+ const status = plan.shouldRemove ? "matching" : "skipped";
1833
+ process.stdout.write(`${plan.status.label}: ${plan.status.path} (${status})
1834
+ `);
1835
+ if (plan.blockedMessage !== null) {
1836
+ process.stdout.write(` ${plan.blockedMessage}
1725
1837
  `);
1726
1838
  }
1727
1839
  }
@@ -1730,14 +1842,16 @@ No files were removed.
1730
1842
  `);
1731
1843
  return 0;
1732
1844
  }
1733
- const removeOpenCode = openCodePlan !== null && openCodePlan.shouldRemove;
1734
- if (filesToRemove.length === 0 && !removeOpenCode) {
1845
+ const hasAgentConfigToRemove = agentPlans.some((plan) => plan.shouldRemove);
1846
+ if (filesToRemove.length === 0 && !hasAgentConfigToRemove) {
1735
1847
  process.stdout.write(
1736
1848
  "agent-inspector onboard: no generated onboarding files match this package version\n"
1737
1849
  );
1738
- if (openCodePlan !== null && openCodePlan.blockedMessage !== null) {
1739
- process.stdout.write(`${openCodePlan.blockedMessage}
1850
+ for (const plan of agentPlans) {
1851
+ if (plan.blockedMessage !== null) {
1852
+ process.stdout.write(`${plan.blockedMessage}
1740
1853
  `);
1854
+ }
1741
1855
  }
1742
1856
  return 0;
1743
1857
  }
@@ -1748,11 +1862,13 @@ No files were removed.
1748
1862
  process.stdout.write(`Removed ${file.label}: ${file.path}
1749
1863
  `);
1750
1864
  }
1751
- if (openCodePlan !== null && openCodePlan.shouldRemove && openCodePlan.body !== null) {
1752
- mkdirSync(dirname(openCodePlan.status.path), { recursive: true });
1753
- writeFileSync(openCodePlan.status.path, openCodePlan.body, "utf8");
1754
- process.stdout.write(`Removed OpenCode MCP entry from: ${openCodePlan.status.path}
1865
+ for (const plan of agentPlans) {
1866
+ if (plan.shouldRemove && plan.body !== null) {
1867
+ mkdirSync(dirname(plan.status.path), { recursive: true });
1868
+ writeFileSync(plan.status.path, plan.body, "utf8");
1869
+ process.stdout.write(`Removed ${plan.status.label} entry from: ${plan.status.path}
1755
1870
  `);
1871
+ }
1756
1872
  }
1757
1873
  } catch (err) {
1758
1874
  const msg = err instanceof Error ? err.message : String(err);
@@ -1765,20 +1881,24 @@ No files were removed.
1765
1881
  function formatStatusVersion(status) {
1766
1882
  return status.version ?? "-";
1767
1883
  }
1768
- function summarizeStatusAction(statuses, openCodeStatus) {
1884
+ function summarizeStatusAction(statuses, agentStatuses) {
1769
1885
  const actionable = statuses.filter(
1770
1886
  (status) => status.state === "missing" || status.state === "outdated"
1771
1887
  );
1772
1888
  const actions = actionable.map((status) => status.action);
1773
- if (openCodeStatus !== null && openCodeStatus.state === "missing") {
1774
- actions.push(openCodeStatus.action);
1889
+ for (const agentStatus of agentStatuses) {
1890
+ if (agentStatus.state === "missing") {
1891
+ actions.push(agentStatus.action);
1892
+ }
1775
1893
  }
1776
1894
  if (actions.length > 0) {
1777
1895
  const uniqueActions = Array.from(new Set(actions));
1778
1896
  return `Run: ${uniqueActions.join(" && ")}`;
1779
1897
  }
1780
- if (openCodeStatus !== null && (openCodeStatus.state === "custom" || openCodeStatus.state === "disabled" || openCodeStatus.state === "invalid")) {
1781
- return `OpenCode config needs review: ${openCodeStatus.action}`;
1898
+ for (const agentStatus of agentStatuses) {
1899
+ if (agentStatus.state === "custom" || agentStatus.state === "disabled" || agentStatus.state === "invalid") {
1900
+ return `${agentStatus.label} needs review: ${agentStatus.action}`;
1901
+ }
1782
1902
  }
1783
1903
  if (statuses.some((status) => status.state === "custom")) {
1784
1904
  return "Custom files are preserved. Use --force only if you want to replace them.";
@@ -1788,17 +1908,20 @@ function summarizeStatusAction(statuses, openCodeStatus) {
1788
1908
  }
1789
1909
  return "All selected onboarding files are current.";
1790
1910
  }
1791
- function runStatus(plannedFiles, currentVersion, json, openCodeStatus) {
1911
+ function runStatus(plannedFiles, currentVersion, json, agentStatuses) {
1792
1912
  const enabledFiles = plannedFiles.filter((file) => file.enabled);
1793
1913
  const statuses = enabledFiles.map((file) => readGeneratedFileStatus(file, currentVersion));
1794
- const summary = summarizeStatusAction(statuses, openCodeStatus);
1914
+ const summary = summarizeStatusAction(statuses, agentStatuses);
1915
+ const opencodeConfig = agentStatuses.find((status) => status.label === "OpenCode MCP config") ?? null;
1916
+ const mimoConfig = agentStatuses.find((status) => status.label === "MiMo Code MCP config") ?? null;
1795
1917
  if (json) {
1796
1918
  process.stdout.write(
1797
1919
  `${JSON.stringify(
1798
1920
  {
1799
1921
  packageVersion: currentVersion,
1800
1922
  files: statuses,
1801
- opencodeConfig: openCodeStatus,
1923
+ opencodeConfig,
1924
+ mimoConfig,
1802
1925
  suggestedAction: summary
1803
1926
  },
1804
1927
  null,
@@ -1822,17 +1945,17 @@ function runStatus(plannedFiles, currentVersion, json, openCodeStatus) {
1822
1945
  process.stdout.write(` Action: ${status.action}
1823
1946
  `);
1824
1947
  }
1825
- if (openCodeStatus !== null) {
1826
- process.stdout.write(`${openCodeStatus.label}: ${openCodeStatus.state}`);
1827
- process.stdout.write(`, transport ${openCodeStatus.transport}
1948
+ for (const agentStatus of agentStatuses) {
1949
+ process.stdout.write(`${agentStatus.label}: ${agentStatus.state}`);
1950
+ process.stdout.write(`, transport ${agentStatus.transport}
1828
1951
  `);
1829
- process.stdout.write(` ${openCodeStatus.path}
1952
+ process.stdout.write(` ${agentStatus.path}
1830
1953
  `);
1831
- process.stdout.write(` Endpoint: ${openCodeStatus.endpoint}
1954
+ process.stdout.write(` Endpoint: ${agentStatus.endpoint}
1832
1955
  `);
1833
- process.stdout.write(` Detail: ${openCodeStatus.detail}
1956
+ process.stdout.write(` Detail: ${agentStatus.detail}
1834
1957
  `);
1835
- process.stdout.write(` Action: ${openCodeStatus.action}
1958
+ process.stdout.write(` Action: ${agentStatus.action}
1836
1959
  `);
1837
1960
  }
1838
1961
  process.stdout.write(`
@@ -1857,21 +1980,27 @@ function runOnboardSync(argv) {
1857
1980
  const version = readPackageVersion();
1858
1981
  const plannedFiles = buildPlannedFiles(flags, targets, version);
1859
1982
  const enabledFiles = plannedFiles.filter((file) => file.enabled);
1860
- const openCodePlan = isOpenCodeEnabled(flags) ? buildOpenCodePlan(flags) : null;
1861
- const openCodeStatus = openCodePlan === null ? null : openCodePlan.status;
1983
+ const agentPlans = [];
1984
+ if (isOpenCodeEnabled(flags)) {
1985
+ agentPlans.push(buildAgentPlan(openCodeTarget(flags), flags.uninstall, flags.force));
1986
+ }
1987
+ if (isMiMoEnabled(flags)) {
1988
+ agentPlans.push(buildAgentPlan(miMoTarget(flags), flags.uninstall, flags.force));
1989
+ }
1990
+ const agentStatuses = agentPlans.map((plan) => plan.status);
1862
1991
  if (flags.json && !flags.status) {
1863
1992
  process.stderr.write("agent-inspector onboard: --json is only supported with --status\n");
1864
1993
  return 2;
1865
1994
  }
1866
- if (enabledFiles.length === 0 && openCodePlan === null) {
1995
+ if (enabledFiles.length === 0 && agentPlans.length === 0) {
1867
1996
  process.stderr.write("agent-inspector onboard: no onboarding target selected\n");
1868
1997
  return 2;
1869
1998
  }
1870
1999
  if (flags.status) {
1871
- return runStatus(plannedFiles, version, flags.json, openCodeStatus);
2000
+ return runStatus(plannedFiles, version, flags.json, agentStatuses);
1872
2001
  }
1873
2002
  if (flags.uninstall) {
1874
- return runUninstall(plannedFiles, version, flags.dryRun, openCodePlan);
2003
+ return runUninstall(plannedFiles, version, flags.dryRun, agentPlans);
1875
2004
  }
1876
2005
  if (flags.dryRun) {
1877
2006
  process.stdout.write(`agent-inspector onboard --dry-run
@@ -1882,26 +2011,24 @@ function runOnboardSync(argv) {
1882
2011
  process.stdout.write(`${file.label}: ${file.path} (${status})
1883
2012
  `);
1884
2013
  }
1885
- if (openCodePlan !== null) {
1886
- process.stdout.write(
1887
- `${openCodePlan.status.label}: ${openCodePlan.status.path} (${openCodePlan.status.state})
1888
- `
1889
- );
1890
- process.stdout.write(` Transport: ${flags.opencodeTransport}
2014
+ for (const plan of agentPlans) {
2015
+ process.stdout.write(`${plan.status.label}: ${plan.status.path} (${plan.status.state})
2016
+ `);
2017
+ process.stdout.write(` Transport: ${plan.status.transport}
1891
2018
  `);
1892
- process.stdout.write(` Endpoint: ${openCodePlan.status.endpoint}
2019
+ process.stdout.write(` Endpoint: ${plan.status.endpoint}
1893
2020
  `);
1894
- process.stdout.write(` Action: ${openCodePlan.status.action}
2021
+ process.stdout.write(` Action: ${plan.status.action}
1895
2022
  `);
1896
- if (openCodePlan.blockedMessage !== null) {
1897
- process.stdout.write(` ${openCodePlan.blockedMessage}
2023
+ if (plan.blockedMessage !== null) {
2024
+ process.stdout.write(` ${plan.blockedMessage}
1898
2025
  `);
1899
2026
  }
1900
2027
  }
1901
2028
  process.stdout.write(`
1902
2029
  Claude skill headings:
1903
2030
  `);
1904
- if (!flags.codexOnly && !flags.opencodeOnly) {
2031
+ if (!flags.codexOnly && !hasOnlyAgentMcpTarget(flags)) {
1905
2032
  for (const heading of REQUIRED_PHASE_HEADINGS) {
1906
2033
  process.stdout.write(` - ${heading}
1907
2034
  `);
@@ -1913,7 +2040,7 @@ Claude skill headings:
1913
2040
  process.stdout.write(`
1914
2041
  Codex skill headings:
1915
2042
  `);
1916
- if (!flags.skipCodexSkill && !flags.opencodeOnly) {
2043
+ if (!flags.skipCodexSkill && !hasOnlyAgentMcpTarget(flags)) {
1917
2044
  for (const heading of REQUIRED_CODEX_PHASE_HEADINGS) {
1918
2045
  process.stdout.write(` - ${heading}
1919
2046
  `);
@@ -1922,7 +2049,7 @@ Codex skill headings:
1922
2049
  process.stdout.write(` (disabled by selected targets)
1923
2050
  `);
1924
2051
  }
1925
- if (!flags.codexOnly && !flags.opencodeOnly) {
2052
+ if (!flags.codexOnly && !hasOnlyAgentMcpTarget(flags)) {
1926
2053
  process.stdout.write(`
1927
2054
  Detected tools:
1928
2055
  ${buildDetectedSummary()}
@@ -1934,19 +2061,23 @@ No files were written.
1934
2061
  return 0;
1935
2062
  }
1936
2063
  const filesToWrite = plannedFiles.filter((file) => shouldWrite(file, flags.force, version));
1937
- const shouldWriteOpenCode = openCodePlan !== null && openCodePlan.shouldWrite && openCodePlan.body !== null;
1938
- if (openCodePlan !== null && openCodePlan.status.state === "invalid") {
1939
- process.stderr.write(`agent-inspector onboard: ${openCodePlan.blockedMessage ?? "invalid"}
2064
+ const agentPlansToWrite = agentPlans.filter((plan) => plan.shouldWrite && plan.body !== null);
2065
+ for (const plan of agentPlans) {
2066
+ if (plan.status.state === "invalid") {
2067
+ process.stderr.write(`agent-inspector onboard: ${plan.blockedMessage ?? "invalid"}
1940
2068
  `);
1941
- return 1;
2069
+ return 1;
2070
+ }
1942
2071
  }
1943
- if (filesToWrite.length === 0 && !shouldWriteOpenCode) {
2072
+ if (filesToWrite.length === 0 && agentPlansToWrite.length === 0) {
1944
2073
  process.stdout.write(
1945
2074
  "agent-inspector onboard: all selected onboarding files are already up to date\n"
1946
2075
  );
1947
- if (openCodePlan !== null && openCodePlan.blockedMessage !== null) {
1948
- process.stdout.write(`${openCodePlan.blockedMessage}
2076
+ for (const plan of agentPlans) {
2077
+ if (plan.blockedMessage !== null) {
2078
+ process.stdout.write(`${plan.blockedMessage}
1949
2079
  `);
2080
+ }
1950
2081
  }
1951
2082
  process.stdout.write("Re-run with --force to refresh.\n");
1952
2083
  return 0;
@@ -1956,9 +2087,11 @@ No files were written.
1956
2087
  mkdirSync(dirname(file.path), { recursive: true });
1957
2088
  writeFileSync(file.path, file.body, "utf8");
1958
2089
  }
1959
- if (shouldWriteOpenCode && openCodePlan !== null && openCodePlan.body !== null) {
1960
- mkdirSync(dirname(openCodePlan.status.path), { recursive: true });
1961
- writeFileSync(openCodePlan.status.path, openCodePlan.body, "utf8");
2090
+ for (const plan of agentPlansToWrite) {
2091
+ if (plan.body !== null) {
2092
+ mkdirSync(dirname(plan.status.path), { recursive: true });
2093
+ writeFileSync(plan.status.path, plan.body, "utf8");
2094
+ }
1962
2095
  }
1963
2096
  } catch (err) {
1964
2097
  const msg = err instanceof Error ? err.message : String(err);
@@ -1972,30 +2105,31 @@ No files were written.
1972
2105
  process.stdout.write(`Installed/updated ${file.label} to: ${file.path}
1973
2106
  `);
1974
2107
  }
1975
- if (shouldWriteOpenCode && openCodePlan !== null) {
1976
- process.stdout.write(`Installed/updated OpenCode MCP config: ${openCodePlan.status.path}
2108
+ for (const plan of agentPlansToWrite) {
2109
+ process.stdout.write(`Installed/updated ${plan.status.label}: ${plan.status.path}
1977
2110
  `);
1978
2111
  }
1979
2112
  process.stdout.write(`
1980
2113
  Next steps:
1981
2114
  `);
1982
- if (!flags.codexOnly && !flags.opencodeOnly) {
2115
+ if (!flags.codexOnly && !hasOnlyAgentMcpTarget(flags)) {
1983
2116
  process.stdout.write(` - Open Claude Code and run: /agent-inspector:onboard
1984
2117
  `);
1985
2118
  }
1986
- if (!flags.skipCodexSkill && !flags.opencodeOnly) {
2119
+ if (!flags.skipCodexSkill && !hasOnlyAgentMcpTarget(flags)) {
1987
2120
  process.stdout.write(` - Open Codex and ask to use the agent-inspector-onboard skill
1988
2121
  `);
1989
2122
  }
1990
- if (openCodePlan !== null) {
1991
- process.stdout.write(` - Verify OpenCode MCP: opencode mcp list
2123
+ for (const plan of agentPlans) {
2124
+ process.stdout.write(` - Verify ${plan.status.label}: ${plan.status.verifyCommand}
1992
2125
  `);
1993
2126
  }
1994
- if (flags.opencodeOnly) {
1995
- process.stdout.write(
1996
- ` - Refresh OpenCode later: agent-inspector onboard --opencode-only --force
1997
- `
1998
- );
2127
+ if (hasOnlyAgentMcpTarget(flags)) {
2128
+ const refreshActions = agentPlans.map((plan) => plan.status.forceAction);
2129
+ const uniqueRefreshActions = Array.from(new Set(refreshActions));
2130
+ const refresh = uniqueRefreshActions.length > 0 ? uniqueRefreshActions.join(" && ") : "agent-inspector onboard --force";
2131
+ process.stdout.write(` - Refresh selected MCP config later: ${refresh}
2132
+ `);
1999
2133
  } else {
2000
2134
  process.stdout.write(` - Refresh later: agent-inspector onboard --force
2001
2135
  `);