vibe-forge 0.4.0 → 0.8.1
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 -63
- package/.claude/commands/compact-context.md +52 -0
- package/.claude/commands/configure-vcs.md +102 -102
- package/.claude/commands/forge.md +218 -171
- package/.claude/commands/need-help.md +77 -77
- package/.claude/commands/update-status.md +64 -64
- package/.claude/commands/worker-loop.md +106 -106
- package/.claude/hooks/worker-loop.js +217 -187
- package/.claude/scripts/setup-worker-loop.sh +45 -45
- package/.claude/settings.json +89 -0
- package/LICENSE +21 -21
- package/README.md +253 -232
- package/agents/aegis/personality.md +303 -269
- package/agents/anvil/personality.md +278 -240
- package/agents/architect/personality.md +260 -234
- package/agents/crucible/personality.md +362 -309
- package/agents/crucible-x/personality.md +210 -0
- package/agents/ember/personality.md +293 -265
- package/agents/flux/personality.md +248 -0
- package/agents/furnace/personality.md +342 -291
- package/agents/herald/personality.md +249 -247
- package/agents/loki/personality.md +108 -0
- package/agents/oracle/personality.md +284 -0
- package/agents/pixel/personality.md +140 -0
- package/agents/planning-hub/personality.md +473 -251
- package/agents/scribe/personality.md +253 -251
- package/agents/slag/personality.md +268 -0
- package/agents/temper/personality.md +270 -0
- package/bin/cli.js +372 -325
- package/bin/dashboard/api/agents.js +333 -0
- package/bin/dashboard/api/dispatch.js +507 -0
- package/bin/dashboard/api/tasks.js +416 -0
- package/bin/dashboard/public/assets/index-BpHfsx1r.js +2 -0
- package/bin/dashboard/public/assets/index-QODv4Zn9.css +1 -0
- package/bin/dashboard/public/index.html +14 -0
- package/bin/dashboard/server.js +645 -0
- package/bin/forge-daemon.sh +477 -851
- package/bin/forge-setup.sh +661 -645
- package/bin/forge-spawn.sh +164 -164
- package/bin/forge.cmd +83 -83
- package/bin/forge.sh +566 -387
- package/bin/lib/agents.sh +177 -177
- package/bin/lib/check-aliases.js +50 -0
- package/bin/lib/colors.sh +44 -44
- package/bin/lib/config.sh +347 -313
- package/bin/lib/constants.sh +241 -206
- package/bin/lib/daemon/budgets.sh +107 -0
- package/bin/lib/daemon/dependencies.sh +146 -0
- package/bin/lib/daemon/display.sh +128 -0
- package/bin/lib/daemon/notifications.sh +273 -0
- package/bin/lib/daemon/routing.sh +93 -0
- package/bin/lib/daemon/state.sh +163 -0
- package/bin/lib/daemon/sync.sh +103 -0
- package/bin/lib/database.sh +357 -305
- package/bin/lib/frontmatter.js +106 -0
- package/bin/lib/heimdall-setup.js +113 -0
- package/bin/lib/heimdall.js +265 -0
- package/bin/lib/json.sh +264 -258
- package/bin/lib/terminal.js +452 -446
- package/bin/lib/util.sh +126 -126
- package/bin/lib/vcs.js +349 -349
- package/config/agent-manifest.yaml +237 -243
- package/config/agents.json +207 -132
- package/config/task-template.md +159 -87
- package/config/task-types.yaml +111 -106
- package/config/templates/handoff-template.md +40 -0
- package/context/agent-overrides/README.md +41 -0
- package/context/architecture.md +42 -0
- package/context/modern-conventions.md +129 -129
- package/context/project-context-template.md +122 -122
- package/docs/agents.md +473 -409
- package/docs/architecture.md +194 -162
- package/docs/commands.md +451 -388
- package/docs/security.md +195 -144
- package/package.json +77 -50
- package/.claude/settings.local.json +0 -33
- package/agents/forge-master/capabilities.md +0 -144
- package/agents/forge-master/context-template.md +0 -128
- package/agents/forge-master/personality.md +0 -138
- package/agents/sentinel/personality.md +0 -194
- package/context/forge-state.yaml +0 -19
- package/docs/TODO.md +0 -150
- package/docs/getting-started.md +0 -243
- package/docs/npm-publishing.md +0 -95
- package/docs/workflows/README.md +0 -32
- package/docs/workflows/azure-devops.md +0 -108
- package/docs/workflows/bitbucket.md +0 -104
- package/docs/workflows/git-only.md +0 -130
- package/docs/workflows/gitea.md +0 -168
- package/docs/workflows/github.md +0 -103
- package/docs/workflows/gitlab.md +0 -105
- package/docs/workflows.md +0 -454
- package/tasks/completed/ARCH-001-duplicate-agent-config.md +0 -121
- package/tasks/completed/ARCH-002-mixed-bash-node-implementation.md +0 -88
- package/tasks/completed/ARCH-003-worker-loop-hook-duplication.md +0 -77
- package/tasks/completed/ARCH-009-test-organization.md +0 -78
- package/tasks/completed/ARCH-011-jq-vs-nodejs-json.md +0 -94
- package/tasks/completed/ARCH-012-tmp-files-in-root.md +0 -71
- package/tasks/completed/ARCH-013-exit-code-constants.md +0 -65
- package/tasks/completed/ARCH-014-sed-incompatibility.md +0 -96
- package/tasks/completed/ARCH-015-docs-todo-tracking.md +0 -83
- package/tasks/completed/CLEAN-001.md +0 -38
- package/tasks/completed/CLEAN-003.md +0 -47
- package/tasks/completed/CLEAN-004.md +0 -56
- package/tasks/completed/CLEAN-005.md +0 -75
- package/tasks/completed/CLEAN-006.md +0 -47
- package/tasks/completed/CLEAN-007.md +0 -34
- package/tasks/completed/CLEAN-008.md +0 -49
- package/tasks/completed/CLEAN-012.md +0 -58
- package/tasks/completed/CLEAN-013.md +0 -45
- package/tasks/completed/SEC-001-sql-injection-fix.md +0 -58
- package/tasks/completed/SEC-002-notification-injection-fix.md +0 -45
- package/tasks/completed/SEC-003-eval-injection-fix.md +0 -54
- package/tasks/completed/SEC-004-pid-race-condition-fix.md +0 -49
- package/tasks/completed/SEC-005-worker-loop-path-fix.md +0 -51
- package/tasks/completed/SEC-006-eval-agent-names.md +0 -55
- package/tasks/completed/SEC-007-spawn-escaping.md +0 -67
- package/tasks/pending/ARCH-004-git-bash-detection-duplication.md +0 -72
- package/tasks/pending/ARCH-005-missing-src-directory.md +0 -95
- package/tasks/pending/ARCH-006-task-template-location.md +0 -64
- package/tasks/pending/ARCH-007-daemon-monolith.md +0 -91
- package/tasks/pending/ARCH-008-forge-master-vs-hub.md +0 -81
- package/tasks/pending/ARCH-010-missing-index-files.md +0 -84
- package/tasks/pending/CLEAN-002.md +0 -29
- package/tasks/pending/CLEAN-009.md +0 -31
- package/tasks/pending/CLEAN-010.md +0 -30
- package/tasks/pending/CLEAN-011.md +0 -30
- package/tasks/pending/CLEAN-014.md +0 -32
- package/tasks/review/task-001.md +0 -78
package/bin/forge.sh
CHANGED
|
@@ -1,387 +1,566 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Vibe Forge - Main Launcher
|
|
4
|
-
# Starts the Planning Hub or specific worker agents
|
|
5
|
-
#
|
|
6
|
-
# Usage:
|
|
7
|
-
# forge - Start Planning Hub (main session)
|
|
8
|
-
# forge init - Initialize Vibe Forge
|
|
9
|
-
# forge start <agent> - Start a specific worker agent
|
|
10
|
-
# forge spawn <agent> - Spawn agent in new terminal window/tab
|
|
11
|
-
# forge status - Show forge status
|
|
12
|
-
# forge
|
|
13
|
-
# forge daemon - Start/stop the background daemon
|
|
14
|
-
# forge help - Show help
|
|
15
|
-
#
|
|
16
|
-
# Security Note:
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# See docs/security.md for
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
set -e
|
|
23
|
-
|
|
24
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
-
FORGE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
26
|
-
CONFIG_FILE="$FORGE_ROOT/.forge/config.json"
|
|
27
|
-
|
|
28
|
-
# =============================================================================
|
|
29
|
-
# Load Shared Libraries
|
|
30
|
-
# =============================================================================
|
|
31
|
-
|
|
32
|
-
# shellcheck source=lib/colors.sh
|
|
33
|
-
source "$SCRIPT_DIR/lib/colors.sh"
|
|
34
|
-
# shellcheck source=lib/constants.sh
|
|
35
|
-
source "$SCRIPT_DIR/lib/constants.sh"
|
|
36
|
-
# shellcheck source=lib/config.sh
|
|
37
|
-
source "$SCRIPT_DIR/lib/config.sh"
|
|
38
|
-
# shellcheck source=lib/json.sh
|
|
39
|
-
source "$SCRIPT_DIR/lib/json.sh"
|
|
40
|
-
# shellcheck source=lib/agents.sh
|
|
41
|
-
source "$SCRIPT_DIR/lib/agents.sh"
|
|
42
|
-
|
|
43
|
-
# Load agent configuration from JSON if available
|
|
44
|
-
# This overwrites the fallback values in constants.sh
|
|
45
|
-
if [[ -f "$FORGE_ROOT/$AGENTS_CONFIG" ]]; then
|
|
46
|
-
if ! load_agents_from_json "$FORGE_ROOT/$AGENTS_CONFIG" 2>/dev/null; then
|
|
47
|
-
log_warn "Failed to load agents.json, using fallback defaults"
|
|
48
|
-
fi
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
# =============================================================================
|
|
52
|
-
# Commands
|
|
53
|
-
# =============================================================================
|
|
54
|
-
|
|
55
|
-
cmd_init() {
|
|
56
|
-
"$SCRIPT_DIR/forge-setup.sh" "$@"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
cmd_start() {
|
|
60
|
-
local agent="${1:-hub}"
|
|
61
|
-
|
|
62
|
-
# Load and validate config
|
|
63
|
-
require_forge_config "$FORGE_ROOT"
|
|
64
|
-
|
|
65
|
-
# Validate and resolve agent name (SECURITY: whitelist validation)
|
|
66
|
-
local resolved
|
|
67
|
-
resolved=$(resolve_agent "$agent") || {
|
|
68
|
-
log_error "Unknown agent: $agent"
|
|
69
|
-
echo ""
|
|
70
|
-
show_available_agents
|
|
71
|
-
exit $EXIT_INVALID_ARGUMENT
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# Get personality path (SECURITY: path traversal protection)
|
|
75
|
-
local personality_path
|
|
76
|
-
personality_path=$(get_agent_personality_path "$FORGE_ROOT" "$resolved") || {
|
|
77
|
-
log_error "Personality file not found for agent: $resolved"
|
|
78
|
-
exit $EXIT_CONFIG_ERROR
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# Get display name
|
|
82
|
-
local agent_name
|
|
83
|
-
agent_name=$(get_agent_display_name "$resolved")
|
|
84
|
-
|
|
85
|
-
log_header "🔥 Starting $agent_name..."
|
|
86
|
-
echo ""
|
|
87
|
-
|
|
88
|
-
# Build the system prompt from personality file
|
|
89
|
-
local system_prompt
|
|
90
|
-
system_prompt=$(cat "$personality_path")
|
|
91
|
-
|
|
92
|
-
# Add project context if it exists
|
|
93
|
-
local project_context="$FORGE_ROOT/$CONTEXT_DIR/project-context.md"
|
|
94
|
-
if [[ -f "$project_context" ]]; then
|
|
95
|
-
system_prompt="$system_prompt
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
# Project Context
|
|
100
|
-
|
|
101
|
-
$(cat "$project_context")"
|
|
102
|
-
fi
|
|
103
|
-
|
|
104
|
-
# Add
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
system_prompt="$system_prompt
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
#
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
echo "
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
echo "
|
|
190
|
-
fi
|
|
191
|
-
|
|
192
|
-
echo ""
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
echo "
|
|
317
|
-
echo "
|
|
318
|
-
echo "
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
echo "
|
|
334
|
-
echo "
|
|
335
|
-
echo ""
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
"
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
"
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
"
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Vibe Forge - Main Launcher
|
|
4
|
+
# Starts the Planning Hub or specific worker agents
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# forge - Start Planning Hub (main session)
|
|
8
|
+
# forge init - Initialize Vibe Forge
|
|
9
|
+
# forge start <agent> - Start a specific worker agent
|
|
10
|
+
# forge spawn <agent> - Spawn agent in new terminal window/tab
|
|
11
|
+
# forge status - Show forge status
|
|
12
|
+
# forge doctor - Full environment diagnostics (alias: test)
|
|
13
|
+
# forge daemon - Start/stop the background daemon
|
|
14
|
+
# forge help - Show help
|
|
15
|
+
#
|
|
16
|
+
# Security Note:
|
|
17
|
+
# Agents use allowlist-based permissions (.claude/settings.json) plus
|
|
18
|
+
# Heimdall pre-tool hooks instead of --dangerously-skip-permissions.
|
|
19
|
+
# See docs/security.md for the trust model.
|
|
20
|
+
#
|
|
21
|
+
|
|
22
|
+
set -e
|
|
23
|
+
|
|
24
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
+
FORGE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
26
|
+
CONFIG_FILE="$FORGE_ROOT/.forge/config.json"
|
|
27
|
+
|
|
28
|
+
# =============================================================================
|
|
29
|
+
# Load Shared Libraries
|
|
30
|
+
# =============================================================================
|
|
31
|
+
|
|
32
|
+
# shellcheck source=lib/colors.sh
|
|
33
|
+
source "$SCRIPT_DIR/lib/colors.sh"
|
|
34
|
+
# shellcheck source=lib/constants.sh
|
|
35
|
+
source "$SCRIPT_DIR/lib/constants.sh"
|
|
36
|
+
# shellcheck source=lib/config.sh
|
|
37
|
+
source "$SCRIPT_DIR/lib/config.sh"
|
|
38
|
+
# shellcheck source=lib/json.sh
|
|
39
|
+
source "$SCRIPT_DIR/lib/json.sh"
|
|
40
|
+
# shellcheck source=lib/agents.sh
|
|
41
|
+
source "$SCRIPT_DIR/lib/agents.sh"
|
|
42
|
+
|
|
43
|
+
# Load agent configuration from JSON if available
|
|
44
|
+
# This overwrites the fallback values in constants.sh
|
|
45
|
+
if [[ -f "$FORGE_ROOT/$AGENTS_CONFIG" ]]; then
|
|
46
|
+
if ! load_agents_from_json "$FORGE_ROOT/$AGENTS_CONFIG" 2>/dev/null; then
|
|
47
|
+
log_warn "Failed to load agents.json, using fallback defaults"
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# =============================================================================
|
|
52
|
+
# Commands
|
|
53
|
+
# =============================================================================
|
|
54
|
+
|
|
55
|
+
cmd_init() {
|
|
56
|
+
"$SCRIPT_DIR/forge-setup.sh" "$@"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
cmd_start() {
|
|
60
|
+
local agent="${1:-hub}"
|
|
61
|
+
|
|
62
|
+
# Load and validate config
|
|
63
|
+
require_forge_config "$FORGE_ROOT"
|
|
64
|
+
|
|
65
|
+
# Validate and resolve agent name (SECURITY: whitelist validation)
|
|
66
|
+
local resolved
|
|
67
|
+
resolved=$(resolve_agent "$agent") || {
|
|
68
|
+
log_error "Unknown agent: $agent"
|
|
69
|
+
echo ""
|
|
70
|
+
show_available_agents
|
|
71
|
+
exit $EXIT_INVALID_ARGUMENT
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Get personality path (SECURITY: path traversal protection)
|
|
75
|
+
local personality_path
|
|
76
|
+
personality_path=$(get_agent_personality_path "$FORGE_ROOT" "$resolved") || {
|
|
77
|
+
log_error "Personality file not found for agent: $resolved"
|
|
78
|
+
exit $EXIT_CONFIG_ERROR
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Get display name
|
|
82
|
+
local agent_name
|
|
83
|
+
agent_name=$(get_agent_display_name "$resolved")
|
|
84
|
+
|
|
85
|
+
log_header "🔥 Starting $agent_name..."
|
|
86
|
+
echo ""
|
|
87
|
+
|
|
88
|
+
# Build the system prompt from personality file
|
|
89
|
+
local system_prompt
|
|
90
|
+
system_prompt=$(cat "$personality_path")
|
|
91
|
+
|
|
92
|
+
# Add project context if it exists
|
|
93
|
+
local project_context="$FORGE_ROOT/$CONTEXT_DIR/project-context.md"
|
|
94
|
+
if [[ -f "$project_context" ]]; then
|
|
95
|
+
system_prompt="$system_prompt
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
# Project Context
|
|
100
|
+
|
|
101
|
+
$(cat "$project_context")"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Add per-project agent overrides if they exist (T2-E3)
|
|
105
|
+
local agent_override="$FORGE_ROOT/$CONTEXT_DIR/agent-overrides/${resolved}.md"
|
|
106
|
+
if [[ -f "$agent_override" ]]; then
|
|
107
|
+
system_prompt="$system_prompt
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
# Project-Specific Rules for $agent_name
|
|
112
|
+
|
|
113
|
+
$(cat "$agent_override")"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Check for handoff files from previous sessions (T2-F2)
|
|
117
|
+
local handoff_dir="$FORGE_ROOT/tasks/handoffs"
|
|
118
|
+
if [[ -d "$handoff_dir" ]]; then
|
|
119
|
+
for handoff in "$handoff_dir"/*-"${resolved}"-*.md "$handoff_dir"/*-handoff.md; do
|
|
120
|
+
if [[ -f "$handoff" ]]; then
|
|
121
|
+
local handoff_agent
|
|
122
|
+
handoff_agent=$(node "$SCRIPT_DIR/lib/frontmatter.js" "$handoff" "agent" 2>/dev/null | sed -n 's/^agent=//p')
|
|
123
|
+
if [[ "$handoff_agent" == "$resolved" ]]; then
|
|
124
|
+
system_prompt="$system_prompt
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
# Session Handoff (from previous session)
|
|
129
|
+
|
|
130
|
+
$(cat "$handoff")"
|
|
131
|
+
break
|
|
132
|
+
fi
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# Add startup instructions based on agent type
|
|
138
|
+
if [[ "$resolved" == "hub" ]]; then
|
|
139
|
+
# Planning Hub startup - Party Mode Team
|
|
140
|
+
system_prompt="$system_prompt
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
# Startup Instructions
|
|
145
|
+
|
|
146
|
+
On startup, you MUST immediately display the team assembly welcome as shown in the Startup Behavior section of your personality. Show the forge council members assembling with their icons and roles. Then check for any current work status.
|
|
147
|
+
"
|
|
148
|
+
else
|
|
149
|
+
# Worker agent startup
|
|
150
|
+
system_prompt="$system_prompt
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
# Startup Instructions
|
|
155
|
+
|
|
156
|
+
On startup:
|
|
157
|
+
1. Announce yourself briefly (icon, name, role)
|
|
158
|
+
2. Check tasks/pending/ and tasks/needs-changes/ for tasks assigned to you
|
|
159
|
+
3. If you find assigned tasks, IMMEDIATELY begin working on them (no confirmation needed)
|
|
160
|
+
4. If no tasks found, announce you're idle and ready for work
|
|
161
|
+
|
|
162
|
+
You are autonomous - when assigned work exists, start it without asking permission.
|
|
163
|
+
"
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
# Launch Claude Code with the personality
|
|
167
|
+
# Agents use project-level .claude/settings.json for permissions (allowlist + Heimdall hooks)
|
|
168
|
+
# instead of --dangerously-skip-permissions. See docs/security.md.
|
|
169
|
+
if [[ "$resolved" == "hub" ]]; then
|
|
170
|
+
claude --system-prompt "$system_prompt" "begin"
|
|
171
|
+
else
|
|
172
|
+
claude --system-prompt "$system_prompt" "startup"
|
|
173
|
+
fi
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
cmd_status() {
|
|
177
|
+
require_forge_config "$FORGE_ROOT"
|
|
178
|
+
|
|
179
|
+
local state_file="$FORGE_ROOT/$CONTEXT_DIR/forge-state.yaml"
|
|
180
|
+
|
|
181
|
+
echo ""
|
|
182
|
+
log_header "🔥 Forge Status"
|
|
183
|
+
|
|
184
|
+
if [[ -f "$state_file" ]]; then
|
|
185
|
+
cat "$state_file"
|
|
186
|
+
else
|
|
187
|
+
echo "No active forge state."
|
|
188
|
+
echo ""
|
|
189
|
+
echo "Start the forge with: forge"
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
193
|
+
echo ""
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
cmd_test() {
|
|
197
|
+
# Alias for doctor
|
|
198
|
+
cmd_doctor
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
cmd_doctor() {
|
|
202
|
+
echo ""
|
|
203
|
+
log_header "🩺 Forge Doctor"
|
|
204
|
+
echo ""
|
|
205
|
+
|
|
206
|
+
local issues=0
|
|
207
|
+
|
|
208
|
+
# --- Dependencies ---
|
|
209
|
+
echo "Dependencies"
|
|
210
|
+
echo "────────────────────────────────────────────────"
|
|
211
|
+
|
|
212
|
+
if claude --version &> /dev/null; then
|
|
213
|
+
local claude_ver
|
|
214
|
+
claude_ver=$(claude --version 2>&1 | head -1)
|
|
215
|
+
log_success "Claude Code: $claude_ver"
|
|
216
|
+
else
|
|
217
|
+
log_error "Claude Code: not found"
|
|
218
|
+
echo " Install from: https://claude.ai/download"
|
|
219
|
+
issues=$((issues + 1))
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
if command -v node &> /dev/null; then
|
|
223
|
+
local node_ver
|
|
224
|
+
node_ver=$(node --version 2>&1)
|
|
225
|
+
log_success "Node.js: $node_ver"
|
|
226
|
+
# Warn if below Node 18
|
|
227
|
+
local node_major
|
|
228
|
+
node_major=$(node --version | sed 's/v\([0-9]*\).*/\1/')
|
|
229
|
+
if [[ "$node_major" -lt 18 ]]; then
|
|
230
|
+
log_warn "Node.js $node_ver is below recommended v18+"
|
|
231
|
+
fi
|
|
232
|
+
else
|
|
233
|
+
log_error "Node.js: not found"
|
|
234
|
+
issues=$((issues + 1))
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
if command -v git &> /dev/null; then
|
|
238
|
+
local git_ver
|
|
239
|
+
git_ver=$(git --version 2>&1)
|
|
240
|
+
log_success "Git: $git_ver"
|
|
241
|
+
else
|
|
242
|
+
log_error "Git: not found"
|
|
243
|
+
issues=$((issues + 1))
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
if command -v sqlite3 &> /dev/null; then
|
|
247
|
+
local sq_ver
|
|
248
|
+
sq_ver=$(sqlite3 --version 2>&1 | head -1)
|
|
249
|
+
log_success "SQLite3: $sq_ver"
|
|
250
|
+
else
|
|
251
|
+
log_warn "SQLite3: not found (daemon metrics disabled)"
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
# --- Forge Config ---
|
|
255
|
+
echo ""
|
|
256
|
+
echo "Configuration"
|
|
257
|
+
echo "────────────────────────────────────────────────"
|
|
258
|
+
|
|
259
|
+
local config_file="$FORGE_ROOT/.forge/config.json"
|
|
260
|
+
local local_config_file="$FORGE_ROOT/.forge/config.local.json"
|
|
261
|
+
|
|
262
|
+
if [[ -f "$config_file" ]]; then
|
|
263
|
+
log_success "config.json: found"
|
|
264
|
+
local platform terminal
|
|
265
|
+
platform=$(json_get_string "$config_file" "platform" 2>/dev/null || echo "unknown")
|
|
266
|
+
terminal=$(json_get_string "$config_file" "terminal_type" 2>/dev/null || echo "unknown")
|
|
267
|
+
echo " Platform: $platform | Terminal: $terminal"
|
|
268
|
+
else
|
|
269
|
+
log_error "config.json: not found — run 'forge init'"
|
|
270
|
+
issues=$((issues + 1))
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
if [[ -f "$local_config_file" ]]; then
|
|
274
|
+
log_success "config.local.json: found (local overrides active)"
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
# --- agents.json sync check ---
|
|
278
|
+
local agents_file="$FORGE_ROOT/config/agents.json"
|
|
279
|
+
if [[ -f "$agents_file" ]]; then
|
|
280
|
+
log_success "agents.json: found"
|
|
281
|
+
local agent_count
|
|
282
|
+
agent_count=$(node -e "const a=require('$agents_file'); console.log(Object.keys(a.agents||{}).length)" 2>/dev/null || echo "?")
|
|
283
|
+
echo " Agents defined: $agent_count"
|
|
284
|
+
else
|
|
285
|
+
log_error "agents.json: not found"
|
|
286
|
+
issues=$((issues + 1))
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
# --- Alias collision check ---
|
|
290
|
+
if [[ -f "$agents_file" ]]; then
|
|
291
|
+
local collisions
|
|
292
|
+
collisions=$(node -e "
|
|
293
|
+
const a = require('$agents_file').agents || {};
|
|
294
|
+
const seen = {};
|
|
295
|
+
const dupes = [];
|
|
296
|
+
for (const [name, info] of Object.entries(a)) {
|
|
297
|
+
const aliases = [name, ...(info.aliases || [])];
|
|
298
|
+
for (const alias of aliases) {
|
|
299
|
+
if (seen[alias] && seen[alias] !== name) {
|
|
300
|
+
dupes.push(alias + ' (' + seen[alias] + ' vs ' + name + ')');
|
|
301
|
+
}
|
|
302
|
+
seen[alias] = name;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (dupes.length) console.log('COLLISION: ' + dupes.join(', '));
|
|
306
|
+
" 2>/dev/null || true)
|
|
307
|
+
if [[ -n "$collisions" ]]; then
|
|
308
|
+
log_error "Alias collision detected: $collisions"
|
|
309
|
+
issues=$((issues + 1))
|
|
310
|
+
else
|
|
311
|
+
log_success "No alias collisions"
|
|
312
|
+
fi
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
# --- Task directories ---
|
|
316
|
+
echo ""
|
|
317
|
+
echo "Task System"
|
|
318
|
+
echo "────────────────────────────────────────────────"
|
|
319
|
+
|
|
320
|
+
local tasks_dir="$FORGE_ROOT/tasks"
|
|
321
|
+
local required_dirs=("pending" "in-progress" "completed" "review" "approved" "merged" "needs-changes" "attention" "bugs")
|
|
322
|
+
for dir in "${required_dirs[@]}"; do
|
|
323
|
+
if [[ -d "$tasks_dir/$dir" ]]; then
|
|
324
|
+
local count
|
|
325
|
+
count=$(ls "$tasks_dir/$dir/"*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
326
|
+
log_success "$dir/: $count task(s)"
|
|
327
|
+
else
|
|
328
|
+
log_warn "$dir/: missing (will be created by daemon)"
|
|
329
|
+
fi
|
|
330
|
+
done
|
|
331
|
+
|
|
332
|
+
# --- Daemon ---
|
|
333
|
+
echo ""
|
|
334
|
+
echo "Daemon"
|
|
335
|
+
echo "────────────────────────────────────────────────"
|
|
336
|
+
|
|
337
|
+
local pid_file="$FORGE_ROOT/.forge/daemon.pid"
|
|
338
|
+
if [[ -f "$pid_file" ]]; then
|
|
339
|
+
local pid
|
|
340
|
+
pid=$(cat "$pid_file" 2>/dev/null)
|
|
341
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
342
|
+
log_success "Daemon running (PID $pid)"
|
|
343
|
+
else
|
|
344
|
+
log_warn "Daemon PID file exists but process is dead — run 'forge daemon start'"
|
|
345
|
+
fi
|
|
346
|
+
else
|
|
347
|
+
log_warn "Daemon not running — run 'forge daemon start' for automated task routing"
|
|
348
|
+
fi
|
|
349
|
+
|
|
350
|
+
# --- Claude Code test ---
|
|
351
|
+
echo ""
|
|
352
|
+
echo "Claude Code Integration"
|
|
353
|
+
echo "────────────────────────────────────────────────"
|
|
354
|
+
|
|
355
|
+
local test_output
|
|
356
|
+
test_output=$(claude --system-prompt "You are a test. Reply only: FORGE_TEST_OK" --print "test" 2>&1 | head -1)
|
|
357
|
+
if [[ "$test_output" == *"FORGE_TEST_OK"* || "$test_output" == *"test"* ]]; then
|
|
358
|
+
log_success "Personality injection: working"
|
|
359
|
+
else
|
|
360
|
+
log_warn "Personality injection: response unexpected"
|
|
361
|
+
echo " Output: $test_output"
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
# --- Summary ---
|
|
365
|
+
echo ""
|
|
366
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
367
|
+
if [[ $issues -eq 0 ]]; then
|
|
368
|
+
log_success "🔥 Forge looks healthy"
|
|
369
|
+
else
|
|
370
|
+
log_error "Found $issues issue(s) — resolve the errors above before starting"
|
|
371
|
+
fi
|
|
372
|
+
echo ""
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
cmd_spawn() {
|
|
376
|
+
local agent="${1:-}"
|
|
377
|
+
|
|
378
|
+
if [[ -z "$agent" ]]; then
|
|
379
|
+
log_error "No agent specified."
|
|
380
|
+
echo "Usage: forge spawn <agent>"
|
|
381
|
+
echo ""
|
|
382
|
+
show_available_agents
|
|
383
|
+
exit $EXIT_INVALID_ARGUMENT
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
# Validate agent before passing to spawn script (SECURITY: whitelist check)
|
|
387
|
+
if ! is_valid_agent "$agent"; then
|
|
388
|
+
log_error "Unknown agent: $agent"
|
|
389
|
+
echo ""
|
|
390
|
+
show_available_agents
|
|
391
|
+
exit $EXIT_INVALID_ARGUMENT
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
"$SCRIPT_DIR/forge-spawn.sh" "$agent"
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
cmd_daemon() {
|
|
398
|
+
local action="${1:-status}"
|
|
399
|
+
|
|
400
|
+
case "$action" in
|
|
401
|
+
"start")
|
|
402
|
+
echo "Starting forge daemon..."
|
|
403
|
+
"$SCRIPT_DIR/forge-daemon.sh" start
|
|
404
|
+
;;
|
|
405
|
+
"stop")
|
|
406
|
+
echo "Stopping forge daemon..."
|
|
407
|
+
"$SCRIPT_DIR/forge-daemon.sh" stop
|
|
408
|
+
;;
|
|
409
|
+
"status")
|
|
410
|
+
"$SCRIPT_DIR/forge-daemon.sh" status
|
|
411
|
+
;;
|
|
412
|
+
"notifications"|"notify")
|
|
413
|
+
shift
|
|
414
|
+
"$SCRIPT_DIR/forge-daemon.sh" notifications "$@"
|
|
415
|
+
;;
|
|
416
|
+
"clear")
|
|
417
|
+
"$SCRIPT_DIR/forge-daemon.sh" clear
|
|
418
|
+
;;
|
|
419
|
+
*)
|
|
420
|
+
echo "Usage: forge daemon [start|stop|status|notifications|clear]"
|
|
421
|
+
;;
|
|
422
|
+
esac
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
cmd_config() {
|
|
426
|
+
local setting="${1:-}"
|
|
427
|
+
local value="${2:-}"
|
|
428
|
+
local config_file="$FORGE_ROOT/.forge/config.json"
|
|
429
|
+
|
|
430
|
+
if [[ ! -f "$config_file" ]]; then
|
|
431
|
+
log_error "Forge not initialized. Run 'forge init' first."
|
|
432
|
+
exit $EXIT_CONFIG_ERROR
|
|
433
|
+
fi
|
|
434
|
+
|
|
435
|
+
case "$setting" in
|
|
436
|
+
"worker-loop"|"loop")
|
|
437
|
+
case "$value" in
|
|
438
|
+
"on"|"true"|"1"|"enable"|"enabled")
|
|
439
|
+
# Enable worker loop
|
|
440
|
+
json_write_bool "$config_file" "worker_loop_enabled" true
|
|
441
|
+
log_success "Worker Loop enabled"
|
|
442
|
+
echo "Workers will now keep running to check for new tasks."
|
|
443
|
+
;;
|
|
444
|
+
"off"|"false"|"0"|"disable"|"disabled")
|
|
445
|
+
# Disable worker loop
|
|
446
|
+
json_write_bool "$config_file" "worker_loop_enabled" false
|
|
447
|
+
log_success "Worker Loop disabled"
|
|
448
|
+
echo "Workers will exit after completing their tasks."
|
|
449
|
+
;;
|
|
450
|
+
""|"status")
|
|
451
|
+
# Show current status
|
|
452
|
+
local current
|
|
453
|
+
current=$(json_read "$config_file" "worker_loop_enabled" "false")
|
|
454
|
+
if [[ "$current" == "true" ]]; then
|
|
455
|
+
echo "Worker Loop: enabled"
|
|
456
|
+
else
|
|
457
|
+
echo "Worker Loop: disabled"
|
|
458
|
+
fi
|
|
459
|
+
;;
|
|
460
|
+
*)
|
|
461
|
+
echo "Usage: forge config worker-loop [on|off|status]"
|
|
462
|
+
;;
|
|
463
|
+
esac
|
|
464
|
+
;;
|
|
465
|
+
"")
|
|
466
|
+
# Show all config
|
|
467
|
+
echo ""
|
|
468
|
+
log_header "Forge Configuration"
|
|
469
|
+
echo ""
|
|
470
|
+
json_pretty "$config_file"
|
|
471
|
+
echo ""
|
|
472
|
+
;;
|
|
473
|
+
*)
|
|
474
|
+
log_error "Unknown setting: $setting"
|
|
475
|
+
echo ""
|
|
476
|
+
echo "Available settings:"
|
|
477
|
+
echo " worker-loop Toggle persistent worker mode (on/off)"
|
|
478
|
+
echo ""
|
|
479
|
+
echo "Usage: forge config <setting> [value]"
|
|
480
|
+
;;
|
|
481
|
+
esac
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
cmd_help() {
|
|
485
|
+
echo ""
|
|
486
|
+
log_header "🔥 Vibe Forge"
|
|
487
|
+
echo ""
|
|
488
|
+
echo "Usage: forge [command] [options]"
|
|
489
|
+
echo ""
|
|
490
|
+
echo "Commands:"
|
|
491
|
+
echo " (none) Start the Planning Hub (main session)"
|
|
492
|
+
echo " init Initialize Vibe Forge for this project"
|
|
493
|
+
echo " start <agent> Start a specific worker agent (in current terminal)"
|
|
494
|
+
echo " spawn <agent> Spawn agent in new terminal window/tab"
|
|
495
|
+
echo " status Show current forge status"
|
|
496
|
+
echo " doctor Full environment diagnostics (alias: test)"
|
|
497
|
+
echo " daemon <action> Manage background daemon (start|stop|status|notifications|clear)"
|
|
498
|
+
echo " config <setting> View or change configuration settings"
|
|
499
|
+
echo " help Show this help message"
|
|
500
|
+
echo ""
|
|
501
|
+
show_available_agents
|
|
502
|
+
echo ""
|
|
503
|
+
echo "Configuration:"
|
|
504
|
+
echo " forge config Show all settings"
|
|
505
|
+
echo " forge config worker-loop on Enable persistent worker mode"
|
|
506
|
+
echo " forge config worker-loop off Disable persistent worker mode"
|
|
507
|
+
echo ""
|
|
508
|
+
echo "Examples:"
|
|
509
|
+
echo " forge Start Planning Hub"
|
|
510
|
+
echo " forge init Initialize for new project"
|
|
511
|
+
echo " forge start anvil Start Anvil (frontend) agent"
|
|
512
|
+
echo " forge spawn fe Spawn frontend agent in new terminal"
|
|
513
|
+
echo " forge status Check current status"
|
|
514
|
+
echo ""
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
# =============================================================================
|
|
518
|
+
# Main
|
|
519
|
+
# =============================================================================
|
|
520
|
+
|
|
521
|
+
main() {
|
|
522
|
+
local command="${1:-}"
|
|
523
|
+
|
|
524
|
+
case "$command" in
|
|
525
|
+
"init")
|
|
526
|
+
shift
|
|
527
|
+
cmd_init "$@"
|
|
528
|
+
;;
|
|
529
|
+
"start")
|
|
530
|
+
shift
|
|
531
|
+
cmd_start "$@"
|
|
532
|
+
;;
|
|
533
|
+
"spawn")
|
|
534
|
+
shift
|
|
535
|
+
cmd_spawn "$@"
|
|
536
|
+
;;
|
|
537
|
+
"status")
|
|
538
|
+
cmd_status
|
|
539
|
+
;;
|
|
540
|
+
"test"|"doctor")
|
|
541
|
+
cmd_doctor
|
|
542
|
+
;;
|
|
543
|
+
"daemon")
|
|
544
|
+
shift
|
|
545
|
+
cmd_daemon "$@"
|
|
546
|
+
;;
|
|
547
|
+
"config")
|
|
548
|
+
shift
|
|
549
|
+
cmd_config "$@"
|
|
550
|
+
;;
|
|
551
|
+
"help"|"--help"|"-h")
|
|
552
|
+
cmd_help
|
|
553
|
+
;;
|
|
554
|
+
"")
|
|
555
|
+
# Default: start Planning Hub
|
|
556
|
+
cmd_start "hub"
|
|
557
|
+
;;
|
|
558
|
+
*)
|
|
559
|
+
log_error "Unknown command: $command"
|
|
560
|
+
echo "Run 'forge help' for usage."
|
|
561
|
+
exit $EXIT_INVALID_ARGUMENT
|
|
562
|
+
;;
|
|
563
|
+
esac
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
main "$@"
|