ccrecall 0.0.5 → 0.0.6

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.
Files changed (3) hide show
  1. package/README.md +8 -4
  2. package/package.json +1 -1
  3. package/src/db.ts +27 -1
package/README.md CHANGED
@@ -63,10 +63,14 @@ bun src/index.ts stats
63
63
 
64
64
  ### Commands
65
65
 
66
- | Command | Description |
67
- | ------- | ------------------------------------------ |
68
- | `sync` | Import transcripts and teams (incremental) |
69
- | `stats` | Show session/message/team/token counts |
66
+ | Command | Description |
67
+ | ---------- | ------------------------------------------ |
68
+ | `sync` | Import transcripts and teams (incremental) |
69
+ | `stats` | Show session/message/team/token counts |
70
+ | `sessions` | List recent sessions |
71
+ | `search` | Full-text search across messages |
72
+ | `tools` | Show most-used tools |
73
+ | `query` | Execute raw SQL against the database |
70
74
 
71
75
  ### Options
72
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccrecall",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Sync Claude Code transcripts to SQLite and recall context from past sessions",
5
5
  "type": "module",
6
6
  "bin": {
package/src/db.ts CHANGED
@@ -142,6 +142,32 @@ CREATE TRIGGER IF NOT EXISTS messages_fts_update AFTER UPDATE ON messages BEGIN
142
142
  END;
143
143
  `;
144
144
 
145
+ /**
146
+ * Escape a search term for FTS5 MATCH queries.
147
+ * Handles special characters while preserving prefix (*) and phrase ("") searches.
148
+ */
149
+ function escape_fts5_query(term: string): string {
150
+ // If already a phrase query (wrapped in quotes), just escape internal quotes
151
+ if (term.startsWith('"') && term.endsWith('"')) {
152
+ return term;
153
+ }
154
+
155
+ // Check for prefix search (ends with *)
156
+ const is_prefix = term.endsWith('*');
157
+ const base_term = is_prefix ? term.slice(0, -1) : term;
158
+
159
+ // FTS5 special chars that cause syntax errors
160
+ const has_special = /[/\-:()^]/.test(base_term);
161
+
162
+ if (!has_special && !base_term.includes('"')) {
163
+ return term; // Safe as-is
164
+ }
165
+
166
+ // Escape by wrapping in quotes (double internal quotes)
167
+ const escaped = `"${base_term.replace(/"/g, '""')}"`;
168
+ return is_prefix ? escaped + '*' : escaped;
169
+ }
170
+
145
171
  export class Database {
146
172
  private db: BunDB;
147
173
  private stmt_upsert_session: Statement;
@@ -490,7 +516,7 @@ export class Database {
490
516
  JOIN sessions s ON s.id = m.session_id
491
517
  WHERE messages_fts MATCH ?
492
518
  `;
493
- const params: (string | number)[] = [term];
519
+ const params: (string | number)[] = [escape_fts5_query(term)];
494
520
 
495
521
  if (options.project) {
496
522
  query += ` AND s.project_path LIKE ?`;