fix: separate Pi ACP and passthrough commands (#2708)
This commit is contained in:
@@ -85,7 +85,7 @@ Connect Kandev to the tools your team already uses — pull issues into the kanb
|
||||
| **Factory Droid** | `droid` |
|
||||
| **iFlow (beta)** | `@iflow-ai/iflow-cli` |
|
||||
| **Kilocode** | `@kilocode/cli` |
|
||||
| **Pi** | `pi-acp` |
|
||||
| **Pi** | ACP adapter: `pi-acp`; CLI passthrough: `pi` |
|
||||
| **Kimi** | `kimi` *(install Kimi CLI from Moonshot AI)* |
|
||||
| **Kiro** | `kiro-cli-chat` *(install Kiro CLI from AWS)* |
|
||||
| **Qoder** | `qodercli` *(install Qoder CLI)* |
|
||||
|
||||
@@ -2,7 +2,10 @@ package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -21,8 +24,8 @@ type acpAgentSpec struct {
|
||||
// detectBinaries lists every binary name IsInstalled accepts via
|
||||
// WithCommand. Used by TestNewACPAgents_DetectionRequiresGlobalBinary
|
||||
// to skip the test whenever ANY of these is on PATH — otherwise an
|
||||
// agent with multiple WithCommand fallbacks (e.g. Pi accepts both
|
||||
// `pi-acp` and `pi`) flakes when the secondary binary is present.
|
||||
// agent with multiple WithCommand fallbacks flakes when a secondary binary
|
||||
// is present.
|
||||
detectBinaries []string
|
||||
expectedArgv []string // BuildCommand and Runtime.Cmd
|
||||
inferenceArgv []string // InferenceConfig.Command
|
||||
@@ -76,11 +79,12 @@ var newACPAgentSpecs = []struct {
|
||||
sessionDirTemplate: "{home}/.kilocode",
|
||||
}},
|
||||
{func() Agent { return NewPiACP() }, acpAgentSpec{
|
||||
id: "pi-acp", displayName: "Pi", detectBinaries: []string{"pi-acp", "pi"},
|
||||
id: "pi-acp", displayName: "Pi", detectBinaries: []string{"pi"},
|
||||
expectedArgv: []string{"npx", "-y", "pi-acp"},
|
||||
inferenceArgv: []string{"npx", "-y", "pi-acp"},
|
||||
passthroughArgv: []string{"npx", "-y", "pi-acp"},
|
||||
passthroughArgv: []string{"pi"},
|
||||
installViaNpm: true,
|
||||
installScript: "npm install -g --ignore-scripts @earendil-works/pi-coding-agent",
|
||||
sessionDirTemplate: "{home}/.pi",
|
||||
}},
|
||||
{func() Agent { return NewCursorACP() }, acpAgentSpec{
|
||||
@@ -287,7 +291,7 @@ func TestNewACPAgents_InstallScript(t *testing.T) {
|
||||
// to use. detectBinaries comes from the spec table so npx-launched agents
|
||||
// (whose argv[0] is "npx") are still verified against their real detection
|
||||
// targets (qwen, iflow, droid, …), and agents with multiple WithCommand
|
||||
// fallbacks (e.g. Pi accepts both `pi-acp` and `pi`) skip the test
|
||||
// fallbacks skip the test
|
||||
// whenever ANY of those is on PATH so the test doesn't flake on CI hosts
|
||||
// that happen to have a generic `pi` (Raspberry Pi tooling) installed.
|
||||
func TestNewACPAgents_DetectionRequiresGlobalBinary(t *testing.T) {
|
||||
@@ -310,6 +314,27 @@ func TestNewACPAgents_DetectionRequiresGlobalBinary(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPiACPDetectionRejectsPiBinaryWithoutVersionSupport(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("shell executable fixture is Unix-specific")
|
||||
}
|
||||
|
||||
binDir := t.TempDir()
|
||||
piPath := filepath.Join(binDir, "pi")
|
||||
if err := os.WriteFile(piPath, []byte("#!/bin/sh\nexit 1\n"), 0o755); err != nil {
|
||||
t.Fatalf("write fake pi executable: %v", err)
|
||||
}
|
||||
t.Setenv("PATH", binDir)
|
||||
|
||||
result, err := NewPiACP().IsInstalled(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("IsInstalled error: %v", err)
|
||||
}
|
||||
if result.Available {
|
||||
t.Fatalf("Available=true for pi executable that fails --version")
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewACPAgents_LogosNonEmpty guards against agents shipping with empty
|
||||
// embedded SVGs (which renders as a broken <img> in the UI).
|
||||
func TestNewACPAgents_LogosNonEmpty(t *testing.T) {
|
||||
|
||||
@@ -16,7 +16,11 @@ var piACPLogoLight []byte
|
||||
//go:embed logos/pi_acp_dark.svg
|
||||
var piACPLogoDark []byte
|
||||
|
||||
const piACPPkg = "pi-acp"
|
||||
const (
|
||||
piACPPkg = "pi-acp"
|
||||
piCLIBin = "pi"
|
||||
piCLIPkg = "@earendil-works/pi-coding-agent"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Agent = (*PiACP)(nil)
|
||||
@@ -37,7 +41,7 @@ func NewPiACP() *PiACP {
|
||||
Supported: true,
|
||||
Label: "CLI Passthrough",
|
||||
Description: "Show terminal directly instead of chat interface",
|
||||
PassthroughCmd: NewCommand("npx", "-y", piACPPkg),
|
||||
PassthroughCmd: NewCommand(piCLIBin),
|
||||
ModelFlag: NewParam("--model", "{model}"),
|
||||
IdleTimeout: 3 * time.Second,
|
||||
BufferMaxBytes: DefaultBufferMaxBytes,
|
||||
@@ -64,13 +68,11 @@ func (a *PiACP) Logo(v LogoVariant) []byte {
|
||||
}
|
||||
|
||||
func (a *PiACP) IsInstalled(ctx context.Context) (*DiscoveryResult, error) {
|
||||
// "pi" is short and could in theory collide with unrelated tooling, but
|
||||
// the pi-mono coding agent (https://github.com/badlogic/pi-mono) ships
|
||||
// its CLI as `pi`, and a kandev user with `pi` on PATH is overwhelmingly
|
||||
// likely to be the pi coding-agent installation we're targeting.
|
||||
// Checking `pi-acp` first lets a dedicated wrapper take precedence
|
||||
// when both are present.
|
||||
result, err := Detect(ctx, WithCommand("pi-acp"), WithCommand("pi"))
|
||||
// The Pi package publishes the short `pi` binary used by passthrough. A
|
||||
// non-interactive version check is a best-effort filter for unrelated tools
|
||||
// with the same name; it does not prove package identity. The separate ACP
|
||||
// probe validates the structured `npx -y pi-acp` surface, not this binary.
|
||||
result, err := Detect(ctx, WithCommandCheck(piCLIBin, "--version"))
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
@@ -111,7 +113,7 @@ func (a *PiACP) Runtime() *RuntimeConfig {
|
||||
func (a *PiACP) RemoteAuth() *RemoteAuth { return nil }
|
||||
|
||||
func (a *PiACP) InstallScript() string {
|
||||
return "npm install -g " + piACPPkg
|
||||
return "npm install -g --ignore-scripts " + piCLIPkg
|
||||
}
|
||||
|
||||
func (a *PiACP) PermissionSettings() map[string]PermissionSetting {
|
||||
|
||||
@@ -536,9 +536,13 @@ func TestPassthroughPiWritesProjectFile(t *testing.T) {
|
||||
mgr, execution, profile := newPassthroughMCPTestManager(t, "pi-acp")
|
||||
piPath := filepath.Join(execution.WorkspacePath, ".pi", "mcp.json")
|
||||
|
||||
if _, _, _, _, err := mgr.passthroughAgentCommand(context.Background(), execution, profile); err != nil {
|
||||
_, _, _, cmd, err := mgr.passthroughAgentCommand(context.Background(), execution, profile)
|
||||
if err != nil {
|
||||
t.Fatalf("passthroughAgentCommand returned error: %v", err)
|
||||
}
|
||||
if got, want := cmd.Args(), []string{"pi", "--model", "default"}; !slices.Equal(got, want) {
|
||||
t.Fatalf("passthrough command = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(piPath)
|
||||
if err != nil {
|
||||
|
||||
@@ -276,7 +276,7 @@ test("@search reveals and flashes a cached preview content match selected with E
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.getByRole("combobox").fill(CACHED_PREVIEW_MARKER);
|
||||
const targetResult = dialog.getByTestId("content-search-result").filter({ hasText: targetPath });
|
||||
await expect(targetResult).toHaveCount(1);
|
||||
await expect(targetResult).toHaveCount(1, { timeout: 30_000 });
|
||||
await testPage.keyboard.press("Enter");
|
||||
await expect(dialog).not.toBeVisible();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ADR-2026-08-12-validated-managed-runtime-version-selection: Validate and Persist Managed Runtime Version Selection
|
||||
|
||||
**Status:** accepted
|
||||
**Status:** accepted (amended 2026-08-16)
|
||||
**Date:** 2026-08-12
|
||||
**Area:** backend, frontend, protocol
|
||||
**Supersedes:**
|
||||
@@ -45,6 +45,12 @@ continue to resolve their own runtime. When no selection record exists, Kandev
|
||||
retains the legacy unversioned host behavior until the first candidate is
|
||||
successfully activated.
|
||||
|
||||
The managed package and exact-version override belong only to an agent's ACP
|
||||
command surfaces. They do not replace `PassthroughConfig.PassthroughCmd`, an
|
||||
interactive authentication helper, or either surface's install recipe. Agents
|
||||
such as Pi can therefore use an ACP adapter package for structured execution
|
||||
and a separately distributed native CLI for terminal passthrough.
|
||||
|
||||
The selection is install-wide and per built-in agent. A saved selection applies
|
||||
only while its stored package identity matches the agent's current trusted
|
||||
package metadata; a package change starts with no selection and requires fresh
|
||||
@@ -85,3 +91,6 @@ capabilities.
|
||||
transactional selection without reimplementing package storage.
|
||||
- Applying the host selection to remote executors was rejected because each
|
||||
remote runtime has separate platform, cache, credentials, and ownership.
|
||||
- Reusing the managed ACP package for terminal passthrough was rejected because
|
||||
an ACP JSON-RPC stdio adapter is not an interactive PTY application, and some
|
||||
integrations distribute those surfaces as different packages and binaries.
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
spec: docs/specs/cli-mode-parity/spec.md
|
||||
created: 2026-08-16
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Implementation Plan: Separate Pi Runtime Surfaces
|
||||
|
||||
## Overview
|
||||
|
||||
Pi's built-in definition assigns `npx -y pi-acp` to both structured ACP
|
||||
execution and interactive passthrough. Registry metadata confirms that
|
||||
`pi-acp` publishes the ACP adapter binary, while
|
||||
`@earendil-works/pi-coding-agent` publishes the interactive `pi` binary. The
|
||||
repair keeps the ACP adapter on structured and inference paths, launches `pi`
|
||||
for passthrough, and makes installation and discovery agree on that executable.
|
||||
|
||||
The durable managed-runtime boundary is recorded in
|
||||
[`docs/decisions/2026-08-12-validated-managed-runtime-version-selection.md`](../../decisions/2026-08-12-validated-managed-runtime-version-selection.md),
|
||||
and the observable behavior is specified in
|
||||
[`docs/specs/cli-mode-parity/spec.md`](../../specs/cli-mode-parity/spec.md) and
|
||||
[`docs/specs/agents/runtime-updates.md`](../../specs/agents/runtime-updates.md).
|
||||
|
||||
---
|
||||
|
||||
## Backend
|
||||
|
||||
### Pi agent definition
|
||||
|
||||
- Update `apps/backend/internal/agent/agents/pi_acp.go` so
|
||||
`BuildCommand`, `Runtime().Cmd`, and `InferenceConfig().Command` remain
|
||||
`npx -y pi-acp`.
|
||||
- Change `PassthroughConfig.PassthroughCmd` to the globally installed `pi`
|
||||
executable. Do not route the passthrough path through managed ACP package or
|
||||
version resolution.
|
||||
- Make `IsInstalled` probe `pi`, the executable provisioned for users and
|
||||
required by passthrough, with a non-interactive `--version` check instead of
|
||||
accepting an adapter-only `pi-acp` installation or an unrelated `pi`
|
||||
executable that cannot satisfy the full integration.
|
||||
- Change `InstallScript` to the supplied safe install recipe:
|
||||
`npm install -g --ignore-scripts @earendil-works/pi-coding-agent`.
|
||||
|
||||
### Public documentation
|
||||
|
||||
- Update `docs/public/agents-and-profiles.md` to identify `pi` as Pi's detected
|
||||
and passthrough executable, document the exact install command, and explain
|
||||
that structured sessions continue through `pi-acp`.
|
||||
- Clarify the Pi entry in `README.md` so the supported-agent table does not
|
||||
imply that the ACP adapter is also the interactive CLI.
|
||||
|
||||
## Tests
|
||||
|
||||
- **What:** Structured Pi chat and inference remain on `npx -y pi-acp`, while
|
||||
`PassthroughCmd` is exactly `pi`; the install recipe and detection binary
|
||||
match the interactive package.
|
||||
**File:** `apps/backend/internal/agent/agents/new_acp_agents_test.go`.
|
||||
**How:** Change the Pi row in the shared command-surface contract before the
|
||||
production edit. Confirm the command, installation, and detection tests fail
|
||||
for the reported mismatch, then pass after the repair.
|
||||
- **What:** The lifecycle's real Pi passthrough resolution, including MCP
|
||||
project-file materialization, returns `pi` rather than the ACP adapter.
|
||||
**File:**
|
||||
`apps/backend/internal/agent/runtime/lifecycle/manager_passthrough_test.go`.
|
||||
**How:** Extend `TestPassthroughPiWritesProjectFile` to assert the resolved
|
||||
command argv as well as the existing `.pi/mcp.json` contract. This covers the
|
||||
registry-to-lifecycle passthrough path where a future managed-runtime change
|
||||
could otherwise reintroduce the conflation.
|
||||
|
||||
No browser E2E is needed because the settings UI and passthrough terminal UI do
|
||||
not change; the behavior is the backend command selected behind the existing
|
||||
profile mode.
|
||||
|
||||
## Verification Results
|
||||
|
||||
- Red: the focused Go contract run failed on Pi's old passthrough command and
|
||||
install script, as expected.
|
||||
- Green: the focused Go command, including the `pi --version` collision
|
||||
regression, passed with 43 tests across the agents and lifecycle packages.
|
||||
- PR fixup: the detection probe now uses `WithCommandCheck("pi", "--version")`
|
||||
and restores the rationale comment for the remaining binary-name tradeoff.
|
||||
- Public docs: `node --test scripts/validate-public-docs.test.mjs` passed all
|
||||
61 tests, `node scripts/validate-public-docs.mjs` validated 41 pages, and
|
||||
`git diff --check` passed.
|
||||
|
||||
## Implementation Tasks
|
||||
|
||||
- [x] [task-01-correct-pi-execution-surfaces](task-01-correct-pi-execution-surfaces.md)
|
||||
|
||||
Execution is sequential in the primary conversation. There are no parallel
|
||||
candidates for this single vertical repair.
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
id: "01-correct-pi-execution-surfaces"
|
||||
title: "Correct Pi execution surfaces"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
spec: "../../specs/cli-mode-parity/spec.md"
|
||||
---
|
||||
|
||||
# Task 01: Correct Pi Execution Surfaces
|
||||
|
||||
## Intent
|
||||
|
||||
Keep Pi's ACP JSON-RPC adapter on structured execution surfaces while launching
|
||||
the separately distributed interactive `pi` CLI for passthrough. Align host
|
||||
installation and discovery with the executable users actually run.
|
||||
|
||||
## Inputs
|
||||
|
||||
- `docs/specs/cli-mode-parity/spec.md`, sections **ACP and passthrough commands
|
||||
remain distinct** and the three Pi scenarios.
|
||||
- `docs/specs/agents/runtime-updates.md`, managed-runtime command-routing
|
||||
boundary.
|
||||
- `docs/decisions/2026-08-12-validated-managed-runtime-version-selection.md`,
|
||||
amended ACP-only ownership decision.
|
||||
- Existing agent pattern: `apps/backend/internal/agent/agents/claude_acp.go`
|
||||
keeps its managed ACP package separate from its native passthrough CLI.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Files Likely Touched
|
||||
|
||||
- `apps/backend/internal/agent/agents/pi_acp.go`
|
||||
- `apps/backend/internal/agent/agents/new_acp_agents_test.go`
|
||||
- `apps/backend/internal/agent/runtime/lifecycle/manager_passthrough_test.go`
|
||||
- `docs/public/agents-and-profiles.md`
|
||||
- `README.md`
|
||||
- `docs/plans/pi-runtime-surfaces/plan.md`
|
||||
- `docs/plans/pi-runtime-surfaces/task-01-correct-pi-execution-surfaces.md`
|
||||
|
||||
## TDD Sequence
|
||||
|
||||
1. Change the Pi expectations in `new_acp_agents_test.go` to require
|
||||
`PassthroughCmd == ["pi"]`, detection through `pi --version`, and the exact install
|
||||
script
|
||||
`npm install -g --ignore-scripts @earendil-works/pi-coding-agent`.
|
||||
2. Extend `TestPassthroughPiWritesProjectFile` to require the lifecycle-resolved
|
||||
passthrough argv to be `["pi"]` while preserving the MCP file assertions.
|
||||
3. Run the targeted Go command and confirm it fails because production still
|
||||
returns `npx -y pi-acp` and the old install/detection contract.
|
||||
4. Apply the minimal `pi_acp.go` changes. Do not change structured ACP or
|
||||
inference argv.
|
||||
5. Update the public Pi installation and command-surface documentation.
|
||||
6. Run the exact verification block and record every result below and in
|
||||
`plan.md`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- Structured `BuildCommand`, `Runtime().Cmd`, and one-shot inference remain
|
||||
`npx -y pi-acp`.
|
||||
- Passthrough lifecycle command resolution returns `pi`, including the path
|
||||
that materializes Pi's project MCP configuration.
|
||||
- Pi discovery requires `pi`, and installation runs exactly
|
||||
`npm install -g --ignore-scripts @earendil-works/pi-coding-agent`; discovery
|
||||
rejects a same-named executable that fails the non-interactive version check.
|
||||
- Public docs explain the separate ACP adapter and interactive CLI without
|
||||
implying that managed ACP version selection controls passthrough.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```bash
|
||||
cd apps/backend && go test ./internal/agent/agents ./internal/agent/runtime/lifecycle -run 'Test(NewACPAgents_(AllCommandSurfaces|InstallScript|DetectionRequiresGlobalBinary)|PiACPDetectionRejectsPiBinaryWithoutVersionSupport|PassthroughPiWritesProjectFile)$' -count=1 && cd ../../ && node --test scripts/validate-public-docs.test.mjs && node scripts/validate-public-docs.mjs && git diff --check
|
||||
```
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`. The agent definition, shared contract fixture, lifecycle
|
||||
regression, and documentation describe one coupled behavior.
|
||||
|
||||
## Risks
|
||||
|
||||
- Hosts that have only a global `pi-acp` adapter will become correctly
|
||||
unavailable until the interactive Pi package is installed; this is required
|
||||
because adapter-only installation cannot run passthrough.
|
||||
- The package is installed with `--ignore-scripts` exactly as reported. The
|
||||
implementation must not relax or remove that safety flag.
|
||||
- No package version-management support is added for `pi-acp` in this repair.
|
||||
|
||||
## Output Contract
|
||||
|
||||
Report the root-cause fix, files changed, red/green command results, public-doc
|
||||
validation, blockers, remaining risks, and synchronized task/plan status in the
|
||||
primary conversation.
|
||||
|
||||
## Results
|
||||
|
||||
- Red: the focused Go contract run failed on the old Pi passthrough argv and
|
||||
install script before the production change.
|
||||
- Green: the focused Go command passed with 43 tests across the agents and
|
||||
lifecycle packages, including the collision regression for `pi --version`.
|
||||
- Public docs validation passed: 61 validation tests, 41 published pages, and
|
||||
`git diff --check`.
|
||||
- The lifecycle regression preserves Pi's existing `--model default` profile
|
||||
flag while proving the executable is `pi` and the `.pi/mcp.json` file is
|
||||
materialized.
|
||||
- PR fixup: restored the `pi` collision rationale and validated the package's
|
||||
non-interactive version flag with the repository's `WithCommandCheck` helper.
|
||||
@@ -24,6 +24,19 @@ The production registry currently shows Auggie, Claude, Codex, Copilot, Gemini,
|
||||
|
||||
Hermes launches with `hermes acp`. Install the required `hermes` executable from its **Settings > Agents** card, which runs the official Hermes installer. Hermes currently supports task and workspace sessions. Office-assigned skill injection is not yet supported.
|
||||
|
||||
### Pi command surfaces
|
||||
|
||||
Pi uses separate executables for its two Kandev modes:
|
||||
|
||||
- Structured ACP sessions and one-shot inference use `npx -y pi-acp`.
|
||||
- CLI Passthrough starts the globally installed `pi` executable.
|
||||
- The Pi install action runs `npm install -g --ignore-scripts @earendil-works/pi-coding-agent`.
|
||||
|
||||
After installation, select **Rescan**. Kandev detects Pi when `pi` is on the
|
||||
`PATH` of the backend process and responds to the non-interactive `--version`
|
||||
check. The `pi-acp` adapter is not the interactive terminal CLI, and managed
|
||||
ACP runtime selection does not replace the passthrough command.
|
||||
|
||||
1. Select **Rescan** after installing or updating a CLI.
|
||||
2. If the card offers an install action, review the command before running it. Installation runs on the Kandev host.
|
||||
3. If the card reports that login is required, open its login terminal or authenticate the CLI as the same operating-system user that runs Kandev.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
status: approved
|
||||
created: 2026-07-26
|
||||
updated: 2026-08-12
|
||||
updated: 2026-08-16
|
||||
owner: Kandev
|
||||
---
|
||||
|
||||
@@ -40,6 +40,10 @@ broken release again.
|
||||
metadata. A caller can submit only a version returned by the trusted
|
||||
package's npm metadata. Tags, prereleases, package specs, registry URLs, and
|
||||
shell text are rejected.
|
||||
- Managed runtime resolution changes only the structured ACP command surfaces.
|
||||
When an agent's interactive passthrough CLI is distributed separately from
|
||||
its ACP adapter, passthrough keeps its own package, executable, and install
|
||||
recipe.
|
||||
- Jobs for one agent are idempotent while queued or running. Installation and
|
||||
version management for the same agent cannot run concurrently.
|
||||
|
||||
@@ -197,6 +201,8 @@ version while its current probe is unknown produces a repair job.
|
||||
sessionless utility prompts use the same active-version resolver.
|
||||
- Native-binary preference continues to win when an agent deliberately selects
|
||||
its supported native binary path.
|
||||
- Passthrough command construction does not receive or apply the active managed
|
||||
ACP version. It continues to use the agent's declared interactive CLI.
|
||||
- SSH and container command builders receive no host version override.
|
||||
- A saved selection read error fails the new host command with an actionable
|
||||
error. It does not fall back to an unversioned package.
|
||||
@@ -271,6 +277,10 @@ version while its current probe is unknown produces a repair job.
|
||||
and does not run a second candidate concurrently.
|
||||
- **GIVEN** an SSH or container session, **WHEN** the host active version
|
||||
changes, **THEN** that executor's command remains unchanged.
|
||||
- **GIVEN** an agent whose interactive passthrough CLI is separate from its
|
||||
managed ACP adapter, **WHEN** the host active ACP version changes, **THEN**
|
||||
later passthrough sessions still launch the declared interactive CLI and do
|
||||
not launch the ACP package under a PTY.
|
||||
- **GIVEN** a phone viewport and a long version catalogue or process log,
|
||||
**WHEN** the operator selects and activates a version, **THEN** the drawer
|
||||
remains contained and the primary action remains touch-reachable.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
status: draft
|
||||
created: 2026-05-16
|
||||
updated: 2026-08-16
|
||||
owner: cfl
|
||||
issue: https://github.com/kdlbs/kandev/issues/906
|
||||
needs-upgrade: true
|
||||
@@ -22,6 +23,21 @@ This spec brings CLI-passthrough mode up to feature parity with ACP for the **ka
|
||||
|
||||
## What
|
||||
|
||||
### ACP and passthrough commands remain distinct
|
||||
|
||||
A built-in agent that uses a separate ACP adapter and interactive CLI keeps
|
||||
those execution surfaces separate. Structured chat and one-shot inference use
|
||||
the ACP adapter. CLI passthrough launches the interactive CLI directly under
|
||||
the PTY; managed ACP runtime resolution does not replace that passthrough
|
||||
command.
|
||||
|
||||
For Pi, structured chat and inference use `npx -y pi-acp`, while CLI
|
||||
passthrough launches the globally installed `pi` executable. Kandev's Pi
|
||||
install action runs
|
||||
`npm install -g --ignore-scripts @earendil-works/pi-coding-agent`, and agent
|
||||
discovery treats a `pi` executable on the Kandev process `PATH` that passes its
|
||||
non-interactive `--version` check as the installation signal.
|
||||
|
||||
### Prompt allowed at task creation in CLI mode
|
||||
|
||||
The task-create dialog's prompt textarea is **enabled** when a CLI/passthrough-capable agent is selected. Users can write the prompt the same way they would for ACP. The control flow that today gates this off when `cli_passthrough` is true is removed.
|
||||
@@ -58,6 +74,25 @@ Users can still press Ctrl-C directly inside the xterm terminal. A dedicated too
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Pi uses its interactive CLI in passthrough mode
|
||||
- GIVEN a Pi profile with `cli_passthrough: true` and a `pi` executable on the
|
||||
Kandev process `PATH` that passes `pi --version`
|
||||
- WHEN Kandev starts its passthrough PTY
|
||||
- THEN the command starts with `pi`
|
||||
- AND Kandev does not launch `pi-acp` or `npx` as the passthrough process
|
||||
|
||||
### Pi keeps its ACP adapter for structured execution
|
||||
- GIVEN a Pi profile with `cli_passthrough: false`
|
||||
- WHEN Kandev starts structured chat or one-shot inference
|
||||
- THEN the command remains `npx -y pi-acp`
|
||||
|
||||
### Pi installation provisions the passthrough executable
|
||||
- GIVEN Pi is unavailable on the Kandev host
|
||||
- WHEN the operator runs the Pi install action and rescans agents
|
||||
- THEN Kandev runs
|
||||
`npm install -g --ignore-scripts @earendil-works/pi-coding-agent`
|
||||
- AND discovery finds the installed `pi` executable after its version check
|
||||
|
||||
### CLI-mode task can have a prompt
|
||||
- GIVEN a Claude profile with `cli_passthrough: true`
|
||||
- WHEN the user opens the task-create dialog and types in the prompt field
|
||||
@@ -161,6 +196,7 @@ Pressing Ctrl-C inside the passthrough terminal writes `\x03` to PTY stdin. A fu
|
||||
- Parsing PTY output into `task_messages` (transcriber). The terminal panel shows live output; the chat transcript only shows user-sent text in CLI mode.
|
||||
- Billing-type / subscription-quota badge or DTO surface. That belongs to `subscription-usage.md`.
|
||||
- Adding passthrough support to agents that don't have it (`Supported: false`).
|
||||
- Adding `pi-acp` to the managed runtime update catalogue.
|
||||
- Migrating away from the current ACP bridge.
|
||||
- Headless `-p` mode for Claude (drains API credit; we deliberately do not use it).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user