Skip to content

[AI-888] AWS Kiro CLI ingest (hooks, JSONL watcher, import, transparent live install)#165

Merged
realtonyyoung merged 12 commits into
mainfrom
tonyyoung/ai-888-aws-kiro-cli-session-ingest
Jun 18, 2026
Merged

[AI-888] AWS Kiro CLI ingest (hooks, JSONL watcher, import, transparent live install)#165
realtonyyoung merged 12 commits into
mainfrom
tonyyoung/ai-888-aws-kiro-cli-session-ingest

Conversation

@realtonyyoung

@realtonyyoung realtonyyoung commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

What

Phase 2 (CLI) for AWS Kiro CLI ingest — the fifth vendor (kiro). Pairs with the server side, kcap-server#760.

Linear: AI-888

What Kiro needs that's new

Kiro CLI (AWS's terminal coding agent; a bun/TUI rewrite, not the older Rust Amazon Q Developer CLI) writes an append-only JSONL log per session — ~/.kiro/sessions/cli/{id}.jsonl (one {version, kind, data} object per line; honours KIRO_HOME), with a sibling {id}.json for cwd/title/timestamps/model. So it tails like the other file-vendors; what's actually new is the lifecycle: there's no session-start line in the log, so start metadata comes from Kiro's agentSpawn hook (fires every prompt → deduped server-side), and Kiro has no session-end trigger, so the watcher synthesizes it on kiro-cli exit. (Kiro also writes a data.sqlite3, but the JSONL is written for every session, so kcap ignores the DB.)

Changes

  • kcap hook --kiro (KiroHookCommand) — agentSpawn dispatcher: POSTs /hooks/session-start/kiro (enriched with the model read from the sibling {id}.json), ensures the watcher, always exits 0 with empty stdout (a stdout-writing Kiro hook re-injects and loops the agent). agentSpawn-only — it carries the session id and fires every prompt, covering session start + idempotent watcher liveness.
  • JSONL watcher — the watcher tails ~/.kiro/sessions/cli/{id}.jsonl directly through the existing file-tail drain (WatchCommand), streaming its lines to /hooks/transcript?vendor=kiro — so all the title/threshold/resume/parent-exit machinery is reused unchanged, with no DB read, copy step, or flatten. Session-end is synthesized via the existing parent-exit path (now that kiro is in KnownVendors).
  • kcap import --kiro (KiroImportSource) — walks ~/.kiro/sessions/cli, replaying historical sessions through session-start → transcript → session-end. Idempotent (deterministic server-side event ids).
  • Installer + setupkcap plugin install/remove --kiro writes ~/.kiro/agents/kcap.json; the setup wizard detects Kiro (~/.kiro/ or kiro/kiro-cli on PATH) and offers install. --skip-kiro-hooks opts out.
  • Wiring--kiro in VendorSelection, Program.cs hook/import dispatch + KCAP_SKIP, watcher KnownVendors + Kiro title extractors.

No new dependencies

Kiro is pure JSONL tailing, so it reuses the existing file-tail watcher/drain — no Microsoft.Data.Sqlite or other native dependency was added, and nothing new to vet under NativeAOT publish.

Tests

  • 21 new unit tests across KiroHooksTests, KiroImportSourceTests, KiroSettingsTests, and KiroUsageTests, plus the Kiro setup branch of CodingAgentsStepTests. Full unit suite green (the one unrelated GetCodingAgentPid flake passes in isolation).
  • 1 new integration test: WatcherParentExitPostTests.ParentExit_PostsToVendorSpecificRoute_ForKiro — the synthesized session-end routes to /hooks/session-end/kiro.
  • Docs: README.md + help-{hook,import,plugin,setup}.txt updated.

Notes / follow-ups

  • The ~/.kiro/agents/kcap.json owned-agent model assumes Kiro applies agents/*.json hooks globally; final confirmation belongs to a manual E2E against a live kiro-cli (the JSONL line schema is officially undocumented — kirodotdev/Kiro #5094 — so it's treated as version-fragile/fail-open throughout).
  • Kiro persists no token counts, so Kiro sessions show no token usage by design.

🤖 Generated with Claude Code

Phase 2 (CLI) for AWS Kiro CLI ingest — the fifth vendor, matching the
server side (kcap-server #760).

- `kcap hook --kiro`: agentSpawn dispatcher (KiroHookCommand). Posts
  /hooks/session-start/kiro and ensures the watcher; always exits 0 with
  empty stdout (a stdout-writing Kiro hook loops the agent). agentSpawn-only
  — its session-id-bearing payload covers session start + idempotent watcher
  liveness; the watcher synthesizes session-end on kiro-cli exit (Kiro has no
  session-end hook).
- SQLite-reading watcher: KiroTranscriptReader opens data.sqlite3 copy-first,
  read-only (WAL-aware), reads conversations_v2 (legacy conversations
  fallback), and flattens history[] into the per-turn JSONL the server
  normalizer consumes. WatchCommand materializes it to a kcap-owned file that
  the shared file-tail drain streams — reusing title/threshold/resume/
  parent-exit machinery unchanged.
- `kcap import --kiro`: KiroImportSource (IImportSource) discovers + classifies
  + replays conversations through session-start -> transcript -> session-end.
- Installer: `kcap plugin install/remove --kiro` writes ~/.kiro/agents/kcap.json;
  setup wizard detects Kiro (~/.kiro or kiro/kiro-cli on PATH) and offers install.
- Wiring: --kiro in VendorSelection, Program.cs hook/import dispatch + KCAP_SKIP,
  WatchCommand KnownVendors + Kiro title extractors.

New dependency: Microsoft.Data.Sqlite (10.0.7) — verified clean under NativeAOT
publish (no IL2026/IL3050). Tests: 18 new unit (KiroHooks, KiroTranscriptReader
incl. SQLite round-trip, CodingAgentsStep, VendorSelection) + 1 integration
(parent-exit session-end -> /hooks/session-end/kiro), all green; docs (README +
help-{hook,import,plugin,setup}.txt) updated.

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

linear-code Bot commented Jun 17, 2026

Copy link
Copy Markdown

AI-888

@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 and others added 4 commits June 17, 2026 16:49
The shipped Kiro CLI ingest targeted the Amazon-Q-era SQLite (conversations_v2)
reverse-engineered from frozen source. The actual current kiro-cli (bun/TUI)
writes a per-session append-only JSONL log at ~/.kiro/sessions/cli/{id}.jsonl
(sibling {id}.json holds cwd/model/title) — confirmed against a real session — so
this drops SQLite entirely and tails the JSONL like every other vendor.

- Delete KiroTranscriptReader (SQLite copy-first reader + materializer) and the
  Microsoft.Data.Sqlite dependency. The watcher now tails the real .jsonl; no
  native-lib bundling, no AOT-Sqlite risk.
- KiroPaths: SessionsDir / SessionJsonl / SessionJson (drop the DB paths).
- KiroHookCommand: transcriptPath = the real .jsonl; read model from the sibling
  {id}.json and forward it on the agentSpawn payload (the JSONL lines carry none).
- KiroImportSource: walk ~/.kiro/sessions/cli/*.jsonl (mirrors CopilotImportSource),
  read {id}.json for cwd/model/title, forward the title via /hooks/set-title.
- WatchCommand: title extractors + IsEvent parse the real {version,kind,data} lines.
- Tests: KiroImportSourceTests (discovery + relevance) replaces the deleted SQLite
  reader tests; KiroHooks/CodingAgentsStep/VendorSelection unchanged. 13 Kiro unit
  green; full build + NativeAOT publish clean (no IL2026/IL3050). README +
  help-import updated.

Pairs with the server-side normalizer rewrite (kcap-server #760).
Kiro records no token counts, but each user_turn_metadatas[] entry in the
session's {id}.json carries billing credits (metering_usage[]) and an end-of-turn
context_usage_percentage. That metadata isn't in the JSONL the server sees, so the
CLI reads it and injects it onto the transcript.

- KiroUsage.AnchorMap(): {id}.json -> (turn's final message_id) -> {credits, ctx%}.
- KiroUsage.EnrichLine(): adds data._kcap_usage to the matching AssistantMessage line.
- KiroImportSource: when usage exists, sends an enriched copy (same lines/order/
  numbers, _kcap_usage added on anchor lines); else sends the file as-is.
- 6 KiroUsage unit tests; AOT publish clean.

Server side (kcap-server #760) lifts _kcap_usage onto extensions.kiro on the turn's
final AssistantTextGenerated. Import-only; the live path needs Kiro's per-turn
'stop' hook (deferred). Token $usage still pending real non-auto-model data.
…RO_SESSION_ID

Kiro hooks fire only for the ACTIVE agent (there is no global hook), so
`plugin install --kiro` now clones the user's current default agent
(preserving its tools — a minimal agent loses tool access), injects the
agentSpawn hook, and makes it the default (chat.defaultAgent in
~/.kiro/settings/cli.json). `remove --kiro` restores the prior default
(recorded in the marker) and deletes kcap.json. Requires kiro-cli on
PATH; RunKiroCli sets EDITOR/VISUAL=true so `agent create --from` does
not block on $EDITOR, and waits-then-kills so the 60s bound applies.

Critical fix: Kiro's agentSpawn payload carries no session_id — Kiro
exposes it via the KIRO_SESSION_ID env var. KiroHookCommand now reads it
from there (payload fallback). Without this the hook bailed and live
capture was a silent no-op.

New KiroSettings (chat.defaultAgent read/write, other keys preserved);
KiroHooksInstaller marker line 2 records the prior default. README +
help-plugin updated. Verified end-to-end against a local server:
SessionStarted(vendor=kiro, model, cwd) -> watcher SignalR stream -> 24
canonical events (UserMessage/AssistantText/ToolCalls/ToolResult) ->
SessionEnded(parent_exited); plugin remove restored the default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings in the Gemini CLI vendor (AI-887, #164), help-text refresh (#163),
and the YAML redactor fix (#166). All conflicts were parallel-vendor
additions (Kiro vs Gemini) resolved by keeping both, Gemini before Kiro.
Build + 1567 unit tests green; NativeAOT publish clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@realtonyyoung realtonyyoung changed the title [AI-888] AWS Kiro CLI ingest (hooks, SQLite watcher, import, installer) [AI-888] AWS Kiro CLI ingest (hooks, JSONL watcher, import, transparent live install) Jun 18, 2026
}

var exit = await PostHookAsync(baseUrl, "session-start/kiro", enriched);
if (exit != 0) return exit;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Kiro hook contract in this PR says the dispatcher must always exit 0 with empty stdout, but this path returns 1 whenever /hooks/session-start/kiro is temporarily unreachable or returns a non-2xx. That can surface as a failed agentSpawn hook inside kiro-cli for a server/auth blip, which is exactly the failure mode the Kiro-specific wrapper is trying to avoid. For this vendor, please log the failure to stderr but still return 0 (and decide separately whether EnsureWatcherRunning should still be attempted after a failed start POST).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a69453e. HandleAgentSpawn now returns 0 when the session-start POST fails (PostHookAsync already logs the failure to stderr), so a transient server/auth blip no longer surfaces as a failed agentSpawn hook inside kiro-cli. On a failed POST it also skips EnsureWatcherRunning for that firing — agentSpawn fires again on the next prompt and retries both the POST and the watcher.

// the global agents dir, preserving tools/prompt). Skipped if kcap exists.
if (!File.Exists(agentJsonPath)) {
if (!AgentDetector.IsInstalled(KiroBinary)) return false;
if (RunKiroCli($"agent create {KiroAgentName} --from {recordedDefault}") != 0 || !File.Exists(agentJsonPath))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This builds the kiro-cli argument string by concatenating the saved default-agent name. ProcessStartInfo(fileName, arguments) does not preserve argument boundaries, so a valid Kiro agent name containing whitespace (or quotes) is split before it reaches kiro-cli (--from My Agent becomes two trailing args). That makes transparent install fail for users whose current default agent is not a single shell token. Please switch this helper to ProcessStartInfo.ArgumentList (for example agent, create, kcap, --from, recordedDefault) so the recorded default is passed as one argument.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a69453e. RunKiroCli now takes params string[] and uses ProcessStartInfo.ArgumentList ("agent", "create", "kcap", "--from", recordedDefault), so a default-agent name containing whitespace or quotes reaches kiro-cli as a single argument.

ct.ThrowIfCancellationRequested();

// Filename stem is the dashed session UUID Kiro uses for both files.
var dashed = Path.GetFileNameWithoutExtension(jsonl);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kiro session files are UUID-named, and the live hook path already rejects non-GUID session ids. The importer should apply the same Guid.TryParse guard here before deriving dashless; otherwise any stray *.jsonl in this directory (backup/export/debug file, partially renamed file, etc.) is discovered as a session and then starts hitting /api/sessions/{name}/last-line / lifecycle routes with a non-session id. That will at best show probe/import errors for files that are not Kiro sessions, and at worst create inconsistent server state if the route accepts the string. Please skip stems that are not valid UUIDs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a69453e. DiscoverAsync now applies Guid.TryParse to the filename stem and skips any non-UUID *.jsonl (backup/export/debug/partial-rename) before deriving dashless or probing /api/sessions/{id}/..., mirroring the live hook path.

…D import guard

Three reviewer findings:
- KiroHookCommand: a failed session-start POST returned 1, surfacing as a
  FAILED agentSpawn hook inside kiro-cli on a transient server/auth blip —
  exactly what the vendor wrapper must avoid. Now fail-open: PostHookAsync
  already logs to stderr, so swallow the non-zero exit (return 0) and skip
  the watcher this firing; the next prompt's agentSpawn retries both.
- RunKiroCli: built the `kiro-cli` args by string concatenation, so a default
  agent name with whitespace/quotes (`--from My Agent`) was split into two
  args and broke the clone. Switched to ProcessStartInfo.ArgumentList.
- KiroImportSource: apply the live path's Guid.TryParse guard to the filename
  stem so a stray non-UUID *.jsonl (backup/export/partial rename) isn't
  discovered as a session and probed against /api/sessions/{id}/... routes.

Kiro CLI unit tests green; build + NativeAOT publish clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/// </summary>
public static bool SetDefaultAgent(string settingsPath, string agentName) {
try {
var root = (File.Exists(settingsPath) ? JsonNode.Parse(File.ReadAllText(settingsPath)) : null) as JsonObject

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Kiro’s shared settings file, but when it already exists and is malformed or is not a JSON object this expression falls back to new JsonObject() and File.WriteAllText replaces the whole file with only chat.defaultAgent. That can silently drop unrelated Kiro settings (chat.defaultModel, etc.) during install/remove. The Gemini installer handles the same shared-settings case by failing closed on malformed JSON; this should do the same here: if the file exists but cannot be parsed as a JsonObject, return false and leave it untouched.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e3aeeba. SetDefaultAgent now fails closed: if the settings file exists but does not parse as a JsonObject (a JSON array/scalar, or malformed JSON which throws) it returns false and leaves the file untouched, instead of replacing it with a fresh {chat.defaultAgent} and dropping chat.defaultModel etc. Mirrors the Gemini installer. Added set_default_fails_closed_on_valid_json_that_is_not_an_object and set_default_fails_closed_on_malformed_file.

// Restore the default agent kcap replaced (recorded at install time).
var previousDefault = KiroHooksInstaller.ReadPreviousDefault(agentPath) ?? "kiro_default";
if (KiroSettings.ReadDefaultAgent(settingsPath) == KiroAgentName)
KiroSettings.SetDefaultAgent(settingsPath, previousDefault);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetDefaultAgent returns false on I/O/parse failure, but removal ignores that and then deletes ~/.kiro/agents/kcap.json plus the marker. If the settings write fails here, the user is left with chat.defaultAgent still set to kcap while the kcap agent file has been removed, and the recorded previous default is gone so a retry cannot restore it. Please fail removal before deleting the agent/marker when the default is currently kcap and restoring previousDefault fails (and report the settings path/error to the user).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e3aeeba. RemoveKiro now checks SetDefaultAgent's return: when kcap is the current default and restoring previousDefault fails, it aborts BEFORE deleting kcap.json/the marker, prints the settings path + retry hint to stderr, and returns 1. The agent file and the recorded previous default stay in place so kcap plugin remove --kiro is retryable after the settings file is fixed.

realtonyyoung and others added 2 commits June 17, 2026 23:18
…ssion-end

Two reviewer findings + the CLI side of a third (server #760):
- KiroSettings.SetDefaultAgent: an existing settings file that is valid JSON
  but not an object (or otherwise unparseable) was clobbered with a fresh
  {chat.defaultAgent}, dropping unrelated keys (chat.defaultModel, etc.). Now
  fails closed and leaves the file untouched, mirroring the Gemini installer.
- RemoveKiro: ignored SetDefaultAgent's false return and deleted kcap.json +
  the marker anyway, stranding chat.defaultAgent=kcap on a deleted agent with
  the recorded previous default gone (unrecoverable). Now aborts before
  deleting when the restore write fails and reports the path, staying retryable.
- WatchCommand parent-exit session-end now stamps `ended_at` (computed once,
  stable across POST retries) so the server can scope the SessionEnded id per
  run. Kiro has no session-end hook — this is its ONLY live end path — so
  without a timestamp a resumed session's second exit deduped against the first
  and left the session stuck Active. Benefits every vendor's parent-exit path.

New KiroSettings fail-closed tests; full unit suite green; AOT publish clean.

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

if (!InjectKiroHooksIntoAgent(agentJsonPath)) return false;

KiroHooksInstaller.WriteMarker(agentJsonPath, recordedDefault);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WriteMarker happens before the final SetDefaultAgent write. If the settings flip fails (for example the existing shared settings file is malformed and SetDefaultAgent now correctly returns false), InstallKiroHooks reports failure but leaves .kcap-hooks-version behind. That makes the failed install look installed to IsInstalled/--if-installed refreshes, even though chat.defaultAgent was never changed to kcap. Please only write the marker after SetDefaultAgent succeeds, or delete it on this failure path so failed installs do not poison future refresh/detection state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7674626. InstallKiroHooks now flips the default (SetDefaultAgent) FIRST and stamps .kcap-hooks-version only after it succeeds — a failed settings flip returns false with no marker left behind, so IsInstalled/--if-installed no longer treat the broken install as done and the next --if-installed refresh retries it.

…e default flips

WriteMarker ran before the final SetDefaultAgent, so a failed settings flip
(e.g. a malformed shared settings file, which SetDefaultAgent now fails closed
on) left .kcap-hooks-version behind. That made the broken install look done to
IsInstalled / `--if-installed`, so the next refresh skipped it and kcap never
became the default. Now flip the default FIRST and stamp the marker only on
success — a failed install leaves no marker, so the next `--if-installed`
refresh retries it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
// the default. With no marker, the next --if-installed refresh retries.
if (!KiroSettings.SetDefaultAgent(settingsPath, KiroAgentName)) return false;

KiroHooksInstaller.WriteMarker(agentJsonPath, recordedDefault);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ordering is fixed now, but WriteMarker still swallows all write failures while InstallKiroHooks returns success. That marker is not just a refresh optimization for Kiro: line 2 is the only record of the user’s previous default agent. If writing .kcap-hooks-version fails after SetDefaultAgent succeeds, plugin install --kiro reports success with chat.defaultAgent=kcap but plugin remove --kiro later falls back to kiro_default and can restore the wrong agent; a subsequent --if-installed refresh also sees the hook file and can re-stamp the wrong previous default. Please make the marker write part of the atomic install contract (return false/throw from WriteMarker, and either fail before reporting success or roll the default back if the marker cannot be written).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8d3e5a. WriteMarker now returns bool (false on I/O failure instead of swallowing), and InstallKiroHooks treats it as part of the atomic install: if the marker write fails after the default flip, it rolls chat.defaultAgent back to the recorded previous default and returns failure — so install never reports success in a state where remove --kiro would restore the wrong agent or --if-installed could re-stamp a bogus previous default.

realtonyyoung and others added 2 commits June 18, 2026 07:19
…kiro-cli-session-ingest

# 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/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/VendorSelection.cs
#	src/Capacitor.Cli/Commands/WatchCommand.cs
#	src/Capacitor.Cli/Program.cs
#	test/Capacitor.Cli.Tests.Integration/WatcherParentExitPostTests.cs
#	test/Capacitor.Cli.Tests.Unit/CodingAgentsStepTests.cs
… of the atomic install

WriteMarker swallowed all I/O failures while InstallKiroHooks still returned
success. The marker's line 2 is the ONLY record of the user's previous default
agent, so a silent failure left `chat.defaultAgent=kcap` with no way back:
`remove --kiro` would fall back to `kiro_default` (wrong agent) and a later
`--if-installed` refresh could re-stamp a bogus previous default. WriteMarker
now returns bool; InstallKiroHooks rolls the default back to the recorded
previous and returns failure if the marker can't be written.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
// Treat it as part of the atomic install: on failure roll the default
// back and report failure rather than a success we can't undo.
if (!KiroHooksInstaller.WriteMarker(agentJsonPath, recordedDefault)) {
KiroSettings.SetDefaultAgent(settingsPath, recordedDefault);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rollback is still best-effort because the return value is ignored. If the marker write fails and the settings rollback also fails (for example the shared settings file is replaced, locked, or becomes malformed between the two writes), InstallKiroHooks returns failure but leaves chat.defaultAgent=kcap with no marker recording the previous default. A later remove --kiro then falls back to kiro_default, so the user can still lose their real prior default. Please check the rollback result and, on rollback failure, either leave enough recovery state for remove --kiro to restore the recorded default or surface a distinct failure path instead of silently returning the same false state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7607018. The rollback now checks its own result: if SetDefaultAgent(recordedDefault) also fails, InstallKiroHooks writes a distinct, actionable message to stderr naming the previous default agent (recordedDefault) plus the settings + agent-file paths, so the user can restore chat.defaultAgent by hand — instead of returning the same opaque false as "kiro-cli not installed" and silently losing the prior default. (A richer return type would ripple through the Func<string,bool> wiring in SetupCommand/CodingAgentsStep, so the recovery info is surfaced via stderr on this rare double-failure path.)

…stall rollback also fails

The marker-write rollback ignored its own result. If both the marker write AND
the settings rollback fail (shared cli.json locked / replaced / malformed
between the two writes), InstallKiroHooks left chat.defaultAgent=kcap with no
marker and returned the same opaque false as "kiro-cli not installed" — so the
user silently lost their real prior default. Now the rollback result is checked
and, on rollback failure, a distinct actionable message names the previous
default agent + the settings/agent paths so it can be restored by hand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@realtonyyoung realtonyyoung merged commit 433fbab into main Jun 18, 2026
5 checks passed
@realtonyyoung realtonyyoung deleted the tonyyoung/ai-888-aws-kiro-cli-session-ingest branch June 18, 2026 13:19
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