Skip to content

feat: honour the Actor's original start command when run as ENTRYPOINT - #11

Closed
Pijukatel wants to merge 2 commits into
masterfrom
pr-toolkit-workaround
Closed

Pijukatel wants to merge 2 commits into
masterfrom
pr-toolkit-workaround

Conversation

@Pijukatel

Copy link
Copy Markdown
Collaborator

Why

Running the debugger as the image CMD has two problems:

  1. The Actor's real start command is lost. The entrypoint was guessed from package.json scripts.start / main / conventional paths, so Node flags (--max-old-space-size, -r ...) and script arguments never reached the Actor.
  2. An ENTRYPOINT in the Actor's own Dockerfile silently swallows our CMD. Docker then runs that entrypoint with ["npx", "actor-debugger", "--brk"] as arguments — the Actor starts with no debugger attached and no error anywhere.

This matters for the planned Console "Debug" option, which appends the debug layer to an arbitrary user Dockerfile: it cannot know whether that Dockerfile defines an ENTRYPOINT, and it cannot guess the Actor's start command.

What changed

ENTRYPOINT ["actor-debugger", "--brk"] is now the recommended form. Docker appends the image's own CMD to our arguments, so everything after --brk is treated as the Actor's start command and resolved into a Node.js launch spec, preserving the original flags and arguments:

Passed-through command Resolves to
node [flags] <script> [args] that script, keeping flags (incl. -r x / --import x) and args
npm start, npm run <s>, pnpm …, yarn … the matching package.json script, parsed again
sh -c "<command>" the inner command, parsed again
dist/main.js that file directly (the explicit-path form)

Chained commands are split on &&/||/;/| and tried from the last segment back, so npm run build && node dist/main.js debugs dist/main.js rather than the build step. Resolution recurses up to 4 levels (an npm start that itself calls sh -c, and so on).

With no command passed (the old CMD ["npx", "actor-debugger"] form) the previous auto-detection is unchanged, so existing Dockerfiles keep working.

If a command is passed but no Node.js entrypoint can be derived from it (e.g. a tsx / ts-node launcher), the debugger now fails fast with the reason instead of starting the Actor undebugged — a run you asked to debug should not silently run without a debugger. The message points at the explicit form: ENTRYPOINT ["actor-debugger", "--brk", "dist/main.js"].

Files

  • lib/resolve_launch.mjs (new) — quote-aware tokenizer + resolveLaunch() returning { entry, nodeFlags, scriptArgs, source }.
  • bin/cli.mjs — treats non---brk argv as the start command, passes the resolved flags/args through to the spawned node, exits 1 with the reason when unresolvable.
  • test/resolve_launch.test.mjs (new) — 18 node:test cases against real temp directories.
  • package.json — npm test script (node --test test/*.test.mjs).
  • .github/workflows/publish.yml — syntax-check the new module and run npm test before publishing.
  • README.md — ENTRYPOINT-first snippet and the rewritten detection order.

Verified

npm test → 18/18 pass. Manual smoke tests of every form against a real temp Actor, asserting both process.argv and that --inspect is in process.execArgv:

  • npm start (→ node dist/main.js --from-cmd) — argv and inspector correct, exit 0
  • sh -c "echo building && node dist/main.js --chained" — resolves the last segment, exit 0
  • dist/main.js (explicit) and no-argument auto-detect — both exit 0
  • tsx src/main.ts — exits 1 with unrecognized start command, as intended

🤖 Generated with Claude Code

https://claude.ai/code/session_01UTxccb4QARxDG34guZbeFG


Generated by Claude Code

claude and others added 2 commits September 4, 2026 09:53
Running as the image CMD has two problems: the Actor's real start command is
lost (the entrypoint is guessed from package.json/conventional paths), and an
ENTRYPOINT defined in the Actor's own Dockerfile silently swallows our CMD, so
the Actor runs with no debugger and no error.

As ENTRYPOINT, Docker appends the image's own CMD to our arguments. Everything
after --brk is now treated as that start command and resolved into a Node.js
launch spec, keeping the original node flags and script arguments:

  node [flags] <script> [args]      -> that script, flags and args preserved
  npm|pnpm|yarn [run] <script>      -> the package.json script, parsed again
  sh -c "<command>"                 -> the inner command, parsed again
  <path>                            -> that file (the explicit-path form)

Chained scripts are resolved from the last segment back, so
`npm run build && node dist/main.js` debugs the Actor, not the build step.
With no command passed, the previous auto-detection still applies, so the
existing CMD forms keep working unchanged. When a command is passed but no
Node.js entrypoint can be derived from it, the debugger fails fast with the
reason instead of starting the Actor undebuggable.

Adds a node:test suite for the resolver (no new dependencies) and runs it,
plus a syntax check of the new module, in the release workflow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTxccb4QARxDG34guZbeFG
@Pijukatel Pijukatel closed this Sep 7, 2026
@github-actions github-actions Bot added this to the 149th sprint - Tooling team milestone Sep 7, 2026
@github-actions github-actions Bot added t-tooling Issues with this label are in the ownership of the tooling team. tested Temporary label used only programatically for some analytics. labels Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-tooling Issues with this label are in the ownership of the tooling team. tested Temporary label used only programatically for some analytics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants