@clauderecallhq/cli 0.12.1 → 0.61.2

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 (220) hide show
  1. package/LICENSE +37 -17
  2. package/README.md +316 -106
  3. package/dist/cli.js +1641 -361
  4. package/dist/daemon/entrypoint.js +1872 -54
  5. package/dist/mcp-server.js +930 -0
  6. package/dist/share/fonts/Inter-Bold.woff +0 -0
  7. package/dist/share/fonts/Inter-Regular.woff +0 -0
  8. package/dist/share/fonts/JetBrainsMono-Regular.woff +0 -0
  9. package/dist/web/assets/_brand-Bw9uSB4O.js +1 -0
  10. package/dist/web/assets/captureNode-9CVj9vYC.js +2 -0
  11. package/dist/web/assets/card-a-minimal-ujNERzX7.js +1 -0
  12. package/dist/web/assets/card-b-terminal-DpJ_tVpg.js +1 -0
  13. package/dist/web/assets/card-c-gradient-CZXVGuNd.js +1 -0
  14. package/dist/web/assets/card-d-dashboard-CHKD-PnB.js +1 -0
  15. package/dist/web/assets/dist-CWaokT35.js +56 -0
  16. package/dist/web/assets/index-B-HrjaDy.css +1 -0
  17. package/dist/web/assets/index-BZYcD76T.js +633 -0
  18. package/dist/web/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
  19. package/dist/web/assets/patterns-BPeZb9N0.js +1 -0
  20. package/dist/web/assets/stats-BSwqSiFU.js +1 -0
  21. package/dist/web/assets/thread-D2AXyhOx.js +1 -0
  22. package/dist/web/index.html +8 -2
  23. package/package.json +57 -16
  24. package/scripts/postinstall.mjs +38 -0
  25. package/dist/cli.js.map +0 -1
  26. package/dist/commands/activate.js +0 -69
  27. package/dist/commands/activate.js.map +0 -1
  28. package/dist/commands/audit-secrets.js +0 -103
  29. package/dist/commands/audit-secrets.js.map +0 -1
  30. package/dist/commands/blame.js +0 -35
  31. package/dist/commands/blame.js.map +0 -1
  32. package/dist/commands/config-verification.js +0 -18
  33. package/dist/commands/config-verification.js.map +0 -1
  34. package/dist/commands/context.js +0 -144
  35. package/dist/commands/context.js.map +0 -1
  36. package/dist/commands/correlate.js +0 -70
  37. package/dist/commands/correlate.js.map +0 -1
  38. package/dist/commands/digest.js +0 -78
  39. package/dist/commands/digest.js.map +0 -1
  40. package/dist/commands/health.js +0 -62
  41. package/dist/commands/health.js.map +0 -1
  42. package/dist/commands/index.js +0 -247
  43. package/dist/commands/index.js.map +0 -1
  44. package/dist/commands/install-extension.js +0 -138
  45. package/dist/commands/install-extension.js.map +0 -1
  46. package/dist/commands/installs.js +0 -128
  47. package/dist/commands/installs.js.map +0 -1
  48. package/dist/commands/license.js +0 -39
  49. package/dist/commands/license.js.map +0 -1
  50. package/dist/commands/list.js +0 -47
  51. package/dist/commands/list.js.map +0 -1
  52. package/dist/commands/mcp.js +0 -29
  53. package/dist/commands/mcp.js.map +0 -1
  54. package/dist/commands/open.js +0 -28
  55. package/dist/commands/open.js.map +0 -1
  56. package/dist/commands/paste.js +0 -154
  57. package/dist/commands/paste.js.map +0 -1
  58. package/dist/commands/projects.js +0 -36
  59. package/dist/commands/projects.js.map +0 -1
  60. package/dist/commands/search.js +0 -67
  61. package/dist/commands/search.js.map +0 -1
  62. package/dist/commands/semantic.js +0 -173
  63. package/dist/commands/semantic.js.map +0 -1
  64. package/dist/commands/show.js +0 -121
  65. package/dist/commands/show.js.map +0 -1
  66. package/dist/commands/start.js +0 -47
  67. package/dist/commands/start.js.map +0 -1
  68. package/dist/commands/stats.js +0 -133
  69. package/dist/commands/stats.js.map +0 -1
  70. package/dist/commands/status.js +0 -45
  71. package/dist/commands/status.js.map +0 -1
  72. package/dist/commands/stop.js +0 -29
  73. package/dist/commands/stop.js.map +0 -1
  74. package/dist/commands/thread.js +0 -396
  75. package/dist/commands/thread.js.map +0 -1
  76. package/dist/context/formatter.js +0 -103
  77. package/dist/context/formatter.js.map +0 -1
  78. package/dist/daemon/auto-tag-config.js +0 -103
  79. package/dist/daemon/auto-tag-config.js.map +0 -1
  80. package/dist/daemon/auto-tag-config.test.js +0 -72
  81. package/dist/daemon/auto-tag-config.test.js.map +0 -1
  82. package/dist/daemon/auto-title-config.js +0 -70
  83. package/dist/daemon/auto-title-config.js.map +0 -1
  84. package/dist/daemon/bulk-title-jobs.js +0 -170
  85. package/dist/daemon/bulk-title-jobs.js.map +0 -1
  86. package/dist/daemon/correlator.js +0 -320
  87. package/dist/daemon/correlator.js.map +0 -1
  88. package/dist/daemon/discover.js +0 -316
  89. package/dist/daemon/discover.js.map +0 -1
  90. package/dist/daemon/editor-detection.js +0 -186
  91. package/dist/daemon/editor-detection.js.map +0 -1
  92. package/dist/daemon/entrypoint.js.map +0 -1
  93. package/dist/daemon/git-correlator.js +0 -256
  94. package/dist/daemon/git-correlator.js.map +0 -1
  95. package/dist/daemon/mcp-installer.js +0 -108
  96. package/dist/daemon/mcp-installer.js.map +0 -1
  97. package/dist/daemon/onboarding-state.js +0 -140
  98. package/dist/daemon/onboarding-state.js.map +0 -1
  99. package/dist/daemon/pidfile.js +0 -57
  100. package/dist/daemon/pidfile.js.map +0 -1
  101. package/dist/daemon/ports.js +0 -48
  102. package/dist/daemon/ports.js.map +0 -1
  103. package/dist/daemon/scanProgressRegistry.js +0 -62
  104. package/dist/daemon/scanProgressRegistry.js.map +0 -1
  105. package/dist/daemon/server.js +0 -2010
  106. package/dist/daemon/server.js.map +0 -1
  107. package/dist/daemon/tag-scanner/anthropic-client.js +0 -40
  108. package/dist/daemon/tag-scanner/anthropic-client.js.map +0 -1
  109. package/dist/daemon/tag-scanner/autopilot.js +0 -131
  110. package/dist/daemon/tag-scanner/autopilot.js.map +0 -1
  111. package/dist/daemon/tag-scanner/claude-cli-driver.js +0 -250
  112. package/dist/daemon/tag-scanner/claude-cli-driver.js.map +0 -1
  113. package/dist/daemon/tag-scanner/orchestrator.js +0 -88
  114. package/dist/daemon/tag-scanner/orchestrator.js.map +0 -1
  115. package/dist/daemon/tag-scanner/prompt.js +0 -46
  116. package/dist/daemon/tag-scanner/prompt.js.map +0 -1
  117. package/dist/daemon/tag-scanner/prompt.test.js +0 -48
  118. package/dist/daemon/tag-scanner/prompt.test.js.map +0 -1
  119. package/dist/daemon/tag-scanner/scan-state.js +0 -49
  120. package/dist/daemon/tag-scanner/scan-state.js.map +0 -1
  121. package/dist/daemon/tag-scanner/session-fetcher.js +0 -82
  122. package/dist/daemon/tag-scanner/session-fetcher.js.map +0 -1
  123. package/dist/daemon/tag-scanner/session-fetcher.test.js +0 -34
  124. package/dist/daemon/tag-scanner/session-fetcher.test.js.map +0 -1
  125. package/dist/daemon/tag-scanner/validator.js +0 -50
  126. package/dist/daemon/tag-scanner/validator.js.map +0 -1
  127. package/dist/daemon/tag-scanner/validator.test.js +0 -41
  128. package/dist/daemon/tag-scanner/validator.test.js.map +0 -1
  129. package/dist/daemon/terminal-registry.js +0 -443
  130. package/dist/daemon/terminal-registry.js.map +0 -1
  131. package/dist/daemon/ui.js +0 -64
  132. package/dist/daemon/ui.js.map +0 -1
  133. package/dist/daemon/watcher.js +0 -256
  134. package/dist/daemon/watcher.js.map +0 -1
  135. package/dist/db/client.js +0 -22
  136. package/dist/db/client.js.map +0 -1
  137. package/dist/db/schema.js +0 -496
  138. package/dist/db/schema.js.map +0 -1
  139. package/dist/license/api-base.js +0 -13
  140. package/dist/license/api-base.js.map +0 -1
  141. package/dist/license/manager.js +0 -43
  142. package/dist/license/manager.js.map +0 -1
  143. package/dist/license/public-key.js +0 -19
  144. package/dist/license/public-key.js.map +0 -1
  145. package/dist/license/storage.js +0 -27
  146. package/dist/license/storage.js.map +0 -1
  147. package/dist/license/verify.js +0 -23
  148. package/dist/license/verify.js.map +0 -1
  149. package/dist/mcp/audit.js +0 -126
  150. package/dist/mcp/audit.js.map +0 -1
  151. package/dist/mcp/prompts.js +0 -180
  152. package/dist/mcp/prompts.js.map +0 -1
  153. package/dist/mcp/server.js +0 -502
  154. package/dist/mcp/server.js.map +0 -1
  155. package/dist/mcp/thread-tools.js +0 -363
  156. package/dist/mcp/thread-tools.js.map +0 -1
  157. package/dist/mcp/write-tools.js +0 -239
  158. package/dist/mcp/write-tools.js.map +0 -1
  159. package/dist/parser/jsonl.js +0 -150
  160. package/dist/parser/jsonl.js.map +0 -1
  161. package/dist/semantic/chunker.js +0 -47
  162. package/dist/semantic/chunker.js.map +0 -1
  163. package/dist/semantic/config.js +0 -74
  164. package/dist/semantic/config.js.map +0 -1
  165. package/dist/semantic/embedder.js +0 -54
  166. package/dist/semantic/embedder.js.map +0 -1
  167. package/dist/semantic/fusion.js +0 -38
  168. package/dist/semantic/fusion.js.map +0 -1
  169. package/dist/semantic/model-download.js +0 -69
  170. package/dist/semantic/model-download.js.map +0 -1
  171. package/dist/semantic/pipeline.js +0 -375
  172. package/dist/semantic/pipeline.js.map +0 -1
  173. package/dist/semantic/query.js +0 -42
  174. package/dist/semantic/query.js.map +0 -1
  175. package/dist/semantic/worker.js +0 -78
  176. package/dist/semantic/worker.js.map +0 -1
  177. package/dist/stats/backfill.js +0 -151
  178. package/dist/stats/backfill.js.map +0 -1
  179. package/dist/stats/health.js +0 -102
  180. package/dist/stats/health.js.map +0 -1
  181. package/dist/stats/query.js +0 -385
  182. package/dist/stats/query.js.map +0 -1
  183. package/dist/utils/aliases.js +0 -107
  184. package/dist/utils/aliases.js.map +0 -1
  185. package/dist/utils/autoCollections.js +0 -635
  186. package/dist/utils/autoCollections.js.map +0 -1
  187. package/dist/utils/autoTitle.js +0 -348
  188. package/dist/utils/autoTitle.js.map +0 -1
  189. package/dist/utils/collections.js +0 -446
  190. package/dist/utils/collections.js.map +0 -1
  191. package/dist/utils/format.js +0 -46
  192. package/dist/utils/format.js.map +0 -1
  193. package/dist/utils/notes.js +0 -270
  194. package/dist/utils/notes.js.map +0 -1
  195. package/dist/utils/paths.js +0 -50
  196. package/dist/utils/paths.js.map +0 -1
  197. package/dist/utils/pricing.js +0 -257
  198. package/dist/utils/pricing.js.map +0 -1
  199. package/dist/utils/secret-scanner.js +0 -166
  200. package/dist/utils/secret-scanner.js.map +0 -1
  201. package/dist/utils/sessionLabel.js +0 -64
  202. package/dist/utils/sessionLabel.js.map +0 -1
  203. package/dist/utils/tags.js +0 -97
  204. package/dist/utils/tags.js.map +0 -1
  205. package/dist/utils/thread-context.js +0 -129
  206. package/dist/utils/thread-context.js.map +0 -1
  207. package/dist/utils/threadFilter.js +0 -18
  208. package/dist/utils/threadFilter.js.map +0 -1
  209. package/dist/utils/threads-titler.js +0 -298
  210. package/dist/utils/threads-titler.js.map +0 -1
  211. package/dist/utils/threads.js +0 -383
  212. package/dist/utils/threads.js.map +0 -1
  213. package/dist/utils/usage.js +0 -76
  214. package/dist/utils/usage.js.map +0 -1
  215. package/dist/verification/compute.js +0 -88
  216. package/dist/verification/compute.js.map +0 -1
  217. package/dist/verification/config.js +0 -34
  218. package/dist/verification/config.js.map +0 -1
  219. package/dist/web/assets/index-CIr6J4Fw.js +0 -1201
  220. package/dist/web/assets/index-Ctc8g9Jw.css +0 -1
@@ -1,320 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import { basename } from 'node:path';
4
- import { terminalRegistry, looksLikeClaudeAutoTitle, stripAutoTitlePrefix, } from './terminal-registry.js';
5
- import { getAlias, setAlias } from '../utils/aliases.js';
6
- import { getDb } from '../db/client.js';
7
- import { detectEditorOrigin } from './editor-detection.js';
8
- const execFileP = promisify(execFile);
9
- /**
10
- * v0.7 correlator.
11
- *
12
- * When the file watcher ingests a newly-created JSONL, we attempt to map that
13
- * session to a VS Code terminal the extension has registered. Process-tree
14
- * matching is 100% deterministic and does not rely on timing windows:
15
- *
16
- * 1. lsof finds which process currently has this JSONL file open
17
- * 2. ps finds that process's parent shell PID
18
- * 3. If the parent shell PID is in our terminalRegistry, we auto-alias the
19
- * session with the tab name the user set in VS Code
20
- *
21
- * v0.15, T4 — if the extension isn't installed, we still read the env of the
22
- * live `claude` process to classify the host editor (Cursor / VS Code / Warp
23
- * / iTerm / …). Tab-name entries from the extension still take precedence;
24
- * origin-derived labels are the fallback.
25
- *
26
- * Failures are silent and non-fatal — a session that doesn't get auto-aliased
27
- * is still manually renameable in the UI. The correlator skips sessions that
28
- * already have an alias, so it never overwrites user intent.
29
- */
30
- async function writerPidFor(filePath) {
31
- try {
32
- // `-Fpc` emits `p<pid>\nc<command>` pairs for every process that has the
33
- // file open. lsof's output includes BOTH the active `claude` process
34
- // (the real writer) AND the recall daemon's reader. If we return the
35
- // first pid blindly, the daemon often wins and the correlator links the
36
- // session to whatever shell launched `recall start` — visible symptom:
37
- // a bunch of unrelated sessions all tied to the same shell_pid.
38
- //
39
- // Fix: walk the pairs and prefer the `claude` command. Only fall back to
40
- // the first pid if no claude is in the list (which means claude has
41
- // already exited — the session is historical, and cwd-based matching
42
- // downstream will take over).
43
- const { stdout } = await execFileP('lsof', ['-Fpc', filePath], {
44
- timeout: 2_000,
45
- });
46
- const lines = stdout.split('\n');
47
- let firstPid = null;
48
- let claudePid = null;
49
- let currentPid = null;
50
- for (const line of lines) {
51
- if (line.startsWith('p')) {
52
- currentPid = Number(line.slice(1));
53
- if (Number.isFinite(currentPid) && currentPid > 0) {
54
- if (firstPid == null)
55
- firstPid = currentPid;
56
- }
57
- else {
58
- currentPid = null;
59
- }
60
- }
61
- else if (line.startsWith('c') && currentPid != null) {
62
- const cmd = line.slice(1).trim();
63
- // Match exactly `claude` (the CLI binary) — avoid matching
64
- // `claude-recall-mcp`, `claudeAgents`, etc.
65
- if (cmd === 'claude' && claudePid == null) {
66
- claudePid = currentPid;
67
- }
68
- }
69
- }
70
- return claudePid ?? firstPid;
71
- }
72
- catch {
73
- return null;
74
- }
75
- }
76
- async function parentPidOf(pid) {
77
- try {
78
- const { stdout } = await execFileP('ps', ['-o', 'ppid=', '-p', String(pid)], { timeout: 2_000 });
79
- const ppid = Number(stdout.trim());
80
- return Number.isFinite(ppid) && ppid > 0 ? ppid : null;
81
- }
82
- catch {
83
- return null;
84
- }
85
- }
86
- /**
87
- * Pure decider for what string to auto-alias a session with. Separated from
88
- * the I/O-heavy `tryAutoAlias` so unit tests can exercise the three spec
89
- * scenarios (tab-name wins, origin fallback, neither) without touching ps/lsof
90
- * or SQLite.
91
- *
92
- * Precedence:
93
- * 1. Non-blank, non-generic `tabName` from the VS Code extension wins
94
- * unconditionally. "Generic" means the bare shell binary (zsh, bash,
95
- * fish, sh, pwsh, powershell, cmd) — VS Code ships that as the default
96
- * terminal name when the user hasn't renamed the tab, so treating it as
97
- * a tab name would produce `zsh` aliases for every session.
98
- * 2. Otherwise, if we detected an editor origin via env, compose
99
- * `${origin.label} · ${basename(cwd)} · ${gitBranch}` — dropping the
100
- * cwd part when cwd is null and the git part when gitBranch is null.
101
- * 3. Otherwise, return null — leave the session without an auto-alias so
102
- * the user can still name it manually.
103
- */
104
- const GENERIC_SHELL_NAMES = new Set([
105
- 'zsh',
106
- 'bash',
107
- 'fish',
108
- 'sh',
109
- 'dash',
110
- 'ksh',
111
- 'tcsh',
112
- 'csh',
113
- 'pwsh',
114
- 'powershell',
115
- 'cmd',
116
- 'nu',
117
- ]);
118
- export function isGenericShellName(tabName) {
119
- const trimmed = tabName.trim().toLowerCase();
120
- if (!trimmed)
121
- return true;
122
- // Also treat "-zsh", "/bin/bash", "zsh (1)" style tab names as generic.
123
- const stripped = trimmed
124
- .replace(/^[-/]+/, '')
125
- .replace(/^.*\//, '')
126
- .replace(/\s*\(\d+\)\s*$/, '')
127
- .trim();
128
- return GENERIC_SHELL_NAMES.has(stripped);
129
- }
130
- export function composeAutoAlias(input) {
131
- const trimmedTab = input.tabName?.trim();
132
- if (trimmedTab &&
133
- !isGenericShellName(trimmedTab) &&
134
- !looksLikeClaudeAutoTitle(trimmedTab)) {
135
- return trimmedTab;
136
- }
137
- if (!input.origin)
138
- return null;
139
- const parts = [input.origin.label];
140
- if (input.cwd) {
141
- // basename drops trailing slashes and returns the last path segment —
142
- // `/Users/me/code/api/` → `api`.
143
- const dir = basename(input.cwd.replace(/\/+$/, ''));
144
- if (dir)
145
- parts.push(dir);
146
- }
147
- if (input.gitBranch)
148
- parts.push(input.gitBranch);
149
- return parts.join(' · ');
150
- }
151
- function readSessionMeta(sessionId) {
152
- try {
153
- const row = getDb()
154
- .prepare('SELECT cwd, git_branch FROM sessions WHERE id = ?')
155
- .get(sessionId);
156
- return row ?? null;
157
- }
158
- catch {
159
- return null;
160
- }
161
- }
162
- /**
163
- * Best-effort auto-alias attempt. Idempotent: if the session already has an
164
- * alias, or if we can't figure out which terminal owned it, we do nothing.
165
- *
166
- * Link strategies, in priority order:
167
- *
168
- * 1. **Pending claude-start (deterministic).** The VS Code extension fires
169
- * `onDidStartTerminalShellExecution` when the user types `claude` in a
170
- * terminal and POSTs (shell_pid, tab_name, cwd, started_at) to the
171
- * daemon. If a fresh entry exists for this session's cwd, link directly
172
- * to that shell_pid — no lsof, no ppid walk. This path covers ~99% of
173
- * real launches.
174
- * 2. **Process-tree (lsof + ppid walk).** Legacy fallback for non-VS-Code
175
- * terminals or VS Code without shell integration. Walks up to 4
176
- * ancestors of the lsof writer.
177
- * 3. **CWD-newest.** Final fallback: pick the newest registered terminal in
178
- * the same cwd. Loose, but lets renames propagate later.
179
- */
180
- export async function tryAutoAlias(filePath) {
181
- const sessionId = basename(filePath, '.jsonl');
182
- if (getAlias(sessionId))
183
- return;
184
- // Read session meta first — both the pending-match check and the cwd
185
- // fallback need it.
186
- const meta = readSessionMeta(sessionId);
187
- let entry = null;
188
- let matchedPid = null;
189
- let matchStrategy = null;
190
- // Strategy 1 — deterministic. The extension already told us which shell
191
- // is about to spawn this session.
192
- const pending = terminalRegistry.takePending(meta?.cwd ?? null, 30_000);
193
- if (pending) {
194
- matchedPid = pending.shell_pid;
195
- matchStrategy = 'pending';
196
- // Prefer the live registry entry (the extension's poll loop keeps it up
197
- // to date with the latest user-set tab name). Fall back to a synthetic
198
- // entry built from the pending payload itself when the registry hasn't
199
- // seen this pid yet — short-lived terminals can fire claude-started
200
- // before the next sync tick.
201
- const live = terminalRegistry.get(pending.shell_pid);
202
- entry =
203
- live ?? {
204
- shell_pid: pending.shell_pid,
205
- tab_name: pending.tab_name,
206
- cwd: pending.cwd,
207
- opened_at: pending.started_at,
208
- last_seen_at: pending.started_at,
209
- };
210
- }
211
- // Best-effort writerPid + origin lookup — runs regardless of which link
212
- // strategy wins, so the editor badge gets populated even when we already
213
- // know the shell pid.
214
- const writerPid = await writerPidFor(filePath);
215
- const origin = writerPid ? await detectEditorOrigin(writerPid) : null;
216
- if (origin)
217
- terminalRegistry.setOrigin(sessionId, origin);
218
- // Strategy 2 — process-tree fallback. Only fires when the deterministic
219
- // path didn't match.
220
- if (!entry && writerPid) {
221
- let currentPid = writerPid;
222
- for (let hop = 0; hop < 4 && currentPid != null; hop++) {
223
- const nextPid = await parentPidOf(currentPid);
224
- if (!nextPid)
225
- break;
226
- const candidate = terminalRegistry.get(nextPid);
227
- if (candidate) {
228
- entry = candidate;
229
- matchedPid = nextPid;
230
- matchStrategy = 'ppid';
231
- break;
232
- }
233
- currentPid = nextPid;
234
- }
235
- }
236
- // Strategy 3 — cwd-newest. Loose match, but at least we can propagate
237
- // future renames. Skip if we already won via pending or ppid.
238
- if (!entry && meta?.cwd) {
239
- const sessionCwd = meta.cwd.replace(/\/+$/, '');
240
- const sameCwd = terminalRegistry
241
- .all()
242
- .filter((t) => t.cwd && t.cwd.replace(/\/+$/, '') === sessionCwd);
243
- if (sameCwd.length > 0) {
244
- const newest = sameCwd.sort((a, b) => Date.parse(b.opened_at) - Date.parse(a.opened_at))[0];
245
- entry = newest;
246
- matchedPid = newest.shell_pid;
247
- matchStrategy = 'cwd';
248
- }
249
- }
250
- // Name resolution order (initial alias only — the LINK to matchedPid is
251
- // already set, so future renames propagate regardless of which name we
252
- // pick now):
253
- // 1. If matched terminal has a clean name: use it.
254
- // 2. Else if matched terminal has a claude auto-title we can strip
255
- // (e.g. "✳ Claude Code" → "Claude Code"): use the stripped version.
256
- // 3. Else, ONLY for non-deterministic strategies (ppid / cwd), look for
257
- // a clean name on a sibling terminal in the same cwd. The
258
- // deterministic path REFUSES sibling fallback — that's exactly the
259
- // "session inherited a sibling's name" bug we set out to fix.
260
- // 4. Else the origin-based composition takes over in composeAutoAlias.
261
- let resolvedTabName = null;
262
- if (entry?.tab_name &&
263
- !isGenericShellName(entry.tab_name) &&
264
- !looksLikeClaudeAutoTitle(entry.tab_name)) {
265
- resolvedTabName = entry.tab_name;
266
- }
267
- else if (entry?.tab_name && looksLikeClaudeAutoTitle(entry.tab_name)) {
268
- const stripped = stripAutoTitlePrefix(entry.tab_name);
269
- if (stripped && !isGenericShellName(stripped))
270
- resolvedTabName = stripped;
271
- }
272
- if (!resolvedTabName && matchStrategy !== 'pending' && meta?.cwd) {
273
- const sessionCwd = meta.cwd.replace(/\/+$/, '');
274
- const alternative = terminalRegistry
275
- .all()
276
- .filter((t) => t.shell_pid !== matchedPid &&
277
- t.cwd &&
278
- t.cwd.replace(/\/+$/, '') === sessionCwd &&
279
- !isGenericShellName(t.tab_name) &&
280
- !looksLikeClaudeAutoTitle(t.tab_name))
281
- .sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at))[0];
282
- if (alternative)
283
- resolvedTabName = alternative.tab_name;
284
- }
285
- const alias = composeAutoAlias({
286
- tabName: resolvedTabName,
287
- origin,
288
- cwd: meta?.cwd ?? null,
289
- gitBranch: meta?.git_branch ?? null,
290
- });
291
- if (!alias)
292
- return;
293
- try {
294
- setAlias(sessionId, alias);
295
- const usedTabName = !!resolvedTabName &&
296
- !isGenericShellName(resolvedTabName) &&
297
- !looksLikeClaudeAutoTitle(resolvedTabName) &&
298
- alias === resolvedTabName.trim();
299
- // Always link the session to its originating shell pid — even if we
300
- // fell back to the origin label. A later terminal rename should still
301
- // propagate to this session's alias.
302
- if (matchedPid != null) {
303
- terminalRegistry.linkSession(sessionId, matchedPid);
304
- }
305
- const matchTag = matchStrategy === 'pending' ? 'pending-claude-start match' : matchStrategy ?? 'unknown';
306
- // eslint-disable-next-line no-console
307
- console.log(`[correlator] auto-aliased ${sessionId.slice(0, 8)} → "${alias}"` +
308
- (usedTabName
309
- ? ` (tab name via ${matchTag}, shell pid ${matchedPid})`
310
- : entry
311
- ? ` (generic shell name "${entry.tab_name}" → ${origin?.editor ?? 'origin'} fallback, shell pid ${matchedPid})`
312
- : origin
313
- ? ` (${origin.editor} origin — no terminal match)`
314
- : ''));
315
- }
316
- catch {
317
- /* non-fatal */
318
- }
319
- }
320
- //# sourceMappingURL=correlator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/daemon/correlator.ts"],"names":[],"mappings":"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"}
@@ -1,316 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import { stat } from 'node:fs/promises';
4
- import { getDb } from '../db/client.js';
5
- import { estimateCost, formatDollars, formatTokens, priceFor } from '../utils/pricing.js';
6
- import { findSessionsByCommit } from './git-correlator.js';
7
- const execFileP = promisify(execFile);
8
- /**
9
- * v0.12b — Rediscovery surface. Three independent "For you" picks that
10
- * consume the data streams shipped in v0.10a (cost), v0.10b (git), and
11
- * v0.11 (semantic). Each picker degrades gracefully when its backing
12
- * feature has no data yet — the corresponding field in the response is
13
- * just `null` and the UI quietly hides that card.
14
- *
15
- * Invariants:
16
- * - Purely local. No outbound HTTP, no telemetry.
17
- * - `authored` spawns `git rev-parse HEAD` scoped to the session's own
18
- * cwd via execFile (array args, no shell). Same hardening posture as
19
- * the v0.10b git-correlator.
20
- * - Any picker can throw; `discoverToday` catches per-picker so a single
21
- * failure never blanks the whole surface.
22
- */
23
- const REDISCOVERY_MIN_AGE_DAYS = 60;
24
- const RECENT_WINDOW_DAYS = 7;
25
- const EXPENSIVE_WINDOW_DAYS = 7;
26
- const GIT_HEAD_TIMEOUT_MS = 5_000;
27
- function detectAvailability() {
28
- const db = getDb();
29
- // All three existence checks are read-only and microsecond-fast because
30
- // the indexes are already in place. We still wrap in try/catch — a fresh
31
- // DB that predates some migrations could theoretically be missing a table.
32
- const exists = (sql) => {
33
- try {
34
- return !!db.prepare(sql).get();
35
- }
36
- catch {
37
- return false;
38
- }
39
- };
40
- return {
41
- semantic: exists('SELECT 1 FROM session_semantic LIMIT 1'),
42
- cost: exists(`SELECT 1 FROM sessions
43
- WHERE (COALESCE(total_input_tokens,0)
44
- + COALESCE(total_output_tokens,0)
45
- + COALESCE(total_cache_create_tokens,0)
46
- + COALESCE(total_cache_read_tokens,0)) > 0
47
- LIMIT 1`),
48
- git: exists('SELECT 1 FROM session_commits LIMIT 1'),
49
- };
50
- }
51
- function splitKeywords(csv) {
52
- if (!csv)
53
- return [];
54
- const seen = new Set();
55
- const out = [];
56
- for (const raw of csv.split(',')) {
57
- const k = raw.trim().toLowerCase();
58
- if (!k || seen.has(k))
59
- continue;
60
- seen.add(k);
61
- out.push(k);
62
- }
63
- return out;
64
- }
65
- function toHeader(row) {
66
- return {
67
- sessionId: row.session_id,
68
- project: row.project,
69
- alias: row.alias,
70
- startedAt: row.started_at,
71
- endedAt: row.ended_at,
72
- firstUserMessage: row.first_user_message,
73
- };
74
- }
75
- /**
76
- * Pick one session from 60+ days ago whose semantic keyword set overlaps
77
- * with the union of keyword sets from the last 7 days. Highest overlap
78
- * wins; ties break toward the oldest session (maximises the "rediscovery"
79
- * effect). Returns null when the semantic index is empty or there is no
80
- * non-zero overlap.
81
- */
82
- export function pickRediscovered() {
83
- const db = getDb();
84
- const recentKeywordRows = db
85
- .prepare(`SELECT ss.keywords
86
- FROM session_semantic ss
87
- JOIN sessions s ON s.id = ss.session_id
88
- WHERE s.started_at IS NOT NULL
89
- AND julianday('now') - julianday(s.started_at) <= @windowDays`)
90
- .all({ windowDays: RECENT_WINDOW_DAYS });
91
- if (recentKeywordRows.length === 0)
92
- return null;
93
- const recentKw = new Set();
94
- for (const r of recentKeywordRows) {
95
- for (const k of splitKeywords(r.keywords))
96
- recentKw.add(k);
97
- }
98
- if (recentKw.size === 0)
99
- return null;
100
- const candidates = db
101
- .prepare(`SELECT ss.session_id AS session_id,
102
- ss.summary AS summary,
103
- ss.keywords AS keywords,
104
- p.name AS project,
105
- NULLIF(sa.alias, '') AS alias,
106
- s.started_at AS started_at,
107
- s.ended_at AS ended_at,
108
- s.first_user_message AS first_user_message,
109
- julianday('now') - julianday(s.started_at) AS days_old
110
- FROM session_semantic ss
111
- JOIN sessions s ON s.id = ss.session_id
112
- JOIN projects p ON p.id = s.project_id
113
- LEFT JOIN session_aliases sa ON sa.session_id = s.id
114
- WHERE s.started_at IS NOT NULL
115
- AND s.message_count > 2
116
- AND julianday('now') - julianday(s.started_at) >= @ageDays
117
- ORDER BY s.started_at ASC`)
118
- .all({ ageDays: REDISCOVERY_MIN_AGE_DAYS });
119
- if (candidates.length === 0)
120
- return null;
121
- let best = null;
122
- for (const row of candidates) {
123
- const kw = splitKeywords(row.keywords);
124
- const overlap = kw.filter((k) => recentKw.has(k));
125
- if (overlap.length === 0)
126
- continue;
127
- if (!best || overlap.length > best.overlap.length) {
128
- best = { row, overlap };
129
- }
130
- }
131
- if (!best)
132
- return null;
133
- return {
134
- ...toHeader(best.row),
135
- summary: best.row.summary,
136
- keywords: splitKeywords(best.row.keywords),
137
- matchedKeywords: best.overlap,
138
- daysAgo: Math.max(0, Math.round(best.row.days_old)),
139
- };
140
- }
141
- /**
142
- * Pick the single highest-cost session in the last 7 days. Uses the
143
- * per-session rollup columns populated by v0.10a; skips sessions whose
144
- * rollups are all zero (either because they have no usage data yet or
145
- * because backfill hasn't run). Returns null when no 7-day session has
146
- * non-zero cost.
147
- */
148
- export function pickExpensive() {
149
- const db = getDb();
150
- const rows = db
151
- .prepare(`SELECT s.id AS session_id,
152
- p.name AS project,
153
- NULLIF(sa.alias, '') AS alias,
154
- s.started_at AS started_at,
155
- s.ended_at AS ended_at,
156
- s.first_user_message AS first_user_message,
157
- s.primary_model AS primary_model,
158
- COALESCE(s.total_input_tokens, 0) AS input_tokens,
159
- COALESCE(s.total_output_tokens, 0) AS output_tokens,
160
- COALESCE(s.total_cache_create_tokens, 0) AS cache_create_tokens,
161
- COALESCE(s.total_cache_read_tokens, 0) AS cache_read_tokens
162
- FROM sessions s
163
- JOIN projects p ON p.id = s.project_id
164
- LEFT JOIN session_aliases sa ON sa.session_id = s.id
165
- WHERE s.started_at IS NOT NULL
166
- AND julianday('now') - julianday(s.started_at) <= @windowDays
167
- AND (COALESCE(s.total_input_tokens, 0)
168
- + COALESCE(s.total_output_tokens, 0)
169
- + COALESCE(s.total_cache_create_tokens, 0)
170
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`)
171
- .all({ windowDays: EXPENSIVE_WINDOW_DAYS });
172
- if (rows.length === 0)
173
- return null;
174
- let best = null;
175
- for (const row of rows) {
176
- const cost = estimateCost({
177
- inputTokens: row.input_tokens,
178
- outputTokens: row.output_tokens,
179
- cacheCreateTokens: row.cache_create_tokens,
180
- cacheReadTokens: row.cache_read_tokens,
181
- }, row.primary_model);
182
- if (cost.cents <= 0)
183
- continue;
184
- if (!best || cost.cents > best.cents) {
185
- best = { row, cents: cost.cents, totalTokens: cost.totalTokens };
186
- }
187
- }
188
- if (!best)
189
- return null;
190
- return {
191
- ...toHeader(best.row),
192
- totalTokens: best.totalTokens,
193
- costCents: best.cents,
194
- costDisplay: formatDollars(best.cents),
195
- tokensDisplay: formatTokens(best.totalTokens),
196
- primaryModel: best.row.primary_model,
197
- primaryModelLabel: priceFor(best.row.primary_model).label,
198
- };
199
- }
200
- async function readHeadSha(cwd) {
201
- // Scoped subprocess; array args; read-only subcommand. Mirrors the
202
- // discipline in src/daemon/git-correlator.ts — see that file for why.
203
- try {
204
- const s = await stat(cwd);
205
- if (!s.isDirectory())
206
- return null;
207
- }
208
- catch {
209
- return null;
210
- }
211
- try {
212
- const { stdout } = await execFileP('git', ['rev-parse', 'HEAD'], {
213
- cwd,
214
- timeout: GIT_HEAD_TIMEOUT_MS,
215
- });
216
- const sha = stdout.trim();
217
- return /^[0-9a-f]{40}$/.test(sha) ? sha : null;
218
- }
219
- catch {
220
- return null;
221
- }
222
- }
223
- /**
224
- * Pick the session that authored the current HEAD in the cwd of the most
225
- * recent session. When multiple sessions share a commit (rare — overlap
226
- * at session boundaries) we keep the first row of findSessionsByCommit,
227
- * which is ordered by committed_at DESC so the freshest window wins.
228
- */
229
- export async function pickAuthored() {
230
- const db = getDb();
231
- const recent = db
232
- .prepare(`SELECT s.id AS id, s.cwd AS cwd
233
- FROM sessions s
234
- WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
235
- ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
236
- LIMIT 1`)
237
- .get();
238
- if (!recent?.cwd)
239
- return null;
240
- const headSha = await readHeadSha(recent.cwd);
241
- if (!headSha)
242
- return null;
243
- const matches = findSessionsByCommit(headSha);
244
- if (matches.length === 0)
245
- return null;
246
- const first = matches[0];
247
- // First-user-message isn't on BlameRow; fetch it for the card subtitle.
248
- const meta = db
249
- .prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
250
- FROM sessions s
251
- WHERE s.id = ?`)
252
- .get(first.sessionId);
253
- return {
254
- sessionId: first.sessionId,
255
- project: first.project,
256
- alias: first.alias,
257
- startedAt: first.startedAt,
258
- endedAt: meta?.ended_at ?? first.endedAt,
259
- firstUserMessage: meta?.first_user_message ?? null,
260
- commitSha: first.commitSha,
261
- shortSha: first.commitSha.slice(0, 7),
262
- subject: first.subject,
263
- committedAt: first.committedAt,
264
- cwd: recent.cwd,
265
- };
266
- }
267
- /**
268
- * Orchestrator. Runs all three pickers in parallel so a slow `git
269
- * rev-parse` (e.g. cold-cache repo) doesn't block the synchronous picks.
270
- * Per-picker errors are swallowed — the corresponding field becomes
271
- * `null` and the UI hides that card.
272
- */
273
- export async function discoverToday() {
274
- const availability = detectAvailability();
275
- const rediscoveredPromise = availability.semantic
276
- ? Promise.resolve().then(() => {
277
- try {
278
- return pickRediscovered();
279
- }
280
- catch (err) {
281
- console.error('[discover.rediscovered]', err);
282
- return null;
283
- }
284
- })
285
- : Promise.resolve(null);
286
- const expensivePromise = availability.cost
287
- ? Promise.resolve().then(() => {
288
- try {
289
- return pickExpensive();
290
- }
291
- catch (err) {
292
- console.error('[discover.expensive]', err);
293
- return null;
294
- }
295
- })
296
- : Promise.resolve(null);
297
- const authoredPromise = availability.git
298
- ? pickAuthored().catch((err) => {
299
- console.error('[discover.authored]', err);
300
- return null;
301
- })
302
- : Promise.resolve(null);
303
- const [rediscovered, expensive, authored] = await Promise.all([
304
- rediscoveredPromise,
305
- expensivePromise,
306
- authoredPromise,
307
- ]);
308
- return {
309
- rediscovered,
310
- expensive,
311
- authored,
312
- availability,
313
- generatedAt: new Date().toISOString(),
314
- };
315
- }
316
- //# sourceMappingURL=discover.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/daemon/discover.ts"],"names":[],"mappings":"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"}