instar 0.27.2 → 0.28.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 (59) hide show
  1. package/.claude/skills/build/SKILL.md +268 -0
  2. package/README.md +2 -1
  3. package/dashboard/index.html +501 -491
  4. package/dist/cli.js +81 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/init.d.ts.map +1 -1
  7. package/dist/commands/init.js +16 -9
  8. package/dist/commands/init.js.map +1 -1
  9. package/dist/commands/listener.d.ts +46 -0
  10. package/dist/commands/listener.d.ts.map +1 -0
  11. package/dist/commands/listener.js +467 -0
  12. package/dist/commands/listener.js.map +1 -0
  13. package/dist/commands/server.d.ts.map +1 -1
  14. package/dist/commands/server.js +101 -3
  15. package/dist/commands/server.js.map +1 -1
  16. package/dist/commands/setup.d.ts.map +1 -1
  17. package/dist/commands/setup.js +84 -21
  18. package/dist/commands/setup.js.map +1 -1
  19. package/dist/core/AgentRegistry.d.ts.map +1 -1
  20. package/dist/core/AgentRegistry.js +30 -2
  21. package/dist/core/AgentRegistry.js.map +1 -1
  22. package/dist/core/PostUpdateMigrator.d.ts +2 -1
  23. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  24. package/dist/core/PostUpdateMigrator.js +29 -28
  25. package/dist/core/PostUpdateMigrator.js.map +1 -1
  26. package/dist/core/types.d.ts +32 -0
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
  29. package/dist/lifeline/TelegramLifeline.js +10 -2
  30. package/dist/lifeline/TelegramLifeline.js.map +1 -1
  31. package/dist/server/routes.d.ts.map +1 -1
  32. package/dist/server/routes.js +87 -0
  33. package/dist/server/routes.js.map +1 -1
  34. package/dist/threadline/PipeSessionSpawner.d.ts +123 -0
  35. package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -0
  36. package/dist/threadline/PipeSessionSpawner.js +343 -0
  37. package/dist/threadline/PipeSessionSpawner.js.map +1 -0
  38. package/dist/threadline/ThreadResumeMap.d.ts +22 -0
  39. package/dist/threadline/ThreadResumeMap.d.ts.map +1 -1
  40. package/dist/threadline/ThreadResumeMap.js +37 -0
  41. package/dist/threadline/ThreadResumeMap.js.map +1 -1
  42. package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
  43. package/dist/threadline/ThreadlineBootstrap.js +155 -72
  44. package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
  45. package/dist/threadline/WakeSocketServer.d.ts +49 -0
  46. package/dist/threadline/WakeSocketServer.d.ts.map +1 -0
  47. package/dist/threadline/WakeSocketServer.js +115 -0
  48. package/dist/threadline/WakeSocketServer.js.map +1 -0
  49. package/dist/threadline/listener-daemon.d.ts +94 -0
  50. package/dist/threadline/listener-daemon.d.ts.map +1 -0
  51. package/dist/threadline/listener-daemon.js +550 -0
  52. package/dist/threadline/listener-daemon.js.map +1 -0
  53. package/package.json +2 -1
  54. package/src/data/builtin-manifest.json +91 -91
  55. package/upgrades/0.28.0.md +54 -0
  56. package/upgrades/NEXT.md +35 -0
  57. /package/.claude/skills/autonomous/{skill.md → SKILL.md} +0 -0
  58. /package/.claude/skills/secret-setup/{skill.md → SKILL.md} +0 -0
  59. /package/.claude/skills/setup-wizard/{skill.md → SKILL.md} +0 -0
@@ -0,0 +1,467 @@
1
+ /**
2
+ * `instar listener` — Manage the standalone listener daemon.
3
+ *
4
+ * Commands:
5
+ * instar listener start — Start the listener daemon
6
+ * instar listener stop — Gracefully stop the daemon
7
+ * instar listener status — Show daemon state + connection info
8
+ * instar listener logs — Tail daemon log file
9
+ * instar listener restart — Graceful restart
10
+ * instar listener doctor — Pre-flight check
11
+ * instar listener install — Install launchd plist / systemd unit
12
+ * instar listener uninstall — Remove launchd plist / systemd unit
13
+ * instar listener purge — Delete all listener data (GDPR right-to-erasure)
14
+ */
15
+ import { execSync, spawn } from 'node:child_process';
16
+ import fs from 'node:fs';
17
+ import path from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import pc from 'picocolors';
20
+ import { loadConfig, ensureStateDir } from '../core/Config.js';
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ // ── Helpers ─────────────────────────────────────────────────────────
23
+ function getProjectDir(opts) {
24
+ return opts.dir || process.cwd();
25
+ }
26
+ function getStateDir(opts) {
27
+ return path.join(getProjectDir(opts), '.instar');
28
+ }
29
+ function getPidFile(stateDir) {
30
+ return path.join(stateDir, 'listener-daemon.pid');
31
+ }
32
+ function getDaemonPid(stateDir) {
33
+ const pidFile = getPidFile(stateDir);
34
+ if (!fs.existsSync(pidFile))
35
+ return null;
36
+ try {
37
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
38
+ if (isNaN(pid))
39
+ return null;
40
+ // Check if process is running
41
+ try {
42
+ process.kill(pid, 0);
43
+ return pid;
44
+ }
45
+ catch {
46
+ return null; // Process not running
47
+ }
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ function readHealth(stateDir) {
54
+ const healthPath = path.join(stateDir, 'listener-health.json');
55
+ if (!fs.existsSync(healthPath))
56
+ return null;
57
+ try {
58
+ return JSON.parse(fs.readFileSync(healthPath, 'utf-8'));
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }
64
+ function formatUptime(seconds) {
65
+ const h = Math.floor(seconds / 3600);
66
+ const m = Math.floor((seconds % 3600) / 60);
67
+ if (h > 0)
68
+ return `${h}h ${m}m`;
69
+ return `${m}m`;
70
+ }
71
+ function formatAge(isoDate) {
72
+ const diff = Date.now() - new Date(isoDate).getTime();
73
+ const mins = Math.floor(diff / 60000);
74
+ if (mins < 1)
75
+ return 'just now';
76
+ if (mins < 60)
77
+ return `${mins} minutes ago`;
78
+ const hours = Math.floor(mins / 60);
79
+ return `${hours} hours ago`;
80
+ }
81
+ // ── Commands ────────────────────────────────────────────────────────
82
+ export async function startListener(opts) {
83
+ const stateDir = getStateDir(opts);
84
+ ensureStateDir(stateDir);
85
+ // Check if already running
86
+ const existingPid = getDaemonPid(stateDir);
87
+ if (existingPid) {
88
+ console.log(pc.yellow(`Listener daemon already running (pid: ${existingPid})`));
89
+ return;
90
+ }
91
+ // Load config for relay URL
92
+ const config = loadConfig(getProjectDir(opts));
93
+ const relayUrl = config?.threadline?.listener?.relayUrl
94
+ || config?.threadline?.relayUrl
95
+ || 'wss://threadline-relay.fly.dev/v1/connect';
96
+ const agentName = config?.projectName || path.basename(path.dirname(stateDir));
97
+ // Find the listener daemon script
98
+ const daemonScript = path.join(path.dirname(path.dirname(__filename)), 'threadline', 'listener-daemon.js');
99
+ if (!fs.existsSync(daemonScript)) {
100
+ console.log(pc.red('Listener daemon script not found. Ensure instar is built.'));
101
+ console.log(pc.dim(`Expected at: ${daemonScript}`));
102
+ return;
103
+ }
104
+ if (opts.foreground) {
105
+ // Run in foreground
106
+ console.log(pc.blue('Starting listener daemon in foreground...'));
107
+ const child = spawn('node', [
108
+ daemonScript,
109
+ '--state-dir', stateDir,
110
+ '--relay-url', relayUrl,
111
+ '--name', agentName,
112
+ ], {
113
+ stdio: 'inherit',
114
+ });
115
+ child.on('exit', (code) => {
116
+ console.log(pc.dim(`Daemon exited with code ${code}`));
117
+ });
118
+ }
119
+ else {
120
+ // Run in background
121
+ console.log(pc.blue('Starting listener daemon...'));
122
+ const child = spawn('node', [
123
+ daemonScript,
124
+ '--state-dir', stateDir,
125
+ '--relay-url', relayUrl,
126
+ '--name', agentName,
127
+ ], {
128
+ stdio: 'ignore',
129
+ detached: true,
130
+ });
131
+ child.unref();
132
+ console.log(pc.green(`Listener daemon started (pid: ${child.pid})`));
133
+ console.log(pc.dim('Run `instar listener status` to check connection.'));
134
+ }
135
+ }
136
+ export async function stopListener(opts) {
137
+ const stateDir = getStateDir(opts);
138
+ const pid = getDaemonPid(stateDir);
139
+ if (!pid) {
140
+ console.log(pc.yellow('Listener daemon is not running.'));
141
+ return;
142
+ }
143
+ console.log(pc.blue(`Stopping listener daemon (pid: ${pid})...`));
144
+ try {
145
+ process.kill(pid, 'SIGTERM');
146
+ // Wait up to 5 seconds for graceful shutdown
147
+ for (let i = 0; i < 50; i++) {
148
+ await new Promise(r => setTimeout(r, 100));
149
+ try {
150
+ process.kill(pid, 0);
151
+ }
152
+ catch {
153
+ console.log(pc.green('Listener daemon stopped.'));
154
+ return;
155
+ }
156
+ }
157
+ // Force kill if still running
158
+ process.kill(pid, 'SIGKILL');
159
+ console.log(pc.yellow('Listener daemon force-killed.'));
160
+ }
161
+ catch (err) {
162
+ console.log(pc.red(`Failed to stop daemon: ${err}`));
163
+ }
164
+ }
165
+ export async function listenerStatus(opts) {
166
+ const stateDir = getStateDir(opts);
167
+ const pid = getDaemonPid(stateDir);
168
+ const health = readHealth(stateDir);
169
+ if (!pid) {
170
+ console.log(`Listener Daemon: ${pc.red('STOPPED')}`);
171
+ if (health && typeof health.uptime === 'number') {
172
+ console.log(pc.dim(` Last known uptime: ${formatUptime(health.uptime)}`));
173
+ }
174
+ return;
175
+ }
176
+ const state = health?.state || 'unknown';
177
+ const stateColor = state === 'connected' ? pc.green(state.toUpperCase())
178
+ : state === 'authenticating' ? pc.yellow(state.toUpperCase())
179
+ : pc.red(state.toUpperCase());
180
+ console.log(`Listener Daemon: ${stateColor} (pid ${pid})`);
181
+ if (health) {
182
+ console.log(` Uptime: ${formatUptime(health.uptime)}`);
183
+ console.log(` Relay: ${state === 'connected' ? pc.green('session active') : pc.yellow('not connected')}`);
184
+ console.log(` Last message: ${health.lastMessage ? formatAge(health.lastMessage) : pc.dim('none')}`);
185
+ console.log(` Messages: ${health.msgsIn} received, ${health.msgsOut} processed`);
186
+ console.log(` Disconnects: ${health.disconnects10m} in last 10 min`);
187
+ }
188
+ // Check socket connection
189
+ const socketPath = path.join(stateDir, 'listener.sock');
190
+ console.log(` Socket: ${fs.existsSync(socketPath) ? pc.green(socketPath) : pc.dim('not available')}`);
191
+ // Check inbox
192
+ const inboxPath = path.join(stateDir, 'threadline', 'inbox.jsonl.active');
193
+ if (fs.existsSync(inboxPath)) {
194
+ const stat = fs.statSync(inboxPath);
195
+ const sizeKb = (stat.size / 1024).toFixed(1);
196
+ console.log(` Inbox: ${sizeKb} KB (inbox.jsonl.active)`);
197
+ }
198
+ else {
199
+ console.log(` Inbox: ${pc.dim('empty')}`);
200
+ }
201
+ }
202
+ export async function listenerLogs(opts) {
203
+ const stateDir = getStateDir(opts);
204
+ const logPath = path.join(stateDir, 'logs', 'listener-daemon.log');
205
+ if (!fs.existsSync(logPath)) {
206
+ console.log(pc.yellow('No listener daemon log file found.'));
207
+ return;
208
+ }
209
+ const lines = opts.lines || 50;
210
+ try {
211
+ const tailCmd = opts.follow
212
+ ? `tail -f -n ${lines} "${logPath}"`
213
+ : `tail -n ${lines} "${logPath}"`;
214
+ execSync(tailCmd, { stdio: 'inherit' });
215
+ }
216
+ catch {
217
+ // tail exits with error on SIGINT (Ctrl+C) — that's fine
218
+ }
219
+ }
220
+ export async function listenerDoctor(opts) {
221
+ const stateDir = getStateDir(opts);
222
+ let passed = 0;
223
+ let failed = 0;
224
+ function check(name, fn) {
225
+ try {
226
+ const result = fn();
227
+ if (result === true) {
228
+ console.log(` ${pc.green('✓')} ${name}`);
229
+ passed++;
230
+ }
231
+ else {
232
+ console.log(` ${pc.red('✗')} ${name}${typeof result === 'string' ? `: ${result}` : ''}`);
233
+ failed++;
234
+ }
235
+ }
236
+ catch (err) {
237
+ console.log(` ${pc.red('✗')} ${name}: ${err instanceof Error ? err.message : err}`);
238
+ failed++;
239
+ }
240
+ }
241
+ console.log(pc.bold('Listener Daemon Doctor\n'));
242
+ check('State directory exists', () => fs.existsSync(stateDir));
243
+ check('Identity file exists', () => {
244
+ const canonical = path.join(stateDir, 'identity.json');
245
+ const legacy = path.join(stateDir, 'threadline', 'identity.json');
246
+ if (fs.existsSync(canonical) || fs.existsSync(legacy))
247
+ return true;
248
+ return 'No identity file found — server must generate one first';
249
+ });
250
+ check('Config file exists', () => {
251
+ const configPath = path.join(stateDir, 'config.json');
252
+ return fs.existsSync(configPath) || 'No config.json found — run `instar init`';
253
+ });
254
+ check('HMAC key available', () => {
255
+ const keyFile = path.join(stateDir, 'threadline', 'inbox-hmac.key');
256
+ const configPath = path.join(stateDir, 'config.json');
257
+ if (fs.existsSync(keyFile))
258
+ return true;
259
+ if (fs.existsSync(configPath)) {
260
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
261
+ if (config.authToken)
262
+ return true;
263
+ }
264
+ return 'No HMAC key file and no authToken in config';
265
+ });
266
+ check('Inbox directory writable', () => {
267
+ const inboxDir = path.join(stateDir, 'threadline');
268
+ if (!fs.existsSync(inboxDir)) {
269
+ fs.mkdirSync(inboxDir, { recursive: true });
270
+ }
271
+ const testFile = path.join(inboxDir, '.write-test');
272
+ fs.writeFileSync(testFile, 'test');
273
+ fs.unlinkSync(testFile);
274
+ return true;
275
+ });
276
+ check('Log directory writable', () => {
277
+ const logDir = path.join(stateDir, 'logs');
278
+ if (!fs.existsSync(logDir)) {
279
+ fs.mkdirSync(logDir, { recursive: true });
280
+ }
281
+ return true;
282
+ });
283
+ check('Daemon script exists', () => {
284
+ const script = path.join(path.dirname(path.dirname(__filename)), 'threadline', 'listener-daemon.js');
285
+ return fs.existsSync(script) || `Not found at ${script} — run npm run build`;
286
+ });
287
+ check('No stale PID file', () => {
288
+ const pidFile = getPidFile(stateDir);
289
+ if (!fs.existsSync(pidFile))
290
+ return true;
291
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
292
+ try {
293
+ process.kill(pid, 0);
294
+ return true; // Process is actually running — not stale
295
+ }
296
+ catch {
297
+ fs.unlinkSync(pidFile);
298
+ return true; // Cleaned up stale PID
299
+ }
300
+ });
301
+ // Relay connectivity check (optional — may timeout)
302
+ check('Relay reachable (DNS)', () => {
303
+ try {
304
+ // Use nslookup which is available on all platforms
305
+ execSync('nslookup relay.threadline.dev', { timeout: 5000, stdio: 'pipe' });
306
+ return true;
307
+ }
308
+ catch {
309
+ try {
310
+ // Fallback: try host command
311
+ execSync('host relay.threadline.dev', { timeout: 5000, stdio: 'pipe' });
312
+ return true;
313
+ }
314
+ catch {
315
+ return 'Cannot resolve relay.threadline.dev — check network';
316
+ }
317
+ }
318
+ });
319
+ console.log(`\n ${pc.bold(`${passed} passed`)}, ${failed > 0 ? pc.red(`${failed} failed`) : pc.green(`${failed} failed`)}`);
320
+ if (failed === 0) {
321
+ console.log(pc.green('\n Ready to start: instar listener start'));
322
+ }
323
+ }
324
+ export async function restartListener(opts) {
325
+ await stopListener(opts);
326
+ await new Promise(r => setTimeout(r, 1000));
327
+ await startListener(opts);
328
+ }
329
+ export async function purgeListener(opts) {
330
+ const stateDir = getStateDir(opts);
331
+ if (!opts.force) {
332
+ console.log(pc.yellow('This will permanently delete all listener data:'));
333
+ console.log(' - Inbox files and archives');
334
+ console.log(' - Daemon logs');
335
+ console.log(' - Health snapshots');
336
+ console.log(' - Dedup cache');
337
+ console.log(' - HMAC key file');
338
+ console.log();
339
+ console.log(pc.bold('Add --force to confirm.'));
340
+ return;
341
+ }
342
+ // Stop daemon first
343
+ const pid = getDaemonPid(stateDir);
344
+ if (pid) {
345
+ console.log(pc.blue('Stopping daemon before purge...'));
346
+ await stopListener(opts);
347
+ }
348
+ const toDelete = [
349
+ path.join(stateDir, 'threadline', 'inbox.jsonl.active'),
350
+ path.join(stateDir, 'threadline', 'inbox-hmac.key'),
351
+ path.join(stateDir, 'threadline', 'inbox.cursor'),
352
+ path.join(stateDir, 'threadline', 'dedup.db'),
353
+ path.join(stateDir, 'listener-health.json'),
354
+ path.join(stateDir, 'listener-daemon.pid'),
355
+ path.join(stateDir, 'listener-displaced-alert.json'),
356
+ path.join(stateDir, 'logs', 'listener-daemon.log'),
357
+ path.join(stateDir, 'logs', 'listener-daemon.log.1'),
358
+ ];
359
+ let deleted = 0;
360
+ for (const file of toDelete) {
361
+ if (fs.existsSync(file)) {
362
+ fs.unlinkSync(file);
363
+ deleted++;
364
+ }
365
+ }
366
+ // Clean inbox archive directory
367
+ const archiveDir = path.join(stateDir, 'threadline', 'inbox-archive');
368
+ if (fs.existsSync(archiveDir)) {
369
+ fs.rmSync(archiveDir, { recursive: true });
370
+ deleted++;
371
+ }
372
+ // Clean temp prompt files
373
+ const tmpDir = path.join(stateDir, 'tmp');
374
+ if (fs.existsSync(tmpDir)) {
375
+ const files = fs.readdirSync(tmpDir).filter(f => f.startsWith('prompt-'));
376
+ for (const f of files) {
377
+ fs.unlinkSync(path.join(tmpDir, f));
378
+ deleted++;
379
+ }
380
+ }
381
+ console.log(pc.green(`Purged ${deleted} files. Listener data erased.`));
382
+ }
383
+ export async function installListener(opts) {
384
+ const stateDir = getStateDir(opts);
385
+ const platform = process.platform;
386
+ if (platform === 'darwin') {
387
+ // macOS — launchd plist
388
+ const plistDir = path.join(process.env.HOME || '', 'Library', 'LaunchAgents');
389
+ const plistName = 'dev.instar.listener.plist';
390
+ const plistPath = path.join(plistDir, plistName);
391
+ const daemonScript = path.join(path.dirname(path.dirname(__filename)), 'threadline', 'listener-daemon.js');
392
+ const nodePath = process.execPath;
393
+ const config = loadConfig(getProjectDir(opts));
394
+ const relayUrl = config?.threadline?.listener?.relayUrl
395
+ || config?.threadline?.relayUrl
396
+ || 'wss://threadline-relay.fly.dev/v1/connect';
397
+ const agentName = config?.projectName || 'instar-agent';
398
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
399
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
400
+ <plist version="1.0">
401
+ <dict>
402
+ <key>Label</key>
403
+ <string>dev.instar.listener</string>
404
+ <key>ProgramArguments</key>
405
+ <array>
406
+ <string>${nodePath}</string>
407
+ <string>${daemonScript}</string>
408
+ <string>--state-dir</string>
409
+ <string>${stateDir}</string>
410
+ <string>--relay-url</string>
411
+ <string>${relayUrl}</string>
412
+ <string>--name</string>
413
+ <string>${agentName}</string>
414
+ </array>
415
+ <key>RunAtLoad</key>
416
+ <true/>
417
+ <key>KeepAlive</key>
418
+ <dict>
419
+ <key>SuccessfulExit</key>
420
+ <false/>
421
+ </dict>
422
+ <key>StandardOutPath</key>
423
+ <string>${path.join(stateDir, 'logs', 'listener-daemon-stdout.log')}</string>
424
+ <key>StandardErrorPath</key>
425
+ <string>${path.join(stateDir, 'logs', 'listener-daemon-stderr.log')}</string>
426
+ <key>WorkingDirectory</key>
427
+ <string>${path.dirname(stateDir)}</string>
428
+ </dict>
429
+ </plist>`;
430
+ if (!fs.existsSync(plistDir)) {
431
+ fs.mkdirSync(plistDir, { recursive: true });
432
+ }
433
+ fs.writeFileSync(plistPath, plist);
434
+ console.log(pc.green(`Installed launchd plist: ${plistPath}`));
435
+ console.log(pc.dim('The daemon will auto-start on login and restart on crash (not on clean exit).'));
436
+ console.log(pc.dim('Load now: launchctl load ' + plistPath));
437
+ }
438
+ else if (platform === 'linux') {
439
+ console.log(pc.yellow('systemd unit file generation not yet implemented.'));
440
+ console.log(pc.dim('For now, use `instar listener start` to run manually.'));
441
+ }
442
+ else {
443
+ console.log(pc.yellow(`Unsupported platform: ${platform}`));
444
+ }
445
+ }
446
+ export async function uninstallListener(opts) {
447
+ if (process.platform === 'darwin') {
448
+ const plistPath = path.join(process.env.HOME || '', 'Library', 'LaunchAgents', 'dev.instar.listener.plist');
449
+ if (fs.existsSync(plistPath)) {
450
+ try {
451
+ execSync(`launchctl unload "${plistPath}"`, { stdio: 'pipe' });
452
+ }
453
+ catch {
454
+ // May not be loaded
455
+ }
456
+ fs.unlinkSync(plistPath);
457
+ console.log(pc.green('Uninstalled launchd plist.'));
458
+ }
459
+ else {
460
+ console.log(pc.yellow('No launchd plist found.'));
461
+ }
462
+ }
463
+ else {
464
+ console.log(pc.yellow('Only macOS launchd is currently supported.'));
465
+ }
466
+ }
467
+ //# sourceMappingURL=listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener.js","sourceRoot":"","sources":["../../src/commands/listener.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAizCD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA63HtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAizCD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+9HtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
@@ -1643,7 +1643,15 @@ export async function startServer(options) {
1643
1643
  console.log(pc.red(` Port conflict: ${err instanceof Error ? err.message : err}`));
1644
1644
  process.exit(1);
1645
1645
  }
1646
- const stopHeartbeat = startHeartbeat(config.projectDir);
1646
+ let stopHeartbeat;
1647
+ try {
1648
+ stopHeartbeat = startHeartbeat(config.projectDir);
1649
+ }
1650
+ catch (err) {
1651
+ // Registry heartbeat is non-critical — server should run without it.
1652
+ // ELOCKED errors from concurrent agent startups are transient.
1653
+ console.log(pc.yellow(` Registry heartbeat failed to start (non-critical): ${err instanceof Error ? err.message : err}`));
1654
+ }
1647
1655
  // Warn if no auth token configured — server allows unauthenticated access
1648
1656
  if (!config.authToken) {
1649
1657
  console.log(pc.yellow(pc.bold(' ⚠ WARNING: No auth token configured — all API endpoints are unauthenticated!')));
@@ -4497,6 +4505,62 @@ export async function startServer(options) {
4497
4505
  const listenerManager = config.threadline?.relayEnabled
4498
4506
  ? new ListenerSessionManager(config.stateDir, config.authToken ?? '', config.threadline)
4499
4507
  : null;
4508
+ // Wake Socket Server — receives signals from the standalone listener daemon (Phase 1)
4509
+ let wakeSocketServer;
4510
+ try {
4511
+ const { WakeSocketServer } = await import('../threadline/WakeSocketServer.js');
4512
+ wakeSocketServer = new WakeSocketServer(config.stateDir);
4513
+ wakeSocketServer.on('wake', () => {
4514
+ // Daemon wrote a new inbox entry — read and process it
4515
+ const inboxPath = path.join(config.stateDir, 'threadline', 'inbox.jsonl.active');
4516
+ if (fs.existsSync(inboxPath)) {
4517
+ console.log('[wake-socket] Received wake signal from listener daemon');
4518
+ }
4519
+ });
4520
+ // Phase 3: Fast failover via relay presence detection
4521
+ wakeSocketServer.on('failover-trigger', () => {
4522
+ console.log('[wake-socket] Received FAILOVER_TRIGGER from listener daemon');
4523
+ // Read trigger details
4524
+ const triggerPath = path.join(config.stateDir, 'failover-trigger.json');
4525
+ if (fs.existsSync(triggerPath)) {
4526
+ try {
4527
+ const trigger = JSON.parse(fs.readFileSync(triggerPath, 'utf-8'));
4528
+ console.log(`[wake-socket] Peer agent ${trigger.agentId?.slice(0, 8)}... disconnected from relay`);
4529
+ // The MultiMachineCoordinator can use this to speed up failover
4530
+ // For now, log the event. Full failover integration requires
4531
+ // evaluating whether this agent is a standby for the disconnected peer.
4532
+ }
4533
+ catch { /* ignore parse errors */ }
4534
+ }
4535
+ });
4536
+ wakeSocketServer.start();
4537
+ console.log(pc.dim(` Wake socket: listening at ${path.join(config.stateDir, 'listener.sock')}`));
4538
+ }
4539
+ catch (err) {
4540
+ console.log(pc.dim(` Wake socket: not started (${err instanceof Error ? err.message : err})`));
4541
+ }
4542
+ // Pipe Session Spawner — lightweight claude -p sessions for simple queries (Phase 2)
4543
+ let pipeSpawner;
4544
+ if (config.threadline?.relayEnabled) {
4545
+ try {
4546
+ const { PipeSessionSpawner } = await import('../threadline/PipeSessionSpawner.js');
4547
+ const pipeConfig = config.threadline?.listener?.pipeMode;
4548
+ pipeSpawner = new PipeSessionSpawner({
4549
+ stateDir: config.stateDir,
4550
+ model: pipeConfig?.model ?? 'sonnet',
4551
+ timeoutMs: pipeConfig?.timeoutMs ?? 600_000,
4552
+ warningMs: pipeConfig?.warningMs ?? 480_000,
4553
+ maxConcurrent: pipeConfig?.maxConcurrent ?? 5,
4554
+ allowedTools: pipeConfig?.allowedTools ?? ['threadline_send', 'Read', 'Glob', 'Grep'],
4555
+ allowedPaths: pipeConfig?.allowedPaths ?? ['src/', 'docs/', 'specs/'],
4556
+ minIqsBand: pipeConfig?.minIqsBand ?? 70,
4557
+ });
4558
+ console.log(pc.dim(` Pipe sessions: enabled (model: ${pipeConfig?.model ?? 'sonnet'}, max: ${pipeConfig?.maxConcurrent ?? 5})`));
4559
+ }
4560
+ catch (err) {
4561
+ console.log(pc.dim(` Pipe sessions: not available (${err instanceof Error ? err.message : err})`));
4562
+ }
4563
+ }
4500
4564
  console.log(pc.green(` Inter-agent messaging: enabled (token: ${agentToken.slice(0, 8)}...)${dropSummary}`));
4501
4565
  // ── System Reviewer: self-monitoring feature health ──────────────
4502
4566
  const systemReviewConfig = config.monitoring?.systemReview;
@@ -4657,7 +4721,39 @@ export async function startServer(options) {
4657
4721
  console.error(`[relay] Auto-ack failed: ${ackErr instanceof Error ? ackErr.message : ackErr}`);
4658
4722
  }
4659
4723
  }
4660
- // Phase 2: Route to warm listener if available and appropriate
4724
+ // Phase 2a: Pipe-mode session for simple queries (lightweight, auto-exit)
4725
+ if (pipeSpawner && msg.threadId && !threadResumeMap.get(msg.threadId)) {
4726
+ const pipeCheck = pipeSpawner.shouldUsePipeMode({
4727
+ threadId: msg.threadId,
4728
+ messageText: textContent,
4729
+ fromFingerprint: senderFingerprint,
4730
+ fromName: senderName,
4731
+ trustLevel,
4732
+ });
4733
+ if (pipeCheck.eligible) {
4734
+ try {
4735
+ const { classifyIntent, summarizeThreadHistory } = await import('../threadline/PipeSessionSpawner.js');
4736
+ const intent = await classifyIntent(textContent);
4737
+ if (intent === 'pipe') {
4738
+ const result = await pipeSpawner.spawn({
4739
+ threadId: msg.threadId,
4740
+ messageText: textContent,
4741
+ fromFingerprint: senderFingerprint,
4742
+ fromName: senderName,
4743
+ trustLevel,
4744
+ });
4745
+ if (result.spawned) {
4746
+ console.log(`[relay] Pipe session spawned for ${senderName} (thread: ${msg.threadId.slice(0, 8)})`);
4747
+ return;
4748
+ }
4749
+ }
4750
+ }
4751
+ catch (err) {
4752
+ console.error(`[relay] Pipe session error (falling through to interactive): ${err instanceof Error ? err.message : err}`);
4753
+ }
4754
+ }
4755
+ }
4756
+ // Phase 2b: Route to warm listener if available and appropriate
4661
4757
  if (listenerManager && listenerManager.shouldUseListener(trustLevel, textContent.length)) {
4662
4758
  listenerManager.writeToInbox({ from: senderFingerprint, senderName, trustLevel, threadId: msg.threadId ?? getSyntheticThreadId(senderFingerprint), text: textContent });
4663
4759
  console.log(`[relay] Routed to listener inbox from ${senderName} (trust: ${trustLevel})`);
@@ -5071,7 +5167,9 @@ export async function startServer(options) {
5071
5167
  await tunnel.stop();
5072
5168
  if (threadlineShutdown)
5073
5169
  await threadlineShutdown();
5074
- stopHeartbeat();
5170
+ wakeSocketServer?.stop();
5171
+ pipeSpawner?.killAll();
5172
+ stopHeartbeat?.();
5075
5173
  unregisterAgent(config.projectDir);
5076
5174
  scheduler?.stop();
5077
5175
  if (telegram)