@dmsdc-ai/aigentry-telepty 0.6.9 → 0.6.10
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 +18 -0
- package/README.md +1 -1
- package/cli.js +10 -2
- package/daemon.js +48 -7
- package/package.json +4 -4
- package/src/submit-gate.js +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,8 @@ All notable changes to `@dmsdc-ai/aigentry-telepty` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.6.10] - 2026-07-05
|
|
8
|
+
|
|
7
9
|
### Added — seamless cross-machine on Tailscale (auto bind + auto trust) (#672)
|
|
8
10
|
|
|
9
11
|
- **On a Tailscale host, a fresh install is cross-machine-ready with zero manual env.** At
|
|
@@ -31,6 +33,22 @@ All notable changes to `@dmsdc-ai/aigentry-telepty` are documented here.
|
|
|
31
33
|
Zero-config cross-machine is Tailscale-specific; other topologies use the manual
|
|
32
34
|
`TELEPTY_BIND` path. Addressing stays IP-free — use MagicDNS names with `<id>@<host>`.
|
|
33
35
|
|
|
36
|
+
### Fixed — busy-target `--submit` latency (busy-dispatch fast-path) (#694)
|
|
37
|
+
|
|
38
|
+
- **A gated `--submit` to a BUSY (mid-turn) recipient no longer burns the full gate timeout.**
|
|
39
|
+
A busy claude sits in `working`/`thinking` — neither is a ready state — so the render-gate
|
|
40
|
+
(`awaitReplReady`) could never pass mid-turn and waited out the entire `gate_timeout_ms`
|
|
41
|
+
(default 10s) before dispatching best-effort. A new busy-dispatch fast-path detects a
|
|
42
|
+
**genuine ongoing turn** (`working`/`thinking` held ≥ `TELEPTY_SUBMIT_BUSY_GRACE_MS`, default
|
|
43
|
+
250ms — which excludes the transient `working` a target emits while echoing our own
|
|
44
|
+
just-injected text) and dispatches after only the existing echo+micro-quiet settle
|
|
45
|
+
(`awaitInputSettled`), cutting the busy path from ~10s to **sub-second**.
|
|
46
|
+
- **Never fires blindly, idle path unchanged.** The downstream `gatedTerminalSubmit` still
|
|
47
|
+
runs its own echo+quiet gate before the `\r`; a CR into a busy composer merely queues and the
|
|
48
|
+
#617 hold-and-redeliver loop re-fires it on idle (delivery reliability unchanged). `idle`/
|
|
49
|
+
`waiting` targets never match the fast-path, so the proven idle behavior is byte-for-byte
|
|
50
|
+
identical. Rollback via `TELEPTY_SUBMIT_BUSY_DISPATCH=off`.
|
|
51
|
+
|
|
34
52
|
## [0.6.6] - 2026-06-14
|
|
35
53
|
|
|
36
54
|
### Fixed — duplicate same-id `allow` flap loop + `kill` doesn't stick (#56)
|
package/README.md
CHANGED
package/cli.js
CHANGED
|
@@ -2375,7 +2375,14 @@ async function main() {
|
|
|
2375
2375
|
const target = await resolveSessionTarget(sessionId);
|
|
2376
2376
|
if (!target) {
|
|
2377
2377
|
console.error(`❌ Session '${sessionId}' was not found on any discovered host.`);
|
|
2378
|
-
process.exit(
|
|
2378
|
+
// #691: drain-exit, do NOT process.exit() here. resolveSessionTarget →
|
|
2379
|
+
// discoverSessions() leaves undici keep-alive sockets and AbortSignal.timeout
|
|
2380
|
+
// timers still mid-close; a hard process.exit() races that teardown and trips a
|
|
2381
|
+
// libuv double-close assertion (src/win/async.c:76 UV_HANDLE_CLOSING) on Windows,
|
|
2382
|
+
// which wedges the session. Setting exitCode + returning lets the event loop close
|
|
2383
|
+
// each handle exactly once. Same exit code (1); success path unchanged.
|
|
2384
|
+
process.exitCode = 1;
|
|
2385
|
+
return;
|
|
2379
2386
|
}
|
|
2380
2387
|
|
|
2381
2388
|
let injectPrompt = prompt;
|
|
@@ -2388,7 +2395,8 @@ async function main() {
|
|
|
2388
2395
|
const ent = checkEntitlement({ feature: 'telepty.remote_sessions' });
|
|
2389
2396
|
if (!ent.allowed) {
|
|
2390
2397
|
console.error(`⚠️ ${ent.reason}\n Upgrade: ${ent.upgrade_url}`);
|
|
2391
|
-
process.exit(
|
|
2398
|
+
process.exitCode = 1; // #691: drain-exit (see not-found above), not process.exit() mid-teardown
|
|
2399
|
+
return;
|
|
2392
2400
|
}
|
|
2393
2401
|
|
|
2394
2402
|
if (useRef) {
|
package/daemon.js
CHANGED
|
@@ -53,6 +53,15 @@ const REDELIVER_ENABLED = String(process.env.TELEPTY_REDELIVER || '').toLowerCas
|
|
|
53
53
|
const REDELIVER_MAX_ATTEMPTS = Math.max(1, Number(process.env.TELEPTY_REDELIVER_MAX_ATTEMPTS || 3));
|
|
54
54
|
const REDELIVER_TOTAL_TIMEOUT_MS = Math.max(1000, Number(process.env.TELEPTY_REDELIVER_TOTAL_TIMEOUT_MS || 600000));
|
|
55
55
|
const REDELIVER_IDLE_WAIT_MS = Math.max(1000, Number(process.env.TELEPTY_REDELIVER_IDLE_WAIT_MS || 120000));
|
|
56
|
+
// #694: busy-dispatch fast-path — on a busy (mid-turn) recipient the render-gate (awaitReplReady)
|
|
57
|
+
// can never reach idle/waiting, so it burns the full gate timeout before best-effort dispatch.
|
|
58
|
+
// When enabled, a genuine ongoing turn (working/thinking held ≥ grace) dispatches after only the
|
|
59
|
+
// echo+micro-quiet settle instead of the full timeout. `off` restores the pure-idle-gate behavior.
|
|
60
|
+
const SUBMIT_BUSY_DISPATCH_ENABLED = String(process.env.TELEPTY_SUBMIT_BUSY_DISPATCH || '').toLowerCase() !== 'off';
|
|
61
|
+
// Grace floor separating a REAL ongoing turn from the transient `working` a target emits while
|
|
62
|
+
// echoing our OWN just-injected text (duration_ms ≈ 0). Default 250ms: above the echo transient,
|
|
63
|
+
// below any human-perceptible latency.
|
|
64
|
+
const SUBMIT_BUSY_GRACE_MS = Math.max(0, Number(process.env.TELEPTY_SUBMIT_BUSY_GRACE_MS || 250));
|
|
56
65
|
|
|
57
66
|
// Session state machine manager — auto-detects session state from PTY output
|
|
58
67
|
const sessionStateManager = new SessionStateManager({
|
|
@@ -1798,7 +1807,9 @@ function forceSubmitDeliveredToSurface(session, strategy) {
|
|
|
1798
1807
|
// PTY/ownerWs really is gone, submitViaPty returns false → a clean 503, not a false success).
|
|
1799
1808
|
// Only genuinely-terminal PTY states — session_dead / session_error / session_restarting — still
|
|
1800
1809
|
// short-circuit, because writing a CR to a dead/errored/restarting PTY is pointless.
|
|
1801
|
-
|
|
1810
|
+
// #694: `busy_settled` (busy-dispatch fast-path) joins the best-effort DISPATCH set — the target is
|
|
1811
|
+
// alive and mid-turn, so firing the CR is correct (it queues + #617 redelivers), never a hard-fail.
|
|
1812
|
+
const NON_TERMINAL_GATE_REASONS = new Set(['timeout', 'no_state', 'no_state_manager', 'busy_settled']);
|
|
1802
1813
|
function isTerminalGateFailure(gateResult) {
|
|
1803
1814
|
return !!(
|
|
1804
1815
|
gateResult &&
|
|
@@ -2843,8 +2854,10 @@ function submitViaOsascript(sessionId, keyCombo) {
|
|
|
2843
2854
|
// POST /api/sessions/:id/submit — render-gated CLI-aware submit
|
|
2844
2855
|
//
|
|
2845
2856
|
// Default behavior (0.3.0+): wait for the target REPL to be ready (sessionStateManager
|
|
2846
|
-
// reports `idle`/`waiting` with confidence ≥ 0.
|
|
2847
|
-
//
|
|
2857
|
+
// reports `idle`/`waiting` with confidence ≥ 0.5, the awaitReplReady default) before firing
|
|
2858
|
+
// Enter. #694: a BUSY recipient (working/thinking) is never idle/waiting, so the busy-dispatch
|
|
2859
|
+
// fast-path below dispatches best-effort after an echo+quiet settle instead of burning the gate
|
|
2860
|
+
// timeout. When the caller passes `injected_body`, also verify the body has been consumed (i.e.
|
|
2848
2861
|
// disappeared from the input box) by polling the session output ring; if still
|
|
2849
2862
|
// visible, perform one bounded retry.
|
|
2850
2863
|
//
|
|
@@ -3044,10 +3057,38 @@ app.post('/api/sessions/:id/submit', async (req, res) => {
|
|
|
3044
3057
|
// Hard-fail reasons (session_dead/error/restarting/no_state/no_state_manager)
|
|
3045
3058
|
// still short-circuit to 504 because dispatching to a dead/missing PTY is
|
|
3046
3059
|
// pointless. See spec §1.3 / §3.3.
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3060
|
+
//
|
|
3061
|
+
// #694 busy-dispatch fast-path: a BUSY (mid-turn) recipient sits in working/thinking — neither
|
|
3062
|
+
// is a READY_STATE — so awaitReplReady can never pass mid-turn and would burn the FULL
|
|
3063
|
+
// gateTimeoutMs (up to 10s) before best-effort dispatch. When the target is a GENUINE ongoing
|
|
3064
|
+
// turn (isBusyDispatchState: working/thinking held ≥ SUBMIT_BUSY_GRACE_MS, which excludes the
|
|
3065
|
+
// transient `working` from echoing our OWN just-injected text, duration_ms ≈ 0), wait ONLY for
|
|
3066
|
+
// the input to settle (body echoed + micro-quiet, via awaitInputSettled) and dispatch
|
|
3067
|
+
// best-effort — the same downstream path as a gate timeout, but in ~hundreds of ms. idle/waiting
|
|
3068
|
+
// never match isBusyDispatchState, so the idle path is byte-unchanged. gatedTerminalSubmit below
|
|
3069
|
+
// still runs its OWN echo+quiet gate before the \r (never fires blindly), and a CR into a busy
|
|
3070
|
+
// composer merely queues → #617 redeliver fires it on idle. Rollback: TELEPTY_SUBMIT_BUSY_DISPATCH=off.
|
|
3071
|
+
let gateResult = null;
|
|
3072
|
+
if (injectedBody && SUBMIT_BUSY_DISPATCH_ENABLED) {
|
|
3073
|
+
const cur = sessionStateManager.getState(id);
|
|
3074
|
+
if (submitGate.isBusyDispatchState(cur, SUBMIT_BUSY_GRACE_MS)) {
|
|
3075
|
+
const settle = await submitGate.awaitInputSettled(session, injectedBody, {
|
|
3076
|
+
timeoutMs: 1200,
|
|
3077
|
+
quietWindowMs: 100,
|
|
3078
|
+
echoGraceMs: 400,
|
|
3079
|
+
pollIntervalMs: 30,
|
|
3080
|
+
stripAnsi: stripAnsiState,
|
|
3081
|
+
});
|
|
3082
|
+
gateResult = { ready: false, reason: 'busy_settled', last_state: cur.state, waited_ms: settle.waited_ms };
|
|
3083
|
+
console.log(`[SUBMIT] busy-dispatch fast-path ${id}: state=${cur.state} (${cur.duration_ms}ms) settle=${settle.reason} (${settle.waited_ms}ms) — dispatching without idle-gate burn`);
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
if (!gateResult) {
|
|
3087
|
+
gateResult = await submitGate.awaitReplReady(id, sessionStateManager, {
|
|
3088
|
+
timeoutMs: gateTimeoutMs,
|
|
3089
|
+
...(minConfidence !== undefined ? { minConfidence } : {}),
|
|
3090
|
+
});
|
|
3091
|
+
}
|
|
3051
3092
|
const gatedDispatchAfterTimeout = !gateResult.ready;
|
|
3052
3093
|
if (isTerminalGateFailure(gateResult)) {
|
|
3053
3094
|
console.log(`[SUBMIT] gate hard-fail ${id}: ${gateResult.reason} (last_state=${gateResult.last_state})`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmsdc-ai/aigentry-telepty",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
4
4
|
"main": "daemon.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aigentry-telepty": "install.js",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"scripts": {
|
|
38
38
|
"postinstall": "node scripts/postinstall.js",
|
|
39
39
|
"preuninstall": "node scripts/preuninstall.js",
|
|
40
|
-
"test": "node --require ./test-support/setup-env.js --test test/auth.test.js test/http-auth.test.js test/tailnet-autobind.test.js test/win-firewall.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/daemon-harness-port.test.js test/daemon-bind-default.test.js test/integration/daemon-launch.test.js test/cli.test.js test/subcommand-help.test.js test/telepty-kill.test.js test/dupid-flap-kill-stick-56.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/submit-gate-restore-register-678.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/inject-consumption-evidence.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/uninstall.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/daemon-restart-fallback-15.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/daemon-lifecycle-55.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/idle-unconfirmed-settle.test.js test/idle-unconfirmed-consumption.test.js test/idle-unconfirmed-decayed-619.test.js test/inject-redeliver.test.js test/provenance.test.js test/inject-audit-broker-seam.test.js test/inject-provenance-daemon.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
|
-
"test:watch": "node --require ./test-support/setup-env.js --test --watch test/auth.test.js test/http-auth.test.js test/tailnet-autobind.test.js test/win-firewall.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/daemon-harness-port.test.js test/daemon-bind-default.test.js test/integration/daemon-launch.test.js test/cli.test.js test/subcommand-help.test.js test/telepty-kill.test.js test/dupid-flap-kill-stick-56.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/submit-gate-restore-register-678.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/inject-consumption-evidence.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/uninstall.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/daemon-restart-fallback-15.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/daemon-lifecycle-55.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/idle-unconfirmed-settle.test.js test/idle-unconfirmed-consumption.test.js test/idle-unconfirmed-decayed-619.test.js test/inject-redeliver.test.js test/provenance.test.js test/inject-audit-broker-seam.test.js test/inject-provenance-daemon.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js",
|
|
42
|
-
"test:ci": "node --require ./test-support/setup-env.js --test --test-reporter=spec test/auth.test.js test/http-auth.test.js test/tailnet-autobind.test.js test/win-firewall.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/daemon-harness-port.test.js test/daemon-bind-default.test.js test/integration/daemon-launch.test.js test/cli.test.js test/subcommand-help.test.js test/telepty-kill.test.js test/dupid-flap-kill-stick-56.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/submit-gate-restore-register-678.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/inject-consumption-evidence.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/uninstall.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/daemon-restart-fallback-15.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/daemon-lifecycle-55.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/idle-unconfirmed-settle.test.js test/idle-unconfirmed-consumption.test.js test/idle-unconfirmed-decayed-619.test.js test/inject-redeliver.test.js test/provenance.test.js test/inject-audit-broker-seam.test.js test/inject-provenance-daemon.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/",
|
|
40
|
+
"test": "node --require ./test-support/setup-env.js --test test/auth.test.js test/http-auth.test.js test/tailnet-autobind.test.js test/win-firewall.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/daemon-harness-port.test.js test/daemon-bind-default.test.js test/integration/daemon-launch.test.js test/cli.test.js test/subcommand-help.test.js test/telepty-kill.test.js test/dupid-flap-kill-stick-56.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/submit-gate-restore-register-678.test.js test/submit-busy-dispatch-694.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/inject-consumption-evidence.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/uninstall.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/daemon-restart-fallback-15.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/daemon-lifecycle-55.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/idle-unconfirmed-settle.test.js test/idle-unconfirmed-consumption.test.js test/idle-unconfirmed-decayed-619.test.js test/inject-redeliver.test.js test/provenance.test.js test/inject-audit-broker-seam.test.js test/inject-provenance-daemon.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js test/inject-notfound-teardown-691.test.js && git diff --exit-code tests/snippet-protocol/v1/",
|
|
41
|
+
"test:watch": "node --require ./test-support/setup-env.js --test --watch test/auth.test.js test/http-auth.test.js test/tailnet-autobind.test.js test/win-firewall.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/daemon-harness-port.test.js test/daemon-bind-default.test.js test/integration/daemon-launch.test.js test/cli.test.js test/subcommand-help.test.js test/telepty-kill.test.js test/dupid-flap-kill-stick-56.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/submit-gate-restore-register-678.test.js test/submit-busy-dispatch-694.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/inject-consumption-evidence.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/uninstall.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/daemon-restart-fallback-15.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/daemon-lifecycle-55.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/idle-unconfirmed-settle.test.js test/idle-unconfirmed-consumption.test.js test/idle-unconfirmed-decayed-619.test.js test/inject-redeliver.test.js test/provenance.test.js test/inject-audit-broker-seam.test.js test/inject-provenance-daemon.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js test/inject-notfound-teardown-691.test.js",
|
|
42
|
+
"test:ci": "node --require ./test-support/setup-env.js --test --test-reporter=spec test/auth.test.js test/http-auth.test.js test/tailnet-autobind.test.js test/win-firewall.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/daemon-harness-port.test.js test/daemon-bind-default.test.js test/integration/daemon-launch.test.js test/cli.test.js test/subcommand-help.test.js test/telepty-kill.test.js test/dupid-flap-kill-stick-56.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/submit-gate-restore-register-678.test.js test/submit-busy-dispatch-694.test.js test/prompt-symbol-registry.test.js test/inject-submit-flags.test.js test/inject-submit-force-env.test.js test/inject-consumption-evidence.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/uninstall.test.js test/win-resolve-executable.test.js test/version-handshake.test.js test/ensure-daemon-running.test.js test/daemon-restart-fallback-15.test.js test/win-kill-process.test.js test/daemon-control-port-owner.test.js test/daemon-lifecycle-55.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/idle-unconfirmed-settle.test.js test/idle-unconfirmed-consumption.test.js test/idle-unconfirmed-decayed-619.test.js test/inject-redeliver.test.js test/provenance.test.js test/inject-audit-broker-seam.test.js test/inject-provenance-daemon.test.js test/inject-audit-log.test.js test/inject-audit-daemon.test.js test/inject-audit-cli.test.js test/inject-notfound-teardown-691.test.js && git diff --exit-code tests/snippet-protocol/v1/",
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
44
|
"regen-fixtures": "node scripts/regen-snippet-fixtures.js"
|
|
45
45
|
},
|
package/src/submit-gate.js
CHANGED
|
@@ -35,6 +35,19 @@ function isFailed(state) {
|
|
|
35
35
|
return !!(state && FAIL_STATES.has(state.state));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// #694: a "busy-dispatch" state — the recipient is mid-turn (working/thinking, the
|
|
39
|
+
// ACCEPTED_AFTER_SUBMIT_STATES) and has been for at least graceMs. Used by the submit gate to
|
|
40
|
+
// short-circuit the idle-wait on a genuinely-busy target: working/thinking are NOT READY_STATES,
|
|
41
|
+
// so awaitReplReady can never pass mid-turn and would burn its full timeout before best-effort
|
|
42
|
+
// dispatch. The graceMs floor is what distinguishes a REAL ongoing turn from the transient
|
|
43
|
+
// `working` a target emits while echoing our OWN just-injected text (duration_ms ≈ 0) — so a
|
|
44
|
+
// fresh inject never trips the fast-path prematurely, and idle/waiting never match at all.
|
|
45
|
+
function isBusyDispatchState(state, graceMs) {
|
|
46
|
+
if (!state || !ACCEPTED_AFTER_SUBMIT_STATES.has(state.state)) return false;
|
|
47
|
+
const grace = Number.isFinite(graceMs) ? graceMs : 0;
|
|
48
|
+
return Number.isFinite(state.duration_ms) && state.duration_ms >= grace;
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
/**
|
|
39
52
|
* Wait until the session's REPL is ready to accept Enter.
|
|
40
53
|
*
|
|
@@ -784,6 +797,7 @@ module.exports = {
|
|
|
784
797
|
defaultReadScreen,
|
|
785
798
|
isReady,
|
|
786
799
|
isFailed,
|
|
800
|
+
isBusyDispatchState,
|
|
787
801
|
READY_STATES,
|
|
788
802
|
FAIL_STATES,
|
|
789
803
|
ACCEPTED_AFTER_SUBMIT_STATES,
|