chat-logbook 0.13.0 → 0.15.0

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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  A local-first library for the conversations you've had with your AI tools. Read by chat-logbook, kept on your machine, browsable and searchable in one place — even after your AI tool has deleted the original.
6
6
 
7
- > **Status.** A personal side project, moving at side-project pace — development and responses happen as time allows. Early release: browsing, rendering, soft-delete, and a local archive that survives vendor cleanup all work today. Search and tags are next. See [Roadmap](#roadmap).
7
+ > **Status.** A personal side project, moving at side-project pace — development and responses happen as time allows. Early release: browsing, rendering, tags, soft-delete, and a local archive that survives vendor cleanup all work today. Search is next. See [Roadmap](#roadmap).
8
8
 
9
9
  ## What chat-logbook is
10
10
 
@@ -33,6 +33,7 @@ The full problem statement, user stories, and direction live in the [PRD](docs/P
33
33
  and conversation content.
34
34
  - **Rich conversation rendering.** Markdown, syntax-highlighted code blocks, collapsible tool calls with one-line summaries, and collapsible thinking blocks.
35
35
  - **Virtual scrolling.** Long conversations scroll smoothly.
36
+ - **A chat list that scales.** The list loads on demand as you scroll and stays fast even with tens of thousands of chats.
36
37
  - **Solarized Dark theme.** Easy on the eyes, consistent with Claude
37
38
  Code's terminal look.
38
39
  - **Soft delete with Trash.** Hide chats you don't want to see; restore
@@ -40,10 +41,10 @@ The full problem statement, user stories, and direction live in the [PRD](docs/P
40
41
  - **Sortable lists.** Sort your chats by title, created time, or updated time, and the choice sticks between visits. Trash sorts independently — by deleted time by default.
41
42
  - **Custom chat titles.** Rename any chat — click its title in the list or conversation header, or select it and press `F2` / `↵`. Clear the title to fall back to the first message.
42
43
  - **Local archive.** Every conversation chat-logbook reads is copied into `~/.chat-logbook/archive.db`. The UI reads from the archive, so a chat stays visible even after the source JSONL is gone.
43
- - **Live updates.** While Claude Code is actively writing to a chat, new messages appear in chat-logbook within seconds — no restart needed.
44
+ - **Live updates.** While Claude Code is actively writing to a chat, new messages appear in chat-logbook within seconds — no restart needed. New and changed chats surface in the list on their own, without a manual refresh.
44
45
  - **Chat metadata at a glance.** A ⓘ button on the conversation header opens a popover showing when the chat started, when it was last updated, the agent, the project working directory, and the chat's IDs — with one-click copy.
45
46
  - **Tags.** Create tags, give them colors, and assign them to chats. They show as colored chips on the chat and in the list. Rename or delete them anytime.
46
- - **Filter by tag or project.** Narrow the chat list to a project, or to chats that carry all of several selected tags.
47
+ - **Filter by tag or project.** Narrow the chat list to a project, or to chats by tag match every tag you pick, or any one of them.
47
48
 
48
49
  ## Quick start
49
50
 
@@ -0,0 +1 @@
1
+ CREATE INDEX `chats_meta_deleted_at_idx` ON `chats_meta` (`deleted_at`,`id`) WHERE `deleted_at` IS NOT NULL;
@@ -0,0 +1,7 @@
1
+ CREATE TABLE `chat_sort_keys` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `text_key` text,
4
+ `sort_key` text
5
+ );
6
+ --> statement-breakpoint
7
+ CREATE INDEX `chat_sort_keys_sort_key_idx` ON `chat_sort_keys` (`sort_key`,`id`);
@@ -0,0 +1,21 @@
1
+ -- Denormalized "most recent activity" column for the server-side activity sort
2
+ -- (ADR-0017, issue #129). Nullable on ADD COLUMN, then backfilled below so every
3
+ -- existing row gets a value; new rows are initialized by the ingest write seam.
4
+ ALTER TABLE `chats` ADD COLUMN `updated_at` integer;
5
+ --> statement-breakpoint
6
+ -- Backfill: most recent message ts per chat, falling back to first_seen_at for a
7
+ -- chat that has no messages yet, so updated_at is never NULL.
8
+ UPDATE `chats`
9
+ SET `updated_at` = coalesce(
10
+ (SELECT max(`m`.`ts`)
11
+ FROM `messages` `m`
12
+ WHERE `m`.`agent` = `chats`.`agent`
13
+ AND `m`.`source_id` = `chats`.`source_id`),
14
+ `chats`.`first_seen_at`
15
+ );
16
+ --> statement-breakpoint
17
+ -- Covering keyset indexes: (sortKey, id) so each list sort's ORDER BY + LIMIT is
18
+ -- an index range scan that stops after one page.
19
+ CREATE INDEX `chats_created_keyset_idx` ON `chats` (`first_seen_at`,`id`);
20
+ --> statement-breakpoint
21
+ CREATE INDEX `chats_updated_keyset_idx` ON `chats` (`updated_at`,`id`);
@@ -0,0 +1,26 @@
1
+ -- Denormalized "conversation start" column for the createdAt list sort (issue
2
+ -- #143, reconciling ADR-0017). The createdAt axis must page by what the reader
3
+ -- displays — min(messages.ts) — not first_seen_at (the ingest time), so the
4
+ -- paged order and the shown createdAt agree. Nullable on ADD COLUMN, then
5
+ -- backfilled below so every existing row gets a value; new rows are initialized
6
+ -- by the ingest write seam.
7
+ ALTER TABLE `chats` ADD COLUMN `created_at` integer;
8
+ --> statement-breakpoint
9
+ -- Backfill: earliest message ts per chat, falling back to first_seen_at for a
10
+ -- chat that has no messages yet, so created_at is never NULL and matches the
11
+ -- reader's displayed createdAt (min(messages.ts) ?? first_seen_at).
12
+ UPDATE `chats`
13
+ SET `created_at` = coalesce(
14
+ (SELECT min(`m`.`ts`)
15
+ FROM `messages` `m`
16
+ WHERE `m`.`agent` = `chats`.`agent`
17
+ AND `m`.`source_id` = `chats`.`source_id`),
18
+ `chats`.`first_seen_at`
19
+ );
20
+ --> statement-breakpoint
21
+ -- Repoint the createdAt keyset index from first_seen_at to created_at: the
22
+ -- covering (sortKey, id) so the createdAt ORDER BY + LIMIT stays an index range
23
+ -- scan that stops after one page, in either direction.
24
+ DROP INDEX `chats_created_keyset_idx`;
25
+ --> statement-breakpoint
26
+ CREATE INDEX `chats_created_keyset_idx` ON `chats` (`created_at`,`id`);
@@ -64,6 +64,20 @@
64
64
  "when": 1779300000000,
65
65
  "tag": "0008_add_chats_project_idx",
66
66
  "breakpoints": true
67
+ },
68
+ {
69
+ "idx": 9,
70
+ "version": "6",
71
+ "when": 1779400000000,
72
+ "tag": "0009_add_chats_updated_at",
73
+ "breakpoints": true
74
+ },
75
+ {
76
+ "idx": 10,
77
+ "version": "6",
78
+ "when": 1779500000000,
79
+ "tag": "0010_add_chats_created_at",
80
+ "breakpoints": true
67
81
  }
68
82
  ]
69
83
  }
@@ -36,6 +36,20 @@
36
36
  "when": 1780000000000,
37
37
  "tag": "0004_add_tags",
38
38
  "breakpoints": true
39
+ },
40
+ {
41
+ "idx": 5,
42
+ "version": "6",
43
+ "when": 1780500000000,
44
+ "tag": "0005_add_deleted_at_index",
45
+ "breakpoints": true
46
+ },
47
+ {
48
+ "idx": 6,
49
+ "version": "6",
50
+ "when": 1781000000000,
51
+ "tag": "0006_add_chat_sort_keys",
52
+ "breakpoints": true
39
53
  }
40
54
  ]
41
55
  }