@dmsdc-ai/aigentry-telepty 0.5.3 → 0.5.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/daemon.js +52 -12
- package/package.json +4 -4
- package/src/submit-gate.js +9 -3
package/daemon.js
CHANGED
|
@@ -298,9 +298,20 @@ function fireAutoReport(targetId, targetSession, pendingReport, trigger, deps =
|
|
|
298
298
|
const srcSession = _sessions[srcId];
|
|
299
299
|
if (!srcSession) return;
|
|
300
300
|
|
|
301
|
+
// #537 / Bug B: a never-started worker (transient submit failure → claude startup
|
|
302
|
+
// busy→idle settle at ~4.5s) must NOT be reported TASK_COMPLETE. When a submit was
|
|
303
|
+
// expected, the elapsed floor and startup-polluted sawWorkingAfterInject are NOT trusted
|
|
304
|
+
// as proof of processing — require positive submit confirmation (screen-poll verify /
|
|
305
|
+
// honest force / gate-off). Paths with no submit expected keep the legacy floor/work rule.
|
|
306
|
+
const strongSubmitConfirmed = !!(
|
|
307
|
+
pendingReport.submitConfirmedAt ||
|
|
308
|
+
(pendingReport.submitConfirm && pendingReport.submitConfirm.accepted === true)
|
|
309
|
+
);
|
|
301
310
|
const confirmed = trigger === 'ready-signal' && pendingReport.submitExpected
|
|
302
311
|
? false
|
|
303
|
-
:
|
|
312
|
+
: pendingReport.submitExpected
|
|
313
|
+
? strongSubmitConfirmed
|
|
314
|
+
: (elapsedNum >= AUTO_REPORT_MIN_REAL_SECONDS || hasSubmitEvidence);
|
|
304
315
|
const injTag = pendingReport.injectId ? ` inject=${pendingReport.injectId}` : '';
|
|
305
316
|
const reportMsg = confirmed
|
|
306
317
|
? `TASK_COMPLETE: ${targetId} is now idle after processing inject (${elapsed}s, via ${trigger}${injTag})`
|
|
@@ -1169,21 +1180,39 @@ async function writeDataToSession(id, session, data) {
|
|
|
1169
1180
|
}
|
|
1170
1181
|
|
|
1171
1182
|
/**
|
|
1172
|
-
* Submit Enter to a session
|
|
1183
|
+
* Submit Enter to a session via the PTY/context layer.
|
|
1173
1184
|
* Used by POST /submit endpoint for explicit terminal-level submit.
|
|
1174
|
-
*
|
|
1175
|
-
*
|
|
1185
|
+
*
|
|
1186
|
+
* Submit is a CONTEXT operation (telepty-owned), not a SURFACE operation
|
|
1187
|
+
* (cmux/kitty adaptor-owned). Deliver the submit Enter via the PTY only — a bare
|
|
1188
|
+
* 0x0D into the CLI's innermost node-pty. The former kitty `send-text` (P1) and
|
|
1189
|
+
* `cmux send-key` (P2) branches were SURFACE ops on a flaky side channel (75×
|
|
1190
|
+
* "Failed to write to socket" vs 0× for pty_cr in a 222k-line run; live
|
|
1191
|
+
* 2026-06-07 confirmed pty-only works 3/3). `submitViaCmux`/`sendViaKitty` defs
|
|
1192
|
+
* are kept (non-submit callers); codebase removal is gated on the warp/tmux
|
|
1193
|
+
* matrix. See docs/adr/2026-06-07-submit-via-pty-context-layer.md.
|
|
1194
|
+
*
|
|
1195
|
+
* Returns the strategy name ('pty_cr') or null on failure.
|
|
1176
1196
|
*/
|
|
1177
1197
|
function terminalLevelSubmit(id, session) {
|
|
1178
|
-
// Priority 1: kitty send-text (terminal-level, bypasses PTY raw mode quirks)
|
|
1179
|
-
if (session.type === 'wrapped' && sendViaKitty(id, '\r')) return 'kitty';
|
|
1180
|
-
// Priority 2: cmux send-key
|
|
1181
|
-
if (session.backend === 'cmux' && session.cmuxWorkspaceId && submitViaCmux(id)) return 'cmux';
|
|
1182
|
-
// Priority 3: PTY \r
|
|
1183
1198
|
if (submitViaPty(session)) return 'pty_cr';
|
|
1184
1199
|
return null;
|
|
1185
1200
|
}
|
|
1186
1201
|
|
|
1202
|
+
// #544 / #537 / Bug B: with PTY-native submit (terminalLevelSubmit → pty_cr only),
|
|
1203
|
+
// a successful pty_cr IS real delivery on every backend — the bare 0x0D reaches the
|
|
1204
|
+
// CLI's innermost node-pty directly (live 2026-06-07: pty-only delivered 3/3 even
|
|
1205
|
+
// when cmux send-key failed). The honest "was it accepted?" signal is the
|
|
1206
|
+
// PTY-derived confirm (confirmSubmitAccepted: state∈{working,thinking} since≥
|
|
1207
|
+
// submittedAt, or body consumed from outputRing) — NOT the strategy name. We no
|
|
1208
|
+
// longer special-case pty_cr-on-cmux as undelivered; that false-negative was the
|
|
1209
|
+
// direct cause of the BUG B bogus UNCONFIRMED reports + worker re-send loops.
|
|
1210
|
+
// Pure + exported so the decision is unit-testable.
|
|
1211
|
+
// See docs/adr/2026-06-07-submit-via-pty-context-layer.md.
|
|
1212
|
+
function forceSubmitDeliveredToSurface(session, strategy) {
|
|
1213
|
+
return !!strategy;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1187
1216
|
async function deliverInjectionToSession(id, session, prompt, options = {}) {
|
|
1188
1217
|
const now = Date.now();
|
|
1189
1218
|
if (!options.bypassBootstrapQueue && shouldQueueBootstrapOperation(session)) {
|
|
@@ -2190,11 +2219,19 @@ app.post('/api/sessions/:id/submit', async (req, res) => {
|
|
|
2190
2219
|
}
|
|
2191
2220
|
const strategy = terminalLevelSubmit(id, session);
|
|
2192
2221
|
if (strategy) {
|
|
2222
|
+
// #537 / Bug B: force-confirm must reflect ACTUAL delivery. A pty_cr fallback on a
|
|
2223
|
+
// cmux surface means cmux send-key failed and Enter never reached the CLI — record
|
|
2224
|
+
// UNCONFIRMED so the ENFORCE-REPORT gate never labels a never-delivered inject DONE.
|
|
2225
|
+
const deliveredToSurface = forceSubmitDeliveredToSurface(session, strategy);
|
|
2193
2226
|
if (injectedBody) {
|
|
2194
|
-
|
|
2227
|
+
if (deliveredToSurface) {
|
|
2228
|
+
markPendingReportSubmitConfirmed(id, { reason: 'force', attempts: 1 });
|
|
2229
|
+
} else {
|
|
2230
|
+
markPendingReportSubmitUnconfirmed(id, { reason: 'cmux_send_failed', attempts: 1, retryable: true });
|
|
2231
|
+
}
|
|
2195
2232
|
}
|
|
2196
|
-
emitSubmitBus({ strategy, attempts: 1, gated: false, forced: true });
|
|
2197
|
-
return res.json({ success: true, strategy, attempts: 1, gated: false, forced: true });
|
|
2233
|
+
emitSubmitBus({ strategy, attempts: 1, gated: false, forced: true, submit_confirmed: deliveredToSurface });
|
|
2234
|
+
return res.json({ success: true, strategy, attempts: 1, gated: false, forced: true, submit_confirmed: deliveredToSurface });
|
|
2198
2235
|
}
|
|
2199
2236
|
if (injectedBody) {
|
|
2200
2237
|
markPendingReportSubmitUnconfirmed(id, { reason: 'strategy_failed', attempts: 0, retryable: false });
|
|
@@ -3488,6 +3525,9 @@ if (require.main === module) {
|
|
|
3488
3525
|
// production call sites is unchanged. NOT a public API — internal/test use only.
|
|
3489
3526
|
module.exports = {
|
|
3490
3527
|
fireAutoReport, // #32: provenance-tagged auto-report (deps DI: now/deliver/...)
|
|
3528
|
+
forceSubmitDeliveredToSurface, // #544/#537/Bug B: PTY-native force-confirm (pty_cr = delivered)
|
|
3529
|
+
terminalLevelSubmit, // #544: PTY-only submit path (pty_cr | null)
|
|
3530
|
+
submitViaPty, // #544: bare-0x0D submit into the innermost node-pty
|
|
3491
3531
|
failBootstrapQueueOnTimeout, // #31: actionable bootstrap-timeout queue flush
|
|
3492
3532
|
shouldApplyOwnerAliveFloor, // #29: owner-alive optimistic-floor decision (deps DI: isProcessRunning/...)
|
|
3493
3533
|
scheduleBootstrapPromptPoll, // #29: arms the floor timer (deps DI: setTimeout/...)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmsdc-ai/aigentry-telepty",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
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 --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/submit-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/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 --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/submit-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/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 --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/submit-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/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 --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/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 --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/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 --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/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/",
|
|
41
41
|
"typecheck": "tsc --noEmit",
|
|
42
42
|
"regen-fixtures": "node scripts/regen-snippet-fixtures.js"
|
|
43
43
|
},
|
package/src/submit-gate.js
CHANGED
|
@@ -308,10 +308,16 @@ function observeBodyVisibility(session, bodyText, opts = {}) {
|
|
|
308
308
|
};
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
// PTY-native confirm (#544): do NOT shell to `cmux read-screen` for the submit
|
|
312
|
+
// confirm. The body-visibility source is the PTY-fed outputRing
|
|
313
|
+
// (observeBodyVisibility falls through to it when this returns null). An explicit
|
|
314
|
+
// opts.readScreen seam is still honored (tests / future surface adaptors); the
|
|
315
|
+
// cmux default is dropped so confirmation is screen-free and no longer depends on
|
|
316
|
+
// the flaky cmux surface. The pre-submit readiness probe (awaitPromptSymbol) keeps
|
|
317
|
+
// its own defaultReadScreen — that is a separate concern, out of scope here.
|
|
318
|
+
// See docs/adr/2026-06-07-submit-via-pty-context-layer.md.
|
|
311
319
|
function readCurrentScreen(session, opts = {}) {
|
|
312
|
-
const readScreen = typeof opts.readScreen === 'function'
|
|
313
|
-
? opts.readScreen
|
|
314
|
-
: (session && session.backend === 'cmux' && session.cmuxWorkspaceId ? defaultReadScreen : null);
|
|
320
|
+
const readScreen = typeof opts.readScreen === 'function' ? opts.readScreen : null;
|
|
315
321
|
if (!readScreen || !session || !session.cmuxWorkspaceId) return null;
|
|
316
322
|
const tailLines = Number.isFinite(opts.tailLines) ? opts.tailLines : 30;
|
|
317
323
|
try {
|