@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.
- package/LICENSE +37 -17
- package/README.md +316 -106
- package/dist/cli.js +1641 -361
- 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 +57 -16
- 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/installs.js +0 -128
- package/dist/commands/installs.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
|
@@ -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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAqB,MAAM,uBAAuB,CAAC;AAE9E,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,yEAAyE;QACzE,qEAAqE;QACrE,qEAAqE;QACrE,wEAAwE;QACxE,uEAAuE;QACvE,gEAAgE;QAChE,EAAE;QACF,yEAAyE;QACzE,oEAAoE;QACpE,qEAAqE;QACrE,8BAA8B;QAC9B,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;YAC7D,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,SAAS,GAAkB,IAAI,CAAC;QACpC,IAAI,UAAU,GAAkB,IAAI,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;oBAClD,IAAI,QAAQ,IAAI,IAAI;wBAAE,QAAQ,GAAG,UAAU,CAAC;gBAC9C,CAAC;qBAAM,CAAC;oBACN,UAAU,GAAG,IAAI,CAAC;gBACpB,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;gBACtD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACjC,2DAA2D;gBAC3D,4CAA4C;gBAC5C,IAAI,GAAG,KAAK,QAAQ,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;oBAC1C,SAAS,GAAG,UAAU,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,SAAS,IAAI,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACjG,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,KAAK;IACL,MAAM;IACN,MAAM;IACN,IAAI;IACJ,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,YAAY;IACZ,KAAK;IACL,IAAI;CACL,CAAC,CAAC;AAEH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7C,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,wEAAwE;IACxE,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;SAC7B,IAAI,EAAE,CAAC;IACV,OAAO,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAKhC;IACC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;IACzC,IACE,UAAU;QACV,CAAC,kBAAkB,CAAC,UAAU,CAAC;QAC/B,CAAC,wBAAwB,CAAC,UAAU,CAAC,EACrC,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,KAAK,GAAa,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,sEAAsE;QACtE,iCAAiC;QACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;QACpD,IAAI,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IACD,IAAI,KAAK,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACjD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAOD,SAAS,eAAe,CAAC,SAAiB;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,KAAK,EAAE;aAChB,OAAO,CAAC,mDAAmD,CAAC;aAC5D,GAAG,CAAC,SAAS,CAA+B,CAAC;QAChD,OAAO,GAAG,IAAI,IAAI,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO;IAEhC,qEAAqE;IACrE,oBAAoB;IACpB,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAExC,IAAI,KAAK,GAA4C,IAAI,CAAC;IAC1D,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,aAAa,GAAsC,IAAI,CAAC;IAE5D,wEAAwE;IACxE,kCAAkC;IAClC,MAAM,OAAO,GAAG,gBAAgB,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,OAAO,EAAE,CAAC;QACZ,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;QAC/B,aAAa,GAAG,SAAS,CAAC;QAC1B,wEAAwE;QACxE,uEAAuE;QACvE,uEAAuE;QACvE,oEAAoE;QACpE,6BAA6B;QAC7B,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACrD,KAAK;YACH,IAAI,IAAI;gBACN,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,SAAS,EAAE,OAAO,CAAC,UAAU;gBAC7B,YAAY,EAAE,OAAO,CAAC,UAAU;aACjC,CAAC;IACN,CAAC;IAED,wEAAwE;IACxE,yEAAyE;IACzE,sBAAsB;IACtB,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,IAAI,MAAM;QAAE,gBAAgB,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAE1D,wEAAwE;IACxE,qBAAqB;IACrB,IAAI,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC;QACxB,IAAI,UAAU,GAAkB,SAAS,CAAC;QAC1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,UAAU,IAAI,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACvD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,OAAO;gBAAE,MAAM;YACpB,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAChD,IAAI,SAAS,EAAE,CAAC;gBACd,KAAK,GAAG,SAAS,CAAC;gBAClB,UAAU,GAAG,OAAO,CAAC;gBACrB,aAAa,GAAG,MAAM,CAAC;gBACvB,MAAM;YACR,CAAC;YACD,UAAU,GAAG,OAAO,CAAC;QACvB,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,8DAA8D;IAC9D,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,gBAAgB;aAC7B,GAAG,EAAE;aACL,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,UAAU,CAAC,CAAC;QACpE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CACzB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAC5D,CAAC,CAAC,CAAC,CAAC;YACL,KAAK,GAAG,MAAM,CAAC;YACf,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;YAC9B,aAAa,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,uEAAuE;IACvE,aAAa;IACb,qDAAqD;IACrD,qEAAqE;IACrE,yEAAyE;IACzE,0EAA0E;IAC1E,+DAA+D;IAC/D,wEAAwE;IACxE,mEAAmE;IACnE,yEAAyE;IACzE,IAAI,eAAe,GAAkB,IAAI,CAAC;IAC1C,IACE,KAAK,EAAE,QAAQ;QACf,CAAC,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC;QACnC,CAAC,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,EACzC,CAAC;QACD,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC;IACnC,CAAC;SAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,QAAQ,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YAAE,eAAe,GAAG,QAAQ,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,eAAe,IAAI,aAAa,KAAK,SAAS,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC;QACjE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,WAAW,GAAG,gBAAgB;aACjC,GAAG,EAAE;aACL,MAAM,CACL,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,SAAS,KAAK,UAAU;YAC1B,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,UAAU;YACxC,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC/B,CAAC,wBAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC,CACxC;aACA,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAClE,CAAC,CAAC,CAAC,CAAC;QACP,IAAI,WAAW;YAAE,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC1D,CAAC;IACD,MAAM,KAAK,GAAG,gBAAgB,CAAC;QAC7B,OAAO,EAAE,eAAe;QACxB,MAAM;QACN,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI;QACtB,SAAS,EAAE,IAAI,EAAE,UAAU,IAAI,IAAI;KACpC,CAAC,CAAC;IACH,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC3B,MAAM,WAAW,GACf,CAAC,CAAC,eAAe;YACjB,CAAC,kBAAkB,CAAC,eAAe,CAAC;YACpC,CAAC,wBAAwB,CAAC,eAAe,CAAC;YAC1C,KAAK,KAAK,eAAe,CAAC,IAAI,EAAE,CAAC;QACnC,oEAAoE;QACpE,sEAAsE;QACtE,qCAAqC;QACrC,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;YACvB,gBAAgB,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,QAAQ,GAAG,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,aAAa,IAAI,SAAS,CAAC;QACzG,sCAAsC;QACtC,OAAO,CAAC,GAAG,CACT,6BAA6B,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,KAAK,GAAG;YAC/D,CAAC,WAAW;gBACV,CAAC,CAAC,kBAAkB,QAAQ,eAAe,UAAU,GAAG;gBACxD,CAAC,CAAC,KAAK;oBACL,CAAC,CAAC,yBAAyB,KAAK,CAAC,QAAQ,OAAO,MAAM,EAAE,MAAM,IAAI,QAAQ,wBAAwB,UAAU,GAAG;oBAC/G,CAAC,CAAC,MAAM;wBACN,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,8BAA8B;wBAClD,CAAC,CAAC,EAAE,CAAC,CACd,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC"}
|
package/dist/daemon/discover.js
DELETED
|
@@ -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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEtC;;;;;;;;;;;;;;GAcG;AAEH,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAChC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AA0DlC,SAAS,kBAAkB;IACzB,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,wEAAwE;IACxE,yEAAyE;IACzE,2EAA2E;IAC3E,MAAM,MAAM,GAAG,CAAC,GAAW,EAAW,EAAE;QACtC,IAAI,CAAC;YACH,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IACF,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,wCAAwC,CAAC;QAC1D,IAAI,EAAE,MAAM,CACV;;;;;eAKS,CACV;QACD,GAAG,EAAE,MAAM,CAAC,uCAAuC,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAA8B;IACnD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QAChC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,GAOjB;IACC,OAAO;QACL,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,gBAAgB,EAAE,GAAG,CAAC,kBAAkB;KACzC,CAAC;AACJ,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnB,MAAM,iBAAiB,GAAG,EAAE;SACzB,OAAO,CACN;;;;uEAIiE,CAClE;SACA,GAAG,CAAC,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAgC,CAAC;IAC1E,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAClC,KAAK,MAAM,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,UAAU,GAAG,EAAE;SAClB,OAAO,CACN;;;;;;;;;;;;;;;;iCAgB2B,CAC5B;SACA,GAAG,CAAC,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAA6B,CAAC;IAC1E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,IAAI,IAAI,GAA8D,IAAI,CAAC;IAC3E,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAClD,IAAI,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO;QACL,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;QACrB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO;QACzB,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1C,eAAe,EAAE,IAAI,CAAC,OAAO;QAC7B,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;KACpD,CAAC;AACJ,CAAC;AAgBD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;;;;;;;;;;;;;;;;;;0DAmBoD,CACrD;SACA,GAAG,CAAC,EAAE,UAAU,EAAE,qBAAqB,EAAE,CAA4B,CAAC;IACzE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,IAAI,IAAI,GAA8E,IAAI,CAAC;IAC3F,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,YAAY,CACvB;YACE,WAAW,EAAE,GAAG,CAAC,YAAY;YAC7B,YAAY,EAAE,GAAG,CAAC,aAAa;YAC/B,iBAAiB,EAAE,GAAG,CAAC,mBAAmB;YAC1C,eAAe,EAAE,GAAG,CAAC,iBAAiB;SACvC,EACD,GAAG,CAAC,aAAa,CAClB,CAAC;QACF,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC;YAAE,SAAS;QAC9B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QACnE,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO;QACL,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;QACrB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,WAAW,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QACtC,aAAa,EAAE,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;QAC7C,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,aAAa;QACpC,iBAAiB,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,KAAK;KAC1D,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,mEAAmE;IACnE,sEAAsE;IACtE,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE;YAC/D,GAAG;YACH,OAAO,EAAE,mBAAmB;SAC7B,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1B,OAAO,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,EAAE;SACd,OAAO,CACN;;;;eAIS,CACV;SACA,GAAG,EAA6C,CAAC;IACpD,IAAI,CAAC,MAAM,EAAE,GAAG;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEzB,wEAAwE;IACxE,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;sBAEgB,CACjB;SACA,GAAG,CAAC,KAAK,CAAC,SAAS,CAET,CAAC;IAEd,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,KAAK,CAAC,OAAO;QACxC,gBAAgB,EAAE,IAAI,EAAE,kBAAkB,IAAI,IAAI;QAClD,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACrC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,EAAE,MAAM,CAAC,GAAG;KAChB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;IAE1C,MAAM,mBAAmB,GAAqC,YAAY,CAAC,QAAQ;QACjF,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC;gBACH,OAAO,gBAAgB,EAAE,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;gBAC9C,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC;QACJ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,MAAM,gBAAgB,GAAkC,YAAY,CAAC,IAAI;QACvE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC;gBACH,OAAO,aAAa,EAAE,CAAC;YACzB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;gBAC3C,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC;QACJ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,MAAM,eAAe,GAAiC,YAAY,CAAC,GAAG;QACpE,CAAC,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC3B,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QACJ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,MAAM,CAAC,YAAY,EAAE,SAAS,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC5D,mBAAmB;QACnB,gBAAgB;QAChB,eAAe;KAChB,CAAC,CAAC;IAEH,OAAO;QACL,YAAY;QACZ,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACtC,CAAC;AACJ,CAAC"}
|