Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bafbb21
refactor(server): share Claude and Pi transcript projections
ScriptedAlchemy Nov 12, 2026
d1ca880
feat(contracts): describe discovered external history sources
ScriptedAlchemy Nov 12, 2026
5477f47
refactor(server): unify local external history search and paging
ScriptedAlchemy Nov 12, 2026
7a264be
feat(server): discover Claude Pi and OpenCode external history
ScriptedAlchemy Nov 12, 2026
74b3e40
feat(clients): lead external history with discovered conversations
ScriptedAlchemy Nov 12, 2026
e627fee
fix(server): one external history search request keeps going until it…
ScriptedAlchemy Nov 12, 2026
8109415
fix(server): external history hides sessions T3 already owns, matched…
ScriptedAlchemy Nov 12, 2026
10bd7f8
fix(server): search large histories and skip malformed records
ScriptedAlchemy Nov 12, 2026
01d3ad3
fix(clients): follow empty external history pages automatically
ScriptedAlchemy Nov 12, 2026
a42a914
refactor: remove the typed ChatGPT export path source from external h…
ScriptedAlchemy Nov 13, 2026
8c7a22e
docs: portable handoffs names the sources external history finds
ScriptedAlchemy Nov 13, 2026
8e267c3
fix(history): audit native search and retain full legacy export removal
ScriptedAlchemy Nov 13, 2026
f2c52b2
fix(history): preserve paging consistency and isolate broken sources
ScriptedAlchemy Nov 13, 2026
d3e9981
fix(history): encode the search listing digest without JSON.stringify
ScriptedAlchemy Nov 13, 2026
0ee3007
Merge remote-tracking branch 'origin/main' into t3/external-history-l…
ScriptedAlchemy Nov 13, 2026
582802c
Merge remote-tracking branch 'origin/main' into t3/external-history-l…
ScriptedAlchemy Nov 14, 2026
ce43a26
fix(mobile): external history search field stays above the keyboard
ScriptedAlchemy Nov 14, 2026
cf6ddc2
test(server): JSONL history store tests pass on macOS temp paths
ScriptedAlchemy Nov 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,25 @@ const ref = {
digest: "a".repeat(64),
};
vi.mock("../../state/query", () => ({
useEnvironmentQuery: (request: ExternalHistoryRequest) => {
useEnvironmentQuery: (request: ExternalHistoryRequest | null) => {
if (request === null)
return { data: null, error: null, isPending: false, isSuccess: false, refresh: vi.fn() };
state.requests.push(request);
const data: ExternalHistoryResponse =
request.operation === "sources"
? {
operation: "sources",
enabled: true,
sources: [{ id: "codex-history", label: "Native Codex", kind: "codex" }],
sources: [
{
id: "codex-history",
label: "Native Codex",
kind: "codex",
capabilities: { cwdFilter: true, archived: true },
status: "ready",
},
],
unsupported: [],
}
: request.operation === "search"
? {
Expand Down Expand Up @@ -148,7 +159,7 @@ vi.mock("../../state/query", () => ({
totalChars: 33,
nextTextOffset: request.textOffset ? null : 16,
};
return { data, error: null, isPending: false, refresh: vi.fn() };
return { data, error: null, isPending: false, isSuccess: true, refresh: vi.fn() };
},
}));

Expand All @@ -158,7 +169,7 @@ const configFor = (supported: boolean, enabled = true) => ({
environment: { capabilities: supported ? { externalHistory: 1 as const } : {} },
settings: {
...DEFAULT_SERVER_SETTINGS,
externalHistory: { enabled, chatGptExportPaths: ["/remote/export.json"] },
externalHistory: { enabled },
},
});

Expand Down Expand Up @@ -200,9 +211,6 @@ it("keeps remote history read-only without settings permission and stops reads w
expect(container.textContent).toContain("Update this server");
act(() => registry.set(config, configFor(true)));
expect(button("Allow external history search").disabled).toBe(true);
expect(
container.querySelector<HTMLInputElement>('[aria-label="ChatGPT export paths"]')?.disabled,
).toBe(true);
const input = container.querySelector<HTMLInputElement>(
'[aria-label="Search external history"]',
)!;
Expand All @@ -212,8 +220,6 @@ it("keeps remote history read-only without settings permission and stops reads w
});
await click("This project");
await click("Search");
expect(container.textContent).toContain("No matches on this page. Continue");
await click("Continue search");
expect(container.textContent).toContain("Compiler investigation");
expect(state.requests).toContainEqual({
operation: "search",
Expand All @@ -229,7 +235,7 @@ it("keeps remote history read-only without settings permission and stops reads w
expect(container.textContent).toContain("Second exact page");
expect(container.textContent).not.toContain("First exact page");
await click("Search");
expect(container.textContent).toContain("No matches on this page. Continue");
expect(container.textContent).toContain("Compiler investigation");
expect(container.textContent).not.toContain("Second exact page");
expect(state.update).not.toHaveBeenCalled();
act(() => registry.set(config, configFor(true, false)));
Expand Down
Loading
Loading