fix(tui): restored image attachments on /tree and esc-esc branch

- branch() and navigateTree() now return the selected user message's image
  parts (selectedImages/editorImages) alongside the text, extracted in marker
  order by #extractUserMessageImages.
- CustomEditor.setDraft() replaces the composer draft with text plus its
  pending images, so restored [Image #N] markers resolve on resubmit instead
  of degrading to literal text.
- Wired all six restore call sites (selector-controller, extension-ui-controller)
  through setDraft; updated rpc-subagents mocks for the new branch shape.
- Added offline regression tests for branch/navigateTree image restitution,
  multi-image marker order, and text-only prompts.
This commit is contained in:
can1357
2026-07-28 00:57:34 +02:00
parent 7760f853d3
commit cfd335d2b1
8 changed files with 174 additions and 14 deletions
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import type { ImageContent } from "@oh-my-pi/pi-ai";
import { RpcClient } from "@oh-my-pi/pi-coding-agent/modes/rpc/rpc-client";
import {
handleRpcSessionChange,
@@ -70,14 +71,15 @@ function createRegistryWithSnapshot(): RpcSubagentRegistry {
type SessionChangeStubOptions = {
newSession?: boolean;
switchSession?: boolean;
branch?: { selectedText: string; cancelled: boolean };
branch?: { selectedText: string; selectedImages: ImageContent[]; cancelled: boolean };
};
function createSessionChangeSession(options: SessionChangeStubOptions): RpcSessionChangeSession {
return {
newSession: async (_options?: unknown) => options.newSession ?? true,
switchSession: async (_sessionPath: string) => options.switchSession ?? true,
branch: async (_entryId: string) => options.branch ?? { selectedText: "branched text", cancelled: false },
branch: async (_entryId: string) =>
options.branch ?? { selectedText: "branched text", selectedImages: [], cancelled: false },
};
}
@@ -208,7 +210,9 @@ describe("RPC subagent registry", () => {
},
{
command: { type: "branch", entryId: "entry-1" },
session: createSessionChangeSession({ branch: { selectedText: "Branch text", cancelled: false } }),
session: createSessionChangeSession({
branch: { selectedText: "Branch text", selectedImages: [], cancelled: false },
}),
expected: { type: "branch", data: { text: "Branch text", cancelled: false } },
},
];
@@ -247,7 +251,7 @@ describe("RPC subagent registry", () => {
},
{
command: { type: "branch", entryId: "entry-1" },
session: createSessionChangeSession({ branch: { selectedText: "", cancelled: true } }),
session: createSessionChangeSession({ branch: { selectedText: "", selectedImages: [], cancelled: true } }),
expected: { type: "branch", data: { text: "", cancelled: true } },
},
];