@dmsdc-ai/aigentry-telepty 0.5.1 → 0.5.2
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/CHANGELOG.md +14 -0
- package/cli.js +23 -122
- package/daemon.js +320 -428
- package/package.json +9 -4
- package/src/cli/session-view.js +100 -0
- package/src/lifecycle.js +114 -1
- package/src/protocol/http-auth.js +71 -0
- package/src/session-store/persistence.js +88 -0
- package/src/submit-gate.js +157 -0
- package/src/transport/peer-relay.js +51 -0
- package/src/transport/websocket.js +287 -0
- package/terminal-backend.js +339 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to `@dmsdc-ai/aigentry-telepty` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.2] - 2026-06-06
|
|
8
|
+
|
|
9
|
+
### Fixed — submit handshake confirmation (#507-B / #508)
|
|
10
|
+
|
|
11
|
+
- **`--submit` Enter sometimes did not register in a CLI's TUI** (the recurring
|
|
12
|
+
"Enter 안눌림" bug). `inject --submit` wrote the carriage return but did not
|
|
13
|
+
confirm the target actually consumed it, so under timing pressure the submit
|
|
14
|
+
could be dropped and the injected prompt left sitting unsubmitted. **Fix:** a
|
|
15
|
+
submit-gate handshake in `src/submit-gate.js` confirms the submit landed, with
|
|
16
|
+
`cli.js` / `daemon.js` wiring the gate into the inject path. Landed on `main`
|
|
17
|
+
at commit `2a21265`. This release ships that already-tested fix (npm 0.5.1
|
|
18
|
+
still served the pre-fix code; the running daemon must be restarted separately
|
|
19
|
+
to pick it up). (telepty#512)
|
|
20
|
+
|
|
7
21
|
## [0.5.1] - 2026-05-30
|
|
8
22
|
|
|
9
23
|
### Fixed — daemon never started (CRITICAL, regresses 0.5.0)
|
package/cli.js
CHANGED
|
@@ -17,6 +17,13 @@ const { getRuntimeInfo } = require('./runtime-info');
|
|
|
17
17
|
const { formatHostLabel, groupSessionsByHost, pickSessionTarget } = require('./session-routing');
|
|
18
18
|
const { buildSharedContextPrompt, createSharedContextDescriptor, ensureSharedContextFile } = require('./shared-context');
|
|
19
19
|
const { runInteractiveSkillInstaller } = require('./skill-installer');
|
|
20
|
+
const {
|
|
21
|
+
detectTerminalProgram,
|
|
22
|
+
formatSessionTerminal,
|
|
23
|
+
enrichSessionIdle,
|
|
24
|
+
formatSessionStatusWithIdle,
|
|
25
|
+
printSessionInfo
|
|
26
|
+
} = require('./src/cli/session-view');
|
|
20
27
|
const { resolveWindowsExecutable } = require('./src/win-resolve-executable');
|
|
21
28
|
const { decideVersionAction } = require('./src/version-handshake');
|
|
22
29
|
const crossMachine = require('./cross-machine');
|
|
@@ -176,62 +183,6 @@ async function getDaemonMeta(host = REMOTE_HOST) {
|
|
|
176
183
|
}
|
|
177
184
|
}
|
|
178
185
|
|
|
179
|
-
function detectTerminalProgram(env = process.env) {
|
|
180
|
-
const rawTermProgram = typeof env.TERM_PROGRAM === 'string' ? env.TERM_PROGRAM.trim() : '';
|
|
181
|
-
if (rawTermProgram) {
|
|
182
|
-
return rawTermProgram;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (env.TMUX) {
|
|
186
|
-
return 'tmux';
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const term = typeof env.TERM === 'string' ? env.TERM.toLowerCase() : '';
|
|
190
|
-
if (term.includes('kitty')) return 'kitty';
|
|
191
|
-
if (term.includes('ghostty')) return 'ghostty';
|
|
192
|
-
if (term.includes('tmux')) return 'tmux';
|
|
193
|
-
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function formatSessionTerminal(session) {
|
|
198
|
-
const terminal = session.terminal || session.termProgram || null;
|
|
199
|
-
const term = session.term || null;
|
|
200
|
-
if (terminal && term) {
|
|
201
|
-
return `${terminal} (${term})`;
|
|
202
|
-
}
|
|
203
|
-
return terminal || term || 'unknown';
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function formatSessionHealth(session) {
|
|
207
|
-
const status = session.healthStatus || 'UNKNOWN';
|
|
208
|
-
const reason = session.healthReason || null;
|
|
209
|
-
if (reason && reason !== status) {
|
|
210
|
-
return `${status} (${reason})`;
|
|
211
|
-
}
|
|
212
|
-
return status;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function enrichSessionIdle(session, nowMs = Date.now()) {
|
|
216
|
-
const idleSeconds = typeof session.idleSeconds === 'number'
|
|
217
|
-
? session.idleSeconds
|
|
218
|
-
: lifecycle.computeIdleSeconds(session.lastActivityAt, nowMs);
|
|
219
|
-
return {
|
|
220
|
-
...session,
|
|
221
|
-
idleSeconds,
|
|
222
|
-
idle_seconds: idleSeconds
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function formatSessionStatusWithIdle(session) {
|
|
227
|
-
const base = formatSessionHealth(session);
|
|
228
|
-
const idleSeconds = typeof session.idleSeconds === 'number' ? session.idleSeconds : null;
|
|
229
|
-
if (idleSeconds !== null && idleSeconds > 60) {
|
|
230
|
-
return `${base} 💤 idle (${lifecycle.formatIdleDuration(idleSeconds)})`;
|
|
231
|
-
}
|
|
232
|
-
return base;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
186
|
function formatApiError(data, fallback = 'Request failed.') {
|
|
236
187
|
if (!data) {
|
|
237
188
|
return fallback;
|
|
@@ -352,39 +303,6 @@ function ensureRemoteSharedReference(peerName, descriptor, message = '') {
|
|
|
352
303
|
};
|
|
353
304
|
}
|
|
354
305
|
|
|
355
|
-
function printSessionInfo(session, options = {}) {
|
|
356
|
-
const host = options.host || session.host || '127.0.0.1';
|
|
357
|
-
console.log('\x1b[1mSession Info:\x1b[0m');
|
|
358
|
-
console.log(` - ID: \x1b[36m${session.id}\x1b[0m`);
|
|
359
|
-
console.log(` Host: ${formatHostLabel(host)}`);
|
|
360
|
-
console.log(` Command: ${session.command}`);
|
|
361
|
-
console.log(` Type: ${session.type || 'unknown'}`);
|
|
362
|
-
console.log(` Status: ${formatSessionHealth(session)}`);
|
|
363
|
-
console.log(` Terminal: ${session.terminal || session.termProgram || 'unknown'}`);
|
|
364
|
-
console.log(` TERM: ${session.term || 'n/a'}`);
|
|
365
|
-
console.log(` CWD: ${session.cwd}`);
|
|
366
|
-
console.log(` Clients: ${session.active_clients ?? 0}`);
|
|
367
|
-
if (session.createdAt) {
|
|
368
|
-
console.log(` Started: ${new Date(session.createdAt).toLocaleString()}`);
|
|
369
|
-
}
|
|
370
|
-
if (session.lastActivityAt) {
|
|
371
|
-
console.log(` Last Activity: ${new Date(session.lastActivityAt).toLocaleString()}`);
|
|
372
|
-
}
|
|
373
|
-
if (typeof session.idleSeconds === 'number') {
|
|
374
|
-
console.log(` Idle: ${session.idleSeconds}s`);
|
|
375
|
-
}
|
|
376
|
-
if (session.semantic && session.semantic.phase) {
|
|
377
|
-
console.log(` Phase: ${session.semantic.phase}`);
|
|
378
|
-
}
|
|
379
|
-
if (session.semantic && session.semantic.current_task) {
|
|
380
|
-
console.log(` Current Task: ${session.semantic.current_task}`);
|
|
381
|
-
}
|
|
382
|
-
if (session.semantic && session.semantic.blocker) {
|
|
383
|
-
console.log(` Blocker: ${session.semantic.blocker}`);
|
|
384
|
-
}
|
|
385
|
-
console.log('');
|
|
386
|
-
}
|
|
387
|
-
|
|
388
306
|
function resolveTeleptyEntryPoint() {
|
|
389
307
|
// After npm upgrade, process.argv[1] still points to the OLD version's cli.js.
|
|
390
308
|
// Resolve the current telepty binary from PATH, which npm updates on install.
|
|
@@ -1954,43 +1872,26 @@ async function main() {
|
|
|
1954
1872
|
}
|
|
1955
1873
|
const submitBody = {
|
|
1956
1874
|
injected_body: injectPrompt || '',
|
|
1957
|
-
retries:
|
|
1875
|
+
retries: submitRetries,
|
|
1958
1876
|
retry_delay_ms: 500,
|
|
1959
1877
|
...(submitForce ? { force: true } : {}),
|
|
1960
1878
|
};
|
|
1961
|
-
const RETRY_DELAY_MS = 300;
|
|
1962
|
-
const RETRY_SAFE_REASONS = new Set([
|
|
1963
|
-
'gated_dispatch_unconsumed',
|
|
1964
|
-
'gate_timeout',
|
|
1965
|
-
'no_prompt_symbol_seen',
|
|
1966
|
-
]);
|
|
1967
|
-
const maxAttempts = 1 + submitRetries;
|
|
1968
1879
|
let submitRes = null;
|
|
1969
1880
|
let submitData = null;
|
|
1970
1881
|
let attemptsMade = 0;
|
|
1971
1882
|
let lastError = null;
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
} catch (submitErr) {
|
|
1985
|
-
lastError = submitErr;
|
|
1986
|
-
submitRes = null;
|
|
1987
|
-
submitData = null;
|
|
1988
|
-
break;
|
|
1989
|
-
}
|
|
1990
|
-
if (submitRes.ok) break;
|
|
1991
|
-
if (submitRes.status !== 504) break;
|
|
1992
|
-
const retryReason = submitData && typeof submitData.reason === 'string' ? submitData.reason : null;
|
|
1993
|
-
if (!RETRY_SAFE_REASONS.has(retryReason)) break;
|
|
1883
|
+
try {
|
|
1884
|
+
attemptsMade = 1;
|
|
1885
|
+
submitRes = await fetchWithAuth(`${daemonUrl(target.host)}/api/sessions/${encodeURIComponent(target.id)}/submit`, {
|
|
1886
|
+
method: 'POST',
|
|
1887
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1888
|
+
body: JSON.stringify(submitBody),
|
|
1889
|
+
});
|
|
1890
|
+
submitData = await submitRes.json();
|
|
1891
|
+
} catch (submitErr) {
|
|
1892
|
+
lastError = submitErr;
|
|
1893
|
+
submitRes = null;
|
|
1894
|
+
submitData = null;
|
|
1994
1895
|
}
|
|
1995
1896
|
if (lastError) {
|
|
1996
1897
|
console.error(`⚠️ Submit failed: ${lastError.message}`);
|
|
@@ -2002,16 +1903,16 @@ async function main() {
|
|
|
2002
1903
|
? ' (dispatched-after-gate-timeout)'
|
|
2003
1904
|
: '';
|
|
2004
1905
|
const attemptsNote = submitData.attempts > 1 ? ` (${submitData.attempts} attempts)` : '';
|
|
2005
|
-
const retryNote = attemptsMade > 1 ? ` [retry ${attemptsMade - 1}/${submitRetries}]` : '';
|
|
2006
1906
|
const forcedNote = submitData.forced ? ' [forced]' : '';
|
|
2007
|
-
console.log(`✅ Submitted via ${submitData.strategy}${attemptsNote}${gateNote}${lateNote}${
|
|
1907
|
+
console.log(`✅ Submitted via ${submitData.strategy}${attemptsNote}${gateNote}${lateNote}${forcedNote}.`);
|
|
2008
1908
|
} else if (submitRes && submitRes.status === 504) {
|
|
2009
1909
|
// Soft failure: REPL never readied. Orchestrator scripts depend on
|
|
2010
1910
|
// exit 0 here — surface a clear remediation hint but do not exit
|
|
2011
1911
|
// non-zero.
|
|
2012
1912
|
const reason = (submitData && submitData.reason) || 'gate_timeout';
|
|
2013
1913
|
const lastState = (submitData && submitData.last_state) || 'unknown';
|
|
2014
|
-
const
|
|
1914
|
+
const daemonAttempts = submitData && Number.isFinite(Number(submitData.attempts)) ? Number(submitData.attempts) : attemptsMade;
|
|
1915
|
+
const retriesNote = daemonAttempts > 1 ? ` after ${daemonAttempts} attempts` : '';
|
|
2015
1916
|
const hint = submitForce
|
|
2016
1917
|
? ''
|
|
2017
1918
|
: ` Try \`telepty inject --submit --submit-force ${target.id} ...\` or manual \`telepty send-key ${target.id} enter\`.`;
|