Skip to content

[AI-886] Add Pi (badlogic/pi-mono) CLI vendor support#162

Merged
realtonyyoung merged 15 commits into
mainfrom
tonyyoung/ai-886-pi-coding-vendor
Jun 18, 2026
Merged

[AI-886] Add Pi (badlogic/pi-mono) CLI vendor support#162
realtonyyoung merged 15 commits into
mainfrom
tonyyoung/ai-886-pi-coding-vendor

Conversation

@realtonyyoung

Copy link
Copy Markdown
Contributor

Linear: AI-886

Adds Pi (badlogic/pi-mono, the pi CLI) as a CLI ingest vendor. Pi has no shell hooks, so live capture ships as a Pi TypeScript extension rather than a hooks file.

Changes

  • Core: PiPaths (the ~/.pi/agent layout) and PiExtensionInstaller, which embeds kcap.ts and writes it to ~/.pi/agent/extensions/ (version-markered, like the Copilot installer).
  • Live: kcap hook --pi (PiHookCommand) reads the session JSONL header for the id, POSTs /hooks/session-{start,end}/pi (repo/PR-enriched), and spawns the existing detached watcher with vendor=pi. The shipped kcap.ts extension calls it from pi.on("session_start"/"session_shutdown").
  • Batch: kcap import --pi (PiImportSource) walks ~/.pi/agent/sessions/**/*.jsonl, sharing the import classify/watermark machinery.
  • Wired --pi into VendorSelection, the import source list, the hook dispatcher, kcap plugin install/remove --pi, and kcap setup auto-detection (--skip-pi-hooks).
  • Tests: PiImportSourceTests + PiExtensionInstallerTests (20 pass). README updated.

Builds + AOT-publishes clean (0 IL warnings).

Server-side ingest is in the kurrent-io/kcap-server PR on the same branch.

🤖 Generated with Claude Code

Pi has no shell hooks, so live capture ships as a Pi TypeScript extension (kcap.ts) that invokes 'kcap hook --pi' on session_start/shutdown; batch import via 'kcap import --pi'. New: PiPaths + PiExtensionInstaller (embeds kcap.ts) in Core, PiImportSource + PiHookCommand in the CLI. Wired --pi into VendorSelection, the import source list, the hook dispatch, plugin install/remove, and 'kcap setup' auto-detection (--skip-pi-hooks). Unit tests: PiImportSourceTests, PiExtensionInstallerTests. README updated. Builds + AOT-publishes clean (0 IL warnings); 20 Pi unit tests pass.

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

linear-code Bot commented Jun 17, 2026

Copy link
Copy Markdown

AI-886

@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 →

Comment thread src/Capacitor.Cli/Commands/PiHookCommand.cs Outdated
Comment thread src/Capacitor.Cli/Commands/PiHookCommand.cs
…allow pi in parent-exit fallback

PR #162 review fixes. (1) PiHookCommand derived the session id from the header or the whole filename stem, but Pi hands the session file over before the header line is flushed and names files <timestamp>_<uuid>.jsonl — so a not-yet-flushed session_start derived a non-uuid id and dropped the session + watcher. ExtractSessionId now prefers the header uuid and falls back to the filename's uuid suffix. (2) WatchCommand.PostSessionEndOnParentExitAsync gated on {claude,codex,copilot}; added 'pi' so a crashed/closed Pi watcher posts /hooks/session-end/pi on parent exit instead of leaving the session active. Tests: PiHookCommandTests (ExtractSessionId) + a Pi case in WatcherParentExitPostTests. Builds + AOT-clean (0 IL); 24 unit + 5 parent-exit tests pass.

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

Copy link
Copy Markdown
Contributor Author

New re-review note:

src/Capacitor.Cli/Commands/WatchCommand.cs still needs Pi-aware title/event helpers now that PiHookCommand starts the watcher with vendor: "pi". The transcript upload itself still works after the raw-line threshold, but the watcher title path falls through to the Claude JSONL shape: TryExtractUserText(..., "pi"), TryExtractAssistantText(..., "pi"), and IsEvent(..., "pi") all read top-level type: "user"|"assistant", while Pi emits type: "message" with message.role: "user"|"assistant". That means live Pi sessions never get the initial title or LLM title path, even though historical Pi import opts into title generation. Please add Pi-specific extractor/event branches mirroring the server normalizer user/assistant mapping, plus watcher helper tests for Pi lines.

…tled

PR #162 re-review: WatchCommand's title helpers read the Claude JSONL shape (top-level type:user/assistant), so live Pi sessions — which emit type:"message" with message.role — fell through and never got the initial or LLM title (historical import already opts into titles). Added Pi branches to TryExtractUserText / TryExtractAssistantText / IsEvent mirroring the server PiTranscriptNormalizer user/assistant mapping (string or text-block content). Adds PiTitleHelperTests covering user/assistant extraction + the IsEvent message-role threshold.

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

Copy link
Copy Markdown
Contributor Author

Addressed in 4186407 — added Pi-aware branches to WatchCommand.TryExtractUserText / TryExtractAssistantText / IsEvent. They handle Pi's type:"message" + message.role (string or text-block content), mirroring the server PiTranscriptNormalizer user/assistant mapping, so live Pi sessions now reach the initial + LLM title path (matching historical import). Added PiTitleHelperTests covering user/assistant extraction and the IsEvent message-role threshold. CLI builds + AOT-clean (0 IL warnings); 35 Pi unit tests pass.

Comment thread src/Capacitor.Cli/Commands/WatchCommand.cs Outdated
… role

PR #162 re-review: the Pi IsEvent branch counted any type:"message" with role user/assistant toward the title-event threshold, but empty envelopes produce no canonical event (server NormalizeUser returns null for empty content, NormalizeAssistant for zero parts; IsImportRelevantLine requires HasContent). A live Pi session could thus hit the 5-event threshold on contentless lines. Gated on content via PiUserHasContent / PiAssistantHasContent (mirroring the normalizer: user = non-empty string or a text block; assistant = a text/thinking/toolCall part). Added empty-user/assistant false-cases + a tool-only-assistant true-case to PiTitleHelperTests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/Capacitor.Cli/Commands/PiImportSource.cs Outdated
…her IsEvent

PR #162 re-review: PiImportSource.IsImportRelevantLine's user/assistant check (HasContent = any non-empty content array) was broader than the server PiTranscriptNormalizer — which only emits for thinking/text/toolCall blocks (assistant) or text (user). An assistant array of only unsupported blocks (e.g. images) was treated as import-relevant, so a complete session re-classified as Partial forever. Extracted the predicate to Capacitor.Cli.Core.Pi.PiContent (HasUserContent / HasAssistantContent) mirroring the normalizer, and used it from BOTH IsImportRelevantLine and WatchCommand.IsEvent (replacing the duplicated WatchCommand helpers) so the two can't drift from the normalizer or each other. Added assistant-unsupported-block / empty-user import-relevance cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/Capacitor.Cli.Core/Pi/PiContent.cs
…espace extension lookup)

PR #162 review: PiContent (Capacitor.Cli.Core.Pi) calls the Str/Arr JsonElement extension members declared in the parent namespace Capacitor.Cli.Core. It already builds via enclosing-namespace extension-method resolution (the 45 Pi unit tests + AOT publish exercise it through PiImportSource), but added an explicit `using Capacitor.Cli.Core;` so it no longer relies on that and stays correct if the file ever moves. Clean -t:Rebuild of the CLI is green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/Capacitor.Cli/Commands/VendorSelection.cs Outdated
…guards)

PR #162 review: VendorSelection added --pi to KnownVendorFlags but the unknown-vendor-prefixed guards only matched --cursor-/--claude-/--codex-/--copilot-, so a --pi-<x> typo or future option wasn't rejected — and if it was >2 edit distance from --pi it fell through silently, leaving Vendors empty (= import everything). Added --pi- to both guard expressions (the rejection loop and the typo-detection skip). Tests: --pi selects only pi; --pi-session is rejected as an unknown source option.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread README.md Outdated
Comment thread src/Capacitor.Cli/Commands/PiImportSource.cs Outdated
Comment thread src/Capacitor.Cli/Program.cs
Comment thread src/Capacitor.Cli/Commands/PluginCommand.cs Outdated
@realtonyyoung

Copy link
Copy Markdown
Contributor Author

New full-pass finding:

kcap plugin install/remove --pi is wired, but the existing lifecycle-management callers were not updated for the new extension. src/Capacitor.Cli/Commands/UninstallCommand.cs removes Claude, Codex, Cursor, Copilot, and skills, but never calls PluginCommand.HandleAsync(["plugin", "remove", "--pi"]), so kcap uninstall can leave ~/.pi/agent/extensions/kcap.ts auto-loading after the user removed kcap. Likewise npm/kcap/bin/refresh.js refreshes skills/Codex/Cursor/Copilot/Claude with --if-installed, but never runs plugin install --pi --if-installed, so an opted-in Pi extension will not be refreshed by npm postinstall or kcap update. Please add Pi to both cleanup and refresh paths, plus tests covering uninstall invoking --pi and refresh including the Pi command.

…trings

Address review on kcap-cli#162:

- PiImportSource discovery now reuses PiHookCommand.ExtractSessionId to
  validate the session id the same way the live hook path does. A
  corrupt/non-GUID `{"type":"session"}` header no longer mints an
  arbitrary non-GUID session id; it also gains the live path's filename
  fallback ("<timestamp>_<uuid>.jsonl") for an unflushed header. Two new
  discovery tests cover both (skip non-GUID header, recover from filename).
- `kcap watch` usage: --vendor list now includes `pi` (matches
  WatchCommand.KnownVendors).
- `kcap plugin` PrintUsage: now lists all current targets
  (--codex|--cursor|--copilot|--pi|--skills); previously omitted both
  --copilot and --pi.
- CLI README: plugin quick-reference and import-filter sentence now
  mention --pi.

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

Copy link
Copy Markdown
Contributor Author

New broader-pass finding: the embedded CLI help resources were not updated with the new Pi surface, even though some direct usage strings and the root README were.

Concrete stale spots at 40feae0:

  • src/Capacitor.Cli.Core/Resources/help-import.txt still says import discovers Claude/Codex/Cursor/Copilot, says kcap walks all four, and lists vendor filters only through --copilot.
  • src/Capacitor.Cli.Core/Resources/help-plugin.txt has no --pi option, no Pi install/remove notes, and no kcap plugin install --pi / remove --pi examples.
  • src/Capacitor.Cli.Core/Resources/help-setup.txt omits --skip-pi-hooks, omits Pi from the detected-agent description, and its post-setup install example lists only --codex, --cursor, and --copilot.
  • src/Capacitor.Cli.Core/Resources/help-hook.txt still documents only stdin JSON hook dispatch and only --claude|--codex|--cursor|--copilot, but Pi is arg-driven and now supported via kcap hook --pi --event ... --file ....

These back kcap <command> --help, so users relying on CLI help will not discover the Pi integration or its skip/install/import flags. Please update the embedded help resources and add/update help-output snapshot tests if the project has them.

@realtonyyoung

Copy link
Copy Markdown
Contributor Author

New routed-import finding: PiImportSource.SupportsTitleGeneration returns true, but Pi sessions never actually reach the import title-generation path.

Pi classifications set FilePath = "", so they go through the routed-source phase (src.ImportSessionAsync) instead of ImportChainsAsync. The only place that queues GenerateTitleForImportAsync is the chain worker OnTitleTaskReady callback; the routed phase only calls src.ImportSessionAsync, updates counts, and never schedules title/background work. Even if a Pi title task were queued, GenerateTitleForImportAsync currently only special-cases vendor == "codex"; every other vendor uses the Claude-shaped TitleGenerator.ExtractTitleContext, which looks for top-level type:"user"/"assistant" and would skip Pi type:"message" + message.role lines.

Net effect: historical kcap import --pi advertises/supports title generation in the source contract, but imported Pi sessions will not get LLM-generated titles from the import pipeline. Please either set SupportsTitleGeneration = false and document that the server fallback title is the intended behavior, or add a routed-source title hook plus a Pi-shaped title extractor/tests so --pi imports match live Pi title behavior.

@realtonyyoung

Copy link
Copy Markdown
Contributor Author

New setup UX finding: the end-of-setup restart reminder is still Claude-specific after adding Pi to the setup flow.

CodingAgentsStep can now install only the Pi extension, and AnyHooksInstalled correctly includes PiExtensionInstalled, so SetupCommand.LiveRecordingRestartTip will run for that case. But the text still says Restart your agent (or run claude --continue), which is misleading for Pi, Cursor, and Copilot installs, and especially odd when the only installed integration was Pi. Please make the reminder generic or build it from the installed agents; for Pi it should tell users to restart Pi so the extension is loaded, matching the per-agent note printed during the Pi install step.

@realtonyyoung

Copy link
Copy Markdown
Contributor Author

Additional docs/help drift from the exhaustive sweep, separate from the command-specific help resources already noted:

The root README still has several old “four agents” / Claude-Codex-only sections after the targeted edits: the npm install-script warning and manual refresh command omit --pi; setup step 4 omits Pi; the restart note still suggests only claude --continue; the “Need at least one agent” / “What it records” / import prose still describes only the older agent set in places; and the upgrade/uninstall/finer-grained removal sections omit the Pi extension. npm/kcap/README.md is also still Claude-only, and help-usage.txt still advertises import/plugin/hook support without Pi (and plugin help there is missing Cursor/Copilot/skills too).

Please do one docs sweep across the root README, npm package README, and help-usage.txt so the published/package help matches the new Pi support and the existing Cursor/Copilot surfaces.

@realtonyyoung

Copy link
Copy Markdown
Contributor Author

kcap status still only reports Claude and Codex hook state, so a user who installs the new Pi extension has no status feedback that Pi recording is installed. StatusCommand.HandleAsync builds the Hooks line from only IsClaudePluginInstalled(ClaudePaths.UserSettings) and IsCodexHooksInstalled(CodexPaths.UserHooksJson), and help-status.txt documents the same older two-agent view. Please extend status/help to include the new Pi extension state (and ideally the already-supported Cursor/Copilot states too) so setup/plugin install can be verified from kcap status.

@realtonyyoung

Copy link
Copy Markdown
Contributor Author

Coverage gap worth closing before this lands: the new Pi support has helper-level tests (PiExtensionInstallerTests, discovery/import-relevance in PiImportSourceTests, and Pi title parsing), but I could not find tests that exercise the user-facing Pi branches. In particular, PluginCommand.HandleAsync(["plugin", "install", "--pi" ...]) / remove --pi / --if-installed, CodingAgentsStep setup/no-prompt behavior for detected Pi, and PiImportSource.ClassifyAsync + ImportSessionAsync posting /hooks/session-start/pi, the transcript payload with vendor pi, and /hooks/session-end/pi appear uncovered. Those are the integration points most likely to drift from the lower-level helpers, so please add focused tests around the command/routed-import flows rather than only the file writer and line parser.

…t, generic setup tip, update help

Address the broader-pass review on kcap-cli#162:

- Lifecycle callers: `kcap uninstall` now removes the Pi extension
  (`plugin remove --pi`) and refresh.js refreshes it (`plugin install
  --pi --if-installed`), so uninstall no longer leaves
  ~/.pi/agent/extensions/kcap.ts auto-loading and npm postinstall /
  `kcap update` refresh an opted-in Pi extension. InstallPi already
  honours --if-installed (no-op unless previously installed), so the
  refresh never force-installs Pi onto non-Pi users.

- PiImportSource.SupportsTitleGeneration => false. Pi is a routed source
  (FilePath=""), so it never reaches the chain title worker, and the
  import title path is Claude-shaped anyway. Imported Pi sessions get the
  server-side fallback title (PiHookHandlers), matching Copilot/Cursor;
  live Pi still gets an LLM title via the watcher. Advertising true was a
  no-op contract lie.

- Setup restart reminder is now built from the installed agents instead
  of always naming Claude: Pi-only -> "restart pi so the kcap extension
  loads"; Claude keeps --continue; others get a generic restart.

- Embedded help resources updated for the Pi surface: help-import,
  help-plugin, help-setup (--skip-pi-hooks), help-hook (arg-driven Pi
  dispatch), help-usage.

Tests: PluginCommandPiTests (install --if-installed no-op / refresh /
remove), uninstall removes Pi extension, Pi-only restart tip, import does
not support title generation. 1573/1573 unit pass; AOT-clean.

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

Copy link
Copy Markdown
Contributor Author

All four broader-pass findings addressed in 79dbf7a:

Lifecycle callers (uninstall + refresh). UninstallCommand now calls plugin remove --pi (and prints the ~/.pi/agent/extensions/kcap.ts removal line), and refresh.js now runs ["plugin","install","--pi","--if-installed"]. InstallPi already honours --if-installed (no-ops unless a marker/extension is present), so the npm postinstall / kcap update refresh path never force-installs Pi onto users who never opted in. Tests: PluginCommandPiTests (--if-installed no-op when not installed, refresh-in-place, remove deletes extension+marker) and UninstallCommandTests.User_level_uninstall_removes_pi_extension (removes kcap.ts + marker, preserves a user-authored sibling extension).

Routed-import title contract. Set PiImportSource.SupportsTitleGeneration => false. You're right that a routed source (FilePath="") never reaches the chain worker's OnTitleTaskReady, and GenerateTitleForImportAsync is Claude-shaped anyway — so I took option 1: imported Pi sessions get the server-side fallback title from PiHookHandlers (matching Copilot/Cursor), while live Pi still gets an LLM title via the watcher's Pi-aware extractors. Updated the docstring to say so; added does_not_support_title_generation.

Setup restart reminder. LiveRecordingRestartTip now builds the hint from the installed agents: Claude keeps claude --continue; a Pi-only install reads "Restart pi so the kcap extension loads"; anything else gets a generic "Restart your agent". Added LiveRecordingRestartTip_pi_only_tells_user_to_restart_pi (asserts it mentions pi and not claude --continue).

Embedded help resources. Updated help-import.txt (Pi in the agent list, transcript path, --pi filter, "all five"), help-plugin.txt (--pi option + notes + examples), help-setup.txt (--skip-pi-hooks, Pi detection, install example), help-hook.txt (arg-driven Pi dispatch, since Pi has no stdin payload), and also help-usage.txt (top-level import line + hook list) which had the same gap.

No JS test harness exists in the repo (no *.test.js, no package.json test script), so the refresh.js change is covered indirectly via the C# InstallPi --if-installed no-op test rather than a new JS suite.

1573/1573 unit tests pass; AOT publish clean (0 IL warnings).

…ration tests

Address the status + coverage-gap review on kcap-cli#162:

- `kcap status` now reports per-agent integration state for all five
  agents (Claude, Codex, Cursor, Copilot, Pi) instead of only
  Claude+Codex, so a Pi extension install is verifiable from status. The
  Hooks-line formatting is extracted into the pure, testable
  StatusCommand.BuildHooksStatusLine; help-status.txt updated.

- Close the user-facing Pi coverage gap (the helpers had tests, the
  command/routed-import branches did not):
  * CodingAgentsStepTests: Pi detected/accepted, declined, not-detected,
    skipped-by-flag, --no-prompt auto-install, kcap-not-on-PATH abort,
    installer-failure warning (mirrors the Copilot/Cursor coverage).
  * PiImportSourceImportTests (integration, WireMock): full
    discover -> classify -> import asserting the wire contract —
    POST /hooks/session-start/pi, the transcript batch tagged vendor=pi,
    POST /hooks/session-end/pi (reason pi-import), plus the
    Partial/resume-from-watermark path.

(The `plugin install/remove --pi --if-installed` branches were covered in
the prior commit's PluginCommandPiTests.)

1582/1582 unit + 2 new integration tests pass; AOT-clean (0 IL).

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

Copy link
Copy Markdown
Contributor Author

Both addressed in d61719d:

kcap status now reports Pi. The Hooks line was Claude+Codex only; it now reports all five agents — Claude ✓ Codex ✗ Cursor ✗ Copilot ✗ Pi ✓ — using the existing per-agent detectors (CursorHooksInstaller.IsInstalled, CopilotHooksInstaller.IsInstalled, PiExtensionInstaller.IsInstalled). I extracted the line formatting into a pure StatusCommand.BuildHooksStatusLine(...) so it's unit-testable without the HTTP/daemon/global-state in HandleAsync, and added two tests for it. help-status.txt updated to describe the per-agent state.

Command + routed-import coverage gap closed. Added the user-facing branch tests that were missing:

  • CodingAgentsStepTests — Pi detected/accepted, declined, not-detected, skipped-by-flag, --no-prompt auto-install, kcap-not-on-PATH abort, and installer-failure warning. Mirrors the Copilot/Cursor branch coverage.
  • PiImportSourceImportTests (integration, WireMock) — drives the full DiscoverAsync → ClassifyAsync → ImportSessionAsync path and asserts the wire contract: POST /hooks/session-start/pi, then the transcript batch carrying "vendor":"pi", then POST /hooks/session-end/pi with reason: pi-import — in receipt order. A second case covers the Partial/resume-from-watermark path (server reports last_line_number: 0 → resume from line 1 → Resumed).
  • The plugin install/remove --pi / --if-installed branches you noted were covered by PluginCommandPiTests in 79dbf7a.

1582/1582 unit + 2 new integration tests pass; AOT publish clean.

The server PiTranscriptNormalizer now maps `compaction` → ContextCompacted
(AI-892), so a compaction line advances the canonical $lineNumber
watermark. Keep PiImportSource.IsImportRelevantLine in sync: `compaction`
now returns true (was in the skip set). Flips the matching
is_import_relevant_line_matches_normalizer case.

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

Copy link
Copy Markdown
Contributor Author

Remaining docs/help drift on the current head after the Pi follow-ups:

  • src/Capacitor.Cli.Core/Resources/help-usage.txt updated import + hooks for Pi, but the top-level Plugin section still advertises only plugin install/remove [--project] [--codex] and says “Claude or --codex for Codex”. Since this is what kcap --help shows, users discovering integrations there still cannot see --cursor, --copilot, --pi, or --skills. Please broaden those two lines to match help-plugin.txt.
  • README.md still has several older-agent passages despite nearby Pi edits: the install-script warning/manual refresh list omits --pi, setup step 4 omits Pi detection, the historical import section still says “All four agents” and omits the Pi session root, the upgrade paragraph omits Cursor/Copilot/Pi refresh targets, and uninstall/finer-grained removal still omits Copilot/Pi.
  • npm/kcap/README.md is still Claude-only (“records and visualizes Claude Code sessions”, setup walks through Claude plugin installation) even though the package now installs/refreshes multi-agent integrations including Pi.

This is user-visible packaging/help text, so it is worth one final docs sweep before merging; otherwise the shipped CLI/npm docs understate the new Pi support and some already-supported Cursor/Copilot paths.

realtonyyoung and others added 2 commits June 17, 2026 21:51
…oding-vendor

# Conflicts:
#	src/Capacitor.Cli/Commands/PluginCommand.cs
Address the docs-drift review on kcap-cli#162:

- README.md: postinstall refresh list, manual `--if-installed` example,
  setup step 4 detection, both import backfill source lists ("all four" →
  "all five" + ~/.pi root), uninstall coverage (+ Copilot, + Pi extension),
  and the `plugin remove` flag list now all include Pi (and the
  already-supported Cursor/Copilot where they were missing).
- npm/kcap/README.md: no longer Claude-only — describes multi-agent
  recording (Claude/Codex/Cursor/Copilot/Pi) and setup's per-agent
  integration step.

(help-usage.txt's Plugin section was already broadened to
--cursor|--copilot|--pi|--skills in the origin/main merge, 38c6046.)

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

Copy link
Copy Markdown
Contributor Author

Done in 9674e84 (the help-usage Plugin lines were already broadened in the origin/main merge 38c6046):

  • help-usage.txt Plugin section — now plugin install/remove [--project] [--codex|--cursor|--copilot|--pi|--skills] with "Register/Remove hooks/skills (Claude default; flag picks the vendor)" (landed via the [AI-815] Surface --cursor/--copilot in kcap --help Plugin section #163 merge + the --pi add).
  • README.md — postinstall refresh list, the manual --if-installed example, setup step 4 detection, both import backfill source lists ("all four" → "all five" + ~/.pi/agent/sessions/), the uninstall coverage paragraph (+ Copilot hooks, + the Pi kcap.ts extension), and the plugin remove finer-grained-cleanup flags now all include Pi (and the Cursor/Copilot paths that were missing).
  • npm/kcap/README.md — no longer Claude-only: the tagline and setup step now describe multi-agent recording across Claude/Codex/Cursor/Copilot/Pi.

Verified no residual all four / Claude-only / --pi-less plugin lists remain in either README.

…oding-vendor

# Conflicts:
#	README.md
#	src/Capacitor.Cli.Core/Resources/help-hook.txt
#	src/Capacitor.Cli.Core/Resources/help-import.txt
#	src/Capacitor.Cli.Core/Resources/help-plugin.txt
#	src/Capacitor.Cli.Core/Resources/help-setup.txt
#	src/Capacitor.Cli.Core/Resources/help-usage.txt
#	src/Capacitor.Cli/Commands/CodingAgentsStep.cs
#	src/Capacitor.Cli/Commands/PluginCommand.cs
#	src/Capacitor.Cli/Commands/PluginEnvironment.cs
#	src/Capacitor.Cli/Commands/SetupCommand.cs
#	src/Capacitor.Cli/Commands/UninstallCommand.cs
#	src/Capacitor.Cli/Commands/VendorSelection.cs
#	src/Capacitor.Cli/Commands/WatchCommand.cs
#	src/Capacitor.Cli/Program.cs
#	test/Capacitor.Cli.Tests.Unit/CodingAgentsStepTests.cs
Re-merge after #168 (AI-897 Copilot session.shutdown tail) landed on main.
Only conflict was help-usage.txt's plugin flag list — kept the superset
(--gemini AND --pi). Program.cs auto-merged (Pi + Gemini hook routing intact).
@realtonyyoung realtonyyoung merged commit 15f1670 into main Jun 18, 2026
5 checks passed
@realtonyyoung realtonyyoung deleted the tonyyoung/ai-886-pi-coding-vendor branch June 18, 2026 03:24
@realtonyyoung

Copy link
Copy Markdown
Contributor Author

Fresh re-review findings on current head (7daa29b), after the Gemini/main merge:

  • kcap status now says it renders every supported agent, but the merged branch supports Gemini and StatusCommand.BuildHooksStatusLine still only accepts/prints Claude, Codex, Cursor, Copilot, and Pi. help-status.txt has the same omission. A user who installs kcap plugin install --gemini cannot verify it from kcap status, while all the other current vendors can. Please add Gemini to the status detector/line/helper tests (using GeminiHooksInstaller.IsInstalled(GeminiPaths.SettingsJson())) and update the help text from “Codex / Cursor / Copilot hooks, and Pi...” to include Gemini hooks.
  • npm/kcap/bin/refresh.js still does not run plugin install --gemini --if-installed, even though this branch’s README says npm postinstall / kcap update refreshes Claude/Codex/Cursor/Copilot/Gemini/Pi. That means opted-in Gemini users keep stale ~/.gemini/settings.json hook command strings after upgrade, while the docs promise refresh. Please add the Gemini refresh entry and update the header comment accordingly.
  • src/Capacitor.Cli.Core/Resources/help-uninstall.txt mentions Pi only in the finer-grained plugin remove [...] note, but the main description still says uninstall removes Claude/Codex/Cursor/Gemini hooks, Copilot hooks, skills, and config. Since UninstallCommand now also removes ~/.pi/agent/extensions/kcap.ts, the command-specific help should say that in the primary removal list too.
  • npm/kcap/README.md was updated from Claude-only to multi-agent, but it lists Claude/Codex/Cursor/Copilot/Pi and still omits Gemini in both the tagline and setup sentence. Since the current package includes Gemini hooks/import/setup, please include Gemini there as well.

@realtonyyoung

Copy link
Copy Markdown
Contributor Author

New functional finding from the latest re-review:

GeminiHookCommand.EnsureWatcher starts the shared watcher with vendor: "gemini" and only skips titles on source resume/clear, so a fresh live Gemini session is expected to use the watcher title path. But WatchCommand has no Gemini branches in TryExtractUserText, TryExtractAssistantText, or IsEvent: it handles Codex/Copilot/Pi specially, then falls back to the Claude shape. Gemini transcript lines are shaped like {"type":"user","content":[{"text":"..."}]} and {"type":"gemini","content":"..."} (as used by GeminiImportSource.IsImportRelevantLine), while the Claude fallback looks for user text under message.content and only counts type:"user"|"assistant" events.

Net effect: live Gemini sessions still stream transcript lines, but they never capture FirstUserText, never send the initial title, and never reach the LLM title threshold because assistant turns are type:"gemini", not type:"assistant". Please add Gemini-specific watcher title/event helpers mirroring the Gemini normalizer/import predicate (skip <session_context> user bootstrap and use type:"gemini" as assistant context), plus WatchCommand tests for Gemini user/gemini lines.

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