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.
- package/.claude/skills/build/SKILL.md +268 -0
- package/README.md +2 -1
- package/dashboard/index.html +501 -491
- package/dist/cli.js +81 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +16 -9
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/listener.d.ts +46 -0
- package/dist/commands/listener.d.ts.map +1 -0
- package/dist/commands/listener.js +467 -0
- package/dist/commands/listener.js.map +1 -0
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +101 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +84 -21
- package/dist/commands/setup.js.map +1 -1
- package/dist/core/AgentRegistry.d.ts.map +1 -1
- package/dist/core/AgentRegistry.js +30 -2
- package/dist/core/AgentRegistry.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +2 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +29 -28
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/types.d.ts +32 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +10 -2
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +87 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/PipeSessionSpawner.d.ts +123 -0
- package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -0
- package/dist/threadline/PipeSessionSpawner.js +343 -0
- package/dist/threadline/PipeSessionSpawner.js.map +1 -0
- package/dist/threadline/ThreadResumeMap.d.ts +22 -0
- package/dist/threadline/ThreadResumeMap.d.ts.map +1 -1
- package/dist/threadline/ThreadResumeMap.js +37 -0
- package/dist/threadline/ThreadResumeMap.js.map +1 -1
- package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
- package/dist/threadline/ThreadlineBootstrap.js +155 -72
- package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
- package/dist/threadline/WakeSocketServer.d.ts +49 -0
- package/dist/threadline/WakeSocketServer.d.ts.map +1 -0
- package/dist/threadline/WakeSocketServer.js +115 -0
- package/dist/threadline/WakeSocketServer.js.map +1 -0
- package/dist/threadline/listener-daemon.d.ts +94 -0
- package/dist/threadline/listener-daemon.d.ts.map +1 -0
- package/dist/threadline/listener-daemon.js +550 -0
- package/dist/threadline/listener-daemon.js.map +1 -0
- package/package.json +2 -1
- package/src/data/builtin-manifest.json +91 -91
- package/upgrades/0.28.0.md +54 -0
- package/upgrades/NEXT.md +35 -0
- /package/.claude/skills/autonomous/{skill.md → SKILL.md} +0 -0
- /package/.claude/skills/secret-setup/{skill.md → SKILL.md} +0 -0
- /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,
|
|
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"}
|
package/dist/commands/server.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
5170
|
+
wakeSocketServer?.stop();
|
|
5171
|
+
pipeSpawner?.killAll();
|
|
5172
|
+
stopHeartbeat?.();
|
|
5075
5173
|
unregisterAgent(config.projectDir);
|
|
5076
5174
|
scheduler?.stop();
|
|
5077
5175
|
if (telegram)
|