@clauderecallhq/cli 0.12.5 → 0.61.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +37 -17
- package/README.md +110 -22
- package/dist/cli.js +1641 -353
- package/dist/daemon/entrypoint.js +1872 -54
- package/dist/mcp-server.js +930 -0
- package/dist/share/fonts/Inter-Bold.woff +0 -0
- package/dist/share/fonts/Inter-Regular.woff +0 -0
- package/dist/share/fonts/JetBrainsMono-Regular.woff +0 -0
- package/dist/web/assets/_brand-Bw9uSB4O.js +1 -0
- package/dist/web/assets/captureNode-9CVj9vYC.js +2 -0
- package/dist/web/assets/card-a-minimal-ujNERzX7.js +1 -0
- package/dist/web/assets/card-b-terminal-DpJ_tVpg.js +1 -0
- package/dist/web/assets/card-c-gradient-CZXVGuNd.js +1 -0
- package/dist/web/assets/card-d-dashboard-CHKD-PnB.js +1 -0
- package/dist/web/assets/dist-CWaokT35.js +56 -0
- package/dist/web/assets/index-B-HrjaDy.css +1 -0
- package/dist/web/assets/index-BZYcD76T.js +633 -0
- package/dist/web/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
- package/dist/web/assets/patterns-BPeZb9N0.js +1 -0
- package/dist/web/assets/stats-BSwqSiFU.js +1 -0
- package/dist/web/assets/thread-D2AXyhOx.js +1 -0
- package/dist/web/index.html +8 -2
- package/package.json +58 -18
- package/scripts/postinstall.mjs +38 -0
- package/dist/cli.js.map +0 -1
- package/dist/commands/activate.js +0 -69
- package/dist/commands/activate.js.map +0 -1
- package/dist/commands/audit-secrets.js +0 -103
- package/dist/commands/audit-secrets.js.map +0 -1
- package/dist/commands/blame.js +0 -35
- package/dist/commands/blame.js.map +0 -1
- package/dist/commands/config-verification.js +0 -18
- package/dist/commands/config-verification.js.map +0 -1
- package/dist/commands/context.js +0 -144
- package/dist/commands/context.js.map +0 -1
- package/dist/commands/correlate.js +0 -70
- package/dist/commands/correlate.js.map +0 -1
- package/dist/commands/digest.js +0 -78
- package/dist/commands/digest.js.map +0 -1
- package/dist/commands/health.js +0 -62
- package/dist/commands/health.js.map +0 -1
- package/dist/commands/index.js +0 -247
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/install-extension.js +0 -138
- package/dist/commands/install-extension.js.map +0 -1
- package/dist/commands/license.js +0 -39
- package/dist/commands/license.js.map +0 -1
- package/dist/commands/list.js +0 -47
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/mcp.js +0 -29
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/open.js +0 -28
- package/dist/commands/open.js.map +0 -1
- package/dist/commands/paste.js +0 -154
- package/dist/commands/paste.js.map +0 -1
- package/dist/commands/projects.js +0 -36
- package/dist/commands/projects.js.map +0 -1
- package/dist/commands/search.js +0 -67
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/semantic.js +0 -173
- package/dist/commands/semantic.js.map +0 -1
- package/dist/commands/show.js +0 -121
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/start.js +0 -47
- package/dist/commands/start.js.map +0 -1
- package/dist/commands/stats.js +0 -133
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/status.js +0 -45
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/stop.js +0 -29
- package/dist/commands/stop.js.map +0 -1
- package/dist/commands/thread.js +0 -396
- package/dist/commands/thread.js.map +0 -1
- package/dist/context/formatter.js +0 -103
- package/dist/context/formatter.js.map +0 -1
- package/dist/daemon/auto-tag-config.js +0 -103
- package/dist/daemon/auto-tag-config.js.map +0 -1
- package/dist/daemon/auto-tag-config.test.js +0 -72
- package/dist/daemon/auto-tag-config.test.js.map +0 -1
- package/dist/daemon/auto-title-config.js +0 -70
- package/dist/daemon/auto-title-config.js.map +0 -1
- package/dist/daemon/bulk-title-jobs.js +0 -170
- package/dist/daemon/bulk-title-jobs.js.map +0 -1
- package/dist/daemon/correlator.js +0 -320
- package/dist/daemon/correlator.js.map +0 -1
- package/dist/daemon/discover.js +0 -316
- package/dist/daemon/discover.js.map +0 -1
- package/dist/daemon/editor-detection.js +0 -186
- package/dist/daemon/editor-detection.js.map +0 -1
- package/dist/daemon/entrypoint.js.map +0 -1
- package/dist/daemon/git-correlator.js +0 -256
- package/dist/daemon/git-correlator.js.map +0 -1
- package/dist/daemon/mcp-installer.js +0 -108
- package/dist/daemon/mcp-installer.js.map +0 -1
- package/dist/daemon/onboarding-state.js +0 -140
- package/dist/daemon/onboarding-state.js.map +0 -1
- package/dist/daemon/pidfile.js +0 -57
- package/dist/daemon/pidfile.js.map +0 -1
- package/dist/daemon/ports.js +0 -48
- package/dist/daemon/ports.js.map +0 -1
- package/dist/daemon/scanProgressRegistry.js +0 -62
- package/dist/daemon/scanProgressRegistry.js.map +0 -1
- package/dist/daemon/server.js +0 -2010
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/tag-scanner/anthropic-client.js +0 -40
- package/dist/daemon/tag-scanner/anthropic-client.js.map +0 -1
- package/dist/daemon/tag-scanner/autopilot.js +0 -131
- package/dist/daemon/tag-scanner/autopilot.js.map +0 -1
- package/dist/daemon/tag-scanner/claude-cli-driver.js +0 -250
- package/dist/daemon/tag-scanner/claude-cli-driver.js.map +0 -1
- package/dist/daemon/tag-scanner/orchestrator.js +0 -88
- package/dist/daemon/tag-scanner/orchestrator.js.map +0 -1
- package/dist/daemon/tag-scanner/prompt.js +0 -46
- package/dist/daemon/tag-scanner/prompt.js.map +0 -1
- package/dist/daemon/tag-scanner/prompt.test.js +0 -48
- package/dist/daemon/tag-scanner/prompt.test.js.map +0 -1
- package/dist/daemon/tag-scanner/scan-state.js +0 -49
- package/dist/daemon/tag-scanner/scan-state.js.map +0 -1
- package/dist/daemon/tag-scanner/session-fetcher.js +0 -82
- package/dist/daemon/tag-scanner/session-fetcher.js.map +0 -1
- package/dist/daemon/tag-scanner/session-fetcher.test.js +0 -34
- package/dist/daemon/tag-scanner/session-fetcher.test.js.map +0 -1
- package/dist/daemon/tag-scanner/validator.js +0 -50
- package/dist/daemon/tag-scanner/validator.js.map +0 -1
- package/dist/daemon/tag-scanner/validator.test.js +0 -41
- package/dist/daemon/tag-scanner/validator.test.js.map +0 -1
- package/dist/daemon/terminal-registry.js +0 -443
- package/dist/daemon/terminal-registry.js.map +0 -1
- package/dist/daemon/ui.js +0 -64
- package/dist/daemon/ui.js.map +0 -1
- package/dist/daemon/watcher.js +0 -256
- package/dist/daemon/watcher.js.map +0 -1
- package/dist/db/client.js +0 -22
- package/dist/db/client.js.map +0 -1
- package/dist/db/schema.js +0 -496
- package/dist/db/schema.js.map +0 -1
- package/dist/license/api-base.js +0 -13
- package/dist/license/api-base.js.map +0 -1
- package/dist/license/manager.js +0 -43
- package/dist/license/manager.js.map +0 -1
- package/dist/license/public-key.js +0 -19
- package/dist/license/public-key.js.map +0 -1
- package/dist/license/storage.js +0 -27
- package/dist/license/storage.js.map +0 -1
- package/dist/license/verify.js +0 -23
- package/dist/license/verify.js.map +0 -1
- package/dist/mcp/audit.js +0 -126
- package/dist/mcp/audit.js.map +0 -1
- package/dist/mcp/prompts.js +0 -180
- package/dist/mcp/prompts.js.map +0 -1
- package/dist/mcp/server.js +0 -502
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/thread-tools.js +0 -363
- package/dist/mcp/thread-tools.js.map +0 -1
- package/dist/mcp/write-tools.js +0 -239
- package/dist/mcp/write-tools.js.map +0 -1
- package/dist/parser/jsonl.js +0 -150
- package/dist/parser/jsonl.js.map +0 -1
- package/dist/semantic/chunker.js +0 -47
- package/dist/semantic/chunker.js.map +0 -1
- package/dist/semantic/config.js +0 -74
- package/dist/semantic/config.js.map +0 -1
- package/dist/semantic/embedder.js +0 -54
- package/dist/semantic/embedder.js.map +0 -1
- package/dist/semantic/fusion.js +0 -38
- package/dist/semantic/fusion.js.map +0 -1
- package/dist/semantic/model-download.js +0 -69
- package/dist/semantic/model-download.js.map +0 -1
- package/dist/semantic/pipeline.js +0 -375
- package/dist/semantic/pipeline.js.map +0 -1
- package/dist/semantic/query.js +0 -42
- package/dist/semantic/query.js.map +0 -1
- package/dist/semantic/worker.js +0 -78
- package/dist/semantic/worker.js.map +0 -1
- package/dist/stats/backfill.js +0 -151
- package/dist/stats/backfill.js.map +0 -1
- package/dist/stats/health.js +0 -102
- package/dist/stats/health.js.map +0 -1
- package/dist/stats/query.js +0 -385
- package/dist/stats/query.js.map +0 -1
- package/dist/utils/aliases.js +0 -107
- package/dist/utils/aliases.js.map +0 -1
- package/dist/utils/autoCollections.js +0 -635
- package/dist/utils/autoCollections.js.map +0 -1
- package/dist/utils/autoTitle.js +0 -348
- package/dist/utils/autoTitle.js.map +0 -1
- package/dist/utils/collections.js +0 -446
- package/dist/utils/collections.js.map +0 -1
- package/dist/utils/format.js +0 -46
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/notes.js +0 -270
- package/dist/utils/notes.js.map +0 -1
- package/dist/utils/paths.js +0 -50
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/pricing.js +0 -257
- package/dist/utils/pricing.js.map +0 -1
- package/dist/utils/secret-scanner.js +0 -166
- package/dist/utils/secret-scanner.js.map +0 -1
- package/dist/utils/sessionLabel.js +0 -64
- package/dist/utils/sessionLabel.js.map +0 -1
- package/dist/utils/tags.js +0 -97
- package/dist/utils/tags.js.map +0 -1
- package/dist/utils/thread-context.js +0 -129
- package/dist/utils/thread-context.js.map +0 -1
- package/dist/utils/threadFilter.js +0 -18
- package/dist/utils/threadFilter.js.map +0 -1
- package/dist/utils/threads-titler.js +0 -298
- package/dist/utils/threads-titler.js.map +0 -1
- package/dist/utils/threads.js +0 -383
- package/dist/utils/threads.js.map +0 -1
- package/dist/utils/usage.js +0 -76
- package/dist/utils/usage.js.map +0 -1
- package/dist/verification/compute.js +0 -88
- package/dist/verification/compute.js.map +0 -1
- package/dist/verification/config.js +0 -34
- package/dist/verification/config.js.map +0 -1
- package/dist/web/assets/index-CIr6J4Fw.js +0 -1201
- package/dist/web/assets/index-Ctc8g9Jw.css +0 -1
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtempSync, rmSync, existsSync, statSync } from 'node:fs';
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
describe('auto-tag-config', () => {
|
|
7
|
-
let tmpHome;
|
|
8
|
-
let prevHome;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
tmpHome = mkdtempSync(join(tmpdir(), 'recall-cfg-'));
|
|
11
|
-
prevHome = process.env.RECALL_HOME;
|
|
12
|
-
process.env.RECALL_HOME = tmpHome;
|
|
13
|
-
});
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
if (prevHome)
|
|
16
|
-
process.env.RECALL_HOME = prevHome;
|
|
17
|
-
else
|
|
18
|
-
delete process.env.RECALL_HOME;
|
|
19
|
-
rmSync(tmpHome, { recursive: true, force: true });
|
|
20
|
-
});
|
|
21
|
-
it('returns defaults when config file does not exist', async () => {
|
|
22
|
-
const { readAutoTagConfig } = await import('./auto-tag-config.js');
|
|
23
|
-
const cfg = readAutoTagConfig();
|
|
24
|
-
assert.equal(cfg.enabled, false);
|
|
25
|
-
assert.equal(cfg.backend, 'api');
|
|
26
|
-
assert.equal(cfg.model, 'claude-opus-4-7');
|
|
27
|
-
});
|
|
28
|
-
it('round-trips writes', async () => {
|
|
29
|
-
const { readAutoTagConfig, writeAutoTagConfig } = await import('./auto-tag-config.js');
|
|
30
|
-
writeAutoTagConfig({
|
|
31
|
-
enabled: true,
|
|
32
|
-
backend: 'api',
|
|
33
|
-
apiKey: 'sk-ant-test',
|
|
34
|
-
model: 'claude-opus-4-7',
|
|
35
|
-
maxTagsPerSession: 4,
|
|
36
|
-
minTagsPerSession: 2,
|
|
37
|
-
});
|
|
38
|
-
const got = readAutoTagConfig();
|
|
39
|
-
assert.equal(got.enabled, true);
|
|
40
|
-
assert.equal(got.apiKey, 'sk-ant-test');
|
|
41
|
-
});
|
|
42
|
-
it('writes with 0600 file mode', async () => {
|
|
43
|
-
const { writeAutoTagConfig } = await import('./auto-tag-config.js');
|
|
44
|
-
writeAutoTagConfig({
|
|
45
|
-
enabled: true,
|
|
46
|
-
backend: 'api',
|
|
47
|
-
apiKey: 'secret',
|
|
48
|
-
model: 'claude-opus-4-7',
|
|
49
|
-
maxTagsPerSession: 4,
|
|
50
|
-
minTagsPerSession: 2,
|
|
51
|
-
});
|
|
52
|
-
const path = join(tmpHome, 'config.json');
|
|
53
|
-
assert.equal(existsSync(path), true);
|
|
54
|
-
const mode = statSync(path).mode & 0o777;
|
|
55
|
-
assert.equal(mode, 0o600);
|
|
56
|
-
});
|
|
57
|
-
it('redacts apiKey via redactForApi', async () => {
|
|
58
|
-
const { redactForApi } = await import('./auto-tag-config.js');
|
|
59
|
-
const redacted = redactForApi({
|
|
60
|
-
enabled: true,
|
|
61
|
-
backend: 'api',
|
|
62
|
-
apiKey: 'sk-ant-XXXXX',
|
|
63
|
-
model: 'claude-opus-4-7',
|
|
64
|
-
maxTagsPerSession: 4,
|
|
65
|
-
minTagsPerSession: 2,
|
|
66
|
-
autopilot: false,
|
|
67
|
-
});
|
|
68
|
-
assert.equal(redacted.apiKey, 'sk-ant-…');
|
|
69
|
-
assert.equal(redacted.hasApiKey, true);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
//# sourceMappingURL=auto-tag-config.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-tag-config.test.js","sourceRoot":"","sources":["../../src/daemon/auto-tag-config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
/**
|
|
6
|
-
* v0.14b (T5) — auto-title config, persisted as `{ autoTitle: {...} }` inside
|
|
7
|
-
* `$RECALL_HOME/config.json` alongside the existing `autoTag` block.
|
|
8
|
-
*
|
|
9
|
-
* Two booleans:
|
|
10
|
-
* - `heuristicEnabled` (default true) — indexer-time heuristic pass.
|
|
11
|
-
* - `agentEnabled` (default false) — `claude -p` summarisation path.
|
|
12
|
-
* OFF by default because it spawns a subprocess and uses the user's
|
|
13
|
-
* subscription. The UI's ✨ Generate title button flips this per-click
|
|
14
|
-
* after an explicit confirmation, identical to the auto-tag opt-in.
|
|
15
|
-
*
|
|
16
|
-
* Path resolution mirrors `auto-tag-config.ts`: lazy re-read of
|
|
17
|
-
* `process.env.RECALL_HOME` on every call so tests can redirect the data
|
|
18
|
-
* root per-test without a module-cache dance.
|
|
19
|
-
*/
|
|
20
|
-
function recallHome() {
|
|
21
|
-
return process.env.RECALL_HOME ?? join(homedir(), '.recall');
|
|
22
|
-
}
|
|
23
|
-
function ensureHome() {
|
|
24
|
-
const home = recallHome();
|
|
25
|
-
if (!existsSync(home))
|
|
26
|
-
mkdirSync(home, { recursive: true });
|
|
27
|
-
}
|
|
28
|
-
function configFile() {
|
|
29
|
-
return join(recallHome(), 'config.json');
|
|
30
|
-
}
|
|
31
|
-
export const AutoTitleConfigSchema = z.object({
|
|
32
|
-
heuristicEnabled: z.boolean().default(true),
|
|
33
|
-
agentEnabled: z.boolean().default(false),
|
|
34
|
-
});
|
|
35
|
-
const DEFAULTS = {
|
|
36
|
-
heuristicEnabled: true,
|
|
37
|
-
agentEnabled: false,
|
|
38
|
-
};
|
|
39
|
-
function readFileShape() {
|
|
40
|
-
const path = configFile();
|
|
41
|
-
if (!existsSync(path))
|
|
42
|
-
return {};
|
|
43
|
-
try {
|
|
44
|
-
return JSON.parse(readFileSync(path, 'utf8'));
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
console.error('[auto-title-config] failed to parse config.json, using defaults:', err);
|
|
48
|
-
return {};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
export function readAutoTitleConfig() {
|
|
52
|
-
const raw = readFileShape().autoTitle;
|
|
53
|
-
if (!raw)
|
|
54
|
-
return { ...DEFAULTS };
|
|
55
|
-
const parsed = AutoTitleConfigSchema.safeParse({ ...DEFAULTS, ...raw });
|
|
56
|
-
return parsed.success ? parsed.data : { ...DEFAULTS };
|
|
57
|
-
}
|
|
58
|
-
export function writeAutoTitleConfig(patch) {
|
|
59
|
-
ensureHome();
|
|
60
|
-
const existing = readFileShape();
|
|
61
|
-
const merged = AutoTitleConfigSchema.parse({
|
|
62
|
-
...DEFAULTS,
|
|
63
|
-
...(existing.autoTitle ?? {}),
|
|
64
|
-
...patch,
|
|
65
|
-
});
|
|
66
|
-
const next = { ...existing, autoTitle: merged };
|
|
67
|
-
writeFileSync(configFile(), JSON.stringify(next, null, 2));
|
|
68
|
-
return merged;
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=auto-title-config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-title-config.js","sourceRoot":"","sources":["../../src/daemon/auto-title-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;GAcG;AAEH,SAAS,UAAU;IACjB,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,aAAa,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3C,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACzC,CAAC,CAAC;AAIH,MAAM,QAAQ,GAAoB;IAChC,gBAAgB,EAAE,IAAI;IACtB,YAAY,EAAE,KAAK;CACpB,CAAC;AAOF,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAc,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,kEAAkE,EAAE,GAAG,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC,SAAS,CAAC;IACtC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;IACxE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAA+B;IAClE,UAAU,EAAE,CAAC;IACb,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC;QACzC,GAAG,QAAQ;QACX,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;QAC7B,GAAG,KAAK;KACT,CAAC,CAAC;IACH,MAAM,IAAI,GAAc,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAC3D,aAAa,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { generateThreadTitles, } from '../utils/threads-titler.js';
|
|
3
|
-
const REGISTRY = new Map();
|
|
4
|
-
const TTL_AFTER_DONE_MS = 5 * 60 * 1000;
|
|
5
|
-
function pushEvent(state, kind, data) {
|
|
6
|
-
const id = state.events.length + 1;
|
|
7
|
-
state.events.push({ id, kind, data });
|
|
8
|
-
for (const w of state.waiters)
|
|
9
|
-
w.resolve();
|
|
10
|
-
state.waiters.clear();
|
|
11
|
-
}
|
|
12
|
-
function scheduleCleanup(state) {
|
|
13
|
-
if (state.cleanupTimer)
|
|
14
|
-
clearTimeout(state.cleanupTimer);
|
|
15
|
-
state.cleanupTimer = setTimeout(() => {
|
|
16
|
-
REGISTRY.delete(state.jobId);
|
|
17
|
-
}, TTL_AFTER_DONE_MS);
|
|
18
|
-
}
|
|
19
|
-
function snapshot(state) {
|
|
20
|
-
let done = 0;
|
|
21
|
-
let skipped = 0;
|
|
22
|
-
let failed = 0;
|
|
23
|
-
for (const e of state.events) {
|
|
24
|
-
if (e.kind === 'progress')
|
|
25
|
-
done += 1;
|
|
26
|
-
if (e.kind === 'skipped')
|
|
27
|
-
skipped += 1;
|
|
28
|
-
if (e.kind === 'error')
|
|
29
|
-
failed += 1;
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
jobId: state.jobId,
|
|
33
|
-
threadId: state.threadId,
|
|
34
|
-
status: state.status,
|
|
35
|
-
startedAt: state.startedAt,
|
|
36
|
-
endedAt: state.endedAt,
|
|
37
|
-
total: state.total,
|
|
38
|
-
done,
|
|
39
|
-
skipped,
|
|
40
|
-
failed,
|
|
41
|
-
result: state.result,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Spawn a detached bulk-title walk. Returns the jobId immediately. The walk
|
|
46
|
-
* runs on the daemon's event loop and pushes progress events into the
|
|
47
|
-
* registry; SSE subscribers pull from there.
|
|
48
|
-
*/
|
|
49
|
-
export function startBulkTitleJob(input) {
|
|
50
|
-
const jobId = randomUUID();
|
|
51
|
-
const controller = new AbortController();
|
|
52
|
-
const state = {
|
|
53
|
-
jobId,
|
|
54
|
-
threadId: input.threadId,
|
|
55
|
-
status: 'running',
|
|
56
|
-
startedAt: new Date().toISOString(),
|
|
57
|
-
endedAt: null,
|
|
58
|
-
total: 0,
|
|
59
|
-
events: [],
|
|
60
|
-
waiters: new Set(),
|
|
61
|
-
controller,
|
|
62
|
-
result: null,
|
|
63
|
-
cleanupTimer: null,
|
|
64
|
-
};
|
|
65
|
-
REGISTRY.set(jobId, state);
|
|
66
|
-
// Detached: the walk runs to completion or until cancelled. Errors thrown
|
|
67
|
-
// by generateThreadTitles itself (thread not found, fatal db error) end up
|
|
68
|
-
// as a synthetic 'done' event with failed entries so subscribers always
|
|
69
|
-
// get a terminal event.
|
|
70
|
-
//
|
|
71
|
-
// The leading `await Promise.resolve()` yields once so the caller has time
|
|
72
|
-
// to bind the returned jobId before the walk starts. Without it, the spawn
|
|
73
|
-
// override could fire (and call cancelJob with a stale jobId) inside the
|
|
74
|
-
// same sync stack as `startBulkTitleJob(...)`, which is what the cancel
|
|
75
|
-
// test exercises.
|
|
76
|
-
void (async () => {
|
|
77
|
-
await Promise.resolve();
|
|
78
|
-
try {
|
|
79
|
-
const result = await generateThreadTitles(input.threadId, {
|
|
80
|
-
force: input.force ?? false,
|
|
81
|
-
signal: controller.signal,
|
|
82
|
-
model: input.model,
|
|
83
|
-
onProgress: (ev) => {
|
|
84
|
-
state.total = ev.total;
|
|
85
|
-
pushEvent(state, 'progress', ev);
|
|
86
|
-
},
|
|
87
|
-
onSkipped: (ev) => {
|
|
88
|
-
pushEvent(state, 'skipped', ev);
|
|
89
|
-
},
|
|
90
|
-
onFailed: (ev) => {
|
|
91
|
-
pushEvent(state, 'error', ev);
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
state.result = result;
|
|
95
|
-
state.status = controller.signal.aborted ? 'cancelled' : 'done';
|
|
96
|
-
state.endedAt = new Date().toISOString();
|
|
97
|
-
pushEvent(state, 'done', result);
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
const message = err instanceof Error ? err.message : String(err ?? 'unknown error');
|
|
101
|
-
state.result = {
|
|
102
|
-
generated: [],
|
|
103
|
-
skipped: [],
|
|
104
|
-
failed: [{ sessionId: input.threadId, error: message }],
|
|
105
|
-
};
|
|
106
|
-
state.status = 'failed';
|
|
107
|
-
state.endedAt = new Date().toISOString();
|
|
108
|
-
pushEvent(state, 'done', state.result);
|
|
109
|
-
}
|
|
110
|
-
finally {
|
|
111
|
-
scheduleCleanup(state);
|
|
112
|
-
}
|
|
113
|
-
})();
|
|
114
|
-
return jobId;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Async iterator over a job's events. Resumes from `afterId` if provided
|
|
118
|
-
* (use `Last-Event-ID` from the SSE protocol). Yields buffered events first,
|
|
119
|
-
* then awaits new ones until the job emits `done`. The consumer is expected
|
|
120
|
-
* to break on the `done` event; the iterator itself does not exit early so
|
|
121
|
-
* heartbeats can interleave.
|
|
122
|
-
*/
|
|
123
|
-
export async function* subscribeJob(jobId, afterId = 0) {
|
|
124
|
-
const state = REGISTRY.get(jobId);
|
|
125
|
-
if (!state)
|
|
126
|
-
return;
|
|
127
|
-
let cursor = afterId;
|
|
128
|
-
while (true) {
|
|
129
|
-
while (cursor < state.events.length) {
|
|
130
|
-
const ev = state.events[cursor];
|
|
131
|
-
cursor += 1;
|
|
132
|
-
yield ev;
|
|
133
|
-
if (ev.kind === 'done')
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (state.endedAt)
|
|
137
|
-
return;
|
|
138
|
-
await new Promise((resolve) => {
|
|
139
|
-
state.waiters.add({ resolve });
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
export function cancelJob(jobId) {
|
|
144
|
-
const state = REGISTRY.get(jobId);
|
|
145
|
-
if (!state)
|
|
146
|
-
return false;
|
|
147
|
-
if (state.status !== 'running')
|
|
148
|
-
return false;
|
|
149
|
-
state.controller.abort();
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
export function getJobSnapshot(jobId) {
|
|
153
|
-
const state = REGISTRY.get(jobId);
|
|
154
|
-
if (!state)
|
|
155
|
-
return null;
|
|
156
|
-
return snapshot(state);
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Test-only helper: clear every job (useful between tests so registry
|
|
160
|
-
* residue from one test does not leak into the next). Not exported from a
|
|
161
|
-
* module index; tests reach in directly.
|
|
162
|
-
*/
|
|
163
|
-
export function __resetForTests() {
|
|
164
|
-
for (const state of REGISTRY.values()) {
|
|
165
|
-
if (state.cleanupTimer)
|
|
166
|
-
clearTimeout(state.cleanupTimer);
|
|
167
|
-
}
|
|
168
|
-
REGISTRY.clear();
|
|
169
|
-
}
|
|
170
|
-
//# sourceMappingURL=bulk-title-jobs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-title-jobs.js","sourceRoot":"","sources":["../../src/daemon/bulk-title-jobs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,oBAAoB,GAKrB,MAAM,4BAA4B,CAAC;AAsEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;AAC7C,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAExC,SAAS,SAAS,CAAC,KAAe,EAAE,IAAwB,EAAE,IAAa;IACzE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACnC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO;QAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAC3C,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,eAAe,CAAC,KAAe;IACtC,IAAI,KAAK,CAAC,YAAY;QAAE,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACzD,KAAK,CAAC,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;QACnC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC,EAAE,iBAAiB,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAe;IAC/B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;YAAE,IAAI,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;YAAE,MAAM,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI;QACJ,OAAO;QACP,MAAM;QACN,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC;AACJ,CAAC;AAQD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAa;QACtB,KAAK;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,UAAU;QACV,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,IAAI;KACnB,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE3B,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,wBAAwB;IACxB,EAAE;IACF,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,wEAAwE;IACxE,kBAAkB;IAClB,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,QAAQ,EAAE;gBACxD,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK;gBAC3B,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,UAAU,EAAE,CAAC,EAAiB,EAAE,EAAE;oBAChC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;oBACvB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;gBACnC,CAAC;gBACD,SAAS,EAAE,CAAC,EAAgB,EAAE,EAAE;oBAC9B,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;gBAClC,CAAC;gBACD,QAAQ,EAAE,CAAC,EAAe,EAAE,EAAE;oBAC5B,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;gBAChC,CAAC;aACF,CAAC,CAAC;YACH,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;YACtB,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;YAChE,KAAK,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACzC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,eAAe,CAAC,CAAC;YACtE,KAAK,CAAC,MAAM,GAAG;gBACb,SAAS,EAAE,EAAE;gBACb,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;aACxD,CAAC;YACF,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC;YACxB,KAAK,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACzC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;gBAAS,CAAC;YACT,eAAe,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,YAAY,CACjC,KAAa,EACb,OAAO,GAAG,CAAC;IAEX,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,IAAI,MAAM,GAAG,OAAO,CAAC;IACrB,OAAO,IAAI,EAAE,CAAC;QACZ,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACpC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChC,MAAM,IAAI,CAAC,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO;QACjC,CAAC;QACD,IAAI,KAAK,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7C,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACzB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,YAAY;YAAE,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3D,CAAC;IACD,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
import { basename } from 'node:path';
|
|
4
|
-
import { terminalRegistry, looksLikeClaudeAutoTitle, stripAutoTitlePrefix, } from './terminal-registry.js';
|
|
5
|
-
import { getAlias, setAlias } from '../utils/aliases.js';
|
|
6
|
-
import { getDb } from '../db/client.js';
|
|
7
|
-
import { detectEditorOrigin } from './editor-detection.js';
|
|
8
|
-
const execFileP = promisify(execFile);
|
|
9
|
-
/**
|
|
10
|
-
* v0.7 correlator.
|
|
11
|
-
*
|
|
12
|
-
* When the file watcher ingests a newly-created JSONL, we attempt to map that
|
|
13
|
-
* session to a VS Code terminal the extension has registered. Process-tree
|
|
14
|
-
* matching is 100% deterministic and does not rely on timing windows:
|
|
15
|
-
*
|
|
16
|
-
* 1. lsof finds which process currently has this JSONL file open
|
|
17
|
-
* 2. ps finds that process's parent shell PID
|
|
18
|
-
* 3. If the parent shell PID is in our terminalRegistry, we auto-alias the
|
|
19
|
-
* session with the tab name the user set in VS Code
|
|
20
|
-
*
|
|
21
|
-
* v0.15, T4 — if the extension isn't installed, we still read the env of the
|
|
22
|
-
* live `claude` process to classify the host editor (Cursor / VS Code / Warp
|
|
23
|
-
* / iTerm / …). Tab-name entries from the extension still take precedence;
|
|
24
|
-
* origin-derived labels are the fallback.
|
|
25
|
-
*
|
|
26
|
-
* Failures are silent and non-fatal — a session that doesn't get auto-aliased
|
|
27
|
-
* is still manually renameable in the UI. The correlator skips sessions that
|
|
28
|
-
* already have an alias, so it never overwrites user intent.
|
|
29
|
-
*/
|
|
30
|
-
async function writerPidFor(filePath) {
|
|
31
|
-
try {
|
|
32
|
-
// `-Fpc` emits `p<pid>\nc<command>` pairs for every process that has the
|
|
33
|
-
// file open. lsof's output includes BOTH the active `claude` process
|
|
34
|
-
// (the real writer) AND the recall daemon's reader. If we return the
|
|
35
|
-
// first pid blindly, the daemon often wins and the correlator links the
|
|
36
|
-
// session to whatever shell launched `recall start` — visible symptom:
|
|
37
|
-
// a bunch of unrelated sessions all tied to the same shell_pid.
|
|
38
|
-
//
|
|
39
|
-
// Fix: walk the pairs and prefer the `claude` command. Only fall back to
|
|
40
|
-
// the first pid if no claude is in the list (which means claude has
|
|
41
|
-
// already exited — the session is historical, and cwd-based matching
|
|
42
|
-
// downstream will take over).
|
|
43
|
-
const { stdout } = await execFileP('lsof', ['-Fpc', filePath], {
|
|
44
|
-
timeout: 2_000,
|
|
45
|
-
});
|
|
46
|
-
const lines = stdout.split('\n');
|
|
47
|
-
let firstPid = null;
|
|
48
|
-
let claudePid = null;
|
|
49
|
-
let currentPid = null;
|
|
50
|
-
for (const line of lines) {
|
|
51
|
-
if (line.startsWith('p')) {
|
|
52
|
-
currentPid = Number(line.slice(1));
|
|
53
|
-
if (Number.isFinite(currentPid) && currentPid > 0) {
|
|
54
|
-
if (firstPid == null)
|
|
55
|
-
firstPid = currentPid;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
currentPid = null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else if (line.startsWith('c') && currentPid != null) {
|
|
62
|
-
const cmd = line.slice(1).trim();
|
|
63
|
-
// Match exactly `claude` (the CLI binary) — avoid matching
|
|
64
|
-
// `claude-recall-mcp`, `claudeAgents`, etc.
|
|
65
|
-
if (cmd === 'claude' && claudePid == null) {
|
|
66
|
-
claudePid = currentPid;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return claudePid ?? firstPid;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async function parentPidOf(pid) {
|
|
77
|
-
try {
|
|
78
|
-
const { stdout } = await execFileP('ps', ['-o', 'ppid=', '-p', String(pid)], { timeout: 2_000 });
|
|
79
|
-
const ppid = Number(stdout.trim());
|
|
80
|
-
return Number.isFinite(ppid) && ppid > 0 ? ppid : null;
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Pure decider for what string to auto-alias a session with. Separated from
|
|
88
|
-
* the I/O-heavy `tryAutoAlias` so unit tests can exercise the three spec
|
|
89
|
-
* scenarios (tab-name wins, origin fallback, neither) without touching ps/lsof
|
|
90
|
-
* or SQLite.
|
|
91
|
-
*
|
|
92
|
-
* Precedence:
|
|
93
|
-
* 1. Non-blank, non-generic `tabName` from the VS Code extension wins
|
|
94
|
-
* unconditionally. "Generic" means the bare shell binary (zsh, bash,
|
|
95
|
-
* fish, sh, pwsh, powershell, cmd) — VS Code ships that as the default
|
|
96
|
-
* terminal name when the user hasn't renamed the tab, so treating it as
|
|
97
|
-
* a tab name would produce `zsh` aliases for every session.
|
|
98
|
-
* 2. Otherwise, if we detected an editor origin via env, compose
|
|
99
|
-
* `${origin.label} · ${basename(cwd)} · ${gitBranch}` — dropping the
|
|
100
|
-
* cwd part when cwd is null and the git part when gitBranch is null.
|
|
101
|
-
* 3. Otherwise, return null — leave the session without an auto-alias so
|
|
102
|
-
* the user can still name it manually.
|
|
103
|
-
*/
|
|
104
|
-
const GENERIC_SHELL_NAMES = new Set([
|
|
105
|
-
'zsh',
|
|
106
|
-
'bash',
|
|
107
|
-
'fish',
|
|
108
|
-
'sh',
|
|
109
|
-
'dash',
|
|
110
|
-
'ksh',
|
|
111
|
-
'tcsh',
|
|
112
|
-
'csh',
|
|
113
|
-
'pwsh',
|
|
114
|
-
'powershell',
|
|
115
|
-
'cmd',
|
|
116
|
-
'nu',
|
|
117
|
-
]);
|
|
118
|
-
export function isGenericShellName(tabName) {
|
|
119
|
-
const trimmed = tabName.trim().toLowerCase();
|
|
120
|
-
if (!trimmed)
|
|
121
|
-
return true;
|
|
122
|
-
// Also treat "-zsh", "/bin/bash", "zsh (1)" style tab names as generic.
|
|
123
|
-
const stripped = trimmed
|
|
124
|
-
.replace(/^[-/]+/, '')
|
|
125
|
-
.replace(/^.*\//, '')
|
|
126
|
-
.replace(/\s*\(\d+\)\s*$/, '')
|
|
127
|
-
.trim();
|
|
128
|
-
return GENERIC_SHELL_NAMES.has(stripped);
|
|
129
|
-
}
|
|
130
|
-
export function composeAutoAlias(input) {
|
|
131
|
-
const trimmedTab = input.tabName?.trim();
|
|
132
|
-
if (trimmedTab &&
|
|
133
|
-
!isGenericShellName(trimmedTab) &&
|
|
134
|
-
!looksLikeClaudeAutoTitle(trimmedTab)) {
|
|
135
|
-
return trimmedTab;
|
|
136
|
-
}
|
|
137
|
-
if (!input.origin)
|
|
138
|
-
return null;
|
|
139
|
-
const parts = [input.origin.label];
|
|
140
|
-
if (input.cwd) {
|
|
141
|
-
// basename drops trailing slashes and returns the last path segment —
|
|
142
|
-
// `/Users/me/code/api/` → `api`.
|
|
143
|
-
const dir = basename(input.cwd.replace(/\/+$/, ''));
|
|
144
|
-
if (dir)
|
|
145
|
-
parts.push(dir);
|
|
146
|
-
}
|
|
147
|
-
if (input.gitBranch)
|
|
148
|
-
parts.push(input.gitBranch);
|
|
149
|
-
return parts.join(' · ');
|
|
150
|
-
}
|
|
151
|
-
function readSessionMeta(sessionId) {
|
|
152
|
-
try {
|
|
153
|
-
const row = getDb()
|
|
154
|
-
.prepare('SELECT cwd, git_branch FROM sessions WHERE id = ?')
|
|
155
|
-
.get(sessionId);
|
|
156
|
-
return row ?? null;
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Best-effort auto-alias attempt. Idempotent: if the session already has an
|
|
164
|
-
* alias, or if we can't figure out which terminal owned it, we do nothing.
|
|
165
|
-
*
|
|
166
|
-
* Link strategies, in priority order:
|
|
167
|
-
*
|
|
168
|
-
* 1. **Pending claude-start (deterministic).** The VS Code extension fires
|
|
169
|
-
* `onDidStartTerminalShellExecution` when the user types `claude` in a
|
|
170
|
-
* terminal and POSTs (shell_pid, tab_name, cwd, started_at) to the
|
|
171
|
-
* daemon. If a fresh entry exists for this session's cwd, link directly
|
|
172
|
-
* to that shell_pid — no lsof, no ppid walk. This path covers ~99% of
|
|
173
|
-
* real launches.
|
|
174
|
-
* 2. **Process-tree (lsof + ppid walk).** Legacy fallback for non-VS-Code
|
|
175
|
-
* terminals or VS Code without shell integration. Walks up to 4
|
|
176
|
-
* ancestors of the lsof writer.
|
|
177
|
-
* 3. **CWD-newest.** Final fallback: pick the newest registered terminal in
|
|
178
|
-
* the same cwd. Loose, but lets renames propagate later.
|
|
179
|
-
*/
|
|
180
|
-
export async function tryAutoAlias(filePath) {
|
|
181
|
-
const sessionId = basename(filePath, '.jsonl');
|
|
182
|
-
if (getAlias(sessionId))
|
|
183
|
-
return;
|
|
184
|
-
// Read session meta first — both the pending-match check and the cwd
|
|
185
|
-
// fallback need it.
|
|
186
|
-
const meta = readSessionMeta(sessionId);
|
|
187
|
-
let entry = null;
|
|
188
|
-
let matchedPid = null;
|
|
189
|
-
let matchStrategy = null;
|
|
190
|
-
// Strategy 1 — deterministic. The extension already told us which shell
|
|
191
|
-
// is about to spawn this session.
|
|
192
|
-
const pending = terminalRegistry.takePending(meta?.cwd ?? null, 30_000);
|
|
193
|
-
if (pending) {
|
|
194
|
-
matchedPid = pending.shell_pid;
|
|
195
|
-
matchStrategy = 'pending';
|
|
196
|
-
// Prefer the live registry entry (the extension's poll loop keeps it up
|
|
197
|
-
// to date with the latest user-set tab name). Fall back to a synthetic
|
|
198
|
-
// entry built from the pending payload itself when the registry hasn't
|
|
199
|
-
// seen this pid yet — short-lived terminals can fire claude-started
|
|
200
|
-
// before the next sync tick.
|
|
201
|
-
const live = terminalRegistry.get(pending.shell_pid);
|
|
202
|
-
entry =
|
|
203
|
-
live ?? {
|
|
204
|
-
shell_pid: pending.shell_pid,
|
|
205
|
-
tab_name: pending.tab_name,
|
|
206
|
-
cwd: pending.cwd,
|
|
207
|
-
opened_at: pending.started_at,
|
|
208
|
-
last_seen_at: pending.started_at,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
// Best-effort writerPid + origin lookup — runs regardless of which link
|
|
212
|
-
// strategy wins, so the editor badge gets populated even when we already
|
|
213
|
-
// know the shell pid.
|
|
214
|
-
const writerPid = await writerPidFor(filePath);
|
|
215
|
-
const origin = writerPid ? await detectEditorOrigin(writerPid) : null;
|
|
216
|
-
if (origin)
|
|
217
|
-
terminalRegistry.setOrigin(sessionId, origin);
|
|
218
|
-
// Strategy 2 — process-tree fallback. Only fires when the deterministic
|
|
219
|
-
// path didn't match.
|
|
220
|
-
if (!entry && writerPid) {
|
|
221
|
-
let currentPid = writerPid;
|
|
222
|
-
for (let hop = 0; hop < 4 && currentPid != null; hop++) {
|
|
223
|
-
const nextPid = await parentPidOf(currentPid);
|
|
224
|
-
if (!nextPid)
|
|
225
|
-
break;
|
|
226
|
-
const candidate = terminalRegistry.get(nextPid);
|
|
227
|
-
if (candidate) {
|
|
228
|
-
entry = candidate;
|
|
229
|
-
matchedPid = nextPid;
|
|
230
|
-
matchStrategy = 'ppid';
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
currentPid = nextPid;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
// Strategy 3 — cwd-newest. Loose match, but at least we can propagate
|
|
237
|
-
// future renames. Skip if we already won via pending or ppid.
|
|
238
|
-
if (!entry && meta?.cwd) {
|
|
239
|
-
const sessionCwd = meta.cwd.replace(/\/+$/, '');
|
|
240
|
-
const sameCwd = terminalRegistry
|
|
241
|
-
.all()
|
|
242
|
-
.filter((t) => t.cwd && t.cwd.replace(/\/+$/, '') === sessionCwd);
|
|
243
|
-
if (sameCwd.length > 0) {
|
|
244
|
-
const newest = sameCwd.sort((a, b) => Date.parse(b.opened_at) - Date.parse(a.opened_at))[0];
|
|
245
|
-
entry = newest;
|
|
246
|
-
matchedPid = newest.shell_pid;
|
|
247
|
-
matchStrategy = 'cwd';
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
// Name resolution order (initial alias only — the LINK to matchedPid is
|
|
251
|
-
// already set, so future renames propagate regardless of which name we
|
|
252
|
-
// pick now):
|
|
253
|
-
// 1. If matched terminal has a clean name: use it.
|
|
254
|
-
// 2. Else if matched terminal has a claude auto-title we can strip
|
|
255
|
-
// (e.g. "✳ Claude Code" → "Claude Code"): use the stripped version.
|
|
256
|
-
// 3. Else, ONLY for non-deterministic strategies (ppid / cwd), look for
|
|
257
|
-
// a clean name on a sibling terminal in the same cwd. The
|
|
258
|
-
// deterministic path REFUSES sibling fallback — that's exactly the
|
|
259
|
-
// "session inherited a sibling's name" bug we set out to fix.
|
|
260
|
-
// 4. Else the origin-based composition takes over in composeAutoAlias.
|
|
261
|
-
let resolvedTabName = null;
|
|
262
|
-
if (entry?.tab_name &&
|
|
263
|
-
!isGenericShellName(entry.tab_name) &&
|
|
264
|
-
!looksLikeClaudeAutoTitle(entry.tab_name)) {
|
|
265
|
-
resolvedTabName = entry.tab_name;
|
|
266
|
-
}
|
|
267
|
-
else if (entry?.tab_name && looksLikeClaudeAutoTitle(entry.tab_name)) {
|
|
268
|
-
const stripped = stripAutoTitlePrefix(entry.tab_name);
|
|
269
|
-
if (stripped && !isGenericShellName(stripped))
|
|
270
|
-
resolvedTabName = stripped;
|
|
271
|
-
}
|
|
272
|
-
if (!resolvedTabName && matchStrategy !== 'pending' && meta?.cwd) {
|
|
273
|
-
const sessionCwd = meta.cwd.replace(/\/+$/, '');
|
|
274
|
-
const alternative = terminalRegistry
|
|
275
|
-
.all()
|
|
276
|
-
.filter((t) => t.shell_pid !== matchedPid &&
|
|
277
|
-
t.cwd &&
|
|
278
|
-
t.cwd.replace(/\/+$/, '') === sessionCwd &&
|
|
279
|
-
!isGenericShellName(t.tab_name) &&
|
|
280
|
-
!looksLikeClaudeAutoTitle(t.tab_name))
|
|
281
|
-
.sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at))[0];
|
|
282
|
-
if (alternative)
|
|
283
|
-
resolvedTabName = alternative.tab_name;
|
|
284
|
-
}
|
|
285
|
-
const alias = composeAutoAlias({
|
|
286
|
-
tabName: resolvedTabName,
|
|
287
|
-
origin,
|
|
288
|
-
cwd: meta?.cwd ?? null,
|
|
289
|
-
gitBranch: meta?.git_branch ?? null,
|
|
290
|
-
});
|
|
291
|
-
if (!alias)
|
|
292
|
-
return;
|
|
293
|
-
try {
|
|
294
|
-
setAlias(sessionId, alias);
|
|
295
|
-
const usedTabName = !!resolvedTabName &&
|
|
296
|
-
!isGenericShellName(resolvedTabName) &&
|
|
297
|
-
!looksLikeClaudeAutoTitle(resolvedTabName) &&
|
|
298
|
-
alias === resolvedTabName.trim();
|
|
299
|
-
// Always link the session to its originating shell pid — even if we
|
|
300
|
-
// fell back to the origin label. A later terminal rename should still
|
|
301
|
-
// propagate to this session's alias.
|
|
302
|
-
if (matchedPid != null) {
|
|
303
|
-
terminalRegistry.linkSession(sessionId, matchedPid);
|
|
304
|
-
}
|
|
305
|
-
const matchTag = matchStrategy === 'pending' ? 'pending-claude-start match' : matchStrategy ?? 'unknown';
|
|
306
|
-
// eslint-disable-next-line no-console
|
|
307
|
-
console.log(`[correlator] auto-aliased ${sessionId.slice(0, 8)} → "${alias}"` +
|
|
308
|
-
(usedTabName
|
|
309
|
-
? ` (tab name via ${matchTag}, shell pid ${matchedPid})`
|
|
310
|
-
: entry
|
|
311
|
-
? ` (generic shell name "${entry.tab_name}" → ${origin?.editor ?? 'origin'} fallback, shell pid ${matchedPid})`
|
|
312
|
-
: origin
|
|
313
|
-
? ` (${origin.editor} origin — no terminal match)`
|
|
314
|
-
: ''));
|
|
315
|
-
}
|
|
316
|
-
catch {
|
|
317
|
-
/* non-fatal */
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
//# sourceMappingURL=correlator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/daemon/correlator.ts"],"names":[],"mappings":"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"}
|