@clauderecallhq/cli 0.12.5 → 0.61.3
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/LICENSE +37 -17
- package/README.md +110 -22
- package/dist/cli.js +1641 -353
- package/dist/daemon/entrypoint.js +1872 -54
- package/dist/mcp-server.js +930 -0
- package/dist/share/fonts/Inter-Bold.woff +0 -0
- package/dist/share/fonts/Inter-Regular.woff +0 -0
- package/dist/share/fonts/JetBrainsMono-Regular.woff +0 -0
- package/dist/web/assets/_brand-Bw9uSB4O.js +1 -0
- package/dist/web/assets/captureNode-9CVj9vYC.js +2 -0
- package/dist/web/assets/card-a-minimal-ujNERzX7.js +1 -0
- package/dist/web/assets/card-b-terminal-DpJ_tVpg.js +1 -0
- package/dist/web/assets/card-c-gradient-CZXVGuNd.js +1 -0
- package/dist/web/assets/card-d-dashboard-CHKD-PnB.js +1 -0
- package/dist/web/assets/dist-CWaokT35.js +56 -0
- package/dist/web/assets/index-B-HrjaDy.css +1 -0
- package/dist/web/assets/index-BZYcD76T.js +633 -0
- package/dist/web/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
- package/dist/web/assets/patterns-BPeZb9N0.js +1 -0
- package/dist/web/assets/stats-BSwqSiFU.js +1 -0
- package/dist/web/assets/thread-D2AXyhOx.js +1 -0
- package/dist/web/index.html +8 -2
- package/package.json +58 -18
- package/scripts/postinstall.mjs +38 -0
- package/dist/cli.js.map +0 -1
- package/dist/commands/activate.js +0 -69
- package/dist/commands/activate.js.map +0 -1
- package/dist/commands/audit-secrets.js +0 -103
- package/dist/commands/audit-secrets.js.map +0 -1
- package/dist/commands/blame.js +0 -35
- package/dist/commands/blame.js.map +0 -1
- package/dist/commands/config-verification.js +0 -18
- package/dist/commands/config-verification.js.map +0 -1
- package/dist/commands/context.js +0 -144
- package/dist/commands/context.js.map +0 -1
- package/dist/commands/correlate.js +0 -70
- package/dist/commands/correlate.js.map +0 -1
- package/dist/commands/digest.js +0 -78
- package/dist/commands/digest.js.map +0 -1
- package/dist/commands/health.js +0 -62
- package/dist/commands/health.js.map +0 -1
- package/dist/commands/index.js +0 -247
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/install-extension.js +0 -138
- package/dist/commands/install-extension.js.map +0 -1
- package/dist/commands/license.js +0 -39
- package/dist/commands/license.js.map +0 -1
- package/dist/commands/list.js +0 -47
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/mcp.js +0 -29
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/open.js +0 -28
- package/dist/commands/open.js.map +0 -1
- package/dist/commands/paste.js +0 -154
- package/dist/commands/paste.js.map +0 -1
- package/dist/commands/projects.js +0 -36
- package/dist/commands/projects.js.map +0 -1
- package/dist/commands/search.js +0 -67
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/semantic.js +0 -173
- package/dist/commands/semantic.js.map +0 -1
- package/dist/commands/show.js +0 -121
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/start.js +0 -47
- package/dist/commands/start.js.map +0 -1
- package/dist/commands/stats.js +0 -133
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/status.js +0 -45
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/stop.js +0 -29
- package/dist/commands/stop.js.map +0 -1
- package/dist/commands/thread.js +0 -396
- package/dist/commands/thread.js.map +0 -1
- package/dist/context/formatter.js +0 -103
- package/dist/context/formatter.js.map +0 -1
- package/dist/daemon/auto-tag-config.js +0 -103
- package/dist/daemon/auto-tag-config.js.map +0 -1
- package/dist/daemon/auto-tag-config.test.js +0 -72
- package/dist/daemon/auto-tag-config.test.js.map +0 -1
- package/dist/daemon/auto-title-config.js +0 -70
- package/dist/daemon/auto-title-config.js.map +0 -1
- package/dist/daemon/bulk-title-jobs.js +0 -170
- package/dist/daemon/bulk-title-jobs.js.map +0 -1
- package/dist/daemon/correlator.js +0 -320
- package/dist/daemon/correlator.js.map +0 -1
- package/dist/daemon/discover.js +0 -316
- package/dist/daemon/discover.js.map +0 -1
- package/dist/daemon/editor-detection.js +0 -186
- package/dist/daemon/editor-detection.js.map +0 -1
- package/dist/daemon/entrypoint.js.map +0 -1
- package/dist/daemon/git-correlator.js +0 -256
- package/dist/daemon/git-correlator.js.map +0 -1
- package/dist/daemon/mcp-installer.js +0 -108
- package/dist/daemon/mcp-installer.js.map +0 -1
- package/dist/daemon/onboarding-state.js +0 -140
- package/dist/daemon/onboarding-state.js.map +0 -1
- package/dist/daemon/pidfile.js +0 -57
- package/dist/daemon/pidfile.js.map +0 -1
- package/dist/daemon/ports.js +0 -48
- package/dist/daemon/ports.js.map +0 -1
- package/dist/daemon/scanProgressRegistry.js +0 -62
- package/dist/daemon/scanProgressRegistry.js.map +0 -1
- package/dist/daemon/server.js +0 -2010
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/tag-scanner/anthropic-client.js +0 -40
- package/dist/daemon/tag-scanner/anthropic-client.js.map +0 -1
- package/dist/daemon/tag-scanner/autopilot.js +0 -131
- package/dist/daemon/tag-scanner/autopilot.js.map +0 -1
- package/dist/daemon/tag-scanner/claude-cli-driver.js +0 -250
- package/dist/daemon/tag-scanner/claude-cli-driver.js.map +0 -1
- package/dist/daemon/tag-scanner/orchestrator.js +0 -88
- package/dist/daemon/tag-scanner/orchestrator.js.map +0 -1
- package/dist/daemon/tag-scanner/prompt.js +0 -46
- package/dist/daemon/tag-scanner/prompt.js.map +0 -1
- package/dist/daemon/tag-scanner/prompt.test.js +0 -48
- package/dist/daemon/tag-scanner/prompt.test.js.map +0 -1
- package/dist/daemon/tag-scanner/scan-state.js +0 -49
- package/dist/daemon/tag-scanner/scan-state.js.map +0 -1
- package/dist/daemon/tag-scanner/session-fetcher.js +0 -82
- package/dist/daemon/tag-scanner/session-fetcher.js.map +0 -1
- package/dist/daemon/tag-scanner/session-fetcher.test.js +0 -34
- package/dist/daemon/tag-scanner/session-fetcher.test.js.map +0 -1
- package/dist/daemon/tag-scanner/validator.js +0 -50
- package/dist/daemon/tag-scanner/validator.js.map +0 -1
- package/dist/daemon/tag-scanner/validator.test.js +0 -41
- package/dist/daemon/tag-scanner/validator.test.js.map +0 -1
- package/dist/daemon/terminal-registry.js +0 -443
- package/dist/daemon/terminal-registry.js.map +0 -1
- package/dist/daemon/ui.js +0 -64
- package/dist/daemon/ui.js.map +0 -1
- package/dist/daemon/watcher.js +0 -256
- package/dist/daemon/watcher.js.map +0 -1
- package/dist/db/client.js +0 -22
- package/dist/db/client.js.map +0 -1
- package/dist/db/schema.js +0 -496
- package/dist/db/schema.js.map +0 -1
- package/dist/license/api-base.js +0 -13
- package/dist/license/api-base.js.map +0 -1
- package/dist/license/manager.js +0 -43
- package/dist/license/manager.js.map +0 -1
- package/dist/license/public-key.js +0 -19
- package/dist/license/public-key.js.map +0 -1
- package/dist/license/storage.js +0 -27
- package/dist/license/storage.js.map +0 -1
- package/dist/license/verify.js +0 -23
- package/dist/license/verify.js.map +0 -1
- package/dist/mcp/audit.js +0 -126
- package/dist/mcp/audit.js.map +0 -1
- package/dist/mcp/prompts.js +0 -180
- package/dist/mcp/prompts.js.map +0 -1
- package/dist/mcp/server.js +0 -502
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/thread-tools.js +0 -363
- package/dist/mcp/thread-tools.js.map +0 -1
- package/dist/mcp/write-tools.js +0 -239
- package/dist/mcp/write-tools.js.map +0 -1
- package/dist/parser/jsonl.js +0 -150
- package/dist/parser/jsonl.js.map +0 -1
- package/dist/semantic/chunker.js +0 -47
- package/dist/semantic/chunker.js.map +0 -1
- package/dist/semantic/config.js +0 -74
- package/dist/semantic/config.js.map +0 -1
- package/dist/semantic/embedder.js +0 -54
- package/dist/semantic/embedder.js.map +0 -1
- package/dist/semantic/fusion.js +0 -38
- package/dist/semantic/fusion.js.map +0 -1
- package/dist/semantic/model-download.js +0 -69
- package/dist/semantic/model-download.js.map +0 -1
- package/dist/semantic/pipeline.js +0 -375
- package/dist/semantic/pipeline.js.map +0 -1
- package/dist/semantic/query.js +0 -42
- package/dist/semantic/query.js.map +0 -1
- package/dist/semantic/worker.js +0 -78
- package/dist/semantic/worker.js.map +0 -1
- package/dist/stats/backfill.js +0 -151
- package/dist/stats/backfill.js.map +0 -1
- package/dist/stats/health.js +0 -102
- package/dist/stats/health.js.map +0 -1
- package/dist/stats/query.js +0 -385
- package/dist/stats/query.js.map +0 -1
- package/dist/utils/aliases.js +0 -107
- package/dist/utils/aliases.js.map +0 -1
- package/dist/utils/autoCollections.js +0 -635
- package/dist/utils/autoCollections.js.map +0 -1
- package/dist/utils/autoTitle.js +0 -348
- package/dist/utils/autoTitle.js.map +0 -1
- package/dist/utils/collections.js +0 -446
- package/dist/utils/collections.js.map +0 -1
- package/dist/utils/format.js +0 -46
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/notes.js +0 -270
- package/dist/utils/notes.js.map +0 -1
- package/dist/utils/paths.js +0 -50
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/pricing.js +0 -257
- package/dist/utils/pricing.js.map +0 -1
- package/dist/utils/secret-scanner.js +0 -166
- package/dist/utils/secret-scanner.js.map +0 -1
- package/dist/utils/sessionLabel.js +0 -64
- package/dist/utils/sessionLabel.js.map +0 -1
- package/dist/utils/tags.js +0 -97
- package/dist/utils/tags.js.map +0 -1
- package/dist/utils/thread-context.js +0 -129
- package/dist/utils/thread-context.js.map +0 -1
- package/dist/utils/threadFilter.js +0 -18
- package/dist/utils/threadFilter.js.map +0 -1
- package/dist/utils/threads-titler.js +0 -298
- package/dist/utils/threads-titler.js.map +0 -1
- package/dist/utils/threads.js +0 -383
- package/dist/utils/threads.js.map +0 -1
- package/dist/utils/usage.js +0 -76
- package/dist/utils/usage.js.map +0 -1
- package/dist/verification/compute.js +0 -88
- package/dist/verification/compute.js.map +0 -1
- package/dist/verification/config.js +0 -34
- package/dist/verification/config.js.map +0 -1
- package/dist/web/assets/index-CIr6J4Fw.js +0 -1201
- package/dist/web/assets/index-Ctc8g9Jw.css +0 -1
package/dist/db/schema.js
DELETED
|
@@ -1,496 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Every write feature in Recall is backed by SQLite (with a history column
|
|
3
|
-
* wherever a row can change) AND a plain-text mirror on disk so users can
|
|
4
|
-
* grep, edit, or restore their data without opening the database.
|
|
5
|
-
*
|
|
6
|
-
* The plain-text mirrors and companion preference files live under
|
|
7
|
-
* `$RECALL_HOME` (default `~/.recall/`):
|
|
8
|
-
*
|
|
9
|
-
* aliases.json — session alias current state + previous_aliases[] history
|
|
10
|
-
* tags.json — current tag state + append-only event log
|
|
11
|
-
* notes/<session-id>.md — one markdown file per session note (history inside SQLite)
|
|
12
|
-
* collections.json — collection tree snapshot + full collection_events log
|
|
13
|
-
* config.json — auto-tag config (may contain an Anthropic API key; 0600)
|
|
14
|
-
* onboarding.json — v0.14a first-run tour state (no secrets, default perms).
|
|
15
|
-
* Shape:
|
|
16
|
-
* {
|
|
17
|
-
* "version": 1,
|
|
18
|
-
* "completed": boolean,
|
|
19
|
-
* "skipped": boolean,
|
|
20
|
-
* "finishedAt": ISO-8601 | null,
|
|
21
|
-
* "completedSteps": string[]
|
|
22
|
-
* }
|
|
23
|
-
* Parsed/validated in src/daemon/onboarding-state.ts.
|
|
24
|
-
* daemon.pid / daemon.port / daemon.log — lifecycle metadata.
|
|
25
|
-
*
|
|
26
|
-
* Schema invariants (enforced here):
|
|
27
|
-
* 1. `IF NOT EXISTS` on every DDL — migrations stay backwards compatible.
|
|
28
|
-
* 2. Session UUIDs are immutable primary keys; aliases/notes/tags layer on top.
|
|
29
|
-
* 3. History columns (`previous_*`) are append-only JSON arrays — never pruned.
|
|
30
|
-
* 4. Source JSONLs at `~/.claude/projects/` are read-only to Recall.
|
|
31
|
-
*/
|
|
32
|
-
export const SCHEMA_SQL = `
|
|
33
|
-
PRAGMA journal_mode = WAL;
|
|
34
|
-
PRAGMA synchronous = NORMAL;
|
|
35
|
-
PRAGMA foreign_keys = ON;
|
|
36
|
-
|
|
37
|
-
CREATE TABLE IF NOT EXISTS projects (
|
|
38
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
39
|
-
encoded_path TEXT UNIQUE NOT NULL,
|
|
40
|
-
decoded_path TEXT NOT NULL,
|
|
41
|
-
name TEXT NOT NULL
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
45
|
-
id TEXT PRIMARY KEY,
|
|
46
|
-
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
47
|
-
file_path TEXT NOT NULL,
|
|
48
|
-
file_mtime REAL NOT NULL,
|
|
49
|
-
started_at TEXT,
|
|
50
|
-
ended_at TEXT,
|
|
51
|
-
message_count INTEGER NOT NULL DEFAULT 0,
|
|
52
|
-
user_message_count INTEGER NOT NULL DEFAULT 0,
|
|
53
|
-
assistant_message_count INTEGER NOT NULL DEFAULT 0,
|
|
54
|
-
first_user_message TEXT,
|
|
55
|
-
cwd TEXT,
|
|
56
|
-
git_branch TEXT,
|
|
57
|
-
version TEXT,
|
|
58
|
-
indexed_at TEXT NOT NULL
|
|
59
|
-
);
|
|
60
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id);
|
|
61
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_started ON sessions(started_at DESC);
|
|
62
|
-
|
|
63
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
64
|
-
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
65
|
-
uuid TEXT UNIQUE NOT NULL,
|
|
66
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
67
|
-
parent_uuid TEXT,
|
|
68
|
-
type TEXT NOT NULL,
|
|
69
|
-
role TEXT,
|
|
70
|
-
timestamp TEXT,
|
|
71
|
-
is_sidechain INTEGER NOT NULL DEFAULT 0,
|
|
72
|
-
content_text TEXT,
|
|
73
|
-
tool_names TEXT,
|
|
74
|
-
raw_json TEXT NOT NULL
|
|
75
|
-
);
|
|
76
|
-
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, timestamp);
|
|
77
|
-
|
|
78
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
|
|
79
|
-
content_text,
|
|
80
|
-
tool_names,
|
|
81
|
-
content='messages',
|
|
82
|
-
content_rowid='rowid',
|
|
83
|
-
tokenize = 'porter unicode61'
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN
|
|
87
|
-
INSERT INTO messages_fts(rowid, content_text, tool_names)
|
|
88
|
-
VALUES (new.rowid, new.content_text, new.tool_names);
|
|
89
|
-
END;
|
|
90
|
-
|
|
91
|
-
CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN
|
|
92
|
-
INSERT INTO messages_fts(messages_fts, rowid, content_text, tool_names)
|
|
93
|
-
VALUES ('delete', old.rowid, old.content_text, old.tool_names);
|
|
94
|
-
END;
|
|
95
|
-
|
|
96
|
-
CREATE TRIGGER IF NOT EXISTS messages_au AFTER UPDATE ON messages BEGIN
|
|
97
|
-
INSERT INTO messages_fts(messages_fts, rowid, content_text, tool_names)
|
|
98
|
-
VALUES ('delete', old.rowid, old.content_text, old.tool_names);
|
|
99
|
-
INSERT INTO messages_fts(rowid, content_text, tool_names)
|
|
100
|
-
VALUES (new.rowid, new.content_text, new.tool_names);
|
|
101
|
-
END;
|
|
102
|
-
|
|
103
|
-
-- v0.4.1 — session aliases. The UUID stays the primary key forever; aliases
|
|
104
|
-
-- are a display layer on top. Every edit archives the prior value into
|
|
105
|
-
-- previous_aliases (JSON array) — we never destroy history.
|
|
106
|
-
CREATE TABLE IF NOT EXISTS session_aliases (
|
|
107
|
-
session_id TEXT PRIMARY KEY REFERENCES sessions(id) ON DELETE CASCADE,
|
|
108
|
-
alias TEXT NOT NULL,
|
|
109
|
-
updated_at TEXT NOT NULL,
|
|
110
|
-
previous_aliases TEXT NOT NULL DEFAULT '[]'
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
-- v0.4.2 — per-session markdown notes.
|
|
114
|
-
-- Every save archives the prior content into previous_versions and also mirrors
|
|
115
|
-
-- the full note out to ~/.recall/notes/<session_id>.md on disk. Nothing is ever
|
|
116
|
-
-- destroyed: an empty string means "cleared" with full history preserved.
|
|
117
|
-
CREATE TABLE IF NOT EXISTS session_notes (
|
|
118
|
-
session_id TEXT PRIMARY KEY REFERENCES sessions(id) ON DELETE CASCADE,
|
|
119
|
-
content TEXT NOT NULL DEFAULT '',
|
|
120
|
-
updated_at TEXT NOT NULL,
|
|
121
|
-
previous_versions TEXT NOT NULL DEFAULT '[]'
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
-- v0.4.3 — session tags. Many-to-many. Never destructively delete:
|
|
125
|
-
-- tag_events is an append-only log of every add and remove across all time,
|
|
126
|
-
-- so the full history of what was tagged when and why is always recoverable.
|
|
127
|
-
CREATE TABLE IF NOT EXISTS session_tags (
|
|
128
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
129
|
-
tag TEXT NOT NULL,
|
|
130
|
-
created_at TEXT NOT NULL,
|
|
131
|
-
PRIMARY KEY (session_id, tag)
|
|
132
|
-
);
|
|
133
|
-
CREATE INDEX IF NOT EXISTS idx_session_tags_tag ON session_tags(tag);
|
|
134
|
-
|
|
135
|
-
CREATE TABLE IF NOT EXISTS tag_events (
|
|
136
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
137
|
-
session_id TEXT NOT NULL,
|
|
138
|
-
tag TEXT NOT NULL,
|
|
139
|
-
action TEXT NOT NULL, -- 'add' | 'remove'
|
|
140
|
-
at TEXT NOT NULL
|
|
141
|
-
);
|
|
142
|
-
CREATE INDEX IF NOT EXISTS idx_tag_events_session ON tag_events(session_id, at DESC);
|
|
143
|
-
CREATE INDEX IF NOT EXISTS idx_tag_events_tag ON tag_events(tag, at DESC);
|
|
144
|
-
|
|
145
|
-
-- v0.4.5 — opt-in clipboard archive. This is the ONE table where a user can
|
|
146
|
-
-- truly purge a row on demand (not soft-delete), because it may contain
|
|
147
|
-
-- accidentally-archived secrets. This carve-out is documented as a deliberate
|
|
148
|
-
-- exception to the "never delete" rule specifically for this data class.
|
|
149
|
-
CREATE TABLE IF NOT EXISTS paste_archives (
|
|
150
|
-
id TEXT PRIMARY KEY,
|
|
151
|
-
created_at TEXT NOT NULL,
|
|
152
|
-
content TEXT NOT NULL,
|
|
153
|
-
size_bytes INTEGER NOT NULL,
|
|
154
|
-
source TEXT NOT NULL DEFAULT 'cli', -- 'cli' | 'cli-piped' | 'ui' | …
|
|
155
|
-
label TEXT -- optional user-supplied short description
|
|
156
|
-
);
|
|
157
|
-
CREATE INDEX IF NOT EXISTS idx_paste_archives_created ON paste_archives(created_at DESC);
|
|
158
|
-
|
|
159
|
-
-- v0.8 — collections. User-curated hand-picked groupings of sessions that
|
|
160
|
-
-- cut across the coarse-grained cwd-based "projects". A collection can nest
|
|
161
|
-
-- as a tree (parent_id → null means root). Soft-deletion only: archived_at
|
|
162
|
-
-- hides rows from default views, the row itself stays forever.
|
|
163
|
-
--
|
|
164
|
-
-- Durability: SQLite (this table + collection_events append-only log) plus a
|
|
165
|
-
-- plain-text mirror at ~/.recall/collections.json rewritten on every mutation.
|
|
166
|
-
CREATE TABLE IF NOT EXISTS collections (
|
|
167
|
-
id TEXT PRIMARY KEY,
|
|
168
|
-
name TEXT NOT NULL,
|
|
169
|
-
description TEXT,
|
|
170
|
-
icon TEXT,
|
|
171
|
-
color TEXT,
|
|
172
|
-
parent_id TEXT REFERENCES collections(id) ON DELETE SET NULL,
|
|
173
|
-
sort_key TEXT NOT NULL DEFAULT '',
|
|
174
|
-
created_at TEXT NOT NULL,
|
|
175
|
-
updated_at TEXT NOT NULL,
|
|
176
|
-
archived_at TEXT
|
|
177
|
-
);
|
|
178
|
-
CREATE INDEX IF NOT EXISTS idx_collections_parent ON collections(parent_id);
|
|
179
|
-
CREATE INDEX IF NOT EXISTS idx_collections_archived ON collections(archived_at);
|
|
180
|
-
|
|
181
|
-
CREATE TABLE IF NOT EXISTS collection_sessions (
|
|
182
|
-
collection_id TEXT NOT NULL REFERENCES collections(id) ON DELETE CASCADE,
|
|
183
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
184
|
-
added_at TEXT NOT NULL,
|
|
185
|
-
note TEXT,
|
|
186
|
-
PRIMARY KEY (collection_id, session_id)
|
|
187
|
-
);
|
|
188
|
-
CREATE INDEX IF NOT EXISTS idx_collection_sessions_session ON collection_sessions(session_id);
|
|
189
|
-
|
|
190
|
-
CREATE TABLE IF NOT EXISTS collection_events (
|
|
191
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
192
|
-
collection_id TEXT NOT NULL,
|
|
193
|
-
session_id TEXT,
|
|
194
|
-
action TEXT NOT NULL, -- 'create' | 'rename' | 'describe' | 'recolor' | 'add' | 'remove' | 'archive' | 'restore' | 'move' | 'reorder'
|
|
195
|
-
payload TEXT, -- JSON context (old_name, new_parent, etc.)
|
|
196
|
-
at TEXT NOT NULL
|
|
197
|
-
);
|
|
198
|
-
CREATE INDEX IF NOT EXISTS idx_collection_events_at ON collection_events(at DESC);
|
|
199
|
-
CREATE INDEX IF NOT EXISTS idx_collection_events_collection ON collection_events(collection_id, at DESC);
|
|
200
|
-
|
|
201
|
-
-- v0.11 — semantic search (Tier 0: shells out to the user's local claude CLI to
|
|
202
|
-
-- summarize each session into 3-sentence prose + a keyword set). Both columns
|
|
203
|
-
-- are TEXT and feed sessions_fts so a conceptual query can hit this index in
|
|
204
|
-
-- addition to the per-message FTS5 index. Pipeline is OFF by default; users opt
|
|
205
|
-
-- in via "recall semantic on". Plain-text mirror at ~/.recall/semantic/<id>.json.
|
|
206
|
-
CREATE TABLE IF NOT EXISTS session_semantic (
|
|
207
|
-
session_id TEXT PRIMARY KEY REFERENCES sessions(id) ON DELETE CASCADE,
|
|
208
|
-
summary TEXT NOT NULL DEFAULT '',
|
|
209
|
-
keywords TEXT NOT NULL DEFAULT '', -- comma-separated
|
|
210
|
-
model TEXT,
|
|
211
|
-
source_message_count INTEGER NOT NULL DEFAULT 0,
|
|
212
|
-
generated_at TEXT NOT NULL
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS sessions_fts USING fts5(
|
|
216
|
-
summary,
|
|
217
|
-
keywords,
|
|
218
|
-
content='session_semantic',
|
|
219
|
-
content_rowid='rowid',
|
|
220
|
-
tokenize = 'porter unicode61'
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
CREATE TRIGGER IF NOT EXISTS session_semantic_ai AFTER INSERT ON session_semantic BEGIN
|
|
224
|
-
INSERT INTO sessions_fts(rowid, summary, keywords)
|
|
225
|
-
VALUES (new.rowid, new.summary, new.keywords);
|
|
226
|
-
END;
|
|
227
|
-
|
|
228
|
-
CREATE TRIGGER IF NOT EXISTS session_semantic_ad AFTER DELETE ON session_semantic BEGIN
|
|
229
|
-
INSERT INTO sessions_fts(sessions_fts, rowid, summary, keywords)
|
|
230
|
-
VALUES ('delete', old.rowid, old.summary, old.keywords);
|
|
231
|
-
END;
|
|
232
|
-
|
|
233
|
-
CREATE TRIGGER IF NOT EXISTS session_semantic_au AFTER UPDATE ON session_semantic BEGIN
|
|
234
|
-
INSERT INTO sessions_fts(sessions_fts, rowid, summary, keywords)
|
|
235
|
-
VALUES ('delete', old.rowid, old.summary, old.keywords);
|
|
236
|
-
INSERT INTO sessions_fts(rowid, summary, keywords)
|
|
237
|
-
VALUES (new.rowid, new.summary, new.keywords);
|
|
238
|
-
END;
|
|
239
|
-
|
|
240
|
-
-- v0.7 — vector search tier (Pro-only). Chunks are per-conversational-turn
|
|
241
|
-
-- segments of messages, embedded via local bge-base-en-v1.5 (768d). The vector
|
|
242
|
-
-- data is a derived cache; if lost, it is recomputable from messages.
|
|
243
|
-
-- Tables stay empty on Free tier (no model downloaded, no worker started).
|
|
244
|
-
|
|
245
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
|
|
246
|
-
embedding float[768] distance_metric=cosine
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
CREATE TABLE IF NOT EXISTS chunk_meta (
|
|
250
|
-
rowid INTEGER PRIMARY KEY,
|
|
251
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
252
|
-
message_uuids TEXT NOT NULL DEFAULT '[]',
|
|
253
|
-
text TEXT NOT NULL DEFAULT '',
|
|
254
|
-
embedding_model_id TEXT NOT NULL DEFAULT 'bge-base-en-v1.5',
|
|
255
|
-
embedding_dim INTEGER NOT NULL DEFAULT 768,
|
|
256
|
-
stale INTEGER NOT NULL DEFAULT 0,
|
|
257
|
-
generated_at TEXT NOT NULL DEFAULT ''
|
|
258
|
-
);
|
|
259
|
-
CREATE INDEX IF NOT EXISTS idx_chunk_meta_session ON chunk_meta(session_id);
|
|
260
|
-
CREATE INDEX IF NOT EXISTS idx_chunk_meta_stale ON chunk_meta(stale) WHERE stale = 1;
|
|
261
|
-
|
|
262
|
-
CREATE TABLE IF NOT EXISTS chunk_queue (
|
|
263
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
264
|
-
session_id TEXT NOT NULL,
|
|
265
|
-
message_uuid TEXT,
|
|
266
|
-
action TEXT NOT NULL CHECK (action IN ('embed', 'reembed', 'delete')),
|
|
267
|
-
enqueued_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
268
|
-
);
|
|
269
|
-
CREATE INDEX IF NOT EXISTS idx_chunk_queue_session ON chunk_queue(session_id);
|
|
270
|
-
|
|
271
|
-
CREATE TRIGGER IF NOT EXISTS messages_vec_ai AFTER INSERT ON messages
|
|
272
|
-
WHEN new.is_sidechain = 0 AND new.content_text IS NOT NULL
|
|
273
|
-
BEGIN
|
|
274
|
-
INSERT INTO chunk_queue(session_id, message_uuid, action, enqueued_at)
|
|
275
|
-
VALUES (new.session_id, new.uuid, 'embed', datetime('now'));
|
|
276
|
-
END;
|
|
277
|
-
|
|
278
|
-
CREATE TRIGGER IF NOT EXISTS messages_vec_ad AFTER DELETE ON messages BEGIN
|
|
279
|
-
INSERT INTO chunk_queue(session_id, message_uuid, action, enqueued_at)
|
|
280
|
-
VALUES (old.session_id, old.uuid, 'delete', datetime('now'));
|
|
281
|
-
END;
|
|
282
|
-
|
|
283
|
-
CREATE TRIGGER IF NOT EXISTS messages_vec_au AFTER UPDATE OF content_text ON messages
|
|
284
|
-
WHEN new.is_sidechain = 0
|
|
285
|
-
BEGIN
|
|
286
|
-
INSERT INTO chunk_queue(session_id, message_uuid, action, enqueued_at)
|
|
287
|
-
VALUES (new.session_id, new.uuid, 'reembed', datetime('now'));
|
|
288
|
-
END;
|
|
289
|
-
|
|
290
|
-
-- v0.10a — cost / token analytics. Claude Code already writes per-assistant-
|
|
291
|
-
-- message usage + model into the source JSONLs; we persist the raw counts
|
|
292
|
-
-- here and derive dollar amounts at render time (pricing changes; token
|
|
293
|
-
-- counts don't). message_usage is 1:1 with messages (keyed by message_uuid)
|
|
294
|
-
-- so a reindex rebuilds it cleanly; rollup columns on sessions are a
|
|
295
|
-
-- cache for fast list rendering.
|
|
296
|
-
CREATE TABLE IF NOT EXISTS message_usage (
|
|
297
|
-
message_uuid TEXT PRIMARY KEY REFERENCES messages(uuid) ON DELETE CASCADE,
|
|
298
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
299
|
-
model TEXT,
|
|
300
|
-
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
301
|
-
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
302
|
-
cache_create_tokens INTEGER NOT NULL DEFAULT 0,
|
|
303
|
-
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
|
304
|
-
timestamp TEXT
|
|
305
|
-
);
|
|
306
|
-
CREATE INDEX IF NOT EXISTS idx_message_usage_session ON message_usage(session_id);
|
|
307
|
-
CREATE INDEX IF NOT EXISTS idx_message_usage_model ON message_usage(model);
|
|
308
|
-
|
|
309
|
-
-- v0.10b — git correlation. For any session whose cwd is a git worktree we
|
|
310
|
-
-- run a read-only \`git log\` scoped to that cwd for the [started_at, ended_at]
|
|
311
|
-
-- window and record every resulting commit. Composite PK (session_id,
|
|
312
|
-
-- commit_sha) lets a single commit belong to multiple sessions (rare, but
|
|
313
|
-
-- happens when a long session ends right as another starts). The reverse
|
|
314
|
-
-- index on commit_sha powers \`recall blame <sha>\`.
|
|
315
|
-
--
|
|
316
|
-
-- correlated_at lets the correlator skip sessions it has already processed
|
|
317
|
-
-- recently; cwd_snapshot captures the directory we ran git in so stale rows
|
|
318
|
-
-- can be identified if the user later points the session elsewhere.
|
|
319
|
-
CREATE TABLE IF NOT EXISTS session_commits (
|
|
320
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
321
|
-
commit_sha TEXT NOT NULL,
|
|
322
|
-
committed_at TEXT,
|
|
323
|
-
subject TEXT,
|
|
324
|
-
cwd_snapshot TEXT,
|
|
325
|
-
correlated_at TEXT NOT NULL,
|
|
326
|
-
PRIMARY KEY (session_id, commit_sha)
|
|
327
|
-
);
|
|
328
|
-
CREATE INDEX IF NOT EXISTS idx_session_commits_sha ON session_commits(commit_sha);
|
|
329
|
-
CREATE INDEX IF NOT EXISTS idx_session_commits_session ON session_commits(session_id);
|
|
330
|
-
-- v0.13 — MCP write audit log. Every write tool invocation appends one row,
|
|
331
|
-
-- regardless of outcome (ok / error / rate_limited). Tags and collections
|
|
332
|
-
-- already have their own append-only event tables (tag_events,
|
|
333
|
-
-- collection_events) — this table covers note/alias writes and provides a
|
|
334
|
-
-- single chronological feed across all MCP write activity for review.
|
|
335
|
-
CREATE TABLE IF NOT EXISTS mcp_audit_events (
|
|
336
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
337
|
-
tool TEXT NOT NULL,
|
|
338
|
-
args_json TEXT NOT NULL,
|
|
339
|
-
result TEXT NOT NULL, -- 'ok' | 'error' | 'rate_limited'
|
|
340
|
-
error_message TEXT,
|
|
341
|
-
caller TEXT,
|
|
342
|
-
at TEXT NOT NULL
|
|
343
|
-
);
|
|
344
|
-
CREATE INDEX IF NOT EXISTS idx_mcp_audit_events_at ON mcp_audit_events(at DESC);
|
|
345
|
-
CREATE INDEX IF NOT EXISTS idx_mcp_audit_events_tool ON mcp_audit_events(tool, at DESC);
|
|
346
|
-
|
|
347
|
-
-- v0.15 T6 — auto-collections. Rules match sessions by cwd prefix, project
|
|
348
|
-
-- id, tag, plan-file reference, or git branch prefix, and insert auto
|
|
349
|
-
-- memberships into collection_sessions (tagged with source='auto' + the
|
|
350
|
-
-- originating rule_id). Manual memberships (source='manual') are never
|
|
351
|
-
-- touched by the rule engine — so a user's hand-curated pick always wins.
|
|
352
|
-
--
|
|
353
|
-
-- Suggestions are the discovery half: the daemon periodically surveys the
|
|
354
|
-
-- corpus, detects clusters that *would* make good auto-collections, and
|
|
355
|
-
-- stashes them here for the user to accept or dismiss. UNIQUE(type,pattern)
|
|
356
|
-
-- means the same cluster won't be re-suggested every scan.
|
|
357
|
-
--
|
|
358
|
-
-- Durability mirror: ~/.recall/auto-rules/{rules.json,suggestions.json}
|
|
359
|
-
-- rewritten on every mutation. Deleting a rule removes ONLY its auto
|
|
360
|
-
-- memberships (matched via rule_id); the target collection stays so the
|
|
361
|
-
-- user can keep whatever they manually added into it.
|
|
362
|
-
CREATE TABLE IF NOT EXISTS auto_collection_rules (
|
|
363
|
-
id TEXT PRIMARY KEY,
|
|
364
|
-
name TEXT NOT NULL,
|
|
365
|
-
type TEXT NOT NULL CHECK (type IN ('cwd-prefix','project-id','tag','plan-file','git-branch-prefix')),
|
|
366
|
-
pattern TEXT NOT NULL,
|
|
367
|
-
collection_id TEXT NOT NULL REFERENCES collections(id) ON DELETE CASCADE,
|
|
368
|
-
priority INTEGER NOT NULL DEFAULT 100,
|
|
369
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
370
|
-
created_at TEXT NOT NULL,
|
|
371
|
-
created_by TEXT NOT NULL DEFAULT 'user' -- 'user' | 'suggestion-accepted' | 'seed'
|
|
372
|
-
);
|
|
373
|
-
CREATE INDEX IF NOT EXISTS idx_auto_rules_type_enabled ON auto_collection_rules(type, enabled);
|
|
374
|
-
CREATE INDEX IF NOT EXISTS idx_auto_rules_collection ON auto_collection_rules(collection_id);
|
|
375
|
-
|
|
376
|
-
CREATE TABLE IF NOT EXISTS auto_collection_suggestions (
|
|
377
|
-
id TEXT PRIMARY KEY,
|
|
378
|
-
type TEXT NOT NULL,
|
|
379
|
-
pattern TEXT NOT NULL,
|
|
380
|
-
suggested_name TEXT NOT NULL,
|
|
381
|
-
suggested_parent_collection_id TEXT,
|
|
382
|
-
session_count INTEGER NOT NULL,
|
|
383
|
-
detected_at TEXT NOT NULL,
|
|
384
|
-
dismissed INTEGER NOT NULL DEFAULT 0,
|
|
385
|
-
UNIQUE(type, pattern)
|
|
386
|
-
);
|
|
387
|
-
CREATE INDEX IF NOT EXISTS idx_auto_suggestions_detected ON auto_collection_suggestions(detected_at DESC);
|
|
388
|
-
|
|
389
|
-
-- v0.15 Threads. The headline intent-grouping primitive: a DAG of sessions
|
|
390
|
-
-- connected by shared purpose (one or more origin sessions plus their
|
|
391
|
-
-- children). Additive to Projects and Collections; neither is refactored.
|
|
392
|
-
-- thread_edges is many-to-many so a session can belong to multiple threads
|
|
393
|
-
-- (planning session that seeds two features). parent_session_id is
|
|
394
|
-
-- nullable; when null, the row is an origin. confidence = 1.0 for manual
|
|
395
|
-
-- edges; < 1.0 for auto-detected edges (v0.15b). source tracks provenance
|
|
396
|
-
-- for the audit/undo paths.
|
|
397
|
-
CREATE TABLE IF NOT EXISTS threads (
|
|
398
|
-
id TEXT PRIMARY KEY,
|
|
399
|
-
name TEXT NOT NULL,
|
|
400
|
-
summary TEXT,
|
|
401
|
-
created_at TEXT NOT NULL,
|
|
402
|
-
closed_at TEXT,
|
|
403
|
-
archived INTEGER NOT NULL DEFAULT 0
|
|
404
|
-
);
|
|
405
|
-
|
|
406
|
-
CREATE TABLE IF NOT EXISTS thread_edges (
|
|
407
|
-
thread_id TEXT NOT NULL,
|
|
408
|
-
session_id TEXT NOT NULL,
|
|
409
|
-
parent_session_id TEXT,
|
|
410
|
-
role TEXT NOT NULL CHECK(role IN ('origin','child')),
|
|
411
|
-
confidence REAL NOT NULL DEFAULT 1.0 CHECK(confidence >= 0 AND confidence <= 1),
|
|
412
|
-
source TEXT NOT NULL DEFAULT 'manual',
|
|
413
|
-
added_at TEXT NOT NULL,
|
|
414
|
-
PRIMARY KEY (thread_id, session_id),
|
|
415
|
-
FOREIGN KEY (thread_id) REFERENCES threads(id) ON DELETE CASCADE
|
|
416
|
-
);
|
|
417
|
-
CREATE INDEX IF NOT EXISTS idx_thread_edges_session ON thread_edges(session_id);
|
|
418
|
-
CREATE INDEX IF NOT EXISTS idx_thread_edges_parent ON thread_edges(parent_session_id);
|
|
419
|
-
CREATE INDEX IF NOT EXISTS idx_thread_edges_thread_role ON thread_edges(thread_id, role);
|
|
420
|
-
`;
|
|
421
|
-
export function runMigrations(db) {
|
|
422
|
-
const cols = db.prepare(`PRAGMA table_info(sessions)`).all();
|
|
423
|
-
const have = new Set(cols.map((c) => c.name));
|
|
424
|
-
const adds = [
|
|
425
|
-
// v0.10a — per-session token rollups + dominant model. Nullable; filled
|
|
426
|
-
// on index/reindex and by the lazy backfill pass. Dollar amounts are
|
|
427
|
-
// NEVER persisted — prices change; raw token counts don't.
|
|
428
|
-
['total_input_tokens', 'INTEGER'],
|
|
429
|
-
['total_output_tokens', 'INTEGER'],
|
|
430
|
-
['total_cache_create_tokens', 'INTEGER'],
|
|
431
|
-
['total_cache_read_tokens', 'INTEGER'],
|
|
432
|
-
['primary_model', 'TEXT'],
|
|
433
|
-
// v0.14b (T5) — derived session titles. Two tiers:
|
|
434
|
-
// heuristic — scrubbed first_user_message, computed synchronously at
|
|
435
|
-
// index time, always on.
|
|
436
|
-
// agent — 'claude -p' summary, opt-in via ✨ Generate title button.
|
|
437
|
-
// Fallback chain at display: alias → auto_title → first_user_message →
|
|
438
|
-
// id.slice(0,8). Manual alias always wins.
|
|
439
|
-
['auto_title', 'TEXT'],
|
|
440
|
-
['auto_title_source', 'TEXT'],
|
|
441
|
-
['auto_title_generated_at', 'INTEGER'],
|
|
442
|
-
// JSON array of { title, source, replaced_at } — append-only history so
|
|
443
|
-
// a ✨ regenerate never loses the prior title (three-layer durability rule).
|
|
444
|
-
['auto_title_history', 'TEXT'],
|
|
445
|
-
// v0.16 — Verification badges (opt-in preview). Computed on demand; cached
|
|
446
|
-
// in the sessions row with a 24h TTL.
|
|
447
|
-
['verification_status', 'TEXT'],
|
|
448
|
-
['verification_computed_at', 'INTEGER'],
|
|
449
|
-
];
|
|
450
|
-
for (const [name, type] of adds) {
|
|
451
|
-
if (!have.has(name)) {
|
|
452
|
-
db.exec(`ALTER TABLE sessions ADD COLUMN ${name} ${type}`);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
// v0.15 T6 — auto-collections. `source` distinguishes manual vs auto
|
|
456
|
-
// memberships so the rule engine can safely re-run without ever
|
|
457
|
-
// stomping a user's hand-picked choice. `rule_id` is the FK back to the
|
|
458
|
-
// rule that added the auto row — deleting a rule removes ONLY rows it
|
|
459
|
-
// authored. Both columns are additive and default to the pre-T6
|
|
460
|
-
// behaviour ('manual', no rule) so existing rows stay valid.
|
|
461
|
-
const csCols = db
|
|
462
|
-
.prepare(`PRAGMA table_info(collection_sessions)`)
|
|
463
|
-
.all();
|
|
464
|
-
const csHave = new Set(csCols.map((c) => c.name));
|
|
465
|
-
const csAdds = [
|
|
466
|
-
['source', "TEXT NOT NULL DEFAULT 'manual'"],
|
|
467
|
-
['rule_id', 'TEXT'],
|
|
468
|
-
];
|
|
469
|
-
for (const [name, type] of csAdds) {
|
|
470
|
-
if (!csHave.has(name)) {
|
|
471
|
-
db.exec(`ALTER TABLE collection_sessions ADD COLUMN ${name} ${type}`);
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
// ✨ Generate Note — agent-generated synopsis stored ALONGSIDE the
|
|
475
|
-
// user-typed note. Never overwrites `content`. Hand-written notes and
|
|
476
|
-
// auto-synopses can coexist; the UI shows the synopsis beneath the
|
|
477
|
-
// manual note. Three nullable columns track value + source + timestamp,
|
|
478
|
-
// matching the auto_title pattern.
|
|
479
|
-
const snCols = db
|
|
480
|
-
.prepare(`PRAGMA table_info(session_notes)`)
|
|
481
|
-
.all();
|
|
482
|
-
const snHave = new Set(snCols.map((c) => c.name));
|
|
483
|
-
const snAdds = [
|
|
484
|
-
['auto_synopsis', 'TEXT'],
|
|
485
|
-
['auto_synopsis_generated_at', 'INTEGER'],
|
|
486
|
-
// JSON array of { synopsis, replaced_at } — append-only history so
|
|
487
|
-
// regenerating never loses the prior synopsis.
|
|
488
|
-
['auto_synopsis_history', 'TEXT'],
|
|
489
|
-
];
|
|
490
|
-
for (const [name, type] of snAdds) {
|
|
491
|
-
if (!snHave.has(name)) {
|
|
492
|
-
db.exec(`ALTER TABLE session_notes ADD COLUMN ${name} ${type}`);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
//# sourceMappingURL=schema.js.map
|
package/dist/db/schema.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/license/api-base.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where the CLI talks to the activation/validation API.
|
|
3
|
-
*
|
|
4
|
-
* Override with RECALL_API_BASE when developing against a local Next dev server,
|
|
5
|
-
* e.g. `RECALL_API_BASE=http://127.0.0.1:3010 recall activate ...`.
|
|
6
|
-
*/
|
|
7
|
-
export function apiBase() {
|
|
8
|
-
const fromEnv = process.env.RECALL_API_BASE;
|
|
9
|
-
if (fromEnv && fromEnv.length > 0)
|
|
10
|
-
return fromEnv.replace(/\/$/, '');
|
|
11
|
-
return 'https://clauderecall.com';
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=api-base.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-base.js","sourceRoot":"","sources":["../../src/license/api-base.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC5C,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrE,OAAO,0BAA0B,CAAC;AACpC,CAAC"}
|
package/dist/license/manager.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { readStoredLicense } from './storage.js';
|
|
2
|
-
import { verifyLicenseJwt } from './verify.js';
|
|
3
|
-
export async function getLicenseStatus() {
|
|
4
|
-
const stored = readStoredLicense();
|
|
5
|
-
if (!stored)
|
|
6
|
-
return { tier: 'free' };
|
|
7
|
-
const verified = await verifyLicenseJwt(stored.license_jwt);
|
|
8
|
-
if (!verified.valid || !verified.claims) {
|
|
9
|
-
return { tier: 'free', invalid_reason: verified.reason };
|
|
10
|
-
}
|
|
11
|
-
return claimsToStatus(stored, verified.claims);
|
|
12
|
-
}
|
|
13
|
-
function claimsToStatus(stored, claims) {
|
|
14
|
-
return {
|
|
15
|
-
tier: 'pro',
|
|
16
|
-
key_short: stored.key_short,
|
|
17
|
-
customer_email: stored.customer_email,
|
|
18
|
-
activated_at: stored.activated_at,
|
|
19
|
-
test_mode: stored.test_mode,
|
|
20
|
-
expires_at: typeof claims.exp === 'number' ? new Date(claims.exp * 1000).toISOString() : null,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export async function isPro() {
|
|
24
|
-
const status = await getLicenseStatus();
|
|
25
|
-
return status.tier === 'pro';
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* CLI gate. Prints a friendly message and exits 1 when the caller is not Pro.
|
|
29
|
-
* Synchronous-style sugar for use at the top of a runX() command.
|
|
30
|
-
*/
|
|
31
|
-
export async function requireProOrExit(featureName) {
|
|
32
|
-
const status = await getLicenseStatus();
|
|
33
|
-
if (status.tier === 'pro')
|
|
34
|
-
return;
|
|
35
|
-
process.stderr.write(`\n${featureName} is a Pro feature.\n\n` +
|
|
36
|
-
`Buy a license at https://clauderecall.com/pricing ($29.69 one-time, lifetime updates).\n` +
|
|
37
|
-
`Then run: recall activate <license-key>\n\n`);
|
|
38
|
-
if (status.invalid_reason) {
|
|
39
|
-
process.stderr.write(`(stored license is invalid: ${status.invalid_reason})\n\n`);
|
|
40
|
-
}
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
//# sourceMappingURL=manager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/license/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAsB,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAsB,MAAM,aAAa,CAAC;AAgBnE,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5D,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,cAAc,CAAC,MAAqB,EAAE,MAAqB;IAClE,OAAO;QACL,IAAI,EAAE,KAAK;QACX,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;KAC9F,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,OAAO,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACxD,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,KAAK,WAAW,wBAAwB;QACtC,0FAA0F;QAC1F,8CAA8C,CACjD,CAAC;IACF,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,cAAc,OAAO,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ES256 (P-256) public key used to verify license JWTs offline.
|
|
3
|
-
*
|
|
4
|
-
* IMPORTANT: This PEM must match the one at site/lib/license-public-key.ts byte-for-byte.
|
|
5
|
-
* Both copies were generated together on 2026-04-25. Rotating one without the other
|
|
6
|
-
* would invalidate every previously-issued license JWT — that would break the
|
|
7
|
-
* dead-man clause for all existing customers.
|
|
8
|
-
*
|
|
9
|
-
* The matching private key lives only in the site's LICENSE_JWT_PRIVATE_KEY env var.
|
|
10
|
-
*/
|
|
11
|
-
export const LICENSE_JWT_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
12
|
-
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
|
|
13
|
-
kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
|
|
14
|
-
-----END PUBLIC KEY-----
|
|
15
|
-
`;
|
|
16
|
-
export const LICENSE_JWT_ALG = 'ES256';
|
|
17
|
-
export const LICENSE_JWT_ISSUER = 'clauderecall.com';
|
|
18
|
-
export const LICENSE_JWT_AUDIENCE = 'clauderecall-cli';
|
|
19
|
-
//# sourceMappingURL=public-key.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"public-key.js","sourceRoot":"","sources":["../../src/license/public-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;;;;CAIzC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,OAAgB,CAAC;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAA2B,CAAC;AAC9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAA2B,CAAC"}
|
package/dist/license/storage.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { RECALL_HOME, ensureRecallHome } from '../utils/paths.js';
|
|
4
|
-
export const LICENSE_FILE = join(RECALL_HOME, 'license.json');
|
|
5
|
-
export function readStoredLicense() {
|
|
6
|
-
if (!existsSync(LICENSE_FILE))
|
|
7
|
-
return null;
|
|
8
|
-
try {
|
|
9
|
-
const raw = readFileSync(LICENSE_FILE, 'utf8');
|
|
10
|
-
const parsed = JSON.parse(raw);
|
|
11
|
-
if (typeof parsed.license_jwt !== 'string' || parsed.license_jwt.length === 0)
|
|
12
|
-
return null;
|
|
13
|
-
return parsed;
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export function writeStoredLicense(license) {
|
|
20
|
-
ensureRecallHome();
|
|
21
|
-
writeFileSync(LICENSE_FILE, JSON.stringify(license, null, 2) + '\n', { mode: 0o600 });
|
|
22
|
-
}
|
|
23
|
-
export function clearStoredLicense() {
|
|
24
|
-
if (existsSync(LICENSE_FILE))
|
|
25
|
-
unlinkSync(LICENSE_FILE);
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/license/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAmB9D,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;QAChD,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3F,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAsB;IACvD,gBAAgB,EAAE,CAAC;IACnB,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,IAAI,UAAU,CAAC,YAAY,CAAC;QAAE,UAAU,CAAC,YAAY,CAAC,CAAC;AACzD,CAAC"}
|
package/dist/license/verify.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { jwtVerify, importSPKI } from 'jose';
|
|
2
|
-
import { LICENSE_JWT_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, LICENSE_JWT_ISSUER, LICENSE_JWT_AUDIENCE, } from './public-key.js';
|
|
3
|
-
let cachedKey = null;
|
|
4
|
-
async function loadKey() {
|
|
5
|
-
if (cachedKey)
|
|
6
|
-
return cachedKey;
|
|
7
|
-
cachedKey = await importSPKI(LICENSE_JWT_PUBLIC_KEY_PEM, LICENSE_JWT_ALG);
|
|
8
|
-
return cachedKey;
|
|
9
|
-
}
|
|
10
|
-
export async function verifyLicenseJwt(token) {
|
|
11
|
-
try {
|
|
12
|
-
const key = await loadKey();
|
|
13
|
-
const { payload } = await jwtVerify(token, key, {
|
|
14
|
-
issuer: LICENSE_JWT_ISSUER,
|
|
15
|
-
audience: LICENSE_JWT_AUDIENCE,
|
|
16
|
-
});
|
|
17
|
-
return { valid: true, claims: payload };
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
return { valid: false, reason: err instanceof Error ? err.message : 'verification failed' };
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=verify.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/license/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAmB,MAAM,MAAM,CAAC;AAC9D,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAgBzB,IAAI,SAAS,GAAkD,IAAI,CAAC;AAEpE,KAAK,UAAU,OAAO;IACpB,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,SAAS,GAAG,MAAM,UAAU,CAAC,0BAA0B,EAAE,eAAe,CAAC,CAAC;IAC1E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAa;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAC;QAC5B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE;YAC9C,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,oBAAoB;SAC/B,CAAC,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAwB,EAAE,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAC;IAC9F,CAAC;AACH,CAAC"}
|