@gkorepanov/ccodex 0.5.0-rc.2 → 0.5.0-rc.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +156 -157
- package/claude/chat-formatting.md +25 -0
- package/config/compatibility.json +1 -1
- package/dist/claude/commandActions.d.ts +2 -0
- package/dist/claude/commandActions.js +43 -24
- package/dist/claude/commandActions.js.map +1 -1
- package/dist/claude/delegation.d.ts +10 -0
- package/dist/claude/delegation.js +41 -0
- package/dist/claude/delegation.js.map +1 -0
- package/dist/claude/native/catalog.d.ts +14 -0
- package/dist/claude/native/catalog.js +52 -17
- package/dist/claude/native/catalog.js.map +1 -1
- package/dist/claude/native/history.d.ts +8 -1
- package/dist/claude/native/history.js +43 -19
- package/dist/claude/native/history.js.map +1 -1
- package/dist/claude/native/pages.d.ts +54 -0
- package/dist/claude/native/pages.js +271 -0
- package/dist/claude/native/pages.js.map +1 -0
- package/dist/claude/native/projector.d.ts +18 -2
- package/dist/claude/native/projector.js +104 -46
- package/dist/claude/native/projector.js.map +1 -1
- package/dist/claude/native/records.d.ts +2 -0
- package/dist/claude/native/records.js +35 -13
- package/dist/claude/native/records.js.map +1 -1
- package/dist/claude/native/search.d.ts +7 -0
- package/dist/claude/native/search.js +79 -0
- package/dist/claude/native/search.js.map +1 -0
- package/dist/claude/native/summary.d.ts +6 -1
- package/dist/claude/native/summary.js +24 -6
- package/dist/claude/native/summary.js.map +1 -1
- package/dist/claude/peers.d.ts +4 -0
- package/dist/claude/peers.js +19 -5
- package/dist/claude/peers.js.map +1 -1
- package/dist/claude/processes.d.ts +2 -0
- package/dist/claude/processes.js +15 -0
- package/dist/claude/processes.js.map +1 -1
- package/dist/claude/sdk.d.ts +8 -2
- package/dist/claude/sdk.js +23 -6
- package/dist/claude/sdk.js.map +1 -1
- package/dist/claude/session.d.ts +34 -7
- package/dist/claude/session.js +184 -72
- package/dist/claude/session.js.map +1 -1
- package/dist/claude/threads.d.ts +61 -3
- package/dist/claude/threads.js +408 -100
- package/dist/claude/threads.js.map +1 -1
- package/dist/claude/toolMapper.d.ts +23 -3
- package/dist/claude/toolMapper.js +50 -1
- package/dist/claude/toolMapper.js.map +1 -1
- package/dist/cli/args.js +2 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +7 -3
- package/dist/config.js.map +1 -1
- package/dist/daemon/daemon.d.ts +3 -0
- package/dist/daemon/daemon.js +6 -3
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/supervisor.d.ts +8 -0
- package/dist/daemon/supervisor.js +15 -7
- package/dist/daemon/supervisor.js.map +1 -1
- package/dist/desktop/stdioFrontend.js +1 -1
- package/dist/desktop/stdioFrontend.js.map +1 -1
- package/dist/gateway/catalog.js +35 -20
- package/dist/gateway/catalog.js.map +1 -1
- package/dist/gateway/connection.js +2 -2
- package/dist/gateway/connection.js.map +1 -1
- package/dist/gateway/lineage.d.ts +29 -1
- package/dist/gateway/lineage.js +260 -38
- package/dist/gateway/lineage.js.map +1 -1
- package/dist/gateway/remote.js +3 -8
- package/dist/gateway/remote.js.map +1 -1
- package/dist/gateway/server.d.ts +2 -1
- package/dist/gateway/server.js +26 -13
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/status.d.ts +15 -5
- package/dist/gateway/status.js +142 -47
- package/dist/gateway/status.js.map +1 -1
- package/dist/gateway/stock.js +17 -2
- package/dist/gateway/stock.js.map +1 -1
- package/dist/management/commands.d.ts +2 -0
- package/dist/management/commands.js +66 -3
- package/dist/management/commands.js.map +1 -1
- package/dist/meta.d.ts +39 -11
- package/dist/meta.js +59 -28
- package/dist/meta.js.map +1 -1
- package/dist/protocol/codex.d.ts +1 -3
- package/dist/protocol/codex.js +1 -4
- package/dist/protocol/codex.js.map +1 -1
- package/dist/protocol/turnPagination.d.ts +35 -2
- package/dist/protocol/turnPagination.js +53 -28
- package/dist/protocol/turnPagination.js.map +1 -1
- package/examples/config.toml +2 -2
- package/package.json +5 -4
- package/scripts/migrate-0.4-to-0.5.mjs +31 -20
|
@@ -16,14 +16,22 @@ interface Page<T> {
|
|
|
16
16
|
nextCursor: string | null;
|
|
17
17
|
backwardsCursor: string | null;
|
|
18
18
|
}
|
|
19
|
+
interface AnchorCursor {
|
|
20
|
+
anchor: string;
|
|
21
|
+
includeAnchor: boolean;
|
|
22
|
+
}
|
|
23
|
+
type CursorKey = "turnId" | "itemId";
|
|
19
24
|
export declare function turnCursor(turnId: string, includeAnchor: boolean): string;
|
|
20
25
|
export declare function itemCursor(itemId: string, includeAnchor: boolean): string;
|
|
26
|
+
export declare function anchorCursor(key: CursorKey, cursor: string): AnchorCursor | undefined;
|
|
21
27
|
/** The agent item stock treats as a turn's final answer: latest final_answer, else a phase-less message on a finished turn. */
|
|
22
28
|
export declare function finalAgentItem(turn: Turn): ThreadItem | undefined;
|
|
23
29
|
/** `itemsView: "summary"`: the first user message and the final agent message, in rollout order. Stock's live view of a running turn shows its latest agent message regardless of phase. */
|
|
24
30
|
export declare function summaryItems(turn: Turn): ThreadItem[];
|
|
25
|
-
export declare function paginateTurns(turns: readonly Turn[], params: TurnsListParams
|
|
26
|
-
|
|
31
|
+
export declare function paginateTurns(turns: readonly Turn[], params: TurnsListParams): Page<Turn>;
|
|
32
|
+
/** The turn as a turns page shows it (`itemsView`, default summary). */
|
|
33
|
+
export declare function turnView(turn: Turn, itemsView: TurnsListParams["itemsView"]): Turn;
|
|
34
|
+
export declare function paginateItems(turns: readonly Turn[], params: ItemsListParams): Page<{
|
|
27
35
|
turnId: string;
|
|
28
36
|
item: ThreadItem;
|
|
29
37
|
}>;
|
|
@@ -34,4 +42,29 @@ export declare function historyCursors(turns: readonly Turn[]): {
|
|
|
34
42
|
turnsBackwardsCursor: string | null;
|
|
35
43
|
itemsBackwardsCursor: string | null;
|
|
36
44
|
};
|
|
45
|
+
interface Occurrence {
|
|
46
|
+
turnId: string;
|
|
47
|
+
itemId: string;
|
|
48
|
+
snippet: string;
|
|
49
|
+
snippetMatchRange: {
|
|
50
|
+
start: number;
|
|
51
|
+
end: number;
|
|
52
|
+
};
|
|
53
|
+
turnCursor: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Stock's `thread/searchOccurrences` (codex-rs thread-store `search.rs`) over turns, oldest first: every match of the
|
|
57
|
+
* term, any case, in user messages and each turn's final agent message, with the 49 characters before it and 96
|
|
58
|
+
* after; the match range counts UTF-16 units, as JavaScript does.
|
|
59
|
+
*/
|
|
60
|
+
export declare function turnOccurrences(turns: readonly Turn[], term: string): Occurrence[];
|
|
61
|
+
/** A `thread/searchOccurrences` page of all occurrences (50 by default, at most 250). */
|
|
62
|
+
export declare function occurrencesPage<T>(all: readonly T[], params: {
|
|
63
|
+
searchTerm?: string;
|
|
64
|
+
cursor?: string | null;
|
|
65
|
+
limit?: number | null;
|
|
66
|
+
}): {
|
|
67
|
+
data: T[];
|
|
68
|
+
nextCursor: string | null;
|
|
69
|
+
};
|
|
37
70
|
export {};
|
|
@@ -8,7 +8,7 @@ export function turnCursor(turnId, includeAnchor) {
|
|
|
8
8
|
export function itemCursor(itemId, includeAnchor) {
|
|
9
9
|
return encodeCursor("itemId", itemId, includeAnchor);
|
|
10
10
|
}
|
|
11
|
-
function anchorCursor(key, cursor) {
|
|
11
|
+
export function anchorCursor(key, cursor) {
|
|
12
12
|
try {
|
|
13
13
|
const parsed = JSON.parse(cursor);
|
|
14
14
|
if (typeof parsed[key] === "string" && typeof parsed.includeAnchor === "boolean") {
|
|
@@ -20,15 +20,8 @@ function anchorCursor(key, cursor) {
|
|
|
20
20
|
}
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
-
function legacyOffset(cursor, prefixes) {
|
|
24
|
-
const prefix = prefixes.find((candidate) => cursor.startsWith(candidate));
|
|
25
|
-
if (!prefix)
|
|
26
|
-
return undefined;
|
|
27
|
-
const offset = Number(cursor.slice(prefix.length));
|
|
28
|
-
return Number.isInteger(offset) && offset >= 0 ? offset : undefined;
|
|
29
|
-
}
|
|
30
23
|
/** Stock-style anchor pagination over a chronological list: cursors name an entry and whether it is included. */
|
|
31
|
-
function paginate(entries, key, idOf, params,
|
|
24
|
+
function paginate(entries, key, idOf, params, defaultDirection, selected = () => true) {
|
|
32
25
|
if (entries.length === 0)
|
|
33
26
|
return { data: [], nextCursor: null, backwardsCursor: null };
|
|
34
27
|
const direction = params.sortDirection ?? defaultDirection;
|
|
@@ -37,6 +30,8 @@ function paginate(entries, key, idOf, params, legacyPrefixes, defaultDirection,
|
|
|
37
30
|
keyed.reverse();
|
|
38
31
|
// Like stock, anchors are positions in the whole list; `selected` (e.g. a turn filter) applies on top.
|
|
39
32
|
const anchor = params.cursor ? anchorCursor(key, params.cursor) : undefined;
|
|
33
|
+
if (params.cursor && !anchor)
|
|
34
|
+
throw invalidRequest(`invalid cursor: ${params.cursor}`);
|
|
40
35
|
if (anchor) {
|
|
41
36
|
const anchorIndex = entries.findIndex((entry) => idOf(entry) === anchor.anchor);
|
|
42
37
|
if (anchorIndex < 0)
|
|
@@ -46,12 +41,6 @@ function paginate(entries, key, idOf, params, legacyPrefixes, defaultDirection,
|
|
|
46
41
|
: anchor.includeAnchor ? index <= anchorIndex : index < anchorIndex);
|
|
47
42
|
}
|
|
48
43
|
keyed = keyed.filter(({ entry }) => selected(entry));
|
|
49
|
-
if (params.cursor && !anchor) {
|
|
50
|
-
const offset = legacyOffset(params.cursor, legacyPrefixes);
|
|
51
|
-
if (offset === undefined)
|
|
52
|
-
throw invalidRequest(`invalid cursor: ${params.cursor}`);
|
|
53
|
-
keyed = keyed.slice(offset);
|
|
54
|
-
}
|
|
55
44
|
const limit = Math.max(1, Math.min(params.limit ?? 25, 100));
|
|
56
45
|
const page = keyed.slice(0, limit).map(({ entry }) => entry);
|
|
57
46
|
return {
|
|
@@ -72,21 +61,18 @@ export function summaryItems(turn) {
|
|
|
72
61
|
const final = turn.status === "inProgress" ? turn.items.findLast((item) => item.type === "agentMessage") : finalAgentItem(turn);
|
|
73
62
|
return turn.items.filter((item) => item === first || item === final);
|
|
74
63
|
}
|
|
75
|
-
export function paginateTurns(turns, params
|
|
76
|
-
const page = paginate(turns, "turnId", (turn) => turn.id, params,
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
...page,
|
|
80
|
-
data: page.data.map((turn) => ({
|
|
81
|
-
...turn,
|
|
82
|
-
itemsView,
|
|
83
|
-
items: itemsView === "notLoaded" ? [] : itemsView === "summary" ? summaryItems(turn) : turn.items,
|
|
84
|
-
})),
|
|
85
|
-
};
|
|
64
|
+
export function paginateTurns(turns, params) {
|
|
65
|
+
const page = paginate(turns, "turnId", (turn) => turn.id, params, "desc");
|
|
66
|
+
return { ...page, data: page.data.map((turn) => turnView(turn, params.itemsView)) };
|
|
86
67
|
}
|
|
87
|
-
|
|
68
|
+
/** The turn as a turns page shows it (`itemsView`, default summary). */
|
|
69
|
+
export function turnView(turn, itemsView) {
|
|
70
|
+
const view = itemsView ?? "summary";
|
|
71
|
+
return { ...turn, itemsView: view, items: view === "notLoaded" ? [] : view === "summary" ? summaryItems(turn) : turn.items };
|
|
72
|
+
}
|
|
73
|
+
export function paginateItems(turns, params) {
|
|
88
74
|
const entries = turns.flatMap((turn) => turn.items.map((item) => ({ turnId: turn.id, item })));
|
|
89
|
-
return paginate(entries, "itemId", (entry) => entry.item.id, params,
|
|
75
|
+
return paginate(entries, "itemId", (entry) => entry.item.id, params, "asc", (entry) => !params.turnId || entry.turnId === params.turnId);
|
|
90
76
|
}
|
|
91
77
|
/** The turn shape stock returns from `turn/start` and announces in `turn/started`: no items, `notLoaded`; items follow via `item/started`. */
|
|
92
78
|
export function startedTurn(turn) {
|
|
@@ -100,4 +86,43 @@ export function historyCursors(turns) {
|
|
|
100
86
|
itemsBackwardsCursor: lastItem ? itemCursor(lastItem.id, true) : null,
|
|
101
87
|
};
|
|
102
88
|
}
|
|
89
|
+
/** What stock searches in an agent message: its text without markdown (links read as their labels). */
|
|
90
|
+
function plainText(markdown) {
|
|
91
|
+
return markdown.replace(/!?\[([^\]]*)\]\([^)]*\)/gu, "$1").replace(/[*_`#>|~]+/gu, " ").split(/\s+/u).filter(Boolean).join(" ");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Stock's `thread/searchOccurrences` (codex-rs thread-store `search.rs`) over turns, oldest first: every match of the
|
|
95
|
+
* term, any case, in user messages and each turn's final agent message, with the 49 characters before it and 96
|
|
96
|
+
* after; the match range counts UTF-16 units, as JavaScript does.
|
|
97
|
+
*/
|
|
98
|
+
export function turnOccurrences(turns, term) {
|
|
99
|
+
const needle = term.toLowerCase();
|
|
100
|
+
return turns.flatMap((turn) => {
|
|
101
|
+
const final = finalAgentItem(turn);
|
|
102
|
+
return turn.items.filter((item) => item.type === "userMessage" || item === final).flatMap((item) => {
|
|
103
|
+
const text = item.type === "userMessage" ? item.content.flatMap((input) => input.type === "text" ? [input.text] : []).join("")
|
|
104
|
+
: plainText(String(item.text));
|
|
105
|
+
const found = [];
|
|
106
|
+
for (let at = text.toLowerCase().indexOf(needle); at >= 0; at = text.toLowerCase().indexOf(needle, at + needle.length)) {
|
|
107
|
+
const before = [...text.slice(0, at)];
|
|
108
|
+
const after = [...text.slice(at + needle.length)];
|
|
109
|
+
const head = before.slice(Math.max(0, before.length - 49)).join("");
|
|
110
|
+
const lead = before.length > 49 ? "... " : "";
|
|
111
|
+
const start = lead.length + head.length;
|
|
112
|
+
found.push({
|
|
113
|
+
turnId: turn.id, itemId: item.id, turnCursor: turnCursor(turn.id, true),
|
|
114
|
+
snippet: `${lead}${head}${text.slice(at, at + needle.length)}${after.slice(0, 96).join("")}${after.length > 96 ? " ..." : ""}`,
|
|
115
|
+
snippetMatchRange: { start, end: start + needle.length },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return found;
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** A `thread/searchOccurrences` page of all occurrences (50 by default, at most 250). */
|
|
123
|
+
export function occurrencesPage(all, params) {
|
|
124
|
+
const from = params.cursor ? Number(JSON.parse(params.cursor).index) : 0;
|
|
125
|
+
const limit = Math.max(1, Math.min(params.limit ?? 50, 250));
|
|
126
|
+
return { data: all.slice(from, from + limit), nextCursor: from + limit < all.length ? JSON.stringify({ searchTerm: params.searchTerm, index: from + limit }) : null };
|
|
127
|
+
}
|
|
103
128
|
//# sourceMappingURL=turnPagination.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turnPagination.js","sourceRoot":"","sources":["../../src/protocol/turnPagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA8B,MAAM,YAAY,CAAC;AAaxE,SAAS,YAAY,CAAC,GAAc,EAAE,MAAc,EAAE,aAAsB;IAC1E,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,aAAsB;IAC/D,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,aAAsB;IAC/D,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AACvD,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"turnPagination.js","sourceRoot":"","sources":["../../src/protocol/turnPagination.ts"],"names":[],"mappings":"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"}
|
package/examples/config.toml
CHANGED
|
@@ -17,6 +17,6 @@ Return only the title.
|
|
|
17
17
|
# model_prefix = "claude:"
|
|
18
18
|
|
|
19
19
|
log_level = "info"
|
|
20
|
-
# Codex App RPC capture under data_dir (rpc.jsonl, mode 0600, rolling).
|
|
21
|
-
rpc_capture =
|
|
20
|
+
# Codex App RPC capture under data_dir (rpc.jsonl, mode 0600, rolling; holds prompts and outputs). Off by default.
|
|
21
|
+
rpc_capture = false
|
|
22
22
|
rpc_capture_max_bytes = 1073741824
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gkorepanov/ccodex",
|
|
3
|
-
"version": "0.5.0-rc.
|
|
3
|
+
"version": "0.5.0-rc.21",
|
|
4
4
|
"description": "Unofficial Codex App compatibility bridge for Codex CLI and Claude Code runtimes.",
|
|
5
5
|
"homepage": "https://github.com/gkorepanov/ccodex#readme",
|
|
6
6
|
"repository": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"scripts/install-claude-stack.sh",
|
|
34
34
|
"agents/*.md",
|
|
35
35
|
"skills/**/*.md",
|
|
36
|
+
"claude/chat-formatting.md",
|
|
36
37
|
"examples/config.toml",
|
|
37
38
|
"legal/LICENSES.md",
|
|
38
39
|
"legal/THIRD_PARTY_NOTICES.md",
|
|
@@ -65,9 +66,9 @@
|
|
|
65
66
|
"ws": "8.21.0"
|
|
66
67
|
},
|
|
67
68
|
"optionalDependencies": {
|
|
68
|
-
"@gkorepanov/ccodex-relay-darwin-arm64": "0.5.0-rc.
|
|
69
|
-
"@gkorepanov/ccodex-relay-linux-arm64-gnu": "0.5.0-rc.
|
|
70
|
-
"@gkorepanov/ccodex-relay-linux-x64-gnu": "0.5.0-rc.
|
|
69
|
+
"@gkorepanov/ccodex-relay-darwin-arm64": "0.5.0-rc.21",
|
|
70
|
+
"@gkorepanov/ccodex-relay-linux-arm64-gnu": "0.5.0-rc.21",
|
|
71
|
+
"@gkorepanov/ccodex-relay-linux-x64-gnu": "0.5.0-rc.21"
|
|
71
72
|
},
|
|
72
73
|
"devDependencies": {
|
|
73
74
|
"@openai/codex": "0.156.0",
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
// One-off migration of CCodex 0.4 state (state.sqlite + handoffs.sqlite) to 0.5's meta.json. `ccodex setup` runs it
|
|
3
3
|
// once, before it activates 0.5 (0.4's state.sqlite is there, meta.json is not). `--dry-run` only prints what it would do.
|
|
4
4
|
//
|
|
5
|
-
// -
|
|
6
|
-
//
|
|
5
|
+
// - 0.4 thread ids go: a Claude thread is listed under its Claude session id, a provider-switch lineage (a segment
|
|
6
|
+
// list) under its first segment, a fork whose 0.4 id was no backend under its current backend.
|
|
7
|
+
// - 0.4 side chats (/btw, full Claude forks) are no chats: their sessions are archived, without a 0.4 id.
|
|
7
8
|
// - Archive flags, sections and section order of Claude threads carry over; names go into the transcripts.
|
|
8
9
|
// - Claude threads whose transcript Claude's cleanup deleted (cleanupPeriodDays, 30 by default) get one back from the
|
|
9
10
|
// 0.4 turns: prompts and answers as text, without tool calls, reasoning or compactions. Claude resumes it as such.
|
|
10
11
|
// - A lineage is archived when its current backend was (0.4 archived sealed stock backends to hide them); 0.5 reads
|
|
11
12
|
// the flag from the row's backend, so that one is set to match, stock ones through `codex app-server`.
|
|
12
|
-
// SQLite files are only read. meta.json is backed up before it is replaced.
|
|
13
|
+
// SQLite files are only read, then moved to ~/.ccodex.0.4-backup. meta.json is backed up before it is replaced.
|
|
13
14
|
import { spawn } from "node:child_process";
|
|
14
15
|
import { randomUUID } from "node:crypto";
|
|
15
|
-
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, utimesSync, writeFileSync } from "node:fs";
|
|
16
|
+
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, utimesSync, writeFileSync } from "node:fs";
|
|
16
17
|
import { homedir } from "node:os";
|
|
17
18
|
import { dirname, join } from "node:path";
|
|
18
19
|
import { createInterface } from "node:readline";
|
|
@@ -51,13 +52,14 @@ const claudeThreads = new Map(state.prepare(`select id, claude_session_id, archi
|
|
|
51
52
|
json_extract(thread_json, '$.parentThreadId') parent, json_extract(thread_json, '$.name') name,
|
|
52
53
|
json_extract(thread_json, '$.section') section, json_extract(thread_json, '$.sectionEnteredAt') section_entered_at
|
|
53
54
|
from threads`).all().map((row) => [row.id, row]));
|
|
55
|
+
const sides = new Set(handoffs?.prepare("select public_thread_id from side_threads").all().map((row) => row.public_thread_id));
|
|
54
56
|
|
|
55
57
|
// A turn's last record takes the uuid 0.4 kept for it, so provider-switch segments still end at that turn.
|
|
56
58
|
for (const thread of state.prepare(`select id, claude_session_id, cwd, claude_code_version, coalesce(resolved_model, claude_model_value) model
|
|
57
59
|
from threads where claude_session_id is not null and deletion_pending = 0
|
|
58
60
|
and json_extract(thread_json, '$.parentThreadId') is null`).all()) {
|
|
59
61
|
const sessionId = thread.claude_session_id;
|
|
60
|
-
if (transcripts.has(sessionId)) continue;
|
|
62
|
+
if (transcripts.has(sessionId) || sides.has(thread.id)) continue;
|
|
61
63
|
const lines = [];
|
|
62
64
|
let parentUuid = null;
|
|
63
65
|
let at = 0;
|
|
@@ -70,13 +72,13 @@ for (const thread of state.prepare(`select id, claude_session_id, cwd, claude_co
|
|
|
70
72
|
};
|
|
71
73
|
for (const row of state.prepare("select turn_json, last_claude_message_uuid last from turns where thread_id = ? order by ordinal").all(thread.id)) {
|
|
72
74
|
const turn = JSON.parse(row.turn_json);
|
|
73
|
-
const messageId = `msg_${randomUUID().replaceAll("-", "")}`;
|
|
74
75
|
const start = lines.length;
|
|
75
76
|
for (const item of turn.items) {
|
|
76
77
|
if (item.type === "userMessage") {
|
|
77
78
|
add({ type: "user", message: { role: "user", content: item.content.map((part) => part.text).join("\n") } }, turn.startedAt);
|
|
78
79
|
} else if (item.type === "agentMessage" && item.text) {
|
|
79
|
-
|
|
80
|
+
// Each message its own API message: one shared id would group them across the turn's steers.
|
|
81
|
+
add({ type: "assistant", message: { id: `msg_${randomUUID().replaceAll("-", "")}`, type: "message", role: "assistant", model: thread.model,
|
|
80
82
|
content: [{ type: "text", text: item.text }], stop_reason: "end_turn", usage: { input_tokens: 0, output_tokens: 0 } } }, turn.completedAt ?? turn.startedAt);
|
|
81
83
|
}
|
|
82
84
|
}
|
|
@@ -102,6 +104,8 @@ function claudeTurnId(threadId, turnId) {
|
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
const lineages = {};
|
|
107
|
+
/** 0.4 public id → the id 0.5 lists its lineage under. */
|
|
108
|
+
const publicIds = new Map();
|
|
105
109
|
const lineageBackends = new Set();
|
|
106
110
|
let skipped = 0;
|
|
107
111
|
if (handoffs) {
|
|
@@ -127,12 +131,13 @@ if (handoffs) {
|
|
|
127
131
|
lastTurnId: last || !end ? null : claudeTurnId(epoch.backend_thread_id, end),
|
|
128
132
|
};
|
|
129
133
|
});
|
|
130
|
-
// 0.5 names a fork by its current backend; a lineage started from a thread
|
|
134
|
+
// 0.5 names a fork by its current backend; a lineage started from a thread goes by that thread's backend.
|
|
131
135
|
// Stock never lists threads without a user message of their own (0.4 made such forks); those take the current id.
|
|
132
136
|
const unlisted = segments[0].provider === "codex"
|
|
133
137
|
&& stock.prepare("select first_user_message from threads where id = ?").get(segments[0].threadId)?.first_user_message === "";
|
|
134
|
-
const publicId = parts[0].epoch.backend_thread_id === task.public_thread_id && !unlisted ?
|
|
135
|
-
if (publicId !==
|
|
138
|
+
const publicId = parts[0].epoch.backend_thread_id === task.public_thread_id && !unlisted ? segments[0].threadId : segments.at(-1).threadId;
|
|
139
|
+
if (publicId !== segments[0].threadId) log(`${unlisted ? "unlisted" : "fork"} ${task.public_thread_id} is now ${publicId}`);
|
|
140
|
+
publicIds.set(task.public_thread_id, publicId);
|
|
136
141
|
if (segments.length === 1 && segments[0].threadId === publicId) continue;
|
|
137
142
|
lineages[publicId] = segments;
|
|
138
143
|
}
|
|
@@ -144,8 +149,9 @@ const named = [];
|
|
|
144
149
|
for (const thread of claudeThreads.values()) {
|
|
145
150
|
const sessionId = thread.claude_session_id;
|
|
146
151
|
if (thread.deletion_pending || thread.parent || !transcripts.has(sessionId)) continue;
|
|
147
|
-
if (
|
|
148
|
-
|
|
152
|
+
if (sides.has(thread.id)) {
|
|
153
|
+
archived.add(sessionId);
|
|
154
|
+
continue;
|
|
149
155
|
}
|
|
150
156
|
if (thread.archived) archived.add(sessionId);
|
|
151
157
|
if (thread.section) sections[sessionId] = { sectionId: JSON.parse(thread.section).id, enteredAt: thread.section_entered_at ?? thread.updated_at };
|
|
@@ -165,7 +171,7 @@ for (const { backend_thread_id: id } of handoffs?.prepare("select backend_thread
|
|
|
165
171
|
|
|
166
172
|
const archived04 = new Set([...claudeThreads.values()].filter((thread) => thread.archived).map((thread) => thread.claude_session_id));
|
|
167
173
|
for (const [publicId, segments] of Object.entries(lineages)) {
|
|
168
|
-
const row = segments.find((segment) => segment.threadId === publicId)
|
|
174
|
+
const row = segments.find((segment) => segment.threadId === publicId);
|
|
169
175
|
const isArchived = (segment) => segment.provider === "codex"
|
|
170
176
|
? stock.prepare("select archived from threads where id = ?").get(segment.threadId)?.archived === 1
|
|
171
177
|
: archived04.has(segment.threadId);
|
|
@@ -200,11 +206,9 @@ async function stockRequests(requests) {
|
|
|
200
206
|
child.kill();
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
/** A 0.4 id as 0.5 lists it
|
|
209
|
+
/** A 0.4 id as 0.5 lists it. */
|
|
204
210
|
function rowId(id) {
|
|
205
|
-
|
|
206
|
-
if (segments) return (segments.find((segment) => segment.threadId === id) ?? segments[0]).threadId;
|
|
207
|
-
return claudeThreads.get(id)?.claude_session_id ?? id;
|
|
211
|
+
return publicIds.get(id) ?? claudeThreads.get(id)?.claude_session_id ?? id;
|
|
208
212
|
}
|
|
209
213
|
// Older 0.4 states predate section orders.
|
|
210
214
|
const sectionOrders = state.prepare("select 1 from sqlite_master where type = 'table' and name = 'section_orders'").get()
|
|
@@ -217,11 +221,9 @@ const meta = {
|
|
|
217
221
|
archived: [...new Set([...archived, ...(existing.archived ?? [])])],
|
|
218
222
|
sections: { ...sections, ...existing.sections },
|
|
219
223
|
sectionOrder: { ...sectionOrder, ...existing.sectionOrder },
|
|
220
|
-
leaves: existing.leaves ?? {},
|
|
221
224
|
};
|
|
222
225
|
|
|
223
|
-
|
|
224
|
-
log(`lineages: ${Object.keys(lineages).length} (${aliases} kept 0.4 Claude ids, ${Object.keys(lineages).length - aliases} provider switches), skipped ${skipped}`);
|
|
226
|
+
log(`lineages: ${Object.keys(lineages).length}, skipped ${skipped}`);
|
|
225
227
|
log(`restored transcripts: ${restored.size}`);
|
|
226
228
|
log(`archived: ${archived.size}, stock archive changes: ${stockArchives.length}, in sections: ${Object.keys(sections).length}, section orders: ${Object.keys(sectionOrder).length}, names to write: ${named.length}`);
|
|
227
229
|
if (dryRun) {
|
|
@@ -240,4 +242,13 @@ for (const { sessionId, name } of named) {
|
|
|
240
242
|
}
|
|
241
243
|
// Claude lists sessions by their file's time: a restored one keeps its place.
|
|
242
244
|
for (const [sessionId, { at }] of restored) utimesSync(transcripts.get(sessionId), at, at);
|
|
245
|
+
// 0.4's databases go out of the way: nothing reads them, and setup migrates only while state.sqlite is there.
|
|
246
|
+
state.close();
|
|
247
|
+
handoffs?.close();
|
|
248
|
+
const backup = `${home}.0.4-backup`;
|
|
249
|
+
mkdirSync(backup, { recursive: true, mode: 0o700 });
|
|
250
|
+
for (const name of readdirSync(stateDir).filter((name) => /^(state|handoffs)\.sqlite|^backups$|^cursor\.key$/.test(name))) {
|
|
251
|
+
renameSync(join(stateDir, name), join(backup, name));
|
|
252
|
+
}
|
|
253
|
+
log(`moved 0.4's databases to ${backup}`);
|
|
243
254
|
log(`wrote ${metaPath}. Restart the gateway: codex app-server daemon restart`);
|