174 lines
7.8 KiB
Markdown
174 lines
7.8 KiB
Markdown
---
|
|
spec: docs/specs/agents/requirements/runtime-updates.md
|
|
created: 2026-07-27
|
|
status: complete
|
|
---
|
|
|
|
# Implementation Plan: Agent Runtime Update Dialog
|
|
|
|
## Overview
|
|
|
|
PR #1950 placed retained update state, versions, output, and results directly
|
|
inside installed-agent cards. It also configured PR previews with
|
|
`KANDEV_MOCK_AGENT=only`, which intentionally removes every real agent from the
|
|
registry and therefore leaves the install catalogue empty. This repair restores
|
|
the preview catalogue, adds a read-only update-preview contract, and moves the
|
|
approval and ephemeral streaming lifecycle into a responsive dialog.
|
|
|
|
## Confirmed root causes
|
|
|
|
- `apps/backend/cmd/preview/sprite_ops.go` exports
|
|
`KANDEV_MOCK_AGENT=only`. `registry.Provide` treats `only` as an isolated E2E
|
|
mode and registers only `mock-agent`; `ListAvailableAgents` can only return
|
|
registry entries, so Settings receives no real install candidates.
|
|
- `AgentRuntimeUpdateControl` is rendered inside `InstalledAgentCard`, so all
|
|
versions, output, and terminal state expand the card.
|
|
- `useAgentRuntimeUpdates` calls `listAgentUpdateJobs` on mount and upserts
|
|
retained backend jobs into the global Settings store, explicitly restoring
|
|
output and terminal state after a page restart.
|
|
- The only preparation path is `POST /agent-update/:agentName`; target-version
|
|
resolution happens after enqueue, so the UI cannot show the next version and
|
|
exact command before mutation.
|
|
|
|
## Backend
|
|
|
|
### Preview environment catalogue
|
|
|
|
Change `buildExtractScript` in
|
|
`apps/backend/cmd/preview/sprite_ops.go` to use
|
|
`KANDEV_MOCK_AGENT=true`. That mode retains the enabled mock agent while loading
|
|
the built-in real-agent catalogue, allowing unavailable agents with install
|
|
scripts to appear in Settings. Update the focused script assertion in
|
|
`apps/backend/cmd/preview/sprite_ops_test.go`; keep the registry mode test as
|
|
supporting evidence that `true` loads defaults and `only` does not.
|
|
|
|
### Read-only update preview
|
|
|
|
Add `AgentUpdatePreviewDTO` in
|
|
`apps/backend/internal/agent/settings/dto/dto.go` with agent, package, current
|
|
version, target version, argv, and display command fields.
|
|
|
|
Add `Controller.PreviewAgentUpdate(ctx, name)` in
|
|
`apps/backend/internal/agent/settings/controller/agent_update.go`. It validates
|
|
the same built-in `ManagedNPMRuntimeAgent` boundary as enqueue, reads the current
|
|
capability version, resolves the upstream target through `RuntimeUpdater`, and
|
|
serializes `CacheUpdateCommand()` with the existing `buildCommandString`
|
|
helper. Extend that helper to preserve empty argv entries as `""`, so the
|
|
displayed recipe remains an exact representation of the direct argv command.
|
|
It never claims maintenance state, creates a job, or executes the update command.
|
|
|
|
Register `GET /api/v1/agent-update/:agentName/preview` and a focused handler in
|
|
`apps/backend/internal/agent/settings/handlers/handlers.go`. Reuse the existing
|
|
update error classification for not-found, unsupported, unavailable, and
|
|
version-resolution failures.
|
|
|
|
## Frontend
|
|
|
|
### API and page-local update lifecycle
|
|
|
|
Add `AgentUpdatePreview` and `previewAgentUpdate` to
|
|
`apps/web/lib/api/domains/agent-update-api.ts`.
|
|
|
|
Refactor `useAgentRuntimeUpdates` so it does not list or hydrate retained update
|
|
jobs on mount. Starting an update returns or binds the accepted job identity for
|
|
the currently open dialog; WebSocket snapshots and chunks may continue using
|
|
the existing bounded Settings store, but the dialog displays only the job
|
|
started or recovered during its current page-local interaction.
|
|
|
|
### Installed-agent card and responsive update surface
|
|
|
|
Replace the inline `AgentRuntimeUpdateControl` composition with a compact
|
|
icon-only trigger in `apps/web/components/settings/installed-agent-card.tsx`.
|
|
The icon remains visually small while its standalone hitbox is at least 44px
|
|
and has an agent-specific accessible label and tooltip. Unmanaged agents omit
|
|
the trigger.
|
|
|
|
Replace `agent-runtime-update-control.tsx` with a responsive update surface:
|
|
|
|
- Desktop uses a centered `Dialog`.
|
|
- Phone uses an inset bottom `Drawer`, following
|
|
`components/kanban/mobile-menu-sheet.tsx`, because this is a temporary,
|
|
single-purpose approval flow rather than a primary route.
|
|
- Header and approval/dismiss actions remain fixed; one `min-h-0 flex-1
|
|
overflow-y-auto` body owns scrolling and clears the bottom safe area.
|
|
- Opening fetches the read-only preview and shows current/target versions,
|
|
host-only scope, automatic capability refresh, unchanged active sessions,
|
|
and the exact wrapping command.
|
|
- Approval is disabled until preview succeeds and is the only action that
|
|
sends the update POST.
|
|
- After approval, the same surface shows phase, bounded stdout/stderr, terminal
|
|
result, and retry. Closing or restarting the page discards the UI selection
|
|
and presentation state.
|
|
- No update information is rendered in the card.
|
|
|
|
### Public documentation
|
|
|
|
Update `docs/public/agents-and-profiles.md` to describe the icon-triggered
|
|
preview and approval flow, the exact-command disclosure, dialog-only streaming,
|
|
and the intentionally ephemeral browser presentation. The preview launcher
|
|
environment change is internal and does not need public environment-variable
|
|
documentation.
|
|
|
|
## Tests
|
|
|
|
- **Preview catalogue mode:** change `TestBuildExtractScript` first and confirm
|
|
it fails while the script still exports `only`, then make it pass with
|
|
`true`. File: `apps/backend/cmd/preview/sprite_ops_test.go`.
|
|
- **Read-only preview:** controller tests prove current/target/command output,
|
|
empty-argument display, unmanaged rejection, registry failure, and absence
|
|
of update execution.
|
|
File:
|
|
`apps/backend/internal/agent/settings/controller/agent_update_test.go`.
|
|
- **Exact display command:** extend the existing table test for
|
|
`buildCommandString` with an empty argument. File:
|
|
`apps/backend/internal/agent/settings/controller/controller_test.go`.
|
|
- **Preview handler:** handler tests prove the GET response and errors while
|
|
preserving POST enqueue behavior. File:
|
|
`apps/backend/internal/agent/settings/handlers/agent_update_handlers_test.go`.
|
|
- **Ephemeral state helper behavior:** retain focused Settings slice/WS tests
|
|
for bounded same-job output merging, and remove the retained-job hydration
|
|
expectation from the hook path. Files:
|
|
`apps/web/lib/state/slices/settings/settings-slice.test.ts` and
|
|
`apps/web/lib/ws/handlers/agents.test.ts`.
|
|
- **Public docs:** run `node --test scripts/validate-public-docs.test.mjs` and
|
|
`node scripts/validate-public-docs.mjs`.
|
|
|
|
## E2E Tests
|
|
|
|
- **Desktop approval:** opening the card icon shows versions, explanation, and
|
|
exact command while POST count remains zero; approving starts one job and
|
|
streams output/result inside the dialog.
|
|
- **Restart reset:** after progress or a terminal result, restarting the page
|
|
leaves only the icon on the card; a newly opened dialog contains a fresh
|
|
preview and no prior output/result.
|
|
- **Mobile parity:** the Pixel 5 flow taps the 44px icon, uses the bottom
|
|
drawer, reads the preview before approval, streams a long output without
|
|
document horizontal overflow, and reaches the fixed final actions.
|
|
|
|
Files:
|
|
|
|
- `apps/web/e2e/tests/settings/agent-runtime-update.spec.ts`
|
|
- `apps/web/e2e/tests/settings/mobile-agent-runtime-update.spec.ts`
|
|
- `apps/web/e2e/tests/settings/agent-runtime-update-helpers.ts`
|
|
|
|
## Implementation Waves And Parallel Candidates
|
|
|
|
Execution is sequential in the primary conversation. No subagents are
|
|
authorized.
|
|
|
|
Wave 1:
|
|
|
|
- [x] [Task 01: Restore the preview install catalogue](task-01-preview-catalogue.md)
|
|
- [x] [Task 02: Add the read-only update preview API](task-02-update-preview-api.md)
|
|
|
|
Wave 2:
|
|
|
|
- [x] [Task 03: Move updates into an ephemeral responsive dialog](task-03-update-dialog-ui.md)
|
|
|
|
Wave 3:
|
|
|
|
- [x] [Task 04: Verify desktop and mobile update flows](task-04-update-dialog-e2e.md)
|
|
|
|
Tasks 01 and 02 touch disjoint files, but remain sequential unless the user
|
|
explicitly authorizes subagents after the model checkpoint.
|