vibe-forge 0.3.5 โ 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/clear-attention.md +63 -0
- package/.claude/commands/forge.md +23 -8
- package/.claude/commands/need-help.md +77 -0
- package/.claude/commands/worker-loop.md +106 -0
- package/.claude/hooks/worker-loop.sh +141 -0
- package/.claude/scripts/setup-worker-loop.sh +45 -0
- package/.claude/settings.local.json +13 -0
- package/bin/cli.js +49 -0
- package/bin/forge-daemon.sh +122 -7
- package/bin/forge-setup.sh +43 -0
- package/bin/forge-spawn.sh +25 -7
- package/bin/forge.sh +88 -11
- package/bin/lib/agents.sh +20 -0
- package/bin/lib/config.sh +12 -0
- package/bin/lib/constants.sh +27 -0
- package/config/agents.json +18 -9
- package/context/modern-conventions.md +129 -0
- package/docs/TODO.md +121 -10
- package/package.json +1 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Clear an attention signal after helping a worker
|
|
3
|
+
argument-hint: [agent-name | all]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Clear Attention Command
|
|
7
|
+
|
|
8
|
+
Use this command to clear attention signals after you've helped a blocked worker.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
/clear-attention anvil # Clear Anvil's attention signal
|
|
14
|
+
/clear-attention all # Clear all attention signals
|
|
15
|
+
/clear-attention # List current attention signals
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Implementation
|
|
19
|
+
|
|
20
|
+
Based on `$ARGUMENTS`:
|
|
21
|
+
|
|
22
|
+
### If no argument or empty
|
|
23
|
+
|
|
24
|
+
List all current attention signals from `tasks/attention/`:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
๐ Current Attention Signals:
|
|
28
|
+
|
|
29
|
+
1. Anvil (5 min ago): Need clarification on auth implementation
|
|
30
|
+
2. Crucible (2 min ago): Tests failing, unsure of expected behavior
|
|
31
|
+
|
|
32
|
+
Use /clear-attention <agent> to resolve.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### If argument is "all"
|
|
36
|
+
|
|
37
|
+
Remove all files from `tasks/attention/` and confirm:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
โ
Cleared all attention signals (2 resolved)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### If argument is an agent name
|
|
44
|
+
|
|
45
|
+
1. Find and remove files matching that agent in `tasks/attention/`
|
|
46
|
+
2. Confirm removal:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
โ
Cleared attention signal for Anvil
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If no matching signal found:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
No attention signal found for Anvil
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Notes
|
|
59
|
+
|
|
60
|
+
- Attention files are created by workers using `/need-help`
|
|
61
|
+
- The daemon watches this folder and sends notifications
|
|
62
|
+
- Clearing signals is a way to acknowledge you've responded
|
|
63
|
+
- Workers can also clear their own signals when unblocked
|
|
@@ -25,19 +25,34 @@ You are now the **Vibe Forge Planning Hub** - a multi-expert planning team.
|
|
|
25
25
|
|
|
26
26
|
@context/project-context.md
|
|
27
27
|
|
|
28
|
-
####
|
|
28
|
+
#### Modern Tooling Reference (avoid outdated suggestions)
|
|
29
29
|
|
|
30
|
-
@_vibe-forge/context/
|
|
30
|
+
@_vibe-forge/context/modern-conventions.md
|
|
31
|
+
|
|
32
|
+
**Startup:** Display the team assembly welcome:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
๐ฅ VIBE FORGE - Planning Hub
|
|
36
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
37
|
+
|
|
38
|
+
The forge council assembles...
|
|
31
39
|
|
|
32
|
-
|
|
40
|
+
๐ฅ Forge Master - Orchestration & Tasks
|
|
41
|
+
๐๏ธ Architect - Technical Design
|
|
42
|
+
๐ก๏ธ Aegis - Security
|
|
43
|
+
โ๏ธ Ember - DevOps & Infrastructure
|
|
44
|
+
๐จ Pixel - User Experience
|
|
45
|
+
๐ Oracle - Product & Requirements
|
|
46
|
+
๐งช Crucible - Quality & Testing
|
|
33
47
|
|
|
34
|
-
|
|
48
|
+
Ready to plan, review, or coordinate.
|
|
49
|
+
Use /forge status to check current tasks.
|
|
35
50
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
What's on the anvil today?
|
|
52
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
53
|
+
```
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
Do NOT automatically scan task folders - wait for user to ask or use `/forge status`.
|
|
41
56
|
|
|
42
57
|
---
|
|
43
58
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Signal that you need human attention/input
|
|
3
|
+
argument-hint: <brief reason>
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Need Help Command
|
|
7
|
+
|
|
8
|
+
Use this command when you're blocked and need human input. This will:
|
|
9
|
+
|
|
10
|
+
1. Create an attention file in `tasks/attention/`
|
|
11
|
+
2. Ring the terminal bell for immediate notification
|
|
12
|
+
3. Trigger a system toast notification (if daemon is running)
|
|
13
|
+
4. Show in the Planning Hub's status display
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
/need-help Need clarification on auth implementation approach
|
|
19
|
+
/need-help Blocked on API design decision - REST vs GraphQL?
|
|
20
|
+
/need-help Tests failing, need guidance on expected behavior
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Implementation
|
|
24
|
+
|
|
25
|
+
Based on `$ARGUMENTS`:
|
|
26
|
+
|
|
27
|
+
1. Determine your agent identity from your system prompt or context
|
|
28
|
+
2. Create an attention file at `tasks/attention/<agent>-<timestamp>.md`:
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
---
|
|
32
|
+
agent: <your-agent-name>
|
|
33
|
+
created: <ISO timestamp>
|
|
34
|
+
status: pending
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# Attention Needed
|
|
38
|
+
|
|
39
|
+
**Agent:** <icon> <display-name>
|
|
40
|
+
**Time:** <human-readable time>
|
|
41
|
+
|
|
42
|
+
## Issue
|
|
43
|
+
|
|
44
|
+
$ARGUMENTS
|
|
45
|
+
|
|
46
|
+
## Context
|
|
47
|
+
|
|
48
|
+
<Brief context about what you were working on>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
3. Ring the terminal bell:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
printf '\a'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
4. Announce that you've signaled for help and will wait.
|
|
58
|
+
|
|
59
|
+
## Resolving Attention
|
|
60
|
+
|
|
61
|
+
When a human responds (via Hub or directly), they can:
|
|
62
|
+
- Delete the attention file to clear the flag
|
|
63
|
+
- Move it to a resolved folder
|
|
64
|
+
- Or just respond - the worker can delete their own attention file once unblocked
|
|
65
|
+
|
|
66
|
+
## Example Output
|
|
67
|
+
|
|
68
|
+
After running `/need-help Need decision on caching strategy`:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
๐ Attention signal sent!
|
|
72
|
+
|
|
73
|
+
I've created tasks/attention/anvil-20240115-143022.md
|
|
74
|
+
The Planning Hub and daemon have been notified.
|
|
75
|
+
|
|
76
|
+
I'll wait for guidance. You can respond here or via the Hub.
|
|
77
|
+
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Start a persistent worker loop (Ralph-style)
|
|
3
|
+
argument-hint: <agent> [--max-idle 10] | stop
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Worker Loop Command
|
|
7
|
+
|
|
8
|
+
Start a persistent worker loop for the specified agent. The worker will:
|
|
9
|
+
1. Check for assigned tasks
|
|
10
|
+
2. Work on tasks until complete
|
|
11
|
+
3. Loop back and check for more tasks
|
|
12
|
+
4. Only exit after N idle checks with no work found
|
|
13
|
+
|
|
14
|
+
## Activation Modes
|
|
15
|
+
|
|
16
|
+
Worker Loop can be activated in two ways:
|
|
17
|
+
|
|
18
|
+
### 1. Config-based (Recommended)
|
|
19
|
+
|
|
20
|
+
Enable during `forge init` or toggle anytime:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
forge config worker-loop on # Enable for all workers
|
|
24
|
+
forge config worker-loop off # Disable
|
|
25
|
+
forge config worker-loop # Check status
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When enabled, ALL workers will automatically stay running and check for new tasks.
|
|
29
|
+
|
|
30
|
+
### 2. Runtime (Per-session)
|
|
31
|
+
|
|
32
|
+
Use this command for fine-grained control:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
/worker-loop anvil # Start Anvil in persistent loop
|
|
36
|
+
/worker-loop furnace --max-idle 20 # Custom idle limit
|
|
37
|
+
/worker-loop stop # Stop the current loop
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Arguments
|
|
41
|
+
|
|
42
|
+
- `$1` - Agent name (anvil, furnace, crucible, etc.) or "stop"
|
|
43
|
+
- `--max-idle N` - Exit after N checks with no tasks (default: 10)
|
|
44
|
+
|
|
45
|
+
## Implementation
|
|
46
|
+
|
|
47
|
+
Based on `$ARGUMENTS`:
|
|
48
|
+
|
|
49
|
+
### If first argument is "stop"
|
|
50
|
+
|
|
51
|
+
Remove the worker loop state file and confirm:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
rm -f "${CLAUDE_LOCAL_DIR:-$HOME/.claude}/forge-worker-loop.json"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Output: "Worker loop stopped."
|
|
58
|
+
|
|
59
|
+
### Otherwise, start a loop
|
|
60
|
+
|
|
61
|
+
1. Resolve the agent name to canonical form
|
|
62
|
+
2. Create state file at `${CLAUDE_LOCAL_DIR}/forge-worker-loop.json`:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"agent": "<resolved-agent>",
|
|
67
|
+
"max_idle_checks": 10,
|
|
68
|
+
"idle_count": 0,
|
|
69
|
+
"poll_interval": 5,
|
|
70
|
+
"started_at": "<ISO timestamp>"
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
3. Load the agent's personality file
|
|
75
|
+
4. Start working with this system prompt addition:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
You are in PERSISTENT WORKER MODE. After completing each task:
|
|
79
|
+
1. Check for more tasks assigned to you in tasks/pending/ and tasks/needs-changes/
|
|
80
|
+
2. If tasks found, immediately begin working
|
|
81
|
+
3. If no tasks, announce you are idle and waiting
|
|
82
|
+
|
|
83
|
+
Do NOT ask permission to continue - work autonomously until no tasks remain.
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
5. The stop hook (hooks/worker-loop.sh) will intercept exit attempts and:
|
|
87
|
+
- If tasks exist: feed prompt to continue working
|
|
88
|
+
- If no tasks: increment idle counter
|
|
89
|
+
- If max idle reached: allow exit
|
|
90
|
+
|
|
91
|
+
## How It Works
|
|
92
|
+
|
|
93
|
+
The Worker Loop uses Claude Code's **Stop Hook** feature:
|
|
94
|
+
|
|
95
|
+
1. When a worker tries to exit, the hook script runs
|
|
96
|
+
2. It checks for pending tasks in `tasks/pending/` and `tasks/needs-changes/`
|
|
97
|
+
3. If tasks found: blocks exit and feeds a prompt to continue working
|
|
98
|
+
4. If no tasks: allows exit (or waits, depending on config)
|
|
99
|
+
|
|
100
|
+
## Benefits
|
|
101
|
+
|
|
102
|
+
- Workers stay active and pick up new tasks automatically
|
|
103
|
+
- No need to manually respawn workers
|
|
104
|
+
- Tasks can be added to pending/ and workers will find them
|
|
105
|
+
- Config-based mode requires zero per-session setup
|
|
106
|
+
- Configurable idle timeout prevents infinite waiting
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Vibe Forge Worker Loop - Stop Hook
|
|
4
|
+
#
|
|
5
|
+
# Implements the Ralph Loop technique for Vibe Forge workers.
|
|
6
|
+
# When a worker tries to exit, this hook checks if there are pending tasks
|
|
7
|
+
# and feeds the worker prompt back to continue working.
|
|
8
|
+
#
|
|
9
|
+
# Based on the Ralph Loop plugin by Anthropic.
|
|
10
|
+
#
|
|
11
|
+
# Activation modes:
|
|
12
|
+
# 1. Config-based: worker_loop_enabled=true in .forge/config.json
|
|
13
|
+
# 2. Runtime: State file created by /worker-loop command
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
# State file location (runtime toggle)
|
|
19
|
+
STATE_FILE="${CLAUDE_LOCAL_DIR:-$HOME/.claude}/forge-worker-loop.json"
|
|
20
|
+
FORGE_ROOT="${FORGE_ROOT:-$(pwd)}"
|
|
21
|
+
|
|
22
|
+
# Check for runtime state file first (takes precedence)
|
|
23
|
+
LOOP_ACTIVE=false
|
|
24
|
+
WORKER_AGENT=""
|
|
25
|
+
MAX_IDLE_CHECKS=10
|
|
26
|
+
IDLE_COUNT=0
|
|
27
|
+
POLL_INTERVAL=5
|
|
28
|
+
|
|
29
|
+
if [[ -f "$STATE_FILE" ]]; then
|
|
30
|
+
LOOP_ACTIVE=true
|
|
31
|
+
WORKER_AGENT=$(jq -r '.agent // ""' "$STATE_FILE" 2>/dev/null || echo "")
|
|
32
|
+
MAX_IDLE_CHECKS=$(jq -r '.max_idle_checks // 10' "$STATE_FILE" 2>/dev/null || echo "10")
|
|
33
|
+
IDLE_COUNT=$(jq -r '.idle_count // 0' "$STATE_FILE" 2>/dev/null || echo "0")
|
|
34
|
+
POLL_INTERVAL=$(jq -r '.poll_interval // 5' "$STATE_FILE" 2>/dev/null || echo "5")
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# If no runtime state, check config-based setting
|
|
38
|
+
if [[ "$LOOP_ACTIVE" == "false" ]]; then
|
|
39
|
+
CONFIG_FILE="$FORGE_ROOT/.forge/config.json"
|
|
40
|
+
if [[ -f "$CONFIG_FILE" ]]; then
|
|
41
|
+
CONFIG_ENABLED=$(jq -r '.worker_loop_enabled // false' "$CONFIG_FILE" 2>/dev/null || echo "false")
|
|
42
|
+
if [[ "$CONFIG_ENABLED" == "true" ]]; then
|
|
43
|
+
LOOP_ACTIVE=true
|
|
44
|
+
# For config-based, use "any" to match any worker
|
|
45
|
+
WORKER_AGENT="any"
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Check if worker loop is active
|
|
51
|
+
if [[ "$LOOP_ACTIVE" == "false" ]]; then
|
|
52
|
+
# No active loop, allow exit
|
|
53
|
+
echo '{"decision": "allow"}'
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if [[ -z "$WORKER_AGENT" ]]; then
|
|
58
|
+
# Invalid state, clean up and allow exit
|
|
59
|
+
rm -f "$STATE_FILE" 2>/dev/null || true
|
|
60
|
+
echo '{"decision": "allow"}'
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Check for pending tasks (assigned to specific worker or any worker)
|
|
65
|
+
TASKS_DIR="$FORGE_ROOT/tasks"
|
|
66
|
+
PENDING_COUNT=0
|
|
67
|
+
NEEDS_CHANGES_COUNT=0
|
|
68
|
+
|
|
69
|
+
if [[ -d "$TASKS_DIR/pending" ]]; then
|
|
70
|
+
if [[ "$WORKER_AGENT" == "any" ]]; then
|
|
71
|
+
# Config mode: count all pending tasks
|
|
72
|
+
PENDING_COUNT=$(find "$TASKS_DIR/pending" -name "*.md" 2>/dev/null | wc -l || echo "0")
|
|
73
|
+
else
|
|
74
|
+
# Runtime mode: count only tasks assigned to specific worker
|
|
75
|
+
PENDING_COUNT=$(grep -l "assigned_to:.*$WORKER_AGENT" "$TASKS_DIR/pending/"*.md 2>/dev/null | wc -l || echo "0")
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if [[ -d "$TASKS_DIR/needs-changes" ]]; then
|
|
80
|
+
if [[ "$WORKER_AGENT" == "any" ]]; then
|
|
81
|
+
# Config mode: count all needs-changes tasks
|
|
82
|
+
NEEDS_CHANGES_COUNT=$(find "$TASKS_DIR/needs-changes" -name "*.md" 2>/dev/null | wc -l || echo "0")
|
|
83
|
+
else
|
|
84
|
+
# Runtime mode: count only tasks assigned to specific worker
|
|
85
|
+
NEEDS_CHANGES_COUNT=$(grep -l "assigned_to:.*$WORKER_AGENT" "$TASKS_DIR/needs-changes/"*.md 2>/dev/null | wc -l || echo "0")
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
TOTAL_TASKS=$((PENDING_COUNT + NEEDS_CHANGES_COUNT))
|
|
90
|
+
|
|
91
|
+
if [[ "$TOTAL_TASKS" -gt 0 ]]; then
|
|
92
|
+
# Tasks found! Reset idle counter and continue
|
|
93
|
+
if [[ -f "$STATE_FILE" ]]; then
|
|
94
|
+
jq --argjson idle 0 '.idle_count = $idle' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Block exit and feed prompt to continue working
|
|
98
|
+
cat << EOF
|
|
99
|
+
{
|
|
100
|
+
"decision": "block",
|
|
101
|
+
"message": "[Forge Loop] Found $TOTAL_TASKS pending task(s). Continuing work...",
|
|
102
|
+
"prompt": "Check tasks/pending/ and tasks/needs-changes/ for tasks assigned to you and begin working on them immediately."
|
|
103
|
+
}
|
|
104
|
+
EOF
|
|
105
|
+
exit 0
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# No tasks - increment idle counter (only for runtime mode with state file)
|
|
109
|
+
if [[ -f "$STATE_FILE" ]]; then
|
|
110
|
+
IDLE_COUNT=$((IDLE_COUNT + 1))
|
|
111
|
+
jq --argjson idle "$IDLE_COUNT" '.idle_count = $idle' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
112
|
+
|
|
113
|
+
if [[ "$IDLE_COUNT" -ge "$MAX_IDLE_CHECKS" ]]; then
|
|
114
|
+
# Max idle checks reached, clean up and allow exit
|
|
115
|
+
rm -f "$STATE_FILE"
|
|
116
|
+
cat << EOF
|
|
117
|
+
{
|
|
118
|
+
"decision": "allow",
|
|
119
|
+
"message": "[Forge Loop] No tasks found after $MAX_IDLE_CHECKS checks. Exiting."
|
|
120
|
+
}
|
|
121
|
+
EOF
|
|
122
|
+
exit 0
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Still within idle limit - wait and check again
|
|
126
|
+
cat << EOF
|
|
127
|
+
{
|
|
128
|
+
"decision": "block",
|
|
129
|
+
"message": "[Forge Loop] No tasks available. Idle check $IDLE_COUNT/$MAX_IDLE_CHECKS. Waiting...",
|
|
130
|
+
"prompt": "No tasks currently assigned to you. Wait briefly, then check tasks/pending/ and tasks/needs-changes/ again for new work. If still no tasks, announce you are idle and ready."
|
|
131
|
+
}
|
|
132
|
+
EOF
|
|
133
|
+
else
|
|
134
|
+
# Config-based mode - no idle tracking, just allow exit when no tasks
|
|
135
|
+
cat << EOF
|
|
136
|
+
{
|
|
137
|
+
"decision": "allow",
|
|
138
|
+
"message": "[Forge Loop] No pending tasks. Worker exiting."
|
|
139
|
+
}
|
|
140
|
+
EOF
|
|
141
|
+
fi
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Setup Worker Loop
|
|
4
|
+
# Creates state file to enable the worker loop stop hook
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
AGENT="${1:-}"
|
|
10
|
+
MAX_IDLE="${2:-10}"
|
|
11
|
+
STATE_DIR="${CLAUDE_LOCAL_DIR:-$HOME/.claude}"
|
|
12
|
+
STATE_FILE="$STATE_DIR/forge-worker-loop.json"
|
|
13
|
+
|
|
14
|
+
if [[ "$AGENT" == "stop" ]]; then
|
|
15
|
+
if [[ -f "$STATE_FILE" ]]; then
|
|
16
|
+
rm -f "$STATE_FILE"
|
|
17
|
+
echo "Worker loop stopped."
|
|
18
|
+
else
|
|
19
|
+
echo "No active worker loop."
|
|
20
|
+
fi
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if [[ -z "$AGENT" ]]; then
|
|
25
|
+
echo "Usage: setup-worker-loop.sh <agent> [max-idle-checks]"
|
|
26
|
+
echo " setup-worker-loop.sh stop"
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Ensure state directory exists
|
|
31
|
+
mkdir -p "$STATE_DIR"
|
|
32
|
+
|
|
33
|
+
# Create state file
|
|
34
|
+
cat > "$STATE_FILE" << EOF
|
|
35
|
+
{
|
|
36
|
+
"agent": "$AGENT",
|
|
37
|
+
"max_idle_checks": $MAX_IDLE,
|
|
38
|
+
"idle_count": 0,
|
|
39
|
+
"poll_interval": 5,
|
|
40
|
+
"started_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
41
|
+
}
|
|
42
|
+
EOF
|
|
43
|
+
|
|
44
|
+
echo "Worker loop started for $AGENT (max idle: $MAX_IDLE checks)"
|
|
45
|
+
echo "State file: $STATE_FILE"
|
package/bin/cli.js
CHANGED
|
@@ -21,6 +21,8 @@ const REPO_URL = 'https://github.com/SpasticPalate/vibe-forge.git';
|
|
|
21
21
|
const FORGE_DIR = '_vibe-forge';
|
|
22
22
|
|
|
23
23
|
// Colors for terminal output
|
|
24
|
+
// NOTE: Intentionally self-contained - cli.js runs standalone via npx before
|
|
25
|
+
// the rest of Vibe Forge is installed, so it cannot share with colors.sh
|
|
24
26
|
const colors = {
|
|
25
27
|
reset: '\x1b[0m',
|
|
26
28
|
red: '\x1b[31m',
|
|
@@ -199,6 +201,9 @@ async function initCommand() {
|
|
|
199
201
|
|
|
200
202
|
log('');
|
|
201
203
|
|
|
204
|
+
// Update project's .gitignore to ignore tool internals but keep project data
|
|
205
|
+
updateGitignore();
|
|
206
|
+
|
|
202
207
|
// Run the setup script
|
|
203
208
|
logInfo('Running setup...');
|
|
204
209
|
log('');
|
|
@@ -212,6 +217,50 @@ async function initCommand() {
|
|
|
212
217
|
}
|
|
213
218
|
}
|
|
214
219
|
|
|
220
|
+
function updateGitignore() {
|
|
221
|
+
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
222
|
+
const forgeIgnoreMarker = '# Vibe Forge';
|
|
223
|
+
const forgeIgnoreBlock = `
|
|
224
|
+
# Vibe Forge
|
|
225
|
+
# Tool internals (regenerated on update)
|
|
226
|
+
_vibe-forge/.git/
|
|
227
|
+
_vibe-forge/bin/
|
|
228
|
+
_vibe-forge/agents/
|
|
229
|
+
_vibe-forge/config/
|
|
230
|
+
_vibe-forge/docs/
|
|
231
|
+
_vibe-forge/tests/
|
|
232
|
+
_vibe-forge/src/
|
|
233
|
+
_vibe-forge/node_modules/
|
|
234
|
+
_vibe-forge/package*.json
|
|
235
|
+
_vibe-forge/*.md
|
|
236
|
+
_vibe-forge/LICENSE
|
|
237
|
+
_vibe-forge/.github/
|
|
238
|
+
|
|
239
|
+
# Keep project data (tasks, context) - these ARE committed
|
|
240
|
+
# !_vibe-forge/tasks/
|
|
241
|
+
# !_vibe-forge/context/
|
|
242
|
+
# !_vibe-forge/.claude/
|
|
243
|
+
`;
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
let content = '';
|
|
247
|
+
if (fs.existsSync(gitignorePath)) {
|
|
248
|
+
content = fs.readFileSync(gitignorePath, 'utf8');
|
|
249
|
+
// Check if already has forge entries
|
|
250
|
+
if (content.includes(forgeIgnoreMarker)) {
|
|
251
|
+
return; // Already configured
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Append forge ignore block
|
|
256
|
+
const newContent = content.trimEnd() + '\n' + forgeIgnoreBlock;
|
|
257
|
+
fs.writeFileSync(gitignorePath, newContent);
|
|
258
|
+
logSuccess('Updated .gitignore for Vibe Forge');
|
|
259
|
+
} catch (err) {
|
|
260
|
+
logError(`Warning: Could not update .gitignore: ${err.message}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
215
264
|
async function updateCommand() {
|
|
216
265
|
showBanner();
|
|
217
266
|
|