@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.
Files changed (218) hide show
  1. package/LICENSE +37 -17
  2. package/README.md +110 -22
  3. package/dist/cli.js +1641 -353
  4. package/dist/daemon/entrypoint.js +1872 -54
  5. package/dist/mcp-server.js +930 -0
  6. package/dist/share/fonts/Inter-Bold.woff +0 -0
  7. package/dist/share/fonts/Inter-Regular.woff +0 -0
  8. package/dist/share/fonts/JetBrainsMono-Regular.woff +0 -0
  9. package/dist/web/assets/_brand-Bw9uSB4O.js +1 -0
  10. package/dist/web/assets/captureNode-9CVj9vYC.js +2 -0
  11. package/dist/web/assets/card-a-minimal-ujNERzX7.js +1 -0
  12. package/dist/web/assets/card-b-terminal-DpJ_tVpg.js +1 -0
  13. package/dist/web/assets/card-c-gradient-CZXVGuNd.js +1 -0
  14. package/dist/web/assets/card-d-dashboard-CHKD-PnB.js +1 -0
  15. package/dist/web/assets/dist-CWaokT35.js +56 -0
  16. package/dist/web/assets/index-B-HrjaDy.css +1 -0
  17. package/dist/web/assets/index-BZYcD76T.js +633 -0
  18. package/dist/web/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
  19. package/dist/web/assets/patterns-BPeZb9N0.js +1 -0
  20. package/dist/web/assets/stats-BSwqSiFU.js +1 -0
  21. package/dist/web/assets/thread-D2AXyhOx.js +1 -0
  22. package/dist/web/index.html +8 -2
  23. package/package.json +58 -18
  24. package/scripts/postinstall.mjs +38 -0
  25. package/dist/cli.js.map +0 -1
  26. package/dist/commands/activate.js +0 -69
  27. package/dist/commands/activate.js.map +0 -1
  28. package/dist/commands/audit-secrets.js +0 -103
  29. package/dist/commands/audit-secrets.js.map +0 -1
  30. package/dist/commands/blame.js +0 -35
  31. package/dist/commands/blame.js.map +0 -1
  32. package/dist/commands/config-verification.js +0 -18
  33. package/dist/commands/config-verification.js.map +0 -1
  34. package/dist/commands/context.js +0 -144
  35. package/dist/commands/context.js.map +0 -1
  36. package/dist/commands/correlate.js +0 -70
  37. package/dist/commands/correlate.js.map +0 -1
  38. package/dist/commands/digest.js +0 -78
  39. package/dist/commands/digest.js.map +0 -1
  40. package/dist/commands/health.js +0 -62
  41. package/dist/commands/health.js.map +0 -1
  42. package/dist/commands/index.js +0 -247
  43. package/dist/commands/index.js.map +0 -1
  44. package/dist/commands/install-extension.js +0 -138
  45. package/dist/commands/install-extension.js.map +0 -1
  46. package/dist/commands/license.js +0 -39
  47. package/dist/commands/license.js.map +0 -1
  48. package/dist/commands/list.js +0 -47
  49. package/dist/commands/list.js.map +0 -1
  50. package/dist/commands/mcp.js +0 -29
  51. package/dist/commands/mcp.js.map +0 -1
  52. package/dist/commands/open.js +0 -28
  53. package/dist/commands/open.js.map +0 -1
  54. package/dist/commands/paste.js +0 -154
  55. package/dist/commands/paste.js.map +0 -1
  56. package/dist/commands/projects.js +0 -36
  57. package/dist/commands/projects.js.map +0 -1
  58. package/dist/commands/search.js +0 -67
  59. package/dist/commands/search.js.map +0 -1
  60. package/dist/commands/semantic.js +0 -173
  61. package/dist/commands/semantic.js.map +0 -1
  62. package/dist/commands/show.js +0 -121
  63. package/dist/commands/show.js.map +0 -1
  64. package/dist/commands/start.js +0 -47
  65. package/dist/commands/start.js.map +0 -1
  66. package/dist/commands/stats.js +0 -133
  67. package/dist/commands/stats.js.map +0 -1
  68. package/dist/commands/status.js +0 -45
  69. package/dist/commands/status.js.map +0 -1
  70. package/dist/commands/stop.js +0 -29
  71. package/dist/commands/stop.js.map +0 -1
  72. package/dist/commands/thread.js +0 -396
  73. package/dist/commands/thread.js.map +0 -1
  74. package/dist/context/formatter.js +0 -103
  75. package/dist/context/formatter.js.map +0 -1
  76. package/dist/daemon/auto-tag-config.js +0 -103
  77. package/dist/daemon/auto-tag-config.js.map +0 -1
  78. package/dist/daemon/auto-tag-config.test.js +0 -72
  79. package/dist/daemon/auto-tag-config.test.js.map +0 -1
  80. package/dist/daemon/auto-title-config.js +0 -70
  81. package/dist/daemon/auto-title-config.js.map +0 -1
  82. package/dist/daemon/bulk-title-jobs.js +0 -170
  83. package/dist/daemon/bulk-title-jobs.js.map +0 -1
  84. package/dist/daemon/correlator.js +0 -320
  85. package/dist/daemon/correlator.js.map +0 -1
  86. package/dist/daemon/discover.js +0 -316
  87. package/dist/daemon/discover.js.map +0 -1
  88. package/dist/daemon/editor-detection.js +0 -186
  89. package/dist/daemon/editor-detection.js.map +0 -1
  90. package/dist/daemon/entrypoint.js.map +0 -1
  91. package/dist/daemon/git-correlator.js +0 -256
  92. package/dist/daemon/git-correlator.js.map +0 -1
  93. package/dist/daemon/mcp-installer.js +0 -108
  94. package/dist/daemon/mcp-installer.js.map +0 -1
  95. package/dist/daemon/onboarding-state.js +0 -140
  96. package/dist/daemon/onboarding-state.js.map +0 -1
  97. package/dist/daemon/pidfile.js +0 -57
  98. package/dist/daemon/pidfile.js.map +0 -1
  99. package/dist/daemon/ports.js +0 -48
  100. package/dist/daemon/ports.js.map +0 -1
  101. package/dist/daemon/scanProgressRegistry.js +0 -62
  102. package/dist/daemon/scanProgressRegistry.js.map +0 -1
  103. package/dist/daemon/server.js +0 -2010
  104. package/dist/daemon/server.js.map +0 -1
  105. package/dist/daemon/tag-scanner/anthropic-client.js +0 -40
  106. package/dist/daemon/tag-scanner/anthropic-client.js.map +0 -1
  107. package/dist/daemon/tag-scanner/autopilot.js +0 -131
  108. package/dist/daemon/tag-scanner/autopilot.js.map +0 -1
  109. package/dist/daemon/tag-scanner/claude-cli-driver.js +0 -250
  110. package/dist/daemon/tag-scanner/claude-cli-driver.js.map +0 -1
  111. package/dist/daemon/tag-scanner/orchestrator.js +0 -88
  112. package/dist/daemon/tag-scanner/orchestrator.js.map +0 -1
  113. package/dist/daemon/tag-scanner/prompt.js +0 -46
  114. package/dist/daemon/tag-scanner/prompt.js.map +0 -1
  115. package/dist/daemon/tag-scanner/prompt.test.js +0 -48
  116. package/dist/daemon/tag-scanner/prompt.test.js.map +0 -1
  117. package/dist/daemon/tag-scanner/scan-state.js +0 -49
  118. package/dist/daemon/tag-scanner/scan-state.js.map +0 -1
  119. package/dist/daemon/tag-scanner/session-fetcher.js +0 -82
  120. package/dist/daemon/tag-scanner/session-fetcher.js.map +0 -1
  121. package/dist/daemon/tag-scanner/session-fetcher.test.js +0 -34
  122. package/dist/daemon/tag-scanner/session-fetcher.test.js.map +0 -1
  123. package/dist/daemon/tag-scanner/validator.js +0 -50
  124. package/dist/daemon/tag-scanner/validator.js.map +0 -1
  125. package/dist/daemon/tag-scanner/validator.test.js +0 -41
  126. package/dist/daemon/tag-scanner/validator.test.js.map +0 -1
  127. package/dist/daemon/terminal-registry.js +0 -443
  128. package/dist/daemon/terminal-registry.js.map +0 -1
  129. package/dist/daemon/ui.js +0 -64
  130. package/dist/daemon/ui.js.map +0 -1
  131. package/dist/daemon/watcher.js +0 -256
  132. package/dist/daemon/watcher.js.map +0 -1
  133. package/dist/db/client.js +0 -22
  134. package/dist/db/client.js.map +0 -1
  135. package/dist/db/schema.js +0 -496
  136. package/dist/db/schema.js.map +0 -1
  137. package/dist/license/api-base.js +0 -13
  138. package/dist/license/api-base.js.map +0 -1
  139. package/dist/license/manager.js +0 -43
  140. package/dist/license/manager.js.map +0 -1
  141. package/dist/license/public-key.js +0 -19
  142. package/dist/license/public-key.js.map +0 -1
  143. package/dist/license/storage.js +0 -27
  144. package/dist/license/storage.js.map +0 -1
  145. package/dist/license/verify.js +0 -23
  146. package/dist/license/verify.js.map +0 -1
  147. package/dist/mcp/audit.js +0 -126
  148. package/dist/mcp/audit.js.map +0 -1
  149. package/dist/mcp/prompts.js +0 -180
  150. package/dist/mcp/prompts.js.map +0 -1
  151. package/dist/mcp/server.js +0 -502
  152. package/dist/mcp/server.js.map +0 -1
  153. package/dist/mcp/thread-tools.js +0 -363
  154. package/dist/mcp/thread-tools.js.map +0 -1
  155. package/dist/mcp/write-tools.js +0 -239
  156. package/dist/mcp/write-tools.js.map +0 -1
  157. package/dist/parser/jsonl.js +0 -150
  158. package/dist/parser/jsonl.js.map +0 -1
  159. package/dist/semantic/chunker.js +0 -47
  160. package/dist/semantic/chunker.js.map +0 -1
  161. package/dist/semantic/config.js +0 -74
  162. package/dist/semantic/config.js.map +0 -1
  163. package/dist/semantic/embedder.js +0 -54
  164. package/dist/semantic/embedder.js.map +0 -1
  165. package/dist/semantic/fusion.js +0 -38
  166. package/dist/semantic/fusion.js.map +0 -1
  167. package/dist/semantic/model-download.js +0 -69
  168. package/dist/semantic/model-download.js.map +0 -1
  169. package/dist/semantic/pipeline.js +0 -375
  170. package/dist/semantic/pipeline.js.map +0 -1
  171. package/dist/semantic/query.js +0 -42
  172. package/dist/semantic/query.js.map +0 -1
  173. package/dist/semantic/worker.js +0 -78
  174. package/dist/semantic/worker.js.map +0 -1
  175. package/dist/stats/backfill.js +0 -151
  176. package/dist/stats/backfill.js.map +0 -1
  177. package/dist/stats/health.js +0 -102
  178. package/dist/stats/health.js.map +0 -1
  179. package/dist/stats/query.js +0 -385
  180. package/dist/stats/query.js.map +0 -1
  181. package/dist/utils/aliases.js +0 -107
  182. package/dist/utils/aliases.js.map +0 -1
  183. package/dist/utils/autoCollections.js +0 -635
  184. package/dist/utils/autoCollections.js.map +0 -1
  185. package/dist/utils/autoTitle.js +0 -348
  186. package/dist/utils/autoTitle.js.map +0 -1
  187. package/dist/utils/collections.js +0 -446
  188. package/dist/utils/collections.js.map +0 -1
  189. package/dist/utils/format.js +0 -46
  190. package/dist/utils/format.js.map +0 -1
  191. package/dist/utils/notes.js +0 -270
  192. package/dist/utils/notes.js.map +0 -1
  193. package/dist/utils/paths.js +0 -50
  194. package/dist/utils/paths.js.map +0 -1
  195. package/dist/utils/pricing.js +0 -257
  196. package/dist/utils/pricing.js.map +0 -1
  197. package/dist/utils/secret-scanner.js +0 -166
  198. package/dist/utils/secret-scanner.js.map +0 -1
  199. package/dist/utils/sessionLabel.js +0 -64
  200. package/dist/utils/sessionLabel.js.map +0 -1
  201. package/dist/utils/tags.js +0 -97
  202. package/dist/utils/tags.js.map +0 -1
  203. package/dist/utils/thread-context.js +0 -129
  204. package/dist/utils/thread-context.js.map +0 -1
  205. package/dist/utils/threadFilter.js +0 -18
  206. package/dist/utils/threadFilter.js.map +0 -1
  207. package/dist/utils/threads-titler.js +0 -298
  208. package/dist/utils/threads-titler.js.map +0 -1
  209. package/dist/utils/threads.js +0 -383
  210. package/dist/utils/threads.js.map +0 -1
  211. package/dist/utils/usage.js +0 -76
  212. package/dist/utils/usage.js.map +0 -1
  213. package/dist/verification/compute.js +0 -88
  214. package/dist/verification/compute.js.map +0 -1
  215. package/dist/verification/config.js +0 -34
  216. package/dist/verification/config.js.map +0 -1
  217. package/dist/web/assets/index-CIr6J4Fw.js +0 -1201
  218. 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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"}