@tonyclaw/agent-inspector 2.0.15 → 2.0.17

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/.output/cli.js +399 -28
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-B6WCFRJq.js → CompareDrawer-DDg7Cs4N.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-CofGRJoO.js → ProxyViewerContainer-DbbK1y7N.js} +24 -24
  5. package/.output/public/assets/{ReplayDialog-O_53zkX8.js → ReplayDialog-C1zWNkoz.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-CqBSMZv5.js → RequestAnatomy-DR8OICOJ.js} +1 -1
  7. package/.output/public/assets/{ResponseView-BvbA6zot.js → ResponseView-Dh9iSj6h.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-Bnf6djjc.js → StreamingChunkSequence-B_xElyH3.js} +1 -1
  9. package/.output/public/assets/_sessionId-gv1a_NNu.js +1 -0
  10. package/.output/public/assets/index-u-LwDaeH.js +1 -0
  11. package/.output/public/assets/{main-Biir9ZGe.js → main-bwZlEXw2.js} +2 -2
  12. package/.output/server/{_sessionId-B77Gh4IL.mjs → _sessionId-BEuJJhqT.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-D4-RHFqW.mjs → CompareDrawer-yTO93GMz.mjs} +2 -2
  14. package/.output/server/_ssr/{ProxyViewerContainer-YP28-_2H.mjs → ProxyViewerContainer-C8qCkHGB.mjs} +72 -22
  15. package/.output/server/_ssr/{ReplayDialog-D9rQlrcY.mjs → ReplayDialog-DRF9PG7Z.mjs} +3 -3
  16. package/.output/server/_ssr/{RequestAnatomy-BXCRWD9H.mjs → RequestAnatomy-DBcuV_jV.mjs} +2 -2
  17. package/.output/server/_ssr/{ResponseView-DEwWMqSS.mjs → ResponseView-JJm78HZT.mjs} +2 -2
  18. package/.output/server/_ssr/{StreamingChunkSequence-CdrTPf5v.mjs → StreamingChunkSequence-DyGKjBYx.mjs} +2 -2
  19. package/.output/server/_ssr/{index-Chf1DYqT.mjs → index-T7JG28t6.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-BHXU5jWm.mjs → router-BJob8RN3.mjs} +2 -2
  22. package/.output/server/{_tanstack-start-manifest_v-D1dtacWy.mjs → _tanstack-start-manifest_v-CuiFi3XC.mjs} +1 -1
  23. package/.output/server/index.mjs +57 -57
  24. package/README.md +22 -5
  25. package/package.json +3 -3
  26. package/scripts/setup-agent-skills.mjs +64 -0
  27. package/src/cli/onboard.ts +407 -13
  28. package/src/cli/templates/codex-skill-onboard.ts +13 -4
  29. package/src/cli/templates/command-onboard.ts +12 -4
  30. package/src/cli/templates/skill-onboard.ts +30 -8
  31. package/src/components/OnboardingBanner.tsx +35 -7
  32. package/src/components/providers/SettingsDialog.tsx +22 -4
  33. package/src/lib/useOnboarding.ts +9 -1
  34. package/.output/public/assets/_sessionId-9ICCw6YA.js +0 -1
  35. package/.output/public/assets/index-DVkMYH8H.js +0 -1
  36. 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({
@@ -140,6 +143,8 @@ Codex user-level configuration lives in \`~/.codex/config.toml\`. Codex supports
140
143
 
141
144
  Keep this setup local and explicit. Agent Inspector MCP tools can read captured requests and provider configuration, so only wire it into trusted local Codex environments.
142
145
 
146
+ Agent Inspector starts in **Simple mode** by default. Keep Simple mode for everyday capture: requests, responses, tools, timing, and token usage stay available without retaining heavier raw headers, raw response, or detailed SSE chunk artifacts. Use **Full mode** only when the user is debugging provider headers, raw response payloads, or SSE stream details.
147
+
143
148
  ---
144
149
 
145
150
  ## Phase 0: Preflight
@@ -148,12 +153,14 @@ Check that the package and Codex home exist without printing secrets.
148
153
 
149
154
  \`\`\`powershell
150
155
  Get-Command agent-inspector -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source
156
+ agent-inspector onboard --status
151
157
  Test-Path (Join-Path $env:USERPROFILE ".codex")
152
158
  Test-Path (Join-Path $env:USERPROFILE ".codex\\config.toml")
153
159
  \`\`\`
154
160
 
155
161
  \`\`\`bash
156
162
  command -v agent-inspector || true
163
+ agent-inspector onboard --status
157
164
  test -d "$HOME/.codex" && echo "codex home: present" || echo "codex home: missing"
158
165
  test -f "$HOME/.codex/config.toml" && echo "config: present" || echo "config: missing"
159
166
  \`\`\`
@@ -164,25 +171,30 @@ If \`agent-inspector\` is missing, ask the user to install it first:
164
171
  npm install -g @tonyclaw/agent-inspector
165
172
  \`\`\`
166
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
+
167
177
  Do not read \`~/.codex/auth.json\`, token files, or unrelated Codex state files.
168
178
 
169
179
  ---
170
180
 
171
181
  ## Phase 1: Start Agent Inspector
172
182
 
173
- Start or reuse Agent Inspector before wiring MCP. Prefer the installed binary so Windows users get the branded runtime in Task Manager.
183
+ Start or reuse Agent Inspector before wiring MCP. Prefer the installed binary so Windows users get the branded runtime in Task Manager. Start onboarding in Simple mode; if the user needs raw headers, raw response, or SSE chunks later, restart with \`agent-inspector --mode full\`.
174
184
 
175
185
  \`\`\`powershell
176
- agent-inspector --background --no-open
186
+ agent-inspector --mode simple --background --no-open
177
187
  Invoke-RestMethod -Uri "http://localhost:${port}/api/health" -TimeoutSec 3
188
+ Invoke-RestMethod -Uri "http://localhost:${port}/api/config" -TimeoutSec 3 | Select-Object captureMode
178
189
  \`\`\`
179
190
 
180
191
  \`\`\`bash
181
- agent-inspector --background --no-open
192
+ agent-inspector --mode simple --background --no-open
182
193
  curl -fsS "http://localhost:${port}/api/health"
194
+ curl -fsS "http://localhost:${port}/api/config" | grep -o '"captureMode":"[^"]*"'
183
195
  \`\`\`
184
196
 
185
- If the health check fails, show only the relevant error and ask whether to diagnose startup before editing Codex config.
197
+ If the health check fails, show only the relevant error and ask whether to diagnose startup before editing Codex config. If the active capture mode is not \`simple\`, explain that an existing process is already running and offer to restart with \`agent-inspector --mode simple --force-restart\`.
186
198
 
187
199
  ---
188
200
 
@@ -348,7 +360,19 @@ Default proxy port: \`${port}\` (override with \`PORT=<n> agent-inspector\` or \
348
360
 
349
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."
350
362
 
351
- **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.
352
376
 
353
377
  \`\`\`bash
354
378
  # 1. Is the proxy already up?
@@ -504,11 +528,13 @@ if ($null) { Write-Host 'claude-code: present' } else { Write-Host 'claude-code:
504
528
  \`\`\`
505
529
  ## Welcome to Agent Inspector!
506
530
 
507
- Agent Inspector is an agent observability and knowledge-capture platform for AI coding tools. The \`agent-inspector\` CLI runs a transparent local proxy + Web UI, so you can see every model request and response: system prompts, tool definitions, message history, SSE streaming chunks, and token counts captured live in a browser tab.
531
+ Agent Inspector is an agent observability and knowledge-capture platform for AI coding tools. The \`agent-inspector\` CLI runs a transparent local proxy + Web UI, so you can see model requests and responses, system prompts, tool definitions, message history, timing, and token counts captured live in a browser tab.
532
+
533
+ Agent Inspector starts in **Simple mode** by default. Simple mode is the right habit for everyday use: it keeps requests, responses, tools, timing, and token usage while avoiding heavier raw headers, raw response, and detailed SSE chunk artifacts. Use **Full mode** only when the user is debugging provider headers, raw response payloads, or SSE stream details.
508
534
 
509
535
  **What we'll do in the next ~10 minutes:**
510
536
  1. Add your first LLM provider (Anthropic or OpenAI key)
511
- 2. Start the proxy
537
+ 2. Start the proxy in Simple mode
512
538
  3. Wire your AI tool to use it
513
539
  4. Capture a first request end-to-end
514
540
  5. Tour the key UI affordances
@@ -630,7 +656,7 @@ $json | Set-Content -Path $file -Encoding UTF8
630
656
 
631
657
  ## Phase 3: Start proxy
632
658
 
633
- **EXPLAIN:** "Time to start the proxy. It binds to port ${port} by default, reuses an already-running healthy agent-inspector, and prints the URL. Use \`--force-restart\` only when you intentionally want to replace the existing process."
659
+ **EXPLAIN:** "Time to start the proxy. It binds to port ${port} by default, starts in Simple mode for lower overhead, reuses an already-running healthy agent-inspector, and prints the URL. Use \`--force-restart\` only when you intentionally want to replace the existing process. If the user is diagnosing raw headers, raw response, or SSE chunks, restart with \`agent-inspector --mode full\`."
634
660
 
635
661
  **DO:** Skip this phase entirely if the Phase 0 health check already reported \`PROXY: up\` and the user opted to skip done phases.
636
662
 
@@ -638,7 +664,7 @@ $json | Set-Content -Path $file -Encoding UTF8
638
664
 
639
665
  \`\`\`bash
640
666
  # Unix / macOS / WSL
641
- agent-inspector --background --no-open > /tmp/agent-inspector.log 2>&1
667
+ agent-inspector --mode simple --background --no-open > /tmp/agent-inspector.log 2>&1
642
668
  \`\`\`
643
669
 
644
670
  \`\`\`powershell
@@ -651,14 +677,14 @@ $err = Join-Path $env:TEMP 'agent-inspector.err.log'
651
677
  $found = Get-Command agent-inspector -ErrorAction SilentlyContinue
652
678
  if ($found) {
653
679
  $shim = $found.Source
654
- $args = '--background','--no-open'
680
+ $args = '--mode','simple','--background','--no-open'
655
681
  } elseif (Test-Path (Join-Path $env:APPDATA 'npm/agent-inspector.cmd')) {
656
682
  $shim = Join-Path $env:APPDATA 'npm/agent-inspector.cmd'
657
- $args = '--background','--no-open'
683
+ $args = '--mode','simple','--background','--no-open'
658
684
  } else {
659
685
  # bin not on PATH and not at the default npm prefix \u2014 let cmd resolve it
660
686
  $shim = 'cmd.exe'
661
- $args = '/c','agent-inspector','--background','--no-open'
687
+ $args = '/c','agent-inspector','--mode','simple','--background','--no-open'
662
688
  }
663
689
  Start-Process -FilePath $shim -ArgumentList $args -RedirectStandardOutput $log -RedirectStandardError $err -WindowStyle Hidden
664
690
  \`\`\`
@@ -678,6 +704,12 @@ done
678
704
  curl -sS "http://localhost:${port}/api/health"
679
705
  \`\`\`
680
706
 
707
+ **DO:** Read \`/api/config\` and tell the user which capture mode is active. If it is not \`simple\` during onboarding, explain that an existing process is already running and offer to restart with \`agent-inspector --mode simple --force-restart\`.
708
+
709
+ \`\`\`bash
710
+ curl -sS "http://localhost:${port}/api/config" | grep -o '"captureMode":"[^"]*"'
711
+ \`\`\`
712
+
681
713
  > **PAUSE** \u2014 if the health check fails, show the user the log file (\`/tmp/agent-inspector.log\` or \`%TEMP%\\agent-inspector.log\`) and diagnose. Common issues: another process on the port, firewall, missing providers. Use \`AskUserQuestion\` with header \`Proxy up?\` and options \`["Yes, proxy is up", "No, I see an error in the log"]\`. Wait for the answer.
682
714
 
683
715
  ---
@@ -822,6 +854,8 @@ done
822
854
  \`\`\`
823
855
 
824
856
  - **Re-run onboard**: \`agent-inspector onboard --force\` refreshes this skill.
857
+ - **Check onboard files**: \`agent-inspector onboard --status\` shows whether generated skills are
858
+ current, outdated, missing, newer, or custom.
825
859
  - **Full docs**: see the project README (linked from the Web UI footer).
826
860
 
827
861
  > **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.
@@ -852,10 +886,42 @@ var onboard_exports = {};
852
886
  __export(onboard_exports, {
853
887
  runOnboard: () => runOnboard
854
888
  });
855
- import { mkdirSync, writeFileSync, existsSync as existsSync2, readFileSync } from "node:fs";
889
+ import {
890
+ mkdirSync,
891
+ writeFileSync,
892
+ existsSync as existsSync2,
893
+ readFileSync,
894
+ unlinkSync,
895
+ readdirSync,
896
+ rmdirSync
897
+ } from "node:fs";
856
898
  import { homedir as homedir2 } from "node:os";
857
899
  import { dirname, join as join2 } from "node:path";
858
900
  import { fileURLToPath } from "node:url";
901
+ function actionForStatus(label, state) {
902
+ switch (state) {
903
+ case "missing":
904
+ switch (label) {
905
+ case "Codex skill":
906
+ return "agent-inspector onboard --codex-only";
907
+ case "Claude skill":
908
+ case "Claude command":
909
+ return "agent-inspector onboard --skip-codex-skill";
910
+ default:
911
+ return "agent-inspector onboard";
912
+ }
913
+ case "outdated":
914
+ return "agent-inspector onboard --force";
915
+ case "custom":
916
+ return "preserved; use agent-inspector onboard --force to replace";
917
+ case "newer":
918
+ return "no action; installed file is newer than this package";
919
+ case "current":
920
+ return "no action";
921
+ default:
922
+ return "agent-inspector onboard";
923
+ }
924
+ }
859
925
  function parseFlags(argv) {
860
926
  const flags = {
861
927
  force: false,
@@ -864,6 +930,9 @@ function parseFlags(argv) {
864
930
  skipToolWire: false,
865
931
  codexOnly: false,
866
932
  skipCodexSkill: false,
933
+ uninstall: false,
934
+ status: false,
935
+ json: false,
867
936
  skillDir: null,
868
937
  codexSkillDir: null
869
938
  };
@@ -890,6 +959,15 @@ function parseFlags(argv) {
890
959
  case "--skip-codex-skill":
891
960
  flags.skipCodexSkill = true;
892
961
  break;
962
+ case "--uninstall":
963
+ flags.uninstall = true;
964
+ break;
965
+ case "--status":
966
+ flags.status = true;
967
+ break;
968
+ case "--json":
969
+ flags.json = true;
970
+ break;
893
971
  case "--skill-dir": {
894
972
  const next = argv[i + 1];
895
973
  if (next === void 0) {
@@ -938,6 +1016,9 @@ Options:
938
1016
  --skip-tool-wire Skip the wire-tool phase in the Claude skill body
939
1017
  --skip-codex-skill Install only the Claude Code skill and slash command
940
1018
  --codex-only Install only the Codex skill
1019
+ --uninstall Remove generated files whose version matches this package
1020
+ --status Show installed onboarding file versions and suggested action
1021
+ --json Emit machine-readable JSON with --status
941
1022
  --skill-dir <path> Override the target Claude root directory (default: ~/.claude)
942
1023
  --codex-skill-dir <path> Override the target Codex skills directory (default: ~/.codex/skills)
943
1024
  -h, --help Show this help
@@ -973,15 +1054,173 @@ function buildDetectedSummary() {
973
1054
  - Not detected: ${absentList}`;
974
1055
  }
975
1056
  function readPackageVersion() {
1057
+ const packageJsonPaths = [
1058
+ join2(__dirname, "..", "package.json"),
1059
+ join2(__dirname, "..", "..", "package.json")
1060
+ ];
976
1061
  try {
977
- const raw = JSON.parse(readFileSync(join2(__dirname, "..", "package.json"), "utf8"));
978
- if (isObject(raw) && typeof raw["version"] === "string") {
979
- return raw["version"];
1062
+ for (const packageJsonPath of packageJsonPaths) {
1063
+ if (existsSync2(packageJsonPath)) {
1064
+ const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
1065
+ if (isObject(raw) && typeof raw["version"] === "string") {
1066
+ return raw["version"];
1067
+ }
1068
+ }
980
1069
  }
981
1070
  } catch {
982
1071
  }
983
1072
  return "0.0.0";
984
1073
  }
1074
+ function parseVersion(version) {
1075
+ const match = SEMVER_PATTERN.exec(version);
1076
+ if (match === null) {
1077
+ return null;
1078
+ }
1079
+ const majorText = match[1];
1080
+ const minorText = match[2];
1081
+ const patchText = match[3];
1082
+ if (majorText === void 0 || minorText === void 0 || patchText === void 0) {
1083
+ return null;
1084
+ }
1085
+ const major = Number(majorText);
1086
+ const minor = Number(minorText);
1087
+ const patch = Number(patchText);
1088
+ if (!Number.isInteger(major) || !Number.isInteger(minor) || !Number.isInteger(patch)) {
1089
+ return null;
1090
+ }
1091
+ return { major, minor, patch };
1092
+ }
1093
+ function compareVersions(left, right) {
1094
+ const leftVersion = parseVersion(left);
1095
+ const rightVersion = parseVersion(right);
1096
+ if (leftVersion === null || rightVersion === null) {
1097
+ return null;
1098
+ }
1099
+ const leftParts = [leftVersion.major, leftVersion.minor, leftVersion.patch];
1100
+ const rightParts = [rightVersion.major, rightVersion.minor, rightVersion.patch];
1101
+ for (let index = 0; index < leftParts.length; index++) {
1102
+ const leftPart = leftParts[index];
1103
+ const rightPart = rightParts[index];
1104
+ if (leftPart === void 0 || rightPart === void 0) {
1105
+ return null;
1106
+ }
1107
+ if (leftPart > rightPart) {
1108
+ return 1;
1109
+ }
1110
+ if (leftPart < rightPart) {
1111
+ return -1;
1112
+ }
1113
+ }
1114
+ return 0;
1115
+ }
1116
+ function extractGeneratedVersion(body) {
1117
+ const frontmatterMatch = FRONTMATTER_PATTERN.exec(body);
1118
+ if (frontmatterMatch === null) {
1119
+ return null;
1120
+ }
1121
+ const frontmatter = frontmatterMatch[1];
1122
+ if (frontmatter === void 0) {
1123
+ return null;
1124
+ }
1125
+ const versionMatch = GENERATED_VERSION_PATTERN.exec(frontmatter);
1126
+ if (versionMatch === null) {
1127
+ return null;
1128
+ }
1129
+ return versionMatch[1] ?? null;
1130
+ }
1131
+ function hasAgentInspectorAuthor(body) {
1132
+ const frontmatterMatch = FRONTMATTER_PATTERN.exec(body);
1133
+ if (frontmatterMatch === null) {
1134
+ return false;
1135
+ }
1136
+ const frontmatter = frontmatterMatch[1];
1137
+ if (frontmatter === void 0) {
1138
+ return false;
1139
+ }
1140
+ return /^\s*author:\s*agent-inspector\s*$/m.test(frontmatter);
1141
+ }
1142
+ function readGeneratedVersion(path) {
1143
+ try {
1144
+ return extractGeneratedVersion(readFileSync(path, "utf8"));
1145
+ } catch {
1146
+ return null;
1147
+ }
1148
+ }
1149
+ function isMatchingGeneratedFile(path, currentVersion) {
1150
+ try {
1151
+ const body = readFileSync(path, "utf8");
1152
+ return hasAgentInspectorAuthor(body) && extractGeneratedVersion(body) === currentVersion;
1153
+ } catch {
1154
+ return false;
1155
+ }
1156
+ }
1157
+ function readGeneratedFileStatus(file, currentVersion) {
1158
+ if (!existsSync2(file.path)) {
1159
+ return {
1160
+ label: file.label,
1161
+ path: file.path,
1162
+ state: "missing",
1163
+ version: null,
1164
+ action: actionForStatus(file.label, "missing")
1165
+ };
1166
+ }
1167
+ try {
1168
+ const body = readFileSync(file.path, "utf8");
1169
+ const version = extractGeneratedVersion(body);
1170
+ if (!hasAgentInspectorAuthor(body) || version === null) {
1171
+ return {
1172
+ label: file.label,
1173
+ path: file.path,
1174
+ state: "custom",
1175
+ version,
1176
+ action: actionForStatus(file.label, "custom")
1177
+ };
1178
+ }
1179
+ const comparison = compareVersions(version, currentVersion);
1180
+ if (comparison === null) {
1181
+ return {
1182
+ label: file.label,
1183
+ path: file.path,
1184
+ state: "custom",
1185
+ version,
1186
+ action: actionForStatus(file.label, "custom")
1187
+ };
1188
+ }
1189
+ if (comparison < 0) {
1190
+ return {
1191
+ label: file.label,
1192
+ path: file.path,
1193
+ state: "outdated",
1194
+ version,
1195
+ action: actionForStatus(file.label, "outdated")
1196
+ };
1197
+ }
1198
+ if (comparison > 0) {
1199
+ return {
1200
+ label: file.label,
1201
+ path: file.path,
1202
+ state: "newer",
1203
+ version,
1204
+ action: actionForStatus(file.label, "newer")
1205
+ };
1206
+ }
1207
+ return {
1208
+ label: file.label,
1209
+ path: file.path,
1210
+ state: "current",
1211
+ version,
1212
+ action: actionForStatus(file.label, "current")
1213
+ };
1214
+ } catch {
1215
+ return {
1216
+ label: file.label,
1217
+ path: file.path,
1218
+ state: "custom",
1219
+ version: null,
1220
+ action: actionForStatus(file.label, "custom")
1221
+ };
1222
+ }
1223
+ }
985
1224
  function buildPlannedFiles(flags, targets, version) {
986
1225
  const installClaude = !flags.codexOnly;
987
1226
  const installCodex = !flags.skipCodexSkill;
@@ -991,7 +1230,7 @@ function buildPlannedFiles(flags, targets, version) {
991
1230
  port: DEFAULT_PORT,
992
1231
  detectedSummary
993
1232
  }) : "";
994
- const commandBody = installClaude ? renderCommandOnboard() : "";
1233
+ const commandBody = installClaude ? renderCommandOnboard({ version }) : "";
995
1234
  const codexSkillBody = installCodex ? renderCodexSkillOnboard({
996
1235
  version,
997
1236
  port: DEFAULT_PORT
@@ -1017,8 +1256,125 @@ function buildPlannedFiles(flags, targets, version) {
1017
1256
  }
1018
1257
  ];
1019
1258
  }
1020
- function shouldWrite(file, force) {
1021
- return file.enabled && (force || !existsSync2(file.path));
1259
+ function shouldWrite(file, force, currentVersion) {
1260
+ if (!file.enabled) {
1261
+ return false;
1262
+ }
1263
+ if (force || !existsSync2(file.path)) {
1264
+ return true;
1265
+ }
1266
+ const existingVersion = readGeneratedVersion(file.path);
1267
+ if (existingVersion === null) {
1268
+ return false;
1269
+ }
1270
+ const comparison = compareVersions(existingVersion, currentVersion);
1271
+ return comparison !== null && comparison < 0;
1272
+ }
1273
+ function shouldUninstall(file, currentVersion) {
1274
+ return file.enabled && existsSync2(file.path) && isMatchingGeneratedFile(file.path, currentVersion);
1275
+ }
1276
+ function removeEmptyDirectory(path) {
1277
+ try {
1278
+ if (readdirSync(path).length === 0) {
1279
+ rmdirSync(path);
1280
+ }
1281
+ } catch {
1282
+ }
1283
+ }
1284
+ function runUninstall(plannedFiles, currentVersion, dryRun) {
1285
+ const enabledFiles = plannedFiles.filter((file) => file.enabled);
1286
+ const filesToRemove = enabledFiles.filter((file) => shouldUninstall(file, currentVersion));
1287
+ if (dryRun) {
1288
+ process.stdout.write(`agent-inspector onboard --uninstall --dry-run
1289
+
1290
+ `);
1291
+ for (const file of enabledFiles) {
1292
+ const status = shouldUninstall(file, currentVersion) ? "matching" : "skipped";
1293
+ process.stdout.write(`${file.label}: ${file.path} (${status})
1294
+ `);
1295
+ }
1296
+ process.stdout.write(`
1297
+ No files were removed.
1298
+ `);
1299
+ return 0;
1300
+ }
1301
+ if (filesToRemove.length === 0) {
1302
+ process.stdout.write(
1303
+ "agent-inspector onboard: no generated onboarding files match this package version\n"
1304
+ );
1305
+ return 0;
1306
+ }
1307
+ try {
1308
+ for (const file of filesToRemove) {
1309
+ unlinkSync(file.path);
1310
+ removeEmptyDirectory(dirname(file.path));
1311
+ process.stdout.write(`Removed ${file.label}: ${file.path}
1312
+ `);
1313
+ }
1314
+ } catch (err) {
1315
+ const msg = err instanceof Error ? err.message : String(err);
1316
+ process.stderr.write(`agent-inspector onboard: failed to remove files: ${msg}
1317
+ `);
1318
+ return 1;
1319
+ }
1320
+ return 0;
1321
+ }
1322
+ function formatStatusVersion(status) {
1323
+ return status.version ?? "-";
1324
+ }
1325
+ function summarizeStatusAction(statuses) {
1326
+ const actionable = statuses.filter(
1327
+ (status) => status.state === "missing" || status.state === "outdated"
1328
+ );
1329
+ if (actionable.length > 0) {
1330
+ const actions = Array.from(new Set(actionable.map((status) => status.action)));
1331
+ return `Run: ${actions.join(" && ")}`;
1332
+ }
1333
+ if (statuses.some((status) => status.state === "custom")) {
1334
+ return "Custom files are preserved. Use --force only if you want to replace them.";
1335
+ }
1336
+ if (statuses.some((status) => status.state === "newer")) {
1337
+ return "Installed files are newer than this package. No action needed.";
1338
+ }
1339
+ return "All selected onboarding files are current.";
1340
+ }
1341
+ function runStatus(plannedFiles, currentVersion, json) {
1342
+ const enabledFiles = plannedFiles.filter((file) => file.enabled);
1343
+ const statuses = enabledFiles.map((file) => readGeneratedFileStatus(file, currentVersion));
1344
+ const summary = summarizeStatusAction(statuses);
1345
+ if (json) {
1346
+ process.stdout.write(
1347
+ `${JSON.stringify(
1348
+ {
1349
+ packageVersion: currentVersion,
1350
+ files: statuses,
1351
+ suggestedAction: summary
1352
+ },
1353
+ null,
1354
+ 2
1355
+ )}
1356
+ `
1357
+ );
1358
+ return 0;
1359
+ }
1360
+ process.stdout.write(`agent-inspector onboard status
1361
+ `);
1362
+ process.stdout.write(`Package version: ${currentVersion}
1363
+
1364
+ `);
1365
+ for (const status of statuses) {
1366
+ process.stdout.write(`${status.label}: ${status.state}`);
1367
+ process.stdout.write(`, version ${formatStatusVersion(status)}
1368
+ `);
1369
+ process.stdout.write(` ${status.path}
1370
+ `);
1371
+ process.stdout.write(` Action: ${status.action}
1372
+ `);
1373
+ }
1374
+ process.stdout.write(`
1375
+ Suggested action: ${summary}
1376
+ `);
1377
+ return 0;
1022
1378
  }
1023
1379
  function runOnboard(argv) {
1024
1380
  try {
@@ -1037,10 +1393,20 @@ function runOnboardSync(argv) {
1037
1393
  const version = readPackageVersion();
1038
1394
  const plannedFiles = buildPlannedFiles(flags, targets, version);
1039
1395
  const enabledFiles = plannedFiles.filter((file) => file.enabled);
1396
+ if (flags.json && !flags.status) {
1397
+ process.stderr.write("agent-inspector onboard: --json is only supported with --status\n");
1398
+ return 2;
1399
+ }
1040
1400
  if (enabledFiles.length === 0) {
1041
1401
  process.stderr.write("agent-inspector onboard: no onboarding target selected\n");
1042
1402
  return 2;
1043
1403
  }
1404
+ if (flags.status) {
1405
+ return runStatus(plannedFiles, version, flags.json);
1406
+ }
1407
+ if (flags.uninstall) {
1408
+ return runUninstall(plannedFiles, version, flags.dryRun);
1409
+ }
1044
1410
  if (flags.dryRun) {
1045
1411
  process.stdout.write(`agent-inspector onboard --dry-run
1046
1412
 
@@ -1085,9 +1451,11 @@ No files were written.
1085
1451
  `);
1086
1452
  return 0;
1087
1453
  }
1088
- const filesToWrite = plannedFiles.filter((file) => shouldWrite(file, flags.force));
1454
+ const filesToWrite = plannedFiles.filter((file) => shouldWrite(file, flags.force, version));
1089
1455
  if (filesToWrite.length === 0) {
1090
- process.stdout.write("agent-inspector onboard: all selected onboarding files already exist\n");
1456
+ process.stdout.write(
1457
+ "agent-inspector onboard: all selected onboarding files are already up to date\n"
1458
+ );
1091
1459
  process.stdout.write("Re-run with --force to refresh.\n");
1092
1460
  return 0;
1093
1461
  }
@@ -1105,7 +1473,7 @@ No files were written.
1105
1473
  const firstTool = detectFirst();
1106
1474
  const toolHint = firstTool !== null ? firstTool.displayName : "no known tool detected";
1107
1475
  for (const file of filesToWrite) {
1108
- process.stdout.write(`Installed ${file.label} to: ${file.path}
1476
+ process.stdout.write(`Installed/updated ${file.label} to: ${file.path}
1109
1477
  `);
1110
1478
  }
1111
1479
  process.stdout.write(`
@@ -1125,7 +1493,7 @@ Next steps:
1125
1493
  `);
1126
1494
  return 0;
1127
1495
  }
1128
- var __filename, __dirname, DEFAULT_PORT, SKILL_DIR_NAME, SKILL_FILE_NAME, COMMAND_FILE_NAME;
1496
+ var __filename, __dirname, DEFAULT_PORT, SKILL_DIR_NAME, SKILL_FILE_NAME, COMMAND_FILE_NAME, GENERATED_VERSION_PATTERN, FRONTMATTER_PATTERN, SEMVER_PATTERN;
1129
1497
  var init_onboard = __esm({
1130
1498
  "src/cli/onboard.ts"() {
1131
1499
  "use strict";
@@ -1139,6 +1507,9 @@ var init_onboard = __esm({
1139
1507
  SKILL_DIR_NAME = "agent-inspector-onboard";
1140
1508
  SKILL_FILE_NAME = "SKILL.md";
1141
1509
  COMMAND_FILE_NAME = process.platform === "win32" ? "agent-inspector-onboard.md" : "agent-inspector:onboard.md";
1510
+ GENERATED_VERSION_PATTERN = /^\s*version:\s*([0-9]+\.[0-9]+\.[0-9]+(?:[-+][^\s]+)?)\s*$/m;
1511
+ FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/;
1512
+ SEMVER_PATTERN = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/;
1142
1513
  }
1143
1514
  });
1144
1515
 
@@ -1181,7 +1552,7 @@ __export(doctor_exports, {
1181
1552
  parseDoctorArgs: () => parseDoctorArgs,
1182
1553
  runDoctor: () => runDoctor
1183
1554
  });
1184
- import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync } from "node:fs";
1555
+ import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "node:fs";
1185
1556
  import { isAbsolute as isAbsolute2, join as join4, resolve } from "node:path";
1186
1557
  import { createConnection } from "node:net";
1187
1558
  function check(name, severity, message, hint = "") {
@@ -1566,7 +1937,7 @@ function readText(path) {
1566
1937
  }
1567
1938
  function listDir(path) {
1568
1939
  try {
1569
- return readdirSync(path);
1940
+ return readdirSync2(path);
1570
1941
  } catch {
1571
1942
  return null;
1572
1943
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "date": "2026-06-27T01:33:24.458Z",
2
+ "date": "2026-06-27T08:05:51.578Z",
3
3
  "preset": "node-server",
4
4
  "framework": {
5
5
  "name": "nitro",