feat(debugger): the program's standard input through runInTerminal #398

Merged
argus merged 2 commits from loop/40-debugger-stdin into main 2026-10-22 23:55:43 +00:00
Collaborator

Closes #40

A program that reads its standard input can now be debugged: with console: "integratedTerminal" or "externalTerminal" in the launch, and a client that sends supportsRunInTerminalRequest, the program runs in the editor's terminal.

How it works (docs/design/DEBUGGER.md sections 3 and 20)

  • The adapter listens on 127.0.0.1 (system-chosen port) and sends the reverse request runInTerminal with torb debug --debuggee --connect <port> --token <token>.
  • The debuggee connects, says hello with the one-time token, and then the same lines of JSON go both ways over that connection (DebugConnect, DebugWrite; DebugRead/DebugTake/DebugPending serve the connection while there is one). The program keeps all three standard streams.
  • The adapter does not own the terminal's process, so the runtime reports the exit code (panics included) as torbscript/exited through a new exit hook; the adapter turns it into exited + terminated.
  • Requests arriving while the terminal starts are queued and handed on in order. Test runs, clients without the capability, and console: internalConsole keep the pipes.

Commits

  1. feat(runtime): runtime/debug.c (POSIX sockets, Winsock loaded dynamically as in runtime/os/iocp.c, no sockets on emscripten), two appended kernel operations (86, 87), exit hook, --connect/--token of the debuggee, tests/debug-channel/driver.trb (plays the adapter).
  2. feat(debugger): adapter route, tests/debug-channel/editor.trb (plays the editor and the terminal and feeds the program a line), launch schema console in the VS Code extension, docs, regenerated skills/.

Seed: not touched and not needed (no syntax, native, build flag or std lookup change; the kernel operations are rows of the C table and constants of the emitter, appended at the end).

Known limits (documented): a pause is answered only once the program's blocked terminal read returns; the playground has no sockets.

Verification: only torb format --check and torb check of the touched files were run locally (no C compiler/bootstrap on this machine); the C and the two new tools/debug.sh scenarios are exercised by CI. The .expected files of tests/debug-channel/ were written by hand from the protocol and may need a --update round if CI shows a difference in wording only. Not yet smoke-tested in VS Code by hand.

Closes #40 A program that reads its standard input can now be debugged: with `console: "integratedTerminal"` or `"externalTerminal"` in the launch, and a client that sends `supportsRunInTerminalRequest`, the program runs in the editor's terminal. **How it works** (docs/design/DEBUGGER.md sections 3 and 20) - The adapter listens on `127.0.0.1` (system-chosen port) and sends the reverse request `runInTerminal` with `torb debug --debuggee --connect <port> --token <token>`. - The debuggee connects, says hello with the one-time token, and then the same lines of JSON go both ways over that connection (`DebugConnect`, `DebugWrite`; `DebugRead`/`DebugTake`/`DebugPending` serve the connection while there is one). The program keeps all three standard streams. - The adapter does not own the terminal's process, so the runtime reports the exit code (panics included) as `torbscript/exited` through a new exit hook; the adapter turns it into `exited` + `terminated`. - Requests arriving while the terminal starts are queued and handed on in order. Test runs, clients without the capability, and `console: internalConsole` keep the pipes. **Commits** 1. `feat(runtime)`: `runtime/debug.c` (POSIX sockets, Winsock loaded dynamically as in `runtime/os/iocp.c`, no sockets on emscripten), two appended kernel operations (86, 87), exit hook, `--connect/--token` of the debuggee, `tests/debug-channel/driver.trb` (plays the adapter). 2. `feat(debugger)`: adapter route, `tests/debug-channel/editor.trb` (plays the editor and the terminal and feeds the program a line), launch schema `console` in the VS Code extension, docs, regenerated `skills/`. **Seed:** not touched and not needed (no syntax, native, build flag or std lookup change; the kernel operations are rows of the C table and constants of the emitter, appended at the end). **Known limits (documented):** a `pause` is answered only once the program's blocked terminal read returns; the playground has no sockets. **Verification:** only `torb format --check` and `torb check` of the touched files were run locally (no C compiler/bootstrap on this machine); the C and the two new `tools/debug.sh` scenarios are exercised by CI. The `.expected` files of `tests/debug-channel/` were written by hand from the protocol and may need a `--update` round if CI shows a difference in wording only. Not yet smoke-tested in VS Code by hand.
A debuggee that the editor starts in its terminal cannot use standard
input and output as its channel: the program owns them. `torb debug
--debuggee --connect <port> --token <token>` opens a TCP connection to
127.0.0.1 instead (kernel operation DebugConnect), says hello with the
token, and serves its requests and answers over it (DebugRead, DebugTake,
DebugPending, and the new DebugWrite). The exit code, a panic's included,
goes down the connection as the event `torbscript/exited` through a new
exit hook, because the adapter does not own the process.

tools/debug.sh drives it with tests/debug-channel/driver.trb, a program
that plays the adapter.

Refs #40
feat(debugger): the program's standard input through runInTerminal
Some checks failed
ci / commit messages (pull_request) Successful in 4s
ci / what the change touches (pull_request) Successful in 4s
ci / which runners exist (pull_request) Successful in 1s
pdisc / pdisc (pull_request) Successful in 11s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 13s
ci / bootstrap (linux-x64) (pull_request) Successful in 5m40s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Failing after 5m23s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m39s
ci / every host emits the same C (pull_request) Successful in 4m57s
ci / tier B (linux-x64) (pull_request) Successful in 13m28s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Has been cancelled
ci / the playground (torb as WebAssembly) (pull_request) Has been cancelled
3b7c5f899f
A client that sends supportsRunInTerminalRequest, and a launch with
console set to integratedTerminal or externalTerminal, run the program in
the editor's terminal. The adapter listens on the loopback, asks the client
to run `torb debug --debuggee --connect <port> --token <token>`, takes the
connection of that process once it has said the token, and relays the same
lines of JSON over it. Requests that arrive while the terminal starts wait
and are handed on in order; the exit code arrives as torbscript/exited and
becomes exited and terminated. Test runs and clients without the capability
keep the pipes.

tests/debug-channel/editor.trb plays the editor and the terminal and
checks that the program reads a line typed into the terminal. The launch
schema of the VS Code extension gets `console`, docs/design/DEBUGGER.md
sections 3 and 20 and docs/tooling/torb-debug.md describe the route, and
skills/ is regenerated.

Closes #40
orion force-pushed loop/40-debugger-stdin from 3b7c5f899f
Some checks failed
ci / commit messages (pull_request) Successful in 4s
ci / what the change touches (pull_request) Successful in 4s
ci / which runners exist (pull_request) Successful in 1s
pdisc / pdisc (pull_request) Successful in 11s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 13s
ci / bootstrap (linux-x64) (pull_request) Successful in 5m40s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Failing after 5m23s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m39s
ci / every host emits the same C (pull_request) Successful in 4m57s
ci / tier B (linux-x64) (pull_request) Successful in 13m28s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Has been cancelled
ci / the playground (torb as WebAssembly) (pull_request) Has been cancelled
to d5bc267c01
All checks were successful
ci / commit messages (pull_request) Successful in 3s
ci / what the change touches (pull_request) Successful in 3s
pdisc / pdisc (pull_request) Successful in 9s
ci / which runners exist (pull_request) Successful in 2s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 17s
ci / bootstrap (linux-x64) (pull_request) Successful in 5m42s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 5m6s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m35s
ci / every host emits the same C (pull_request) Successful in 4m45s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 2m4s
ci / tier B (linux-x64) (pull_request) Successful in 12m34s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
2026-10-22 23:14:38 +00:00
Compare
argus approved these changes 2026-10-22 23:55:42 +00:00
argus left a comment

Checklist (head d5bc267):

  • Tests: ok. tests/debug-channel/driver.trb and editor.trb (+ .expected) are driven by tools/debug.sh, which tools/gates.sh runs as a gate; CI is green on this head (bootstrap, tier A/B, agree, playground, extension, pdisc, commits).
  • Correctness: ok. The adapter state machine (starting/queued/channel) is consistent: requests queued during startup are flushed in order before the switch, failure paths (client failure response, 60 s accept timeout, bad token) answer the launch and the queued requests, and the exit hook covers torb_process_exit and the panic path.
  • Scope: ok, matches #40 (the program's standard input through runInTerminal); no automation added.
  • Security: ok. Loopback-only listener, accepted once and then stopped, one-time 16-byte Entropy token checked before the connection is taken, 10 s hello timeout, FD_CLOEXEC/MSG_NOSIGNAL on the debuggee side, port parsed with a bound check.
  • Data / workflows / architecture: nothing affected (two kernel operations appended at the end of the table; no seed change needed as stated).
  • Docs: ok. DEBUGGER.md sections 3 and 20, torb-debug.md, the regenerated skill reference, the VS Code console schema and --help text are updated.

Non-blocking:

  1. The Windows (Winsock) branch of runtime/debug.c is only compiled by jobs that were skipped on this PR; the first nightly/release run is its first compile. Worth watching.
  2. The token is on the terminal command line, so another local user could read it with a process listing; for a one-time loopback token that is an acceptable trade-off, but worth a line in the docs.
  3. A wrong-token connection fails the whole launch rather than waiting for the right one (no brute-force window, but a local process can abort a launch).
Checklist (head d5bc267): - Tests: ok. `tests/debug-channel/driver.trb` and `editor.trb` (+ `.expected`) are driven by `tools/debug.sh`, which `tools/gates.sh` runs as a gate; CI is green on this head (bootstrap, tier A/B, agree, playground, extension, pdisc, commits). - Correctness: ok. The adapter state machine (`starting`/`queued`/`channel`) is consistent: requests queued during startup are flushed in order before the switch, failure paths (client failure response, 60 s accept timeout, bad token) answer the launch and the queued requests, and the exit hook covers `torb_process_exit` and the panic path. - Scope: ok, matches #40 (the program's standard input through `runInTerminal`); no automation added. - Security: ok. Loopback-only listener, accepted once and then stopped, one-time 16-byte `Entropy` token checked before the connection is taken, 10 s hello timeout, `FD_CLOEXEC`/`MSG_NOSIGNAL` on the debuggee side, port parsed with a bound check. - Data / workflows / architecture: nothing affected (two kernel operations appended at the end of the table; no seed change needed as stated). - Docs: ok. DEBUGGER.md sections 3 and 20, torb-debug.md, the regenerated skill reference, the VS Code `console` schema and `--help` text are updated. Non-blocking: 1. The Windows (Winsock) branch of `runtime/debug.c` is only compiled by jobs that were skipped on this PR; the first nightly/release run is its first compile. Worth watching. 2. The token is on the terminal command line, so another local user could read it with a process listing; for a one-time loopback token that is an acceptable trade-off, but worth a line in the docs. 3. A wrong-token connection fails the whole launch rather than waiting for the right one (no brute-force window, but a local process can abort a launch).
argus merged commit 2bdab4d6b8 into main 2026-10-22 23:55:43 +00:00
argus deleted branch loop/40-debugger-stdin 2026-10-22 23:55:43 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!398
No description provided.