Skip to content

feat(kiloclaw) Admin tools for bulk version deployments#2975

Merged
St0rmz1 merged 6 commits intomainfrom
kiloclaw-bulk-version-change
Apr 30, 2026
Merged

feat(kiloclaw) Admin tools for bulk version deployments#2975
St0rmz1 merged 6 commits intomainfrom
kiloclaw-bulk-version-change

Conversation

@St0rmz1
Copy link
Copy Markdown
Contributor

@St0rmz1 St0rmz1 commented Apr 30, 2026

Summary

Adds bulk version change for kiloclaw instances on the admin instances page. Admins can filter the list by current running version, select multiple rows, and apply a version change synchronously across the selection. Builds on the tracked_image_tag column landed in PR #2942 (populated by the DO alarm reconciler).

Backend (apps/web/src/routers/admin-kiloclaw-instances-router.ts)

  • New bulkChangeVersion admin tRPC mutation. Validates the target image tag against the catalog (rejects unknown and disabled tags), partitions the selection into applied / skipped / failed, applies in parallel with bounded concurrency of 10 via Promise.allSettled. Per call ceiling 500 instances. Three predicate atomic delete (instance_id + id + updated_at) on pin override, mirroring the single instance restartMachine. DO state synced to the cleared pin via the existing pushPinToWorker helper.
  • Skip reasons surfaced in the result: destroyed, pinned_by_user, pinned_by_admin, already_on_target. Failed entries surface per row with the underlying error.
  • Audit log written after the apply loop. New kiloclaw.instances.bulk_change_version action records actor, target tag, override flag, and the partitioned instance ids in metadata.
  • list and get procedures extended with new output fields: tracked_image_tag and pin: { image_tag, pinned_by_user_id, is_admin_pin } | null. list accepts a new optional imageTag filter input with sentinel __unknown__ for null tracked image tags.

Frontend

  • Admin instances page (KiloclawInstancesPage.tsx): version filter dropdown populated from listVersions, checkbox column with select all visible (with indeterminate state when only some visible rows are checked), bulk action toolbar shown when selection is non empty (with a discoverable empty state hint when the selection is empty), Pin column with the canonical translucent /20 badge pattern, Version column pairing the openclaw_version (semver) with the image_tag (technical id) using a memoized lookup against the already fetched catalog.
  • New BulkChangeVersionDialog.tsx: selection summary derived from visible rows, target version select with rich two tone display in the dropdown list (preserved on the trigger via Radix textValue), Override Existing Pins toggle with typed confirm gate, destructive Alert callout warning that the action runs immediately with no user notice and interrupts active sessions, result panel partitioned into Applied / Skipped (grouped by reason) / Failed sections with copy ids buttons.
  • Column reorder per reviewer feedback: User · Version · Pin · Subscription · Status · Created · Sandbox ID · Destroyed. Sandbox ID demoted (muted, mono, text-xs, max width 110px). Type column dropped to reduce density.
  • Page chrome iteration aligned with design.md: six chunky stat cards collapsed into a single Card with horizontal pills using the eyebrow typography ramp, daily chart slimmed into a tighter Card with inline legend, Search button demoted from yellow primary to secondary so the bulk Change Version CTA is the page's earned primary action.
  • Pin badges adopt the canonical bg-{color}-500/20 text-{color}-400 ring-1 ring-{color}-500/20 border-transparent translucent pattern.
  • Local Checkbox wrapper extended to accept checked: boolean | 'indeterminate'. Native HTML checkboxes expose indeterminate only as a DOM property, applied imperatively via ref.

Schema

  • packages/db/src/schema-types.ts: added kiloclaw.instances.bulk_change_version to the KiloClawAdminAuditAction Zod enum.
  • No table or column changes. The tracked_image_tag column landed in PR Kiloclaw tracked image tag #2942.

Verification

  • Manual e2e walkthrough across all partition classes: filter behavior (populated tag, (unknown), all), selection persistence across filter changes, FORBIDDEN guard for non admin caller, single instance happy path, multi instance happy path, user pin skip and override, admin pin skip and override, already on target (UI exclude path), destroyed instance skip, dialog UI edge cases (older version advisory, typed confirm case sensitivity, mid flight cancel disabled, dialog reset on reopen). State verified via direct queries against the local postgres container after each mutating step.
  • pnpm run format:check clean.
  • pnpm run lint (oxlint) clean.
  • pnpm --filter web typecheck clean.
  • pnpm --filter web test admin-kiloclaw-instances-router passes 58 of 58. 12 new tests for bulkChangeVersion cover FORBIDDEN, Zod validation (empty, oversized, malformed), BAD_REQUEST for unknown and disabled tags, mixed batch partitioning, override semantics on user and admin pins, per instance failure isolation via mockResolvedValueOnce / mockRejectedValueOnce, not_found surfacing for non existent instance ids, and audit log emission.

Visual Changes

N/A

Reviewer Notes

  • The override path deletes any existing pin (user or admin). No replacement admin pin is written; affected users can set a new pin afterwards.
  • When the CAS delete misses (pin row replaced in flight by a new user pin), the worker restart still fires. The DB pin row and DO state diverge until the next user initiated restart, which resyncs both via the push on write path from PR fix(kiloclaw): sync admin version pin to instance DO state #2913. The deliberate posture is documented inline in the procedure.
  • The max(500) cap on instanceIds reflects the per page UI selection model. If a future select all across pages feature lands, revisit.
  • Bulk concurrency uses the manual for loop chunking pattern already present in this router (detectOrphans at line ~1832), not p-limit. Same effective bound, lower friction precedent.
  • Frontend does not introduce any non Zod runtime validation. Untrusted boundaries (tRPC inputs) all validate through Zod; component data flows through RouterOutputs types.

Comment thread apps/web/src/routers/admin-kiloclaw-instances-router.ts Outdated
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 30, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Resolved Previous Findings (2)
File Previous Line Resolution
apps/web/src/app/admin/components/KiloclawInstances/BulkChangeVersionDialog.tsx 97 Fixed: target exclusion is skipped when selections include off-page rows.
apps/web/src/routers/admin-kiloclaw-instances-router.ts 1548 Fixed: CAS delete misses now skip with pin_changed_in_flight instead of restarting.
Files Reviewed (2 files)
  • apps/web/src/app/admin/components/KiloclawInstances/BulkChangeVersionDialog.tsx
  • apps/web/src/routers/admin-kiloclaw-instances-router.ts

Fix these issues in Kilo Cloud


Reviewed by gpt-5.5-20260423 · 778,977 tokens

@St0rmz1 St0rmz1 merged commit 2f25366 into main Apr 30, 2026
39 checks passed
@St0rmz1 St0rmz1 deleted the kiloclaw-bulk-version-change branch April 30, 2026 20:43
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.

2 participants