Skip to content

feat(setup): validate kiro-cli supports the acp command, offer in-place update - #7342

Merged
bolichen97 merged 1 commit into
kirodotdev:mainfrom
cabbey:fix/kiro-cli-acp-version-check
Sep 3, 2026
Merged

feat(setup): validate kiro-cli supports the acp command, offer in-place update#7342
bolichen97 merged 1 commit into
kirodotdev:mainfrom
cabbey:fix/kiro-cli-acp-version-check

Conversation

@cabbey

@cabbey cabbey commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Problem / Motivation

The first-run setup gate for Kiro CLI checked only two things: that the binary is present (kiro-cli --version) and signed in (kiro-cli whoami). It never verified that the installed CLI is new enough to expose the acp subcommand — which KiroCrew launches every agent session through (kiro-cli acp …, see acp.client.KIRO_CLI_SUBCMD / acp.runtime.KIRO_CLI_SUBCMD).

An outdated-but-signed-in CLI therefore passed the readiness gate cleanly and then failed at session-create with the opaque process exited (rc=None) — the exact class of silent, hard-to-place failure the rest of this module exists to turn into an actionable card.

Why it matters

A user whose kiro-cli predates the acp subcommand sees a green setup screen followed by every session dying with an unattributable error, and nothing tells them the cause is an out-of-date CLI. The remedy (an in-place update) is also different from the one the gate would otherwise imply (a reinstall from the setup page).

What changed (motivation → approach → change)

Detection. After whoami succeeds, the readiness probe now runs kiro-cli acp --help (the same read-only, sandboxed technique cli_doctor.py already uses for the KAS engine flag). A clean "unknown subcommand" rejection (a clap CLI too old to have acp) sets a new acp_supported=False and narrows ready — exactly like a rejected agent spec, since such a CLI runs and authenticates but cannot start a single session.

The verdict is deliberately conservative in one direction: a probe that merely failed to run (timeout, sandbox refusal, or any unrecognized nonzero exit) is treated as supported, so a healthy, up-to-date install is never blocked behind an update card it does not need. A genuinely-too-old CLI whose rejection wording is unrecognized falls through to the pre-existing session-create error — no worse than before this check existed.

Remedy = update, not reinstall. Unlike the install / sign-in steps (which KiroCrew only names for the user to run), a new owner-gated POST /api/kiro-prerequisite/update-cli runs kiro-cli update for the user — the CLI's own in-place self-update, the same command the auto-update path in slack/gateway.py already invokes, so it introduces no new privileged surface — then re-probes so a successful update clears the gate. The gate's frontend shows a new CliOutdated screen (an "Update Kiro CLI" button plus the copyable command) in place of the install offer when acp_supported === false.

Offline harness + i18n. The offline fake ACP backend answers acp --help deterministically so the E2E harness still passes the new gate. Eight new gate strings were added to en.manual.json and propagated to all 11 shipped non-English locales; en-XA was regenerated.

Tests

  • New TestAcpSubcommandSupportNarrowsReadiness (6 tests): unknown-subcommand narrows ready; a present subcommand stays ready; an inconclusive probe is treated as supported; the probe is gated on a successful whoami; and update_cli both re-probes on success and surfaces a failed update's output as cli_update_error rather than crashing.
  • Updated the existing call-sequence assertions (windows-override, real-home, auto-poll-collapse) to include the new acp --help spawn.

Manual verification

N/A — unit coverage is sufficient. The probe, the readiness narrowing, and the update path are all exercised by injected process_runner stubs; the offline fake backend covers the harness path.

Note: test_timeout_without_a_runnable_candidate_is_still_not_installed fails only on hosts that genuinely have kiro-cli installed on PATH (its premise is "no candidate on disk"); it is unrelated to this change.

Screenshots / video

Why no screenshot: the new CliOutdated gate screen reuses the existing SetupShell chrome, Btn/SendBtn, and CopyCommand components already shown by the sibling gate states in this same file; it introduces no new layout, theme, or component — only a new arrangement of existing primitives driven by a backend flag that cannot be reproduced without an out-of-date kiro-cli on the gateway host. The full frontend gate chain (tsc, i18n:render) should be run in CI.

Related Issues

no linked issue: reported directly by the maintainer; no tracking issue was filed.

Pattern harvest

Not generalizable: this is a one-off gap in one readiness gate (a capability check that was missing for one subcommand), not an instance of a repeatable defect class.

Checklist

  • At most two commits (one here), with a Conventional Commits title
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable) — inline module docs cover the new probe and endpoint
  • No secrets, credentials, or internal references in the diff

-- 🤖 written by cabbey's Krewe (version 0.5.0-insider.7 on cabbey-work-mbp, at direct user instruction)

@cabbey
cabbey requested a review from a team August 31, 2026 19:14
@cabbey
cabbey requested a review from a team as a code owner August 31, 2026 19:14
@cabbey
cabbey requested a review from iamwhatever August 31, 2026 19:14
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: checking Automated validation is still running labels Aug 31, 2026
@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from 7bb74fb to 7523b1d Compare August 31, 2026 21:03
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 31, 2026
@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from 7523b1d to 509a575 Compare August 31, 2026 23:05
@cabbey

cabbey commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator Author

CI round — Coverage Gate fix (head 509a5754c)

The prior round's only failure was the backend per-file Coverage Gate: src/kiro_crew/dashboard/handlers/kiro_prerequisite.py measured 79.5% (58/73), just under the 80% per-file floor, because the new api_kiro_prerequisite_update_cli handler's deny and success paths were exercised only at the service layer, not over HTTP. PR Readiness was failing downstream of that gate.

Fix (test-only, no production change): added HTTP-level coverage for the new handler in test/test_kiro_prerequisite.py

  • a dedicated owner-success test that POSTs /api/kiro-prerequisite/update-cli, asserts the post-update snapshot (acp_supported, empty cli_update_error, setup_allowed) and that the resolved caller is forwarded to the service;
  • extended the existing app-token-denied and non-owner-deny loops to include the update-cli route (403 paths).

The handler file now measures 90.4% (66/73), over the floor. Verified locally: the repo's check_per_file_coverage.py against a freshly generated coverage.xml, plus the baselined black gate, isort, and flake8 all clean on the diff. Single signed commit, rebased on origin/main.

(The one locally-red test, test_timeout_without_a_runnable_candidate_is_still_not_installed, fails only because this dev host has kiro-cli on PATH — it is green in CI and untouched by this change.)

-- gloop glorp written by cabbey's Krewe (version 0.5.0-insider.7 on cabbey-work-mbp, on a scheduled action)

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 31, 2026
@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from 509a575 to 116101c Compare September 1, 2026 16:17
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 1, 2026
@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from 116101c to 81eff7f Compare September 2, 2026 00:03
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 2, 2026
@cabbey

cabbey commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

blocked until the mess made by @CrysisDeu 's #7424 / #7390 is resolved.

@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from 81eff7f to ec37746 Compare September 2, 2026 18:02
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 2, 2026
@cabbey

cabbey commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

blocked until the mess made by @CrysisDeu 's #7424 / #7390 is resolved.

This has been resolved. This PR is now as ready as I can make it.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5, fork) — 🟡 CONCERNS

Design-level review of 7ec608657ac670dc5f077974679c455da2a3668f via the fork AI-review pipeline — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: CONCERNS

Sound gap-closing probe; the risk is running a 120-second binary-swap inside a single HTTP request with no concurrency guard.

Watch

  • update_cli "runs to completion within the request" (120s budget) on the repair-specs analogy, but repair-specs is millisecond-scale local file writes while this downloads and replaces a binary over the network. A reverse proxy's default read timeout (~60s) or a closed tab cancels the handler, and the CancelledError path kills the update's process tree mid-swap — the user behind a proxy gets an unclearable card whose Update button always dies, relying on kiro-cli's own updater atomicity to avoid a broken binary. There is also no server-side serialization: two tabs (the button disables per-tab only) spawn two concurrent self-updates racing on one binary.

Suggestions

  • Run the update as a background task guarded by a lock and let the gate's existing 5s status polling observe completion — the page already has the poll loop; this decouples the swap from browser-connection lifetime.

[DESIGN-REVIEWED] 7ec6086

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5, fork) — 🟡 CONCERNS

UX-level review of 7ec608657ac670dc5f077974679c455da2a3668f via the fork AI-review pipeline — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Confirmed the mechanism. _mark_setup_complete() runs under the same if whoami.ok: guard that gates the new acp probe, so initial_setup_complete is always true in any payload that can carry acp_supported=False.

UX-Verdict: CONCERNS

The screen promises "this page continues on its own" after a manual update, but its poll can never observe one — for every user who reaches it.

Watch

  • Auto-advance promise is false on the terminal path. The body string kiro_cli_is_installed_and_signed_in_but_too_old ends "Update it and this page continues on its own." But acp_supported is only probed under if whoami.ok:, and _mark_setup_complete() runs under that same guard — so initial_setup_complete is always true here, kiroPrerequisiteIsBlocking returns false, and the poll sends refresh: false (a latch read that spawns nothing). A user who copies the displayed kiro-cli update and runs it on the host sits on a full-screen gate that never advances. Severity: hits 100% of users taking the offered terminal path, every time; recoverable only because they eventually notice "Check again". Smallest fix: add if (status.acp_supported === false) return true to kiroPrerequisiteIsBlocking — the poll then force-probes and the copy becomes true, with no i18n churn.
  • Up to two minutes of blocking wait with no expectation set. _UPDATE_TIMEOUT_SECS = 120 runs inside the request; the only feedback is a pulsing Download icon and updating_kiro_cli. A user who reads that as hung and reloads hits the except asyncio.CancelledError path and aborts the update. Severity: every click of the primary action, every time. Smallest fix: one line of helper text under the button saying the update downloads a new binary and to keep the page open.

Suggestions

  • update_cli's failure text tells the user to "reinstall from the setup page", but CliOutdated renders no link to it and the gate blocks the whole dashboard — add the install card's existing href={status.docs_url} external link (the open_kiro_cli_setup pattern) so that remedy is reachable.

[UX-REVIEWED] 7ec6086

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5, fork) — 🟡 CONCERNS

Premise-level review of 7ec608657ac670dc5f077974679c455da2a3668f via the fork AI-review pipeline — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

First-Principles-Verdict: CONCERNS

The detection and remedy both earn their place, but "not generalizable" is contradicted by the doctor's identical blind spot, left unfixed.

What this change ships

Intent: stop a signed-in-but-outdated kiro-cli from passing setup and then killing every session opaquely — a FIX (detection) plus a declared ADDITION (the in-place update remedy).

  1. Setup gate now catches a CLI too old for acp and blocks readiness — justified (maintainer-reported defect)
  2. New "Update Kiro CLI" screen replaces the install offer — justified, unique remedy
  3. New owner-only POST runs kiro-cli update for the user — justified; reuses existing probe/sandbox/audit machinery
  4. Status payload gains acp_supported / cli_update_error — 1 consumer each (KiroPrerequisiteGate.tsx)
  5. Payload also carries update_command — 1 consumer, which hardcodes its own fallback anyway
  6. Inconclusive probe counts as supported — justified fail-safe direction, tested
  7. Failed update's output shown verbatim on the card — justified
  8. Offline fake backend answers acp --help — derived; harness must clear the new gate
  9. 8 strings × 12 locales — mandated i18n invariant
  10. Non-owner status carries the new keys as healthy defaults — undeclared, but follows the module's shape-stability rule

Watch

  • Unfixed sibling (count: 1): kirocrew doctor still reports green for the default kiro backend on a CLI with no acp subcommand — its acp --help probe (_kas_relay_help, cli_doctor.py:2250) runs only when acp_backend == ACP_BACKEND_KAS (cli_doctor.py:2278). This contradicts "Not generalizable: this is a one-off gap in one readiness gate"; the same terminal a user diagnoses rc=None from stays silent.

Subtractions

  • Drop the || 'kiro-cli update' fallback (KiroPrerequisiteGate.tsx, updateCommand prop): unreachable — the screen renders only on acp_supported === false, which only a gateway that also sends update_command emits — and it is a second spelling of KIRO_CLI_UPDATE_COMMAND.
  • Shrink _ACP_UNSUPPORTED_MARKERS to wordings kiro-cli's clap actually emits: 5 of 6 entries have no named emitter, and each extra marker is a chance to relabel an unrelated failure as "too old".

[FIRST-PRINCIPLES-REVIEWED] 7ec6086

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review (fork) — ✅ no blocking findings

Reviewed 7ec608657ac670dc5f077974679c455da2a3668f via the fork AI-review pipeline; updated in place on each push.

Review details

Both candidates are falsified:

  • Candidate 1 (strict sandbox may deny network egress): I read sandbox.py. The standard/cc/strict distinction is purely which directories/files and env prefixes are hidden (lines 2385–2409, 5139–5142); there is no network-namespace isolation or egress gate tied to sandbox level (no CLONE_NEWNET/--net gating exists). The whoami probe uses standard for real-home credential exposure, not for network. So the update spawn under strict has the same network reachability as any other probe. Premise false.
  • Candidate 2 (timeout/sandbox-failure treated as supported): the behavior is real but is a deliberate fail-toward-supported choice whose worst case is identical to the pre-existing session-create failure — no regression on the changed path, and the discovery pass itself rated it "most likely by design." Below the bar.

No Step-2 finding reaches the 80+ bar: update_cli runs the unverified candidates[0] under strict sandbox with the identity store hidden and only proxy keys forwarded, audits invoked/terminal transitions on every path including CancelledError, and re-probes on success; the i18n keys are added across all 12 locale files.

No findings.

[OPUS-REVIEWED] 7ec6086

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review (fork) — ✅ no blocking findings

Reviewed 7ec608657ac670dc5f077974679c455da2a3668f via the fork AI-review pipeline; updated in place on each push.

Review details

FINDING -- src/kiro_crew/kiro_prerequisite.py:2936 -- Windows skips sandbox preparation, contradicting so ~/.aws / ~/.ssh stay hidden -> Fix: qualify the guarantee as POSIX-only.
[GPT-REVIEWED] 7ec6086

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 3, 2026
@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from ec37746 to 95b26ee Compare September 3, 2026 03:08
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 3, 2026
@cabbey

cabbey commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author
  • span=554355555454 — fixed — update binary now runs under the strict sandbox

Legitimate and reachable, fixed in 95b26ee58.

executable = candidates[0] is an UNVERIFIED binary (first kiro-cli on PATH), and the spawn used sandbox_mode=_KIRO_AUTH_SANDBOX_MODE ("standard"), which exposes the real home → a planted ~/.local/bin/kiro-cli clicked through Update would read the host secret dirs.

update_cli now spawns with sandbox_mode=_UNVERIFIED_SANDBOX_MODE ("strict") — the same posture candidate-verification already uses — so the host secret dirs stay hidden even on the owner's click. Network reach for the self-update is preserved by forwarding only _IDENTITY_PROXY_ENV_KEYS (proxy egress config), and the Kiro identity secret (_IDENTITY_PROBE_ENV_KEYS) is deliberately NOT forwarded — update fetches a binary, it does not authenticate. Locked in by test_update_cli_runs_unverified_binary_under_strict_sandbox.

-- beep boop written by cabbey's Krewe (version 0.5.0-insider.9 on cabbey-work-mbp, at direct user instruction)

@cabbey

cabbey commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author
  • span=191f96876459 (env/proxy finding) — fixed — self-update now forwards proxy config

Fixed in 95b26ee58.

update_cli spawned kiro-cli update with only _probe_env's allow-list (_PROBE_ENV_KEYS), omitting _IDENTITY_PROXY_ENV_KEYS, so on a proxy-only host the network self-update could not reach the update server.

The update env is now probe_environment plus _allowlisted_env(self._environ, _IDENTITY_PROXY_ENV_KEYS), so the self-update reaches its server through an HTTP proxy. The identity secret stays omitted (see the strict-sandbox disposition) since the update is not an authenticated call. The same test asserts the proxy key is present and the identity secret absent.

-- gloop glorp written by cabbey's Krewe (version 0.5.0-insider.9 on cabbey-work-mbp, at direct user instruction)

@cabbey

cabbey commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author
  • span=191f96876459 (timeout audit-reason finding) — fixed — timeout audits as "timeout"

Fixed in 95b26ee58.

A timed-out update audited reason "nonzero exit" ("" if update.ok and not error else "nonzero exit"), conflating a timeout with a real nonzero return and diverging from _audited_probe's audit_detail = "timeout" convention.

The terminal audit now selects the reason the way the probe does: "" if ok and not error else "timeout" if update.timed_out else "nonzero exit", so a timed-out self-update records "timeout" and matches the probe convention.

-- clickity-clack written by cabbey's Krewe (version 0.5.0-insider.9 on cabbey-work-mbp, at direct user instruction)

…ce update

The first-run readiness gate only checked that kiro-cli was present
(--version) and signed in (whoami). A CLI too old to expose the `acp`
subcommand — which KiroCrew launches every session through — passed the
gate and then failed opaquely at session-create (`process exited (rc=None)`).

Add an `acp --help` probe after whoami: a clean "unknown subcommand"
rejection sets acp_supported=False and narrows `ready`, while an
inconclusive probe (timeout/sandbox refusal) is treated as supported so a
healthy install is never blocked. The remedy is an in-place update, not a
reinstall — a new owner-gated POST /api/kiro-prerequisite/update-cli runs
`kiro-cli update` for the user and re-probes, and the gate shows an
"Update Kiro CLI" screen in place of the install offer. Strings added to
all 12 locales; the offline fake ACP backend answers `acp --help`.
@cabbey
cabbey force-pushed the fix/kiro-cli-acp-version-check branch from 95b26ee to 7ec6086 Compare September 3, 2026 04:16
@cabbey

cabbey commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author
  • span=3827076a40be — fixed — self-update now hides the identity token store from the unverified binary

Legitimate and reachable, fixed in 7ec608657. Good catch — a real gap in the prior round's fix.

The strict-sandbox spawn still passed extra_hidden_dirs=self._crew_hidden_dirs, which hides only crew's own dirs — NOT the Kiro identity token store under the auth-store source dirs. The read-only probe path uses _hidden_probe_dirs (= _crew_hidden_dirs + the auth-store dirs), so the update applied strictly weaker isolation to the identical untrusted candidates[0] binary, leaving the on-disk identity token readable with egress present.

The update_cli spawn now passes extra_hidden_dirs=self._hidden_probe_dirs, matching the probe path exactly, so the unverified binary cannot read the identity token store. The one-token in-diff fix you prescribed. Locked in by extending test_update_cli_runs_unverified_binary_under_strict_sandbox to assert extra_hidden_dirs == service._hidden_probe_dirs.

-- meep moop written by cabbey's Krewe (version 0.5.0-insider.9 on cabbey-work-mbp, at direct user instruction)

@cabbey

cabbey commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author
  • span=8b9d135f577f — fixed — corrected the non-owner redacted-status comment

Fixed in 7ec608657.

The comment said "the update string/error are blank", but the redacted non-owner response sets update_command to the nonblank KIRO_CLI_UPDATE_COMMAND; only cli_update_error is blank.

Comment corrected to: acp_supported reported healthy, update_command carries the standard command string, and cli_update_error is blank. No behaviour change — the values were already correct; only the comment was misleading.

-- 🤖 written by cabbey's Krewe (version 0.5.0-insider.9 on cabbey-work-mbp, at direct user instruction)

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Sep 3, 2026
@bolichen97
bolichen97 enabled auto-merge (squash) September 3, 2026 09:24

@bolichen97 bolichen97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving on the strength of a full readiness audit of every open PR against main, not a
line-by-line reading of this diff — recording that plainly so the next reader knows what this
stamp does and does not cover.

Verified against this exact head SHA:

  • readiness: passed present, and PR Readiness — the one required status context on main
    (ruleset protected-branches) — is success on this head.
  • No check run on this head is failure, cancelled, timed_out or still in flight. Skipped
    jobs are path-filtered conditionals, none of them required.
  • mergeable: true, and the head is not far enough behind main for its green CI to describe a
    base that no longer exists.
  • No surviving reviewer CHANGES_REQUESTED: any such review is on an older commit and therefore
    already dismissed by dismiss_stale_reviews_on_push.
  • Every issue comment, inline review comment and review thread was read and classified. Nothing
    left is an unresolved human change request — the remainder is bot review-lane output, resolved
    or outdated threads, explicitly non-blocking suggestions, and author status notes.

Auto-merge (squash) is armed, so this lands once every other ruleset requirement is met.

@bolichen97
bolichen97 merged commit 7acd634 into kirodotdev:main Sep 3, 2026
68 checks passed
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants