-
-
Notifications
You must be signed in to change notification settings - Fork 967
feat(supervisor): add automated worker setup script #2904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(supervisor): add automated worker setup script #2904
Conversation
- Add interactive bash script to automate worker group creation - Support CLI arguments, environment variables, and .env files - Auto-resolve project external refs to internal IDs - Include dry-run mode for testing - Add --list-projects command to discover project IDs - Add comprehensive documentation in README with Quick Setup section - Include finding PAT instructions for all platforms - Add appendix explaining project ID types
|
WalkthroughThis pull request adds comprehensive documentation and a new automation script to the supervisor application. The README.md is expanded with setup instructions, prerequisites, usage examples, script options, and guidance on finding credentials and managing worker groups. A new setup-worker.sh Bash script is introduced that automates the creation and configuration of Trigger.dev worker groups for self-hosted instances, including features for dependency checking, environment loading, argument parsing, interactive prompting, API validation, project listing, and worker creation with dry-run support. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
Review CompleteYour review story is ready! Comment !reviewfast on this PR to re-generate the story. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@apps/supervisor/README.md`:
- Around line 68-72: The PAT placeholder in the options table for `--pat`
currently uses `tr*pat*...` which renders with emphasis; replace that
placeholder with escaped underscores so it reads `tr\_pat\_...` (matching the
existing `proj\_...` pattern used for `--project-ref`) to prevent markdown
formatting and display the literal underscores.
- Around line 98-102: Replace the Windows PowerShell snippet that uses CMD-style
%APPDATA% and the alias type with PowerShell-native equivalents: use
$env:APPDATA instead of %APPDATA% and use Get-Content in place of type, then
pipe to jq as before (locate the README snippet containing "%APPDATA%" and "type
%APPDATA%\trigger\config.json | jq -r \".profiles.default.accessToken\"").
In `@apps/supervisor/scripts/setup-worker.sh`:
- Around line 186-195: The interactive prompt in function prompt_interactive
currently reads the PAT with read -r which echoes the token; change the read
invocation for PAT to use a silent read (add the -s flag) so input is not shown,
and after the silent read emit a newline (e.g., an extra echo) so the terminal
prompt formatting stays correct; update the read that assigns to the PAT
variable and ensure subsequent logic that uses PAT remains unchanged.
- Around line 227-235: In validate_pat(), avoid printing the full secret;
instead build a masked version of the PAT that shows only the first 7 and last 4
characters and replace the middle with asterisks (e.g., "${PAT:0:7}***${PAT:
-4}"), then use that masked value in the echo that currently prints "Got:
$PAT" so logs show the masked token while preserving the existing error messages
and behavior.
- Around line 336-352: In create_worker, the jq payload currently uses
($projectId // null) which returns an empty string instead of null when
PROJECT_ID is empty; update the jq expression in the json_payload construction
so it explicitly converts an empty projectId to null (e.g., by testing length or
equality and returning null for empty strings) while still passing PROJECT_ID
via --arg, so projectId becomes null when no project is selected.
- Around line 255-274: In test_api_connection(), curl can fail and abort the
script under set -euo pipefail; modify the curl invocation to capture its exit
code (e.g., initialize curl_exit=0, run response=$(curl -sS -w "\n%{http_code}"
-H "Authorization: Bearer $PAT" "$API_URL/api/v1/projects" 2>&1) ||
curl_exit=$?), then check curl_exit first and on non-zero emit a clear error via
error "Curl failed (exit $curl_exit)" plus the captured response/body and exit
1; otherwise parse http_code/body as before and keep the existing HTTP status
check.
- Around line 488-499: The CLI allows the --default flag without a project,
causing an invalid payload; add a validation that if the default flag is set
(e.g., DEFAULT or MAKE_DEFAULT variable) then either PROJECT_REF or PROJECT_ID
must be present (or resolve_project_id must succeed) and otherwise print an
error and exit; implement this check after resolve_project_id is run (use
resolve_project_id, PROJECT_REF, PROJECT_ID and the default flag variable names
from the script) so the CLI path mirrors the interactive prompt enforcement.
- Around line 138-183: In parse_arguments, validate the presence and content of
the value for options that consume $2 (e.g., --name -> WORKER_NAME, --pat ->
PAT, --api-url -> API_URL, --project-ref -> PROJECT_REF, --project-id ->
PROJECT_ID) before shifting; specifically check that a non-empty argument exists
(guarding against set -u unbound errors) and that the next token is not another
flag (starts with '-') and emit a clear error and exit if validation fails, then
only assign and shift 2 when the check passes.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/supervisor/README.mdapps/supervisor/scripts/setup-worker.sh
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
apps/supervisor/README.md
🧠 Learnings (6)
📚 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 init` to initialize a Trigger.dev project
Applied to files:
apps/supervisor/README.md
📚 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: Use `trigger.dev/redis-worker` for background job and worker system needs in the webapp and run engine
Applied to files:
apps/supervisor/README.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: Run `npx trigger.devlatest dev` to start the Trigger.dev development server
Applied to files:
apps/supervisor/README.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.config.ts : Configure Trigger.dev project in `trigger.config.ts` using `defineConfig()` with project ref and task directories
Applied to files:
apps/supervisor/README.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} : Export tasks with unique IDs within the project to enable proper task discovery and execution
Applied to files:
apps/supervisor/README.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 the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties
Applied to files:
apps/supervisor/README.md
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| | Option | Description | | ||
| | --------------------- | ----------------------------------------- | | ||
| | `--name <name>` | Worker group name (required) | | ||
| | `--pat <token>` | Personal Access Token (tr*pat*...) | | ||
| | `--api-url <url>` | Trigger.dev API URL | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
head -n 75 apps/supervisor/README.md | tail -n 15Repository: triggerdotdev/trigger.dev
Length of output: 717
Use escaped underscores for the PAT format placeholder, matching the project-ref pattern.
In the options table, tr*pat*... will render with asterisks creating emphasis. However, the suggested fix using tr_pat_... doesn't solve this since underscores also trigger markdown formatting. Use escaped underscores instead: tr\_pat\_... to match the proj\_... pattern already used in the same table for the --project-ref option.
✅ Suggested fix
-| `--pat <token>` | Personal Access Token (tr*pat*...) |
+| `--pat <token>` | Personal Access Token (tr\_pat\_...) |🤖 Prompt for AI Agents
In `@apps/supervisor/README.md` around lines 68 - 72, The PAT placeholder in the
options table for `--pat` currently uses `tr*pat*...` which renders with
emphasis; replace that placeholder with escaped underscores so it reads
`tr\_pat\_...` (matching the existing `proj\_...` pattern used for
`--project-ref`) to prevent markdown formatting and display the literal
underscores.
| **Windows:** | ||
|
|
||
| ```powershell | ||
| type %APPDATA%\trigger\config.json | jq -r ".profiles.default.accessToken" | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
git ls-files "apps/supervisor/README.md"Repository: triggerdotdev/trigger.dev
Length of output: 194
🏁 Script executed:
cat -n apps/supervisor/README.md | sed -n '95,105p'Repository: triggerdotdev/trigger.dev
Length of output: 339
🌐 Web query:
PowerShell %APPDATA% variable expansion vs $env:APPDATA
💡 Result:
Short answer
- %APPDATA% is the CMD/Windows “%VAR%” expansion syntax; PowerShell does not expand it. Use $env:APPDATA (or .NET APIs) in PowerShell. [1][2][3]
Details + examples
- PowerShell exposes environment variables through the Env: drive and $env:Name shorthand; $env:APPDATA returns the AppData path. Use that inside strings: "$env:APPDATA\MyApp". [3][4]
- %APPDATA% will only be expanded if you run it inside cmd.exe (e.g. & cmd /c "echo %APPDATA%") or explicitly call an API that expands %VAR% (e.g. [Environment]::ExpandEnvironmentVariables). PowerShell itself treats "%APPDATA%" as a literal string. [2][5]
- Alternatives:
- $env:APPDATA — recommended for scripts.
- [Environment]::GetEnvironmentVariable("APPDATA") — explicit .NET call.
- [Environment]::ExpandEnvironmentVariables("%APPDATA%\x") — expands percent notation if you must use it. [5]
Example
- Correct PowerShell:
- $p = "$env:APPDATA\MyApp"
- If you have a literal "%APPDATA%\X" and want it expanded:
- $p = [Environment]::ExpandEnvironmentVariables("%APPDATA%\MyApp") . [5]
References
- StackOverflow: % is for cmd.exe; use $env:... in PowerShell. [1].
- Microsoft Q&A / PowerShell guidance recommending $env:USERNAME. [2].
- SS64 / PowerShell Env: drive documentation. [4].
- Opensource.com article on environment variables in PowerShell. [3].
- .NET Environment methods (ExpandEnvironmentVariables / GetEnvironmentVariable) referenced in SS64 and docs. [4][5].
PowerShell syntax: %APPDATA% is CMD-style and will not expand in PowerShell.
Use $env:APPDATA instead. Additionally, use Get-Content (the native PowerShell command) rather than type.
✅ Suggested fix
-type %APPDATA%\trigger\config.json | jq -r ".profiles.default.accessToken"
+Get-Content "$env:APPDATA\trigger\config.json" | jq -r ".profiles.default.accessToken"🤖 Prompt for AI Agents
In `@apps/supervisor/README.md` around lines 98 - 102, Replace the Windows
PowerShell snippet that uses CMD-style %APPDATA% and the alias type with
PowerShell-native equivalents: use $env:APPDATA instead of %APPDATA% and use
Get-Content in place of type, then pipe to jq as before (locate the README
snippet containing "%APPDATA%" and "type %APPDATA%\trigger\config.json | jq -r
\".profiles.default.accessToken\"").
| parse_arguments() { | ||
| while [[ $# -gt 0 ]]; do | ||
| case $1 in | ||
| --name) | ||
| WORKER_NAME="$2" | ||
| shift 2 | ||
| ;; | ||
| --pat) | ||
| PAT="$2" | ||
| shift 2 | ||
| ;; | ||
| --api-url) | ||
| API_URL="$2" | ||
| shift 2 | ||
| ;; | ||
| --project-ref) | ||
| PROJECT_REF="$2" | ||
| shift 2 | ||
| ;; | ||
| --project-id) | ||
| PROJECT_ID="$2" | ||
| shift 2 | ||
| ;; | ||
| --default) | ||
| MAKE_DEFAULT=1 | ||
| shift | ||
| ;; | ||
| --list-projects) | ||
| LIST_PROJECTS=1 | ||
| shift | ||
| ;; | ||
| --dry-run) | ||
| DRY_RUN=1 | ||
| shift | ||
| ;; | ||
| --help|-h) | ||
| show_help | ||
| exit 0 | ||
| ;; | ||
| *) | ||
| error "Unknown option: $1" | ||
| echo "Run with --help for usage information" | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/supervisor/scripts/setup-worker.sh | head -200Repository: triggerdotdev/trigger.dev
Length of output: 6127
🏁 Script executed:
sed -n '200,350p' apps/supervisor/scripts/setup-worker.sh | cat -nRepository: triggerdotdev/trigger.dev
Length of output: 5153
🏁 Script executed:
sed -n '350,450p' apps/supervisor/scripts/setup-worker.sh | cat -nRepository: triggerdotdev/trigger.dev
Length of output: 3378
🏁 Script executed:
sed -n '400,500p' apps/supervisor/scripts/setup-worker.sh | cat -nRepository: triggerdotdev/trigger.dev
Length of output: 3115
🏁 Script executed:
# Test the actual behavior of parse_arguments with missing argument value
cat > /tmp/test_parse.sh << 'EOF'
#!/bin/bash
set -euo pipefail
ERROR_TRIGGERED=0
trap 'ERROR_TRIGGERED=1' ERR
# Simulate parse_arguments
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
--name)
WORKER_NAME="$2"
shift 2
;;
*)
echo "Unknown: $1"
exit 1
;;
esac
done
}
# Test 1: Missing argument value
echo "Test 1: --name without value"
if ! parse_arguments --name 2>&1; then
echo "ERROR: Script failed as expected"
fi
echo ""
echo "Test 2: --name with value"
parse_arguments --name "my-worker"
echo "SUCCESS: Script completed normally"
EOF
chmod +x /tmp/test_parse.sh
bash /tmp/test_parse.sh 2>&1 || trueRepository: triggerdotdev/trigger.dev
Length of output: 147
🏁 Script executed:
# Test more edge cases to understand the behavior fully
cat > /tmp/test_parse2.sh << 'EOF'
#!/bin/bash
set -euo pipefail
WORKER_NAME=""
PAT=""
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
--name)
WORKER_NAME="$2"
shift 2
;;
--pat)
PAT="$2"
shift 2
;;
*)
echo "Unknown: $1"
exit 1
;;
esac
done
}
# Test 1: --name followed by another flag
echo "Test 1: --name followed by --pat"
if parse_arguments --name --pat 2>&1; then
echo "RESULT: parse_arguments completed"
echo "WORKER_NAME='$WORKER_NAME'"
echo "PAT='$PAT'"
else
echo "FAILED"
fi
EOF
chmod +x /tmp/test_parse2.sh
bash /tmp/test_parse2.sh 2>&1 || trueRepository: triggerdotdev/trigger.dev
Length of output: 162
🏁 Script executed:
# Test the projectId handling and PAT echo issue
cat > /tmp/test_json.sh << 'EOF'
#!/bin/bash
# Test 1: Empty PROJECT_ID
echo "Test 1: Empty PROJECT_ID"
PROJECT_ID=""
WORKER_NAME="test"
MAKE_DEFAULT="false"
json_payload=$(jq -n \
--arg name "$WORKER_NAME" \
--arg projectId "$PROJECT_ID" \
--argjson makeDefault "$MAKE_DEFAULT" \
'{name: $name, projectId: ($projectId // null), makeDefaultForProject: $makeDefault}')
echo "Result: $json_payload"
echo ""
echo "Test 2: Non-empty PROJECT_ID"
PROJECT_ID="cmk_123"
json_payload=$(jq -n \
--arg name "$WORKER_NAME" \
--arg projectId "$PROJECT_ID" \
--argjson makeDefault "$MAKE_DEFAULT" \
'{name: $name, projectId: ($projectId // null), makeDefaultForProject: $makeDefault}')
echo "Result: $json_payload"
EOF
bash /tmp/test_json.shRepository: triggerdotdev/trigger.dev
Length of output: 294
🏁 Script executed:
# Verify the PAT echo issue
grep -n "Got:" apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 98
🏁 Script executed:
# Verify curl error handling with set -euo pipefail
cat > /tmp/test_curl.sh << 'EOF'
#!/bin/bash
set -euo pipefail
# Simulate curl failure
test_curl_error() {
local response
response=$(curl -sS "http://invalid.example.com/api" 2>&1 || echo "CURL_FAILED")
echo "Response: $response"
}
echo "Testing curl error with set -euo pipefail:"
test_curl_error 2>&1 || echo "Function failed"
EOF
bash /tmp/test_curl.shRepository: triggerdotdev/trigger.dev
Length of output: 187
Validate option values before consuming $2.
With set -u, a missing argument value causes an unbound variable error that exits the script abruptly. Additionally, if an option is followed by another flag instead of a value (e.g., --name --pat), the next flag gets consumed as the value, misaligning subsequent argument parsing. Add explicit guards for options requiring values.
✅ Suggested fix
parse_arguments() {
+ require_value() {
+ local opt="$1"
+ local val="${2-}"
+ if [[ -z "$val" || "$val" == --* ]]; then
+ error "Option $opt requires a value"
+ exit 1
+ fi
+ }
while [[ $# -gt 0 ]]; do
case $1 in
--name)
+ require_value --name "$2"
WORKER_NAME="$2"
shift 2
;;
--pat)
+ require_value --pat "$2"
PAT="$2"
shift 2
;;
--api-url)
+ require_value --api-url "$2"
API_URL="$2"
shift 2
;;
--project-ref)
+ require_value --project-ref "$2"
PROJECT_REF="$2"
shift 2
;;
--project-id)
+ require_value --project-id "$2"
PROJECT_ID="$2"
shift 2
;;📝 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.
| parse_arguments() { | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| --name) | |
| WORKER_NAME="$2" | |
| shift 2 | |
| ;; | |
| --pat) | |
| PAT="$2" | |
| shift 2 | |
| ;; | |
| --api-url) | |
| API_URL="$2" | |
| shift 2 | |
| ;; | |
| --project-ref) | |
| PROJECT_REF="$2" | |
| shift 2 | |
| ;; | |
| --project-id) | |
| PROJECT_ID="$2" | |
| shift 2 | |
| ;; | |
| --default) | |
| MAKE_DEFAULT=1 | |
| shift | |
| ;; | |
| --list-projects) | |
| LIST_PROJECTS=1 | |
| shift | |
| ;; | |
| --dry-run) | |
| DRY_RUN=1 | |
| shift | |
| ;; | |
| --help|-h) | |
| show_help | |
| exit 0 | |
| ;; | |
| *) | |
| error "Unknown option: $1" | |
| echo "Run with --help for usage information" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| parse_arguments() { | |
| require_value() { | |
| local opt="$1" | |
| local val="${2-}" | |
| if [[ -z "$val" || "$val" == --* ]]; then | |
| error "Option $opt requires a value" | |
| exit 1 | |
| fi | |
| } | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| --name) | |
| require_value --name "$2" | |
| WORKER_NAME="$2" | |
| shift 2 | |
| ;; | |
| --pat) | |
| require_value --pat "$2" | |
| PAT="$2" | |
| shift 2 | |
| ;; | |
| --api-url) | |
| require_value --api-url "$2" | |
| API_URL="$2" | |
| shift 2 | |
| ;; | |
| --project-ref) | |
| require_value --project-ref "$2" | |
| PROJECT_REF="$2" | |
| shift 2 | |
| ;; | |
| --project-id) | |
| require_value --project-id "$2" | |
| PROJECT_ID="$2" | |
| shift 2 | |
| ;; | |
| --default) | |
| MAKE_DEFAULT=1 | |
| shift | |
| ;; | |
| --list-projects) | |
| LIST_PROJECTS=1 | |
| shift | |
| ;; | |
| --dry-run) | |
| DRY_RUN=1 | |
| shift | |
| ;; | |
| --help|-h) | |
| show_help | |
| exit 0 | |
| ;; | |
| *) | |
| error "Unknown option: $1" | |
| echo "Run with --help for usage information" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| } |
🤖 Prompt for AI Agents
In `@apps/supervisor/scripts/setup-worker.sh` around lines 138 - 183, In
parse_arguments, validate the presence and content of the value for options that
consume $2 (e.g., --name -> WORKER_NAME, --pat -> PAT, --api-url -> API_URL,
--project-ref -> PROJECT_REF, --project-id -> PROJECT_ID) before shifting;
specifically check that a non-empty argument exists (guarding against set -u
unbound errors) and that the next token is not another flag (starts with '-')
and emit a clear error and exit if validation fails, then only assign and shift
2 when the check passes.
| prompt_interactive() { | ||
| # Prompt for PAT if missing | ||
| if [[ -z "$PAT" ]]; then | ||
| warning "PAT not found in environment or .env" | ||
| echo "" | ||
| echo "Please enter your Personal Access Token (PAT):" | ||
| echo " Format: tr_pat_..." | ||
| echo " Location: ~/.config/trigger/config.json or ~/Library/Preferences/trigger/config.json" | ||
| read -r -p "PAT: " PAT | ||
| echo "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Check if file exists and view the content at specified lines
head -200 apps/supervisor/scripts/setup-worker.sh | tail -20Repository: triggerdotdev/trigger.dev
Length of output: 610
🏁 Script executed:
# Also verify the exact lines 186-195 with line numbers
sed -n '186,195p' apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 438
🏁 Script executed:
# Check for other instances of read commands in this file
rg "read\s+" apps/supervisor/scripts/setup-worker.sh -nRepository: triggerdotdev/trigger.dev
Length of output: 429
Mask PAT input during interactive prompt to prevent accidental credential exposure.
The current read -r command echoes input characters to the terminal. Add the -s flag to suppress echo of the token:
Suggested fix
- read -r -p "PAT: " PAT
+ read -rs -p "PAT: " PAT
echo ""📝 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.
| prompt_interactive() { | |
| # Prompt for PAT if missing | |
| if [[ -z "$PAT" ]]; then | |
| warning "PAT not found in environment or .env" | |
| echo "" | |
| echo "Please enter your Personal Access Token (PAT):" | |
| echo " Format: tr_pat_..." | |
| echo " Location: ~/.config/trigger/config.json or ~/Library/Preferences/trigger/config.json" | |
| read -r -p "PAT: " PAT | |
| echo "" | |
| prompt_interactive() { | |
| # Prompt for PAT if missing | |
| if [[ -z "$PAT" ]]; then | |
| warning "PAT not found in environment or .env" | |
| echo "" | |
| echo "Please enter your Personal Access Token (PAT):" | |
| echo " Format: tr_pat_..." | |
| echo " Location: ~/.config/trigger/config.json or ~/Library/Preferences/trigger/config.json" | |
| read -rs -p "PAT: " PAT | |
| echo "" |
🤖 Prompt for AI Agents
In `@apps/supervisor/scripts/setup-worker.sh` around lines 186 - 195, The
interactive prompt in function prompt_interactive currently reads the PAT with
read -r which echoes the token; change the read invocation for PAT to use a
silent read (add the -s flag) so input is not shown, and after the silent read
emit a newline (e.g., an extra echo) so the terminal prompt formatting stays
correct; update the read that assigns to the PAT variable and ensure subsequent
logic that uses PAT remains unchanged.
| validate_pat() { | ||
| if [[ ! "$PAT" =~ ^tr_pat_ ]]; then | ||
| error "Invalid Personal Access Token format" | ||
| echo "" | ||
| echo "Expected: tr_pat_... (40 characters)" | ||
| echo "Got: $PAT" | ||
| echo "" | ||
| echo "PAT starts with 'tr_pat_', not 'tr_prod_' or 'tr_dev_'" | ||
| echo "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find . -name "setup-worker.sh" -type fRepository: triggerdotdev/trigger.dev
Length of output: 110
🏁 Script executed:
# Once we find the file, let's read lines 227-235
sed -n '220,240p' apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 670
Mask the PAT before displaying in error output.
The code echoes the full PAT to stdout/stderr, which leaks the secret credential into logs and terminal history. Use the suggested masking approach to display only the first 7 and last 4 characters:
Suggested fix
- echo "Got: $PAT"
+ local pat_redacted="$PAT"
+ if [[ ${`#PAT`} -gt 10 ]]; then
+ pat_redacted="${PAT:0:7}***${PAT: -4}"
+ fi
+ echo "Got: $pat_redacted"📝 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.
| validate_pat() { | |
| if [[ ! "$PAT" =~ ^tr_pat_ ]]; then | |
| error "Invalid Personal Access Token format" | |
| echo "" | |
| echo "Expected: tr_pat_... (40 characters)" | |
| echo "Got: $PAT" | |
| echo "" | |
| echo "PAT starts with 'tr_pat_', not 'tr_prod_' or 'tr_dev_'" | |
| echo "" | |
| validate_pat() { | |
| if [[ ! "$PAT" =~ ^tr_pat_ ]]; then | |
| error "Invalid Personal Access Token format" | |
| echo "" | |
| echo "Expected: tr_pat_... (40 characters)" | |
| local pat_redacted="$PAT" | |
| if [[ ${`#PAT`} -gt 10 ]]; then | |
| pat_redacted="${PAT:0:7}***${PAT: -4}" | |
| fi | |
| echo "Got: $pat_redacted" | |
| echo "" | |
| echo "PAT starts with 'tr_pat_', not 'tr_prod_' or 'tr_dev_'" | |
| echo "" |
🤖 Prompt for AI Agents
In `@apps/supervisor/scripts/setup-worker.sh` around lines 227 - 235, In
validate_pat(), avoid printing the full secret; instead build a masked version
of the PAT that shows only the first 7 and last 4 characters and replace the
middle with asterisks (e.g., "${PAT:0:7}***${PAT: -4}"), then use that masked
value in the echo that currently prints "Got: $PAT" so logs show the masked
token while preserving the existing error messages and behavior.
| test_api_connection() { | ||
| info "Testing API connection..." | ||
|
|
||
| local response | ||
| local http_code | ||
| local body | ||
|
|
||
| response=$(curl -sS -w "\n%{http_code}" \ | ||
| -H "Authorization: Bearer $PAT" \ | ||
| "$API_URL/api/v1/projects" 2>&1) | ||
|
|
||
| http_code=$(echo "$response" | tail -n1) | ||
| body=$(echo "$response" | sed '$d') | ||
|
|
||
| if [[ "$http_code" != "200" ]]; then | ||
| error "Failed to connect to API (HTTP $http_code)" | ||
| echo "" | ||
| echo "Response: $body" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/supervisor/scripts/setup-worker.sh | head -50Repository: triggerdotdev/trigger.dev
Length of output: 1513
🏁 Script executed:
sed -n '255,274p' apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 536
Handle curl failures explicitly to avoid set -e aborts.
The script has set -euo pipefail enabled (line 11). When curl encounters a network error (connection refused, timeout, etc.), it exits with a non-zero code, causing the script to abort immediately before the HTTP code check runs. Capture curl's exit status with the || curl_exit=$? pattern so you can emit a clear error message.
✅ Suggested fix
- response=$(curl -sS -w "\n%{http_code}" \
- -H "Authorization: Bearer $PAT" \
- "$API_URL/api/v1/projects" 2>&1)
+ local curl_exit=0
+ response=$(curl -sS -w "\n%{http_code}" \
+ -H "Authorization: Bearer $PAT" \
+ "$API_URL/api/v1/projects" 2>&1) || curl_exit=$?
+
+ if [[ $curl_exit -ne 0 ]]; then
+ error "Failed to connect to API (curl exit $curl_exit)"
+ echo ""
+ echo "Response: $response"
+ exit 1
+ fi📝 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.
| test_api_connection() { | |
| info "Testing API connection..." | |
| local response | |
| local http_code | |
| local body | |
| response=$(curl -sS -w "\n%{http_code}" \ | |
| -H "Authorization: Bearer $PAT" \ | |
| "$API_URL/api/v1/projects" 2>&1) | |
| http_code=$(echo "$response" | tail -n1) | |
| body=$(echo "$response" | sed '$d') | |
| if [[ "$http_code" != "200" ]]; then | |
| error "Failed to connect to API (HTTP $http_code)" | |
| echo "" | |
| echo "Response: $body" | |
| exit 1 | |
| fi | |
| test_api_connection() { | |
| info "Testing API connection..." | |
| local response | |
| local http_code | |
| local body | |
| local curl_exit=0 | |
| response=$(curl -sS -w "\n%{http_code}" \ | |
| -H "Authorization: Bearer $PAT" \ | |
| "$API_URL/api/v1/projects" 2>&1) || curl_exit=$? | |
| if [[ $curl_exit -ne 0 ]]; then | |
| error "Failed to connect to API (curl exit $curl_exit)" | |
| echo "" | |
| echo "Response: $response" | |
| exit 1 | |
| fi | |
| http_code=$(echo "$response" | tail -n1) | |
| body=$(echo "$response" | sed '$d') | |
| if [[ "$http_code" != "200" ]]; then | |
| error "Failed to connect to API (HTTP $http_code)" | |
| echo "" | |
| echo "Response: $body" | |
| exit 1 | |
| fi |
🤖 Prompt for AI Agents
In `@apps/supervisor/scripts/setup-worker.sh` around lines 255 - 274, In
test_api_connection(), curl can fail and abort the script under set -euo
pipefail; modify the curl invocation to capture its exit code (e.g., initialize
curl_exit=0, run response=$(curl -sS -w "\n%{http_code}" -H "Authorization:
Bearer $PAT" "$API_URL/api/v1/projects" 2>&1) || curl_exit=$?), then check
curl_exit first and on non-zero emit a clear error via error "Curl failed (exit
$curl_exit)" plus the captured response/body and exit 1; otherwise parse
http_code/body as before and keep the existing HTTP status check.
| create_worker() { | ||
| local json_payload | ||
| local make_default_bool | ||
|
|
||
| # Convert 0/1 to false/true for JSON boolean | ||
| if [[ $MAKE_DEFAULT -eq 1 ]]; then | ||
| make_default_bool="true" | ||
| else | ||
| make_default_bool="false" | ||
| fi | ||
|
|
||
| json_payload=$(jq -n \ | ||
| --arg name "$WORKER_NAME" \ | ||
| --arg projectId "$PROJECT_ID" \ | ||
| --argjson makeDefault "$make_default_bool" \ | ||
| '{name: $name, projectId: ($projectId // null), makeDefaultForProject: $makeDefault}') | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the file
find . -name "setup-worker.sh" -type fRepository: triggerdotdev/trigger.dev
Length of output: 110
🏁 Script executed:
# Test jq behavior with the alternative operator and empty strings
# Create a test to see if // operator treats empty strings as falsy
cat << 'EOF' | jq '.projectId = (if $projectId == "" then null else $projectId end)' --arg projectId ""
{"projectId": ""}
EOF
echo "---"
cat << 'EOF' | jq '.projectId = ($projectId // null)' --arg projectId ""
{"projectId": ""}
EOF
echo "---"
# Test with a non-empty projectId
cat << 'EOF' | jq '.projectId = ($projectId // null)' --arg projectId "my-project"
{"projectId": ""}
EOF
EOFRepository: triggerdotdev/trigger.dev
Length of output: 216
🏁 Script executed:
# Examine the actual file to confirm the code matches the review comment
sed -n '336,352p' ./apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 530
Fix empty projectId conversion in JSON payload.
jq's alternative operator // only treats null and false as falsy; empty strings are truthy. The current code ($projectId // null) produces "projectId": "" when no project is chosen, but it should be null.
Fix
- '{name: $name, projectId: ($projectId // null), makeDefaultForProject: $makeDefault}')
+ '{
+ name: $name,
+ projectId: (if $projectId == "" then null else $projectId end),
+ makeDefaultForProject: $makeDefault
+ }')🤖 Prompt for AI Agents
In `@apps/supervisor/scripts/setup-worker.sh` around lines 336 - 352, In
create_worker, the jq payload currently uses ($projectId // null) which returns
an empty string instead of null when PROJECT_ID is empty; update the jq
expression in the json_payload construction so it explicitly converts an empty
projectId to null (e.g., by testing length or equality and returning null for
empty strings) while still passing PROJECT_ID via --arg, so projectId becomes
null when no project is selected.
| # 9. Validate worker name | ||
| if [[ -z "$WORKER_NAME" ]]; then | ||
| error "Worker name is required" | ||
| echo "Run with --help for usage information" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # 10. Resolve project ID | ||
| if [[ -n "$PROJECT_REF" ]]; then | ||
| resolve_project_id | ||
| fi | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
fd setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 108
🏁 Script executed:
wc -l apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 112
🏁 Script executed:
cat -n apps/supervisor/scripts/setup-worker.shRepository: triggerdotdev/trigger.dev
Length of output: 16241
Validate that --default requires a project reference.
Currently, the --default flag can be set via CLI without requiring --project-ref or --project-id. This would result in sending makeDefaultForProject: true with projectId: null to the API, which is invalid since a worker cannot be made default for an unspecified project. The interactive prompt correctly enforces this requirement (lines 211–224), but the CLI path does not.
Suggested fix
# 9. Validate worker name
if [[ -z "$WORKER_NAME" ]]; then
error "Worker name is required"
echo "Run with --help for usage information"
exit 1
fi
+
+ if [[ $MAKE_DEFAULT -eq 1 && -z "$PROJECT_REF" && -z "$PROJECT_ID" ]]; then
+ error "--default requires --project-ref or --project-id"
+ exit 1
+ fi📝 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.
| # 9. Validate worker name | |
| if [[ -z "$WORKER_NAME" ]]; then | |
| error "Worker name is required" | |
| echo "Run with --help for usage information" | |
| exit 1 | |
| fi | |
| # 10. Resolve project ID | |
| if [[ -n "$PROJECT_REF" ]]; then | |
| resolve_project_id | |
| fi | |
| # 9. Validate worker name | |
| if [[ -z "$WORKER_NAME" ]]; then | |
| error "Worker name is required" | |
| echo "Run with --help for usage information" | |
| exit 1 | |
| fi | |
| if [[ $MAKE_DEFAULT -eq 1 && -z "$PROJECT_REF" && -z "$PROJECT_ID" ]]; then | |
| error "--default requires --project-ref or --project-id" | |
| exit 1 | |
| fi | |
| # 10. Resolve project ID | |
| if [[ -n "$PROJECT_REF" ]]; then | |
| resolve_project_id | |
| fi |
🤖 Prompt for AI Agents
In `@apps/supervisor/scripts/setup-worker.sh` around lines 488 - 499, The CLI
allows the --default flag without a project, causing an invalid payload; add a
validation that if the default flag is set (e.g., DEFAULT or MAKE_DEFAULT
variable) then either PROJECT_REF or PROJECT_ID must be present (or
resolve_project_id must succeed) and otherwise print an error and exit;
implement this check after resolve_project_id is run (use resolve_project_id,
PROJECT_REF, PROJECT_ID and the default flag variable names from the script) so
the CLI path mirrors the interactive prompt enforcement.
Adds an interactive bash script to automate worker group creation and configuration for self-hosted Trigger.dev supervisor instances.
✅ Checklist
Testing
Successfully tested all features:
--helpdisplays complete usage information--list-projectsagainst live API, correctly displays both external refs and internal IDs--dry-runshows expected actions without executingproj_...) to internal IDAll tests passed successfully.
Changelog
Added
apps/supervisor/scripts/setup-worker.sh):--list-projectscommand to discover project identifiers--dry-runmode for testing without executionapps/supervisor/README.md):Benefits
Screenshots
