Skip to content

doctor/install --host claude: claude plugin list --json errors[] is never read, so a plugin Claude refused to load is reported as installed/current #464

Description

@ScriptedAlchemy

Symptom in cargo-hauler

ScriptedAlchemy/cargo-hauler#48 — the installed Claude pack is refused by Claude Code (Status: ✘ failed to load, errors: ["Hook load failed: Duplicate hooks file detected …"] in claude plugin list --json), yet the framework's own tooling reported it healthy: cargo-hauler PR 34's install proof records agent-bundle install claude --from artifact/claude --scope user → state: installed and doctor --host claude → installed copy: current. The user only found out by running claude plugin list --json | jq '.errors' by hand.

The second ask in that issue is exactly this: have the install/verify path surface errors[] so a plugin that failed to load is reported as broken, not current.

Root cause in agent-bundle (main 10a98a0fb)

Both readers of claude plugin list --json only look at id, installPath, scope, version and treat every row as state: 'installed':

  • packages/agent-bundle/src/install/doctor.ts:874-893 (publicHostInventory, Claude branch) — builds DoctorFinding { state: 'installed', … } per row; the row's errors array (and any enabled/failed status field) is never read, so the installed-copy comparison proceeds to current.
  • packages/agent-bundle/src/install/install.ts:305-328 (parsePublicHostInventory) — same fields; install prints state: installed from this even when the host has rejected the plugin.
  • The Codex branch (doctor.ts:894-912) skips rows with installed === false but likewise ignores any error payload.

The capabilities table already knows the surface: capabilities/claude-2.1.250.json:839 records that claude plugin list --json exposes error codes (dependency-unsatisfied, range-conflict, …) in errors.

Workaround currently in cargo-hauler

None; docs/install.md tells users to trust agent-bundle doctor --host <host>.

Proposed fix

  • Parse errors (array of strings) on Claude rows and the equivalent failure/enabled fields on Codex rows in one shared reader (install.ts parsePublicHostInventory is already shared by install and doctor).
  • doctor: when the matching row has a non-empty errors, emit an error-severity diagnostic (new code in the AB73xx install/doctor family) naming the host's message verbatim, and report the installed copy as broken rather than current/stale. The JSON output carries errors on the finding.
  • install: after claude plugin install, re-read the inventory and fail (non-zero, state: 'failed-to-load' or similar) when the freshly installed row reports errors, instead of state: installed.
  • Docs: website/docs/{en,zh} doctor/install pages and docs/diagnostics.md gain the new code.

Acceptance

  • Fixture: a claude plugin list --json payload with errors: ["Hook load failed: …"]agent-bundle doctor --host claude exits non-zero, prints the message, and the JSON report's installed copy state is not current.
  • agent-bundle install claude … against a plugin Claude refuses (e.g. today's duplicate-hooks manifest) exits non-zero and names the error.
  • No change in output for a healthy install (errors: []).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghost-integrationAgent host capabilities, projection, discovery, and lifecycle

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions