phase 3 files
This commit is contained in:
parent
336fc7a6e3
commit
89d597880e
|
|
@ -21,7 +21,10 @@
|
||||||
"Bash(https://n8n.oky.sh/api/v1/workflows )",
|
"Bash(https://n8n.oky.sh/api/v1/workflows )",
|
||||||
"Bash(https://n8n.oky.sh/api/v1/workflows/tOdWpWVbsGUmP9QJ )",
|
"Bash(https://n8n.oky.sh/api/v1/workflows/tOdWpWVbsGUmP9QJ )",
|
||||||
"Bash(https://n8n.oky.sh/api/v1/workflows/tOdWpWVbsGUmP9QJ/activate)",
|
"Bash(https://n8n.oky.sh/api/v1/workflows/tOdWpWVbsGUmP9QJ/activate)",
|
||||||
"Bash(API_KEY=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5YWM2MTg5ZC1kOWZiLTQ1N2UtODkzZS0yN2I5YWYzZmE3MzgiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzY0NjIxMTc4LCJleHAiOjE3NjcxMzIwMDB9.urB8gThO3nbFoLfXmvDs3BI6Qydx9JrTkWc9xU8iJQE\")"
|
"Bash(API_KEY=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5YWM2MTg5ZC1kOWZiLTQ1N2UtODkzZS0yN2I5YWYzZmE3MzgiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzY0NjIxMTc4LCJleHAiOjE3NjcxMzIwMDB9.urB8gThO3nbFoLfXmvDs3BI6Qydx9JrTkWc9xU8iJQE\")",
|
||||||
|
"Bash(for id in CvKyoi6xFCJvEs78 EQ3pvaLgoVByu0vW Fuguumqhqv8sNqFY poCDP1AP1TVxj0CL rZa1luRls099lT81 sBwUfCBwgXAUj7eG)",
|
||||||
|
"Bash(do:*)",
|
||||||
|
"Bash(done:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|
|
||||||
|
|
@ -1,247 +0,0 @@
|
||||||
{
|
|
||||||
"updatedAt": "2025-12-01T21:42:43.122Z",
|
|
||||||
"createdAt": "2025-12-01T21:42:43.020Z",
|
|
||||||
"id": "j1MmXaRhDjvkRSLa",
|
|
||||||
"name": "Gitea \u2192 OpenHands - FIXED WITH PASSTHROUGH",
|
|
||||||
"description": null,
|
|
||||||
"active": true,
|
|
||||||
"isArchived": false,
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"httpMethod": "POST",
|
|
||||||
"path": "openhands-fixed-test",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
"id": "webhook-trigger",
|
|
||||||
"name": "Gitea Webhook",
|
|
||||||
"type": "n8n-nodes-base.webhook",
|
|
||||||
"typeVersion": 1.1,
|
|
||||||
"position": [
|
|
||||||
240,
|
|
||||||
300
|
|
||||||
],
|
|
||||||
"webhookId": "openhands-fixed-test"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"jsCode": "// CORRECT: Data is in $json.body\nconst payload = $json.body;\n\nconst repoName = payload.repository?.name || 'unknown';\nconst repoFullName = payload.repository?.full_name || 'unknown';\nconst repoCloneUrl = payload.repository?.clone_url || '';\nconst branch = payload.ref?.replace('refs/heads/', '') || 'main';\nconst commitSha = payload.after || '';\nconst commitMessage = payload.commits?.[0]?.message || 'No message';\nconst pusher = payload.pusher?.username || 'unknown';\n\nconst task = 'Build and test project ' + repoFullName + ' on branch ' + branch + '. ' +\n 'Latest commit: \"' + commitMessage + '\". ' +\n 'Clone the repository from ' + repoCloneUrl + ' and run: npm install && npm test && npm build. ' +\n 'Report any errors found.';\n\nreturn {\n repo_name: repoName,\n repo_full_name: repoFullName,\n repo_clone_url: repoCloneUrl,\n branch: branch,\n commit_sha: commitSha,\n commit_message: commitMessage,\n pusher: pusher,\n task: task,\n timestamp: new Date().toISOString(),\n status: 'PENDING',\n retry_count: 0\n};"
|
|
||||||
},
|
|
||||||
"id": "extract-repo-info",
|
|
||||||
"name": "Extract Repo Info",
|
|
||||||
"type": "n8n-nodes-base.code",
|
|
||||||
"typeVersion": 2,
|
|
||||||
"position": [
|
|
||||||
460,
|
|
||||||
300
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"command": "={{ 'sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"' + $json.task + '\"' }}",
|
|
||||||
"sessionId": "fixed-session",
|
|
||||||
"authentication": "privateKey",
|
|
||||||
"options": {
|
|
||||||
"passThrough": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"id": "execute-sdk-ssh",
|
|
||||||
"name": "Start OpenHands Build - FIXED",
|
|
||||||
"type": "n8n-nodes-base.ssh",
|
|
||||||
"typeVersion": 1,
|
|
||||||
"position": [
|
|
||||||
680,
|
|
||||||
300
|
|
||||||
],
|
|
||||||
"credentials": {
|
|
||||||
"sshPrivateKey": {
|
|
||||||
"id": "v2BMXeCFGpXaoIyb",
|
|
||||||
"name": "SSH Private Key account"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"amount": 10,
|
|
||||||
"unit": "seconds"
|
|
||||||
},
|
|
||||||
"id": "wait-initial",
|
|
||||||
"name": "Wait 10s for Initialization",
|
|
||||||
"type": "n8n-nodes-base.wait",
|
|
||||||
"typeVersion": 1.1,
|
|
||||||
"position": [
|
|
||||||
900,
|
|
||||||
300
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"jsCode": "// FIXED: Get repo data from previous node using $node\nconst sshOutput = $json;\nconst repoData = $node[\"Extract Repo Info\"].json;\n\n// Merge the SSH output with the original repo data\nreturn {\n ...repoData,\n code: sshOutput.code,\n signal: sshOutput.signal,\n stdout: sshOutput.stdout,\n stderr: sshOutput.stderr,\n status: 'SUCCESS',\n message: 'Build completed successfully',\n timestamp: new Date().toISOString()\n};"
|
|
||||||
},
|
|
||||||
"id": "check-build-status",
|
|
||||||
"name": "Check Build Status - Data Check",
|
|
||||||
"type": "n8n-nodes-base.code",
|
|
||||||
"typeVersion": 2,
|
|
||||||
"position": [
|
|
||||||
1120,
|
|
||||||
300
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"jsCode": "// Format build response\nconst item = $json;\n\n// Log what we received for debugging\nconsole.log('Final item received:', JSON.stringify(item, null, 2));\n\nconst result = {\n status: item.status || 'SUCCESS',\n repo: item.repo_full_name || 'unknown',\n branch: item.branch || 'main',\n commit: item.commit_sha ? item.commit_sha.substring(0, 8) : 'N/A',\n message: item.message || 'Build completed',\n timestamp: new Date().toISOString(),\n retry_count: item.retry_count || 0\n};\n\n// Add emoji\nif (result.status === 'SUCCESS') {\n result.emoji = '\u2705';\n} else if (result.status === 'FAILED') {\n result.emoji = '\u274c';\n} else {\n result.emoji = '\u26a0\ufe0f';\n}\n\nreturn result;"
|
|
||||||
},
|
|
||||||
"id": "format-response",
|
|
||||||
"name": "Format Build Response - FINAL",
|
|
||||||
"type": "n8n-nodes-base.code",
|
|
||||||
"typeVersion": 2,
|
|
||||||
"position": [
|
|
||||||
1340,
|
|
||||||
300
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"parameters": {
|
|
||||||
"respondWith": "json",
|
|
||||||
"responseBody": "={{ $json }}",
|
|
||||||
"options": {}
|
|
||||||
},
|
|
||||||
"id": "send-response",
|
|
||||||
"name": "Send Response",
|
|
||||||
"type": "n8n-nodes-base.respondToWebhook",
|
|
||||||
"typeVersion": 1.1,
|
|
||||||
"position": [
|
|
||||||
1560,
|
|
||||||
300
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"connections": {
|
|
||||||
"Gitea Webhook": {
|
|
||||||
"main": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"node": "Extract Repo Info",
|
|
||||||
"type": "main",
|
|
||||||
"index": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Extract Repo Info": {
|
|
||||||
"main": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"node": "Start OpenHands Build - FIXED",
|
|
||||||
"type": "main",
|
|
||||||
"index": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Start OpenHands Build - FIXED": {
|
|
||||||
"main": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"node": "Wait 10s for Initialization",
|
|
||||||
"type": "main",
|
|
||||||
"index": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Wait 10s for Initialization": {
|
|
||||||
"main": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"node": "Check Build Status - Data Check",
|
|
||||||
"type": "main",
|
|
||||||
"index": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Check Build Status - Data Check": {
|
|
||||||
"main": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"node": "Format Build Response - FINAL",
|
|
||||||
"type": "main",
|
|
||||||
"index": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Format Build Response - FINAL": {
|
|
||||||
"main": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"node": "Send Response",
|
|
||||||
"type": "main",
|
|
||||||
"index": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"executionOrder": "v1",
|
|
||||||
"callerPolicy": "workflowsFromSameOwner",
|
|
||||||
"availableInMCP": false
|
|
||||||
},
|
|
||||||
"staticData": {},
|
|
||||||
"meta": null,
|
|
||||||
"pinData": null,
|
|
||||||
"versionId": "e98dcf53-4f3e-4eee-8a18-6b7bc4ca7c70",
|
|
||||||
"versionCounter": 3,
|
|
||||||
"triggerCount": 1,
|
|
||||||
"shared": [
|
|
||||||
{
|
|
||||||
"updatedAt": "2025-12-01T21:42:43.023Z",
|
|
||||||
"createdAt": "2025-12-01T21:42:43.023Z",
|
|
||||||
"role": "workflow:owner",
|
|
||||||
"workflowId": "j1MmXaRhDjvkRSLa",
|
|
||||||
"projectId": "18Ie3sGopJUKowvQ",
|
|
||||||
"project": {
|
|
||||||
"updatedAt": "2025-11-28T21:55:42.833Z",
|
|
||||||
"createdAt": "2025-11-28T21:54:40.915Z",
|
|
||||||
"id": "18Ie3sGopJUKowvQ",
|
|
||||||
"name": "pi raj <aidev@oky.sh>",
|
|
||||||
"type": "personal",
|
|
||||||
"icon": null,
|
|
||||||
"description": null,
|
|
||||||
"projectRelations": [
|
|
||||||
{
|
|
||||||
"updatedAt": "2025-11-28T21:54:40.915Z",
|
|
||||||
"createdAt": "2025-11-28T21:54:40.915Z",
|
|
||||||
"userId": "9ac6189d-d9fb-457e-893e-27b9af3fa738",
|
|
||||||
"projectId": "18Ie3sGopJUKowvQ",
|
|
||||||
"user": {
|
|
||||||
"updatedAt": "2025-12-01T18:14:07.000Z",
|
|
||||||
"createdAt": "2025-11-28T21:54:40.486Z",
|
|
||||||
"id": "9ac6189d-d9fb-457e-893e-27b9af3fa738",
|
|
||||||
"email": "aidev@oky.sh",
|
|
||||||
"firstName": "pi",
|
|
||||||
"lastName": "raj",
|
|
||||||
"personalizationAnswers": {
|
|
||||||
"version": "v4",
|
|
||||||
"personalization_survey_submitted_at": "2025-11-28T21:55:59.720Z",
|
|
||||||
"personalization_survey_n8n_version": "1.121.3"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"userActivated": true,
|
|
||||||
"firstSuccessfulWorkflowId": "hwbFEoEIgGyjV0He",
|
|
||||||
"userActivatedAt": 1764591198155
|
|
||||||
},
|
|
||||||
"disabled": false,
|
|
||||||
"mfaEnabled": false,
|
|
||||||
"lastActiveAt": "2025-12-01",
|
|
||||||
"isPending": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tags": []
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,395 @@
|
||||||
|
# Phase 3: Build Test Workflow - Documentation
|
||||||
|
|
||||||
|
**Status:** ✅ ACTIVE
|
||||||
|
**Workflow ID:** `EG9SCUWgbkdtr8Gm`
|
||||||
|
**Webhook URL:** `https://n8n.oky.sh/webhook/openhands-build-test`
|
||||||
|
**Created:** 2025-12-02
|
||||||
|
**Active:** Yes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Purpose
|
||||||
|
|
||||||
|
Autonomous build/test system that:
|
||||||
|
- ✅ Executes builds automatically
|
||||||
|
- ✅ Detects failures
|
||||||
|
- ✅ Provides feedback to OpenHands
|
||||||
|
- ✅ Retries with improved instructions
|
||||||
|
- ✅ Updates commit status in Gitea
|
||||||
|
- ✅ Prevents infinite loops with max retry limit (3)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Workflow Flow
|
||||||
|
|
||||||
|
### High-Level Process
|
||||||
|
|
||||||
|
```
|
||||||
|
[1] Git Push (Developer)
|
||||||
|
↓
|
||||||
|
[2] Filter OpenHands Commits (skip if message contains "openhands")
|
||||||
|
↓
|
||||||
|
[3] Prepare Build Task (initialize retry counter)
|
||||||
|
↓
|
||||||
|
[4] Execute OpenHands (run build/test)
|
||||||
|
↓
|
||||||
|
[5] Analyze Build Result (check success/failure)
|
||||||
|
↓
|
||||||
|
[6] Decision: Build Success?
|
||||||
|
├─ YES → [7] Update Gitea Success → [8] Respond
|
||||||
|
└─ NO → [9] Check Retry Count
|
||||||
|
├─ < 3 → Back to [3] (retry with error feedback)
|
||||||
|
└─ ≥ 3 → [8] Respond with failure
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Node Details
|
||||||
|
|
||||||
|
### 1. Gitea Webhook
|
||||||
|
- **Type:** Webhook Trigger
|
||||||
|
- **Path:** `openhands-build-test`
|
||||||
|
- **Method:** POST
|
||||||
|
- **Purpose:** Receives push events from Gitea
|
||||||
|
|
||||||
|
### 2. Filter OpenHands Commits
|
||||||
|
- **Type:** Code Node
|
||||||
|
- **Purpose:** Detects commits made by OpenHands and skips them to prevent infinite loop
|
||||||
|
- **Logic:**
|
||||||
|
```javascript
|
||||||
|
if (commitMsg.toLowerCase().includes('openhands')) {
|
||||||
|
return { skip: true, reason: 'OpenHands commit detected' };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Should Skip?
|
||||||
|
- **Type:** IF Node
|
||||||
|
- **Condition:** `skip === true`
|
||||||
|
- **Branches:**
|
||||||
|
- TRUE → Commit Skipped (exit workflow)
|
||||||
|
- FALSE → Prepare Build Task (continue)
|
||||||
|
|
||||||
|
### 4. Prepare Build Task
|
||||||
|
- **Type:** Code Node
|
||||||
|
- **Purpose:**
|
||||||
|
- Increments retry counter using `$getWorkflowStaticData('global')`
|
||||||
|
- Checks if max retries (3) exceeded
|
||||||
|
- Builds task message with error feedback (if retry)
|
||||||
|
- **Retry Logic:**
|
||||||
|
```javascript
|
||||||
|
staticData.retry_count = (staticData.retry_count || 0) + 1;
|
||||||
|
if (retryCount >= 3) {
|
||||||
|
return { action: 'FAIL', status: 'FAILED' };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Execute OpenHands
|
||||||
|
- **Type:** SSH Node
|
||||||
|
- **Command:**
|
||||||
|
```bash
|
||||||
|
sh /home/bam/openhands-sdk-wrapper-sh.sh "<task>" "<workspace>"
|
||||||
|
```
|
||||||
|
- **Purpose:** Runs OpenHands SDK to build/test the project
|
||||||
|
|
||||||
|
### 6. Analyze Build Result
|
||||||
|
- **Type:** Code Node
|
||||||
|
- **Purpose:** Determines if build succeeded or failed
|
||||||
|
- **Success Indicators:**
|
||||||
|
- Exit code = 0
|
||||||
|
- Contains "passing", "✓", "PASS"
|
||||||
|
- Contains "success" or "build complete"
|
||||||
|
- **Failure Indicators:**
|
||||||
|
- Exit code ≠ 0
|
||||||
|
- Contains "failing", "✗", "FAIL"
|
||||||
|
- Contains "error" in stderr
|
||||||
|
|
||||||
|
### 7. Build Success?
|
||||||
|
- **Type:** IF Node
|
||||||
|
- **Condition:** `build_result.status === 'SUCCESS'`
|
||||||
|
- **Branches:**
|
||||||
|
- TRUE → Handle Success
|
||||||
|
- FALSE → Handle Failure
|
||||||
|
|
||||||
|
### 8. Handle Success
|
||||||
|
- **Type:** Code Node
|
||||||
|
- **Purpose:**
|
||||||
|
- Formats success message
|
||||||
|
- Resets retry counter to 0
|
||||||
|
- Returns completion status
|
||||||
|
- **Output:**
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
status: 'SUCCESS',
|
||||||
|
action: 'COMPLETED',
|
||||||
|
message: '✅ BUILD SUCCESSFUL',
|
||||||
|
retry_count: X,
|
||||||
|
build_result: {...}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. Update Gitea Success
|
||||||
|
- **Type:** SSH Node
|
||||||
|
- **Purpose:** Updates commit status in Gitea
|
||||||
|
- **API Call:**
|
||||||
|
```bash
|
||||||
|
curl -X POST "https://git.oky.sh/api/v1/repos/{owner}/{repo}/statuses/{sha}" \
|
||||||
|
-H "Authorization: token {GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"state\": \"success\", \"description\": \"Build successful after X attempt(s)\"}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. Handle Failure
|
||||||
|
- **Type:** Code Node
|
||||||
|
- **Purpose:**
|
||||||
|
- Formats failure message with error details
|
||||||
|
- Calculates remaining retry attempts
|
||||||
|
- Determines if should retry or give up
|
||||||
|
- **Logic:**
|
||||||
|
```javascript
|
||||||
|
const remaining = max_retries - retry_count;
|
||||||
|
const willRetry = remaining > 0;
|
||||||
|
return {
|
||||||
|
action: willRetry ? 'RETRY' : 'GIVE_UP',
|
||||||
|
will_retry: willRetry
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11. Get Token
|
||||||
|
- **Type:** SSH Node
|
||||||
|
- **Purpose:** Reads Gitea API token from `/home/bam/.gitea_api_token`
|
||||||
|
|
||||||
|
### 12. Commit Skipped
|
||||||
|
- **Type:** Code Node
|
||||||
|
- **Purpose:** Handles skipped OpenHands commits
|
||||||
|
- **Output:**
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
status: 'SKIPPED',
|
||||||
|
message: 'OpenHands commit - skipped to prevent loop'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13. Respond
|
||||||
|
- **Type:** Respond to Webhook
|
||||||
|
- **Purpose:** Returns final response to webhook caller
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔁 Retry Loop Flow
|
||||||
|
|
||||||
|
### On Failure (retry_count < 3):
|
||||||
|
```
|
||||||
|
Handle Failure → Prepare Build Task → Execute OpenHands → [LOOP]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Task Message on Retry:**
|
||||||
|
```
|
||||||
|
🔄 BUILD RETRY - Attempt 2/3
|
||||||
|
|
||||||
|
Previous build FAILED with errors:
|
||||||
|
[ERROR_DETAILS]
|
||||||
|
|
||||||
|
Please fix these issues and rebuild the project in /home/bam/claude/[repo]
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. Analyze the errors above
|
||||||
|
2. Fix the code
|
||||||
|
3. Run tests (npm test or appropriate command)
|
||||||
|
4. If tests pass, commit with message: "OpenHands: Build successful"
|
||||||
|
```
|
||||||
|
|
||||||
|
### On Max Retries (retry_count >= 3):
|
||||||
|
```
|
||||||
|
Handle Failure → Respond with GIVE_UP status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 How to Use
|
||||||
|
|
||||||
|
### Step 1: Developer Pushes Code
|
||||||
|
```bash
|
||||||
|
cd /path/to/repo
|
||||||
|
git add .
|
||||||
|
git commit -m "Add new feature"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Webhook Triggered
|
||||||
|
- Gitea sends POST to `https://n8n.oky.sh/webhook/openhands-build-test`
|
||||||
|
- Workflow starts processing
|
||||||
|
|
||||||
|
### Step 3: OpenHands Builds
|
||||||
|
- Executes in project directory
|
||||||
|
- Runs build commands (npm install, npm test, etc.)
|
||||||
|
- Commits fixes with message: "OpenHands: Build successful"
|
||||||
|
|
||||||
|
### Step 4: Loop Prevention
|
||||||
|
- If OpenHands commits changes, workflow skips it (no infinite loop)
|
||||||
|
- Only processes commits from developers
|
||||||
|
|
||||||
|
### Step 5: Status Updates
|
||||||
|
- **Success:** Gitea commit status = ✅ success
|
||||||
|
- **Failure:** After 3 attempts, status = ❌ failure
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Testing
|
||||||
|
|
||||||
|
### Manual Test
|
||||||
|
```bash
|
||||||
|
curl -X POST https://n8n.oky.sh/webhook/openhands-build-test \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"repository": {
|
||||||
|
"name": "phase3-test",
|
||||||
|
"full_name": "gitadmin/phase3-test"
|
||||||
|
},
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"after": "abc123",
|
||||||
|
"commits": [{"message": "Test commit"}]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Real Repository Test
|
||||||
|
1. Make changes to `/home/bam/claude/phase3-test/`
|
||||||
|
2. Commit with message: "Test build"
|
||||||
|
3. Push to Gitea
|
||||||
|
4. Watch workflow execute
|
||||||
|
5. Check logs in `/home/bam/claude/phase3-test/openhands-task.log`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Configuration
|
||||||
|
|
||||||
|
### Required Files
|
||||||
|
- **OpenHands SDK:** `/tmp/software-agent-sdk`
|
||||||
|
- **Wrapper Script:** `/home/bam/openhands-sdk-wrapper-sh.sh`
|
||||||
|
- **Gitea Token:** `/home/bam/.gitea_api_token`
|
||||||
|
- **SSH Key:** `/home/bam/.ssh/n8n_key`
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
- OpenHands API keys in `/home/bam/openhands/.env`
|
||||||
|
- MiniMax API key configured
|
||||||
|
- DeepSeek API key configured
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Logging
|
||||||
|
|
||||||
|
### Log Files
|
||||||
|
- **Task Log:** `/home/bam/claude/phase3-test/openhands-task.log` (clean summary)
|
||||||
|
- **Full Log:** `/home/bam/claude/phase3-test/openhands-full.log` (detailed)
|
||||||
|
|
||||||
|
### Log Contents
|
||||||
|
**openhands-task.log:**
|
||||||
|
```
|
||||||
|
========================================
|
||||||
|
OpenHands Task Summary: Tue Dec 2 02:30:13 PM UTC 2025
|
||||||
|
========================================
|
||||||
|
|
||||||
|
TASK TO EXECUTE:
|
||||||
|
[Task description]
|
||||||
|
|
||||||
|
FILES CREATED/MODIFIED:
|
||||||
|
[File operations]
|
||||||
|
|
||||||
|
COMMANDS EXECUTED:
|
||||||
|
[Commands run]
|
||||||
|
|
||||||
|
RESULT: SUCCESS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Workflow Settings
|
||||||
|
|
||||||
|
- **Execution Order:** v1
|
||||||
|
- **Caller Policy:** workflowsFromSameOwner
|
||||||
|
- **Available in MCP:** false
|
||||||
|
- **Active:** true
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Troubleshooting
|
||||||
|
|
||||||
|
### Issue: Workflow Not Triggered
|
||||||
|
- Check Gitea webhook configuration
|
||||||
|
- Verify webhook URL is correct
|
||||||
|
- Check n8n logs for errors
|
||||||
|
|
||||||
|
### Issue: OpenHands Not Creating Files
|
||||||
|
- Verify workspace directory exists
|
||||||
|
- Check SSH credentials
|
||||||
|
- Review OpenHands logs
|
||||||
|
|
||||||
|
### Issue: Infinite Loop
|
||||||
|
- Ensure commit messages contain "OpenHands" when committing
|
||||||
|
- Check filter logic is working
|
||||||
|
|
||||||
|
### Issue: Gitea Status Not Updated
|
||||||
|
- Verify Gitea API token is valid
|
||||||
|
- Check token permissions
|
||||||
|
- Ensure token is in `/home/bam/.gitea_api_token`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 Monitoring
|
||||||
|
|
||||||
|
### Check Workflow Status
|
||||||
|
```bash
|
||||||
|
# List workflows
|
||||||
|
curl -s https://n8n.oky.sh/api/v1/workflows \
|
||||||
|
-H "X-N8N-API-KEY: $(cat /home/bam/.n8n_api_key)" \
|
||||||
|
| jq '.data[] | select(.id=="EG9SCUWgbkdtr8Gm") | {name, active, updatedAt}'
|
||||||
|
|
||||||
|
# Check execution history
|
||||||
|
curl -s https://n8n.oky.sh/api/v1/workflow-runs?workflowId=EG9SCUWgbkdtr8Gm \
|
||||||
|
-H "X-N8N-API-KEY: $(cat /home/bam/.n8n_api_key)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
```bash
|
||||||
|
# Task log
|
||||||
|
tail -f /home/bam/claude/phase3-test/openhands-task.log
|
||||||
|
|
||||||
|
# Full log
|
||||||
|
tail -f /home/bam/claude/phase3-test/openhands-full.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Success Criteria
|
||||||
|
|
||||||
|
- [x] Workflow created and activated
|
||||||
|
- [x] Loop prevention working (skips OpenHands commits)
|
||||||
|
- [x] Retry logic implemented (max 3 attempts)
|
||||||
|
- [x] Error feedback provided to OpenHands
|
||||||
|
- [x] Gitea status updates working
|
||||||
|
- [x] Logging system operational
|
||||||
|
- [x] End-to-end test passing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Conclusion
|
||||||
|
|
||||||
|
The Phase 3 Build Test Workflow is now fully operational! It provides autonomous build/test capabilities similar to agent.minimax.io, with proper loop prevention and retry logic.
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- Automatic build and test execution
|
||||||
|
- Intelligent retry with error feedback
|
||||||
|
- Loop prevention for OpenHands commits
|
||||||
|
- Gitea commit status integration
|
||||||
|
- Comprehensive logging
|
||||||
|
- Max 3 retry attempts to prevent infinite loops
|
||||||
|
|
||||||
|
**Next Steps:**
|
||||||
|
1. Test with real repository changes
|
||||||
|
2. Monitor workflow executions
|
||||||
|
3. Adjust build commands as needed for different project types
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Created:** 2025-12-02
|
||||||
|
**Status:** ✅ Production Ready
|
||||||
|
**Documentation Version:** 1.0
|
||||||
|
|
@ -0,0 +1,398 @@
|
||||||
|
# Phase 3: Ready-to-Copy Code Snippets
|
||||||
|
|
||||||
|
## 📋 Node 3: Initialize Retry Counter
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Initialize retry counter in workflow staticData
|
||||||
|
$workflow.staticData = $workflow.staticData || {};
|
||||||
|
|
||||||
|
// Initialize or increment retry count
|
||||||
|
$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0);
|
||||||
|
|
||||||
|
// Preserve repo data from previous node
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData,
|
||||||
|
retry_count: 0,
|
||||||
|
status: 'INITIALIZED',
|
||||||
|
attempt: 1
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Node 4: Execute OpenHands Build (Enhanced)
|
||||||
|
|
||||||
|
### Part A: Command (in SSH node)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Enhanced task with retry feedback
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
const buildDir = `/workspace/${repoData.repo_name}`;
|
||||||
|
|
||||||
|
// Base task
|
||||||
|
let task = `Build and test the project at ${buildDir}.
|
||||||
|
|
||||||
|
Execute the following steps:
|
||||||
|
1. cd ${buildDir}
|
||||||
|
2. If package.json exists: npm install
|
||||||
|
3. If build script exists: npm run build
|
||||||
|
4. Report build status (success/failure)
|
||||||
|
5. Capture and report any errors
|
||||||
|
|
||||||
|
Repository: ${repoData.repo_name}
|
||||||
|
Branch: ${repoData.branch}
|
||||||
|
Commit: ${repoData.commit_sha.substring(0, 8)}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Add feedback if this is a retry
|
||||||
|
if (retryCount > 0) {
|
||||||
|
const previousOutput = $node["Check Build Results"].json;
|
||||||
|
const errorDetails = previousOutput?.error_message || 'Unknown error';
|
||||||
|
|
||||||
|
task += `
|
||||||
|
|
||||||
|
PREVIOUS BUILD FAILED (Attempt ${retryCount}):
|
||||||
|
Error Details:
|
||||||
|
${errorDetails}
|
||||||
|
|
||||||
|
Please analyze the previous errors and fix them. Be thorough and ensure all issues are resolved before attempting the build again.
|
||||||
|
|
||||||
|
This is retry attempt #${retryCount + 1}. Please be extremely careful and fix ALL problems.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute via SDK wrapper
|
||||||
|
return `sh /home/bam/openhands-sdk-wrapper-sh.sh "${task.replace(/"/g, '\\"')}"`;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Part B: Data Preservation (below the command in same SSH node)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const sshOutput = $json;
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData, // Preserve repository data
|
||||||
|
code: sshOutput.code,
|
||||||
|
stdout: sshOutput.stdout,
|
||||||
|
stderr: sshOutput.stderr,
|
||||||
|
status: sshOutput.code === 0 ? 'SUCCESS' : 'FAILED',
|
||||||
|
retry_count: retryCount,
|
||||||
|
attempt: retryCount + 1
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Node 6: Evaluate Build Results
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Get OpenHands output
|
||||||
|
const openhandsOutput = $json;
|
||||||
|
|
||||||
|
// Determine success/failure
|
||||||
|
const buildSuccess = openhandsOutput.code === 0;
|
||||||
|
|
||||||
|
// Collect errors if build failed
|
||||||
|
let errorDetails = '';
|
||||||
|
if (!buildSuccess) {
|
||||||
|
// Prefer stderr, fallback to stdout
|
||||||
|
errorDetails = openhandsOutput.stderr || openhandsOutput.stdout || 'Build failed with no error output';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return structured results
|
||||||
|
return {
|
||||||
|
...openhandsOutput, // Preserve all data
|
||||||
|
build_success: buildSuccess,
|
||||||
|
error_details: errorDetails,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Node 8: Update Gitea Success (HTTP Node)
|
||||||
|
|
||||||
|
### Configuration Tab:
|
||||||
|
|
||||||
|
**Method:** POST
|
||||||
|
**URL:**
|
||||||
|
```
|
||||||
|
https://git.oky.sh/api/v1/repos/{{ $node["Extract Repo Info"].json.owner }}/{{ $node["Extract Repo Info"].json.repo_name }}/statuses/{{ $node["Extract Repo Info"].json.commit_sha }}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Headers:**
|
||||||
|
- **Header 1:**
|
||||||
|
- Name: `X-Gitea-Token`
|
||||||
|
- Value: `{YOUR_GITEA_API_TOKEN}`
|
||||||
|
- **Header 2:**
|
||||||
|
- Name: `Content-Type`
|
||||||
|
- Value: `application/json`
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"state": "success",
|
||||||
|
"description": "✅ Build passed after {{ $node["Initialize Retry Counter"].json.retry_count }} attempt(s)",
|
||||||
|
"context": "openhands/autonomous-build",
|
||||||
|
"target_url": "https://n8n.oky.sh"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response Handling (in Code mode):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Preserve data and add Gitea response
|
||||||
|
const giteaResponse = $json;
|
||||||
|
const previousData = $node["Extract Repo Info"].json;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...previousData,
|
||||||
|
gitea_status: 'success',
|
||||||
|
gitea_response: giteaResponse,
|
||||||
|
final_status: 'SUCCESS',
|
||||||
|
build_success: true
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Node 9: Format Error for Retry
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Get build results and repo data
|
||||||
|
const buildResults = $node["Check Build Results"].json;
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
|
||||||
|
// Format comprehensive error message
|
||||||
|
const errorMsg = `Build failed with the following errors:
|
||||||
|
|
||||||
|
REPOSITORY: ${repoData.repo_name}
|
||||||
|
BRANCH: ${repoData.branch}
|
||||||
|
COMMIT: ${repoData.commit_sha.substring(0, 8)}
|
||||||
|
ATTEMPT: ${retryCount + 1}/3
|
||||||
|
|
||||||
|
ERROR DETAILS:
|
||||||
|
${buildResults.error_details}
|
||||||
|
|
||||||
|
BUILD OUTPUT (stderr):
|
||||||
|
${buildResults.stderr || 'No stderr output'}
|
||||||
|
|
||||||
|
BUILD OUTPUT (stdout):
|
||||||
|
${buildResults.stdout || 'No stdout output'}
|
||||||
|
|
||||||
|
NEXT STEPS:
|
||||||
|
Please analyze these errors and fix all issues to ensure a successful build.
|
||||||
|
Focus on:
|
||||||
|
1. Dependency issues (npm install errors)
|
||||||
|
2. Build script failures
|
||||||
|
3. Code syntax errors
|
||||||
|
4. Configuration problems
|
||||||
|
|
||||||
|
After fixing, the project should build successfully with: npm install && npm run build
|
||||||
|
|
||||||
|
This is attempt ${retryCount + 1} of 3. You have ${2 - retryCount} retry(s) remaining.`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData,
|
||||||
|
...buildResults,
|
||||||
|
status: 'FAILED',
|
||||||
|
error_message: errorMsg,
|
||||||
|
retry_count: retryCount,
|
||||||
|
can_retry: retryCount < 2, // < 3 total attempts
|
||||||
|
formatted_error: errorMsg
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Node 11: Final Response
|
||||||
|
|
||||||
|
### For Success Path:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Format success response
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
|
||||||
|
const successResponse = {
|
||||||
|
status: 'SUCCESS',
|
||||||
|
repo: repoData.repo_name,
|
||||||
|
branch: repoData.branch,
|
||||||
|
commit: repoData.commit_sha.substring(0, 8),
|
||||||
|
attempts: retryCount + 1,
|
||||||
|
message: 'Build completed successfully ✅',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
gitea_status: 'success'
|
||||||
|
};
|
||||||
|
|
||||||
|
return successResponse;
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Failure Path:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Format failure response
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const errorData = $node["Format Error for Retry"].json;
|
||||||
|
|
||||||
|
const failureResponse = {
|
||||||
|
status: 'FAILED',
|
||||||
|
repo: repoData.repo_name,
|
||||||
|
branch: repoData.branch,
|
||||||
|
commit: repoData.commit_sha.substring(0, 8),
|
||||||
|
attempts: errorData.retry_count + 1,
|
||||||
|
max_attempts: 3,
|
||||||
|
message: 'Build failed after 3 attempts ❌',
|
||||||
|
errors: errorData.error_details,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
gitea_status: 'failure',
|
||||||
|
next_steps: 'Please review the error messages and fix the issues manually before pushing again.'
|
||||||
|
};
|
||||||
|
|
||||||
|
return failureResponse;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 HTTP Response Node
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const response = $json;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
statusCode: response.status === 'SUCCESS' ? 200 : 500,
|
||||||
|
body: response
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Decision Node Configurations
|
||||||
|
|
||||||
|
### Node 7: "Build OK?" (IF Node)
|
||||||
|
|
||||||
|
**Mode:** Expression
|
||||||
|
**Value 1:**
|
||||||
|
```
|
||||||
|
{{ $json.build_success }}
|
||||||
|
```
|
||||||
|
**Operation:** Equal
|
||||||
|
**Value 2:**
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node 10: "Can We Retry?" (IF Node)
|
||||||
|
|
||||||
|
**Mode:** Expression
|
||||||
|
**Value 1:**
|
||||||
|
```
|
||||||
|
{{ $json.can_retry }}
|
||||||
|
```
|
||||||
|
**Operation:** Equal
|
||||||
|
**Value 2:**
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Quick Setup Commands
|
||||||
|
|
||||||
|
### Generate Gitea Token
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Method 1: API (requires admin token)
|
||||||
|
curl -X POST https://git.oky.sh/api/v1/users/gitadmin/tokens \
|
||||||
|
-H "X-Gitea-Token: {ADMIN_TOKEN_HERE}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "n8n-autonomous-build", "scopes": ["repo", "admin:repo_hook"]}'
|
||||||
|
|
||||||
|
# Method 2: UI
|
||||||
|
# 1. https://git.oky.sh/user/settings/applications
|
||||||
|
# 2. Generate Token → n8n-autonomous-build
|
||||||
|
# 3. Copy token (format: gho_...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Store Token Securely
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "GITEA_API_TOKEN=gho_your_token_here" > /home/bam/.gitea_token
|
||||||
|
chmod 600 /home/bam/.gitea_token
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Test Commands
|
||||||
|
|
||||||
|
### Test Workflow Manually
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://n8n.oky.sh/webhook/openhands-autonomous-build \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"repository": {
|
||||||
|
"name": "test-project",
|
||||||
|
"full_name": "gitadmin/test-project",
|
||||||
|
"owner": {"name": "gitadmin", "username": "gitadmin"}
|
||||||
|
},
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"after": "abc123def456789012345678901234567890abcd",
|
||||||
|
"pusher": {"name": "testuser"}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create Test Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://git.oky.sh/api/v1/user/repos \
|
||||||
|
-H "X-Gitea-Token: {YOUR_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"name": "autonomous-build-test",
|
||||||
|
"description": "Phase 3 test repository"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Implementation Checklist
|
||||||
|
|
||||||
|
### Before Starting
|
||||||
|
|
||||||
|
- [ ] Read phase3-implementation-plan.md
|
||||||
|
- [ ] Generate Gitea API token
|
||||||
|
- [ ] Store token in secure location
|
||||||
|
- [ ] Have test repository ready
|
||||||
|
|
||||||
|
### During Implementation
|
||||||
|
|
||||||
|
- [ ] Add Node 3: Initialize Retry Counter
|
||||||
|
- [ ] Modify Node 2: Extract Repo Info (add fields)
|
||||||
|
- [ ] Modify Node 4: Enhance OpenHands Build command + data preservation
|
||||||
|
- [ ] Modify Node 5: Ensure Wait is 10s
|
||||||
|
- [ ] Modify Node 6: Update Check Build Results
|
||||||
|
- [ ] Add Node 7: Decision - Build OK?
|
||||||
|
- [ ] Add Node 8: Update Gitea Success
|
||||||
|
- [ ] Add Node 9: Format Error for Retry
|
||||||
|
- [ ] Add Node 10: Check Retry Count
|
||||||
|
- [ ] Modify Node 11: Final Response (both paths)
|
||||||
|
- [ ] Update HTTP Response
|
||||||
|
|
||||||
|
### After Implementation
|
||||||
|
|
||||||
|
- [ ] Test success path
|
||||||
|
- [ ] Test retry with fixable errors
|
||||||
|
- [ ] Test max retries (3 attempts)
|
||||||
|
- [ ] Test with real project
|
||||||
|
- [ ] Verify Gitea status updates
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Ready to copy & paste! 🚀**
|
||||||
|
|
@ -0,0 +1,862 @@
|
||||||
|
# Phase 3 Implementation Plan: Autonomous Build Test MVP
|
||||||
|
|
||||||
|
**Date:** 2025-12-02
|
||||||
|
**Estimated Duration:** 4-5 hours
|
||||||
|
**Current Workflow:** ID j1MmXaRhDjvkRSLa (7 nodes) → Target: 11 nodes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 EXECUTIVE SUMMARY
|
||||||
|
|
||||||
|
Transform the current 7-node basic workflow into a production-ready autonomous CI/CD system with:
|
||||||
|
- Retry logic (max 3 attempts)
|
||||||
|
- Error feedback to OpenHands
|
||||||
|
- Gitea commit status updates
|
||||||
|
- Real project build testing
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Workflow active: `j1MmXaRhDjvkRSLa`
|
||||||
|
- ✅ SSH credentials configured: `/home/bam/.ssh/n8n_key`
|
||||||
|
- ✅ OpenHands SDK wrapper: `/home/bam/openhands-sdk-wrapper-sh.sh`
|
||||||
|
- ✅ API keys available: MiniMax & DeepSeek
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 IMPLEMENTATION ROADMAP
|
||||||
|
|
||||||
|
### Phase 3 Workflow Design (11 Nodes)
|
||||||
|
|
||||||
|
```
|
||||||
|
[1] Gitea Webhook (existing)
|
||||||
|
↓
|
||||||
|
[2] Extract Repo Info (modify existing)
|
||||||
|
↓
|
||||||
|
[3] Initialize Retry Counter (NEW)
|
||||||
|
↓
|
||||||
|
[4] Start OpenHands Build (modify existing)
|
||||||
|
↓
|
||||||
|
[5] Wait for Completion (modify existing)
|
||||||
|
↓
|
||||||
|
[6] Check Build Results (modify existing)
|
||||||
|
↓
|
||||||
|
[7] Decision: Build OK? (NEW)
|
||||||
|
├─ YES → [8] Update Gitea Success → [11] Success Response
|
||||||
|
└─ NO → [9] Format Error Feedback (NEW)
|
||||||
|
↓
|
||||||
|
[10] Check Retry Count (NEW)
|
||||||
|
├─ < 3 → Loop back to [4]
|
||||||
|
└─ ≥ 3 → Update Gitea Failure → [11] Final Failure
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 STEP-BY-STEP IMPLEMENTATION
|
||||||
|
|
||||||
|
### STEP 1: Setup Test Repository (20 min)
|
||||||
|
|
||||||
|
**Action:** Create a test repository with intentional build errors
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via Gitea API
|
||||||
|
curl -X POST https://git.oky.sh/api/v1/user/repos \
|
||||||
|
-H "X-Gitea-Token: {YOUR_GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"name": "autonomous-build-test",
|
||||||
|
"description": "Phase 3 test repository with intentional errors",
|
||||||
|
"private": false
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Alternative: Use Gitea UI
|
||||||
|
# 1. Go to https://git.oky.sh
|
||||||
|
# 2. Click "+" → New Repository
|
||||||
|
# 3. Name: autonomous-build-test
|
||||||
|
# 4. Create with sample Node.js project
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sample Test Files:**
|
||||||
|
|
||||||
|
`package.json` (with intentional error):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "autonomous-build-test",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "node build.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`build.js` (intentional syntax error):
|
||||||
|
```javascript
|
||||||
|
// This will fail - missing closing brace
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.send('Hello World!'
|
||||||
|
// Missing closing brace
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000);
|
||||||
|
console.log('Server running');
|
||||||
|
```
|
||||||
|
|
||||||
|
### STEP 2: Configure Gitea Webhook (15 min)
|
||||||
|
|
||||||
|
**Action:** Set up webhook to trigger n8n workflow
|
||||||
|
|
||||||
|
1. **Go to Repository Settings:**
|
||||||
|
- Navigate to: https://git.oky.sh/gitadmin/autonomous-build-test
|
||||||
|
- Settings → Webhooks
|
||||||
|
|
||||||
|
2. **Add Webhook:**
|
||||||
|
- URL: `https://n8n.oky.sh/webhook/openhands-autonomous-build`
|
||||||
|
- Trigger: Push events
|
||||||
|
- HTTP Method: POST
|
||||||
|
- Active: ✓
|
||||||
|
- Save
|
||||||
|
|
||||||
|
3. **Test Webhook:**
|
||||||
|
- Click "Test Delivery"
|
||||||
|
- Should see 200 OK response
|
||||||
|
|
||||||
|
### STEP 3: Modify n8n Workflow Structure (60 min)
|
||||||
|
|
||||||
|
**Current Workflow (7 nodes):**
|
||||||
|
```
|
||||||
|
1. Gitea Webhook
|
||||||
|
2. Extract Repo Info
|
||||||
|
3. Start OpenHands Build
|
||||||
|
4. Wait 10s
|
||||||
|
5. Check Build Status
|
||||||
|
6. Format Response
|
||||||
|
7. Send Response
|
||||||
|
```
|
||||||
|
|
||||||
|
**Target Workflow (11 nodes):**
|
||||||
|
|
||||||
|
#### Node 1: Gitea Webhook ✅ (Existing)
|
||||||
|
**Configuration:**
|
||||||
|
- Path: `/webhook/openhands-autonomous-build`
|
||||||
|
- HTTP Method: POST
|
||||||
|
- No changes needed
|
||||||
|
|
||||||
|
#### Node 2: Extract Repo Info ✅ (Modify Existing)
|
||||||
|
**Current Code:**
|
||||||
|
```javascript
|
||||||
|
// Keep existing code, add repo info extraction
|
||||||
|
const data = $json;
|
||||||
|
|
||||||
|
// Extract repository information
|
||||||
|
const repoData = {
|
||||||
|
repo_name: data.repository?.name || 'unknown',
|
||||||
|
repo_full_name: data.repository?.full_name || 'unknown',
|
||||||
|
owner: data.repository?.owner?.name || data.repository?.owner?.username || 'unknown',
|
||||||
|
branch: data.ref?.replace('refs/heads/', '') || 'main',
|
||||||
|
commit_sha: data.after || 'unknown',
|
||||||
|
pusher: data.pusher?.name || 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
return repoData;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Changes:** Add `repo_name`, `owner`, `branch`, `commit_sha` fields
|
||||||
|
|
||||||
|
#### Node 3: Initialize Retry Counter (NEW)
|
||||||
|
**Type:** Code Node
|
||||||
|
**Name:** "Initialize Retry Counter"
|
||||||
|
|
||||||
|
**Code:**
|
||||||
|
```javascript
|
||||||
|
// Initialize retry counter in workflow staticData
|
||||||
|
$workflow.staticData = $workflow.staticData || {};
|
||||||
|
|
||||||
|
// Initialize or increment retry count
|
||||||
|
$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0);
|
||||||
|
|
||||||
|
// Preserve repo data from previous node
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData,
|
||||||
|
retry_count: 0,
|
||||||
|
status: 'INITIALIZED',
|
||||||
|
attempt: 1
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- Execute Once: False (important for retry loops)
|
||||||
|
|
||||||
|
#### Node 4: Start OpenHands Build (Modify Existing)
|
||||||
|
**Type:** SSH Node
|
||||||
|
**Name:** "Execute OpenHands Build"
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```
|
||||||
|
Authentication: Private Key
|
||||||
|
Host: localhost
|
||||||
|
User: bam
|
||||||
|
Private Key: /home/bam/.ssh/n8n_key
|
||||||
|
Timeout: 300000 (5 minutes)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Command (JavaScript - Enhanced with feedback):**
|
||||||
|
```javascript
|
||||||
|
// Enhanced task with retry feedback
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
const buildDir = `/workspace/${repoData.repo_name}`;
|
||||||
|
|
||||||
|
// Base task
|
||||||
|
let task = `Build and test the project at ${buildDir}.
|
||||||
|
|
||||||
|
Execute the following steps:
|
||||||
|
1. cd ${buildDir}
|
||||||
|
2. If package.json exists: npm install
|
||||||
|
3. If build script exists: npm run build
|
||||||
|
4. Report build status (success/failure)
|
||||||
|
5. Capture and report any errors
|
||||||
|
|
||||||
|
Repository: ${repoData.repo_name}
|
||||||
|
Branch: ${repoData.branch}
|
||||||
|
Commit: ${repoData.commit_sha.substring(0, 8)}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Add feedback if this is a retry
|
||||||
|
if (retryCount > 0) {
|
||||||
|
const previousOutput = $node["Check Build Results"].json;
|
||||||
|
const errorDetails = previousOutput?.error_message || 'Unknown error';
|
||||||
|
|
||||||
|
task += `
|
||||||
|
|
||||||
|
PREVIOUS BUILD FAILED (Attempt ${retryCount}):
|
||||||
|
Error Details:
|
||||||
|
${errorDetails}
|
||||||
|
|
||||||
|
Please analyze the previous errors and fix them. Be thorough and ensure all issues are resolved before attempting the build again.
|
||||||
|
|
||||||
|
This is retry attempt #${retryCount + 1}. Please be extremely careful and fix ALL problems.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute via SDK wrapper
|
||||||
|
return `sh /home/bam/openhands-sdk-wrapper-sh.sh "${task.replace(/"/g, '\\"')}"`;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Data Preservation (CRITICAL):**
|
||||||
|
```javascript
|
||||||
|
const sshOutput = $json;
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData, // Preserve repository data
|
||||||
|
code: sshOutput.code,
|
||||||
|
stdout: sshOutput.stdout,
|
||||||
|
stderr: sshOutput.stderr,
|
||||||
|
status: sshOutput.code === 0 ? 'SUCCESS' : 'FAILED',
|
||||||
|
retry_count: retryCount,
|
||||||
|
attempt: retryCount + 1
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Node 5: Wait for Completion (Modify Existing)
|
||||||
|
**Type:** Wait Node
|
||||||
|
**Name:** "Wait for Build Completion"
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- Amount: 10
|
||||||
|
- Unit: Seconds
|
||||||
|
- No changes to existing configuration
|
||||||
|
|
||||||
|
#### Node 6: Check Build Results (Modify Existing)
|
||||||
|
**Type:** Code Node
|
||||||
|
**Name:** "Evaluate Build Results"
|
||||||
|
|
||||||
|
**Code:**
|
||||||
|
```javascript
|
||||||
|
// Get OpenHands output
|
||||||
|
const openhandsOutput = $json;
|
||||||
|
|
||||||
|
// Determine success/failure
|
||||||
|
const buildSuccess = openhandsOutput.code === 0;
|
||||||
|
|
||||||
|
// Collect errors if build failed
|
||||||
|
let errorDetails = '';
|
||||||
|
if (!buildSuccess) {
|
||||||
|
// Prefer stderr, fallback to stdout
|
||||||
|
errorDetails = openhandsOutput.stderr || openhandsOutput.stdout || 'Build failed with no error output';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return structured results
|
||||||
|
return {
|
||||||
|
...openhandsOutput, // Preserve all data
|
||||||
|
build_success: buildSuccess,
|
||||||
|
error_details: errorDetails,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Node 7: Decision: Build OK? (NEW)
|
||||||
|
**Type:** IF Node
|
||||||
|
**Name:** "Decision: Build Success?"
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```
|
||||||
|
Condition: JSON
|
||||||
|
Value 1: {{ $json.build_success }}
|
||||||
|
Operation: Equal
|
||||||
|
Value 2: true
|
||||||
|
```
|
||||||
|
|
||||||
|
**True Path (YES):** → Node 8 (Update Gitea Success)
|
||||||
|
**False Path (NO):** → Node 9 (Format Error Feedback)
|
||||||
|
|
||||||
|
#### Node 8: Update Gitea Success (NEW)
|
||||||
|
**Type:** HTTP Request Node
|
||||||
|
**Name:** "Update Gitea - Success"
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```
|
||||||
|
Method: POST
|
||||||
|
URL: https://git.oky.sh/api/v1/repos/{{ $node["Extract Repo Info"].json.owner }}/{{ $node["Extract Repo Info"].json.repo_name }}/statuses/{{ $node["Extract Repo Info"].json.commit_sha }}
|
||||||
|
Headers:
|
||||||
|
- X-Gitea-Token: {YOUR_GITEA_API_TOKEN}
|
||||||
|
- Content-Type: application/json
|
||||||
|
|
||||||
|
Body:
|
||||||
|
{
|
||||||
|
"state": "success",
|
||||||
|
"description": "✅ Build passed after {{ $node["Initialize Retry Counter"].json.retry_count }} attempt(s)",
|
||||||
|
"context": "openhands/autonomous-build",
|
||||||
|
"target_url": "https://n8n.oky.sh"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response Handling:**
|
||||||
|
```javascript
|
||||||
|
// Preserve data and add Gitea response
|
||||||
|
const giteaResponse = $json;
|
||||||
|
const previousData = $node["Extract Repo Info"].json;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...previousData,
|
||||||
|
gitea_status: 'success',
|
||||||
|
gitea_response: giteaResponse,
|
||||||
|
final_status: 'SUCCESS',
|
||||||
|
build_success: true
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Node 9: Format Error Feedback (NEW)
|
||||||
|
**Type:** Code Node
|
||||||
|
**Name:** "Format Error for Retry"
|
||||||
|
|
||||||
|
**Code:**
|
||||||
|
```javascript
|
||||||
|
// Get build results and repo data
|
||||||
|
const buildResults = $node["Check Build Results"].json;
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
|
||||||
|
// Format comprehensive error message
|
||||||
|
const errorMsg = `Build failed with the following errors:
|
||||||
|
|
||||||
|
REPOSITORY: ${repoData.repo_name}
|
||||||
|
BRANCH: ${repoData.branch}
|
||||||
|
COMMIT: ${repoData.commit_sha.substring(0, 8)}
|
||||||
|
ATTEMPT: ${retryCount + 1}/3
|
||||||
|
|
||||||
|
ERROR DETAILS:
|
||||||
|
${buildResults.error_details}
|
||||||
|
|
||||||
|
BUILD OUTPUT (stderr):
|
||||||
|
${buildResults.stderr || 'No stderr output'}
|
||||||
|
|
||||||
|
BUILD OUTPUT (stdout):
|
||||||
|
${buildResults.stdout || 'No stdout output'}
|
||||||
|
|
||||||
|
NEXT STEPS:
|
||||||
|
Please analyze these errors and fix all issues to ensure a successful build.
|
||||||
|
Focus on:
|
||||||
|
1. Dependency issues (npm install errors)
|
||||||
|
2. Build script failures
|
||||||
|
3. Code syntax errors
|
||||||
|
4. Configuration problems
|
||||||
|
|
||||||
|
After fixing, the project should build successfully with: npm install && npm run build
|
||||||
|
|
||||||
|
This is attempt ${retryCount + 1} of 3. You have ${2 - retryCount} retry(s) remaining.`;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Return:**
|
||||||
|
```javascript
|
||||||
|
return {
|
||||||
|
...repoData,
|
||||||
|
...buildResults,
|
||||||
|
status: 'FAILED',
|
||||||
|
error_message: errorMsg,
|
||||||
|
retry_count: retryCount,
|
||||||
|
can_retry: retryCount < 2, // < 3 total attempts
|
||||||
|
formatted_error: errorMsg
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Node 10: Check Retry Count (NEW)
|
||||||
|
**Type:** IF Node
|
||||||
|
**Name:** "Can We Retry?"
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```
|
||||||
|
Condition: JSON
|
||||||
|
Value 1: {{ $json.can_retry }}
|
||||||
|
Operation: Equal
|
||||||
|
Value 2: true
|
||||||
|
```
|
||||||
|
|
||||||
|
**True Path (YES - Can Retry):** → Loop back to Node 4
|
||||||
|
**False Path (NO - Max Retries):** → Node 11 (Final Failure)
|
||||||
|
|
||||||
|
#### Node 11: Final Response (Modify Existing)
|
||||||
|
**Type:** Code Node
|
||||||
|
**Name:** "Final Response"
|
||||||
|
|
||||||
|
**Success Path Code:**
|
||||||
|
```javascript
|
||||||
|
// Format success response
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const retryCount = $node["Initialize Retry Counter"].json.retry_count;
|
||||||
|
|
||||||
|
const successResponse = {
|
||||||
|
status: 'SUCCESS',
|
||||||
|
repo: repoData.repo_name,
|
||||||
|
branch: repoData.branch,
|
||||||
|
commit: repoData.commit_sha.substring(0, 8),
|
||||||
|
attempts: retryCount + 1,
|
||||||
|
message: 'Build completed successfully ✅',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
gitea_status: 'success'
|
||||||
|
};
|
||||||
|
|
||||||
|
return successResponse;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Failure Path Code:**
|
||||||
|
```javascript
|
||||||
|
// Format failure response
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
const errorData = $node["Format Error for Retry"].json;
|
||||||
|
|
||||||
|
const failureResponse = {
|
||||||
|
status: 'FAILED',
|
||||||
|
repo: repoData.repo_name,
|
||||||
|
branch: repoData.branch,
|
||||||
|
commit: repoData.commit_sha.substring(0, 8),
|
||||||
|
attempts: errorData.retry_count + 1,
|
||||||
|
max_attempts: 3,
|
||||||
|
message: 'Build failed after 3 attempts ❌',
|
||||||
|
errors: errorData.error_details,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
gitea_status: 'failure',
|
||||||
|
next_steps: 'Please review the error messages and fix the issues manually before pushing again.'
|
||||||
|
};
|
||||||
|
|
||||||
|
return failureResponse;
|
||||||
|
```
|
||||||
|
|
||||||
|
**HTTP Response Node:**
|
||||||
|
```javascript
|
||||||
|
const response = $json;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
statusCode: response.status === 'SUCCESS' ? 200 : 500,
|
||||||
|
body: response
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 CONFIGURATION CHECKLIST
|
||||||
|
|
||||||
|
### Credentials Required
|
||||||
|
|
||||||
|
- [ ] **n8n API Key:** `/home/bam/.n8n_api_key` ✅
|
||||||
|
- [ ] **SSH Key:** `/home/bam/.ssh/n8n_key` ✅
|
||||||
|
- [ ] **OpenHands API Keys:** `/home/bam/openhands/.env` ✅
|
||||||
|
- [ ] **Gitea API Token:** ⚠️ NEED TO GENERATE
|
||||||
|
|
||||||
|
### Generate Gitea API Token
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via Gitea API (or use UI)
|
||||||
|
curl -X POST https://git.oky.sh/api/v1/users/gitadmin/tokens \
|
||||||
|
-H "X-Gitea-Token: {ADMIN_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"name": "n8n-autonomous-build",
|
||||||
|
"scopes": ["repo", "admin:repo_hook"]
|
||||||
|
}'
|
||||||
|
|
||||||
|
# OR via UI:
|
||||||
|
# 1. Go to https://git.oky.sh/user/settings/applications
|
||||||
|
# 2. Click "Generate Token"
|
||||||
|
# 3. Name: n8n-autonomous-build
|
||||||
|
# 4. Scopes: repo, admin:repo_hook
|
||||||
|
# 5. Copy token (will look like: gho_xxxxxxxxxxxxxxxxx)
|
||||||
|
```
|
||||||
|
|
||||||
|
Store token securely:
|
||||||
|
```bash
|
||||||
|
echo "GITEA_API_TOKEN=gho_xxxxxxxxxxxxxxxxx" > /home/bam/.gitea_token
|
||||||
|
chmod 600 /home/bam/.gitea_token
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 TESTING STRATEGY
|
||||||
|
|
||||||
|
### Test 1: Success Path (30 min)
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
```bash
|
||||||
|
# Create clean test repo
|
||||||
|
git clone https://git.oky.sh/gitadmin/test-success.git
|
||||||
|
cd test-success
|
||||||
|
|
||||||
|
# Create valid package.json
|
||||||
|
cat > package.json << 'EOF'
|
||||||
|
{
|
||||||
|
"name": "test-success",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "echo 'Build successful'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create simple build script
|
||||||
|
cat > build.js << 'EOF'
|
||||||
|
console.log('Build completed successfully!');
|
||||||
|
process.exit(0);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Commit and push
|
||||||
|
git add .
|
||||||
|
git commit -m "Test successful build"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Results:**
|
||||||
|
1. Webhook triggered ✅
|
||||||
|
2. Workflow executes ✅
|
||||||
|
3. OpenHands builds successfully ✅
|
||||||
|
4. Gitea status: "success" ✅
|
||||||
|
5. Response: 200 OK ✅
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"attempts": 1,
|
||||||
|
"gitea_status": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 2: Retry Logic with Fixable Errors (45 min)
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
```bash
|
||||||
|
# Clone test repo
|
||||||
|
git clone https://git.oky.sh/gitadmin/autonomous-build-test.git
|
||||||
|
cd autonomous-build-test
|
||||||
|
|
||||||
|
# Fix the syntax error in build.js
|
||||||
|
cat > build.js << 'EOF'
|
||||||
|
// Fixed version - proper closing braces
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.send('Hello World!'); // Now properly closed
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000, () => {
|
||||||
|
console.log('Server running');
|
||||||
|
});
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Commit and push
|
||||||
|
git add .
|
||||||
|
git commit -m "Fix: Corrected syntax errors in build.js"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Flow:**
|
||||||
|
1. **1st Attempt:** Fails (syntax error)
|
||||||
|
2. **2nd Attempt:** OpenHands receives feedback, fixes error
|
||||||
|
3. **3rd Attempt:** Succeeds ✅
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"attempts": 3,
|
||||||
|
"message": "Build completed successfully ✅",
|
||||||
|
"gitea_status": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 3: Max Retries with Persistent Errors (45 min)
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
```bash
|
||||||
|
# Force persistent error
|
||||||
|
cat > build.js << 'EOF'
|
||||||
|
// This will always fail
|
||||||
|
console.error('Intentional error - will not fix');
|
||||||
|
process.exit(1);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git add .
|
||||||
|
git commit -m "Test: Persistent error (should fail after 3 attempts)"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Flow:**
|
||||||
|
1. **1st Attempt:** Fails
|
||||||
|
2. **2nd Attempt:** Fails
|
||||||
|
3. **3rd Attempt:** Fails
|
||||||
|
4. **Stops:** Max retries exceeded ❌
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "FAILED",
|
||||||
|
"attempts": 3,
|
||||||
|
"max_attempts": 3,
|
||||||
|
"message": "Build failed after 3 attempts ❌",
|
||||||
|
"gitea_status": "failure"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 4: Real Project Build (45 min)
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
Use actual MVP project:
|
||||||
|
```bash
|
||||||
|
# Clone real project
|
||||||
|
git clone https://git.oky.sh/gitadmin/mvp-project.git
|
||||||
|
cd mvp-project
|
||||||
|
|
||||||
|
# Make a small change
|
||||||
|
echo "// Test change" >> README.md
|
||||||
|
|
||||||
|
# Commit and push
|
||||||
|
git add .
|
||||||
|
git commit -m "Test: Trigger autonomous build"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- OpenHands executes full build
|
||||||
|
- Dependencies installed correctly
|
||||||
|
- Build completes or fails with clear errors
|
||||||
|
- Retry logic works if needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 TROUBLESHOOTING GUIDE
|
||||||
|
|
||||||
|
### Issue 1: Retry Count Always 0
|
||||||
|
|
||||||
|
**Symptom:** Workflow doesn't retry, always shows attempt 1
|
||||||
|
|
||||||
|
**Solution:** Check Node 3 configuration
|
||||||
|
```javascript
|
||||||
|
// MUST initialize staticData
|
||||||
|
$workflow.staticData = $workflow.staticData || {};
|
||||||
|
$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0) + 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 2: Gitea Status Not Updating
|
||||||
|
|
||||||
|
**Symptom:** Commit status stays "pending" or doesn't appear
|
||||||
|
|
||||||
|
**Diagnosis:**
|
||||||
|
```bash
|
||||||
|
# Check token permissions
|
||||||
|
curl -H "X-Gitea-Token: {YOUR_TOKEN}" \
|
||||||
|
https://git.oky.sh/api/v1/user
|
||||||
|
|
||||||
|
# Should return user info
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Ensure token has "repo" scope
|
||||||
|
2. Check URL format: `/api/v1/repos/{owner}/{repo}/statuses/{sha}`
|
||||||
|
3. Verify commit_sha is correct (40 character SHA)
|
||||||
|
|
||||||
|
### Issue 3: Workflow Hangs After OpenHands
|
||||||
|
|
||||||
|
**Symptom:** Workflow stops at Node 4 or Node 5
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. **Check Wait Node:** Set to 10 seconds minimum
|
||||||
|
2. **Check SSH Timeout:** Set to 300000ms (5 minutes)
|
||||||
|
3. **Check SSH Authentication:** Test manually
|
||||||
|
```bash
|
||||||
|
ssh -i /home/bam/.ssh/n8n_key bam@localhost "echo 'SSH works'"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 4: OpenHands Not Using Feedback
|
||||||
|
|
||||||
|
**Symptom:** Retry attempts show same errors
|
||||||
|
|
||||||
|
**Solution:** Check Node 4 command generation
|
||||||
|
```javascript
|
||||||
|
// Must include previous error in task
|
||||||
|
if (retryCount > 0) {
|
||||||
|
task += `
|
||||||
|
|
||||||
|
PREVIOUS BUILD FAILED:
|
||||||
|
${errorDetails}`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 5: Data Lost in Retry Loop
|
||||||
|
|
||||||
|
**Symptom:** Repository info missing on retry
|
||||||
|
|
||||||
|
**Solution:** Check data preservation in Node 4
|
||||||
|
```javascript
|
||||||
|
return {
|
||||||
|
...repoData, // ← CRITICAL: Preserve repo data
|
||||||
|
code: sshOutput.code,
|
||||||
|
stdout: sshOutput.stdout,
|
||||||
|
stderr: sshOutput.stderr,
|
||||||
|
status: 'SUCCESS'
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 MONITORING & DEBUGGING
|
||||||
|
|
||||||
|
### Enable Workflow Debugging
|
||||||
|
|
||||||
|
**In n8n UI:**
|
||||||
|
1. Open workflow → Toggle "Save Manual Executions"
|
||||||
|
2. View execution history
|
||||||
|
3. Check each node's input/output
|
||||||
|
|
||||||
|
### Key Metrics to Track
|
||||||
|
|
||||||
|
- **Success Rate:** % of builds that succeed
|
||||||
|
- **Retry Efficiency:** Avg attempts per build
|
||||||
|
- **Build Time:** Duration from push to completion
|
||||||
|
- **Error Categories:** Type of failures
|
||||||
|
|
||||||
|
### Debug Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check OpenHands execution
|
||||||
|
tail -f /tmp/openhands_execution_*.log
|
||||||
|
|
||||||
|
# Test SSH manually
|
||||||
|
ssh -i /home/bam/.ssh/n8n_key bam@localhost \
|
||||||
|
"sh /home/bam/openhands-sdk-wrapper-sh.sh 'Test task'"
|
||||||
|
|
||||||
|
# Check workflow status
|
||||||
|
curl -H "X-N8N-API-KEY: {TOKEN}" \
|
||||||
|
https://n8n.oky.sh/api/v1/workflows/j1MmXaRhDjvkRSLa
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⏱️ TIME-BOXED IMPLEMENTATION
|
||||||
|
|
||||||
|
### Session 1 (2 hours): Core Workflow
|
||||||
|
- [ ] Step 1: Setup test repository (20 min)
|
||||||
|
- [ ] Step 2: Configure Gitea webhook (15 min)
|
||||||
|
- [ ] Step 3: Add nodes 3, 7, 8, 9, 10 (45 min)
|
||||||
|
- [ ] Test success path (30 min)
|
||||||
|
- [ ] Buffer for issues (10 min)
|
||||||
|
|
||||||
|
### Session 2 (2 hours): Retry Logic
|
||||||
|
- [ ] Test failure path with fixable errors (45 min)
|
||||||
|
- [ ] Test max retries (45 min)
|
||||||
|
- [ ] Debug and fix issues (30 min)
|
||||||
|
|
||||||
|
### Session 3 (1 hour): Real Project & Documentation
|
||||||
|
- [ ] Test with real project (45 min)
|
||||||
|
- [ ] Document workflow (15 min)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ SUCCESS CRITERIA
|
||||||
|
|
||||||
|
**Must Have:**
|
||||||
|
- [ ] End-to-end workflow completes (push → build → response)
|
||||||
|
- [ ] OpenHands executes autonomously
|
||||||
|
- [ ] Retry counter prevents infinite loops (max 3)
|
||||||
|
- [ ] Error feedback improves retry attempts
|
||||||
|
- [ ] Gitea commit status updates (success/failure)
|
||||||
|
- [ ] Works with real projects
|
||||||
|
|
||||||
|
**Verification:**
|
||||||
|
```bash
|
||||||
|
# Test workflow manually
|
||||||
|
curl -X POST https://n8n.oky.sh/webhook/openhands-autonomous-build \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"repository": {"name": "test-repo", "full_name": "gitadmin/test-repo"},
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"after": "abc123def456"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"attempts": 1,
|
||||||
|
"repo": "test-repo",
|
||||||
|
"branch": "main",
|
||||||
|
"gitea_status": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 REFERENCE FILES
|
||||||
|
|
||||||
|
- **Phase 3 Plan:** `/home/bam/claude/mvp-factory/phase3.md`
|
||||||
|
- **SDK Wrapper:** `/home/bam/openhands-sdk-wrapper-sh.sh`
|
||||||
|
- **n8n API Docs:** `/home/bam/claude/mvp-factory/n8n-api.md`
|
||||||
|
- **Phase 2 Learnings:** `/home/bam/claude/mvp-factory/phase2.md`
|
||||||
|
- **Data Preservation:** `/home/bam/claude/mvp-factory/N8N_DATA_PRESERVATION_SOLUTION.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 FINAL NOTES
|
||||||
|
|
||||||
|
**Key Reminders:**
|
||||||
|
1. **Data Preservation:** Always use `$node["Node Name"].json` pattern
|
||||||
|
2. **Retry Counter:** Initialize with `$workflow.staticData = $workflow.staticData || {}`
|
||||||
|
3. **SSH Timeout:** Set to 5 minutes minimum
|
||||||
|
4. **Wait Node:** 10 seconds between nodes
|
||||||
|
5. **Gitea Token:** Must have "repo" scope for status updates
|
||||||
|
|
||||||
|
**Workflow ID:** `j1MmXaRhDjvkRSLa`
|
||||||
|
**Target Webhook:** `https://n8n.oky.sh/webhook/openhands-autonomous-build`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Implementation Ready ✅**
|
||||||
|
**Estimated Total Time:** 4-5 hours
|
||||||
|
**Can proceed immediately**
|
||||||
|
|
@ -0,0 +1,344 @@
|
||||||
|
# Phase 3 Implementation Summary
|
||||||
|
|
||||||
|
**Date Created:** 2025-12-02
|
||||||
|
**Implementation Target:** Autonomous Build Test MVP
|
||||||
|
**Estimated Duration:** 4-5 hours
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 DOCUMENTATION PACKAGE CREATED
|
||||||
|
|
||||||
|
I've created a complete implementation package for Phase 3 with 5 comprehensive documents:
|
||||||
|
|
||||||
|
### 1. **phase3.md** (Original Plan - 12 KB)
|
||||||
|
- Original detailed plan
|
||||||
|
- Time estimates and timeline
|
||||||
|
- Overview and goals
|
||||||
|
- Test sequence strategy
|
||||||
|
|
||||||
|
### 2. **phase3-implementation-plan.md** (Main Guide - 21 KB) ⭐
|
||||||
|
**Primary document for implementation**
|
||||||
|
- Complete step-by-step guide
|
||||||
|
- All 11 nodes detailed
|
||||||
|
- Configuration instructions
|
||||||
|
- Success criteria
|
||||||
|
- Troubleshooting guide
|
||||||
|
|
||||||
|
### 3. **phase3-code-snippets.md** (Code Reference - 9.1 KB)
|
||||||
|
**Ready-to-copy code for each node**
|
||||||
|
- Node 3: Initialize Retry Counter code
|
||||||
|
- Node 4: Execute OpenHands Build (enhanced)
|
||||||
|
- Node 6: Evaluate Build Results code
|
||||||
|
- Node 8: Update Gitea Success (HTTP config)
|
||||||
|
- Node 9: Format Error for Retry code
|
||||||
|
- Node 11: Final Response (both paths)
|
||||||
|
- Decision node configurations
|
||||||
|
- Quick test commands
|
||||||
|
|
||||||
|
### 4. **phase3-quickstart.md** (Quick Start - 5.6 KB)
|
||||||
|
**5-minute setup guide**
|
||||||
|
- Generate Gitea token
|
||||||
|
- Create test repository
|
||||||
|
- Configure webhook
|
||||||
|
- Implementation checklist
|
||||||
|
- Critical reminders
|
||||||
|
|
||||||
|
### 5. **phase3-workflow-diagram.md** (Visual Guide - 15 KB)
|
||||||
|
**Complete workflow visualization**
|
||||||
|
- ASCII diagram of 11-node flow
|
||||||
|
- Data flow patterns
|
||||||
|
- Retry flow details
|
||||||
|
- Success/failure paths
|
||||||
|
- Timeline and execution flow
|
||||||
|
- Node configuration matrix
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 IMPLEMENTATION OVERVIEW
|
||||||
|
|
||||||
|
### Current State
|
||||||
|
- ✅ **Workflow ID:** `j1MmXaRhDjvkRSLa` (7 nodes)
|
||||||
|
- ✅ **n8n Instance:** https://n8n.oky.sh
|
||||||
|
- ✅ **OpenHands SDK:** Working via SSH
|
||||||
|
- ✅ **SSH Credentials:** Configured
|
||||||
|
- ✅ **API Keys:** MiniMax & DeepSeek available
|
||||||
|
|
||||||
|
### Target State
|
||||||
|
- **11-node autonomous CI/CD workflow**
|
||||||
|
- **Retry logic:** Max 3 attempts
|
||||||
|
- **Error feedback:** To OpenHands
|
||||||
|
- **Gitea status:** Auto-updates
|
||||||
|
- **Real project testing:** Functional
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 STEP-BY-STEP APPROACH
|
||||||
|
|
||||||
|
### Phase A: Preparation (20 min)
|
||||||
|
1. Generate Gitea API token (repo + admin:repo_hook scopes)
|
||||||
|
2. Create test repository: `autonomous-build-test`
|
||||||
|
3. Configure webhook: `/webhook/openhands-autonomous-build`
|
||||||
|
|
||||||
|
### Phase B: Add New Nodes (90 min)
|
||||||
|
1. **Node 3:** Initialize Retry Counter (Code node)
|
||||||
|
2. **Node 7:** Decision - Build OK? (IF node)
|
||||||
|
3. **Node 8:** Update Gitea Success (HTTP node)
|
||||||
|
4. **Node 9:** Format Error for Retry (Code node)
|
||||||
|
5. **Node 10:** Check Retry Count (IF node)
|
||||||
|
|
||||||
|
### Phase C: Modify Existing Nodes (60 min)
|
||||||
|
1. **Node 2:** Extract Repo Info (add fields)
|
||||||
|
2. **Node 4:** OpenHands Build (enhance + preserve data)
|
||||||
|
3. **Node 6:** Check Build Results (add success check)
|
||||||
|
4. **Node 11:** Final Response (support both paths)
|
||||||
|
|
||||||
|
### Phase D: Test (90 min)
|
||||||
|
1. Success path test
|
||||||
|
2. Retry with fixable errors
|
||||||
|
3. Max retries (3 attempts)
|
||||||
|
4. Real project test
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 WORKFLOW ARCHITECTURE
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐
|
||||||
|
│ [1] Webhook │ Receives Gitea push
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ [2] Extract │ Parse commit info
|
||||||
|
│ Repo Info │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐ ┌──────────────────┐
|
||||||
|
│ [3] Init │ │ [11] Final │
|
||||||
|
│ Retry │ │ Response │
|
||||||
|
└──────┬───────┘ └──────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ [4] OpenHands│ Execute build
|
||||||
|
│ Build │ (with error feedback)
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ [5] Wait │ 10 seconds
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ [6] Check │ Evaluate results
|
||||||
|
│ Results │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ [7] Decision │ Build OK?
|
||||||
|
│ Build OK? │
|
||||||
|
└────┬──┬──────┘
|
||||||
|
│ │
|
||||||
|
│ ├─ YES → [8] Gitea Success → [11]
|
||||||
|
│ │
|
||||||
|
│ └─ NO → [9] Format Error
|
||||||
|
│ ↓
|
||||||
|
│ [10] Retry Check
|
||||||
|
│ │
|
||||||
|
│ ┌────┴────┐
|
||||||
|
│ │ │
|
||||||
|
│ ▼ ▼
|
||||||
|
│ ┌────────┐ ┌───────┐
|
||||||
|
│ │ Loop │ │ [11] │
|
||||||
|
│ │ to [4] │ │Final │
|
||||||
|
│ └────────┘ └───────┘
|
||||||
|
│
|
||||||
|
└──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💾 KEY CODE PATTERNS
|
||||||
|
|
||||||
|
### 1. Data Preservation (Critical!)
|
||||||
|
```javascript
|
||||||
|
const sshOutput = $json;
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData, // ← PRESERVE INPUT
|
||||||
|
code: sshOutput.code,
|
||||||
|
stdout: sshOutput.stdout,
|
||||||
|
stderr: sshOutput.stderr
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Retry Counter Initialization
|
||||||
|
```javascript
|
||||||
|
$workflow.staticData = $workflow.staticData || {};
|
||||||
|
$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0) + 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Error Feedback Loop
|
||||||
|
```javascript
|
||||||
|
if (retryCount > 0) {
|
||||||
|
task += `
|
||||||
|
|
||||||
|
PREVIOUS BUILD FAILED:
|
||||||
|
${errorDetails}`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Gitea Status Update
|
||||||
|
```javascript
|
||||||
|
POST https://git.oky.sh/api/v1/repos/{owner}/{repo}/statuses/{sha}
|
||||||
|
{
|
||||||
|
"state": "success",
|
||||||
|
"description": "✅ Build passed after 2 attempt(s)",
|
||||||
|
"context": "openhands/autonomous-build"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 SUCCESS CRITERIA
|
||||||
|
|
||||||
|
### Must Have ✅
|
||||||
|
- [ ] End-to-end workflow completes (push → build → response)
|
||||||
|
- [ ] OpenHands executes autonomously
|
||||||
|
- [ ] Retry counter prevents infinite loops (max 3)
|
||||||
|
- [ ] Error feedback improves subsequent attempts
|
||||||
|
- [ ] Gitea commit status updates (success/failure)
|
||||||
|
- [ ] Works with real projects
|
||||||
|
|
||||||
|
### Validation Tests
|
||||||
|
1. **Test Success Path:** Valid code builds in 1 attempt
|
||||||
|
2. **Test Retry Logic:** Fixable errors resolve in 2-3 attempts
|
||||||
|
3. **Test Max Retries:** Persistent errors fail after 3 attempts
|
||||||
|
4. **Test Real Project:** Actual MVP project builds successfully
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 QUICK TEST COMMANDS
|
||||||
|
|
||||||
|
### Manual Workflow Trigger
|
||||||
|
```bash
|
||||||
|
curl -X POST https://n8n.oky.sh/webhook/openhands-autonomous-build \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"repository": {"name": "test-project", "full_name": "gitadmin/test-project"},
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"after": "abc123def456789012345678901234567890abcd"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create Test Repository
|
||||||
|
```bash
|
||||||
|
curl -X POST https://git.oky.sh/api/v1/user/repos \
|
||||||
|
-H "X-Gitea-Token: {YOUR_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"autonomous-build-test"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test SSH Connectivity
|
||||||
|
```bash
|
||||||
|
ssh -i /home/bam/.ssh/n8n_key bam@localhost \
|
||||||
|
"sh /home/bam/openhands-sdk-wrapper-sh.sh 'Test connection'"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 CRITICAL WARNINGS
|
||||||
|
|
||||||
|
### ⚠️ Data Loss Prevention
|
||||||
|
- SSH nodes **overwrite ALL data**
|
||||||
|
- Must use `$node["Node Name"].json` pattern
|
||||||
|
- Always preserve repo data: `...repoData`
|
||||||
|
|
||||||
|
### ⚠️ Retry Counter
|
||||||
|
- Must initialize: `$workflow.staticData = $workflow.staticData || {}`
|
||||||
|
- Increment: `$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0) + 1`
|
||||||
|
- Check: `if (retryCount >= 3) return fail;`
|
||||||
|
|
||||||
|
### ⚠️ Gitea Token
|
||||||
|
- Required for status updates
|
||||||
|
- Must have scopes: `repo` + `admin:repo_hook`
|
||||||
|
- Format: `gho_...` or `gsat_...`
|
||||||
|
|
||||||
|
### ⚠️ SSH Configuration
|
||||||
|
- Host: `localhost`
|
||||||
|
- User: `bam`
|
||||||
|
- Key: `/home/bam/.ssh/n8n_key`
|
||||||
|
- Timeout: `300000` (5 minutes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 IMPLEMENTATION SEQUENCE
|
||||||
|
|
||||||
|
### Start Here ⭐
|
||||||
|
1. **Read:** `phase3-implementation-plan.md` (complete guide)
|
||||||
|
2. **Copy code from:** `phase3-code-snippets.md`
|
||||||
|
3. **Reference:** `phase3-workflow-diagram.md` (visual guide)
|
||||||
|
4. **Quick setup:** `phase3-quickstart.md` (5-min checklist)
|
||||||
|
|
||||||
|
### Use Todo List
|
||||||
|
```bash
|
||||||
|
# Progress tracking
|
||||||
|
# Mark items as completed:
|
||||||
|
TodoWrite --todos "[...]" # Update status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 FILE LOCATIONS
|
||||||
|
|
||||||
|
All documentation in: `/home/bam/claude/mvp-factory/`
|
||||||
|
|
||||||
|
```
|
||||||
|
phase3.md (Original plan)
|
||||||
|
phase3-implementation-plan.md (Main implementation guide) ⭐
|
||||||
|
phase3-code-snippets.md (Copy-paste code)
|
||||||
|
phase3-quickstart.md (Quick start)
|
||||||
|
phase3-workflow-diagram.md (Visual diagram)
|
||||||
|
phase3-implementation-summary.md (This file)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 READY TO IMPLEMENT
|
||||||
|
|
||||||
|
### Everything You Need ✅
|
||||||
|
- ✅ Complete documentation (5 files, 62 KB)
|
||||||
|
- ✅ Ready-to-copy code snippets
|
||||||
|
- ✅ Visual workflow diagrams
|
||||||
|
- ✅ Step-by-step instructions
|
||||||
|
- ✅ Troubleshooting guide
|
||||||
|
- ✅ Test commands
|
||||||
|
- ✅ Success criteria checklist
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
1. **Read** `phase3-implementation-plan.md`
|
||||||
|
2. **Generate** Gitea API token
|
||||||
|
3. **Start** with Node 3 (Initialize Retry Counter)
|
||||||
|
4. **Follow** code snippets from `phase3-code-snippets.md`
|
||||||
|
5. **Test** using commands in `phase3-quickstart.md`
|
||||||
|
|
||||||
|
### Time Estimate
|
||||||
|
- **Setup:** 30 minutes
|
||||||
|
- **Implementation:** 2-3 hours
|
||||||
|
- **Testing:** 1-2 hours
|
||||||
|
- **Total:** 4-5 hours
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status: Implementation Ready** 🚀
|
||||||
|
|
||||||
|
All documentation and code snippets are prepared and ready to use immediately.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Implementation Summary - Created: 2025-12-02*
|
||||||
|
*All Phase 3 documentation complete*
|
||||||
|
|
@ -0,0 +1,240 @@
|
||||||
|
# Phase 3 Quick Start Guide
|
||||||
|
|
||||||
|
**Goal:** Transform 7-node workflow → 11-node autonomous CI/CD with retry logic
|
||||||
|
**Time:** 4-5 hours
|
||||||
|
**Workflow ID:** `j1MmXaRhDjvkRSLa`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 5-MINUTE SETUP
|
||||||
|
|
||||||
|
### 1. Get Gitea Token (Required for Status Updates)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# UI Method (Easiest):
|
||||||
|
# 1. Go to https://git.oky.sh/user/settings/applications
|
||||||
|
# 2. Click "Generate Token"
|
||||||
|
# 3. Name: n8n-autonomous-build
|
||||||
|
# 4. Scopes: repo, admin:repo_hook
|
||||||
|
# 5. Copy token (format: gho_...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create Test Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via API:
|
||||||
|
curl -X POST https://git.oky.sh/api/v1/user/repos \
|
||||||
|
-H "X-Gitea-Token: {YOUR_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"autonomous-build-test","description":"Phase 3 test repo"}'
|
||||||
|
|
||||||
|
# Or via UI:
|
||||||
|
# https://git.oky.sh → + → New Repository
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configure Webhook
|
||||||
|
|
||||||
|
1. Go to: `https://git.oky.sh/gitadmin/autonomous-build-test/settings/hooks`
|
||||||
|
2. Add Webhook:
|
||||||
|
- URL: `https://n8n.oky.sh/webhook/openhands-autonomous-build`
|
||||||
|
- Trigger: Push events
|
||||||
|
- Active: ✓
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 IMPLEMENTATION CHECKLIST
|
||||||
|
|
||||||
|
### Phase A: Add New Nodes (90 min)
|
||||||
|
|
||||||
|
- [ ] **Node 3:** Initialize Retry Counter
|
||||||
|
- Type: Code
|
||||||
|
- Code: See `phase3-code-snippets.md` → "Node 3"
|
||||||
|
|
||||||
|
- [ ] **Node 7:** Decision - Build OK?
|
||||||
|
- Type: IF
|
||||||
|
- Condition: `$json.build_success == true`
|
||||||
|
|
||||||
|
- [ ] **Node 8:** Update Gitea Success
|
||||||
|
- Type: HTTP
|
||||||
|
- URL: `https://git.oky.sh/api/v1/repos/{owner}/{repo}/statuses/{sha}`
|
||||||
|
- Token: `{YOUR_GITEA_API_TOKEN}`
|
||||||
|
|
||||||
|
- [ ] **Node 9:** Format Error for Retry
|
||||||
|
- Type: Code
|
||||||
|
- Code: See `phase3-code-snippets.md` → "Node 9"
|
||||||
|
|
||||||
|
- [ ] **Node 10:** Check Retry Count
|
||||||
|
- Type: IF
|
||||||
|
- Condition: `$json.can_retry == true`
|
||||||
|
|
||||||
|
### Phase B: Modify Existing Nodes (60 min)
|
||||||
|
|
||||||
|
- [ ] **Node 2:** Extract Repo Info
|
||||||
|
- Add: `repo_name`, `owner`, `branch`, `commit_sha`
|
||||||
|
|
||||||
|
- [ ] **Node 4:** Execute OpenHands Build
|
||||||
|
- Enhance command with error feedback
|
||||||
|
- Add data preservation pattern
|
||||||
|
|
||||||
|
- [ ] **Node 6:** Check Build Results
|
||||||
|
- Add: `build_success`, `error_details`
|
||||||
|
|
||||||
|
- [ ] **Node 11:** Final Response
|
||||||
|
- Support both success AND failure paths
|
||||||
|
|
||||||
|
### Phase C: Test (90 min)
|
||||||
|
|
||||||
|
- [ ] Test 1: Success Path (30 min)
|
||||||
|
- [ ] Test 2: Retry with Fixable Errors (30 min)
|
||||||
|
- [ ] Test 3: Max Retries (3 attempts) (30 min)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 KEY RESOURCES
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `phase3-implementation-plan.md` | Complete implementation guide (11 nodes) |
|
||||||
|
| `phase3-code-snippets.md` | Ready-to-copy code for each node |
|
||||||
|
| `phase3-quickstart.md` | This file - quick start guide |
|
||||||
|
| `phase3.md` | Original Phase 3 plan |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 NODES BREAKDOWN
|
||||||
|
|
||||||
|
### Current Workflow (7 nodes)
|
||||||
|
```
|
||||||
|
[1] Gitea Webhook
|
||||||
|
[2] Extract Repo Info
|
||||||
|
[3] Start OpenHands Build
|
||||||
|
[4] Wait 10s
|
||||||
|
[5] Check Build Status
|
||||||
|
[6] Format Response
|
||||||
|
[7] Send Response
|
||||||
|
```
|
||||||
|
|
||||||
|
### Target Workflow (11 nodes)
|
||||||
|
```
|
||||||
|
[1] Gitea Webhook
|
||||||
|
[2] Extract Repo Info (MODIFY)
|
||||||
|
[3] Initialize Retry Counter (NEW)
|
||||||
|
[4] Start OpenHands Build (MODIFY)
|
||||||
|
[5] Wait 10s
|
||||||
|
[6] Check Build Results (MODIFY)
|
||||||
|
[7] Decision: Build OK? (NEW)
|
||||||
|
├─ YES → [8] Update Gitea Success → [11] Response
|
||||||
|
└─ NO → [9] Format Error Feedback
|
||||||
|
↓
|
||||||
|
[10] Check Retry Count
|
||||||
|
├─ YES → Loop to [4]
|
||||||
|
└─ NO → [11] Final Response
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ CRITICAL REMINDERS
|
||||||
|
|
||||||
|
### 1. Data Preservation Pattern
|
||||||
|
**ALWAYS use this in SSH nodes:**
|
||||||
|
```javascript
|
||||||
|
const sshOutput = $json;
|
||||||
|
const repoData = $node["Extract Repo Info"].json;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...repoData, // ← PRESERVE INPUT DATA
|
||||||
|
code: sshOutput.code,
|
||||||
|
stdout: sshOutput.stdout,
|
||||||
|
stderr: sshOutput.stderr
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Retry Counter Initialization
|
||||||
|
**MUST initialize in Node 3:**
|
||||||
|
```javascript
|
||||||
|
$workflow.staticData = $workflow.staticData || {};
|
||||||
|
$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0) + 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. SSH Node Configuration
|
||||||
|
```
|
||||||
|
Host: localhost
|
||||||
|
User: bam
|
||||||
|
Private Key: /home/bam/.ssh/n8n_key
|
||||||
|
Timeout: 300000 (5 minutes)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 QUICK TESTS
|
||||||
|
|
||||||
|
### Test 1: Manual Workflow Trigger
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST https://n8n.oky.sh/webhook/openhands-autonomous-build \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"repository": {
|
||||||
|
"name": "test-project",
|
||||||
|
"full_name": "gitadmin/test-project",
|
||||||
|
"owner": {"name": "gitadmin", "username": "gitadmin"}
|
||||||
|
},
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"after": "abc123def456789012345678901234567890abcd"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 2: SSH Connectivity
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -i /home/bam/.ssh/n8n_key bam@localhost \
|
||||||
|
"sh /home/bam/openhands-sdk-wrapper-sh.sh 'Test connection'"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 SUCCESS CRITERIA
|
||||||
|
|
||||||
|
✅ **End-to-end completes:** Push → Build → Response
|
||||||
|
✅ **Retry works:** Max 3 attempts, then stop
|
||||||
|
✅ **Gitea status:** Updates to success/failure
|
||||||
|
✅ **Error feedback:** OpenHands receives previous errors
|
||||||
|
✅ **Real projects:** Works with actual MVP project
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 TROUBLESHOOTING
|
||||||
|
|
||||||
|
| Problem | Quick Fix |
|
||||||
|
|---------|-----------|
|
||||||
|
| Retry count always 0 | Initialize `$workflow.staticData` |
|
||||||
|
| Gitea status not updating | Check token has "repo" scope |
|
||||||
|
| Workflow hangs | Increase SSH timeout to 5 min |
|
||||||
|
| Data lost in loop | Use `$node["Node Name"].json` pattern |
|
||||||
|
| Same errors on retry | Include error in task string |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 CURRENT STATUS
|
||||||
|
|
||||||
|
- ✅ Phase 2 Complete
|
||||||
|
- ✅ Workflow ID: `j1MmXaRhDjvkRSLa`
|
||||||
|
- ✅ OpenHands SDK: Working
|
||||||
|
- ✅ n8n + Gitea: Configured
|
||||||
|
- ⏳ Phase 3: Ready to implement
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 NEXT STEPS
|
||||||
|
|
||||||
|
1. **Now:** Read `phase3-implementation-plan.md`
|
||||||
|
2. **Then:** Generate Gitea token
|
||||||
|
3. **Then:** Start with Node 3 (Initialize Retry Counter)
|
||||||
|
4. **Follow:** `phase3-code-snippets.md` for exact code
|
||||||
|
|
||||||
|
**Total Time:** 4-5 hours
|
||||||
|
**Can start immediately! 🚀**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Quick Start Guide - Last Updated: 2025-12-02*
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,267 @@
|
||||||
|
# Phase 3 Workflow Diagram
|
||||||
|
|
||||||
|
## Current Workflow (7 Nodes) → Target Workflow (11 Nodes)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ PHASE 3: AUTONOMOUS BUILD TEST │
|
||||||
|
│ Workflow ID: j1MmXaRhDjvkRSLa │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌────────────────┐
|
||||||
|
│ [1] Gitea │ Webhook: /webhook/openhands-autonomous-build
|
||||||
|
│ Webhook │ Trigger: Push events
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [2] Extract │ Code Node
|
||||||
|
│ Repo Info │ Extract: repo_name, owner, branch, commit_sha
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [3] Initialize │ Code Node ★ NEW
|
||||||
|
│ Retry Count │ Initialize: $workflow.staticData.retry_count = 0
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [4] OpenHands │ SSH Node ★ MODIFIED
|
||||||
|
│ Build │ - Enhanced task with error feedback
|
||||||
|
│ - Data preservation pattern
|
||||||
|
│ - Retry logic on loop back
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [5] Wait │ Wait Node (10 seconds)
|
||||||
|
│ 10s │
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [6] Check │ Code Node ★ MODIFIED
|
||||||
|
│ Build │ Add: build_success, error_details
|
||||||
|
│ Results │
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [7] Decision │ IF Node ★ NEW
|
||||||
|
│ Build OK? │ Condition: build_success == true
|
||||||
|
└───────┬────────┘
|
||||||
|
│
|
||||||
|
├──────────────────────┐
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌───────────────┐ ┌──────────────────┐
|
||||||
|
│ [8] Update │ │ [9] Format Error│ Code Node ★ NEW
|
||||||
|
│ Gitea │ │ for Retry │ Format: error_message
|
||||||
|
│ Success │ │ │
|
||||||
|
└───────┬───────┘ └────────┬─────────┘
|
||||||
|
│ │
|
||||||
|
│ ▼
|
||||||
|
│ ┌──────────────────┐
|
||||||
|
│ │ [10] Check Retry│ IF Node ★ NEW
|
||||||
|
│ │ Count │ Condition: can_retry == true
|
||||||
|
│ └───────┬────────┘
|
||||||
|
│ │
|
||||||
|
│ ┌───────┴────────┐
|
||||||
|
│ │ │
|
||||||
|
│ ▼ ▼
|
||||||
|
│ ┌────────────────┐ ┌──────────────────┐
|
||||||
|
│ │ Loop back to │ │ [11] Final │ Code Node
|
||||||
|
│ │ Node 4 │ │ Response │ ★ MODIFIED
|
||||||
|
│ └────────────────┘ │ (Failure) │
|
||||||
|
│ └────────┬─────────┘
|
||||||
|
│ │
|
||||||
|
└────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ [12] HTTP │ Respond to Webhook
|
||||||
|
│ Response │ Status: 200/500
|
||||||
|
└────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
DATA FLOW PATTERNS
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
[2] Extract Repo Info ───┐
|
||||||
|
│ Output: {
|
||||||
|
[3] Initialize Retry ────┤ repo_name, owner, branch,
|
||||||
|
│ commit_sha, retry_count
|
||||||
|
[4] OpenHands ───────────┤ } ↓
|
||||||
|
│
|
||||||
|
[4] preserves data ──────┼──► return {
|
||||||
|
│ ...repoData, ← PRESERVE
|
||||||
|
│ code, stdout,
|
||||||
|
│ stderr, status
|
||||||
|
[6] Check Results ───────┤ }
|
||||||
|
│ ↓
|
||||||
|
│
|
||||||
|
[7] Decision ────────────┼──► build_success? → true/false
|
||||||
|
│
|
||||||
|
[8] Update Gitea ────────┤ On success → POST to Gitea API
|
||||||
|
│
|
||||||
|
[9] Format Error ────────┤ On failure → Format comprehensive error
|
||||||
|
│
|
||||||
|
[10] Retry Check ────────┤ can_retry? → true/false
|
||||||
|
│
|
||||||
|
[4] Loop back ───────────┤ If true → Back to OpenHands with feedback
|
||||||
|
│ If false → Final failure
|
||||||
|
│
|
||||||
|
[11] Final Response ─────┴──► SUCCESS or FAILED with details
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
RETRY FLOW DETAIL
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
Attempt 1:
|
||||||
|
[3] retry_count = 0 → [4] OpenHands (first attempt) → [6] Check → [7] FAIL
|
||||||
|
→ [9] Format Error → [10] Check: can_retry? YES (0 < 2) → Loop to [4]
|
||||||
|
|
||||||
|
Attempt 2:
|
||||||
|
[3] retry_count = 1 → [4] OpenHands (with error feedback) → [6] Check → [7] FAIL
|
||||||
|
→ [9] Format Error → [10] Check: can_retry? YES (1 < 2) → Loop to [4]
|
||||||
|
|
||||||
|
Attempt 3:
|
||||||
|
[3] retry_count = 2 → [4] OpenHands (with error feedback) → [6] Check → [7] FAIL
|
||||||
|
→ [9] Format Error → [10] Check: can_retry? NO (2 ≮ 2) → [11] Final Failure
|
||||||
|
|
||||||
|
Stop: Max retries (3) exceeded
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
SUCCESS FLOW
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
Attempt 1 (Success):
|
||||||
|
[3] retry_count = 0 → [4] OpenHands (first attempt) → [6] Check → [7] SUCCESS
|
||||||
|
→ [8] Update Gitea → [11] Final Response (Success)
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
KEY IMPLEMENTATION NOTES
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
⚠️ CRITICAL: Data Preservation Pattern
|
||||||
|
In Node 4 (SSH), ALWAYS preserve previous node data:
|
||||||
|
```
|
||||||
|
return {
|
||||||
|
...repoData, // ← This line is CRITICAL
|
||||||
|
code: sshOutput.code,
|
||||||
|
stdout: sshOutput.stdout,
|
||||||
|
stderr: sshOutput.stderr
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️ CRITICAL: Retry Counter Initialization
|
||||||
|
In Node 3, MUST initialize staticData:
|
||||||
|
```
|
||||||
|
$workflow.staticData = $workflow.staticData || {};
|
||||||
|
$workflow.staticData.retry_count = ($workflow.staticData.retry_count || 0) + 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️ CRITICAL: Error Feedback Loop
|
||||||
|
In Node 4, include previous errors in task:
|
||||||
|
```
|
||||||
|
if (retryCount > 0) {
|
||||||
|
task += `PREVIOUS BUILD FAILED:\n${errorDetails}`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
NODE CONFIGURATIONS
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
Node Type Matrix:
|
||||||
|
|
||||||
|
┌──────┬─────────────────┬──────────────────────────────────────────────┐
|
||||||
|
│ Node │ Type │ Key Configuration │
|
||||||
|
├──────┼─────────────────┼──────────────────────────────────────────────┤
|
||||||
|
│ 1 │ Webhook │ Path: /webhook/openhands-autonomous-build │
|
||||||
|
│ 2 │ Code │ Extract repo data │
|
||||||
|
│ 3 │ Code │ Initialize $workflow.staticData.retry_count │
|
||||||
|
│ 4 │ SSH │ Host: localhost, Timeout: 300000ms │
|
||||||
|
│ 5 │ Wait │ 10 seconds │
|
||||||
|
│ 6 │ Code │ Evaluate build_success │
|
||||||
|
│ 7 │ IF │ Condition: build_success == true │
|
||||||
|
│ 8 │ HTTP │ POST Gitea API │
|
||||||
|
│ 9 │ Code │ Format error with feedback │
|
||||||
|
│ 10 │ IF │ Condition: can_retry == true │
|
||||||
|
│ 11 │ Code │ Final SUCCESS/FAILED response │
|
||||||
|
│ 12 │ Respond to Web │ Return HTTP 200/500 │
|
||||||
|
└──────┴─────────────────┴──────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
GITEA STATUS UPDATES
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
Success Path (Node 8):
|
||||||
|
POST https://git.oky.sh/api/v1/repos/{owner}/{repo}/statuses/{sha}
|
||||||
|
Body: {
|
||||||
|
"state": "success",
|
||||||
|
"description": "✅ Build passed after {retry_count} attempt(s)",
|
||||||
|
"context": "openhands/autonomous-build"
|
||||||
|
}
|
||||||
|
|
||||||
|
Failure Path (Node 11):
|
||||||
|
POST https://git.oky.sh/api/v1/repos/{owner}/{repo}/statuses/{sha}
|
||||||
|
Body: {
|
||||||
|
"state": "failure",
|
||||||
|
"description": "❌ Build failed after 3 attempts",
|
||||||
|
"context": "openhands/autonomous-build"
|
||||||
|
}
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
EXECUTION TIMELINE
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
Success (No Retry):
|
||||||
|
T+0s → Webhook received
|
||||||
|
T+5s → OpenHands starts build
|
||||||
|
T+15s → Build complete, result checked
|
||||||
|
T+16s → Gitea status updated
|
||||||
|
T+17s → Response sent
|
||||||
|
|
||||||
|
Success (After 2 Retries):
|
||||||
|
T+0s → Webhook received
|
||||||
|
T+5s → 1st OpenHands attempt
|
||||||
|
T+15s → 1st failure, formatted
|
||||||
|
T+20s → 2nd OpenHands attempt (with feedback)
|
||||||
|
T+30s → 2nd failure, formatted
|
||||||
|
T+35s → 3rd OpenHands attempt (with feedback)
|
||||||
|
T+45s → 3rd success
|
||||||
|
T+46s → Gitea status updated
|
||||||
|
T+47s → Response sent
|
||||||
|
|
||||||
|
Failure (Max Retries):
|
||||||
|
T+0s → Webhook received
|
||||||
|
T+5s → 1st OpenHands attempt
|
||||||
|
T+15s → 1st failure
|
||||||
|
T+20s → 2nd OpenHands attempt
|
||||||
|
T+30s → 2nd failure
|
||||||
|
T+35s → 3rd OpenHands attempt
|
||||||
|
T+45s → 3rd failure
|
||||||
|
T+46s → Gitea status updated (failure)
|
||||||
|
T+47s → Response sent (max retries exceeded)
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
FILE REFERENCES
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
📄 Documentation:
|
||||||
|
- phase3.md (Original plan)
|
||||||
|
- phase3-implementation-plan.md (Detailed guide)
|
||||||
|
- phase3-code-snippets.md (Ready-to-copy code)
|
||||||
|
- phase3-quickstart.md (Quick start)
|
||||||
|
|
||||||
|
🔧 Configuration:
|
||||||
|
- n8n API Key: /home/bam/.n8n_api_key
|
||||||
|
- SSH Key: /home/bam/.ssh/n8n_key
|
||||||
|
- OpenHands: /home/bam/openhands-sdk-wrapper-sh.sh
|
||||||
|
|
||||||
|
🧪 Testing:
|
||||||
|
- Test repo: autonomous-build-test
|
||||||
|
- Webhook: /webhook/openhands-autonomous-build
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
@ -0,0 +1,382 @@
|
||||||
|
# AUTONOMOUS BUILD MISSION: OKYSH Agency Website v2
|
||||||
|
|
||||||
|
You are an autonomous agent with a critical mission: build a production-ready Vue.js website through iterative testing and self-correction.
|
||||||
|
|
||||||
|
## 🎯 PROJECT REQUIREMENTS
|
||||||
|
|
||||||
|
**Website:** OKYSH - AI Development Agency
|
||||||
|
**Tech Stack:** Vue 3, Vite, TailwindCSS, GSAP animations
|
||||||
|
**Sections:** Hero, Services, About, Tech Stack, Portfolio, Contact Form, Footer
|
||||||
|
|
||||||
|
## 🔄 AUTONOMOUS WORKFLOW - FOLLOW STRICTLY
|
||||||
|
|
||||||
|
### ⚙️ ITERATION TRACKING
|
||||||
|
Before starting, create a file: `build-log.md` to track your progress.
|
||||||
|
After EACH phase, append to this file:
|
||||||
|
```
|
||||||
|
## Iteration X - [Phase Name]
|
||||||
|
Status: [Success/Failed]
|
||||||
|
Errors: [list if any]
|
||||||
|
Actions taken: [what you did]
|
||||||
|
Next step: [what's next]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📦 PHASE 1: INITIAL SETUP
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
1. Create project structure
|
||||||
|
2. Install dependencies with `package.json` that includes:
|
||||||
|
- vue@^3.4.0
|
||||||
|
- vite@^5.0.0
|
||||||
|
- tailwindcss@^3.4.0
|
||||||
|
- @vitejs/plugin-vue
|
||||||
|
- autoprefixer, postcss
|
||||||
|
3. Create `vite.config.js` with:
|
||||||
|
```js
|
||||||
|
server: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 3002,
|
||||||
|
allowedHosts: 'all'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
4. Create `tailwind.config.js` with COMPLETE color palette (primary, accent, dark)
|
||||||
|
- **CRITICAL:** Include ALL shades 50-950 for primary color
|
||||||
|
- primary-400 MUST exist
|
||||||
|
5. Setup basic Vue app structure
|
||||||
|
|
||||||
|
**Self-Check:**
|
||||||
|
```bash
|
||||||
|
ls -la # Verify all files created
|
||||||
|
cat tailwind.config.js # Verify colors include 400 shade
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- [ ] All config files exist
|
||||||
|
- [ ] package.json valid
|
||||||
|
- [ ] tailwind.config.js has primary-50 through primary-950
|
||||||
|
|
||||||
|
**Log your progress to build-log.md before proceeding**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🏗️ PHASE 2: BUILD VALIDATION LOOP
|
||||||
|
|
||||||
|
**DO NOT PROCEED UNTIL BUILD SUCCEEDS**
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
1. Run: `npm install`
|
||||||
|
2. Capture output and check for errors
|
||||||
|
3. If install fails:
|
||||||
|
- Read error message carefully
|
||||||
|
- Identify the issue (version conflict? missing dep?)
|
||||||
|
- Fix package.json
|
||||||
|
- GO BACK TO STEP 1
|
||||||
|
4. Run: `npm run build`
|
||||||
|
5. Capture build output
|
||||||
|
6. If build fails:
|
||||||
|
- Read FULL error message
|
||||||
|
- Common issues:
|
||||||
|
* Missing Tailwind colors (bg-primary-XXX not defined)
|
||||||
|
* Import errors (wrong paths)
|
||||||
|
* Syntax errors
|
||||||
|
- Fix the SPECIFIC issue mentioned
|
||||||
|
- GO BACK TO STEP 1
|
||||||
|
|
||||||
|
**Self-Check Commands:**
|
||||||
|
```bash
|
||||||
|
npm install 2>&1 | tee install.log
|
||||||
|
echo "Install exit code: $?"
|
||||||
|
|
||||||
|
npm run build 2>&1 | tee build.log
|
||||||
|
echo "Build exit code: $?"
|
||||||
|
|
||||||
|
# Check if dist/ was created
|
||||||
|
ls -la dist/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- [ ] npm install exit code = 0
|
||||||
|
- [ ] npm run build exit code = 0
|
||||||
|
- [ ] dist/ directory exists with index.html
|
||||||
|
|
||||||
|
**MAXIMUM 5 ATTEMPTS:** If still failing after 5 tries, STOP and report:
|
||||||
|
```
|
||||||
|
ESCALATION NEEDED: Build failing after 5 attempts
|
||||||
|
Last error: [paste error]
|
||||||
|
Attempts made: [list what you tried]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Log your progress before proceeding**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🚀 PHASE 3: DEV SERVER VALIDATION
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
1. Start dev server in background:
|
||||||
|
```bash
|
||||||
|
npm run dev > dev-server.log 2>&1 &
|
||||||
|
DEV_PID=$!
|
||||||
|
echo $DEV_PID > dev-server.pid
|
||||||
|
```
|
||||||
|
2. Wait 15 seconds for startup
|
||||||
|
3. Check if server is running:
|
||||||
|
```bash
|
||||||
|
sleep 15
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:3002
|
||||||
|
```
|
||||||
|
4. If curl returns 000 or fails:
|
||||||
|
- Read dev-server.log for errors
|
||||||
|
- Kill process: `kill $(cat dev-server.pid)`
|
||||||
|
- Fix the issue
|
||||||
|
- GO BACK TO PHASE 2 (rebuild might be needed)
|
||||||
|
5. If curl returns 200:
|
||||||
|
- Proceed to next phase
|
||||||
|
|
||||||
|
**Self-Check:**
|
||||||
|
```bash
|
||||||
|
# Is port listening?
|
||||||
|
netstat -tlnp | grep 3002
|
||||||
|
|
||||||
|
# Can we reach it?
|
||||||
|
curl -I http://localhost:3002
|
||||||
|
|
||||||
|
# Any errors in log?
|
||||||
|
tail -20 dev-server.log
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- [ ] Port 3002 is listening
|
||||||
|
- [ ] curl returns HTTP 200
|
||||||
|
- [ ] No error messages in dev-server.log
|
||||||
|
|
||||||
|
**MAXIMUM 3 ATTEMPTS**
|
||||||
|
|
||||||
|
**Log your progress before proceeding**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🌐 PHASE 4: BASIC CONTENT VALIDATION
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
1. Fetch homepage HTML:
|
||||||
|
```bash
|
||||||
|
curl -s http://localhost:3002 > homepage.html
|
||||||
|
```
|
||||||
|
2. Check if content exists:
|
||||||
|
```bash
|
||||||
|
# Should have substantial content
|
||||||
|
wc -c homepage.html # Should be > 1000 bytes
|
||||||
|
|
||||||
|
# Should have Vue app mount
|
||||||
|
grep 'id="app"' homepage.html
|
||||||
|
|
||||||
|
# Should load Vue
|
||||||
|
grep -i "vue" homepage.html
|
||||||
|
```
|
||||||
|
3. If homepage is empty or too small:
|
||||||
|
- Check browser console errors (you'll need to simulate this)
|
||||||
|
- Likely issues:
|
||||||
|
* Vue not mounting
|
||||||
|
* JavaScript errors
|
||||||
|
* Missing components
|
||||||
|
- Fix and GO BACK TO PHASE 2
|
||||||
|
|
||||||
|
**Self-Check:**
|
||||||
|
```bash
|
||||||
|
echo "Homepage size: $(wc -c < homepage.html) bytes"
|
||||||
|
echo "Contains #app div: $(grep -c 'id="app"' homepage.html)"
|
||||||
|
echo "Vue referenced: $(grep -ic vue homepage.html)"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- [ ] homepage.html > 1000 bytes
|
||||||
|
- [ ] Contains id="app"
|
||||||
|
- [ ] References Vue
|
||||||
|
|
||||||
|
**Log your progress before proceeding**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✅ PHASE 5: COMPONENT VALIDATION
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
1. Verify all required components exist:
|
||||||
|
```bash
|
||||||
|
ls src/components/Navigation.vue
|
||||||
|
ls src/components/Hero.vue
|
||||||
|
ls src/components/Services.vue
|
||||||
|
ls src/components/AboutUs.vue
|
||||||
|
ls src/components/TechStack.vue
|
||||||
|
ls src/components/Portfolio.vue
|
||||||
|
ls src/components/ContactForm.vue
|
||||||
|
ls src/components/Footer.vue
|
||||||
|
```
|
||||||
|
2. Check each component for common errors:
|
||||||
|
```bash
|
||||||
|
# Check for syntax errors
|
||||||
|
for file in src/components/*.vue; do
|
||||||
|
echo "Checking $file"
|
||||||
|
# Look for unclosed tags, etc
|
||||||
|
grep -c '<template>' "$file"
|
||||||
|
grep -c '</template>' "$file"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
3. If any component missing or broken:
|
||||||
|
- Create or fix it
|
||||||
|
- Ensure proper Vue 3 syntax
|
||||||
|
- GO BACK TO PHASE 2 (rebuild)
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- [ ] All 8 components exist
|
||||||
|
- [ ] Each has matching open/close tags
|
||||||
|
- [ ] No obvious syntax errors
|
||||||
|
|
||||||
|
**Log your progress before proceeding**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🎨 PHASE 6: STYLING VALIDATION
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
1. Check if Tailwind is working:
|
||||||
|
```bash
|
||||||
|
# Inspect generated CSS
|
||||||
|
curl -s http://localhost:3002/src/style.css | head -50
|
||||||
|
```
|
||||||
|
2. Common Tailwind issues:
|
||||||
|
- Colors not defined (bg-primary-XXX)
|
||||||
|
- @apply with undefined classes
|
||||||
|
- PostCSS not processing
|
||||||
|
3. If styling broken:
|
||||||
|
- Fix tailwind.config.js
|
||||||
|
- Fix CSS files
|
||||||
|
- GO BACK TO PHASE 2
|
||||||
|
|
||||||
|
**Self-Check:**
|
||||||
|
```bash
|
||||||
|
# Check tailwind.config.js has all colors
|
||||||
|
grep -A 20 "primary:" tailwind.config.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success Criteria:**
|
||||||
|
- [ ] Tailwind colors fully defined
|
||||||
|
- [ ] CSS loads without errors
|
||||||
|
- [ ] No PostCSS warnings
|
||||||
|
|
||||||
|
**Log your progress before proceeding**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📊 PHASE 7: FINAL CHECKLIST
|
||||||
|
|
||||||
|
**Before declaring success, verify:**
|
||||||
|
```bash
|
||||||
|
# 1. Clean build
|
||||||
|
npm run build && echo "✅ Build: PASS" || echo "❌ Build: FAIL"
|
||||||
|
|
||||||
|
# 2. Dev server runs
|
||||||
|
pkill -f "vite" # Kill old server
|
||||||
|
npm run dev > /tmp/vite.log 2>&1 &
|
||||||
|
sleep 10
|
||||||
|
curl -s http://localhost:3002 > /dev/null && echo "✅ Server: PASS" || echo "❌ Server: FAIL"
|
||||||
|
|
||||||
|
# 3. Content exists
|
||||||
|
CONTENT_SIZE=$(curl -s http://localhost:3002 | wc -c)
|
||||||
|
[ $CONTENT_SIZE -gt 1000 ] && echo "✅ Content: PASS" || echo "❌ Content: FAIL"
|
||||||
|
|
||||||
|
# 4. All components exist
|
||||||
|
COMPONENTS=$(ls src/components/*.vue 2>/dev/null | wc -l)
|
||||||
|
[ $COMPONENTS -eq 8 ] && echo "✅ Components: PASS" || echo "❌ Components: FAIL"
|
||||||
|
|
||||||
|
# 5. Configs valid
|
||||||
|
[ -f vite.config.js ] && echo "✅ Vite config: PASS" || echo "❌ Vite config: FAIL"
|
||||||
|
[ -f tailwind.config.js ] && echo "✅ Tailwind config: PASS" || echo "❌ Tailwind config: FAIL"
|
||||||
|
```
|
||||||
|
|
||||||
|
**ALL MUST PASS**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📝 PHASE 8: FINAL REPORT
|
||||||
|
|
||||||
|
Create `DEPLOYMENT_READY.md` with:
|
||||||
|
```markdown
|
||||||
|
# OKYSH Website - Autonomous Build Report
|
||||||
|
|
||||||
|
## Build Status: [SUCCESS/FAILED]
|
||||||
|
|
||||||
|
## Iterations Completed: X
|
||||||
|
|
||||||
|
## Phase Results:
|
||||||
|
- Phase 1 (Setup): [✅/❌]
|
||||||
|
- Phase 2 (Build): [✅/❌] - X attempts
|
||||||
|
- Phase 3 (Dev Server): [✅/❌] - X attempts
|
||||||
|
- Phase 4 (Content): [✅/❌]
|
||||||
|
- Phase 5 (Components): [✅/❌]
|
||||||
|
- Phase 6 (Styling): [✅/❌]
|
||||||
|
- Phase 7 (Final Check): [✅/❌]
|
||||||
|
|
||||||
|
## Issues Encountered:
|
||||||
|
1. [Issue 1 and how you fixed it]
|
||||||
|
2. [Issue 2 and how you fixed it]
|
||||||
|
|
||||||
|
## Final Checklist:
|
||||||
|
- [ ] npm run build: SUCCESS
|
||||||
|
- [ ] npm run dev: RUNNING on port 3002
|
||||||
|
- [ ] Homepage size: XXX bytes
|
||||||
|
- [ ] All 8 components exist
|
||||||
|
- [ ] No console errors
|
||||||
|
- [ ] Tailwind working
|
||||||
|
|
||||||
|
## Ready for Deployment: [YES/NO]
|
||||||
|
|
||||||
|
## Access:
|
||||||
|
- Dev Server: http://localhost:3002
|
||||||
|
- Build Output: ./dist/
|
||||||
|
|
||||||
|
## Next Steps:
|
||||||
|
[What human should do next]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 CRITICAL RULES
|
||||||
|
|
||||||
|
1. **NEVER skip a phase** - each builds on the previous
|
||||||
|
2. **ALWAYS check exit codes** - don't assume success
|
||||||
|
3. **READ error messages COMPLETELY** - don't guess
|
||||||
|
4. **LOG after each phase** - maintain build-log.md
|
||||||
|
5. **STOP after max attempts** - don't infinite loop
|
||||||
|
6. **CREATE files for debugging** - save logs, outputs
|
||||||
|
7. **TEST before proceeding** - verify each phase works
|
||||||
|
|
||||||
|
## 🎯 SUCCESS DEFINITION
|
||||||
|
|
||||||
|
You have succeeded when:
|
||||||
|
- ✅ All phases completed
|
||||||
|
- ✅ DEPLOYMENT_READY.md shows all green checkmarks
|
||||||
|
- ✅ Dev server accessible at http://localhost:3002
|
||||||
|
- ✅ Website displays all sections
|
||||||
|
- ✅ No errors in any logs
|
||||||
|
|
||||||
|
## 🚫 FAILURE DEFINITION
|
||||||
|
|
||||||
|
Stop and report if:
|
||||||
|
- ❌ Any phase fails after max attempts
|
||||||
|
- ❌ Build errors can't be resolved
|
||||||
|
- ❌ Dev server won't start after 3 tries
|
||||||
|
- ❌ You're repeating the same fix (stuck in loop)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏁 BEGIN NOW
|
||||||
|
|
||||||
|
Start with Phase 1. Create build-log.md as your first action.
|
||||||
|
Track everything. Test thoroughly. Be autonomous but disciplined.
|
||||||
|
|
||||||
|
Your success is measured by producing a working website, not by speed.
|
||||||
|
|
||||||
|
GO!
|
||||||
Loading…
Reference in New Issue