Skip to content

Conversation

@deepshekhardas
Copy link

@deepshekhardas deepshekhardas commented Feb 2, 2026

Fixes #2909. Updates \packages/cli-v3/src/commands/dev.ts\ to explicitly handle SIGINT and SIGTERM signals, ensuring that \devInstance.stop()\ is called to terminate child worker processes and remove lockfiles before exiting.


Open with Devin

@changeset-bot
Copy link

changeset-bot bot commented Feb 2, 2026

🦋 Changeset detected

Latest commit: 737ad56

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Walkthrough

This pull request introduces several fixes across the CLI and core modules. The dev command now registers signal handlers (SIGINT/SIGTERM) to cleanly shut down worker processes and prevent orphaned instances. The build process adds optional Docker Hub authentication when environment credentials are present. A new ignoreEngines option enables package managers to skip engine version checks during updates, with package manager-specific flags (npm, pnpm, yarn). ConsoleInterceptor now caches and delegates to original console methods to preserve log chains when other interceptors like Sentry are present. Multiple changeset entries document these fixes, and new test coverage validates the ignoreEngines behavior across package managers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 4
❌ Failed checks (4 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is missing critical sections required by the template: it lacks the Closes statement, checklist, Testing section, and Changelog section. Add the missing template sections including 'Closes #2909', the contributor checklist, a Testing section describing test steps, and a Changelog entry.
Linked Issues check ⚠️ Warning The PR contains multiple unrelated changes beyond the primary objective of fixing orphaned workers, including Docker Hub auth, engine checks, and console interceptor modifications. Focus on the core objective: remove unrelated changeset entries and code changes from deploy.ts, buildImage.ts, consoleInterceptor.ts, and update.ts that don't address the orphaned worker issue.
Out of Scope Changes check ⚠️ Warning Multiple out-of-scope changes are included: Docker Hub authentication (buildImage.ts), Node engine version checks (deploy.ts, update.ts), console interceptor delegation (consoleInterceptor.ts), and related changesets. Remove changes unrelated to issue #2909: keep only dev.ts signal handling changes and their associated changeset entry.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: ensuring worker cleanup on SIGINT/SIGTERM signals and references the fixed issue #2909.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View issue and 4 additional flags in Devin Review.

Open in Devin Review

devInstance = await bootDevSession(watcher.config);

const waitUntilExit = async () => {};
const waitUntilExit = async () => { };

Choose a reason for hiding this comment

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

🔴 waitUntilExit is an empty function that immediately resolves, causing dev command to exit immediately

The waitUntilExit function is defined as an empty async function that immediately resolves.

Click to expand

Bug Mechanism

At packages/cli-v3/src/commands/dev.ts:291, the function is defined as:

const waitUntilExit = async () => { };

This function returns a Promise that immediately resolves to undefined. When called at line 201:

await devInstance.waitUntilExit();

The await completes instantly, then the finally block at lines 202-206 executes, which calls cleanup() that stops the dev instance.

Expected vs Actual Behavior

  • Expected: The waitUntilExit should block/wait indefinitely until the dev session is terminated by a signal or user action.
  • Actual: The function returns immediately, causing the dev command to start and then immediately stop itself.

Impact

The dev command (trigger.dev dev) will start up the worker runtime and then immediately shut it down, making the dev command unusable. Users will see the dev session start briefly and then exit.

Recommendation: The waitUntilExit function should return a Promise that never resolves (or resolves only when signaled to exit). For example:

const waitUntilExit = () => new Promise<void>(() => {});

Or better, create a mechanism to resolve the promise when the dev session should exit.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli-v3/src/deploy/buildImage.ts (1)

642-653: ⚠️ Potential issue | 🟡 Minor

Missing Docker Hub logout on build failure.

When the build fails (exitCode !== 0), the code logs out from cloudRegistryHost but doesn't log out from Docker Hub if loggedInToDockerHub is true. This is inconsistent with the success path at lines 698-701.

🔧 Proposed fix
   if (buildProcess.exitCode !== 0) {
     if (cloudRegistryHost) {
       logger.debug(`Logging out from docker registry: ${cloudRegistryHost}`);
       await x("docker", ["logout", cloudRegistryHost]);
     }
+
+    if (loggedInToDockerHub) {
+      logger.debug("Logging out from Docker Hub");
+      await x("docker", ["logout"]);
+    }
 
     return {
       ok: false as const,
       error: "Error building image",
       logs: extractLogs(errors),
     };
   }
🤖 Fix all issues with AI agents
In @.changeset/fix-docker-hub-rate-limit-2911.md:
- Line 5: The changeset entry contains a duplicated word "checking checking" in
the release note string; edit the changeset text to remove the duplicate so it
reads "checking `DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables
and logging into Docker Hub before building." Make this single-word fix in the
changeset entry where the phrase appears.

In `@packages/cli-v3/src/commands/dev.ts`:
- Around line 182-206: The dev session is exiting immediately because
devInstance.waitUntilExit is a no-op; change waitUntilExit (the method returned
by startDev / defined in devSession.ts) to return a Promise that only resolves
when the session stops (i.e., when devInstance.stop() is called) or when an
external termination signal occurs; implement this by wiring stop() to resolve a
stored Promise (or awaiting an EventEmitter/AbortSignal) so that await
devInstance.waitUntilExit() blocks until cleanup/signalHandler triggers stop(),
ensuring the bundler/watch stays alive until explicit stop.

In `@packages/core/src/v3/consoleInterceptor.ts`:
- Around line 95-113: In ConsoleInterceptor's stdio forwarding (when
this.sendToStdIO and this.originalConsole are set) the INFO branch currently
always calls this.originalConsole.log(...args); change the INFO handling in the
switch (where severityNumber === SeverityNumber.INFO) to inspect the
severityText parameter and call this.originalConsole.info(...args) when
severityText indicates "Info" (otherwise fallback to
this.originalConsole.log(...args)); keep all other severity branches (WARN,
ERROR, DEBUG, default) unchanged so console.info() is routed to
originalConsole.info() while console.log() still uses originalConsole.log().
🧹 Nitpick comments (3)
packages/cli-v3/src/commands/dev.ts (1)

291-291: Empty waitUntilExit function body.

This no-op function causes the dev command to proceed directly to the finally block after starting. If this is intentional, consider adding a comment explaining why blocking is unnecessary here.

💡 Suggested documentation
-    const waitUntilExit = async () => { };
+    // Process stays alive via the config watcher; signal handlers manage cleanup
+    const waitUntilExit = async () => {};
packages/cli-v3/src/commands/update.test.ts (2)

10-51: Consider the guideline on avoiding mocks.

The coding guidelines state "Use vitest exclusively for testing and never mock anything - use testcontainers instead." However, testcontainers are primarily for database/Redis testing, not CLI operations.

For CLI unit tests, mocking package manager operations, file system, and user prompts is a pragmatic approach since these operations can't be containerized. If the team prefers integration tests, you could create actual package.json files in a temp directory and run real install commands, but that would significantly slow down tests and add complexity.

The current mocking approach is reasonable for this use case. If the guidelines should exclude CLI tests from the "no mocks" rule, consider updating them for clarity.


74-112: Tests cover the primary scenarios well.

The four test cases verify:

  • npm with --no-engine-strict
  • pnpm with --config.engine-strict=false
  • yarn with --ignore-engines
  • npm without engine flags when ignoreEngines: false

Consider adding coverage for edge cases:

  1. When packageManager detection returns undefined (should not add any flags)
  2. When an unsupported package manager like bun is detected (should not add engine flags)
💡 Suggested additional test cases
it("should NOT pass engine flags when packageManager is undefined", async () => {
    vi.mocked(nypm.detectPackageManager).mockResolvedValue(undefined as any);

    await updateTriggerPackages(".", { ignoreEngines: true } as any, true, true);

    expect(nypm.installDependencies).toHaveBeenCalledWith(expect.objectContaining({
        args: [],
    }));
});

it("should NOT pass engine flags for unsupported package managers (bun)", async () => {
    vi.mocked(nypm.detectPackageManager).mockResolvedValue({ name: "bun", command: "bun", version: "1.0.0" } as any);

    await updateTriggerPackages(".", { ignoreEngines: true } as any, true, true);

    expect(nypm.installDependencies).toHaveBeenCalledWith(expect.objectContaining({
        args: [],
    }));
});
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ccb8c1 and 737ad56.

📒 Files selected for processing (10)
  • .changeset/fix-console-interceptor-2900.md
  • .changeset/fix-docker-hub-rate-limit-2911.md
  • .changeset/fix-github-install-node-version-2913.md
  • .changeset/fix-orphaned-workers-2909.md
  • packages/cli-v3/src/commands/deploy.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/update.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/core/src/v3/consoleInterceptor.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • packages/cli-v3/src/commands/update.ts
  • packages/core/src/v3/consoleInterceptor.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • packages/cli-v3/src/commands/update.ts
  • packages/core/src/v3/consoleInterceptor.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • packages/cli-v3/src/commands/update.ts
  • packages/core/src/v3/consoleInterceptor.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • packages/cli-v3/src/commands/update.ts
  • packages/core/src/v3/consoleInterceptor.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
{packages,integrations}/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Add a changeset when modifying any public package in packages/* or integrations/* using pnpm run changeset:add

Files:

  • packages/cli-v3/src/commands/update.ts
  • packages/core/src/v3/consoleInterceptor.ts
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/dev.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/commands/deploy.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • packages/core/src/v3/consoleInterceptor.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use vitest for all tests in the Trigger.dev repository

Files:

  • packages/cli-v3/src/commands/update.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx,js,jsx}: Test files should live beside the files under test and use descriptive describe and it blocks
Tests should avoid mocks or stubs and use the helpers from @internal/testcontainers when Redis or Postgres are needed
Use vitest for running unit tests

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • packages/cli-v3/src/commands/update.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use testcontainers helpers (redisTest, postgresTest, containerTest) from @internal/testcontainers for Redis/PostgreSQL testing instead of mocks

Files:

  • packages/cli-v3/src/commands/update.test.ts
🧠 Learnings (19)
📓 Common learnings
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Default to patch version for changesets for bug fixes and minor changes; confirm with maintainers before selecting minor or major

Applied to files:

  • .changeset/fix-github-install-node-version-2913.md
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to {packages,integrations}/**/* : Add a changeset when modifying any public package in `packages/*` or `integrations/*` using `pnpm run changeset:add`

Applied to files:

  • .changeset/fix-github-install-node-version-2913.md
  • packages/cli-v3/src/commands/update.test.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • .changeset/fix-github-install-node-version-2913.md
  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-14T19:24:39.536Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2685
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx:1234-1257
Timestamp: 2025-11-14T19:24:39.536Z
Learning: In the trigger.dev project, version validation for the `useNativeBuildServer` setting cannot be performed at the settings form level because the SDK version is only known at build/deployment time, not when saving project settings.

Applied to files:

  • .changeset/fix-github-install-node-version-2913.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks

Applied to files:

  • .changeset/fix-github-install-node-version-2913.md
  • .changeset/fix-orphaned-workers-2909.md
  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-10-08T11:48:12.327Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.

Applied to files:

  • .changeset/fix-orphaned-workers-2909.md
📚 Learning: 2025-11-27T16:26:44.496Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/executing-commands.mdc:0-0
Timestamp: 2025-11-27T16:26:44.496Z
Learning: For running tests, navigate into the package directory and run `pnpm run test --run` to enable single-file test execution (e.g., `pnpm run test ./src/engine/tests/ttl.test.ts --run`)

Applied to files:

  • packages/cli-v3/src/commands/update.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use vitest for all tests in the Trigger.dev repository

Applied to files:

  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest exclusively for testing and never mock anything - use testcontainers instead

Applied to files:

  • packages/cli-v3/src/commands/update.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to packages/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Applied to files:

  • packages/cli-v3/src/commands/update.test.ts
  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Run `npx trigger.devlatest dev` to start the Trigger.dev development server

Applied to files:

  • packages/cli-v3/src/commands/dev.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export tasks with unique IDs within the project to enable proper task discovery and execution

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure build process in trigger.config.ts using `build` object with external packages, extensions, and JSX settings

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.{ts,tsx} : Always import tasks from `trigger.dev/sdk`, never use `trigger.dev/sdk/v3` or deprecated `client.defineJob` pattern

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure Trigger.dev project in `trigger.config.ts` using `defineConfig()` with project ref and task directories

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
🧬 Code graph analysis (1)
packages/cli-v3/src/commands/deploy.ts (2)
packages/cli-v3/src/commands/update.ts (1)
  • updateTriggerPackages (51-304)
packages/cli-v3/src/utilities/cliOutput.ts (5)
  • isLinksSupported (7-7)
  • chalkError (24-26)
  • cliLink (140-145)
  • chalkWarning (28-30)
  • chalkGrey (20-22)
🔇 Additional comments (14)
.changeset/fix-console-interceptor-2900.md (1)

1-5: LGTM!

Changeset is properly formatted with appropriate patch-level versioning for this bug fix.

.changeset/fix-github-install-node-version-2913.md (1)

1-5: LGTM!

Changeset is properly formatted with appropriate patch-level versioning for this deployment fix.

packages/cli-v3/src/commands/update.ts (3)

18-22: LGTM!

The ignoreEngines option is properly added to the UpdateCommandOptions schema by picking it from CommonCommandOptions.


261-277: LGTM!

The engine-ignoring flags are correctly mapped for each package manager:

  • npm: --no-engine-strict
  • pnpm: --config.engine-strict=false
  • yarn: --ignore-engines

The guard condition properly checks both ignoreEngines and packageManager before applying flags.


278-282: LGTM!

Error message formatting is unchanged in substance.

packages/cli-v3/src/commands/dev.ts (1)

173-176: LGTM!

Minor reformatting of error message template string.

.changeset/fix-orphaned-workers-2909.md (1)

1-5: LGTM!

Changeset is properly formatted with appropriate patch-level versioning. The description accurately reflects the signal handling fix for orphaned workers.

packages/cli-v3/src/deploy/buildImage.ts (3)

476-508: Good security practice using --password-stdin.

The Docker Hub authentication correctly uses stdin to pass the password, avoiding exposure in process listings. The login state tracking with loggedInToDockerHub is clean.


585-592: LGTM!

Cache argument reformatting maintains equivalent functionality.


698-701: LGTM!

Proper cleanup of Docker Hub session on successful build completion.

packages/cli-v3/src/commands/deploy.ts (3)

255-255: Nice: pass ignoreEngines into the update step.

This keeps the update flow consistent with the new package-manager flags.


492-493: Output/link template consolidation looks good.

The inline templates preserve the existing env selection while making the output paths more compact.

Also applies to: 710-711, 734-735, 742-743, 786-787, 1086-1087, 1153-1154, 1236-1237, 1251-1252, 1277-1283, 1295-1296, 1302-1303, 1314-1315, 1321-1322, 1333-1334, 1340-1341, 1359-1365


1200-1203: Log-level styling preserved.

Warn/debug formatting remains intact after the ternary refactor.

packages/core/src/v3/consoleInterceptor.ts (1)

16-63: Good: capture and restore the original console methods.

This keeps interceptors intact and avoids leaving the console in a patched state after completion.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

"@trigger.dev/cli-v3": patch
---

Fix: Native build server failed with Docker Hub rate limits. Added support for checking checking `DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables and logging into Docker Hub before building. (#2911)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix duplicated word in the changeset entry.

Minor typo (“checking checking”) in user-facing release notes.

📝 Suggested fix
-Fix: Native build server failed with Docker Hub rate limits. Added support for checking checking `DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables and logging into Docker Hub before building. (`#2911`)
+Fix: Native build server failed with Docker Hub rate limits. Added support for checking `DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables and logging into Docker Hub before building. (`#2911`)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Fix: Native build server failed with Docker Hub rate limits. Added support for checking checking `DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables and logging into Docker Hub before building. (#2911)
Fix: Native build server failed with Docker Hub rate limits. Added support for checking `DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables and logging into Docker Hub before building. (`#2911`)
🤖 Prompt for AI Agents
In @.changeset/fix-docker-hub-rate-limit-2911.md at line 5, The changeset entry
contains a duplicated word "checking checking" in the release note string; edit
the changeset text to remove the duplicate so it reads "checking
`DOCKER_USERNAME` and `DOCKER_PASSWORD` in environment variables and logging
into Docker Hub before building." Make this single-word fix in the changeset
entry where the phrase appears.

Comment on lines +182 to 206
let devInstance: Awaited<ReturnType<typeof startDev>> | undefined;

const cleanup = async () => {
if (devInstance) {
await devInstance.stop();
}
};

const signalHandler = async (signal: string) => {
logger.debug(`Received ${signal}, cleaning up...`);
await cleanup();
process.exit(0);
};

try {
const devInstance = await startDev({ ...options, cwd: process.cwd(), login: authorization });
watcher = devInstance.watcher;
process.on("SIGINT", signalHandler);
process.on("SIGTERM", signalHandler);

devInstance = await startDev({ ...options, cwd: process.cwd(), login: authorization });
await devInstance.waitUntilExit();
} finally {
await watcher?.stop();
process.off("SIGINT", signalHandler);
process.off("SIGTERM", signalHandler);
await cleanup();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the dev.ts file around the lines in question
cat -n packages/cli-v3/src/commands/dev.ts | sed -n '280,310p'

Repository: triggerdotdev/trigger.dev

Length of output: 857


🏁 Script executed:

# Let's also see the full context of the try-finally block and startDev
cat -n packages/cli-v3/src/commands/dev.ts | sed -n '170,210p'

Repository: triggerdotdev/trigger.dev

Length of output: 1442


🏁 Script executed:

# Search for startDev function definition to understand the full lifecycle
rg -n 'const startDev|function startDev' packages/cli-v3/src/commands/dev.ts -A 30

Repository: triggerdotdev/trigger.dev

Length of output: 1088


🏁 Script executed:

# Check if there's a watcher that might keep the process alive
rg -n 'watcher\|event loop\|setInterval\|setTimeout' packages/cli-v3/src/commands/dev.ts | head -20

Repository: triggerdotdev/trigger.dev

Length of output: 51


🏁 Script executed:

# Search for watchConfig implementation
rg -n 'export.*watchConfig|const watchConfig|function watchConfig' packages/cli-v3/src/ -A 5 --type=ts

Repository: triggerdotdev/trigger.dev

Length of output: 392


🏁 Script executed:

# Check what bootDevSession does
rg -n 'bootDevSession' packages/cli-v3/src/commands/dev.ts -B 2 -A 15

Repository: triggerdotdev/trigger.dev

Length of output: 1399


🏁 Script executed:

# See if there are any imports or setup that might explain the lifecycle
head -50 packages/cli-v3/src/commands/dev.ts

Repository: triggerdotdev/trigger.dev

Length of output: 2316


🏁 Script executed:

# Look for any existing test files or documentation that explains the expected behavior
fd -e test.ts -e spec.ts packages/cli-v3/src/commands/dev | head -5

Repository: triggerdotdev/trigger.dev

Length of output: 51


🏁 Script executed:

# Let's examine the watchConfig implementation in config.ts to see if it sets up file watchers that keep the process alive
cat -n packages/cli-v3/src/config.ts | sed -n '62,150p'

Repository: triggerdotdev/trigger.dev

Length of output: 3206


🏁 Script executed:

# Check the return type of watchConfig to understand what gets returned
rg -n 'return {' packages/cli-v3/src/config.ts | head -10

Repository: triggerdotdev/trigger.dev

Length of output: 148


🏁 Script executed:

# Let's see what the watcher setup looks like - search for chokidar or file watch setup
rg -n 'chokidar\|watch\|FSWatcher' packages/cli-v3/src/config.ts -B 2 -A 2

Repository: triggerdotdev/trigger.dev

Length of output: 51


🏁 Script executed:

# Check devSession to understand what startDevSession returns
rg -n 'export.*startDevSession|function startDevSession' packages/cli-v3/src/dev/devSession.ts -A 20 | head -40

Repository: triggerdotdev/trigger.dev

Length of output: 698


🏁 Script executed:

# Get the full startDevSession function to see what DevSessionInstance contains and what it does
cat -n packages/cli-v3/src/dev/devSession.ts | sed -n '50,150p'

Repository: triggerdotdev/trigger.dev

Length of output: 3562


🏁 Script executed:

# Check the DevSessionInstance type definition
rg -n 'type DevSessionInstance|interface DevSessionInstance' packages/cli-v3/src/dev/devSession.ts -A 10

Repository: triggerdotdev/trigger.dev

Length of output: 274


🏁 Script executed:

# Let's check what startWorkerRuntime returns and if it keeps the process alive
rg -n 'startWorkerRuntime|return {' packages/cli-v3/src/dev/devSession.ts | head -20

Repository: triggerdotdev/trigger.dev

Length of output: 186


🏁 Script executed:

# Look at the end of startDevSession to see what it returns
cat -n packages/cli-v3/src/dev/devSession.ts | tail -100

Repository: triggerdotdev/trigger.dev

Length of output: 3334


The waitUntilExit no-op creates a critical bug: the dev session terminates immediately after starting.

The bundler is started in watch mode (line 200 of devSession.ts, via bundleWorker with watch: true), which keeps the process alive by monitoring file changes. However:

  1. await devInstance.waitUntilExit() (line 291 of dev.ts) is an empty async function that returns immediately
  2. The finally block (lines 202-206) then executes and calls cleanup()
  3. cleanup() calls devInstance.stop(), which stops the bundler and file watchers
  4. The dev session terminates before any user interaction

In normal operation (without signals), the dev session would start and immediately stop, preventing the CLI from functioning. The signal handler flow (SIGINT/SIGTERMcleanup()process.exit(0)) would work correctly if a user manually terminates, but the command would not stay alive waiting for that signal.

The waitUntilExit function needs to block indefinitely while the dev session is running, not be a no-op.

🤖 Prompt for AI Agents
In `@packages/cli-v3/src/commands/dev.ts` around lines 182 - 206, The dev session
is exiting immediately because devInstance.waitUntilExit is a no-op; change
waitUntilExit (the method returned by startDev / defined in devSession.ts) to
return a Promise that only resolves when the session stops (i.e., when
devInstance.stop() is called) or when an external termination signal occurs;
implement this by wiring stop() to resolve a stored Promise (or awaiting an
EventEmitter/AbortSignal) so that await devInstance.waitUntilExit() blocks until
cleanup/signalHandler triggers stop(), ensuring the bundler/watch stays alive
until explicit stop.

Comment on lines 95 to +113
if (this.sendToStdIO) {
if (severityNumber === SeverityNumber.ERROR) {
process.stderr.write(body);
if (this.originalConsole) {
switch (severityNumber) {
case SeverityNumber.INFO:
this.originalConsole.log(...args);
break;
case SeverityNumber.WARN:
this.originalConsole.warn(...args);
break;
case SeverityNumber.ERROR:
this.originalConsole.error(...args);
break;
case SeverityNumber.DEBUG:
this.originalConsole.debug(...args);
break;
default:
this.originalConsole.log(...args);
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the consoleInterceptor.ts file to understand the full context
cat -n packages/core/src/v3/consoleInterceptor.ts | head -150

Repository: triggerdotdev/trigger.dev

Length of output: 5440


🏁 Script executed:

#!/bin/bash
# Search for console.info wrapping or assignment patterns
rg -n 'console\.info\s*=' --type ts --type tsx
rg -n 'console\.info\s*:' --type ts --type tsx
# Check for any console.info patches/spies
rg -n '(jest\.spyOn|sinon|spy).*console\.info' --type ts --type tsx
# Search for ConsoleInterceptor usage
rg -n 'ConsoleInterceptor' --type ts --type tsx

Repository: triggerdotdev/trigger.dev

Length of output: 180


🏁 Script executed:

#!/bin/bash
# Search for console.info wrapping or assignment patterns
rg -n 'console\.info\s*=' -g '*.ts' -g '*.tsx'
# Check for console.info patches/spies
rg -n '(jest\.spyOn|sinon|spy).*console\.info' -g '*.ts' -g '*.tsx'
# Search for ConsoleInterceptor usage and tests
rg -n 'ConsoleInterceptor' -g '*.ts' -g '*.tsx' -g '*.js' | head -30

Repository: triggerdotdev/trigger.dev

Length of output: 2086


🏁 Script executed:

#!/bin/bash
# Look at the test file to understand expected behavior
cat -n packages/core/test/taskExecutor.test.ts | sed -n '1900,1950p'
# Also check if there are any specific tests for console.info routing
rg -n 'console\.info' -g '*.test.ts' -B2 -A2 packages/core/test/

Repository: triggerdotdev/trigger.dev

Length of output: 1525


🏁 Script executed:

#!/bin/bash
# Search for console.info in test files
rg -n 'console\.info' -g '*.test.ts' -B3 -A3
# Search for console method testing in consoleInterceptor context
rg -n 'console\.(log|info|warn|error|debug)' packages/core/test/ -g '*.test.ts' -B2 -A2 | head -100

Repository: triggerdotdev/trigger.dev

Length of output: 7205


🏁 Script executed:

#!/bin/bash
# Check for any console method wrapping or middleware in the codebase
rg -n 'originalConsole' -B3 -A3 packages/core/src/v3/
# Check if info/log distinction matters in the logger.emit calls
rg -n 'severityText' packages/core/src/v3/consoleInterceptor.ts -B2 -A2

Repository: triggerdotdev/trigger.dev

Length of output: 4314


Preserve console.info() routing to maintain consistency with logger output.

Both console.log() and console.info() map to SeverityNumber.INFO, but the current code always dispatches INFO severity to originalConsole.log() (line 99), bypassing originalConsole.info(). The severityText parameter already distinguishes these calls ("Log" vs "Info" at lines 72 and 76) and is used in logger.emit(), so the distinction should also be applied when delegating to stdio. Route INFO calls based on severityText so info() calls use originalConsole.info().

🛠️ Suggested fix
         switch (severityNumber) {
           case SeverityNumber.INFO:
-            this.originalConsole.log(...args);
+            (severityText === "Info" ? this.originalConsole.info : this.originalConsole.log)(
+              ...args
+            );
             break;
🤖 Prompt for AI Agents
In `@packages/core/src/v3/consoleInterceptor.ts` around lines 95 - 113, In
ConsoleInterceptor's stdio forwarding (when this.sendToStdIO and
this.originalConsole are set) the INFO branch currently always calls
this.originalConsole.log(...args); change the INFO handling in the switch (where
severityNumber === SeverityNumber.INFO) to inspect the severityText parameter
and call this.originalConsole.info(...args) when severityText indicates "Info"
(otherwise fallback to this.originalConsole.log(...args)); keep all other
severity branches (WARN, ERROR, DEBUG, default) unchanged so console.info() is
routed to originalConsole.info() while console.log() still uses
originalConsole.log().

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.

bug:

1 participant