chat-logbook 0.12.0 → 0.14.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,8 +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.
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.
47
+ - **Filter by tag or project.** Narrow the chat list to a project, or to chats that carry all of several selected tags.
45
48
 
46
49
  ## Quick start
47
50
 
@@ -109,13 +112,9 @@ No. chat-logbook reads files those tools write on your machine. It doesn't talk
109
112
 
110
113
  ## Roadmap
111
114
 
112
- Two phases of work are in flight, in this order.
113
-
114
- **Custom titles and tags.** Rename a chat to something you'll recognize, attach tags with custom colors, and filter the list by tag or by project. This is the path from "I have a lot of conversations" to "I can find the one I need."
115
-
116
115
  **Spotlight search.** A keyboard-driven overlay (`⌘K` or `/`) that searches across chats, messages, tags, and projects from one input. A match lands you on the exact message with the term highlighted, and you can jump between every match without leaving the overlay.
117
116
 
118
- Beyond these three, several smaller things are on the list without firm timing — live updates while an AI tool is writing, annotations and highlights for marking what matters, editing your own past messages, CLI commands for working with conversations from a terminal. Some will ship; some are still being weighed.
117
+ Beyond this, several smaller things are on the list without firm timing — live updates while an AI tool is writing, annotations and highlights for marking what matters, editing your own past messages, CLI commands for working with conversations from a terminal. Some will ship; some are still being weighed.
119
118
 
120
119
  Explicit non-goals: semantic / vector search, cloud sync inside the OSS core, modification of source directories like `~/.claude/`, and bulk export to bespoke formats (the archive itself is the export). See the [PRD](docs/PRD.md) for the full out-of-scope list.
121
120
 
@@ -0,0 +1,16 @@
1
+ CREATE TABLE `tags` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `name` text NOT NULL,
4
+ `color` text NOT NULL,
5
+ `created_at` integer NOT NULL,
6
+ `updated_at` integer NOT NULL
7
+ );
8
+ --> statement-breakpoint
9
+ CREATE TABLE `chat_tags` (
10
+ `chat_id` text NOT NULL,
11
+ `tag_id` text NOT NULL,
12
+ PRIMARY KEY(`chat_id`, `tag_id`),
13
+ FOREIGN KEY (`tag_id`) REFERENCES `tags`(`id`) ON UPDATE no action ON DELETE cascade
14
+ );
15
+ --> statement-breakpoint
16
+ CREATE INDEX `chat_tags_tag_id_idx` ON `chat_tags` (`tag_id`);
@@ -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 @@
1
+ CREATE INDEX `chats_project_idx` ON `chats` (`project`);
@@ -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`);
@@ -57,6 +57,27 @@
57
57
  "when": 1779200000000,
58
58
  "tag": "0007_drop_session_scan_state",
59
59
  "breakpoints": true
60
+ },
61
+ {
62
+ "idx": 8,
63
+ "version": "6",
64
+ "when": 1779300000000,
65
+ "tag": "0008_add_chats_project_idx",
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
60
81
  }
61
82
  ]
62
83
  }
@@ -29,6 +29,27 @@
29
29
  "when": 1779500000000,
30
30
  "tag": "0003_add_deleted_at",
31
31
  "breakpoints": true
32
+ },
33
+ {
34
+ "idx": 4,
35
+ "version": "6",
36
+ "when": 1780000000000,
37
+ "tag": "0004_add_tags",
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
32
53
  }
33
54
  ]
34
55
  }