openthrottle 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/init.js CHANGED
@@ -142,8 +142,6 @@ async function promptConfig(detected) {
142
142
  type: 'select', name: 'agent', message: 'Agent runtime',
143
143
  choices: [
144
144
  { title: 'Claude', value: 'claude' },
145
- { title: 'Codex', value: 'codex' },
146
- { title: 'Aider', value: 'aider' },
147
145
  ],
148
146
  initial: 0,
149
147
  },
@@ -245,7 +243,7 @@ function copyWorkflow(config) {
245
243
  content = content.replace(/ # @@ENV_SECRETS@@ — scaffolder inserts project-specific secrets here/, envSecrets);
246
244
  // Add --env flags for daytona create
247
245
  const envFlags = allKeys
248
- .map(k => ` --env ${k}=\${${k}} \\`)
246
+ .map(k => ` --env "${k}=\${${k}}" \\`)
249
247
  .join('\n');
250
248
  content = content.replace(/ # @@ENV_FLAGS@@ — scaffolder inserts --env flags for project secrets here/, envFlags);
251
249
  }
@@ -388,11 +386,7 @@ async function pushSecrets(config) {
388
386
  // 7. Print next steps
389
387
  // ---------------------------------------------------------------------------
390
388
  function printNextSteps(config) {
391
- const agentSecret = config.agent === 'claude'
392
- ? ' ANTHROPIC_API_KEY <- option a: pay-per-use API key\n CLAUDE_CODE_OAUTH_TOKEN <- option b: subscription token (claude setup-token)'
393
- : config.agent === 'codex'
394
- ? ' OPENAI_API_KEY <- required for Codex'
395
- : ' OPENAI_API_KEY <- or ANTHROPIC_API_KEY (depends on your Aider model)';
389
+ const agentSecret = ' ANTHROPIC_API_KEY <- option a: pay-per-use API key\n CLAUDE_CODE_OAUTH_TOKEN <- option b: subscription token (claude setup-token)';
396
390
  const secrets = [
397
391
  ' DAYTONA_API_KEY <- required',
398
392
  agentSecret,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openthrottle",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "CLI for Open Throttle — ship prompts to Daytona sandboxes.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,12 +37,10 @@ permissions:
37
37
 
38
38
  jobs:
39
39
  run-task:
40
- if: >-
41
- contains(fromJSON('["prd-queued", "bug-queued", "needs-review", "needs-investigation"]'), github.event.label.name) ||
42
- (github.event.review.state == 'changes_requested')
40
+ if: ${{ contains(fromJSON('["prd-queued","bug-queued","needs-review","needs-investigation"]'), github.event.label.name) || (github.event.review.state == 'changes_requested') }}
43
41
  runs-on: ubuntu-latest
44
42
  steps:
45
- - uses: actions/checkout@v4
43
+ - uses: actions/checkout@v6
46
44
 
47
45
  - name: Resolve work item
48
46
  id: work
@@ -64,7 +62,7 @@ jobs:
64
62
  fi
65
63
  echo "item=$WORK_ITEM" >> "$GITHUB_OUTPUT"
66
64
 
67
- # Determine task type (using env vars, not inline ${{ }} expressions)
65
+ # Determine task type (using env vars, not inline expressions)
68
66
  TASK_TYPE="prd"
69
67
  if [[ "$EVENT_LABEL" == "bug-queued" ]]; then
70
68
  TASK_TYPE="bug"
@@ -77,13 +75,19 @@ jobs:
77
75
  fi
78
76
  echo "task_type=$TASK_TYPE" >> "$GITHUB_OUTPUT"
79
77
 
80
- # Extract session ID for review fixes
81
- RESUME_SESSION=""
78
+ # For review-fix tasks, pass the PR number so the sandbox can
79
+ # use `claude --from-pr` to resume conversation context
80
+ FROM_PR=""
82
81
  if [[ "$TASK_TYPE" == "review-fix" ]]; then
83
- RESUME_SESSION=$(gh pr view "$EVENT_PR_NUM" --json comments \
84
- --jq '[.comments[].body | capture("session-id: (?<id>[^ ]+)") | .id] | last // empty') || true
82
+ FROM_PR="${EVENT_PR_NUM}"
85
83
  fi
86
- echo "resume_session=$RESUME_SESSION" >> "$GITHUB_OUTPUT"
84
+ echo "from_pr=$FROM_PR" >> "$GITHUB_OUTPUT"
85
+
86
+ - name: Install Daytona CLI
87
+ run: curl -Lo daytona "https://download.daytona.io/cli/latest/daytona-linux-amd64" && sudo chmod +x daytona && sudo mv daytona /usr/local/bin/
88
+
89
+ - name: Install yq
90
+ run: sudo snap install yq
87
91
 
88
92
  - name: Validate config
89
93
  id: config
@@ -95,11 +99,25 @@ jobs:
95
99
  fi
96
100
  echo "snapshot=$SNAPSHOT" >> "$GITHUB_OUTPUT"
97
101
 
98
- - name: Activate snapshot (reactivates if idle >2 weeks)
102
+ - name: Authenticate Daytona CLI
103
+ run: daytona login --api-key "$DAYTONA_API_KEY"
104
+ env:
105
+ DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
106
+
107
+ - name: Verify snapshot exists
99
108
  env:
100
109
  DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
110
+ SNAPSHOT: ${{ steps.config.outputs.snapshot }}
101
111
  run: |
102
- daytona snapshot activate "${{ steps.config.outputs.snapshot }}" 2>/dev/null || true
112
+ # Reactivate if idle >2 weeks, then verify it exists
113
+ daytona snapshot activate "$SNAPSHOT" 2>/dev/null || true
114
+ if ! daytona snapshot list 2>/dev/null | grep -q "$SNAPSHOT"; then
115
+ echo "::error::Snapshot '$SNAPSHOT' not found. Create it first: daytona snapshot create $SNAPSHOT --image <your-image:tag>"
116
+ echo "Available snapshots:"
117
+ daytona snapshot list 2>/dev/null || echo " (could not list snapshots)"
118
+ exit 1
119
+ fi
120
+ echo "Snapshot verified: $SNAPSHOT"
103
121
 
104
122
  - name: Create and run sandbox
105
123
  env:
@@ -109,42 +127,37 @@ jobs:
109
127
  CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
110
128
  OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
111
129
  SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
130
+ SNAPSHOT: ${{ steps.config.outputs.snapshot }}
131
+ WORK_ITEM: ${{ steps.work.outputs.item }}
132
+ TASK_TYPE: ${{ steps.work.outputs.task_type }}
133
+ FROM_PR: ${{ steps.work.outputs.from_pr }}
112
134
  # @@ENV_SECRETS@@ — scaffolder inserts project-specific secrets here
113
135
  run: |
136
+ SANDBOX_NAME="ot-${TASK_TYPE}-${WORK_ITEM}-${GITHUB_RUN_ID}"
137
+
114
138
  # Create ephemeral sandbox
115
- OUTPUT=$(daytona create \
116
- --snapshot "${{ steps.config.outputs.snapshot }}" \
117
- --auto-delete 0 \
118
- --auto-stop 60 \
119
- --cpu 2 --memory 4096 --disk 10 \
120
- --label project=${{ github.event.repository.name }} \
121
- --label task_type="${{ steps.work.outputs.task_type }}" \
122
- --label issue="${{ steps.work.outputs.item }}" \
123
- --volume openthrottle-${{ github.repository_id }}:/home/daytona/.claude \
124
- --env GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
125
- --env GITHUB_REPO=${{ github.repository }} \
126
- --env ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \
127
- --env CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN} \
128
- --env OPENAI_API_KEY=${OPENAI_API_KEY} \
129
- --env SUPABASE_ACCESS_TOKEN=${SUPABASE_ACCESS_TOKEN} \
130
- --env TELEGRAM_BOT_TOKEN=${{ secrets.TELEGRAM_BOT_TOKEN }} \
131
- --env TELEGRAM_CHAT_ID=${{ secrets.TELEGRAM_CHAT_ID }} \
132
- --env WORK_ITEM="${{ steps.work.outputs.item }}" \
133
- --env TASK_TYPE="${{ steps.work.outputs.task_type }}" \
134
- --env RESUME_SESSION="${{ steps.work.outputs.resume_session }}" \
139
+ daytona create \
140
+ --snapshot "$SNAPSHOT" \
141
+ --name "$SANDBOX_NAME" \
142
+ --auto-stop 180 \
143
+ --label "project=${{ github.event.repository.name }}" \
144
+ --label "task_type=${TASK_TYPE}" \
145
+ --label "issue=${WORK_ITEM}" \
146
+ --env "GITHUB_TOKEN=${{ secrets.GH_PAT }}" \
147
+ --env "GITHUB_REPO=${{ github.repository }}" \
148
+ --env "ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}" \
149
+ --env "CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN}" \
150
+ --env "OPENAI_API_KEY=${OPENAI_API_KEY}" \
151
+ --env "SUPABASE_ACCESS_TOKEN=${SUPABASE_ACCESS_TOKEN}" \
152
+ --env "TELEGRAM_BOT_TOKEN=${{ secrets.TELEGRAM_BOT_TOKEN }}" \
153
+ --env "TELEGRAM_CHAT_ID=${{ secrets.TELEGRAM_CHAT_ID }}" \
154
+ --env "WORK_ITEM=${WORK_ITEM}" \
155
+ --env "TASK_TYPE=${TASK_TYPE}" \
156
+ --env "FROM_PR=${FROM_PR}" \
135
157
  # @@ENV_FLAGS@@ — scaffolder inserts --env flags for project secrets here
136
- 2>&1) || {
137
- # Redact secrets from error output
138
- SAFE_OUTPUT=$(echo "$OUTPUT" | sed \
139
- -e "s/${ANTHROPIC_API_KEY:-___}/[REDACTED]/g" \
140
- -e "s/${CLAUDE_CODE_OAUTH_TOKEN:-___}/[REDACTED]/g" \
141
- -e "s/${OPENAI_API_KEY:-___}/[REDACTED]/g" \
142
- -e "s/${SUPABASE_ACCESS_TOKEN:-___}/[REDACTED]/g" \
143
- -e "s/${GH_TOKEN:-___}/[REDACTED]/g")
144
- echo "::error::Sandbox creation failed: $SAFE_OUTPUT"
145
- exit 1
146
- }
147
- SANDBOX_ID="$OUTPUT"
148
-
149
- echo "Sandbox created: $SANDBOX_ID"
150
- echo "Task: ${{ steps.work.outputs.task_type }} #${{ steps.work.outputs.item }}"
158
+
159
+ echo "Sandbox created: $SANDBOX_NAME"
160
+ echo "Task: ${TASK_TYPE} #${WORK_ITEM}"
161
+ if [[ -n "$FROM_PR" ]]; then
162
+ echo "Review-fix mode: sandbox will use 'claude --from-pr $FROM_PR' to resume PR context"
163
+ fi