openthrottle 0.1.5 → 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 +12 -14
- package/package.json +1 -1
- package/templates/wake-sandbox.yml +60 -47
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
|
}
|
|
@@ -287,7 +285,9 @@ function setupDaytona(config) {
|
|
|
287
285
|
console.log(` Snapshot already exists: ${snapshotName}`);
|
|
288
286
|
}
|
|
289
287
|
else {
|
|
290
|
-
|
|
288
|
+
const detail = getErrorMessage(err);
|
|
289
|
+
console.log(` Snapshot creation failed: ${detail}`);
|
|
290
|
+
console.log(` You can create it manually:`);
|
|
291
291
|
console.log(` daytona snapshot create ${snapshotName} --image ${image} --cpu 2 --memory 4 --disk 10`);
|
|
292
292
|
}
|
|
293
293
|
}
|
|
@@ -304,9 +304,10 @@ async function pushSecrets(config) {
|
|
|
304
304
|
try {
|
|
305
305
|
execFileSync('gh', ['auth', 'status'], { stdio: 'pipe' });
|
|
306
306
|
}
|
|
307
|
-
catch {
|
|
308
|
-
|
|
309
|
-
console.log(
|
|
307
|
+
catch (err) {
|
|
308
|
+
const detail = getErrorMessage(err);
|
|
309
|
+
console.log(`\n gh CLI check failed: ${detail}`);
|
|
310
|
+
console.log(' Skipping secret push. Run "gh auth login" then set secrets manually.\n');
|
|
310
311
|
return;
|
|
311
312
|
}
|
|
312
313
|
// Detect repo
|
|
@@ -316,8 +317,9 @@ async function pushSecrets(config) {
|
|
|
316
317
|
encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
317
318
|
}).trim();
|
|
318
319
|
}
|
|
319
|
-
catch {
|
|
320
|
-
console.log(
|
|
320
|
+
catch (err) {
|
|
321
|
+
console.log(`\n Could not detect GitHub repo: ${getErrorMessage(err)}`);
|
|
322
|
+
console.log(' Skipping secret push.\n');
|
|
321
323
|
return;
|
|
322
324
|
}
|
|
323
325
|
// Show what we'd push
|
|
@@ -384,11 +386,7 @@ async function pushSecrets(config) {
|
|
|
384
386
|
// 7. Print next steps
|
|
385
387
|
// ---------------------------------------------------------------------------
|
|
386
388
|
function printNextSteps(config) {
|
|
387
|
-
const agentSecret =
|
|
388
|
-
? ' ANTHROPIC_API_KEY <- option a: pay-per-use API key\n CLAUDE_CODE_OAUTH_TOKEN <- option b: subscription token (claude setup-token)'
|
|
389
|
-
: config.agent === 'codex'
|
|
390
|
-
? ' OPENAI_API_KEY <- required for Codex'
|
|
391
|
-
: ' 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)';
|
|
392
390
|
const secrets = [
|
|
393
391
|
' DAYTONA_API_KEY <- required',
|
|
394
392
|
agentSecret,
|
package/package.json
CHANGED
|
@@ -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@
|
|
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
|
|
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
|
-
#
|
|
81
|
-
|
|
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
|
-
|
|
84
|
-
--jq '[.comments[].body | capture("session-id: (?<id>[^ ]+)") | .id] | last // empty') || true
|
|
82
|
+
FROM_PR="${EVENT_PR_NUM}"
|
|
85
83
|
fi
|
|
86
|
-
echo "
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
116
|
-
--snapshot "$
|
|
117
|
-
--
|
|
118
|
-
--auto-stop
|
|
119
|
-
--
|
|
120
|
-
--label
|
|
121
|
-
--label
|
|
122
|
-
--
|
|
123
|
-
--
|
|
124
|
-
--env
|
|
125
|
-
--env
|
|
126
|
-
--env
|
|
127
|
-
--env
|
|
128
|
-
--env
|
|
129
|
-
--env
|
|
130
|
-
--env
|
|
131
|
-
--env
|
|
132
|
-
--env
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|