@clauderecallhq/cli 0.0.1 → 0.12.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/LICENSE +33 -0
- package/README.md +543 -3
- package/README.public.md +523 -0
- package/dist/cli.js +362 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/activate.js +69 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/audit-secrets.js +103 -0
- package/dist/commands/audit-secrets.js.map +1 -0
- package/dist/commands/blame.js +35 -0
- package/dist/commands/blame.js.map +1 -0
- package/dist/commands/config-verification.js +18 -0
- package/dist/commands/config-verification.js.map +1 -0
- package/dist/commands/context.js +144 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/correlate.js +70 -0
- package/dist/commands/correlate.js.map +1 -0
- package/dist/commands/digest.js +78 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/health.js +62 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/index.js +247 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/install-extension.js +138 -0
- package/dist/commands/install-extension.js.map +1 -0
- package/dist/commands/installs.js +128 -0
- package/dist/commands/installs.js.map +1 -0
- package/dist/commands/license.js +39 -0
- package/dist/commands/license.js.map +1 -0
- package/dist/commands/list.js +47 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/mcp.js +29 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/open.js +28 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/paste.js +154 -0
- package/dist/commands/paste.js.map +1 -0
- package/dist/commands/projects.js +36 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/search.js +67 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/semantic.js +173 -0
- package/dist/commands/semantic.js.map +1 -0
- package/dist/commands/show.js +121 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/start.js +47 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/stats.js +133 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/status.js +45 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.js +29 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/thread.js +396 -0
- package/dist/commands/thread.js.map +1 -0
- package/dist/context/formatter.js +103 -0
- package/dist/context/formatter.js.map +1 -0
- package/dist/daemon/auto-tag-config.js +103 -0
- package/dist/daemon/auto-tag-config.js.map +1 -0
- package/dist/daemon/auto-tag-config.test.js +72 -0
- package/dist/daemon/auto-tag-config.test.js.map +1 -0
- package/dist/daemon/auto-title-config.js +70 -0
- package/dist/daemon/auto-title-config.js.map +1 -0
- package/dist/daemon/bulk-title-jobs.js +170 -0
- package/dist/daemon/bulk-title-jobs.js.map +1 -0
- package/dist/daemon/correlator.js +320 -0
- package/dist/daemon/correlator.js.map +1 -0
- package/dist/daemon/discover.js +316 -0
- package/dist/daemon/discover.js.map +1 -0
- package/dist/daemon/editor-detection.js +186 -0
- package/dist/daemon/editor-detection.js.map +1 -0
- package/dist/daemon/entrypoint.js +55 -0
- package/dist/daemon/entrypoint.js.map +1 -0
- package/dist/daemon/git-correlator.js +256 -0
- package/dist/daemon/git-correlator.js.map +1 -0
- package/dist/daemon/mcp-installer.js +108 -0
- package/dist/daemon/mcp-installer.js.map +1 -0
- package/dist/daemon/onboarding-state.js +140 -0
- package/dist/daemon/onboarding-state.js.map +1 -0
- package/dist/daemon/pidfile.js +57 -0
- package/dist/daemon/pidfile.js.map +1 -0
- package/dist/daemon/ports.js +48 -0
- package/dist/daemon/ports.js.map +1 -0
- package/dist/daemon/scanProgressRegistry.js +62 -0
- package/dist/daemon/scanProgressRegistry.js.map +1 -0
- package/dist/daemon/server.js +2010 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/tag-scanner/anthropic-client.js +40 -0
- package/dist/daemon/tag-scanner/anthropic-client.js.map +1 -0
- package/dist/daemon/tag-scanner/autopilot.js +131 -0
- package/dist/daemon/tag-scanner/autopilot.js.map +1 -0
- package/dist/daemon/tag-scanner/claude-cli-driver.js +250 -0
- package/dist/daemon/tag-scanner/claude-cli-driver.js.map +1 -0
- package/dist/daemon/tag-scanner/orchestrator.js +88 -0
- package/dist/daemon/tag-scanner/orchestrator.js.map +1 -0
- package/dist/daemon/tag-scanner/prompt.js +46 -0
- package/dist/daemon/tag-scanner/prompt.js.map +1 -0
- package/dist/daemon/tag-scanner/prompt.test.js +48 -0
- package/dist/daemon/tag-scanner/prompt.test.js.map +1 -0
- package/dist/daemon/tag-scanner/scan-state.js +49 -0
- package/dist/daemon/tag-scanner/scan-state.js.map +1 -0
- package/dist/daemon/tag-scanner/session-fetcher.js +82 -0
- package/dist/daemon/tag-scanner/session-fetcher.js.map +1 -0
- package/dist/daemon/tag-scanner/session-fetcher.test.js +34 -0
- package/dist/daemon/tag-scanner/session-fetcher.test.js.map +1 -0
- package/dist/daemon/tag-scanner/validator.js +50 -0
- package/dist/daemon/tag-scanner/validator.js.map +1 -0
- package/dist/daemon/tag-scanner/validator.test.js +41 -0
- package/dist/daemon/tag-scanner/validator.test.js.map +1 -0
- package/dist/daemon/terminal-registry.js +443 -0
- package/dist/daemon/terminal-registry.js.map +1 -0
- package/dist/daemon/ui.js +64 -0
- package/dist/daemon/ui.js.map +1 -0
- package/dist/daemon/watcher.js +256 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/db/client.js +22 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/schema.js +496 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/license/api-base.js +13 -0
- package/dist/license/api-base.js.map +1 -0
- package/dist/license/manager.js +43 -0
- package/dist/license/manager.js.map +1 -0
- package/dist/license/public-key.js +19 -0
- package/dist/license/public-key.js.map +1 -0
- package/dist/license/storage.js +27 -0
- package/dist/license/storage.js.map +1 -0
- package/dist/license/verify.js +23 -0
- package/dist/license/verify.js.map +1 -0
- package/dist/mcp/audit.js +126 -0
- package/dist/mcp/audit.js.map +1 -0
- package/dist/mcp/prompts.js +180 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/server.js +502 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/thread-tools.js +363 -0
- package/dist/mcp/thread-tools.js.map +1 -0
- package/dist/mcp/write-tools.js +239 -0
- package/dist/mcp/write-tools.js.map +1 -0
- package/dist/parser/jsonl.js +150 -0
- package/dist/parser/jsonl.js.map +1 -0
- package/dist/semantic/chunker.js +47 -0
- package/dist/semantic/chunker.js.map +1 -0
- package/dist/semantic/config.js +74 -0
- package/dist/semantic/config.js.map +1 -0
- package/dist/semantic/embedder.js +54 -0
- package/dist/semantic/embedder.js.map +1 -0
- package/dist/semantic/fusion.js +38 -0
- package/dist/semantic/fusion.js.map +1 -0
- package/dist/semantic/model-download.js +69 -0
- package/dist/semantic/model-download.js.map +1 -0
- package/dist/semantic/pipeline.js +375 -0
- package/dist/semantic/pipeline.js.map +1 -0
- package/dist/semantic/query.js +42 -0
- package/dist/semantic/query.js.map +1 -0
- package/dist/semantic/worker.js +78 -0
- package/dist/semantic/worker.js.map +1 -0
- package/dist/stats/backfill.js +151 -0
- package/dist/stats/backfill.js.map +1 -0
- package/dist/stats/health.js +102 -0
- package/dist/stats/health.js.map +1 -0
- package/dist/stats/query.js +385 -0
- package/dist/stats/query.js.map +1 -0
- package/dist/utils/aliases.js +107 -0
- package/dist/utils/aliases.js.map +1 -0
- package/dist/utils/autoCollections.js +635 -0
- package/dist/utils/autoCollections.js.map +1 -0
- package/dist/utils/autoTitle.js +348 -0
- package/dist/utils/autoTitle.js.map +1 -0
- package/dist/utils/collections.js +446 -0
- package/dist/utils/collections.js.map +1 -0
- package/dist/utils/format.js +46 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/notes.js +270 -0
- package/dist/utils/notes.js.map +1 -0
- package/dist/utils/paths.js +50 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/pricing.js +257 -0
- package/dist/utils/pricing.js.map +1 -0
- package/dist/utils/secret-scanner.js +166 -0
- package/dist/utils/secret-scanner.js.map +1 -0
- package/dist/utils/sessionLabel.js +64 -0
- package/dist/utils/sessionLabel.js.map +1 -0
- package/dist/utils/tags.js +97 -0
- package/dist/utils/tags.js.map +1 -0
- package/dist/utils/thread-context.js +129 -0
- package/dist/utils/thread-context.js.map +1 -0
- package/dist/utils/threadFilter.js +18 -0
- package/dist/utils/threadFilter.js.map +1 -0
- package/dist/utils/threads-titler.js +298 -0
- package/dist/utils/threads-titler.js.map +1 -0
- package/dist/utils/threads.js +383 -0
- package/dist/utils/threads.js.map +1 -0
- package/dist/utils/usage.js +76 -0
- package/dist/utils/usage.js.map +1 -0
- package/dist/verification/compute.js +88 -0
- package/dist/verification/compute.js.map +1 -0
- package/dist/verification/config.js +34 -0
- package/dist/verification/config.js.map +1 -0
- package/dist/web/assets/index-CIr6J4Fw.js +1201 -0
- package/dist/web/assets/index-Ctc8g9Jw.css +1 -0
- package/dist/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/dist/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/dist/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- package/dist/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-700-normal-CjBOestx.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-700-normal-DrXBdSj3.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-700-normal-LO58E6JB.woff +0 -0
- package/dist/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/dist/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/dist/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/dist/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/dist/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- package/dist/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- package/dist/web/assets/inter-greek-700-normal-BUv2fZ6O.woff +0 -0
- package/dist/web/assets/inter-greek-700-normal-C3JjAnD8.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/dist/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/dist/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- package/dist/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-700-normal-BoQ6DsYi.woff +0 -0
- package/dist/web/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2 +0 -0
- package/dist/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/dist/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/dist/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/dist/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/dist/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/dist/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/dist/web/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- package/dist/web/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/dist/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/dist/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- package/dist/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-700-normal-TidjK2hL.woff +0 -0
- package/dist/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/dist/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/dist/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- package/dist/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-700-normal-BZaoP0fm.woff +0 -0
- package/dist/web/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
- package/dist/web/favicon.svg +9 -0
- package/dist/web/index.html +15 -0
- package/package.json +80 -9
- package/bin/cli.js +0 -12
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal registry for the VS Code / Cursor / Windsurf extension.
|
|
3
|
+
*
|
|
4
|
+
* The extension POSTs terminal lifecycle events (opened / renamed / closed /
|
|
5
|
+
* sync) to the daemon. We keep entries in memory AND persist them to
|
|
6
|
+
* `$RECALL_HOME/terminals.json`, so that:
|
|
7
|
+
*
|
|
8
|
+
* - `recall stop && recall start` no longer wipes the registry.
|
|
9
|
+
* - The correlator can resolve writerPid → tab_name even for sessions that
|
|
10
|
+
* start a few seconds after the daemon comes up, before the extension
|
|
11
|
+
* has re-snapshotted.
|
|
12
|
+
* - Renames propagate to existing session aliases (see sessionsByPid).
|
|
13
|
+
*
|
|
14
|
+
* Entries older than 24 hours are evicted — keeps the file bounded. Dead
|
|
15
|
+
* shell PIDs are also purged on load so we don't keep ghost entries forever.
|
|
16
|
+
*
|
|
17
|
+
* The actual correlation step — matching a shell PID to a Claude Code session
|
|
18
|
+
* UUID via process-tree walking — lives in correlator.ts. This module just
|
|
19
|
+
* holds state and persistence.
|
|
20
|
+
*
|
|
21
|
+
* v0.15, T4 — second parallel map: sessionId → EditorOrigin, populated by
|
|
22
|
+
* env-based editor detection when the extension isn't installed. Tab-name
|
|
23
|
+
* entries still take precedence over origin-derived aliases in the correlator.
|
|
24
|
+
*/
|
|
25
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import { join } from 'node:path';
|
|
27
|
+
import { RECALL_HOME, ensureRecallHome } from '../utils/paths.js';
|
|
28
|
+
export const TERMINALS_FILE = join(RECALL_HOME, 'terminals.json');
|
|
29
|
+
const MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
30
|
+
const PENDING_CLAUDE_TTL_MS = 30_000;
|
|
31
|
+
/**
|
|
32
|
+
* Names that Claude Code writes to the terminal tab via escape codes — we
|
|
33
|
+
* must NOT let these overwrite a user-set terminal name. They mutate ~every
|
|
34
|
+
* second (spinner animation, version string, first-message excerpt) and
|
|
35
|
+
* would otherwise churn the session alias continuously.
|
|
36
|
+
*
|
|
37
|
+
* Matches:
|
|
38
|
+
* - Spinner braille glyphs: ⠂ ⠐ ⠠ ⠄ ⠈ ⠁ ⠀ and the full U+2800–U+28FF range
|
|
39
|
+
* - The ✳ "busy" indicator Claude Code prepends while processing
|
|
40
|
+
* - Pure version strings: "2.1.119", "3.0.0", "1.0"
|
|
41
|
+
*
|
|
42
|
+
* When the daemon receives a name matching any of these, it keeps whatever
|
|
43
|
+
* reliable name the pid had before (even if that's "zsh") rather than
|
|
44
|
+
* letting Claude Code's ephemeral UI win.
|
|
45
|
+
*/
|
|
46
|
+
const SPINNER_PREFIX_RE = /^[⠀-⣿✳\s]+/;
|
|
47
|
+
const VERSION_ONLY_RE = /^\d+(\.\d+){1,3}$/;
|
|
48
|
+
export function looksLikeClaudeAutoTitle(name) {
|
|
49
|
+
const trimmed = name.trim();
|
|
50
|
+
if (!trimmed)
|
|
51
|
+
return true;
|
|
52
|
+
if (SPINNER_PREFIX_RE.test(trimmed))
|
|
53
|
+
return true;
|
|
54
|
+
if (VERSION_ONLY_RE.test(trimmed))
|
|
55
|
+
return true;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Best-effort: pull a usable human name out of Claude Code's auto-title.
|
|
60
|
+
* Example: "✳ Claude Code" → "Claude Code"
|
|
61
|
+
* "⠐ Upgrade npm packages" → "Upgrade npm packages"
|
|
62
|
+
* "2.1.119" → null (pure version, no human content)
|
|
63
|
+
* "✳ " → null (nothing after the prefix)
|
|
64
|
+
*
|
|
65
|
+
* Used by the correlator's name-resolution path: when the terminal's
|
|
66
|
+
* current registry name is a claude auto-title AND we have nothing else,
|
|
67
|
+
* this at least gives the session a recognisable alias instead of falling
|
|
68
|
+
* back to a random sibling terminal's name.
|
|
69
|
+
*/
|
|
70
|
+
export function stripAutoTitlePrefix(name) {
|
|
71
|
+
const trimmed = name.trim();
|
|
72
|
+
if (!trimmed)
|
|
73
|
+
return null;
|
|
74
|
+
if (VERSION_ONLY_RE.test(trimmed))
|
|
75
|
+
return null;
|
|
76
|
+
const stripped = trimmed.replace(SPINNER_PREFIX_RE, '').trim();
|
|
77
|
+
return stripped.length > 0 ? stripped : null;
|
|
78
|
+
}
|
|
79
|
+
class TerminalRegistry {
|
|
80
|
+
entries = new Map();
|
|
81
|
+
origins = new Map();
|
|
82
|
+
// shell_pid → session UUIDs that started in that shell. Lets renames
|
|
83
|
+
// propagate to already-aliased sessions.
|
|
84
|
+
sessionsByPid = new Map();
|
|
85
|
+
// In-memory only — short-lived breadcrumbs the extension drops when the
|
|
86
|
+
// user types `claude` in a terminal. The correlator drains them within
|
|
87
|
+
// ~30s of the JSONL appearing on disk; survival across daemon restarts
|
|
88
|
+
// isn't required (the user is right there at the keyboard).
|
|
89
|
+
pendingClaudeStarts = [];
|
|
90
|
+
loaded = false;
|
|
91
|
+
ensureLoaded() {
|
|
92
|
+
if (this.loaded)
|
|
93
|
+
return;
|
|
94
|
+
this.loaded = true;
|
|
95
|
+
if (!existsSync(TERMINALS_FILE))
|
|
96
|
+
return;
|
|
97
|
+
try {
|
|
98
|
+
const raw = readFileSync(TERMINALS_FILE, 'utf8');
|
|
99
|
+
const parsed = JSON.parse(raw);
|
|
100
|
+
if (Array.isArray(parsed.terminals)) {
|
|
101
|
+
for (const e of parsed.terminals) {
|
|
102
|
+
if (e &&
|
|
103
|
+
typeof e.shell_pid === 'number' &&
|
|
104
|
+
typeof e.tab_name === 'string' &&
|
|
105
|
+
typeof e.opened_at === 'string' &&
|
|
106
|
+
typeof e.last_seen_at === 'string') {
|
|
107
|
+
this.entries.set(e.shell_pid, {
|
|
108
|
+
shell_pid: e.shell_pid,
|
|
109
|
+
tab_name: e.tab_name,
|
|
110
|
+
cwd: typeof e.cwd === 'string' ? e.cwd : null,
|
|
111
|
+
opened_at: e.opened_at,
|
|
112
|
+
last_seen_at: e.last_seen_at,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (parsed.sessions_by_pid && typeof parsed.sessions_by_pid === 'object') {
|
|
118
|
+
for (const [pid, sids] of Object.entries(parsed.sessions_by_pid)) {
|
|
119
|
+
const pidNum = Number(pid);
|
|
120
|
+
if (!Number.isFinite(pidNum) || !Array.isArray(sids))
|
|
121
|
+
continue;
|
|
122
|
+
const set = new Set();
|
|
123
|
+
for (const sid of sids) {
|
|
124
|
+
if (typeof sid === 'string' && sid.length > 0)
|
|
125
|
+
set.add(sid);
|
|
126
|
+
}
|
|
127
|
+
if (set.size > 0)
|
|
128
|
+
this.sessionsByPid.set(pidNum, set);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
this.gc();
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
/* corrupted file — start fresh */
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
save() {
|
|
138
|
+
try {
|
|
139
|
+
ensureRecallHome();
|
|
140
|
+
const payload = {
|
|
141
|
+
schema: 'claude-recall.terminals.v1',
|
|
142
|
+
saved_at: new Date().toISOString(),
|
|
143
|
+
terminals: Array.from(this.entries.values()),
|
|
144
|
+
sessions_by_pid: Object.fromEntries(Array.from(this.sessionsByPid.entries()).map(([pid, sids]) => [
|
|
145
|
+
String(pid),
|
|
146
|
+
Array.from(sids),
|
|
147
|
+
])),
|
|
148
|
+
};
|
|
149
|
+
writeFileSync(TERMINALS_FILE, JSON.stringify(payload, null, 2));
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
/* non-fatal — registry still works in memory */
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
upsert(e) {
|
|
156
|
+
this.ensureLoaded();
|
|
157
|
+
const now = new Date().toISOString();
|
|
158
|
+
const existing = this.entries.get(e.shell_pid);
|
|
159
|
+
// If the incoming tab_name is Claude Code's auto-title noise, keep the
|
|
160
|
+
// previous reliable name for this pid (if any) so a rename the user typed
|
|
161
|
+
// earlier doesn't get clobbered by the spinner frame or version string
|
|
162
|
+
// claude just wrote to the terminal.
|
|
163
|
+
const effectiveName = existing && looksLikeClaudeAutoTitle(e.tab_name) && !looksLikeClaudeAutoTitle(existing.tab_name)
|
|
164
|
+
? existing.tab_name
|
|
165
|
+
: e.tab_name;
|
|
166
|
+
// Preserve the original opened_at so "newest terminal by opened_at" stays
|
|
167
|
+
// meaningful. The extension sends a fresh ISO stamp on every poll, which
|
|
168
|
+
// would otherwise flatten everyone's opened_at to the latest sync time.
|
|
169
|
+
const opened_at = existing?.opened_at ?? e.opened_at;
|
|
170
|
+
const entry = {
|
|
171
|
+
...e,
|
|
172
|
+
tab_name: effectiveName,
|
|
173
|
+
opened_at,
|
|
174
|
+
last_seen_at: now,
|
|
175
|
+
};
|
|
176
|
+
this.entries.set(e.shell_pid, entry);
|
|
177
|
+
this.gc();
|
|
178
|
+
this.save();
|
|
179
|
+
return entry;
|
|
180
|
+
}
|
|
181
|
+
rename(shell_pid, tab_name) {
|
|
182
|
+
this.ensureLoaded();
|
|
183
|
+
const existing = this.entries.get(shell_pid);
|
|
184
|
+
if (!existing)
|
|
185
|
+
return null;
|
|
186
|
+
// Same guard: never overwrite a real name with Claude Code noise.
|
|
187
|
+
if (looksLikeClaudeAutoTitle(tab_name) &&
|
|
188
|
+
!looksLikeClaudeAutoTitle(existing.tab_name)) {
|
|
189
|
+
const updated = {
|
|
190
|
+
...existing,
|
|
191
|
+
last_seen_at: new Date().toISOString(),
|
|
192
|
+
};
|
|
193
|
+
this.entries.set(shell_pid, updated);
|
|
194
|
+
this.save();
|
|
195
|
+
return updated;
|
|
196
|
+
}
|
|
197
|
+
const updated = {
|
|
198
|
+
...existing,
|
|
199
|
+
tab_name,
|
|
200
|
+
last_seen_at: new Date().toISOString(),
|
|
201
|
+
};
|
|
202
|
+
this.entries.set(shell_pid, updated);
|
|
203
|
+
this.save();
|
|
204
|
+
return updated;
|
|
205
|
+
}
|
|
206
|
+
remove(shell_pid) {
|
|
207
|
+
this.ensureLoaded();
|
|
208
|
+
const hadEntry = this.entries.delete(shell_pid);
|
|
209
|
+
const hadSessions = this.sessionsByPid.delete(shell_pid);
|
|
210
|
+
if (hadEntry || hadSessions)
|
|
211
|
+
this.save();
|
|
212
|
+
return hadEntry;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Idempotent snapshot sync: replace the entire registry with the given
|
|
216
|
+
* list. Entries not in the snapshot are kept only if they still have
|
|
217
|
+
* associated sessions (so we don't drop a terminal's session mapping just
|
|
218
|
+
* because VS Code restarted). The extension calls this on activation and
|
|
219
|
+
* on every poll cycle.
|
|
220
|
+
*/
|
|
221
|
+
sync(snapshot) {
|
|
222
|
+
this.ensureLoaded();
|
|
223
|
+
const now = new Date().toISOString();
|
|
224
|
+
const incoming = new Map();
|
|
225
|
+
for (const e of snapshot)
|
|
226
|
+
incoming.set(e.shell_pid, e);
|
|
227
|
+
let added = 0;
|
|
228
|
+
let updated = 0;
|
|
229
|
+
let removed = 0;
|
|
230
|
+
for (const [pid, existing] of this.entries) {
|
|
231
|
+
if (!incoming.has(pid)) {
|
|
232
|
+
// Keep if we have linked sessions — someone restarted VS Code but
|
|
233
|
+
// sessions from that pid still live in the DB; renames should still
|
|
234
|
+
// propagate if the pid gets reused.
|
|
235
|
+
if (!this.sessionsByPid.has(pid)) {
|
|
236
|
+
this.entries.delete(pid);
|
|
237
|
+
removed++;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
const next = incoming.get(pid);
|
|
242
|
+
// Reject Claude Code's spinner/version auto-titles: if the incoming
|
|
243
|
+
// name looks like a claude-written title but the existing name is a
|
|
244
|
+
// real user-set name, KEEP the existing one. Prevents the session
|
|
245
|
+
// alias from flapping every time claude updates its tab title.
|
|
246
|
+
const effectiveName = looksLikeClaudeAutoTitle(next.tab_name) &&
|
|
247
|
+
!looksLikeClaudeAutoTitle(existing.tab_name)
|
|
248
|
+
? existing.tab_name
|
|
249
|
+
: next.tab_name;
|
|
250
|
+
if (existing.tab_name !== effectiveName ||
|
|
251
|
+
existing.cwd !== next.cwd) {
|
|
252
|
+
updated++;
|
|
253
|
+
}
|
|
254
|
+
// Preserve existing.opened_at — the extension re-sends `new Date()`
|
|
255
|
+
// on every poll which would otherwise flatten every terminal's
|
|
256
|
+
// opened_at to the latest sync time, breaking newest-first sorting.
|
|
257
|
+
this.entries.set(pid, {
|
|
258
|
+
...next,
|
|
259
|
+
tab_name: effectiveName,
|
|
260
|
+
opened_at: existing.opened_at,
|
|
261
|
+
last_seen_at: now,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
for (const [pid, next] of incoming) {
|
|
266
|
+
if (!this.entries.has(pid)) {
|
|
267
|
+
this.entries.set(pid, { ...next, last_seen_at: now });
|
|
268
|
+
added++;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
this.gc();
|
|
272
|
+
this.save();
|
|
273
|
+
return { added, updated, removed };
|
|
274
|
+
}
|
|
275
|
+
get(shell_pid) {
|
|
276
|
+
this.ensureLoaded();
|
|
277
|
+
return this.entries.get(shell_pid) ?? null;
|
|
278
|
+
}
|
|
279
|
+
all() {
|
|
280
|
+
this.ensureLoaded();
|
|
281
|
+
this.gc();
|
|
282
|
+
return Array.from(this.entries.values());
|
|
283
|
+
}
|
|
284
|
+
size() {
|
|
285
|
+
this.ensureLoaded();
|
|
286
|
+
return this.entries.size;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Record that a Claude Code session was spawned from the given shell. The
|
|
290
|
+
* correlator calls this after a successful tab-name match so later tab
|
|
291
|
+
* renames can propagate to the session's alias.
|
|
292
|
+
*/
|
|
293
|
+
linkSession(sessionId, shell_pid) {
|
|
294
|
+
this.ensureLoaded();
|
|
295
|
+
let set = this.sessionsByPid.get(shell_pid);
|
|
296
|
+
if (!set) {
|
|
297
|
+
set = new Set();
|
|
298
|
+
this.sessionsByPid.set(shell_pid, set);
|
|
299
|
+
}
|
|
300
|
+
if (!set.has(sessionId)) {
|
|
301
|
+
set.add(sessionId);
|
|
302
|
+
this.save();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
sessionsFor(shell_pid) {
|
|
306
|
+
this.ensureLoaded();
|
|
307
|
+
return Array.from(this.sessionsByPid.get(shell_pid) ?? []);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* True iff the given session's alias was set by the correlator (auto) as
|
|
311
|
+
* opposed to being typed by the user (manual). The UI uses this to decide
|
|
312
|
+
* whether an ✨ agent title should override the alias.
|
|
313
|
+
*/
|
|
314
|
+
isSessionAutoLinked(sessionId) {
|
|
315
|
+
this.ensureLoaded();
|
|
316
|
+
for (const set of this.sessionsByPid.values()) {
|
|
317
|
+
if (set.has(sessionId))
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Drop the session from the auto-linked set. Called when the user manually
|
|
324
|
+
* renames a session via the alias PUT endpoint — from that moment on the
|
|
325
|
+
* alias is user-intent and must beat any agent-generated title.
|
|
326
|
+
*/
|
|
327
|
+
unlinkSession(sessionId) {
|
|
328
|
+
this.ensureLoaded();
|
|
329
|
+
let touched = false;
|
|
330
|
+
for (const [pid, set] of this.sessionsByPid) {
|
|
331
|
+
if (set.delete(sessionId)) {
|
|
332
|
+
touched = true;
|
|
333
|
+
if (set.size === 0)
|
|
334
|
+
this.sessionsByPid.delete(pid);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (touched)
|
|
338
|
+
this.save();
|
|
339
|
+
return touched;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Record that the user just typed `claude` in a terminal. The correlator
|
|
343
|
+
* uses this to deterministically link the next Claude session JSONL it
|
|
344
|
+
* sees to the exact shell that spawned it — no lsof or process-tree walk
|
|
345
|
+
* required. Drops entries older than the TTL so a long-idle daemon doesn't
|
|
346
|
+
* keep serving stale matches.
|
|
347
|
+
*/
|
|
348
|
+
pushPending(p) {
|
|
349
|
+
this.ensureLoaded();
|
|
350
|
+
this.gcPending();
|
|
351
|
+
this.pendingClaudeStarts.push({ ...p });
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Find AND REMOVE the most recent pending claude-start whose cwd matches
|
|
355
|
+
* `sessionCwd` and whose `started_at` is within `withinMs` of now. Returns
|
|
356
|
+
* null when no fresh match exists. Removal makes pending entries
|
|
357
|
+
* single-use: two parallel `claude` launches in two different terminals
|
|
358
|
+
* each get their own breadcrumb.
|
|
359
|
+
*/
|
|
360
|
+
takePending(sessionCwd, withinMs) {
|
|
361
|
+
this.ensureLoaded();
|
|
362
|
+
this.gcPending();
|
|
363
|
+
if (!sessionCwd)
|
|
364
|
+
return null;
|
|
365
|
+
const wanted = sessionCwd.replace(/\/+$/, '');
|
|
366
|
+
const cutoff = Date.now() - withinMs;
|
|
367
|
+
let bestIdx = -1;
|
|
368
|
+
let bestTime = -Infinity;
|
|
369
|
+
for (let i = 0; i < this.pendingClaudeStarts.length; i++) {
|
|
370
|
+
const p = this.pendingClaudeStarts[i];
|
|
371
|
+
if (!p.cwd)
|
|
372
|
+
continue;
|
|
373
|
+
if (p.cwd.replace(/\/+$/, '') !== wanted)
|
|
374
|
+
continue;
|
|
375
|
+
const t = Date.parse(p.started_at);
|
|
376
|
+
if (!Number.isFinite(t) || t < cutoff)
|
|
377
|
+
continue;
|
|
378
|
+
if (t > bestTime) {
|
|
379
|
+
bestTime = t;
|
|
380
|
+
bestIdx = i;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (bestIdx < 0)
|
|
384
|
+
return null;
|
|
385
|
+
const [taken] = this.pendingClaudeStarts.splice(bestIdx, 1);
|
|
386
|
+
return taken ?? null;
|
|
387
|
+
}
|
|
388
|
+
pendingSize() {
|
|
389
|
+
this.ensureLoaded();
|
|
390
|
+
this.gcPending();
|
|
391
|
+
return this.pendingClaudeStarts.length;
|
|
392
|
+
}
|
|
393
|
+
gcPending() {
|
|
394
|
+
const cutoff = Date.now() - PENDING_CLAUDE_TTL_MS;
|
|
395
|
+
if (this.pendingClaudeStarts.length === 0)
|
|
396
|
+
return;
|
|
397
|
+
this.pendingClaudeStarts = this.pendingClaudeStarts.filter((p) => {
|
|
398
|
+
const t = Date.parse(p.started_at);
|
|
399
|
+
return Number.isFinite(t) && t >= cutoff;
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
/** v0.15, T4 — origin map accessors. */
|
|
403
|
+
setOrigin(sessionId, origin) {
|
|
404
|
+
this.ensureLoaded();
|
|
405
|
+
this.origins.set(sessionId, origin);
|
|
406
|
+
this.gcOrigins();
|
|
407
|
+
}
|
|
408
|
+
getOrigin(sessionId) {
|
|
409
|
+
this.ensureLoaded();
|
|
410
|
+
return this.origins.get(sessionId) ?? null;
|
|
411
|
+
}
|
|
412
|
+
removeOrigin(sessionId) {
|
|
413
|
+
this.ensureLoaded();
|
|
414
|
+
return this.origins.delete(sessionId);
|
|
415
|
+
}
|
|
416
|
+
allOrigins() {
|
|
417
|
+
this.ensureLoaded();
|
|
418
|
+
this.gcOrigins();
|
|
419
|
+
return new Map(this.origins);
|
|
420
|
+
}
|
|
421
|
+
originSize() {
|
|
422
|
+
this.ensureLoaded();
|
|
423
|
+
return this.origins.size;
|
|
424
|
+
}
|
|
425
|
+
gc() {
|
|
426
|
+
const cutoff = Date.now() - MAX_AGE_MS;
|
|
427
|
+
for (const [pid, entry] of this.entries) {
|
|
428
|
+
const t = Date.parse(entry.last_seen_at);
|
|
429
|
+
if (!Number.isNaN(t) && t < cutoff) {
|
|
430
|
+
this.entries.delete(pid);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
gcOrigins() {
|
|
435
|
+
const cutoff = Date.now() - MAX_AGE_MS;
|
|
436
|
+
for (const [sid, origin] of this.origins) {
|
|
437
|
+
if (origin.detectedAt < cutoff)
|
|
438
|
+
this.origins.delete(sid);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
export const terminalRegistry = new TerminalRegistry();
|
|
443
|
+
//# sourceMappingURL=terminal-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-registry.js","sourceRoot":"","sources":["../../src/daemon/terminal-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;AAgClE,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACvC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,MAAM,iBAAiB,GAAG,YAAY,CAAC;AACvC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAE5C,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED,MAAM,gBAAgB;IACZ,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC3C,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAClD,qEAAqE;IACrE,yCAAyC;IACjC,aAAa,GAAG,IAAI,GAAG,EAAuB,CAAC;IACvD,wEAAwE;IACxE,uEAAuE;IACvE,uEAAuE;IACvE,4DAA4D;IACpD,mBAAmB,GAAyB,EAAE,CAAC;IAC/C,MAAM,GAAG,KAAK,CAAC;IAEf,YAAY;QAClB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC;YAAE,OAAO;QACxC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA0B,CAAC;YACxD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACpC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACjC,IACE,CAAC;wBACD,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;wBAC/B,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;wBAC9B,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;wBAC/B,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,EAClC,CAAC;wBACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE;4BAC5B,SAAS,EAAE,CAAC,CAAC,SAAS;4BACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;4BACpB,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;4BAC7C,SAAS,EAAE,CAAC,CAAC,SAAS;4BACtB,YAAY,EAAE,CAAC,CAAC,YAAY;yBAC7B,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,MAAM,CAAC,eAAe,IAAI,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;gBACzE,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;oBACjE,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;wBAAE,SAAS;oBAC/D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;oBAC9B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;wBACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;4BAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAC9D,CAAC;oBACD,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC;wBAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;YACD,IAAI,CAAC,EAAE,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,kCAAkC;QACpC,CAAC;IACH,CAAC;IAEO,IAAI;QACV,IAAI,CAAC;YACH,gBAAgB,EAAE,CAAC;YACnB,MAAM,OAAO,GAAiB;gBAC5B,MAAM,EAAE,4BAA4B;gBACpC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAClC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC5C,eAAe,EAAE,MAAM,CAAC,WAAW,CACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;oBAC5D,MAAM,CAAC,GAAG,CAAC;oBACX,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;iBACjB,CAAC,CACH;aACF,CAAC;YACF,aAAa,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;IAED,MAAM,CAAC,CAAsC;QAC3C,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/C,uEAAuE;QACvE,0EAA0E;QAC1E,uEAAuE;QACvE,qCAAqC;QACrC,MAAM,aAAa,GACjB,QAAQ,IAAI,wBAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC9F,CAAC,CAAC,QAAQ,CAAC,QAAQ;YACnB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACjB,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,MAAM,SAAS,GAAG,QAAQ,EAAE,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;QACrD,MAAM,KAAK,GAAkB;YAC3B,GAAG,CAAC;YACJ,QAAQ,EAAE,aAAa;YACvB,SAAS;YACT,YAAY,EAAE,GAAG;SAClB,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,EAAE,CAAC;QACV,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,SAAiB,EAAE,QAAgB;QACxC,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,kEAAkE;QAClE,IACE,wBAAwB,CAAC,QAAQ,CAAC;YAClC,CAAC,wBAAwB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAC5C,CAAC;YACD,MAAM,OAAO,GAAkB;gBAC7B,GAAG,QAAQ;gBACX,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACvC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACrC,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,OAAO,GAAkB;YAC7B,GAAG,QAAQ;YACX,QAAQ;YACR,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,SAAiB;QACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,QAAQ,IAAI,WAAW;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACzC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;OAMG;IACH,IAAI,CAAC,QAAoD;QAKvD,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+C,CAAC;QACxE,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAEvD,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,kEAAkE;gBAClE,oEAAoE;gBACpE,oCAAoC;gBACpC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACjC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACzB,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;gBAChC,oEAAoE;gBACpE,oEAAoE;gBACpE,kEAAkE;gBAClE,+DAA+D;gBAC/D,MAAM,aAAa,GACjB,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC;oBACvC,CAAC,wBAAwB,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAC1C,CAAC,CAAC,QAAQ,CAAC,QAAQ;oBACnB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACpB,IACE,QAAQ,CAAC,QAAQ,KAAK,aAAa;oBACnC,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,EACzB,CAAC;oBACD,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,oEAAoE;gBACpE,+DAA+D;gBAC/D,oEAAoE;gBACpE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;oBACpB,GAAG,IAAI;oBACP,QAAQ,EAAE,aAAa;oBACvB,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,YAAY,EAAE,GAAG;iBAClB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;gBACtD,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QACD,IAAI,CAAC,EAAE,EAAE,CAAC;QACV,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACrC,CAAC;IAED,GAAG,CAAC,SAAiB;QACnB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC7C,CAAC;IAED,GAAG;QACD,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,EAAE,EAAE,CAAC;QACV,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI;QACF,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,SAAiB,EAAE,SAAiB;QAC9C,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACnB,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACH,mBAAmB,CAAC,SAAiB;QACnC,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;YAC9C,IAAI,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,CAAC;QACtC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,SAAiB;QAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC5C,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,OAAO,GAAG,IAAI,CAAC;gBACf,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,IAAI,OAAO;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,CAAqB;QAC/B,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,UAAyB,EAAE,QAAgB;QACrD,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC;QACrC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;QACjB,IAAI,QAAQ,GAAG,CAAC,QAAQ,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzD,MAAM,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAE,CAAC;YACvC,IAAI,CAAC,CAAC,CAAC,GAAG;gBAAE,SAAS;YACrB,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,MAAM;gBAAE,SAAS;YACnD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM;gBAAE,SAAS;YAChD,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;gBACjB,QAAQ,GAAG,CAAC,CAAC;gBACb,OAAO,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC;QACD,IAAI,OAAO,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC5D,OAAO,KAAK,IAAI,IAAI,CAAC;IACvB,CAAC;IAED,WAAW;QACT,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC;IACzC,CAAC;IAEO,SAAS;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,qBAAqB,CAAC;QAClD,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAClD,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YAC/D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,wCAAwC;IACxC,SAAS,CAAC,SAAiB,EAAE,MAAoB;QAC/C,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,SAAS,CAAC,SAAiB;QACzB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC7C,CAAC;IAED,YAAY,CAAC,SAAiB;QAC5B,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,UAAU;QACR,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAEO,EAAE;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC;gBACnC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAEO,SAAS;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,MAAM,CAAC,UAAU,GAAG,MAAM;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Placeholder HTML for v0.2. v0.3 will replace this with a bundled Vite + React + Tailwind SPA.
|
|
3
|
+
* Kept inline to avoid any asset-loading complexity for the tracer.
|
|
4
|
+
*/
|
|
5
|
+
export function placeholderHtml(params) {
|
|
6
|
+
const { projects, sessions, messages, port, version } = params;
|
|
7
|
+
return `<!DOCTYPE html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="utf-8" />
|
|
11
|
+
<title>Claude Recall — local</title>
|
|
12
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13
|
+
<style>
|
|
14
|
+
:root {
|
|
15
|
+
--bg: #0b0c0f;
|
|
16
|
+
--fg: #e7e9ee;
|
|
17
|
+
--dim: #8b9098;
|
|
18
|
+
--accent: #f97316;
|
|
19
|
+
--card: #15171c;
|
|
20
|
+
--line: #22252d;
|
|
21
|
+
}
|
|
22
|
+
* { box-sizing: border-box; }
|
|
23
|
+
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif; }
|
|
24
|
+
main { max-width: 760px; margin: 0 auto; padding: 6rem 2rem 4rem; }
|
|
25
|
+
h1 { font-size: 2.4rem; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 0.4rem; }
|
|
26
|
+
.tag { color: var(--accent); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; font-size: 0.75rem; margin: 0 0 0.8rem; }
|
|
27
|
+
p { color: var(--dim); font-size: 1.05rem; line-height: 1.55; margin: 0 0 1.2rem; }
|
|
28
|
+
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin: 2.5rem 0; }
|
|
29
|
+
.stat { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 1.25rem; }
|
|
30
|
+
.stat .n { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
|
|
31
|
+
.stat .k { color: var(--dim); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; margin-top: 0.25rem; }
|
|
32
|
+
code { background: var(--card); padding: 0.12em 0.42em; border-radius: 4px; border: 1px solid var(--line); font-size: 0.9em; }
|
|
33
|
+
footer { color: var(--dim); font-size: 0.8rem; margin-top: 4rem; border-top: 1px solid var(--line); padding-top: 1.5rem; }
|
|
34
|
+
a { color: var(--accent); text-decoration: none; }
|
|
35
|
+
a:hover { text-decoration: underline; }
|
|
36
|
+
.soon { display: inline-block; background: rgba(249, 115, 22, 0.12); color: var(--accent); border: 1px solid rgba(249, 115, 22, 0.3); border-radius: 999px; padding: 0.2rem 0.7rem; font-size: 0.75rem; font-weight: 600; margin-left: 0.5rem; }
|
|
37
|
+
</style>
|
|
38
|
+
</head>
|
|
39
|
+
<body>
|
|
40
|
+
<main>
|
|
41
|
+
<p class="tag">Claude Recall · local-only</p>
|
|
42
|
+
<h1>Your sessions are indexed.</h1>
|
|
43
|
+
<p>The full browser UI with projects tree, search, and transcript view ships in <strong>v0.3</strong>.<br />Everything is already running on <code>127.0.0.1:${port}</code> — nothing ever leaves your machine.</p>
|
|
44
|
+
|
|
45
|
+
<div class="grid">
|
|
46
|
+
<div class="stat"><div class="n">${projects.toLocaleString()}</div><div class="k">Projects</div></div>
|
|
47
|
+
<div class="stat"><div class="n">${sessions.toLocaleString()}</div><div class="k">Sessions</div></div>
|
|
48
|
+
<div class="stat"><div class="n">${messages.toLocaleString()}</div><div class="k">Messages</div></div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<p>For now, keep driving from the terminal:</p>
|
|
52
|
+
<p><code>recall search "your query"</code> <code>recall list</code> <code>recall show <id></code></p>
|
|
53
|
+
|
|
54
|
+
<p><strong>Up next</strong> <span class="soon">v0.3</span> three-pane React + Tailwind UI right here. <span class="soon">v0.4</span> context re-injection into new Claude sessions.</p>
|
|
55
|
+
|
|
56
|
+
<footer>
|
|
57
|
+
v${version} · daemon pid ${process.pid} · running on http://127.0.0.1:${port}<br />
|
|
58
|
+
data stays on your disk at <code>~/.recall/db.sqlite</code>
|
|
59
|
+
</footer>
|
|
60
|
+
</main>
|
|
61
|
+
</body>
|
|
62
|
+
</html>`;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/daemon/ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAM/B;IACC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAC/D,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mKAoC0J,IAAI;;;yCAG9H,QAAQ,CAAC,cAAc,EAAE;yCACzB,QAAQ,CAAC,cAAc,EAAE;yCACzB,QAAQ,CAAC,cAAc,EAAE;;;;;;;;;SASzD,OAAO,iBAAiB,OAAO,CAAC,GAAG,kCAAkC,IAAI;;;;;QAK1E,CAAC;AACT,CAAC"}
|