@dmsdc-ai/aigentry-telepty 0.1.98 → 0.3.5
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/AGENTS.md +23 -0
- package/CHANGELOG.md +436 -0
- package/CLAUDE.md +5 -1
- package/README.md +70 -1
- package/cli.js +232 -53
- package/cross-machine.js +132 -0
- package/daemon.js +399 -39
- package/docs/reports/2026-05-05-issue-8-claude-review.md +194 -0
- package/docs/specs/2026-05-05-issue-8-telepty-init.md +477 -0
- package/docs/superpowers/specs/2026-04-26-inject-submit-enter-reliability.md +447 -0
- package/docs/superpowers/specs/2026-04-26-prompt-symbol-render-gate.md +571 -0
- package/docs/superpowers/specs/2026-04-26-submit-gate-fixes-v2.md +608 -0
- package/docs/superpowers/specs/2026-05-02-submit-force-and-retry.md +139 -0
- package/host-spec.js +60 -0
- package/mcp-server/index.mjs +24 -3
- package/package.json +6 -5
- package/scripts/regen-snippet-fixtures.js +42 -0
- package/skill-installer.js +42 -6
- package/skills/telepty/SKILL.md +1 -1
- package/skills/telepty-allow/SKILL.md +1 -1
- package/skills/telepty-attach/SKILL.md +1 -1
- package/skills/telepty-broadcast/SKILL.md +1 -1
- package/skills/telepty-daemon/SKILL.md +1 -1
- package/skills/telepty-inject/SKILL.md +76 -4
- package/skills/telepty-list/SKILL.md +1 -1
- package/skills/telepty-listen/SKILL.md +1 -1
- package/skills/telepty-rename/SKILL.md +1 -1
- package/skills/telepty-session/SKILL.md +1 -1
- package/specs/enforce-report-spec.md +237 -0
- package/src/init/print-snippet.js +114 -0
- package/src/init/snippets/agents.md +15 -0
- package/src/init/snippets/claude.md +15 -0
- package/src/init/snippets/gemini.md +15 -0
- package/src/prompt-symbol-registry.js +97 -0
- package/src/report-enforcement.js +86 -0
- package/src/submit-gate.js +269 -0
- package/tests/snippet-protocol/v1/golden-agents.json +1 -0
- package/tests/snippet-protocol/v1/golden-agents.md +17 -0
- package/tests/snippet-protocol/v1/golden-all.json +3 -0
- package/tests/snippet-protocol/v1/golden-all.md +53 -0
- package/tests/snippet-protocol/v1/golden-claude.json +1 -0
- package/tests/snippet-protocol/v1/golden-claude.md +17 -0
- package/tests/snippet-protocol/v1/golden-gemini.json +1 -0
- package/tests/snippet-protocol/v1/golden-gemini.md +17 -0
package/cross-machine.js
CHANGED
|
@@ -5,10 +5,16 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
7
|
const { getSharedContextPromptPath } = require('./shared-context');
|
|
8
|
+
const { parseHostSpec } = require('./host-spec');
|
|
8
9
|
|
|
9
10
|
const PEERS_PATH = path.join(os.homedir(), '.telepty', 'peers.json');
|
|
10
11
|
const CONTROL_DIR = path.join(os.homedir(), '.telepty', 'ssh');
|
|
11
12
|
|
|
13
|
+
function getPeerTransport(entry) {
|
|
14
|
+
if (!entry) return null;
|
|
15
|
+
return entry.transport || 'ssh';
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
// SSH ControlMaster socket path pattern
|
|
13
19
|
function controlPath(target) {
|
|
14
20
|
return path.join(CONTROL_DIR, `ctrl-${target.replace(/[^a-zA-Z0-9@.-]/g, '_')}`);
|
|
@@ -307,6 +313,126 @@ function removePeer(name) {
|
|
|
307
313
|
return { success: true };
|
|
308
314
|
}
|
|
309
315
|
|
|
316
|
+
// ── HTTP peer support (no SSH required) ─────────────────────────────────────
|
|
317
|
+
// connect-http records a remote daemon's host:port in peers.json with
|
|
318
|
+
// transport='http'. Subsequent inject/list calls discover sessions via the
|
|
319
|
+
// remote daemon's HTTP API directly. Built for laptop daemons where running
|
|
320
|
+
// sshd is not viable. See GitHub issue #13.
|
|
321
|
+
|
|
322
|
+
async function connectHttp(target, options = {}) {
|
|
323
|
+
const spec = parseHostSpec(target);
|
|
324
|
+
if (!spec.host) {
|
|
325
|
+
return { success: false, error: 'connect-http requires a host (got empty value).' };
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const name = options.name || spec.host.split('.')[0] || spec.host;
|
|
329
|
+
|
|
330
|
+
const headers = {};
|
|
331
|
+
if (options.token) headers['x-telepty-token'] = options.token;
|
|
332
|
+
|
|
333
|
+
let machineId = name;
|
|
334
|
+
let healthOk = false;
|
|
335
|
+
try {
|
|
336
|
+
const healthUrl = `http://${spec.host}:${spec.port}/api/health`;
|
|
337
|
+
const res = await fetch(healthUrl, { signal: AbortSignal.timeout(5000) });
|
|
338
|
+
if (!res.ok) {
|
|
339
|
+
return { success: false, error: `Daemon at ${spec.host}:${spec.port} returned HTTP ${res.status} on /api/health.` };
|
|
340
|
+
}
|
|
341
|
+
healthOk = true;
|
|
342
|
+
} catch (err) {
|
|
343
|
+
return { success: false, error: `Cannot reach daemon at ${spec.host}:${spec.port}: ${err.message}` };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
const metaUrl = `http://${spec.host}:${spec.port}/api/meta`;
|
|
348
|
+
const res = await fetch(metaUrl, { signal: AbortSignal.timeout(3000), headers });
|
|
349
|
+
if (res.ok) {
|
|
350
|
+
const meta = await res.json();
|
|
351
|
+
if (meta && typeof meta.machine_id === 'string' && meta.machine_id) {
|
|
352
|
+
machineId = meta.machine_id;
|
|
353
|
+
} else if (meta && typeof meta.host === 'string' && meta.host) {
|
|
354
|
+
machineId = meta.host;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} catch {
|
|
358
|
+
// /api/meta is auth-gated; failure is not fatal — health passed.
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const peers = loadPeers();
|
|
362
|
+
peers.peers[name] = {
|
|
363
|
+
transport: 'http',
|
|
364
|
+
host: spec.host,
|
|
365
|
+
port: spec.port,
|
|
366
|
+
target: `${spec.host}:${spec.port}`,
|
|
367
|
+
machineId,
|
|
368
|
+
lastConnected: new Date().toISOString()
|
|
369
|
+
};
|
|
370
|
+
if (options.token) {
|
|
371
|
+
peers.peers[name].token = options.token;
|
|
372
|
+
}
|
|
373
|
+
savePeers(peers);
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
success: true,
|
|
377
|
+
name,
|
|
378
|
+
host: spec.host,
|
|
379
|
+
port: spec.port,
|
|
380
|
+
machineId,
|
|
381
|
+
healthOk
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function listHttpPeers() {
|
|
386
|
+
const peers = loadPeers().peers || {};
|
|
387
|
+
return Object.entries(peers)
|
|
388
|
+
.filter(([, entry]) => getPeerTransport(entry) === 'http')
|
|
389
|
+
.map(([name, entry]) => ({
|
|
390
|
+
name,
|
|
391
|
+
host: entry.host,
|
|
392
|
+
port: entry.port,
|
|
393
|
+
machineId: entry.machineId,
|
|
394
|
+
lastConnected: entry.lastConnected,
|
|
395
|
+
hasToken: Boolean(entry.token)
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function listHttpRemoteSessions(name, options = {}) {
|
|
400
|
+
const peers = loadPeers().peers || {};
|
|
401
|
+
const entry = peers[name];
|
|
402
|
+
if (!entry || getPeerTransport(entry) !== 'http') return [];
|
|
403
|
+
|
|
404
|
+
const headers = {};
|
|
405
|
+
const token = options.token || entry.token;
|
|
406
|
+
if (token) headers['x-telepty-token'] = token;
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
const url = `http://${entry.host}:${entry.port}/api/sessions`;
|
|
410
|
+
const res = await fetch(url, {
|
|
411
|
+
signal: AbortSignal.timeout(options.timeoutMs || 3000),
|
|
412
|
+
headers
|
|
413
|
+
});
|
|
414
|
+
if (!res.ok) return [];
|
|
415
|
+
const sessions = await res.json();
|
|
416
|
+
if (!Array.isArray(sessions)) return [];
|
|
417
|
+
return sessions.map((s) => ({
|
|
418
|
+
...s,
|
|
419
|
+
host: `${entry.host}:${entry.port}`,
|
|
420
|
+
peerName: name,
|
|
421
|
+
peerPort: entry.port
|
|
422
|
+
}));
|
|
423
|
+
} catch {
|
|
424
|
+
return [];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async function discoverHttpRemoteSessions(options = {}) {
|
|
429
|
+
const peers = listHttpPeers();
|
|
430
|
+
const results = await Promise.all(
|
|
431
|
+
peers.map((peer) => listHttpRemoteSessions(peer.name, options))
|
|
432
|
+
);
|
|
433
|
+
return results.flat();
|
|
434
|
+
}
|
|
435
|
+
|
|
310
436
|
module.exports = {
|
|
311
437
|
connect,
|
|
312
438
|
disconnect,
|
|
@@ -323,5 +449,11 @@ module.exports = {
|
|
|
323
449
|
remoteEnsureSharedContext,
|
|
324
450
|
remoteAttach,
|
|
325
451
|
findSessionPeer,
|
|
452
|
+
// HTTP peer transport (no SSH required)
|
|
453
|
+
connectHttp,
|
|
454
|
+
listHttpPeers,
|
|
455
|
+
listHttpRemoteSessions,
|
|
456
|
+
discoverHttpRemoteSessions,
|
|
457
|
+
getPeerTransport,
|
|
326
458
|
PEERS_PATH
|
|
327
459
|
};
|