@dmsdc-ai/aigentry-telepty 0.5.8 โ†’ 0.6.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/install.js CHANGED
@@ -5,9 +5,6 @@ const os = require('os');
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
  const { cleanupDaemonProcesses } = require('./daemon-control');
8
- const { runInteractiveSkillInstaller } = require('./skill-installer');
9
-
10
- console.log("๐Ÿš€ Installing @dmsdc-ai/aigentry-telepty...");
11
8
 
12
9
  function run(cmd) {
13
10
  try {
@@ -18,6 +15,10 @@ function run(cmd) {
18
15
  }
19
16
  }
20
17
 
18
+ function shellQuote(value) {
19
+ return `'${String(value).replace(/'/g, "'\\''")}'`;
20
+ }
21
+
21
22
  function resolveInstalledPackageRoot() {
22
23
  try {
23
24
  const globalRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
@@ -27,6 +28,15 @@ function resolveInstalledPackageRoot() {
27
28
  }
28
29
  }
29
30
 
31
+ function resolveDaemonLaunchOptions(options = {}) {
32
+ const packageRoot = options.packageRoot || __dirname;
33
+ const nodeBin = options.nodeBin || process.execPath;
34
+ const cliJs = options.cliJs || path.join(packageRoot, 'cli.js');
35
+ const logDir = options.logDir || path.join(os.homedir(), '.telepty', 'logs');
36
+
37
+ return { nodeBin, cliJs, logDir };
38
+ }
39
+
30
40
  function cleanupLocalDaemons() {
31
41
  console.log('๐Ÿงน Cleaning up existing telepty daemons...');
32
42
  const results = cleanupDaemonProcesses();
@@ -36,6 +46,261 @@ function cleanupLocalDaemons() {
36
46
  }
37
47
  }
38
48
 
49
+ function escapeXml(value) {
50
+ return String(value)
51
+ .replace(/&/g, '&')
52
+ .replace(/</g, '&lt;')
53
+ .replace(/>/g, '&gt;')
54
+ .replace(/"/g, '&quot;')
55
+ .replace(/'/g, '&apos;');
56
+ }
57
+
58
+ function uniquePathEntries(entries) {
59
+ const seen = new Set();
60
+ const result = [];
61
+
62
+ for (const entry of entries) {
63
+ if (!entry || seen.has(entry)) {
64
+ continue;
65
+ }
66
+ seen.add(entry);
67
+ result.push(entry);
68
+ }
69
+
70
+ return result;
71
+ }
72
+
73
+ function buildDaemonPath(nodeBin, baseEntries) {
74
+ return uniquePathEntries([path.dirname(nodeBin), ...baseEntries]).join(':');
75
+ }
76
+
77
+ function systemdExecArg(value) {
78
+ const text = String(value);
79
+ if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(text)) {
80
+ return text;
81
+ }
82
+ return `"${text.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
83
+ }
84
+
85
+ function quoteWindowsArg(value) {
86
+ return `"${String(value).replace(/"/g, '\\"')}"`;
87
+ }
88
+
89
+ function buildLaunchdPlist(options = {}) {
90
+ const label = options.label || 'com.aigentry.telepty';
91
+ const nodeBin = options.nodeBin || process.execPath;
92
+ const cliJs = options.cliJs || path.join(__dirname, 'cli.js');
93
+ const logDir = options.logDir || path.join(os.homedir(), '.telepty', 'logs');
94
+ const command = options.command || 'daemon';
95
+ const daemonPath = buildDaemonPath(nodeBin, ['/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin']);
96
+ const stdoutPath = path.join(logDir, 'launchd.out.log');
97
+ const stderrPath = path.join(logDir, 'launchd.err.log');
98
+ const envPairs = [['PATH', daemonPath], ...Object.entries(options.extraEnv || {})];
99
+ const envXml = envPairs
100
+ .map(([key, value]) => ` <key>${escapeXml(key)}</key>\n <string>${escapeXml(value)}</string>`)
101
+ .join('\n');
102
+
103
+ return `<?xml version="1.0" encoding="UTF-8"?>
104
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
105
+ <plist version="1.0">
106
+ <dict>
107
+ <key>Label</key>
108
+ <string>${escapeXml(label)}</string>
109
+ <key>ProgramArguments</key>
110
+ <array>
111
+ <string>${escapeXml(nodeBin)}</string>
112
+ <string>${escapeXml(cliJs)}</string>
113
+ <string>${escapeXml(command)}</string>
114
+ </array>
115
+ <key>EnvironmentVariables</key>
116
+ <dict>
117
+ ${envXml}
118
+ </dict>
119
+ <key>StandardOutPath</key>
120
+ <string>${escapeXml(stdoutPath)}</string>
121
+ <key>StandardErrorPath</key>
122
+ <string>${escapeXml(stderrPath)}</string>
123
+ <key>RunAtLoad</key>
124
+ <true/>
125
+ <key>KeepAlive</key>
126
+ <true/>
127
+ </dict>
128
+ </plist>`;
129
+ }
130
+
131
+ function systemdEnvLine(key, value) {
132
+ const escaped = String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
133
+ return `Environment="${key}=${escaped}"`;
134
+ }
135
+
136
+ function buildSystemdService(options = {}) {
137
+ const nodeBin = options.nodeBin || process.execPath;
138
+ const cliJs = options.cliJs || path.join(__dirname, 'cli.js');
139
+ const user = options.user;
140
+ const userLine = user ? `User=${user}\n` : '';
141
+ const daemonPath = buildDaemonPath(nodeBin, ['/usr/local/bin', '/usr/bin', '/bin']);
142
+ const wantedBy = options.wantedBy || 'multi-user.target';
143
+ const command = options.command || 'daemon';
144
+ const description = options.description || 'Telepty Daemon';
145
+ const extraEnvLines = Object.entries(options.extraEnv || {})
146
+ .map(([key, value]) => `${systemdEnvLine(key, value)}\n`)
147
+ .join('');
148
+
149
+ return `[Unit]
150
+ Description=${description}
151
+ After=network.target
152
+
153
+ [Service]
154
+ ExecStart=${systemdExecArg(nodeBin)} ${systemdExecArg(cliJs)} ${systemdExecArg(command)}
155
+ Restart=always
156
+ ${userLine}Environment=PATH=${daemonPath}
157
+ Environment=NODE_ENV=production
158
+ ${extraEnvLines}
159
+ [Install]
160
+ WantedBy=${wantedBy}`;
161
+ }
162
+
163
+ function buildWindowsAutostartCommand(options = {}) {
164
+ const nodeBin = options.nodeBin || process.execPath;
165
+ const cliJs = options.cliJs || path.join(__dirname, 'cli.js');
166
+ const taskName = options.taskName || 'telepty-daemon';
167
+ const command = options.command || 'daemon';
168
+ const taskCommand = `${quoteWindowsArg(nodeBin)} ${quoteWindowsArg(cliJs)} ${command}`;
169
+
170
+ return `schtasks /create /tn ${quoteWindowsArg(taskName)} /sc onlogon /rl LIMITED /f /tr ${quoteWindowsArg(taskCommand)}`;
171
+ }
172
+
173
+ function buildWindowsRunTaskCommand(options = {}) {
174
+ const taskName = options.taskName || 'telepty-daemon';
175
+ return `schtasks /run /tn ${quoteWindowsArg(taskName)}`;
176
+ }
177
+
178
+ function buildWindowsQueryTaskCommand(options = {}) {
179
+ const taskName = options.taskName || 'telepty-daemon';
180
+ return `schtasks /query /tn ${quoteWindowsArg(taskName)} /fo LIST`;
181
+ }
182
+
183
+ // --- Broker-host service variant (telepty #42 broker MVP โ€” spec ยง6 + ยง2 H; reuses #41 hardening) ---
184
+ // The broker runs the SAME hardened service definition as the daemon, but executes
185
+ // `<node> <cli.js> broker` (spec ยง5/ยง6) and carries the broker host env (TLS + JWT/enroll
186
+ // secrets, spec ยง6). Selected via `telepty install --broker` or env TELEPTY_BROKER_MODE.
187
+ const BROKER_LAUNCHD_LABEL = 'com.aigentry.telepty-broker';
188
+ const BROKER_SYSTEMD_SERVICE = 'telepty-broker';
189
+ const BROKER_WINDOWS_TASK = 'telepty-broker';
190
+
191
+ // Pass-through env keys for the broker host service (spec ยง5/ยง6). Secrets are NEVER
192
+ // hardcoded โ€” they are read from the install-time environment and forwarded into the
193
+ // generated service definition so the always-on broker host loads them on start.
194
+ const BROKER_ENV_KEYS = [
195
+ 'TELEPTY_JWT_SECRET',
196
+ 'TELEPTY_ENROLL_SECRET',
197
+ 'TELEPTY_TLS_CERT',
198
+ 'TELEPTY_TLS_KEY',
199
+ 'TELEPTY_BROKER_ACL',
200
+ 'TELEPTY_ENROLL_MAX_NODES',
201
+ 'PORT',
202
+ ];
203
+
204
+ function collectBrokerServiceEnv(env = process.env) {
205
+ const result = { TELEPTY_BROKER_MODE: '1' };
206
+ for (const key of BROKER_ENV_KEYS) {
207
+ const value = env[key];
208
+ if (value !== undefined && value !== '') {
209
+ result[key] = String(value);
210
+ }
211
+ }
212
+ return result;
213
+ }
214
+
215
+ function buildBrokerLaunchdPlist(options = {}) {
216
+ return buildLaunchdPlist({
217
+ ...options,
218
+ label: options.label || BROKER_LAUNCHD_LABEL,
219
+ command: 'broker',
220
+ extraEnv: { ...collectBrokerServiceEnv(options.env), ...(options.extraEnv || {}) },
221
+ });
222
+ }
223
+
224
+ function buildBrokerSystemdService(options = {}) {
225
+ return buildSystemdService({
226
+ ...options,
227
+ command: 'broker',
228
+ description: options.description || 'Telepty Broker',
229
+ extraEnv: { ...collectBrokerServiceEnv(options.env), ...(options.extraEnv || {}) },
230
+ });
231
+ }
232
+
233
+ function buildBrokerWindowsAutostartCommand(options = {}) {
234
+ return buildWindowsAutostartCommand({
235
+ ...options,
236
+ taskName: options.taskName || BROKER_WINDOWS_TASK,
237
+ command: 'broker',
238
+ });
239
+ }
240
+
241
+ // Resolve the active service profile (daemon vs broker) so main() can install either
242
+ // variant from one code path. The daemon profile reproduces the exact pre-#42 values
243
+ // (no behavior change for existing installs); the broker profile selects distinct
244
+ // label/service/task names, the `broker` command, and the broker host env.
245
+ function resolveServiceProfile(options = {}) {
246
+ if (options.broker) {
247
+ return {
248
+ command: 'broker',
249
+ launchdLabel: BROKER_LAUNCHD_LABEL,
250
+ launchdPlistName: `${BROKER_LAUNCHD_LABEL}.plist`,
251
+ systemdService: BROKER_SYSTEMD_SERVICE,
252
+ windowsTask: BROKER_WINDOWS_TASK,
253
+ description: 'Telepty Broker',
254
+ extraEnv: collectBrokerServiceEnv(options.env),
255
+ };
256
+ }
257
+ return {
258
+ command: 'daemon',
259
+ launchdLabel: 'com.aigentry.telepty',
260
+ launchdPlistName: 'com.aigentry.telepty.plist',
261
+ systemdService: 'telepty',
262
+ windowsTask: 'telepty-daemon',
263
+ description: 'Telepty Daemon',
264
+ extraEnv: {},
265
+ };
266
+ }
267
+
268
+ function assertLaunchdServiceLive(label = 'com.aigentry.telepty') {
269
+ let output = '';
270
+ try {
271
+ output = execSync(`launchctl list ${shellQuote(label)}`, { encoding: 'utf8' });
272
+ } catch (e) {
273
+ throw new Error(`launchd service ${label} was not found after load`);
274
+ }
275
+
276
+ const pidMatch = output.match(/"PID"\s*=\s*([0-9]+)/);
277
+ if (!pidMatch || Number(pidMatch[1]) <= 0) {
278
+ throw new Error(`launchd service ${label} loaded but has no live PID. launchctl output:\n${output}`);
279
+ }
280
+ }
281
+
282
+ function assertSystemdServiceLive(serviceName = 'telepty', options = {}) {
283
+ const scope = options.user ? '--user ' : '';
284
+ try {
285
+ execSync(`systemctl ${scope}is-active --quiet ${serviceName}`, { stdio: 'ignore' });
286
+ } catch (e) {
287
+ throw new Error(`systemd service ${serviceName} is not active after start`);
288
+ }
289
+ }
290
+
291
+ function assertWindowsTaskRunning(taskName = 'telepty-daemon') {
292
+ let output = '';
293
+ try {
294
+ output = execSync(buildWindowsQueryTaskCommand({ taskName }), { encoding: 'utf8' });
295
+ } catch (e) {
296
+ throw new Error(`Windows scheduled task ${taskName} was not found after creation`);
297
+ }
298
+
299
+ if (!/^Status:\s*Running$/im.test(output)) {
300
+ throw new Error(`Windows scheduled task ${taskName} started but is not running. schtasks output:\n${output}`);
301
+ }
302
+ }
303
+
39
304
  async function installSkills() {
40
305
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
41
306
  console.log('โญ๏ธ Skipping interactive skill installation (no TTY).');
@@ -46,6 +311,7 @@ async function installSkills() {
46
311
  console.log('\n๐Ÿ“‹ Telepty skill installation');
47
312
 
48
313
  try {
314
+ const { runInteractiveSkillInstaller } = require('./skill-installer');
49
315
  await runInteractiveSkillInstaller({
50
316
  packageRoot: resolveInstalledPackageRoot(),
51
317
  cwd: process.cwd()
@@ -55,7 +321,19 @@ async function installSkills() {
55
321
  }
56
322
  }
57
323
 
58
- (async () => {
324
+ async function main() {
325
+ console.log("๐Ÿš€ Installing @dmsdc-ai/aigentry-telepty...");
326
+
327
+ // Broker-host variant (telepty #42): `telepty install --broker` or env TELEPTY_BROKER_MODE
328
+ // installs the SAME hardened service running `telepty broker` instead of `telepty daemon`.
329
+ // Default-OFF โ€” existing daemon installs are entirely unaffected (additive).
330
+ const wantsBroker = process.argv.slice(2).includes('--broker')
331
+ || process.env.TELEPTY_BROKER_MODE === '1';
332
+ const profile = resolveServiceProfile({ broker: wantsBroker });
333
+ if (wantsBroker) {
334
+ console.log(`๐Ÿ›ฐ๏ธ Broker-host mode: installing service '${profile.launchdLabel}' (runs 'telepty broker').`);
335
+ }
336
+
59
337
  // 1. Install globally via npm
60
338
  console.log("๐Ÿ“ฆ Installing package globally...");
61
339
  run("npm install -g @dmsdc-ai/aigentry-telepty");
@@ -63,12 +341,10 @@ async function installSkills() {
63
341
  // 2. Install telepty skills for supported clients
64
342
  await installSkills();
65
343
 
66
- // 3. Find executable
67
- let teleptyPath = '';
68
- try {
69
- teleptyPath = execSync(os.platform() === 'win32' ? 'where telepty' : 'which telepty', { encoding: 'utf8' }).split('\n')[0].trim();
70
- } catch (e) {
71
- teleptyPath = 'telepty'; // fallback
344
+ // 3. Resolve daemon entrypoint without relying on service-manager PATH.
345
+ const launchOptions = resolveDaemonLaunchOptions({ packageRoot: resolveInstalledPackageRoot() });
346
+ if (!fs.existsSync(launchOptions.cliJs)) {
347
+ throw new Error(`Cannot find daemon entrypoint: ${launchOptions.cliJs}`);
72
348
  }
73
349
 
74
350
  // 4. Setup OS-specific autostart or background daemon
@@ -76,86 +352,115 @@ async function installSkills() {
76
352
 
77
353
  if (platform === 'win32') {
78
354
  cleanupLocalDaemons();
79
- console.log("โš™๏ธ Setting up Windows background process...");
80
- const subprocess = spawn(teleptyPath, ['daemon'], {
81
- detached: true,
82
- stdio: 'ignore',
83
- windowsHide: true
84
- });
85
- subprocess.unref();
86
- console.log("โœ… Windows daemon started in background.");
355
+ console.log("โš™๏ธ Setting up Windows scheduled task...");
356
+ run(buildWindowsAutostartCommand({ ...launchOptions, taskName: profile.windowsTask, command: profile.command }));
357
+ run(buildWindowsRunTaskCommand({ taskName: profile.windowsTask }));
358
+ assertWindowsTaskRunning(profile.windowsTask);
359
+ console.log("โœ… Windows scheduled task installed and started.");
87
360
 
88
361
  } else if (platform === 'darwin') {
89
362
  console.log("โš™๏ธ Setting up macOS launchd service...");
90
- const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.aigentry.telepty.plist');
363
+ const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', profile.launchdPlistName);
91
364
  fs.mkdirSync(path.dirname(plistPath), { recursive: true });
92
- try { execSync(`launchctl unload "${plistPath}" 2>/dev/null`); } catch(e){}
365
+ fs.mkdirSync(launchOptions.logDir, { recursive: true });
366
+ try { execSync(`launchctl unload ${shellQuote(plistPath)} 2>/dev/null`); } catch(e){}
93
367
  cleanupLocalDaemons();
94
368
 
95
- const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
96
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
97
- <plist version="1.0">
98
- <dict>
99
- <key>Label</key>
100
- <string>com.aigentry.telepty</string>
101
- <key>ProgramArguments</key>
102
- <array>
103
- <string>${teleptyPath}</string>
104
- <string>daemon</string>
105
- </array>
106
- <key>RunAtLoad</key>
107
- <true/>
108
- <key>KeepAlive</key>
109
- <true/>
110
- </dict>
111
- </plist>`;
369
+ const plistContent = buildLaunchdPlist({
370
+ ...launchOptions,
371
+ label: profile.launchdLabel,
372
+ command: profile.command,
373
+ extraEnv: profile.extraEnv,
374
+ });
112
375
 
113
376
  fs.writeFileSync(plistPath, plistContent);
114
- run(`launchctl load "${plistPath}"`);
377
+ run(`launchctl load ${shellQuote(plistPath)}`);
378
+ assertLaunchdServiceLive(profile.launchdLabel);
115
379
  console.log("โœ… macOS LaunchAgent installed and started.");
116
380
 
117
381
  } else {
118
382
  // Linux
383
+ let hasSystemd = false;
119
384
  try {
120
385
  execSync('systemctl --version', { stdio: 'ignore' });
386
+ hasSystemd = true;
387
+ } catch(e) {}
388
+
389
+ if (hasSystemd) {
121
390
  if (process.getuid && process.getuid() === 0) {
122
391
  console.log("โš™๏ธ Setting up systemd service for Linux...");
123
- try { execSync('systemctl stop telepty', { stdio: 'ignore' }); } catch(e) {}
392
+ try { execSync(`systemctl stop ${profile.systemdService}`, { stdio: 'ignore' }); } catch(e) {}
124
393
  cleanupLocalDaemons();
125
- const serviceContent = `[Unit]
126
- Description=Telepty Daemon
127
- After=network.target
128
-
129
- [Service]
130
- ExecStart=${teleptyPath} daemon
131
- Restart=always
132
- User=${process.env.SUDO_USER || process.env.USER || 'root'}
133
- Environment=PATH=/usr/bin:/usr/local/bin:$PATH
134
- Environment=NODE_ENV=production
135
-
136
- [Install]
137
- WantedBy=multi-user.target`;
394
+ const serviceContent = buildSystemdService({
395
+ ...launchOptions,
396
+ user: process.env.SUDO_USER || process.env.USER || 'root',
397
+ command: profile.command,
398
+ description: profile.description,
399
+ extraEnv: profile.extraEnv,
400
+ });
138
401
 
139
- fs.writeFileSync('/etc/systemd/system/telepty.service', serviceContent);
402
+ fs.writeFileSync(`/etc/systemd/system/${profile.systemdService}.service`, serviceContent);
140
403
  run('systemctl daemon-reload');
141
- run('systemctl enable telepty');
142
- run('systemctl start telepty');
404
+ run(`systemctl enable ${profile.systemdService}`);
405
+ run(`systemctl start ${profile.systemdService}`);
406
+ assertSystemdServiceLive(profile.systemdService);
143
407
  console.log("โœ… Systemd service installed and started.");
144
408
  process.exit(0);
145
409
  }
146
- } catch(e) {}
147
410
 
148
- // Fallback for Linux without systemd or non-root
149
- console.log("โš ๏ธ Skipping systemd (no root or no systemd). Starting in background...");
411
+ console.log("โš™๏ธ Setting up user systemd service for Linux...");
412
+ const userServicePath = path.join(os.homedir(), '.config', 'systemd', 'user', `${profile.systemdService}.service`);
413
+ fs.mkdirSync(path.dirname(userServicePath), { recursive: true });
414
+ cleanupLocalDaemons();
415
+ fs.writeFileSync(userServicePath, buildSystemdService({
416
+ ...launchOptions,
417
+ wantedBy: 'default.target',
418
+ command: profile.command,
419
+ description: profile.description,
420
+ extraEnv: profile.extraEnv,
421
+ }));
422
+ run('systemctl --user daemon-reload');
423
+ run(`systemctl --user enable ${profile.systemdService}`);
424
+ run(`systemctl --user start ${profile.systemdService}`);
425
+ assertSystemdServiceLive(profile.systemdService, { user: true });
426
+ console.log("โœ… User systemd service installed and started.");
427
+ process.exit(0);
428
+ }
429
+
430
+ // Fallback for Linux without systemd
431
+ console.log("โš ๏ธ Skipping persistent systemd setup. Starting daemon for this session only...");
150
432
  cleanupLocalDaemons();
151
- const subprocess = spawn(teleptyPath, ['daemon'], {
433
+ const subprocess = spawn(launchOptions.nodeBin, [launchOptions.cliJs, profile.command], {
152
434
  detached: true,
153
- stdio: 'ignore'
435
+ stdio: 'ignore',
436
+ env: { ...process.env, ...profile.extraEnv }
154
437
  });
155
438
  subprocess.unref();
156
- console.log("โœ… Linux daemon started in background using nohup equivalent.");
439
+ console.log("โœ… Linux daemon started in background for the current session.");
157
440
  }
158
441
 
159
442
  console.log("\n๐ŸŽ‰ Installation complete! Telepty daemon is running.");
160
443
  console.log("๐Ÿ‘‰ Try running: telepty attach\n");
161
- })();
444
+ }
445
+
446
+ if (require.main === module) {
447
+ main().catch((e) => {
448
+ console.error('โŒ Installation failed:', e.message);
449
+ process.exit(1);
450
+ });
451
+ }
452
+
453
+ module.exports = {
454
+ buildLaunchdPlist,
455
+ buildSystemdService,
456
+ buildWindowsAutostartCommand,
457
+ resolveDaemonLaunchOptions,
458
+ buildBrokerLaunchdPlist,
459
+ buildBrokerSystemdService,
460
+ buildBrokerWindowsAutostartCommand,
461
+ collectBrokerServiceEnv,
462
+ resolveServiceProfile,
463
+ BROKER_LAUNCHD_LABEL,
464
+ BROKER_SYSTEMD_SERVICE,
465
+ BROKER_WINDOWS_TASK,
466
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aigentry-telepty",
3
- "version": "0.5.8",
3
+ "version": "0.6.0",
4
4
  "main": "daemon.js",
5
5
  "bin": {
6
6
  "aigentry-telepty": "install.js",
@@ -35,9 +35,9 @@
35
35
  ],
36
36
  "scripts": {
37
37
  "postinstall": "node scripts/postinstall.js",
38
- "test": "node --require ./test-support/setup-env.js --test test/auth.test.js test/http-auth.test.js test/daemon.test.js test/daemon-singleton.test.js test/integration/daemon-launch.test.js test/cli.test.js test/telepty-kill.test.js test/idle-ttl.test.js test/telepty-clean-older-than.test.js test/lifecycle-transport-agnostic.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js test/session-state.test.js test/session-store-persistence.test.js test/mailbox-lock.test.js test/report-enforcement.test.js test/enforce-report.test.js test/peer-inject-validator.test.js test/enforce-submit-gate.test.js test/submit-gate.test.js test/submit-via-pty.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/host-spec.test.js test/cross-host-inject.test.js test/cross-machine-ssh-routing.test.js test/init.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/banner-stderr-jq-safety.test.js test/bridge-supervisor-ipc.test.js test/bridge-j3-shim.test.js test/bridge-e2e.test.js test/release-0.4.5-bugfixes.test.js && git diff --exit-code tests/snippet-protocol/v1/",
39
- "test:watch": "node --require ./test-support/setup-env.js --test --watch test/auth.test.js test/http-auth.test.js test/daemon.test.js test/daemon-singleton.test.js test/integration/daemon-launch.test.js test/cli.test.js test/telepty-kill.test.js test/idle-ttl.test.js test/telepty-clean-older-than.test.js test/lifecycle-transport-agnostic.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js test/session-state.test.js test/session-store-persistence.test.js test/mailbox-lock.test.js test/report-enforcement.test.js test/enforce-report.test.js test/peer-inject-validator.test.js test/enforce-submit-gate.test.js test/submit-gate.test.js test/submit-via-pty.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/host-spec.test.js test/cross-host-inject.test.js test/cross-machine-ssh-routing.test.js test/init.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/banner-stderr-jq-safety.test.js test/bridge-supervisor-ipc.test.js test/bridge-j3-shim.test.js test/bridge-e2e.test.js test/release-0.4.5-bugfixes.test.js",
40
- "test:ci": "node --require ./test-support/setup-env.js --test --test-reporter=spec test/auth.test.js test/http-auth.test.js test/daemon.test.js test/daemon-singleton.test.js test/integration/daemon-launch.test.js test/cli.test.js test/telepty-kill.test.js test/idle-ttl.test.js test/telepty-clean-older-than.test.js test/lifecycle-transport-agnostic.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js test/session-state.test.js test/session-store-persistence.test.js test/mailbox-lock.test.js test/report-enforcement.test.js test/enforce-report.test.js test/peer-inject-validator.test.js test/enforce-submit-gate.test.js test/submit-gate.test.js test/submit-via-pty.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/host-spec.test.js test/cross-host-inject.test.js test/cross-machine-ssh-routing.test.js test/init.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/banner-stderr-jq-safety.test.js test/bridge-supervisor-ipc.test.js test/bridge-j3-shim.test.js test/bridge-e2e.test.js test/release-0.4.5-bugfixes.test.js && git diff --exit-code tests/snippet-protocol/v1/",
38
+ "test": "node --require ./test-support/setup-env.js --test test/auth.test.js test/http-auth.test.js test/broker-protocol.test.js test/broker-auth.test.js test/broker-server.test.js test/broker-client.test.js test/daemon-broker-wiring.test.js test/broker-cli.test.js test/broker-integration.test.js test/daemon.test.js test/daemon-singleton.test.js test/integration/daemon-launch.test.js test/cli.test.js test/telepty-kill.test.js test/idle-ttl.test.js test/telepty-clean-older-than.test.js test/lifecycle-transport-agnostic.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js test/session-state.test.js test/session-store-persistence.test.js test/mailbox-lock.test.js test/report-enforcement.test.js test/enforce-report.test.js test/peer-inject-validator.test.js test/enforce-submit-gate.test.js test/submit-gate.test.js test/submit-via-pty.test.js test/submit-render-gate.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/host-spec.test.js test/cross-host-inject.test.js test/cross-machine-ssh-routing.test.js test/init.test.js test/install-service-generation.test.js test/install-broker-service.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/banner-stderr-jq-safety.test.js test/bridge-supervisor-ipc.test.js test/bridge-j3-shim.test.js test/bridge-e2e.test.js test/release-0.4.5-bugfixes.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js && git diff --exit-code tests/snippet-protocol/v1/",
39
+ "test:watch": "node --require ./test-support/setup-env.js --test --watch test/auth.test.js test/http-auth.test.js test/broker-protocol.test.js test/broker-auth.test.js test/broker-server.test.js test/broker-client.test.js test/daemon-broker-wiring.test.js test/broker-cli.test.js test/broker-integration.test.js test/daemon.test.js test/daemon-singleton.test.js test/integration/daemon-launch.test.js test/cli.test.js test/telepty-kill.test.js test/idle-ttl.test.js test/telepty-clean-older-than.test.js test/lifecycle-transport-agnostic.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js test/session-state.test.js test/session-store-persistence.test.js test/mailbox-lock.test.js test/report-enforcement.test.js test/enforce-report.test.js test/peer-inject-validator.test.js test/enforce-submit-gate.test.js test/submit-gate.test.js test/submit-via-pty.test.js test/submit-render-gate.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/host-spec.test.js test/cross-host-inject.test.js test/cross-machine-ssh-routing.test.js test/init.test.js test/install-service-generation.test.js test/install-broker-service.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/banner-stderr-jq-safety.test.js test/bridge-supervisor-ipc.test.js test/bridge-j3-shim.test.js test/bridge-e2e.test.js test/release-0.4.5-bugfixes.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js",
40
+ "test:ci": "node --require ./test-support/setup-env.js --test --test-reporter=spec test/auth.test.js test/http-auth.test.js test/broker-protocol.test.js test/broker-auth.test.js test/broker-server.test.js test/broker-client.test.js test/daemon-broker-wiring.test.js test/broker-cli.test.js test/broker-integration.test.js test/daemon.test.js test/daemon-singleton.test.js test/integration/daemon-launch.test.js test/cli.test.js test/telepty-kill.test.js test/idle-ttl.test.js test/telepty-clean-older-than.test.js test/lifecycle-transport-agnostic.test.js test/skill-installer.test.js test/interactive-terminal.test.js test/runtime-info.test.js test/session-routing.test.js test/session-state.test.js test/session-store-persistence.test.js test/mailbox-lock.test.js test/report-enforcement.test.js test/enforce-report.test.js test/peer-inject-validator.test.js test/enforce-submit-gate.test.js test/submit-gate.test.js test/submit-via-pty.test.js test/submit-render-gate.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/host-spec.test.js test/cross-host-inject.test.js test/cross-machine-ssh-routing.test.js test/init.test.js test/install-service-generation.test.js test/install-broker-service.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/banner-stderr-jq-safety.test.js test/bridge-supervisor-ipc.test.js test/bridge-j3-shim.test.js test/bridge-e2e.test.js test/release-0.4.5-bugfixes.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js && git diff --exit-code tests/snippet-protocol/v1/",
41
41
  "typecheck": "tsc --noEmit",
42
42
  "regen-fixtures": "node scripts/regen-snippet-fixtures.js"
43
43
  },
@@ -59,7 +59,7 @@
59
59
  ],
60
60
  "author": "dmsdc-ai",
61
61
  "license": "ISC",
62
- "description": "Universal terminal session bridge โ€” connect any terminal to any terminal, any machine",
62
+ "description": "Universal terminal session bridge \u2014 connect any terminal to any terminal, any machine",
63
63
  "repository": {
64
64
  "type": "git",
65
65
  "url": "git+https://github.com/dmsdc-ai/aigentry-telepty.git"