@tonyclaw/agent-inspector 2.0.16 → 2.0.18

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 (37) hide show
  1. package/.output/cli.js +394 -55
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-DPs4UHwd.js → CompareDrawer-CepU-dLW.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-B1KylMPs.js → ProxyViewerContainer-BG7rc33d.js} +16 -16
  5. package/.output/public/assets/{ReplayDialog-8ISC28XF.js → ReplayDialog-DK6SPv8X.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-BhbsgfBO.js → RequestAnatomy-C_C6ZU3T.js} +1 -1
  7. package/.output/public/assets/{ResponseView-CyM7JXeA.js → ResponseView-Bqpra4Zw.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-BaX0x38n.js → StreamingChunkSequence-CdPbpprq.js} +1 -1
  9. package/.output/public/assets/_sessionId-CsNARHj5.js +1 -0
  10. package/.output/public/assets/index-37NfO0zx.js +1 -0
  11. package/.output/public/assets/{main-B2t-3SYj.js → main-BRXsrxtv.js} +2 -2
  12. package/.output/server/{_sessionId-CEbZTs68.mjs → _sessionId-B8Bbfs-v.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-CEo48Wsu.mjs → CompareDrawer-TgGZLf1J.mjs} +2 -2
  14. package/.output/server/_ssr/{ProxyViewerContainer-5ekIK_jx.mjs → ProxyViewerContainer-B_ppaNmQ.mjs} +41 -12
  15. package/.output/server/_ssr/{ReplayDialog-C0nEvbYo.mjs → ReplayDialog-BXlajnMC.mjs} +3 -3
  16. package/.output/server/_ssr/{RequestAnatomy-CT55prmM.mjs → RequestAnatomy-CCrx09-i.mjs} +2 -2
  17. package/.output/server/_ssr/{ResponseView-DBZSBCOD.mjs → ResponseView-BxtMJrov.mjs} +2 -2
  18. package/.output/server/_ssr/{StreamingChunkSequence-BuVT7Oke.mjs → StreamingChunkSequence-BlpdSPb8.mjs} +2 -2
  19. package/.output/server/_ssr/{index-Cw_zJVQv.mjs → index-BeTMNSJy.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-DxjqHipT.mjs → router-Ddl1tuU7.mjs} +27 -11
  22. package/.output/server/{_tanstack-start-manifest_v-xeOo5gW5.mjs → _tanstack-start-manifest_v-Bvdz_U0f.mjs} +1 -1
  23. package/.output/server/index.mjs +56 -56
  24. package/README.md +37 -5
  25. package/package.json +3 -3
  26. package/scripts/setup-agent-skills.mjs +64 -0
  27. package/src/cli/doctor.ts +12 -5
  28. package/src/cli/onboard.ts +407 -13
  29. package/src/cli/templates/codex-skill-onboard.ts +5 -0
  30. package/src/cli/templates/command-onboard.ts +12 -4
  31. package/src/cli/templates/skill-onboard.ts +17 -21
  32. package/src/components/OnboardingBanner.tsx +5 -0
  33. package/src/components/providers/SettingsDialog.tsx +22 -4
  34. package/src/proxy/dataDir.ts +35 -13
  35. package/.output/public/assets/_sessionId-CShO0OrR.js +0 -1
  36. package/.output/public/assets/index-BkdYiTpV.js +0 -1
  37. package/scripts/setup-codex-skill.mjs +0 -38
package/.output/cli.js CHANGED
@@ -98,14 +98,17 @@ var init_detect_tools = __esm({
98
98
  });
99
99
 
100
100
  // src/cli/templates/command-onboard.ts
101
- function renderCommandOnboard() {
101
+ function renderCommandOnboard(ctx) {
102
102
  return `---
103
- description: Walk through agent-inspector setup \u2014 start the proxy, wire your AI tool, capture your first request.
103
+ description: Walk through agent-inspector setup - start the proxy, wire your AI tool, capture your first request.
104
+ metadata:
105
+ author: agent-inspector
106
+ version: ${ctx.version}
104
107
  ---
105
108
 
106
109
  Invoke the \`agent-inspector-onboard\` skill and follow its phases.
107
110
 
108
- The user wants to set up agent-inspector. If they have specific context (e.g. "I'm on Windows", "I already added my API key"), honor it \u2014 but otherwise just run the skill end-to-end and let the \`EXPLAIN / DO / PAUSE\` markers drive the conversation.
111
+ The user wants to set up agent-inspector. If they have specific context (e.g. "I'm on Windows", "I already added my API key"), honor it - but otherwise just run the skill end-to-end and let the \`EXPLAIN / DO / PAUSE\` markers drive the conversation.
109
112
  `;
110
113
  }
111
114
  var init_command_onboard = __esm({
@@ -150,12 +153,14 @@ Check that the package and Codex home exist without printing secrets.
150
153
 
151
154
  \`\`\`powershell
152
155
  Get-Command agent-inspector -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source
156
+ agent-inspector onboard --status
153
157
  Test-Path (Join-Path $env:USERPROFILE ".codex")
154
158
  Test-Path (Join-Path $env:USERPROFILE ".codex\\config.toml")
155
159
  \`\`\`
156
160
 
157
161
  \`\`\`bash
158
162
  command -v agent-inspector || true
163
+ agent-inspector onboard --status
159
164
  test -d "$HOME/.codex" && echo "codex home: present" || echo "codex home: missing"
160
165
  test -f "$HOME/.codex/config.toml" && echo "config: present" || echo "config: missing"
161
166
  \`\`\`
@@ -166,6 +171,9 @@ If \`agent-inspector\` is missing, ask the user to install it first:
166
171
  npm install -g @tonyclaw/agent-inspector
167
172
  \`\`\`
168
173
 
174
+ If \`agent-inspector onboard --status\` reports \`outdated\` or \`missing\`, ask the user to run
175
+ \`agent-inspector onboard --force\` and restart this skill before continuing.
176
+
169
177
  Do not read \`~/.codex/auth.json\`, token files, or unrelated Codex state files.
170
178
 
171
179
  ---
@@ -352,7 +360,19 @@ Default proxy port: \`${port}\` (override with \`PORT=<n> agent-inspector\` or \
352
360
 
353
361
  **EXPLAIN:** "Before we do anything, let me see what's already set up. If some of the steps are already done, we can skip them."
354
362
 
355
- **DO:** Probe the three pieces of state this skill touches. Use targeted checks \u2014 do **not** read large JSON files into the conversation.
363
+ **DO:** First check whether the generated onboarding files match the installed npm package. If any
364
+ entry is \`outdated\` or \`missing\`, tell the user to run \`agent-inspector onboard --force\` before
365
+ continuing so they are not guided by stale instructions.
366
+
367
+ \`\`\`bash
368
+ agent-inspector onboard --status
369
+ \`\`\`
370
+
371
+ \`\`\`powershell
372
+ agent-inspector onboard --status
373
+ \`\`\`
374
+
375
+ **DO:** Then probe the three pieces of state this skill touches. Use targeted checks \u2014 do **not** read large JSON files into the conversation.
356
376
 
357
377
  \`\`\`bash
358
378
  # 1. Is the proxy already up?
@@ -369,9 +389,6 @@ agent_inspector_data_dir() {
369
389
  case "$AGENT_INSPECTOR_CONFIG_DIR" in /*) printf '%s
370
390
  ' "$AGENT_INSPECTOR_CONFIG_DIR" ;; *) printf '%s
371
391
  ' "$base/$AGENT_INSPECTOR_CONFIG_DIR" ;; esac
372
- elif { [ ! -e "$base/.agent-inspector/providers.json" ] && [ ! -e "$base/.agent-inspector/config.json" ] && [ ! -e "$base/.agent-inspector/logs" ] && [ ! -e "$base/.agent-inspector/chunks" ]; } && { [ -e "$base/.llm-inspector/providers.json" ] || [ -e "$base/.llm-inspector/config.json" ] || [ -e "$base/.llm-inspector/logs" ] || [ -e "$base/.llm-inspector/chunks" ]; }; then
373
- printf '%s
374
- ' "$base/.llm-inspector"
375
392
  else
376
393
  printf '%s
377
394
  ' "$base/.agent-inspector"
@@ -419,14 +436,7 @@ function Resolve-AgentInspectorDataDir {
419
436
  if ([System.IO.Path]::IsPathRooted($env:AGENT_INSPECTOR_CONFIG_DIR)) { return $env:AGENT_INSPECTOR_CONFIG_DIR }
420
437
  return (Join-Path $base $env:AGENT_INSPECTOR_CONFIG_DIR)
421
438
  }
422
- $current = Join-Path $base '.agent-inspector'
423
- $legacy = Join-Path $base '.llm-inspector'
424
- $currentHasState = (Test-Path (Join-Path $current 'providers.json')) -or (Test-Path (Join-Path $current 'config.json')) -or (Test-Path (Join-Path $current 'logs')) -or (Test-Path (Join-Path $current 'chunks'))
425
- $legacyHasState = (Test-Path (Join-Path $legacy 'providers.json')) -or (Test-Path (Join-Path $legacy 'config.json')) -or (Test-Path (Join-Path $legacy 'logs')) -or (Test-Path (Join-Path $legacy 'chunks'))
426
- if (-not $currentHasState -and $legacyHasState) {
427
- return $legacy
428
- }
429
- return $current
439
+ return (Join-Path $base '.agent-inspector')
430
440
  }
431
441
  $dataDir = Resolve-AgentInspectorDataDir
432
442
  $providers = Join-Path $dataDir 'providers.json'
@@ -546,9 +556,6 @@ agent_inspector_data_dir() {
546
556
  case "$AGENT_INSPECTOR_CONFIG_DIR" in /*) printf '%s
547
557
  ' "$AGENT_INSPECTOR_CONFIG_DIR" ;; *) printf '%s
548
558
  ' "$base/$AGENT_INSPECTOR_CONFIG_DIR" ;; esac
549
- elif { [ ! -e "$base/.agent-inspector/providers.json" ] && [ ! -e "$base/.agent-inspector/config.json" ] && [ ! -e "$base/.agent-inspector/logs" ] && [ ! -e "$base/.agent-inspector/chunks" ]; } && { [ -e "$base/.llm-inspector/providers.json" ] || [ -e "$base/.llm-inspector/config.json" ] || [ -e "$base/.llm-inspector/logs" ] || [ -e "$base/.llm-inspector/chunks" ]; }; then
550
- printf '%s
551
- ' "$base/.llm-inspector"
552
559
  else
553
560
  printf '%s
554
561
  ' "$base/.agent-inspector"
@@ -593,14 +600,7 @@ function Resolve-AgentInspectorDataDir {
593
600
  if ([System.IO.Path]::IsPathRooted($env:AGENT_INSPECTOR_CONFIG_DIR)) { return $env:AGENT_INSPECTOR_CONFIG_DIR }
594
601
  return (Join-Path $base $env:AGENT_INSPECTOR_CONFIG_DIR)
595
602
  }
596
- $current = Join-Path $base '.agent-inspector'
597
- $legacy = Join-Path $base '.llm-inspector'
598
- $currentHasState = (Test-Path (Join-Path $current 'providers.json')) -or (Test-Path (Join-Path $current 'config.json')) -or (Test-Path (Join-Path $current 'logs')) -or (Test-Path (Join-Path $current 'chunks'))
599
- $legacyHasState = (Test-Path (Join-Path $legacy 'providers.json')) -or (Test-Path (Join-Path $legacy 'config.json')) -or (Test-Path (Join-Path $legacy 'logs')) -or (Test-Path (Join-Path $legacy 'chunks'))
600
- if (-not $currentHasState -and $legacyHasState) {
601
- return $legacy
602
- }
603
- return $current
603
+ return (Join-Path $base '.agent-inspector')
604
604
  }
605
605
  $dir = Resolve-AgentInspectorDataDir
606
606
  $file = Join-Path $dir 'providers.json'
@@ -834,6 +834,8 @@ done
834
834
  \`\`\`
835
835
 
836
836
  - **Re-run onboard**: \`agent-inspector onboard --force\` refreshes this skill.
837
+ - **Check onboard files**: \`agent-inspector onboard --status\` shows whether generated skills are
838
+ current, outdated, missing, newer, or custom.
837
839
  - **Full docs**: see the project README (linked from the Web UI footer).
838
840
 
839
841
  > **PAUSE** \u2014 use \`AskUserQuestion\` with header \`All set?\` and options \`["All set, I'm done", "Wait, I want to revisit a phase"]\`. Wait for the answer.
@@ -864,10 +866,42 @@ var onboard_exports = {};
864
866
  __export(onboard_exports, {
865
867
  runOnboard: () => runOnboard
866
868
  });
867
- import { mkdirSync, writeFileSync, existsSync as existsSync2, readFileSync } from "node:fs";
869
+ import {
870
+ mkdirSync,
871
+ writeFileSync,
872
+ existsSync as existsSync2,
873
+ readFileSync,
874
+ unlinkSync,
875
+ readdirSync,
876
+ rmdirSync
877
+ } from "node:fs";
868
878
  import { homedir as homedir2 } from "node:os";
869
879
  import { dirname, join as join2 } from "node:path";
870
880
  import { fileURLToPath } from "node:url";
881
+ function actionForStatus(label, state) {
882
+ switch (state) {
883
+ case "missing":
884
+ switch (label) {
885
+ case "Codex skill":
886
+ return "agent-inspector onboard --codex-only";
887
+ case "Claude skill":
888
+ case "Claude command":
889
+ return "agent-inspector onboard --skip-codex-skill";
890
+ default:
891
+ return "agent-inspector onboard";
892
+ }
893
+ case "outdated":
894
+ return "agent-inspector onboard --force";
895
+ case "custom":
896
+ return "preserved; use agent-inspector onboard --force to replace";
897
+ case "newer":
898
+ return "no action; installed file is newer than this package";
899
+ case "current":
900
+ return "no action";
901
+ default:
902
+ return "agent-inspector onboard";
903
+ }
904
+ }
871
905
  function parseFlags(argv) {
872
906
  const flags = {
873
907
  force: false,
@@ -876,6 +910,9 @@ function parseFlags(argv) {
876
910
  skipToolWire: false,
877
911
  codexOnly: false,
878
912
  skipCodexSkill: false,
913
+ uninstall: false,
914
+ status: false,
915
+ json: false,
879
916
  skillDir: null,
880
917
  codexSkillDir: null
881
918
  };
@@ -902,6 +939,15 @@ function parseFlags(argv) {
902
939
  case "--skip-codex-skill":
903
940
  flags.skipCodexSkill = true;
904
941
  break;
942
+ case "--uninstall":
943
+ flags.uninstall = true;
944
+ break;
945
+ case "--status":
946
+ flags.status = true;
947
+ break;
948
+ case "--json":
949
+ flags.json = true;
950
+ break;
905
951
  case "--skill-dir": {
906
952
  const next = argv[i + 1];
907
953
  if (next === void 0) {
@@ -950,6 +996,9 @@ Options:
950
996
  --skip-tool-wire Skip the wire-tool phase in the Claude skill body
951
997
  --skip-codex-skill Install only the Claude Code skill and slash command
952
998
  --codex-only Install only the Codex skill
999
+ --uninstall Remove generated files whose version matches this package
1000
+ --status Show installed onboarding file versions and suggested action
1001
+ --json Emit machine-readable JSON with --status
953
1002
  --skill-dir <path> Override the target Claude root directory (default: ~/.claude)
954
1003
  --codex-skill-dir <path> Override the target Codex skills directory (default: ~/.codex/skills)
955
1004
  -h, --help Show this help
@@ -985,15 +1034,173 @@ function buildDetectedSummary() {
985
1034
  - Not detected: ${absentList}`;
986
1035
  }
987
1036
  function readPackageVersion() {
1037
+ const packageJsonPaths = [
1038
+ join2(__dirname, "..", "package.json"),
1039
+ join2(__dirname, "..", "..", "package.json")
1040
+ ];
988
1041
  try {
989
- const raw = JSON.parse(readFileSync(join2(__dirname, "..", "package.json"), "utf8"));
990
- if (isObject(raw) && typeof raw["version"] === "string") {
991
- return raw["version"];
1042
+ for (const packageJsonPath of packageJsonPaths) {
1043
+ if (existsSync2(packageJsonPath)) {
1044
+ const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
1045
+ if (isObject(raw) && typeof raw["version"] === "string") {
1046
+ return raw["version"];
1047
+ }
1048
+ }
992
1049
  }
993
1050
  } catch {
994
1051
  }
995
1052
  return "0.0.0";
996
1053
  }
1054
+ function parseVersion(version) {
1055
+ const match = SEMVER_PATTERN.exec(version);
1056
+ if (match === null) {
1057
+ return null;
1058
+ }
1059
+ const majorText = match[1];
1060
+ const minorText = match[2];
1061
+ const patchText = match[3];
1062
+ if (majorText === void 0 || minorText === void 0 || patchText === void 0) {
1063
+ return null;
1064
+ }
1065
+ const major = Number(majorText);
1066
+ const minor = Number(minorText);
1067
+ const patch = Number(patchText);
1068
+ if (!Number.isInteger(major) || !Number.isInteger(minor) || !Number.isInteger(patch)) {
1069
+ return null;
1070
+ }
1071
+ return { major, minor, patch };
1072
+ }
1073
+ function compareVersions(left, right) {
1074
+ const leftVersion = parseVersion(left);
1075
+ const rightVersion = parseVersion(right);
1076
+ if (leftVersion === null || rightVersion === null) {
1077
+ return null;
1078
+ }
1079
+ const leftParts = [leftVersion.major, leftVersion.minor, leftVersion.patch];
1080
+ const rightParts = [rightVersion.major, rightVersion.minor, rightVersion.patch];
1081
+ for (let index = 0; index < leftParts.length; index++) {
1082
+ const leftPart = leftParts[index];
1083
+ const rightPart = rightParts[index];
1084
+ if (leftPart === void 0 || rightPart === void 0) {
1085
+ return null;
1086
+ }
1087
+ if (leftPart > rightPart) {
1088
+ return 1;
1089
+ }
1090
+ if (leftPart < rightPart) {
1091
+ return -1;
1092
+ }
1093
+ }
1094
+ return 0;
1095
+ }
1096
+ function extractGeneratedVersion(body) {
1097
+ const frontmatterMatch = FRONTMATTER_PATTERN.exec(body);
1098
+ if (frontmatterMatch === null) {
1099
+ return null;
1100
+ }
1101
+ const frontmatter = frontmatterMatch[1];
1102
+ if (frontmatter === void 0) {
1103
+ return null;
1104
+ }
1105
+ const versionMatch = GENERATED_VERSION_PATTERN.exec(frontmatter);
1106
+ if (versionMatch === null) {
1107
+ return null;
1108
+ }
1109
+ return versionMatch[1] ?? null;
1110
+ }
1111
+ function hasAgentInspectorAuthor(body) {
1112
+ const frontmatterMatch = FRONTMATTER_PATTERN.exec(body);
1113
+ if (frontmatterMatch === null) {
1114
+ return false;
1115
+ }
1116
+ const frontmatter = frontmatterMatch[1];
1117
+ if (frontmatter === void 0) {
1118
+ return false;
1119
+ }
1120
+ return /^\s*author:\s*agent-inspector\s*$/m.test(frontmatter);
1121
+ }
1122
+ function readGeneratedVersion(path) {
1123
+ try {
1124
+ return extractGeneratedVersion(readFileSync(path, "utf8"));
1125
+ } catch {
1126
+ return null;
1127
+ }
1128
+ }
1129
+ function isMatchingGeneratedFile(path, currentVersion) {
1130
+ try {
1131
+ const body = readFileSync(path, "utf8");
1132
+ return hasAgentInspectorAuthor(body) && extractGeneratedVersion(body) === currentVersion;
1133
+ } catch {
1134
+ return false;
1135
+ }
1136
+ }
1137
+ function readGeneratedFileStatus(file, currentVersion) {
1138
+ if (!existsSync2(file.path)) {
1139
+ return {
1140
+ label: file.label,
1141
+ path: file.path,
1142
+ state: "missing",
1143
+ version: null,
1144
+ action: actionForStatus(file.label, "missing")
1145
+ };
1146
+ }
1147
+ try {
1148
+ const body = readFileSync(file.path, "utf8");
1149
+ const version = extractGeneratedVersion(body);
1150
+ if (!hasAgentInspectorAuthor(body) || version === null) {
1151
+ return {
1152
+ label: file.label,
1153
+ path: file.path,
1154
+ state: "custom",
1155
+ version,
1156
+ action: actionForStatus(file.label, "custom")
1157
+ };
1158
+ }
1159
+ const comparison = compareVersions(version, currentVersion);
1160
+ if (comparison === null) {
1161
+ return {
1162
+ label: file.label,
1163
+ path: file.path,
1164
+ state: "custom",
1165
+ version,
1166
+ action: actionForStatus(file.label, "custom")
1167
+ };
1168
+ }
1169
+ if (comparison < 0) {
1170
+ return {
1171
+ label: file.label,
1172
+ path: file.path,
1173
+ state: "outdated",
1174
+ version,
1175
+ action: actionForStatus(file.label, "outdated")
1176
+ };
1177
+ }
1178
+ if (comparison > 0) {
1179
+ return {
1180
+ label: file.label,
1181
+ path: file.path,
1182
+ state: "newer",
1183
+ version,
1184
+ action: actionForStatus(file.label, "newer")
1185
+ };
1186
+ }
1187
+ return {
1188
+ label: file.label,
1189
+ path: file.path,
1190
+ state: "current",
1191
+ version,
1192
+ action: actionForStatus(file.label, "current")
1193
+ };
1194
+ } catch {
1195
+ return {
1196
+ label: file.label,
1197
+ path: file.path,
1198
+ state: "custom",
1199
+ version: null,
1200
+ action: actionForStatus(file.label, "custom")
1201
+ };
1202
+ }
1203
+ }
997
1204
  function buildPlannedFiles(flags, targets, version) {
998
1205
  const installClaude = !flags.codexOnly;
999
1206
  const installCodex = !flags.skipCodexSkill;
@@ -1003,7 +1210,7 @@ function buildPlannedFiles(flags, targets, version) {
1003
1210
  port: DEFAULT_PORT,
1004
1211
  detectedSummary
1005
1212
  }) : "";
1006
- const commandBody = installClaude ? renderCommandOnboard() : "";
1213
+ const commandBody = installClaude ? renderCommandOnboard({ version }) : "";
1007
1214
  const codexSkillBody = installCodex ? renderCodexSkillOnboard({
1008
1215
  version,
1009
1216
  port: DEFAULT_PORT
@@ -1029,8 +1236,125 @@ function buildPlannedFiles(flags, targets, version) {
1029
1236
  }
1030
1237
  ];
1031
1238
  }
1032
- function shouldWrite(file, force) {
1033
- return file.enabled && (force || !existsSync2(file.path));
1239
+ function shouldWrite(file, force, currentVersion) {
1240
+ if (!file.enabled) {
1241
+ return false;
1242
+ }
1243
+ if (force || !existsSync2(file.path)) {
1244
+ return true;
1245
+ }
1246
+ const existingVersion = readGeneratedVersion(file.path);
1247
+ if (existingVersion === null) {
1248
+ return false;
1249
+ }
1250
+ const comparison = compareVersions(existingVersion, currentVersion);
1251
+ return comparison !== null && comparison < 0;
1252
+ }
1253
+ function shouldUninstall(file, currentVersion) {
1254
+ return file.enabled && existsSync2(file.path) && isMatchingGeneratedFile(file.path, currentVersion);
1255
+ }
1256
+ function removeEmptyDirectory(path) {
1257
+ try {
1258
+ if (readdirSync(path).length === 0) {
1259
+ rmdirSync(path);
1260
+ }
1261
+ } catch {
1262
+ }
1263
+ }
1264
+ function runUninstall(plannedFiles, currentVersion, dryRun) {
1265
+ const enabledFiles = plannedFiles.filter((file) => file.enabled);
1266
+ const filesToRemove = enabledFiles.filter((file) => shouldUninstall(file, currentVersion));
1267
+ if (dryRun) {
1268
+ process.stdout.write(`agent-inspector onboard --uninstall --dry-run
1269
+
1270
+ `);
1271
+ for (const file of enabledFiles) {
1272
+ const status = shouldUninstall(file, currentVersion) ? "matching" : "skipped";
1273
+ process.stdout.write(`${file.label}: ${file.path} (${status})
1274
+ `);
1275
+ }
1276
+ process.stdout.write(`
1277
+ No files were removed.
1278
+ `);
1279
+ return 0;
1280
+ }
1281
+ if (filesToRemove.length === 0) {
1282
+ process.stdout.write(
1283
+ "agent-inspector onboard: no generated onboarding files match this package version\n"
1284
+ );
1285
+ return 0;
1286
+ }
1287
+ try {
1288
+ for (const file of filesToRemove) {
1289
+ unlinkSync(file.path);
1290
+ removeEmptyDirectory(dirname(file.path));
1291
+ process.stdout.write(`Removed ${file.label}: ${file.path}
1292
+ `);
1293
+ }
1294
+ } catch (err) {
1295
+ const msg = err instanceof Error ? err.message : String(err);
1296
+ process.stderr.write(`agent-inspector onboard: failed to remove files: ${msg}
1297
+ `);
1298
+ return 1;
1299
+ }
1300
+ return 0;
1301
+ }
1302
+ function formatStatusVersion(status) {
1303
+ return status.version ?? "-";
1304
+ }
1305
+ function summarizeStatusAction(statuses) {
1306
+ const actionable = statuses.filter(
1307
+ (status) => status.state === "missing" || status.state === "outdated"
1308
+ );
1309
+ if (actionable.length > 0) {
1310
+ const actions = Array.from(new Set(actionable.map((status) => status.action)));
1311
+ return `Run: ${actions.join(" && ")}`;
1312
+ }
1313
+ if (statuses.some((status) => status.state === "custom")) {
1314
+ return "Custom files are preserved. Use --force only if you want to replace them.";
1315
+ }
1316
+ if (statuses.some((status) => status.state === "newer")) {
1317
+ return "Installed files are newer than this package. No action needed.";
1318
+ }
1319
+ return "All selected onboarding files are current.";
1320
+ }
1321
+ function runStatus(plannedFiles, currentVersion, json) {
1322
+ const enabledFiles = plannedFiles.filter((file) => file.enabled);
1323
+ const statuses = enabledFiles.map((file) => readGeneratedFileStatus(file, currentVersion));
1324
+ const summary = summarizeStatusAction(statuses);
1325
+ if (json) {
1326
+ process.stdout.write(
1327
+ `${JSON.stringify(
1328
+ {
1329
+ packageVersion: currentVersion,
1330
+ files: statuses,
1331
+ suggestedAction: summary
1332
+ },
1333
+ null,
1334
+ 2
1335
+ )}
1336
+ `
1337
+ );
1338
+ return 0;
1339
+ }
1340
+ process.stdout.write(`agent-inspector onboard status
1341
+ `);
1342
+ process.stdout.write(`Package version: ${currentVersion}
1343
+
1344
+ `);
1345
+ for (const status of statuses) {
1346
+ process.stdout.write(`${status.label}: ${status.state}`);
1347
+ process.stdout.write(`, version ${formatStatusVersion(status)}
1348
+ `);
1349
+ process.stdout.write(` ${status.path}
1350
+ `);
1351
+ process.stdout.write(` Action: ${status.action}
1352
+ `);
1353
+ }
1354
+ process.stdout.write(`
1355
+ Suggested action: ${summary}
1356
+ `);
1357
+ return 0;
1034
1358
  }
1035
1359
  function runOnboard(argv) {
1036
1360
  try {
@@ -1049,10 +1373,20 @@ function runOnboardSync(argv) {
1049
1373
  const version = readPackageVersion();
1050
1374
  const plannedFiles = buildPlannedFiles(flags, targets, version);
1051
1375
  const enabledFiles = plannedFiles.filter((file) => file.enabled);
1376
+ if (flags.json && !flags.status) {
1377
+ process.stderr.write("agent-inspector onboard: --json is only supported with --status\n");
1378
+ return 2;
1379
+ }
1052
1380
  if (enabledFiles.length === 0) {
1053
1381
  process.stderr.write("agent-inspector onboard: no onboarding target selected\n");
1054
1382
  return 2;
1055
1383
  }
1384
+ if (flags.status) {
1385
+ return runStatus(plannedFiles, version, flags.json);
1386
+ }
1387
+ if (flags.uninstall) {
1388
+ return runUninstall(plannedFiles, version, flags.dryRun);
1389
+ }
1056
1390
  if (flags.dryRun) {
1057
1391
  process.stdout.write(`agent-inspector onboard --dry-run
1058
1392
 
@@ -1097,9 +1431,11 @@ No files were written.
1097
1431
  `);
1098
1432
  return 0;
1099
1433
  }
1100
- const filesToWrite = plannedFiles.filter((file) => shouldWrite(file, flags.force));
1434
+ const filesToWrite = plannedFiles.filter((file) => shouldWrite(file, flags.force, version));
1101
1435
  if (filesToWrite.length === 0) {
1102
- process.stdout.write("agent-inspector onboard: all selected onboarding files already exist\n");
1436
+ process.stdout.write(
1437
+ "agent-inspector onboard: all selected onboarding files are already up to date\n"
1438
+ );
1103
1439
  process.stdout.write("Re-run with --force to refresh.\n");
1104
1440
  return 0;
1105
1441
  }
@@ -1117,7 +1453,7 @@ No files were written.
1117
1453
  const firstTool = detectFirst();
1118
1454
  const toolHint = firstTool !== null ? firstTool.displayName : "no known tool detected";
1119
1455
  for (const file of filesToWrite) {
1120
- process.stdout.write(`Installed ${file.label} to: ${file.path}
1456
+ process.stdout.write(`Installed/updated ${file.label} to: ${file.path}
1121
1457
  `);
1122
1458
  }
1123
1459
  process.stdout.write(`
@@ -1137,7 +1473,7 @@ Next steps:
1137
1473
  `);
1138
1474
  return 0;
1139
1475
  }
1140
- var __filename, __dirname, DEFAULT_PORT, SKILL_DIR_NAME, SKILL_FILE_NAME, COMMAND_FILE_NAME;
1476
+ var __filename, __dirname, DEFAULT_PORT, SKILL_DIR_NAME, SKILL_FILE_NAME, COMMAND_FILE_NAME, GENERATED_VERSION_PATTERN, FRONTMATTER_PATTERN, SEMVER_PATTERN;
1141
1477
  var init_onboard = __esm({
1142
1478
  "src/cli/onboard.ts"() {
1143
1479
  "use strict";
@@ -1151,17 +1487,19 @@ var init_onboard = __esm({
1151
1487
  SKILL_DIR_NAME = "agent-inspector-onboard";
1152
1488
  SKILL_FILE_NAME = "SKILL.md";
1153
1489
  COMMAND_FILE_NAME = process.platform === "win32" ? "agent-inspector-onboard.md" : "agent-inspector:onboard.md";
1490
+ GENERATED_VERSION_PATTERN = /^\s*version:\s*([0-9]+\.[0-9]+\.[0-9]+(?:[-+][^\s]+)?)\s*$/m;
1491
+ FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/;
1492
+ SEMVER_PATTERN = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/;
1154
1493
  }
1155
1494
  });
1156
1495
 
1157
1496
  // src/proxy/dataDir.ts
1158
1497
  import { isAbsolute, join as join3 } from "node:path";
1159
- function hasDataDirState(pathExists, dir) {
1160
- return pathExists(join3(dir, "providers.json")) || pathExists(join3(dir, "config.json")) || pathExists(join3(dir, "logs")) || pathExists(join3(dir, "chunks"));
1498
+ function defaultBaseDir(env = process.env, platform = process.platform) {
1499
+ return platform === "win32" ? env["USERPROFILE"] ?? env["APPDATA"] ?? "C:\\" : env["HOME"] ?? "/tmp";
1161
1500
  }
1162
- function resolveDataDir(pathExists, env = process.env, platform = process.platform) {
1163
- const isWindows = platform === "win32";
1164
- const base = isWindows ? env["USERPROFILE"] ?? env["APPDATA"] ?? "C:\\" : env["HOME"] ?? "/tmp";
1501
+ function resolveDataDir(_pathExists, env = process.env, platform = process.platform) {
1502
+ const base = defaultBaseDir(env, platform);
1165
1503
  const dirEnv = env["AGENT_INSPECTOR_DATA_DIR"];
1166
1504
  if (dirEnv !== void 0 && dirEnv !== "") {
1167
1505
  return isAbsolute(dirEnv) ? dirEnv : join3(base, dirEnv);
@@ -1170,16 +1508,13 @@ function resolveDataDir(pathExists, env = process.env, platform = process.platfo
1170
1508
  if (legacyDirEnv !== void 0 && legacyDirEnv !== "") {
1171
1509
  return isAbsolute(legacyDirEnv) ? legacyDirEnv : join3(base, legacyDirEnv);
1172
1510
  }
1173
- const currentDir = join3(base, CURRENT_DATA_DIR_NAME);
1174
- const legacyDir = join3(base, LEGACY_DATA_DIR_NAME);
1175
- return !hasDataDirState(pathExists, currentDir) && hasDataDirState(pathExists, legacyDir) ? legacyDir : currentDir;
1511
+ return join3(base, CURRENT_DATA_DIR_NAME);
1176
1512
  }
1177
- var CURRENT_DATA_DIR_NAME, LEGACY_DATA_DIR_NAME;
1513
+ var CURRENT_DATA_DIR_NAME;
1178
1514
  var init_dataDir = __esm({
1179
1515
  "src/proxy/dataDir.ts"() {
1180
1516
  "use strict";
1181
1517
  CURRENT_DATA_DIR_NAME = ".agent-inspector";
1182
- LEGACY_DATA_DIR_NAME = ".llm-inspector";
1183
1518
  }
1184
1519
  });
1185
1520
 
@@ -1193,7 +1528,7 @@ __export(doctor_exports, {
1193
1528
  parseDoctorArgs: () => parseDoctorArgs,
1194
1529
  runDoctor: () => runDoctor
1195
1530
  });
1196
- import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync } from "node:fs";
1531
+ import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "node:fs";
1197
1532
  import { isAbsolute as isAbsolute2, join as join4, resolve } from "node:path";
1198
1533
  import { createConnection } from "node:net";
1199
1534
  function check(name, severity, message, hint = "") {
@@ -1216,6 +1551,7 @@ function parseDoctorArgs(argv, env = process.env) {
1216
1551
  port: envPort ?? DEFAULT_PORT2,
1217
1552
  configDir: null,
1218
1553
  providersJson: null,
1554
+ chromeExtension: false,
1219
1555
  help: false
1220
1556
  };
1221
1557
  for (let i = 0; i < argv.length; i++) {
@@ -1255,6 +1591,9 @@ function parseDoctorArgs(argv, env = process.env) {
1255
1591
  i++;
1256
1592
  break;
1257
1593
  }
1594
+ case "--chrome-extension":
1595
+ options.chromeExtension = true;
1596
+ break;
1258
1597
  default:
1259
1598
  return { kind: "error", message: `doctor: unknown option ${arg}` };
1260
1599
  }
@@ -1496,13 +1835,12 @@ function checkExtensionPackage(rootDir, deps) {
1496
1835
  }
1497
1836
  async function buildDoctorReport(options, deps = createDoctorDeps()) {
1498
1837
  const rootDir = findProjectRoot(deps.cwd, deps);
1499
- const checks = [
1838
+ const coreChecks = [
1500
1839
  await checkProxyHealth(options.port, deps),
1501
1840
  checkProviderConfig(options, deps),
1502
- checkPackage(rootDir, deps),
1503
- checkExtensionSource(rootDir, deps),
1504
- checkExtensionPackage(rootDir, deps)
1841
+ checkPackage(rootDir, deps)
1505
1842
  ];
1843
+ const checks = options.chromeExtension ? [...coreChecks, checkExtensionSource(rootDir, deps), checkExtensionPackage(rootDir, deps)] : coreChecks;
1506
1844
  const passCount = checks.filter((item) => item.severity === "pass").length;
1507
1845
  const warnCount = checks.filter((item) => item.severity === "warn").length;
1508
1846
  const failCount = checks.filter((item) => item.severity === "fail").length;
@@ -1534,9 +1872,10 @@ function doctorHelp() {
1534
1872
  "agent-inspector doctor",
1535
1873
  "",
1536
1874
  "Usage:",
1537
- " agent-inspector doctor [--port <port>] [--config-dir <dir>] [--providers <json>]",
1875
+ " agent-inspector doctor [--port <port>] [--config-dir <dir>] [--providers <json>] [--chrome-extension]",
1538
1876
  "",
1539
- "Checks local proxy health, provider config presence, package metadata, and Chrome companion readiness.",
1877
+ "Checks local proxy health, provider config presence, and package metadata.",
1878
+ "Pass --chrome-extension to also check Chrome companion source and packaged artifacts.",
1540
1879
  ""
1541
1880
  ].join("\n");
1542
1881
  }
@@ -1578,7 +1917,7 @@ function readText(path) {
1578
1917
  }
1579
1918
  function listDir(path) {
1580
1919
  try {
1581
- return readdirSync(path);
1920
+ return readdirSync2(path);
1582
1921
  } catch {
1583
1922
  return null;
1584
1923
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "date": "2026-06-27T02:00:37.246Z",
2
+ "date": "2026-06-27T08:36:50.558Z",
3
3
  "preset": "node-server",
4
4
  "framework": {
5
5
  "name": "nitro",