Skip to content

feat(cli): run project commands with the project's own checkly install [RED-757] [ship] - #1563

Merged
sorccu merged 5 commits into
mainfrom
simo/red-757-cli-convenience-7578e3
Oct 24, 2026
Merged

sorccu merged 5 commits into
mainfrom
simo/red-757-cli-convenience-7578e3

Conversation

@sorccu

@sorccu sorccu commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Linear: RED-757

Problem

checkly test, deploy and every other command that loads a project failed with Unable to create a construct '…' outside a Checkly CLI project whenever the running checkly was a different install from the project's own node_modules/checkly. That happens with a global npm i -g checkly, pnpm dlx/pnpx checkly, and npx checkly@<other version>. The project's constructs register with the Session of the checkly the project imports, not the one that is running, and the error says nothing about the real cause.

Change

Any checkly install now behaves like npx checkly in the project's directory. bin/launch.cjs loads .env, then looks for node_modules/checkly upwards from the project's directory, the same search a bare checkly import does. The project's directory is that of the --config/-c file when one is given, as the commands themselves resolve it, and the working directory otherwise. When that is a different install by real path, the launcher runs every command with it, before @oclif/core is even imported. The logic is in src/services/project-cli.ts.

  • No per-command metadata: all commands are handed off, including --version and --help, so the project's version decides what is available. The only argument the launcher reads is the config file. It accepts every form oclif does (--config v, --config=v, -c v, -c=v, -cv, and c after boolean short flags in one group, like -pc v) and stops at --. Tests assert that -c means --config on every command, and that the scan's set of boolean short letters matches the commands that take -c, so the scan can ignore which command runs. pnpm symlinks and the project's own npx checkly resolve to the same install and stay in-process.
  • Cheap: the outer process skips oclif entirely. A handed-off --version takes about 30 ms longer than running the project's CLI directly.
  • How it runs: the project install's bin runs with the same argv and inherited stdio. It gets the .env-merged environment, because installs before 8.0.0 don't load .env themselves. It also gets this process's Node flags, minus inspector flags in execArgv and NODE_OPTIONS. SIGINT, SIGTERM and SIGHUP are forwarded; on Windows the console already delivers Ctrl+C to the child. The outer process exits with the child's exit code, or is killed by the same signal.
  • Notice: one line on stderr, only when the versions differ: Using checkly 9.5.0 from this project (node_modules/checkly) instead of checkly 10.0.0. When the invoked CLI is newer, it adds To use 10.0.0, install it in this project.
  • Fallbacks:
    • CHECKLY_NO_DELEGATION=1 keeps the command with the invoked CLI.
    • Deno is skipped, because the child would lose the deno run permissions.
    • When the project's install can't be read or started, the command runs in-process with a stderr line.
    • An internal CHECKLY_HANDED_OFF_TO guard stops an install from handing off to itself again, while a nested checkly in another project can still hand off.

localCliNote (the init footer) still recommends npx checkly, but no longer claims a global install cannot load the project. Global installs from before this release still can't.

Testing

  • src/services/__tests__/project-cli.spec.ts:
    • unit tests for the install lookup, the hand-off decision and the --config/-c scan, which is checked against oclif's own parser;
    • launcher tests that run the real bin/run.cjs against a fake project install. They cover argv, exit code, the .env env, notice wording, handing off every invocation including from subdirectories, the search starting from a -c file in another package, the opt-out, signal forwarding and signal exits;
    • a regression test that runs debug parse-project from this package in a FixtureSandbox project with its own checkly. It succeeds with the hand-off and fails with the original error under CHECKLY_NO_DELEGATION=1.
  • src/services/__tests__/project-cli-spawn-error.spec.ts: fallback when the install can't be started or read.
  • Manually, in a project with published checkly@9.5.0: --version and validate from this checkout were handed off, including from a subdirectory.
  • Full unit suite passes.

Docs: checkly/docs#593.

🤖 Generated with Claude Code

…l [RED-757]

A checkly install other than the project's (a global install, pnpx, an npx
of another version) could not run commands that load the project: the
project's constructs register with the Session of the checkly the project
imports, so the running CLI failed with "Unable to create a construct
outside a Checkly CLI project".

The launcher now detects this before oclif runs or any project file is
imported. For commands marked parsesProject, when a Checkly config file
exists and the nearest node_modules/checkly is a different install, it runs
that install's bin with the same arguments, inherited stdio, forwarded
signals and the same exit status. A one-line notice names the version used
when it differs. CHECKLY_NO_DELEGATION=1 opts out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sorccu and others added 4 commits October 24, 2026 02:32
…757]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-757]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oads [RED-757]

Any checkly install now behaves like `npx checkly` in the same directory:
the launcher looks for node_modules/checkly upwards from the working
directory and, when it is a different install, runs every command with it
before importing oclif. This replaces the per-command parsesProject flag,
the argv parsing and the config-file gate, and makes the hand-off cheaper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… [RED-757]

Commands load the project from the directory of --config/-c, so the
launcher now starts its node_modules/checkly search there too, in every
form oclif accepts the flag (including -c grouped after boolean short
flags), and from the working directory otherwise. This hands off
correctly when --config points into a package with its own checkly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sorccu sorccu changed the title feat(cli): run project commands with the project's own checkly install [RED-757] feat(cli): run project commands with the project's own checkly install [RED-757] [ship] Oct 24, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-approved: ship/show PR from a same-repo branch.

@sorccu
sorccu merged commit 79f5ef6 into main Oct 24, 2026
17 checks passed
@sorccu
sorccu deleted the simo/red-757-cli-convenience-7578e3 branch October 24, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant