@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.
- package/.output/cli.js +399 -28
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-B6WCFRJq.js → CompareDrawer-DDg7Cs4N.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-CofGRJoO.js → ProxyViewerContainer-DbbK1y7N.js} +24 -24
- package/.output/public/assets/{ReplayDialog-O_53zkX8.js → ReplayDialog-C1zWNkoz.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CqBSMZv5.js → RequestAnatomy-DR8OICOJ.js} +1 -1
- package/.output/public/assets/{ResponseView-BvbA6zot.js → ResponseView-Dh9iSj6h.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-Bnf6djjc.js → StreamingChunkSequence-B_xElyH3.js} +1 -1
- package/.output/public/assets/_sessionId-gv1a_NNu.js +1 -0
- package/.output/public/assets/index-u-LwDaeH.js +1 -0
- package/.output/public/assets/{main-Biir9ZGe.js → main-bwZlEXw2.js} +2 -2
- package/.output/server/{_sessionId-B77Gh4IL.mjs → _sessionId-BEuJJhqT.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-D4-RHFqW.mjs → CompareDrawer-yTO93GMz.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-YP28-_2H.mjs → ProxyViewerContainer-C8qCkHGB.mjs} +72 -22
- package/.output/server/_ssr/{ReplayDialog-D9rQlrcY.mjs → ReplayDialog-DRF9PG7Z.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-BXCRWD9H.mjs → RequestAnatomy-DBcuV_jV.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-DEwWMqSS.mjs → ResponseView-JJm78HZT.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-CdrTPf5v.mjs → StreamingChunkSequence-DyGKjBYx.mjs} +2 -2
- package/.output/server/_ssr/{index-Chf1DYqT.mjs → index-T7JG28t6.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-BHXU5jWm.mjs → router-BJob8RN3.mjs} +2 -2
- package/.output/server/{_tanstack-start-manifest_v-D1dtacWy.mjs → _tanstack-start-manifest_v-CuiFi3XC.mjs} +1 -1
- package/.output/server/index.mjs +57 -57
- package/README.md +22 -5
- package/package.json +3 -3
- package/scripts/setup-agent-skills.mjs +64 -0
- package/src/cli/onboard.ts +407 -13
- package/src/cli/templates/codex-skill-onboard.ts +13 -4
- package/src/cli/templates/command-onboard.ts +12 -4
- package/src/cli/templates/skill-onboard.ts +30 -8
- package/src/components/OnboardingBanner.tsx +35 -7
- package/src/components/providers/SettingsDialog.tsx +22 -4
- package/src/lib/useOnboarding.ts +9 -1
- package/.output/public/assets/_sessionId-9ICCw6YA.js +0 -1
- package/.output/public/assets/index-DVkMYH8H.js +0 -1
- 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
|
|
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
|
|
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:**
|
|
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
|
|
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 {
|
|
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
|
|
978
|
-
|
|
979
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
1940
|
+
return readdirSync2(path);
|
|
1570
1941
|
} catch {
|
|
1571
1942
|
return null;
|
|
1572
1943
|
}
|
package/.output/nitro.json
CHANGED