@vibelet/cli 0.1.37 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/README.md +80 -0
  2. package/bin/cloudflared-quick-tunnel.mjs +11 -0
  3. package/bin/cloudflared-resolver.mjs +171 -0
  4. package/bin/vibelet-runtime-policy.mjs +36 -0
  5. package/bin/vibelet.cjs +12 -0
  6. package/bin/vibelet.mjs +1062 -0
  7. package/dist/index.cjs +126 -0
  8. package/package.json +25 -24
  9. package/app.json +0 -5
  10. package/dist/advertised-hosts.d.ts +0 -34
  11. package/dist/advertised-hosts.d.ts.map +0 -1
  12. package/dist/advertised-hosts.js +0 -176
  13. package/dist/advertised-hosts.js.map +0 -1
  14. package/dist/advertised-hosts.test.d.ts +0 -2
  15. package/dist/advertised-hosts.test.d.ts.map +0 -1
  16. package/dist/advertised-hosts.test.js +0 -96
  17. package/dist/advertised-hosts.test.js.map +0 -1
  18. package/dist/audit.d.ts +0 -30
  19. package/dist/audit.d.ts.map +0 -1
  20. package/dist/audit.js +0 -73
  21. package/dist/audit.js.map +0 -1
  22. package/dist/audit.test.d.ts +0 -2
  23. package/dist/audit.test.d.ts.map +0 -1
  24. package/dist/audit.test.js +0 -33
  25. package/dist/audit.test.js.map +0 -1
  26. package/dist/auth.d.ts +0 -6
  27. package/dist/auth.d.ts.map +0 -1
  28. package/dist/auth.js +0 -27
  29. package/dist/auth.js.map +0 -1
  30. package/dist/claude-hooks.d.ts +0 -58
  31. package/dist/claude-hooks.d.ts.map +0 -1
  32. package/dist/claude-hooks.js +0 -129
  33. package/dist/claude-hooks.js.map +0 -1
  34. package/dist/cli-version.d.ts +0 -3
  35. package/dist/cli-version.d.ts.map +0 -1
  36. package/dist/cli-version.js +0 -35
  37. package/dist/cli-version.js.map +0 -1
  38. package/dist/cli-version.test.d.ts +0 -2
  39. package/dist/cli-version.test.d.ts.map +0 -1
  40. package/dist/cli-version.test.js +0 -38
  41. package/dist/cli-version.test.js.map +0 -1
  42. package/dist/config.d.ts +0 -30
  43. package/dist/config.d.ts.map +0 -1
  44. package/dist/config.js +0 -327
  45. package/dist/config.js.map +0 -1
  46. package/dist/config.test.d.ts +0 -2
  47. package/dist/config.test.d.ts.map +0 -1
  48. package/dist/config.test.js +0 -184
  49. package/dist/config.test.js.map +0 -1
  50. package/dist/dev-auth.test.d.ts +0 -2
  51. package/dist/dev-auth.test.d.ts.map +0 -1
  52. package/dist/dev-auth.test.js +0 -154
  53. package/dist/dev-auth.test.js.map +0 -1
  54. package/dist/dev-script.test.d.ts +0 -2
  55. package/dist/dev-script.test.d.ts.map +0 -1
  56. package/dist/dev-script.test.js +0 -412
  57. package/dist/dev-script.test.js.map +0 -1
  58. package/dist/drivers/claude.d.ts +0 -34
  59. package/dist/drivers/claude.d.ts.map +0 -1
  60. package/dist/drivers/claude.js +0 -413
  61. package/dist/drivers/claude.js.map +0 -1
  62. package/dist/drivers/claude.test.d.ts +0 -2
  63. package/dist/drivers/claude.test.d.ts.map +0 -1
  64. package/dist/drivers/claude.test.js +0 -951
  65. package/dist/drivers/claude.test.js.map +0 -1
  66. package/dist/drivers/codex.d.ts +0 -38
  67. package/dist/drivers/codex.d.ts.map +0 -1
  68. package/dist/drivers/codex.js +0 -771
  69. package/dist/drivers/codex.js.map +0 -1
  70. package/dist/drivers/codex.test.d.ts +0 -2
  71. package/dist/drivers/codex.test.d.ts.map +0 -1
  72. package/dist/drivers/codex.test.js +0 -939
  73. package/dist/drivers/codex.test.js.map +0 -1
  74. package/dist/drivers/types.d.ts +0 -14
  75. package/dist/drivers/types.d.ts.map +0 -1
  76. package/dist/drivers/types.js +0 -2
  77. package/dist/drivers/types.js.map +0 -1
  78. package/dist/e2e.test.d.ts +0 -2
  79. package/dist/e2e.test.d.ts.map +0 -1
  80. package/dist/e2e.test.js +0 -111
  81. package/dist/e2e.test.js.map +0 -1
  82. package/dist/identity.d.ts +0 -10
  83. package/dist/identity.d.ts.map +0 -1
  84. package/dist/identity.js +0 -66
  85. package/dist/identity.js.map +0 -1
  86. package/dist/identity.test.d.ts +0 -2
  87. package/dist/identity.test.d.ts.map +0 -1
  88. package/dist/identity.test.js +0 -25
  89. package/dist/identity.test.js.map +0 -1
  90. package/dist/index-entry.test.d.ts +0 -2
  91. package/dist/index-entry.test.d.ts.map +0 -1
  92. package/dist/index-entry.test.js +0 -272
  93. package/dist/index-entry.test.js.map +0 -1
  94. package/dist/index.d.ts +0 -2
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js +0 -707
  97. package/dist/index.js.map +0 -1
  98. package/dist/logger.d.ts +0 -31
  99. package/dist/logger.d.ts.map +0 -1
  100. package/dist/logger.js +0 -75
  101. package/dist/logger.js.map +0 -1
  102. package/dist/metrics.d.ts +0 -52
  103. package/dist/metrics.d.ts.map +0 -1
  104. package/dist/metrics.js +0 -89
  105. package/dist/metrics.js.map +0 -1
  106. package/dist/pairing-store.d.ts +0 -29
  107. package/dist/pairing-store.d.ts.map +0 -1
  108. package/dist/pairing-store.js +0 -131
  109. package/dist/pairing-store.js.map +0 -1
  110. package/dist/pairing-store.test.d.ts +0 -2
  111. package/dist/pairing-store.test.d.ts.map +0 -1
  112. package/dist/pairing-store.test.js +0 -47
  113. package/dist/pairing-store.test.js.map +0 -1
  114. package/dist/paths.d.ts +0 -16
  115. package/dist/paths.d.ts.map +0 -1
  116. package/dist/paths.js +0 -18
  117. package/dist/paths.js.map +0 -1
  118. package/dist/perf-compare.d.ts +0 -13
  119. package/dist/perf-compare.d.ts.map +0 -1
  120. package/dist/perf-compare.js +0 -125
  121. package/dist/perf-compare.js.map +0 -1
  122. package/dist/port-conflict.d.ts +0 -9
  123. package/dist/port-conflict.d.ts.map +0 -1
  124. package/dist/port-conflict.js +0 -33
  125. package/dist/port-conflict.js.map +0 -1
  126. package/dist/port-conflict.test.d.ts +0 -2
  127. package/dist/port-conflict.test.d.ts.map +0 -1
  128. package/dist/port-conflict.test.js +0 -38
  129. package/dist/port-conflict.test.js.map +0 -1
  130. package/dist/process-scanner.d.ts +0 -43
  131. package/dist/process-scanner.d.ts.map +0 -1
  132. package/dist/process-scanner.js +0 -453
  133. package/dist/process-scanner.js.map +0 -1
  134. package/dist/process-scanner.perf.test.d.ts +0 -2
  135. package/dist/process-scanner.perf.test.d.ts.map +0 -1
  136. package/dist/process-scanner.perf.test.js +0 -186
  137. package/dist/process-scanner.perf.test.js.map +0 -1
  138. package/dist/process-scanner.test.d.ts +0 -2
  139. package/dist/process-scanner.test.d.ts.map +0 -1
  140. package/dist/process-scanner.test.js +0 -399
  141. package/dist/process-scanner.test.js.map +0 -1
  142. package/dist/push-protocol.d.ts +0 -15
  143. package/dist/push-protocol.d.ts.map +0 -1
  144. package/dist/push-protocol.js +0 -23
  145. package/dist/push-protocol.js.map +0 -1
  146. package/dist/push-protocol.test.d.ts +0 -2
  147. package/dist/push-protocol.test.d.ts.map +0 -1
  148. package/dist/push-protocol.test.js +0 -57
  149. package/dist/push-protocol.test.js.map +0 -1
  150. package/dist/push-store.d.ts +0 -22
  151. package/dist/push-store.d.ts.map +0 -1
  152. package/dist/push-store.js +0 -103
  153. package/dist/push-store.js.map +0 -1
  154. package/dist/push-store.test.d.ts +0 -2
  155. package/dist/push-store.test.d.ts.map +0 -1
  156. package/dist/push-store.test.js +0 -79
  157. package/dist/push-store.test.js.map +0 -1
  158. package/dist/push.d.ts +0 -65
  159. package/dist/push.d.ts.map +0 -1
  160. package/dist/push.js +0 -202
  161. package/dist/push.js.map +0 -1
  162. package/dist/push.test.d.ts +0 -2
  163. package/dist/push.test.d.ts.map +0 -1
  164. package/dist/push.test.js +0 -199
  165. package/dist/push.test.js.map +0 -1
  166. package/dist/safe-stdio.d.ts +0 -3
  167. package/dist/safe-stdio.d.ts.map +0 -1
  168. package/dist/safe-stdio.js +0 -46
  169. package/dist/safe-stdio.js.map +0 -1
  170. package/dist/scanner.d.ts +0 -30
  171. package/dist/scanner.d.ts.map +0 -1
  172. package/dist/scanner.js +0 -859
  173. package/dist/scanner.js.map +0 -1
  174. package/dist/scanner.perf.test.d.ts +0 -2
  175. package/dist/scanner.perf.test.d.ts.map +0 -1
  176. package/dist/scanner.perf.test.js +0 -320
  177. package/dist/scanner.perf.test.js.map +0 -1
  178. package/dist/scanner.test.d.ts +0 -2
  179. package/dist/scanner.test.d.ts.map +0 -1
  180. package/dist/scanner.test.js +0 -948
  181. package/dist/scanner.test.js.map +0 -1
  182. package/dist/session-inventory.d.ts +0 -63
  183. package/dist/session-inventory.d.ts.map +0 -1
  184. package/dist/session-inventory.js +0 -525
  185. package/dist/session-inventory.js.map +0 -1
  186. package/dist/session-inventory.perf.test.d.ts +0 -2
  187. package/dist/session-inventory.perf.test.d.ts.map +0 -1
  188. package/dist/session-inventory.perf.test.js +0 -220
  189. package/dist/session-inventory.perf.test.js.map +0 -1
  190. package/dist/session-inventory.test.d.ts +0 -2
  191. package/dist/session-inventory.test.d.ts.map +0 -1
  192. package/dist/session-inventory.test.js +0 -712
  193. package/dist/session-inventory.test.js.map +0 -1
  194. package/dist/session-manager.d.ts +0 -75
  195. package/dist/session-manager.d.ts.map +0 -1
  196. package/dist/session-manager.js +0 -1515
  197. package/dist/session-manager.js.map +0 -1
  198. package/dist/session-manager.test.d.ts +0 -2
  199. package/dist/session-manager.test.d.ts.map +0 -1
  200. package/dist/session-manager.test.js +0 -2861
  201. package/dist/session-manager.test.js.map +0 -1
  202. package/dist/session-store.d.ts +0 -42
  203. package/dist/session-store.d.ts.map +0 -1
  204. package/dist/session-store.js +0 -163
  205. package/dist/session-store.js.map +0 -1
  206. package/dist/session-store.test.d.ts +0 -2
  207. package/dist/session-store.test.d.ts.map +0 -1
  208. package/dist/session-store.test.js +0 -236
  209. package/dist/session-store.test.js.map +0 -1
  210. package/dist/session-title.d.ts +0 -6
  211. package/dist/session-title.d.ts.map +0 -1
  212. package/dist/session-title.js +0 -105
  213. package/dist/session-title.js.map +0 -1
  214. package/dist/session-title.perf.test.d.ts +0 -2
  215. package/dist/session-title.perf.test.d.ts.map +0 -1
  216. package/dist/session-title.perf.test.js +0 -99
  217. package/dist/session-title.perf.test.js.map +0 -1
  218. package/dist/session-title.test.d.ts +0 -2
  219. package/dist/session-title.test.d.ts.map +0 -1
  220. package/dist/session-title.test.js +0 -199
  221. package/dist/session-title.test.js.map +0 -1
  222. package/dist/shutdown-endpoint.test.d.ts +0 -2
  223. package/dist/shutdown-endpoint.test.d.ts.map +0 -1
  224. package/dist/shutdown-endpoint.test.js +0 -93
  225. package/dist/shutdown-endpoint.test.js.map +0 -1
  226. package/dist/storage-housekeeping.d.ts +0 -28
  227. package/dist/storage-housekeeping.d.ts.map +0 -1
  228. package/dist/storage-housekeeping.js +0 -76
  229. package/dist/storage-housekeeping.js.map +0 -1
  230. package/dist/storage-housekeeping.test.d.ts +0 -2
  231. package/dist/storage-housekeeping.test.d.ts.map +0 -1
  232. package/dist/storage-housekeeping.test.js +0 -65
  233. package/dist/storage-housekeeping.test.js.map +0 -1
  234. package/dist/test-daemon-harness.d.ts +0 -31
  235. package/dist/test-daemon-harness.d.ts.map +0 -1
  236. package/dist/test-daemon-harness.js +0 -337
  237. package/dist/test-daemon-harness.js.map +0 -1
  238. package/dist/token-auth.test.d.ts +0 -2
  239. package/dist/token-auth.test.d.ts.map +0 -1
  240. package/dist/token-auth.test.js +0 -52
  241. package/dist/token-auth.test.js.map +0 -1
  242. package/dist/utils.d.ts +0 -4
  243. package/dist/utils.d.ts.map +0 -1
  244. package/dist/utils.js +0 -40
  245. package/dist/utils.js.map +0 -1
  246. package/dist/utils.test.d.ts +0 -2
  247. package/dist/utils.test.d.ts.map +0 -1
  248. package/dist/utils.test.js +0 -54
  249. package/dist/utils.test.js.map +0 -1
  250. package/dist/ws-data.d.ts +0 -4
  251. package/dist/ws-data.d.ts.map +0 -1
  252. package/dist/ws-data.js +0 -20
  253. package/dist/ws-data.js.map +0 -1
  254. package/dist/ws-data.test.d.ts +0 -2
  255. package/dist/ws-data.test.d.ts.map +0 -1
  256. package/dist/ws-data.test.js +0 -17
  257. package/dist/ws-data.test.js.map +0 -1
  258. package/perf-reporter.mjs +0 -138
  259. package/scripts/build-release.mjs +0 -41
  260. package/scripts/dev.mjs +0 -537
  261. package/src/advertised-hosts.test.ts +0 -125
  262. package/src/advertised-hosts.ts +0 -225
  263. package/src/audit.test.ts +0 -38
  264. package/src/audit.ts +0 -117
  265. package/src/auth.ts +0 -31
  266. package/src/claude-hooks.ts +0 -195
  267. package/src/cli-version.test.ts +0 -36
  268. package/src/cli-version.ts +0 -46
  269. package/src/config.test.ts +0 -254
  270. package/src/config.ts +0 -324
  271. package/src/dev-auth.test.ts +0 -183
  272. package/src/dev-script.test.ts +0 -511
  273. package/src/drivers/claude.test.ts +0 -1186
  274. package/src/drivers/claude.ts +0 -443
  275. package/src/drivers/codex.test.ts +0 -1096
  276. package/src/drivers/codex.ts +0 -879
  277. package/src/drivers/types.ts +0 -15
  278. package/src/e2e.test.ts +0 -139
  279. package/src/identity.test.ts +0 -26
  280. package/src/identity.ts +0 -82
  281. package/src/index-entry.test.ts +0 -336
  282. package/src/index.ts +0 -781
  283. package/src/logger.ts +0 -112
  284. package/src/metrics.ts +0 -117
  285. package/src/pairing-store.test.ts +0 -53
  286. package/src/pairing-store.ts +0 -154
  287. package/src/paths.ts +0 -19
  288. package/src/perf-compare.ts +0 -164
  289. package/src/port-conflict.test.ts +0 -45
  290. package/src/port-conflict.ts +0 -44
  291. package/src/process-scanner.perf.test.ts +0 -222
  292. package/src/process-scanner.test.ts +0 -575
  293. package/src/process-scanner.ts +0 -514
  294. package/src/push-protocol.test.ts +0 -74
  295. package/src/push-protocol.ts +0 -36
  296. package/src/push-store.test.ts +0 -89
  297. package/src/push-store.ts +0 -126
  298. package/src/push.test.ts +0 -234
  299. package/src/push.ts +0 -318
  300. package/src/safe-stdio.ts +0 -51
  301. package/src/scanner.perf.test.ts +0 -359
  302. package/src/scanner.test.ts +0 -1045
  303. package/src/scanner.ts +0 -924
  304. package/src/session-inventory.perf.test.ts +0 -250
  305. package/src/session-inventory.test.ts +0 -1002
  306. package/src/session-inventory.ts +0 -721
  307. package/src/session-manager.test.ts +0 -3430
  308. package/src/session-manager.ts +0 -1775
  309. package/src/session-store.test.ts +0 -276
  310. package/src/session-store.ts +0 -202
  311. package/src/session-title.perf.test.ts +0 -118
  312. package/src/session-title.test.ts +0 -286
  313. package/src/session-title.ts +0 -108
  314. package/src/shutdown-endpoint.test.ts +0 -95
  315. package/src/storage-housekeeping.test.ts +0 -78
  316. package/src/storage-housekeeping.ts +0 -111
  317. package/src/test-daemon-harness.ts +0 -410
  318. package/src/token-auth.test.ts +0 -67
  319. package/src/utils.test.ts +0 -65
  320. package/src/utils.ts +0 -47
  321. package/src/ws-data.test.ts +0 -20
  322. package/src/ws-data.ts +0 -26
  323. package/tsconfig.json +0 -12
@@ -1,575 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { mkdir, mkdtemp, rm, utimes, writeFile } from 'fs/promises';
4
- import { join } from 'path';
5
- import { tmpdir } from 'os';
6
- import {
7
- classifyProcessSnapshot,
8
- extractExplicitSessionId,
9
- findRecentSessionFileForCwd,
10
- hasContinueFlag,
11
- isRelevantProcessCommand,
12
- isProcessAlive,
13
- mergeRunningSessionCandidates,
14
- type ProcessSnapshot,
15
- type RunningSessionCandidate,
16
- } from './process-scanner.js';
17
-
18
- function snapshot(overrides: Partial<ProcessSnapshot>): ProcessSnapshot {
19
- return {
20
- pid: 1,
21
- agent: 'codex',
22
- command: 'codex --yolo',
23
- cwd: '/repo',
24
- sessionFiles: [],
25
- ...overrides,
26
- };
27
- }
28
-
29
- test('classifies explicit codex resume as high confidence', () => {
30
- const candidate = classifyProcessSnapshot(snapshot({
31
- pid: 6581,
32
- command: 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111',
33
- }));
34
-
35
- assert.deepEqual(candidate, {
36
- agent: 'codex',
37
- pid: 6581,
38
- cwd: '/repo',
39
- command: 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111',
40
- sessionId: '019d03e3-2672-7011-9c6d-5ba083b71111',
41
- confidence: 'high',
42
- });
43
- });
44
-
45
- test('classifies explicit Claude resume with permission flags and keeps approval mode', () => {
46
- const candidate = classifyProcessSnapshot(snapshot({
47
- agent: 'claude',
48
- pid: 6582,
49
- command: 'claude --resume session-1 --permission-mode acceptEdits',
50
- }));
51
-
52
- assert.deepEqual(candidate, {
53
- agent: 'claude',
54
- pid: 6582,
55
- cwd: '/repo',
56
- command: 'claude --resume session-1 --permission-mode acceptEdits',
57
- sessionId: 'session-1',
58
- confidence: 'high',
59
- approvalMode: 'acceptEdits',
60
- });
61
- });
62
-
63
- test('classifies explicit Claude bypass mode from process command', () => {
64
- const candidate = classifyProcessSnapshot(snapshot({
65
- agent: 'claude',
66
- pid: 6583,
67
- command: 'claude --resume session-2 --dangerously-skip-permissions',
68
- }));
69
-
70
- assert.equal(candidate?.approvalMode, 'autoApprove');
71
- });
72
-
73
- test('classifies explicit Claude resume without forcing normal and keeps unique session file for hydration', () => {
74
- const filePath = '/Users/test/.claude/projects/-Users-test-repo/session-3.jsonl';
75
- const candidate = classifyProcessSnapshot(snapshot({
76
- agent: 'claude',
77
- pid: 6584,
78
- command: 'claude --resume session-3',
79
- sessionFiles: [filePath],
80
- }));
81
-
82
- assert.deepEqual(candidate, {
83
- agent: 'claude',
84
- pid: 6584,
85
- cwd: '/repo',
86
- command: 'claude --resume session-3',
87
- sessionId: 'session-3',
88
- confidence: 'high',
89
- sessionFilePath: filePath,
90
- });
91
- });
92
-
93
- test('classifies a single codex rollout file as medium confidence', () => {
94
- const filePath = '/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-37-12-019d08ac-c265-7270-9497-d14125228a50.jsonl';
95
- const candidate = classifyProcessSnapshot(snapshot({
96
- pid: 52424,
97
- sessionFiles: [filePath],
98
- }));
99
-
100
- assert.equal(candidate?.confidence, 'medium');
101
- assert.equal(candidate?.sessionId, '019d08ac-c265-7270-9497-d14125228a50');
102
- assert.equal(candidate?.sessionFilePath, filePath);
103
- });
104
-
105
- test('drops ambiguous app-server processes with multiple session files', () => {
106
- const candidate = classifyProcessSnapshot(snapshot({
107
- command: 'codex app-server',
108
- sessionFiles: [
109
- '/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-37-12-019d08ac-c265-7270-9497-d14125228a50.jsonl',
110
- '/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-42-17-019d08b1-67e6-75a1-bdb6-3c1b25b1103b.jsonl',
111
- ],
112
- }));
113
-
114
- assert.equal(candidate, null);
115
- });
116
-
117
- test('drops claude --continue without a unique session file', () => {
118
- const candidate = classifyProcessSnapshot(snapshot({
119
- agent: 'claude',
120
- command: 'claude --dangerously-skip-permissions --continue',
121
- sessionFiles: [],
122
- }));
123
-
124
- assert.equal(candidate, null);
125
- });
126
-
127
- test('drops claude subagent transcript files', () => {
128
- const candidate = classifyProcessSnapshot(snapshot({
129
- agent: 'claude',
130
- command: 'claude --dangerously-skip-permissions --continue',
131
- sessionFiles: [
132
- '/Users/test/.claude/projects/-Users-test/repo/subagents/agent-aa9cc4dbb140502a8.jsonl',
133
- ],
134
- }));
135
-
136
- assert.equal(candidate, null);
137
- });
138
-
139
- // ===== extractExplicitSessionId =====
140
-
141
- test('extracts claude session id from --resume flag', () => {
142
- assert.equal(
143
- extractExplicitSessionId('claude', 'claude --resume abc-123-def'),
144
- 'abc-123-def',
145
- );
146
- });
147
-
148
- test('extracts claude session id from --resume= syntax', () => {
149
- assert.equal(
150
- extractExplicitSessionId('claude', 'claude --resume=abc-123-def'),
151
- 'abc-123-def',
152
- );
153
- });
154
-
155
- test('returns null for claude without --resume', () => {
156
- assert.equal(
157
- extractExplicitSessionId('claude', 'claude --dangerously-skip-permissions --continue'),
158
- null,
159
- );
160
- });
161
-
162
- test('returns null when --resume has no value', () => {
163
- assert.equal(
164
- extractExplicitSessionId('claude', 'claude --resume --other-flag'),
165
- null,
166
- );
167
- });
168
-
169
- test('extracts codex session id from resume subcommand', () => {
170
- assert.equal(
171
- extractExplicitSessionId('codex', 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111'),
172
- '019d03e3-2672-7011-9c6d-5ba083b71111',
173
- );
174
- });
175
-
176
- test('returns null for codex without resume subcommand', () => {
177
- assert.equal(
178
- extractExplicitSessionId('codex', 'codex --yolo'),
179
- null,
180
- );
181
- });
182
-
183
- test('returns null when agent does not match binary in command', () => {
184
- assert.equal(
185
- extractExplicitSessionId('claude', 'codex resume abc-123'),
186
- null,
187
- );
188
- });
189
-
190
- test('handles quoted tokens in command', () => {
191
- assert.equal(
192
- extractExplicitSessionId('claude', 'claude --resume "my-session-id"'),
193
- 'my-session-id',
194
- );
195
- });
196
-
197
- test('handles full path to binary', () => {
198
- assert.equal(
199
- extractExplicitSessionId('claude', '/usr/local/bin/claude --resume sess-1'),
200
- 'sess-1',
201
- );
202
- });
203
-
204
- test('extracts claude session id from shell-wrapped resume command', () => {
205
- assert.equal(
206
- extractExplicitSessionId('claude', "zsh -lc 'cd /repo && claude --resume sess-1'"),
207
- 'sess-1',
208
- );
209
- });
210
-
211
- test('returns null for empty command', () => {
212
- assert.equal(
213
- extractExplicitSessionId('codex', ''),
214
- null,
215
- );
216
- });
217
-
218
- // ===== relevant process command matching =====
219
-
220
- test('isRelevantProcessCommand matches shell-wrapped claude resume commands', () => {
221
- assert.equal(
222
- isRelevantProcessCommand("zsh -lc 'cd /repo && claude --resume sess-1'"),
223
- true,
224
- );
225
- });
226
-
227
- test('isRelevantProcessCommand ignores binaries that only contain claude as a substring', () => {
228
- assert.equal(
229
- isRelevantProcessCommand("zsh -lc '/usr/local/bin/claude-wrapper --resume sess-1'"),
230
- false,
231
- );
232
- });
233
-
234
- // ===== mergeRunningSessionCandidates (continued) =====
235
-
236
- test('dedupes duplicate running candidates by keeping the higher confidence entry', () => {
237
- const high: RunningSessionCandidate = {
238
- agent: 'codex',
239
- pid: 6581,
240
- cwd: '/repo',
241
- command: 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111',
242
- sessionId: '019d03e3-2672-7011-9c6d-5ba083b71111',
243
- confidence: 'high',
244
- };
245
- const medium: RunningSessionCandidate = {
246
- agent: 'codex',
247
- pid: 72545,
248
- cwd: '/repo',
249
- command: 'codex --yolo',
250
- sessionId: '019d03e3-2672-7011-9c6d-5ba083b71111',
251
- confidence: 'medium',
252
- title: 'Recovered title',
253
- sessionFilePath: '/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-37-12-019d03e3-2672-7011-9c6d-5ba083b71111.jsonl',
254
- isResponding: true,
255
- };
256
-
257
- assert.deepEqual(mergeRunningSessionCandidates([medium, high]), [{
258
- ...high,
259
- title: 'Recovered title',
260
- sessionFilePath: medium.sessionFilePath,
261
- isResponding: true,
262
- }]);
263
- });
264
-
265
- test('mergeRunningSessionCandidates: keeps both when different sessionIds', () => {
266
- const a: RunningSessionCandidate = {
267
- agent: 'codex', pid: 1, cwd: '/repo', command: 'codex',
268
- sessionId: 'aaa', confidence: 'high',
269
- };
270
- const b: RunningSessionCandidate = {
271
- agent: 'codex', pid: 2, cwd: '/repo', command: 'codex',
272
- sessionId: 'bbb', confidence: 'high',
273
- };
274
-
275
- assert.equal(mergeRunningSessionCandidates([a, b]).length, 2);
276
- });
277
-
278
- test('mergeRunningSessionCandidates: returns empty for empty input', () => {
279
- assert.deepEqual(mergeRunningSessionCandidates([]), []);
280
- });
281
-
282
- // ===== classifyProcessSnapshot edge cases =====
283
-
284
- test('classifies claude --resume as high confidence', () => {
285
- const candidate = classifyProcessSnapshot(snapshot({
286
- agent: 'claude',
287
- command: 'claude --resume my-session-id-123',
288
- sessionFiles: [],
289
- }));
290
-
291
- assert.equal(candidate?.confidence, 'high');
292
- assert.equal(candidate?.sessionId, 'my-session-id-123');
293
- });
294
-
295
- test('classifies single claude project file as medium confidence', () => {
296
- const filePath = '/Users/test/.claude/projects/-Users-test-repo/session-abc.jsonl';
297
- const candidate = classifyProcessSnapshot(snapshot({
298
- agent: 'claude',
299
- command: 'claude --dangerously-skip-permissions',
300
- sessionFiles: [filePath],
301
- }));
302
-
303
- assert.equal(candidate?.confidence, 'medium');
304
- assert.equal(candidate?.sessionId, 'session-abc');
305
- });
306
-
307
- test('returns null for process with no session files and no explicit id', () => {
308
- const candidate = classifyProcessSnapshot(snapshot({
309
- command: 'codex app-server',
310
- sessionFiles: [],
311
- }));
312
-
313
- assert.equal(candidate, null);
314
- });
315
-
316
- test('filters out non-supported session file paths', () => {
317
- const candidate = classifyProcessSnapshot(snapshot({
318
- command: 'codex app-server',
319
- sessionFiles: ['/tmp/random.jsonl'],
320
- }));
321
-
322
- assert.equal(candidate, null);
323
- });
324
-
325
- // ===== extractExplicitSessionId edge cases =====
326
-
327
- test('extracts codex resume id skipping flags before session id', () => {
328
- assert.equal(
329
- extractExplicitSessionId('codex', 'codex resume --some-flag session-id-abc'),
330
- 'session-id-abc',
331
- );
332
- });
333
-
334
- test('returns null for codex resume with only flags', () => {
335
- assert.equal(
336
- extractExplicitSessionId('codex', 'codex resume --flag-only'),
337
- null,
338
- );
339
- });
340
-
341
- test('handles single-quoted session id', () => {
342
- assert.equal(
343
- extractExplicitSessionId('claude', "claude --resume 'my-session'"),
344
- 'my-session',
345
- );
346
- });
347
-
348
- // ===== classifyProcessSnapshot edge cases =====
349
-
350
- test('classifies process with single codex session file in supported path', () => {
351
- const filePath = '/Users/test/.codex/sessions/2026/03/20/some-file-019d08ac-c265-7270-9497-d14125228a50.jsonl';
352
- const candidate = classifyProcessSnapshot(snapshot({
353
- command: 'codex app-server',
354
- sessionFiles: [filePath],
355
- }));
356
-
357
- assert.equal(candidate?.confidence, 'medium');
358
- assert.equal(candidate?.sessionFilePath, filePath);
359
- });
360
-
361
- test('classifies process with single claude project file', () => {
362
- const filePath = '/Users/test/.claude/projects/-Users-test-repo/my-session.jsonl';
363
- const candidate = classifyProcessSnapshot(snapshot({
364
- agent: 'claude',
365
- command: 'claude --continue',
366
- sessionFiles: [filePath],
367
- }));
368
-
369
- assert.equal(candidate?.confidence, 'medium');
370
- assert.equal(candidate?.sessionId, 'my-session');
371
- });
372
-
373
- test('ignores duplicate session files (dedupes before counting)', () => {
374
- const filePath = '/Users/test/.codex/sessions/2026/03/20/rollout-019d08ac-c265-7270-9497-d14125228a50.jsonl';
375
- const candidate = classifyProcessSnapshot(snapshot({
376
- command: 'codex app-server',
377
- sessionFiles: [filePath, filePath], // duplicate
378
- }));
379
-
380
- assert.equal(candidate?.confidence, 'medium');
381
- assert.equal(candidate?.sessionId, '019d08ac-c265-7270-9497-d14125228a50');
382
- });
383
-
384
- // ===== mergeRunningSessionCandidates edge cases =====
385
-
386
- test('mergeRunningSessionCandidates: same confidence uses lower PID as winner', () => {
387
- const a: RunningSessionCandidate = {
388
- agent: 'codex', pid: 100, cwd: '/repo', command: 'codex',
389
- sessionId: 'same-id', confidence: 'medium',
390
- };
391
- const b: RunningSessionCandidate = {
392
- agent: 'codex', pid: 200, cwd: '/other', command: 'codex',
393
- sessionId: 'same-id', confidence: 'medium',
394
- title: 'Title from B',
395
- };
396
-
397
- const result = mergeRunningSessionCandidates([a, b]);
398
- assert.equal(result.length, 1);
399
- assert.equal(result[0].pid, 100); // lower PID wins
400
- assert.equal(result[0].title, 'Title from B'); // title merged from loser
401
- });
402
-
403
- test('mergeRunningSessionCandidates: winner gets cwd from loser when winner has empty cwd', () => {
404
- const a: RunningSessionCandidate = {
405
- agent: 'codex', pid: 1, cwd: '', command: 'codex',
406
- sessionId: 'id-1', confidence: 'high',
407
- };
408
- const b: RunningSessionCandidate = {
409
- agent: 'codex', pid: 2, cwd: '/repo', command: 'codex',
410
- sessionId: 'id-1', confidence: 'low',
411
- };
412
-
413
- const result = mergeRunningSessionCandidates([a, b]);
414
- assert.equal(result[0].cwd, '/repo');
415
- });
416
-
417
- test('mergeRunningSessionCandidates: different agents are separate entries', () => {
418
- const a: RunningSessionCandidate = {
419
- agent: 'codex', pid: 1, cwd: '/repo', command: 'codex',
420
- sessionId: 'same-id', confidence: 'high',
421
- };
422
- const b: RunningSessionCandidate = {
423
- agent: 'claude', pid: 2, cwd: '/repo', command: 'claude',
424
- sessionId: 'same-id', confidence: 'high',
425
- };
426
-
427
- const result = mergeRunningSessionCandidates([a, b]);
428
- assert.equal(result.length, 2); // different agents = different keys
429
- });
430
-
431
- test('mergeRunningSessionCandidates: single candidate passes through', () => {
432
- const a: RunningSessionCandidate = {
433
- agent: 'codex', pid: 42, cwd: '/repo', command: 'codex resume abc',
434
- sessionId: 'abc', confidence: 'high', title: 'My Title',
435
- };
436
-
437
- const result = mergeRunningSessionCandidates([a]);
438
- assert.equal(result.length, 1);
439
- assert.deepEqual(result[0], a);
440
- });
441
-
442
- // ===== extractExplicitSessionId: --session-id support =====
443
-
444
- test('extracts claude session id from --session-id flag', () => {
445
- assert.equal(
446
- extractExplicitSessionId('claude', 'claude --session-id 7f03bcf8-d5aa-4eb2-b123-abcdef012345'),
447
- '7f03bcf8-d5aa-4eb2-b123-abcdef012345',
448
- );
449
- });
450
-
451
- test('extracts claude session id from --session-id= syntax', () => {
452
- assert.equal(
453
- extractExplicitSessionId('claude', 'claude --session-id=7f03bcf8-d5aa-4eb2-b123-abcdef012345'),
454
- '7f03bcf8-d5aa-4eb2-b123-abcdef012345',
455
- );
456
- });
457
-
458
- test('extracts claude session id from full path binary with --session-id', () => {
459
- assert.equal(
460
- extractExplicitSessionId('claude', '/Users/test/.local/bin/claude --session-id abc-123'),
461
- 'abc-123',
462
- );
463
- });
464
-
465
- test('classifies claude --session-id as high confidence', () => {
466
- const candidate = classifyProcessSnapshot(snapshot({
467
- agent: 'claude',
468
- command: '/Users/test/.local/bin/claude --session-id 7f03bcf8-d5aa-4eb2-b123-abcdef012345',
469
- sessionFiles: [],
470
- }));
471
-
472
- assert.equal(candidate?.confidence, 'high');
473
- assert.equal(candidate?.sessionId, '7f03bcf8-d5aa-4eb2-b123-abcdef012345');
474
- });
475
-
476
- // ===== hasContinueFlag =====
477
-
478
- test('hasContinueFlag detects --continue', () => {
479
- assert.equal(hasContinueFlag('claude', 'claude --dangerously-skip-permissions --continue'), true);
480
- });
481
-
482
- test('hasContinueFlag detects -c shorthand', () => {
483
- assert.equal(hasContinueFlag('claude', '/usr/local/bin/claude -c'), true);
484
- });
485
-
486
- test('hasContinueFlag returns false without --continue', () => {
487
- assert.equal(hasContinueFlag('claude', 'claude --resume abc'), false);
488
- });
489
-
490
- test('hasContinueFlag returns false for wrong agent', () => {
491
- assert.equal(hasContinueFlag('codex', 'claude --continue'), false);
492
- });
493
-
494
- // ===== cwd fallback: classifyProcessSnapshot returns null, scanRunningSessions uses filesystem =====
495
-
496
- test('classifyProcessSnapshot returns null for --continue without session files (fallback skipped)', () => {
497
- const candidate = classifyProcessSnapshot(snapshot({
498
- agent: 'claude',
499
- command: '/Users/test/.local/bin/claude --dangerously-skip-permissions --continue',
500
- cwd: '/some/project',
501
- sessionFiles: [],
502
- }));
503
-
504
- // classifyProcessSnapshot returns null; scanRunningSessions skips the mtime fallback for --continue
505
- assert.equal(candidate, null);
506
- });
507
-
508
- test('findRecentSessionFileForCwd matches Codex fallback by cwd instead of global newest file', async () => {
509
- const tempHome = await mkdtemp(join(tmpdir(), 'vibe-codex-cwd-'));
510
- const sessionsDir = join(tempHome, '.codex', 'sessions', '2026', '03', '21');
511
- const matchingOld = join(sessionsDir, 'matching-old.jsonl');
512
- const nonMatchingNewest = join(sessionsDir, 'other-cwd.jsonl');
513
- const matchingNewest = join(sessionsDir, 'matching-new.jsonl');
514
- const originalHome = process.env.HOME;
515
-
516
- await mkdir(sessionsDir, { recursive: true });
517
- await writeFile(matchingOld, `${JSON.stringify({ cwd: '/repo-a', id: 'codex-a-old', title: 'Old match' })}\n`);
518
- await writeFile(nonMatchingNewest, `${JSON.stringify({ cwd: '/repo-b', id: 'codex-b-new', title: 'Wrong cwd' })}\n`);
519
- await writeFile(matchingNewest, `${JSON.stringify({ cwd: '/repo-a', id: 'codex-a-new', title: 'New match' })}\n`);
520
-
521
- await utimes(matchingOld, new Date(1_000), new Date(1_000));
522
- await utimes(nonMatchingNewest, new Date(4_000), new Date(4_000));
523
- await utimes(matchingNewest, new Date(3_000), new Date(3_000));
524
-
525
- process.env.HOME = tempHome;
526
-
527
- try {
528
- const result = await findRecentSessionFileForCwd('codex', '/repo-a');
529
- assert.deepEqual(result, {
530
- sessionId: 'codex-a-new',
531
- filePath: matchingNewest,
532
- });
533
- } finally {
534
- process.env.HOME = originalHome;
535
- await rm(tempHome, { recursive: true, force: true });
536
- }
537
- });
538
-
539
- // ===== scanProcessSnapshots / scanRunningSessions (live system tests) =====
540
-
541
- import { scanProcessSnapshots, scanRunningSessions } from './process-scanner.js';
542
-
543
- test('scanProcessSnapshots returns an array', async () => {
544
- const snapshots = await scanProcessSnapshots();
545
- assert.ok(Array.isArray(snapshots));
546
- // Each snapshot should have the right shape
547
- for (const s of snapshots) {
548
- assert.equal(typeof s.pid, 'number');
549
- assert.ok(s.agent === 'claude' || s.agent === 'codex');
550
- assert.equal(typeof s.command, 'string');
551
- assert.equal(typeof s.cwd, 'string');
552
- assert.ok(Array.isArray(s.sessionFiles));
553
- }
554
- });
555
-
556
- test('scanRunningSessions returns an array of valid candidates', async () => {
557
- const candidates = await scanRunningSessions();
558
- assert.ok(Array.isArray(candidates));
559
- for (const c of candidates) {
560
- assert.equal(typeof c.sessionId, 'string');
561
- assert.ok(c.agent === 'claude' || c.agent === 'codex');
562
- assert.ok(['high', 'medium', 'low'].includes(c.confidence));
563
- }
564
- });
565
-
566
- // ─── isProcessAlive ──────────────────────────────────────────────────────────
567
-
568
- test('isProcessAlive returns true for the current process', () => {
569
- assert.equal(isProcessAlive(process.pid), true);
570
- });
571
-
572
- test('isProcessAlive returns false for a non-existent PID', () => {
573
- // PID 2147483647 (INT32_MAX) is almost certainly not in use.
574
- assert.equal(isProcessAlive(2147483647), false);
575
- });