@clauderecallhq/cli 0.12.5 → 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 +110 -22
- package/dist/cli.js +1641 -353
- package/dist/daemon/entrypoint.js +1872 -54
- package/dist/mcp-server.js +930 -0
- package/dist/share/fonts/Inter-Bold.woff +0 -0
- package/dist/share/fonts/Inter-Regular.woff +0 -0
- package/dist/share/fonts/JetBrainsMono-Regular.woff +0 -0
- package/dist/web/assets/_brand-Bw9uSB4O.js +1 -0
- package/dist/web/assets/captureNode-9CVj9vYC.js +2 -0
- package/dist/web/assets/card-a-minimal-ujNERzX7.js +1 -0
- package/dist/web/assets/card-b-terminal-DpJ_tVpg.js +1 -0
- package/dist/web/assets/card-c-gradient-CZXVGuNd.js +1 -0
- package/dist/web/assets/card-d-dashboard-CHKD-PnB.js +1 -0
- package/dist/web/assets/dist-CWaokT35.js +56 -0
- package/dist/web/assets/index-B-HrjaDy.css +1 -0
- package/dist/web/assets/index-BZYcD76T.js +633 -0
- package/dist/web/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
- package/dist/web/assets/patterns-BPeZb9N0.js +1 -0
- package/dist/web/assets/stats-BSwqSiFU.js +1 -0
- package/dist/web/assets/thread-D2AXyhOx.js +1 -0
- package/dist/web/index.html +8 -2
- package/package.json +56 -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/license.js +0 -39
- package/dist/commands/license.js.map +0 -1
- package/dist/commands/list.js +0 -47
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/mcp.js +0 -29
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/open.js +0 -28
- package/dist/commands/open.js.map +0 -1
- package/dist/commands/paste.js +0 -154
- package/dist/commands/paste.js.map +0 -1
- package/dist/commands/projects.js +0 -36
- package/dist/commands/projects.js.map +0 -1
- package/dist/commands/search.js +0 -67
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/semantic.js +0 -173
- package/dist/commands/semantic.js.map +0 -1
- package/dist/commands/show.js +0 -121
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/start.js +0 -47
- package/dist/commands/start.js.map +0 -1
- package/dist/commands/stats.js +0 -133
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/status.js +0 -45
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/stop.js +0 -29
- package/dist/commands/stop.js.map +0 -1
- package/dist/commands/thread.js +0 -396
- package/dist/commands/thread.js.map +0 -1
- package/dist/context/formatter.js +0 -103
- package/dist/context/formatter.js.map +0 -1
- package/dist/daemon/auto-tag-config.js +0 -103
- package/dist/daemon/auto-tag-config.js.map +0 -1
- package/dist/daemon/auto-tag-config.test.js +0 -72
- package/dist/daemon/auto-tag-config.test.js.map +0 -1
- package/dist/daemon/auto-title-config.js +0 -70
- package/dist/daemon/auto-title-config.js.map +0 -1
- package/dist/daemon/bulk-title-jobs.js +0 -170
- package/dist/daemon/bulk-title-jobs.js.map +0 -1
- package/dist/daemon/correlator.js +0 -320
- package/dist/daemon/correlator.js.map +0 -1
- package/dist/daemon/discover.js +0 -316
- package/dist/daemon/discover.js.map +0 -1
- package/dist/daemon/editor-detection.js +0 -186
- package/dist/daemon/editor-detection.js.map +0 -1
- package/dist/daemon/entrypoint.js.map +0 -1
- package/dist/daemon/git-correlator.js +0 -256
- package/dist/daemon/git-correlator.js.map +0 -1
- package/dist/daemon/mcp-installer.js +0 -108
- package/dist/daemon/mcp-installer.js.map +0 -1
- package/dist/daemon/onboarding-state.js +0 -140
- package/dist/daemon/onboarding-state.js.map +0 -1
- package/dist/daemon/pidfile.js +0 -57
- package/dist/daemon/pidfile.js.map +0 -1
- package/dist/daemon/ports.js +0 -48
- package/dist/daemon/ports.js.map +0 -1
- package/dist/daemon/scanProgressRegistry.js +0 -62
- package/dist/daemon/scanProgressRegistry.js.map +0 -1
- package/dist/daemon/server.js +0 -2010
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/tag-scanner/anthropic-client.js +0 -40
- package/dist/daemon/tag-scanner/anthropic-client.js.map +0 -1
- package/dist/daemon/tag-scanner/autopilot.js +0 -131
- package/dist/daemon/tag-scanner/autopilot.js.map +0 -1
- package/dist/daemon/tag-scanner/claude-cli-driver.js +0 -250
- package/dist/daemon/tag-scanner/claude-cli-driver.js.map +0 -1
- package/dist/daemon/tag-scanner/orchestrator.js +0 -88
- package/dist/daemon/tag-scanner/orchestrator.js.map +0 -1
- package/dist/daemon/tag-scanner/prompt.js +0 -46
- package/dist/daemon/tag-scanner/prompt.js.map +0 -1
- package/dist/daemon/tag-scanner/prompt.test.js +0 -48
- package/dist/daemon/tag-scanner/prompt.test.js.map +0 -1
- package/dist/daemon/tag-scanner/scan-state.js +0 -49
- package/dist/daemon/tag-scanner/scan-state.js.map +0 -1
- package/dist/daemon/tag-scanner/session-fetcher.js +0 -82
- package/dist/daemon/tag-scanner/session-fetcher.js.map +0 -1
- package/dist/daemon/tag-scanner/session-fetcher.test.js +0 -34
- package/dist/daemon/tag-scanner/session-fetcher.test.js.map +0 -1
- package/dist/daemon/tag-scanner/validator.js +0 -50
- package/dist/daemon/tag-scanner/validator.js.map +0 -1
- package/dist/daemon/tag-scanner/validator.test.js +0 -41
- package/dist/daemon/tag-scanner/validator.test.js.map +0 -1
- package/dist/daemon/terminal-registry.js +0 -443
- package/dist/daemon/terminal-registry.js.map +0 -1
- package/dist/daemon/ui.js +0 -64
- package/dist/daemon/ui.js.map +0 -1
- package/dist/daemon/watcher.js +0 -256
- package/dist/daemon/watcher.js.map +0 -1
- package/dist/db/client.js +0 -22
- package/dist/db/client.js.map +0 -1
- package/dist/db/schema.js +0 -496
- package/dist/db/schema.js.map +0 -1
- package/dist/license/api-base.js +0 -13
- package/dist/license/api-base.js.map +0 -1
- package/dist/license/manager.js +0 -43
- package/dist/license/manager.js.map +0 -1
- package/dist/license/public-key.js +0 -19
- package/dist/license/public-key.js.map +0 -1
- package/dist/license/storage.js +0 -27
- package/dist/license/storage.js.map +0 -1
- package/dist/license/verify.js +0 -23
- package/dist/license/verify.js.map +0 -1
- package/dist/mcp/audit.js +0 -126
- package/dist/mcp/audit.js.map +0 -1
- package/dist/mcp/prompts.js +0 -180
- package/dist/mcp/prompts.js.map +0 -1
- package/dist/mcp/server.js +0 -502
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/thread-tools.js +0 -363
- package/dist/mcp/thread-tools.js.map +0 -1
- package/dist/mcp/write-tools.js +0 -239
- package/dist/mcp/write-tools.js.map +0 -1
- package/dist/parser/jsonl.js +0 -150
- package/dist/parser/jsonl.js.map +0 -1
- package/dist/semantic/chunker.js +0 -47
- package/dist/semantic/chunker.js.map +0 -1
- package/dist/semantic/config.js +0 -74
- package/dist/semantic/config.js.map +0 -1
- package/dist/semantic/embedder.js +0 -54
- package/dist/semantic/embedder.js.map +0 -1
- package/dist/semantic/fusion.js +0 -38
- package/dist/semantic/fusion.js.map +0 -1
- package/dist/semantic/model-download.js +0 -69
- package/dist/semantic/model-download.js.map +0 -1
- package/dist/semantic/pipeline.js +0 -375
- package/dist/semantic/pipeline.js.map +0 -1
- package/dist/semantic/query.js +0 -42
- package/dist/semantic/query.js.map +0 -1
- package/dist/semantic/worker.js +0 -78
- package/dist/semantic/worker.js.map +0 -1
- package/dist/stats/backfill.js +0 -151
- package/dist/stats/backfill.js.map +0 -1
- package/dist/stats/health.js +0 -102
- package/dist/stats/health.js.map +0 -1
- package/dist/stats/query.js +0 -385
- package/dist/stats/query.js.map +0 -1
- package/dist/utils/aliases.js +0 -107
- package/dist/utils/aliases.js.map +0 -1
- package/dist/utils/autoCollections.js +0 -635
- package/dist/utils/autoCollections.js.map +0 -1
- package/dist/utils/autoTitle.js +0 -348
- package/dist/utils/autoTitle.js.map +0 -1
- package/dist/utils/collections.js +0 -446
- package/dist/utils/collections.js.map +0 -1
- package/dist/utils/format.js +0 -46
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/notes.js +0 -270
- package/dist/utils/notes.js.map +0 -1
- package/dist/utils/paths.js +0 -50
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/pricing.js +0 -257
- package/dist/utils/pricing.js.map +0 -1
- package/dist/utils/secret-scanner.js +0 -166
- package/dist/utils/secret-scanner.js.map +0 -1
- package/dist/utils/sessionLabel.js +0 -64
- package/dist/utils/sessionLabel.js.map +0 -1
- package/dist/utils/tags.js +0 -97
- package/dist/utils/tags.js.map +0 -1
- package/dist/utils/thread-context.js +0 -129
- package/dist/utils/thread-context.js.map +0 -1
- package/dist/utils/threadFilter.js +0 -18
- package/dist/utils/threadFilter.js.map +0 -1
- package/dist/utils/threads-titler.js +0 -298
- package/dist/utils/threads-titler.js.map +0 -1
- package/dist/utils/threads.js +0 -383
- package/dist/utils/threads.js.map +0 -1
- package/dist/utils/usage.js +0 -76
- package/dist/utils/usage.js.map +0 -1
- package/dist/verification/compute.js +0 -88
- package/dist/verification/compute.js.map +0 -1
- package/dist/verification/config.js +0 -34
- package/dist/verification/config.js.map +0 -1
- package/dist/web/assets/index-CIr6J4Fw.js +0 -1201
- package/dist/web/assets/index-Ctc8g9Jw.css +0 -1
package/dist/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":"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"}
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* v0.15, T4 — Passive editor/terminal origin detection.
|
|
3
|
-
*
|
|
4
|
-
* Reads the env of a running `claude` process to figure out whether it was
|
|
5
|
-
* launched from VS Code / Cursor / Warp / iTerm / etc., without requiring
|
|
6
|
-
* our VS Code extension to be installed. Feeds the correlator so sessions
|
|
7
|
-
* started in those surfaces still get a human-readable auto-alias.
|
|
8
|
-
*
|
|
9
|
-
* Security posture (HANDOFF.md):
|
|
10
|
-
* - Process inspection is LOCAL ONLY via `ps eww` (macOS/BSD) or
|
|
11
|
-
* `/proc/<pid>/environ` (Linux). No network, no escalation.
|
|
12
|
-
* - Env is filtered through EDITOR_ENV_ALLOWLIST before it's ever inspected,
|
|
13
|
-
* logged, or passed across a function boundary — so an `OPENAI_API_KEY`
|
|
14
|
-
* or `AWS_SECRET_ACCESS_KEY` the user exported in their shell can never
|
|
15
|
-
* leak into a log line or stored alias.
|
|
16
|
-
*/
|
|
17
|
-
import { execFile } from 'node:child_process';
|
|
18
|
-
import { readFile } from 'node:fs/promises';
|
|
19
|
-
import { promisify } from 'node:util';
|
|
20
|
-
const execFileP = promisify(execFile);
|
|
21
|
-
/**
|
|
22
|
-
* The ONLY env vars this module is allowed to read. Anything else MUST be
|
|
23
|
-
* dropped before it crosses a function boundary — see filterEnvToAllowlist.
|
|
24
|
-
*
|
|
25
|
-
* If you add a new editor/terminal detection rule, add its marker here too.
|
|
26
|
-
*/
|
|
27
|
-
export const EDITOR_ENV_ALLOWLIST = [
|
|
28
|
-
'CURSOR_TRACE_ID',
|
|
29
|
-
'VSCODE_PID',
|
|
30
|
-
'VSCODE_INJECTION',
|
|
31
|
-
'TERM_PROGRAM',
|
|
32
|
-
'TERM_PROGRAM_VERSION',
|
|
33
|
-
'TERM',
|
|
34
|
-
'WT_SESSION',
|
|
35
|
-
'KITTY_WINDOW_ID',
|
|
36
|
-
'ALACRITTY_SOCKET',
|
|
37
|
-
'WARP_HONOR_PS1',
|
|
38
|
-
];
|
|
39
|
-
/**
|
|
40
|
-
* Strip any env key not explicitly allowlisted. Returns a new object — never
|
|
41
|
-
* mutates the input. This is the secret-redaction choke point: nothing outside
|
|
42
|
-
* this module should ever see a raw env map.
|
|
43
|
-
*/
|
|
44
|
-
export function filterEnvToAllowlist(env) {
|
|
45
|
-
const out = {};
|
|
46
|
-
for (const key of EDITOR_ENV_ALLOWLIST) {
|
|
47
|
-
const v = env[key];
|
|
48
|
-
if (typeof v === 'string' && v.length > 0)
|
|
49
|
-
out[key] = v;
|
|
50
|
-
}
|
|
51
|
-
return out;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Pure, synchronous classifier. The input MUST already be filtered through
|
|
55
|
-
* filterEnvToAllowlist — the function itself does not re-filter, so callers
|
|
56
|
-
* that pass unfiltered env risk feeding a secret into the `label` string.
|
|
57
|
-
* (In practice, the only callers in this module do filter first.)
|
|
58
|
-
*
|
|
59
|
-
* Precedence order matters: Cursor is a VS Code fork and ships VSCODE_PID
|
|
60
|
-
* unconditionally, so CURSOR_TRACE_ID has to be checked first or every Cursor
|
|
61
|
-
* session gets misattributed to VS Code.
|
|
62
|
-
*/
|
|
63
|
-
export function detectFromEnv(env) {
|
|
64
|
-
const detectedAt = Date.now();
|
|
65
|
-
if (env.CURSOR_TRACE_ID) {
|
|
66
|
-
return { editor: 'cursor', label: 'Cursor', detectedAt };
|
|
67
|
-
}
|
|
68
|
-
if (env.VSCODE_PID || env.VSCODE_INJECTION) {
|
|
69
|
-
return { editor: 'vscode', label: 'VS Code', detectedAt };
|
|
70
|
-
}
|
|
71
|
-
const termProgram = env.TERM_PROGRAM;
|
|
72
|
-
if (termProgram === 'WarpTerminal') {
|
|
73
|
-
return { editor: 'warp', label: 'Warp', detectedAt };
|
|
74
|
-
}
|
|
75
|
-
if (termProgram === 'iTerm.app') {
|
|
76
|
-
return { editor: 'iterm', label: 'iTerm', detectedAt };
|
|
77
|
-
}
|
|
78
|
-
if (termProgram === 'Apple_Terminal') {
|
|
79
|
-
return { editor: 'apple-terminal', label: 'Terminal', detectedAt };
|
|
80
|
-
}
|
|
81
|
-
if (termProgram === 'WezTerm') {
|
|
82
|
-
return { editor: 'wezterm', label: 'WezTerm', detectedAt };
|
|
83
|
-
}
|
|
84
|
-
if (env.WT_SESSION) {
|
|
85
|
-
return { editor: 'windows-terminal', label: 'Windows Terminal', detectedAt };
|
|
86
|
-
}
|
|
87
|
-
if (env.KITTY_WINDOW_ID) {
|
|
88
|
-
return { editor: 'kitty', label: 'Kitty', detectedAt };
|
|
89
|
-
}
|
|
90
|
-
if (env.TERM === 'alacritty' || env.ALACRITTY_SOCKET) {
|
|
91
|
-
return { editor: 'alacritty', label: 'Alacritty', detectedAt };
|
|
92
|
-
}
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Read the env of an arbitrary PID using a platform-specific shim.
|
|
97
|
-
* - Linux: /proc/<pid>/environ (NUL-delimited KEY=VALUE)
|
|
98
|
-
* - macOS/BSD: `ps eww -o command= -p <pid>` — the `e` flag appends the
|
|
99
|
-
* env after the argv in the command column, separated by spaces.
|
|
100
|
-
*
|
|
101
|
-
* Returns an empty object on any failure (process gone, permission denied,
|
|
102
|
-
* unsupported platform). The caller treats "can't read env" the same as
|
|
103
|
-
* "no editor marker present" → no origin detected.
|
|
104
|
-
*/
|
|
105
|
-
async function readProcessEnv(pid) {
|
|
106
|
-
if (process.platform === 'linux') {
|
|
107
|
-
try {
|
|
108
|
-
const raw = await readFile(`/proc/${pid}/environ`, 'utf8');
|
|
109
|
-
return parseNulDelimited(raw);
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return {};
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// macOS, FreeBSD, OpenBSD — ps eww appends env after argv.
|
|
116
|
-
try {
|
|
117
|
-
const { stdout } = await execFileP('ps', ['eww', '-o', 'command=', '-p', String(pid)], { timeout: 2_000, maxBuffer: 1024 * 1024 });
|
|
118
|
-
return parsePsCommandEnv(stdout);
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return {};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function parseNulDelimited(raw) {
|
|
125
|
-
const out = {};
|
|
126
|
-
for (const pair of raw.split('\0')) {
|
|
127
|
-
if (!pair)
|
|
128
|
-
continue;
|
|
129
|
-
const eq = pair.indexOf('=');
|
|
130
|
-
if (eq <= 0)
|
|
131
|
-
continue;
|
|
132
|
-
const k = pair.slice(0, eq);
|
|
133
|
-
const v = pair.slice(eq + 1);
|
|
134
|
-
out[k] = v;
|
|
135
|
-
}
|
|
136
|
-
return out;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* `ps eww` output looks like:
|
|
140
|
-
* /path/to/claude arg1 arg2 KEY=value OTHER=value2 ...
|
|
141
|
-
*
|
|
142
|
-
* We can't reliably split argv from env (argv can contain `=`), but for our
|
|
143
|
-
* purposes we only care about the allowlisted env keys — so we scan every
|
|
144
|
-
* space-separated token, keep the ones that look like `KEY=value` AND whose
|
|
145
|
-
* KEY is in the allowlist. Everything else (argv, unrelated env) is dropped.
|
|
146
|
-
* This is intentionally conservative: we'd rather miss a marker than misread
|
|
147
|
-
* an argv as env.
|
|
148
|
-
*/
|
|
149
|
-
function parsePsCommandEnv(stdout) {
|
|
150
|
-
const out = {};
|
|
151
|
-
const allowlist = new Set(EDITOR_ENV_ALLOWLIST);
|
|
152
|
-
// Flatten multi-line output (long command lines wrap) into one blob then
|
|
153
|
-
// split on whitespace. `ps eww` doesn't quote — env values with spaces will
|
|
154
|
-
// be truncated at the first whitespace, which is fine for the short ID-like
|
|
155
|
-
// markers we care about.
|
|
156
|
-
const tokens = stdout.replace(/\s+/g, ' ').trim().split(' ');
|
|
157
|
-
for (const tok of tokens) {
|
|
158
|
-
const eq = tok.indexOf('=');
|
|
159
|
-
if (eq <= 0)
|
|
160
|
-
continue;
|
|
161
|
-
const k = tok.slice(0, eq);
|
|
162
|
-
if (!allowlist.has(k))
|
|
163
|
-
continue;
|
|
164
|
-
out[k] = tok.slice(eq + 1);
|
|
165
|
-
}
|
|
166
|
-
return out;
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* End-to-end origin detection for a live process. Reads env via the platform
|
|
170
|
-
* shim, filters through the allowlist, classifies. Returns `null` on any
|
|
171
|
-
* failure — callers treat that as "no origin known" and fall through to the
|
|
172
|
-
* next heuristic. Never throws.
|
|
173
|
-
*/
|
|
174
|
-
export async function detectEditorOrigin(pid) {
|
|
175
|
-
if (!Number.isFinite(pid) || pid <= 0)
|
|
176
|
-
return null;
|
|
177
|
-
try {
|
|
178
|
-
const raw = await readProcessEnv(pid);
|
|
179
|
-
const filtered = filterEnvToAllowlist(raw);
|
|
180
|
-
return detectFromEnv(filtered);
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
//# sourceMappingURL=editor-detection.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"editor-detection.js","sourceRoot":"","sources":["../../src/daemon/editor-detection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../../src/daemon/entrypoint.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,MAAM,2BAA2B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACvD,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,CAAC;AAE9C,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IAEvC,eAAe,CAAC;QACd,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAE/B,0EAA0E;IAC1E,0EAA0E;IAC1E,uEAAuE;IACvE,uDAAuD;IACvD,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC;YACH,iBAAiB,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CAAC;IACF,MAAM,YAAY,GAAG,UAAU,CAAC,iBAAiB,EAAE,2BAA2B,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,WAAW,CAAC,iBAAiB,EAAE,2BAA2B,CAAC,CAAC;IAE9E,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE;QAClC,OAAO,CAAC,GAAG,CAAC,qBAAqB,MAAM,iBAAiB,CAAC,CAAC;QAC1D,YAAY,CAAC,YAAY,CAAC,CAAC;QAC3B,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,eAAe,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE/C,OAAO,CAAC,GAAG,CAAC,sCAAsC,IAAI,SAAS,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACtC,eAAe,EAAE,CAAC;IAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|