fix: harden and de-slop the merged contribution batch

Follow-ups promised on merge, plus review findings on the batch itself:

- chat: task-tool output now respects the 512KiB render cap; quick-open
  icon is visible at rest on coarse pointers and reachable by keyboard
  (row keydown no longer swallows inner-button Enter/Space); composer
  inline-code decoration drops the metric-shifting padding; a btw fork
  send carries only the boundary instruction, never the promotion notice
- sync: cascade revert/unrevert aborts busy descendants, busy state is
  read from every child store at the moment of use; rule 9 documents
  redo clearing all descendant revert markers
- electron: renderer recovery keeps memory-eviction (a valid
  render-process-gone reason) and both windows share one
  attachRendererRecovery helper
- vscode: process registry is a thin re-export of the web module
  (provider-env-aliases precedent) with ordered register/unregister
  writes and an awaited close
- server/cli: managed-process registry takes injectable deps (fixes the
  unreaped-orphans ReferenceError), corrupt settings errors name the
  file, getWorktrees test restores console.warn
- tests: module-mock harnesses removed (AgentsSidebar, SettingsView
  mobile focus — behaviors stay live but uncovered, accepted trade),
  QuestionMarkdown asserts rendered DOM
- i18n: German gains the debug-panel request keys, Japanese/German drop
  removed worktree keys, Ukrainian unit spacing fixed
- changelog: Copilot AI Credits entries (main + VS Code)
This commit is contained in:
Bohdan Triapitsyn
2026-08-28 02:08:09 +03:00
parent a79aff45c1
commit b8465ae133
33 changed files with 673 additions and 1205 deletions
@@ -2,8 +2,18 @@ import { describe, expect, test } from 'bun:test';
import type { Session } from '@opencode-ai/sdk/v2';
import { buildChildrenIndex, computeSubtreeCost, formatCost } from './subagentCost';
function makeSession(id: string, cost: number, parentID?: string): Session {
return { id, cost, parentID } as unknown as Session;
function makeSession(id: string, cost: number | undefined, parentID?: string): Session {
return {
id,
slug: id,
projectID: 'project',
directory: '/project',
title: id,
version: '1',
time: { created: 0, updated: 0 },
cost,
parentID,
};
}
describe('buildChildrenIndex', () => {
@@ -57,7 +67,7 @@ describe('computeSubtreeCost', () => {
test('treats zero and undefined cost as zero, not a break', () => {
const root = makeSession('root', 0);
const child = { id: 'child', parentID: 'root' } as unknown as Session;
const child = makeSession('child', undefined, 'root');
const sessions = [root, child];
const sessionsById = new Map(sessions.map((s) => [s.id, s]));
const childrenByParent = buildChildrenIndex(sessions);
@@ -17,7 +17,7 @@ export const formatCost = (cost: number): string => `$${trimZeros(cost.toFixed(4
export function buildChildrenIndex(sessions: Session[]): Map<string, Session[]> {
const index = new Map<string, Session[]>();
for (const session of sessions) {
const parentID = (session as unknown as { parentID?: string }).parentID;
const parentID = session.parentID;
if (!parentID) continue;
const existing = index.get(parentID);
if (existing) {
@@ -30,8 +30,7 @@ export function buildChildrenIndex(sessions: Session[]): Map<string, Session[]>
}
function sessionCost(session: Session | undefined): number {
const cost = (session as unknown as { cost?: number } | undefined)?.cost;
return typeof cost === 'number' ? cost : 0;
return session?.cost ?? 0;
}
/**
@@ -3,7 +3,17 @@ import type { Session } from '@opencode-ai/sdk/v2';
import { computeRollup } from './useSubagentCostRollup';
function makeSession(id: string, cost: number, parentID?: string): Session {
return { id, cost, parentID } as unknown as Session;
return {
id,
slug: id,
projectID: 'project',
directory: '/project',
title: id,
version: '1',
time: { created: 0, updated: 0 },
cost,
parentID,
};
}
const sessions: Session[] = [