21 Commits

Author SHA1 Message Date
can1357 39477ba39b fix(debug): shortened js-debug install hint to the repo download
- Runtime error now just says to download vscode-js-debug from its GitHub repo;
  tarball recipe, extract path, env var, and Mason detail stay in docs/tools/debug.md.
2026-08-07 14:50:17 +02:00
can1357 db22b98659 test(coding-agent): cover js debug install guidance 2026-08-07 13:39:55 +02:00
roboomp 33ecf0b3ae docs(changelog): note DAP unix socket connect hang fix 2026-07-23 19:54:29 +00:00
roboomp 3b194a3e37 fix(dap): reject and bound the unix socket connect on Linux
connectSocket captured only resolve from Promise.withResolvers and its
error handler merely errored the stream, so a Bun.connect failure
(ECONNREFUSED/ENOENT/EACCES on a stat-ready-but-dead socket) never
settled the promise. The unbounded await in #spawnSocketUnix then hung
the launch forever, and the surrounding kill/reap guard could not fire.

Capture reject, track an opened flag, reject on error/close-before-open
and on the Bun.connect promise rejection, and bound the connect with a
timeout matching the launch deadline (cleared on settle). Thread
timeoutMs from #spawnSocketUnix. Export connectSocket for a deterministic
reject-path test.

Fixes #4087
2026-07-23 19:54:04 +00:00
can1357 2f5a67694a test(dap): made tcp transport tests deterministic
- Replaced the subprocess-based delayed-banner test with in-process
  tests of the exported waitForTcpServerListening gate (banner split
  across chunks, stdout end without banner).
- Dropped wall-clock elapsed assertions from the ghost-socket tests;
  the connection-closed rejection message already distinguishes the
  wake path from a request timeout.
2026-07-23 01:22:24 +02:00
can1357 8a9aa0342d chore: format evaluator fix commits and suppress intentional DAP placeholder lint 2026-07-22 21:16:38 +02:00
roboomp 07019e6c61 fix(dap): close tcp connect race and wake pending requests on transport end
#spawnTcp reserved a port, released it, spawned the adapter, then immediately
connected. On WSL2 with networkingMode=mirrored the Windows relay keeps
accepting connections to the just-released reservation port for tens of ms, so
the first connect bound a ghost socket instead of js-debug. Gate the connect on
the adapter announcing its listening port on stdout (as vscode-js-debug does
from inside its listen callback) so we only connect once the child owns the
port; this also drains stdout, which nothing else consumes in tcp mode.

Separately, the message reader only rejected pending requests from its catch, so
a clean stream end (the ghost socket dropped after we wrote initialize) left
requests and event waiters pending until their own timeout. Route both the
reader end and adapter exit through a single #failConnection that rejects
pending requests and wakes event waiters, turning every transport failure into
an immediate "DAP connection closed" error instead of a silent 30s timeout.

Fixes #6055
2026-07-21 20:57:14 +00:00
can1357 e8add61016 fix(debug): stopped native fallback for missing delve
- Kept missing language-specific adapters from falling through to native debuggers.
- Resolved nested launch roots before session-local binaries and PATH, including explicit adapters and go.work workspaces.
- Added actionable install/configuration errors and deterministic regression coverage.

Fixes #5037
2026-07-10 14:06:57 +02:00
roboomp c932d84aa1 style: bun run fix 2026-07-02 08:43:40 +00:00
roboomp 23cbeb49ff fix(coding-agent/dap): bound writeMessage flush and clean up leaked adapter processes
- Replace the module-level writeMessage with a private DapClient.#writeMessage
  that races sink.flush() against a 30 s cap and this.proc.exited, disposes the
  client, and rethrows on either failure. A wedged adapter stdin previously
  blocked writeMessage forever.
- sendRequest fires the write in the background and attaches a passive
  promise.catch guard so the request timer's rejection cannot become an
  unhandled promise before the caller's await subscribes. This also lets the
  caller's timeoutMs win over a hung flush instead of waiting the full 30 s
  write cap.
- #spawnSocketUnix and #spawnSocketClientAddr wrap the readiness / connect
  race in try/catch that kills proc before rethrowing. Add a private
  socketReadyTimeoutMs hook on DapSpawnOptions so tests do not have to wait
  the full 10 s socket cap.

Regression tests cover all three failure modes: a wedged stdin flush must
reject sendRequest at the caller timeout with no unhandledRejection, and the
Unix + TCP client-addr spawn paths must terminate the detached adapter
process when the socket never appears.

Fixes #4233
2026-07-02 08:43:26 +00:00
can1357 74d7dfd2fa Merge PR #3354: fix: migrate coding-agent tests to removeWithRetries (@oldschoola) 2026-06-27 02:06:38 +02:00
oldschoola a2854ba768 fix: migrate coding-agent tests from fs.rm to removeWithRetries
Migrate 203 test files (356 call sites) from fs.rm/fs.rmSync to
removeWithRetries/removeSyncWithRetries to reduce EBUSY test failures
on Windows. removeWithRetries is now exported from @oh-my-pi/pi-utils.

The migration uses a regex-based approach that:
- Replaces fs.rm(path, { recursive, force }) → removeWithRetries(path)
- Replaces fs.rmSync(path, { recursive, force }) → removeSyncWithRetries(path)
- Replaces fs.rm(path) → removeWithRetries(path) (no options)
- Skips fs.rm/fs.rmSync inside template literals (bun --eval scripts)
- Adds imports to existing @oh-my-pi/pi-utils import or creates new one
- Removes unused fs imports where fs.rm was the only fs usage (4 files)
2026-06-23 15:28:05 -07:00
DanZAIO 23922f3fe2 fix(debug): preserve configured dap launch args 2026-06-20 00:01:26 -03:00
can1357 9d457f73d9 test: migrated test imports to package subpath exports
- Replaced relative `../src` imports with `@oh-my-pi/pi-ai` and `@oh-my-pi/pi-agent-core` subpaths.
2026-06-08 19:03:55 +02:00
roboomp d710b91d96 test(debug): hoist dap module import to top of test file
The repo bans inline imports. Replace per-test `await import("../../src/dap")`
calls with a single top-level `import * as dapModule from "../../src/dap"`
and reuse the namespace for every spy in this file.

Fixes #2020
2026-06-07 03:05:20 +00:00
roboomp 8c25f7d4aa fix(debug): prefer dlv for go directory launches
Prefer directory-capable adapters when selecting a launch adapter for a
resolved directory program. This keeps Go package directories on dlv in
mixed projects that also expose native-debugger root markers such as a
Makefile, instead of selecting gdb/lldb-dap first and rejecting the
directory during validation.

Added a regression test covering a Go module with both go.mod and
Makefile plus local dlv/gdb adapter shims.

Fixes #2020
2026-06-07 03:03:57 +00:00
roboomp 1745529368 fix(debug): accept directory programs for dlv and auto-select dlv mode
The debug tool ran validateLaunchProgram before adapter selection and
rejected any directory program with `launch program resolves to a
directory`, while dlv's default `mode=debug` requires a Go package
path (a directory or .go source file). Every Go-module launch failed:
passing the module dir was rejected outright, and passing the compiled
binary failed at dlv with `not a valid go module`.

- Add `acceptsDirectoryProgram` to DapAdapterConfig/DapResolvedAdapter
  and flag dlv in dap/defaults.json.
- In DebugTool.execute(launch), resolve the adapter first, then call
  validateLaunchProgram with the resolved adapter — the directory
  rejection only fires when the adapter does not advertise the flag.
- Add resolveLaunchOverrides in dap/config.ts: for dlv, derive `mode`
  from the program shape (directory or .go file → debug; other file
  → exec). Plumbed through DapLaunchSessionOptions.extraLaunchArguments
  and spread between adapter.launchDefaults and the hard-coded launch
  fields in session.ts.
- Refresh tests: cover the no-dir-support adapter rejection, dlv on a
  package directory keeping mode=debug, and dlv on a binary switching
  to mode=exec.

Fixes #2020
2026-06-07 02:59:02 +00:00
roboomp dcefc9e3d6 fix(debug): waited for dlv unix socket
Used fs.stat to confirm delayed dlv Unix socket creation before connecting so Linux socket-mode adapters do not race Bun.connect. Added a delayed socket adapter regression test covering the launch path.\n\nFixes #2013
2026-06-06 21:34:33 +00:00
oldschoola 96aad47eb6 fix(coding-agent): address PR #1388 review feedback
Refactor:
- session.ts: extract mapDebugpyMissingModule helper; replace the duplicated
  inline check in launch/attach catch blocks. Add jsdoc on DapStartRequestFailure.settled
  documenting per-call ownership and how throwPreferredDapStartError consumes it.
- path-utils.ts: replace the no-op keepOpaqueResourceUri branch with an
  OPAQUE_RESOURCE_SCHEMES Set so the structure carries the intent. Functionally
  equivalent; new opaque schemes become a one-line Set change.

Tests:
- dap-launch-failures: cover the debugpy stderr -> 'pip install debugpy'
  rewrite for launch and attach, plus a negative case (non-debugpy adapter
  with the substring in stderr is left untouched).
- dap-launch-failures: model the delayed-launch-failure case the new
  settled-race in throwPreferredDapStartError defends against. FakeDapClient
  gains optional launchErrorDelayMs/attachErrorDelayMs.
- dap-launch-failures (DebugTool): assert adapter:'debugpy' early-throw
  surfaces 'python not found in PATH' on both launch and attach when
  selectLaunchAdapter/selectAttachAdapter return null, and the unspecified-adapter
  path still falls back to the generic 'No debugger adapter' error.
- find.ts: export validateFindPathInputs and pin the new backslash-escape
  semantics (\, no longer trips the comma-joined heuristic) plus the
  existing brace-expansion and rejection paths.
- patch.ts: cover the post-write verification error message. The user-facing
  ToolError must contain the caller-supplied relative path and not the
  absolute resolvedPath (which still lives in the structured context for
  log correlation).
- split-internal-url-sel: reword two mcp:// test comments that described a
  'peeler refuses' guard that doesn't exist; rename the tests to reflect the
  actual opaque-scheme rule.
2026-05-26 01:54:09 -07:00
oldschoola 2171ae4dd1 fix(coding-agent): browser default, patch error path, mcp:// selectors, find timeout/sort, DAP launch races, debugpy diagnostics
- browser tool's existing-tab re-nav defaults to waitUntil: 'load' (matching
  new-tab path); identical acquireTab() calls no longer hang on dev servers
- patch tool error path uses caller-supplied relative path; absolute
  resolvedPath stays in structured context only ($HOME no longer leaks to TUI)
- splitInternalUrlSel keeps mcp:// resource URIs opaque even when they end in
  ':raw' or '/:1-50' (McpProtocolHandler matches by verbatim URI)
- find tool: timeout signal honored by onMatch; partial results sorted by
  mtime desc; backslash-escaped commas skipped in path-list validation
- DAP throwPreferredDapStartError waits up to 50ms for the underlying
  launch/attach error instead of one microtask
- debug tool surfaces 'python missing' and 'pip install debugpy' diagnostics
  separately when adapter: 'debugpy' is requested
2026-05-26 01:54:09 -07:00
roboomp cb34503ba5 fix(debug): preserved dap launch failures
- Preserved launch and attach request failures when configurationDone also fails.
- Handled initial stop-outcome watcher rejections for failed launch and attach attempts.
- Rejected directory-valued debug launch programs before adapter selection and documented the debugpy launch shape.

Fixes #1187
2026-05-19 07:18:33 +00:00