Skip to content

fix: complete vendor coverage in kcap status and kcap --help (Gemini + Kiro) - #169

Merged
realtonyyoung merged 4 commits into
mainfrom
tonyyoung/gemini-kcap-status
Jun 22, 2026
Merged

realtonyyoung merged 4 commits into
mainfrom
tonyyoung/gemini-kcap-status

Conversation

@realtonyyoung

@realtonyyoung realtonyyoung commented Jun 22, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Two fully-supported vendors were missing from user-facing surfaces:

  • Gemini — absent from the kcap status per-agent Hooks line (and its help text), despite kcap plugin install --gemini being supported.
  • Kiro — absent from the top-level kcap --help (usage) and the kcap status Hooks line (and its help text), despite full install/import/hook support that's already documented in the per-command help and the README.

Both are the same omission: a vendor was wired up end-to-end but never added to help-usage.txt and/or the status surface. Found while auditing kcap --help and kcap status for vendor completeness/consistency.

Fix

kcap status (StatusCommand.cs) — BuildHooksStatusLine now renders every supported agent in canonical order: Claude, Codex, Cursor, Copilot, Gemini, Kiro, Pi, via GeminiHooksInstaller.IsInstalled / KiroHooksInstaller.IsInstalled:

Hooks:   Claude ✓  Codex ✓  Cursor ✗  Copilot ✓  Gemini ✗  Kiro ✓  Pi ✓
  • help-status.txt — Hooks description now lists Gemini and Kiro.
  • help-usage.txt (kcap --help) — Kiro added to the import line, both plugin flag lists, the hooks header, and a new hook --kiro --event <name> line. (Gemini was already present in usage.)
  • Tests — status line-builder extended from five → seven agents (Gemini ✓/✗ and Kiro ✓/✗). Added direct GeminiHooksInstaller.IsInstalled coverage (marker branch, settings-hooks fallback, negative); Kiro's IsInstalled is already covered by KiroHooksTests.

No README change needed — both vendors' install/import behavior is already documented there; the gap was only in usage + status.

Testing

  • dotnet build succeeds (.NET 10 SDK).
  • Unit suite: 1644 passed, 0 failed, 0 skipped.
  • AOT publish (-c Release): no IL3050/IL2026 warnings.
  • Verified live kcap status, kcap status --help, and kcap --help output for all seven vendors.

🤖 Generated with Claude Code

`kcap status` listed Claude/Codex/Cursor/Copilot/Pi but omitted Gemini, even though `kcap plugin install --gemini` is fully supported — so a Gemini hooks install couldn't be verified from status. Add Gemini to BuildHooksStatusLine (between Copilot and Pi, matching the canonical vendor order), wire in GeminiHooksInstaller.IsInstalled, and update the `kcap status` help text. Extend the line-builder tests from five to six agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

Blocking

None.

Should-fix

None.

Nit

  • test/Capacitor.Cli.Tests.Unit/StatusCommandHooksTests.cs:103
    The PR covers the pure rendered line, but not the actual kcap status Gemini detection path.
    Suggested change: add focused GeminiHooksInstaller.IsInstalled(...) tests for marker-based detection and settings fallback after PluginCommand.InstallGeminiHooks(...), matching the Codex/Cursor installer coverage style.

Looks-good

  • src/Capacitor.Cli/Commands/StatusCommand.cs:61
    GeminiHooksInstaller.IsInstalled(GeminiPaths.SettingsJson()) is the right detection call: GeminiPaths.SettingsJson() honors $GEMINI_HOME, and install writes/merges into that same shared settings file.

  • src/Capacitor.Cli/Commands/PluginCommand.cs:1223 and src/Capacitor.Cli.Core/Gemini/GeminiHooksInstaller.cs:20
    Install writes both the merged kcap hook --gemini entries and a marker; detection checks marker first, then falls back to scanning hooks. False-positive behavior from a stale marker is consistent with the other marker-based vendors.

  • src/Capacitor.Cli/Commands/StatusCommand.cs:153
    The rendered order is Claude, Codex, Cursor, Copilot, Gemini, Pi, matching the canonical order called out for this PR.

  • src/Capacitor.Cli.Core/Resources/help-status.txt:8
    The help text now matches the real status output and accurately distinguishes Gemini hooks from Pi's extension.

  • CLAUDE.md:50
    I don't think the README-sync rule requires a README change here: this is exposing an already-supported integration in status, not a new command, flag, default behavior, or prerequisite. README already documents Gemini install/remove behavior.

  • AOT safety: no new reflection/dynamic-code issue found in the PR diff. The added status code is ordinary method calls/string rendering, and no new JsonArray collection-expression risk is introduced.

Tests were not run, per review instructions.

Verdict: approve-with-nits.

Follow-up to the kcap status Gemini fix (PR #169 review nit): the status ✓/✗ marker is driven by GeminiHooksInstaller.IsInstalled, which had no direct tests. Add focused coverage for both branches — marker-file detection and the settings-hooks fallback when no marker is present — plus a negative, matching the Cursor/Pi installer-detection style.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

Addressed the test nit in 570578c: added focused GeminiHooksInstaller.IsInstalled coverage in GeminiHooksTests.cs — marker-file detection, the settings-hooks fallback when no marker is present, and a no-kcap-hooks negative (mirrors the Cursor/Pi installer-detection style).

🤖 Addressed by Claude Code

Kiro is a fully-supported vendor (install/import/hooks, documented in the per-command help and README), but was missing from the top-level `kcap --help` (usage) and the status surface — the same omission that affected Gemini. Add Kiro to BuildHooksStatusLine (between Gemini and Pi, matching the canonical vendor order) via KiroHooksInstaller.IsInstalled, update the `kcap status` help text, and list Kiro in the usage import line, plugin flag lists, and hook section. Extend the status line-builder tests to seven agents; Kiro's IsInstalled detection is already covered by KiroHooksTests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@realtonyyoung realtonyyoung changed the title fix: report Gemini hooks in kcap status fix: complete vendor coverage in kcap status and kcap --help (Gemini + Kiro) Jun 22, 2026
@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

Scope note: expanded this PR to also cover Kiro, which had the identical gap — fully supported (install/import/hooks, documented in per-command help + README) but missing from kcap --help (usage) and the kcap status Hooks line. Added it alongside Gemini in the same files since it's the same omission and the same lines. Title/description updated; commit 097d8a7.

🤖 Note from Claude Code

@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

Codex review (round 2) — verdict: request-changes

Should-fix: kcap uninstall is the remaining missed completeness surface for Kiro. The updated kcap --help now says uninstall removes all agent integrations, but UninstallCommand and help-uninstall.txt still omit Kiro: the confirmation list has no ~/.kiro/agents/kcap.json, the command never calls plugin remove --kiro, the marker cleanup never deletes KiroHooksInstaller state, and help-uninstall.txt still lists selective cleanup without --kiro. A user can install Kiro hooks, run kcap uninstall --yes, and still leave the Kiro kcap agent/default-agent integration behind. Suggested: add Kiro to the uninstall imports/summary/confirmation list, call PluginCommand.HandleAsync(["plugin", "remove", "--kiro"]), clean KiroHooksInstaller.DeleteMarker(KiroPaths.KcapAgentJson()), and update help-uninstall.txt including the plugin remove list.

Looks good otherwise: KiroHooksInstaller.IsInstalled(KiroPaths.KcapAgentJson()) matches the $KIRO_HOME-aware install path and marker/file-content detection; Gemini detection still matches the shared $GEMINI_HOME settings path; status/help-usage vendor order is Claude, Codex, Cursor, Copilot, Gemini, Kiro, Pi; help-status.txt correctly treats Kiro as hooks and Pi as the extension; the added Gemini detection tests cover marker and settings fallback; and I did not see new NativeAOT/reflection or JsonArray collection-expression risk in the diff. I did not build or run tests per instructions.

— Codex review (automated)

Round-2 review (request-changes): `kcap uninstall` was the remaining surface omitting Kiro — the confirmation list, the per-vendor `plugin remove` calls, and the marker cleanup all skipped it, so a user could install Kiro hooks, run `kcap uninstall`, and leave the kcap Kiro agent + chat.defaultAgent flip behind. The newly-completed `kcap --help` even advertised uninstall as removing all agent integrations.

Add `plugin remove --kiro` (restores the previous default agent and deletes ~/.kiro/agents/kcap.json), the Kiro confirmation-list line, and KiroHooksInstaller.DeleteMarker to UninstallCommand; update help-uninstall.txt (prose + selective `plugin remove` list, also noting the previously-undocumented Pi extension). `plugin remove --kiro` no-ops cleanly (exit 0) when Kiro was never installed, so the unconditional call is safe — guarded by the existing no-Kiro uninstall tests plus a new positive Kiro-removal test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

Fixed in e2a7033: kcap uninstall now tears down the Kiro integration too — added plugin remove --kiro (restores the previous default agent + deletes ~/.kiro/agents/kcap.json), the Kiro confirmation-list line, and KiroHooksInstaller.DeleteMarker; updated help-uninstall.txt (prose + selective plugin remove --kiro, and noted the previously-undocumented Pi extension). plugin remove --kiro no-ops cleanly (exit 0) when Kiro was never installed — verified by the existing no-Kiro uninstall tests plus a new positive Kiro-removal test. Full suite 1645 pass, no AOT warnings.

🤖 Addressed by Claude Code

@realtonyyoung

Copy link
Copy Markdown
Collaborator Author

Codex review (round 3) — verdict: approve

The round-2 request-changes is resolved. The fix adds Kiro to the uninstall confirmation list, calls plugin remove --kiro unconditionally, deletes the Kiro marker in the belt-and-braces cleanup, and updates help-uninstall.txt prose plus the selective plugin remove list. I traced the Kiro-less path: missing settings returns null, the default-agent restore is skipped unless chat.defaultAgent == "kcap", missing ~/.kiro/agents/kcap.json/marker no-ops, and RemoveKiro returns 0, so this should not break uninstall on machines that never had Kiro. The restore-before-delete retry-safety is intact, uninstall does not require kiro-cli, Kiro failures flow into hadFailures without masking later cleanup, and I saw no new AOT/reflection or dynamic JsonArray risk in the delta. I did not build or run tests per instructions.

— Codex review (round 3, automated)

@realtonyyoung
realtonyyoung merged commit a3962cb into main Jun 22, 2026
5 checks passed
@realtonyyoung
realtonyyoung deleted the tonyyoung/gemini-kcap-status branch June 22, 2026 17:10
realtonyyoung added a commit that referenced this pull request Jun 25, 2026
* Surface OpenCode in `kcap status` hooks line

AI-921 wired OpenCode end-to-end (installer, plugin, hook dispatcher,
import-less live ingest) but left it off the `kcap status` Hooks line and
the `kcap status --help` text — the same vendor-surface gap that hit Gemini
and Kiro before (PR #169). The vendor fully works; it just wasn't reported,
so nothing failed and the miss was invisible to build/tests.

- StatusCommand.BuildHooksStatusLine: add `opencode` param + `OpenCode ✓/✗`
  entry (canonical order, last — like Pi it ships a live-ingest plugin file,
  not shell hooks), detected via
  OpenCodeExtensionInstaller.IsInstalled(OpenCodePaths.KcapPlugin()).
- help-status.txt: Hooks line now reads "Pi / OpenCode live-ingest extensions".
- StatusCommandHooksTests: cover OpenCode in both BuildHooksStatusLine tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* README: list OpenCode in the setup-wizard detection paragraph

The `## CLI commands` setup section enumerated detected agents only through
Pi, omitting SST OpenCode — the quick-start paragraph already lists it, and
CLAUDE.md requires both stay in sync. Mirrors the existing phrasing and notes
that, like Pi, OpenCode has no shell hooks so the wizard installs a live-ingest
plugin. Flagged by PR review on #178.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
realtonyyoung added a commit that referenced this pull request Jun 27, 2026
…20) (#192)

* Surface OpenCode in `kcap status` hooks line

AI-921 wired OpenCode end-to-end (installer, plugin, hook dispatcher,
import-less live ingest) but left it off the `kcap status` Hooks line and
the `kcap status --help` text — the same vendor-surface gap that hit Gemini
and Kiro before (PR #169). The vendor fully works; it just wasn't reported,
so nothing failed and the miss was invisible to build/tests.

- StatusCommand.BuildHooksStatusLine: add `opencode` param + `OpenCode ✓/✗`
  entry (canonical order, last — like Pi it ships a live-ingest plugin file,
  not shell hooks), detected via
  OpenCodeExtensionInstaller.IsInstalled(OpenCodePaths.KcapPlugin()).
- help-status.txt: Hooks line now reads "Pi / OpenCode live-ingest extensions".
- StatusCommandHooksTests: cover OpenCode in both BuildHooksStatusLine tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* README: list OpenCode in the setup-wizard detection paragraph

The `## CLI commands` setup section enumerated detected agents only through
Pi, omitting SST OpenCode — the quick-start paragraph already lists it, and
CLAUDE.md requires both stay in sync. Mirrors the existing phrasing and notes
that, like Pi, OpenCode has no shell hooks so the wizard installs a live-ingest
plugin. Flagged by PR review on #178.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Design spec: kcap import --opencode (historical OpenCode import from SQLite)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Revise OpenCode import spec per Codex design review

- Fix subagent lifecycle order (children before parent session-end)
- Resolve subagent watermark via Gemini import precedent (startLine 0 + idempotency)
- Soften byte-match claim to final-state/normalizer-compatible; document watermark caveat
- Pin part ordering (time_created,id) with empirical validation note
- Move SQLite dependency to CLI project (keep daemon/Core AOT-clean)
- Use /hooks/set-title for native title; ms epoch conversion
- Add edge-cases section; accept shared send-failure behavior (idempotency)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Revise OpenCode import spec per Codex 2nd-pass review (rev3)

- Replace line-number resume with binary New/AlreadyLoaded classification
  (live snapshot vs import final-state line spaces are incompatible)
- Add importable-line predicate (Pi IsImportRelevantLine analog) for MinLines
- Fix synthesis query: order by message chronology, not lexical message_id;
  LEFT JOIN so empty messages aren't dropped
- Strengthen part-ordering pre-merge verification requirements
- Document OpenCode-specific send-failure consequence (summary/model recompute)
- Make parent/child lifecycle sequencing explicit; deterministic child order
- Fix Architecture/Core-vs-CLI contradiction; expand edge cases
  (no-canonical-event messages, grandchildren, mixed live/historical)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Implementation plan: kcap import --opencode (TDD, 10 tasks)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Revise OpenCode import plan per Codex plan review

- Add opt-in strict transcript sender (failOnError) — OpenCode aborts before
  session-end/subagent-stop on batch failure (binary policy has no resume)
- Make IsImportRelevantLine role-aware + hidden-aware to match server normalizer
- Subagent start/stop use the real temp transcript path; stronger ordering test
  (agent_id, agent_type, vendor, full POST order)
- Order-sensitive assertions (string.Join+IsEqualTo) instead of IsEquivalentTo
- Harden AOT gate: explicit RIDs + pipefail, no masked publish failures
- Add WAL-writer read test; null-dir / zero-message / timestamp-magnitude cases
- Cleaner fixture JSON via JsonObject
- Reconcile spec (strict sender, role-aware predicate)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Revise plan+spec per Codex 2nd plan review: completeness-gated repair

Blocker fix: binary AlreadyLoaded couldn't repair a partial multi-batch import
(server HWM advances on transcript ingest, not session-end). Replace with
completeness-gated classification:
- New / AlreadyLoaded(ended) / Partial-repair(watermark, not ended) / TooShort
- repair replays full transcript with line numbers offset above HWM (lineNumberOffset
  param added to SendTranscriptBatches); dedup by canonical prt_ id
- strict sender's role clarified: keeps session not-ended on failure so re-run repairs
- per-subsession gating via ?agentId= (skip if SubagentCompleted, else repair)
- new Task 0: confirm server contract (ended signal, dedup-by-id, HWM filter) + fallback

Also from review: align IsImportRelevantLine with server normalizer (Length>0,
assistant id requirement, tool fields null-checked); AOT gate exit 1 not break;
WAL test asserts sidecars + settles Cache=Private; timestamp seconds test;
tighten subagent test (child transcript between start/stop); repair integration test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Revise plan+spec per Codex 3rd plan review: CLI-side import ledger

Codex confirmed no data-loss blocker remains, but the current server exposes no
ended signal — so the completeness-gated design would run in always-replay mode
(re-send every session each run). Per decision, add a client-side import ledger as
the completeness signal instead:

- OpenCodeImportLedger (Task 4b): per-machine, per-server record of fully-imported
  sessions (keyed by server URL + reconstructed line count), AOT-safe source-gen JSON
- classification: ledger hit -> AlreadyLoaded (skip); else New / Partial-repair
- ledger written only after session-end succeeds; strict sender keeps partials unrecorded
- drop the speculative server ended-signal plumbing (ServerState); Task 0 now confirms
  only dedup-by-id + HWM filter
- children: no per-child gate (complete parent skipped wholesale via ledger)
- tests isolated via fixture LedgerPath; add ledger round-trip, second-run-skip,
  and batch2-failure-then-rerun-repairs (WireMock scenario, 150 lines) tests

Also from review: HasField -> string-kind (server Str parity); checked offset
arithmetic for overflow; fix stale no-watermark-left comment; Task 0 reframed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Task 0 confirmed: kcap-server repair contract verified against source

Verified against kurrent-io/kcap-server@main:
- dedup by canonical EventId (HashGuid of prt_/message id), line-number-independent
- HWM filter drops line_number <= currentHwm before normalization
- last-line returns last_line_number only (no ended field -> ledger is required);
  reads max lineNumber over last 50 events backward (under-report caveat noted)
- HWM + dedup keyed sessionId|agentId; last-line accepts ?agentId=

Repair design inherits the live watcher reconnect-resend idempotency profile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* build: add Microsoft.Data.Sqlite to CLI for OpenCode import

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: OpenCodeDb read-only reader, line reconstruction, importable predicate

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: OpenCode import ledger (client-side completeness record)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: OpenCodeImportSource discovery + ledger-gated classify + import + subagents

Includes opt-in failOnError/lineNumberOffset on SessionImporter.SendTranscriptBatches
(defaulted; peers unchanged). Parent + child import with strict send + repair-above-HWM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: wire --opencode import filter + register OpenCodeImportSource

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test: OpenCode import integration tests (lifecycle, subagents, repair, ledger)

Also fix IL2026/IL3050 in OpenCodeDb: cast to JsonNode so Add(JsonNode?) is chosen
over the AOT-unsafe generic Add<T> (per CLAUDE.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: document kcap import --opencode (help + README)

Corrects the README claim that OpenCode capture is live-only / has no import.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* harden OpenCode import per code review: discovery guard, cancellation, overflow

- DiscoverAsync: guard db open/query so a corrupt/schema-drifted opencode.db warns
  and skips OpenCode instead of crashing the whole import run (other vendors)
- QuerySessions: skip malformed/null rows instead of aborting the scan
- propagate OperationCanceledException out of the import catches (was swallowed as Failed)
- checked() on repair line-number offsets (parent + child)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: ledger keyed by content fingerprint; document server-side limitations

#2: replace the ledger's parent line-count key with a SHA-256 content fingerprint
over the parent transcript + children, so a same-line-count mutation (tool part
completing, in-place edit, changed/added child) invalidates the skip and re-imports.
Fingerprint computed at classify, carried on SourceMeta, recorded after session-end.

Document #1 (server returns 200 on swallowed per-event write failure) and #3
(subagent lifecycle hooks return OK on write failure) as known limitations with
server-repo follow-ups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* review: fix NUL byte in source, propagate cancellation in helpers, cite AI-1023

Codex final pre-merge review (no blockers):
- replace the literal NUL fingerprint separator with a backslash-u0000 escape so
  the .cs file is text (rg/tools no longer treat it as binary); runtime unchanged
- rethrow OperationCanceledException in the watermark-probe and PostHookAsync
  catches so cancellation is not masked as ProbeError/hook-failure
- name AI-1023 in the spec server-side limitation notes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant