vibe-forge 0.4.0 → 0.8.2
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 +5 -5
- package/.claude/commands/forge.md +50 -3
- 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 +37 -4
- package/.claude/scripts/setup-worker-loop.sh +45 -45
- package/.claude/settings.json +89 -0
- package/LICENSE +21 -21
- package/README.md +211 -232
- package/agents/aegis/personality.md +35 -1
- package/agents/anvil/personality.md +39 -1
- package/agents/architect/personality.md +26 -0
- package/agents/crucible/personality.md +54 -1
- package/agents/crucible-x/personality.md +210 -0
- package/agents/ember/personality.md +29 -1
- package/agents/flux/personality.md +248 -0
- package/agents/furnace/personality.md +52 -1
- package/agents/herald/personality.md +3 -1
- 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 +222 -0
- package/agents/scribe/personality.md +3 -1
- package/agents/slag/personality.md +268 -0
- package/agents/{sentinel → temper}/personality.md +85 -9
- package/bin/cli.js +77 -30
- 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 +176 -550
- package/bin/forge-setup.sh +28 -11
- package/bin/forge-spawn.sh +5 -5
- package/bin/forge.cmd +83 -83
- package/bin/forge.sh +210 -31
- package/config/agent-manifest.yaml +237 -243
- package/config/agents.json +207 -132
- package/config/task-types.yaml +111 -106
- package/context/agent-overrides/README.md +41 -0
- package/context/architecture.md +42 -0
- package/context/modern-conventions.md +129 -129
- 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 +38 -11
- package/src/lib/check-aliases.js +50 -0
- package/{bin → src}/lib/colors.sh +2 -1
- package/src/lib/config.sh +347 -0
- package/{bin → src}/lib/constants.sh +48 -13
- package/src/lib/daemon/budgets.sh +107 -0
- package/src/lib/daemon/dependencies.sh +146 -0
- package/src/lib/daemon/display.sh +128 -0
- package/src/lib/daemon/notifications.sh +273 -0
- package/src/lib/daemon/routing.sh +93 -0
- package/src/lib/daemon/state.sh +163 -0
- package/src/lib/daemon/sync.sh +103 -0
- package/{bin → src}/lib/database.sh +52 -0
- package/src/lib/frontmatter.js +106 -0
- package/src/lib/heimdall-setup.js +113 -0
- package/src/lib/heimdall.js +265 -0
- package/src/lib/index.sh +25 -0
- package/{bin → src}/lib/json.sh +7 -1
- package/{bin → src}/lib/terminal.js +7 -1
- 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/bin/lib/config.sh +0 -313
- package/config/task-template.md +0 -87
- 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 → src}/lib/agents.sh +0 -0
- /package/{bin → src}/lib/util.sh +0 -0
- /package/{bin → src}/lib/vcs.js +0 -0
- /package/{context → templates}/project-context-template.md +0 -0
package/bin/forge-setup.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Usage: ./forge-setup.sh [--non-interactive]
|
|
7
7
|
#
|
|
8
8
|
|
|
9
|
-
set -
|
|
9
|
+
set -euo pipefail
|
|
10
10
|
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
FORGE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
@@ -16,17 +16,17 @@ FORGE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
16
16
|
# =============================================================================
|
|
17
17
|
|
|
18
18
|
# shellcheck source=lib/colors.sh
|
|
19
|
-
source "$SCRIPT_DIR/lib/colors.sh"
|
|
19
|
+
source "$SCRIPT_DIR/../src/lib/colors.sh"
|
|
20
20
|
# shellcheck source=lib/constants.sh
|
|
21
|
-
source "$SCRIPT_DIR/lib/constants.sh"
|
|
21
|
+
source "$SCRIPT_DIR/../src/lib/constants.sh"
|
|
22
22
|
# shellcheck source=lib/json.sh
|
|
23
|
-
source "$SCRIPT_DIR/lib/json.sh"
|
|
23
|
+
source "$SCRIPT_DIR/../src/lib/json.sh"
|
|
24
24
|
# shellcheck source=lib/util.sh
|
|
25
|
-
source "$SCRIPT_DIR/lib/util.sh"
|
|
25
|
+
source "$SCRIPT_DIR/../src/lib/util.sh"
|
|
26
26
|
|
|
27
27
|
# Parse arguments
|
|
28
28
|
NON_INTERACTIVE=false
|
|
29
|
-
if [[ "$1" == "--non-interactive" ]]; then
|
|
29
|
+
if [[ "${1:-}" == "--non-interactive" ]]; then
|
|
30
30
|
NON_INTERACTIVE=true
|
|
31
31
|
fi
|
|
32
32
|
|
|
@@ -197,7 +197,7 @@ configure_vcs() {
|
|
|
197
197
|
|
|
198
198
|
# Auto-detect VCS
|
|
199
199
|
local detected_vcs
|
|
200
|
-
detected_vcs=$(node "$SCRIPT_DIR/lib/vcs.js" detect 2>/dev/null)
|
|
200
|
+
detected_vcs=$(node "$SCRIPT_DIR/../src/lib/vcs.js" detect 2>/dev/null)
|
|
201
201
|
local detected_type
|
|
202
202
|
detected_type=$(echo "$detected_vcs" | node -e "const d=require('fs').readFileSync(0,'utf8');try{console.log(JSON.parse(d).type)}catch{console.log('none')}")
|
|
203
203
|
local confidence
|
|
@@ -256,7 +256,7 @@ configure_vcs() {
|
|
|
256
256
|
|
|
257
257
|
# Initialize VCS folders and save config
|
|
258
258
|
local init_result
|
|
259
|
-
init_result=$(node "$SCRIPT_DIR/lib/vcs.js" init "$vcs_choice" "$FORGE_ROOT" 2>/dev/null)
|
|
259
|
+
init_result=$(node "$SCRIPT_DIR/../src/lib/vcs.js" init "$vcs_choice" "$FORGE_ROOT" 2>/dev/null)
|
|
260
260
|
|
|
261
261
|
echo ""
|
|
262
262
|
case "$vcs_choice" in
|
|
@@ -411,7 +411,10 @@ configure_daemon() {
|
|
|
411
411
|
log_success "Daemon enabled"
|
|
412
412
|
echo ""
|
|
413
413
|
echo "Starting daemon..."
|
|
414
|
-
"$SCRIPT_DIR/forge-daemon.sh" start
|
|
414
|
+
if ! "$SCRIPT_DIR/forge-daemon.sh" start; then
|
|
415
|
+
log_warn "Daemon failed to start (sqlite3 may be missing)"
|
|
416
|
+
echo " You can install sqlite3 and start it later with: forge daemon start"
|
|
417
|
+
fi
|
|
415
418
|
else
|
|
416
419
|
echo ""
|
|
417
420
|
log_info "Daemon disabled"
|
|
@@ -534,9 +537,20 @@ create_project_context() {
|
|
|
534
537
|
|
|
535
538
|
local context_dir="$PWD/context"
|
|
536
539
|
local context_file="$context_dir/project-context.md"
|
|
537
|
-
local template_file="$FORGE_ROOT/
|
|
540
|
+
local template_file="$FORGE_ROOT/templates/project-context-template.md"
|
|
538
541
|
|
|
539
542
|
mkdir -p "$context_dir"
|
|
543
|
+
mkdir -p "$context_dir/agent-overrides"
|
|
544
|
+
|
|
545
|
+
# Create architecture.md if missing
|
|
546
|
+
if [[ ! -f "$context_dir/architecture.md" ]] && [[ -f "$FORGE_ROOT/context/architecture.md" ]]; then
|
|
547
|
+
cp "$FORGE_ROOT/context/architecture.md" "$context_dir/architecture.md"
|
|
548
|
+
fi
|
|
549
|
+
|
|
550
|
+
# Create agent-overrides README if missing
|
|
551
|
+
if [[ ! -f "$context_dir/agent-overrides/README.md" ]] && [[ -f "$FORGE_ROOT/context/agent-overrides/README.md" ]]; then
|
|
552
|
+
cp "$FORGE_ROOT/context/agent-overrides/README.md" "$context_dir/agent-overrides/README.md"
|
|
553
|
+
fi
|
|
540
554
|
|
|
541
555
|
# Check if context already exists
|
|
542
556
|
if [[ -f "$context_file" ]]; then
|
|
@@ -552,6 +566,7 @@ create_project_context() {
|
|
|
552
566
|
fi
|
|
553
567
|
echo ""
|
|
554
568
|
|
|
569
|
+
local PROJECT_DESC=""
|
|
555
570
|
if [[ "$NON_INTERACTIVE" == "false" ]]; then
|
|
556
571
|
# Ask for project description
|
|
557
572
|
read -p "Brief project description (or Enter to skip): " PROJECT_DESC
|
|
@@ -613,7 +628,9 @@ setup_complete() {
|
|
|
613
628
|
log_info "/forge spawn anvil Spawn a worker agent"
|
|
614
629
|
log_info "/forge help See all commands"
|
|
615
630
|
echo ""
|
|
616
|
-
echo "Optional: Edit context/project-context.md to add
|
|
631
|
+
echo "Optional: Edit context/project-context.md to add project details."
|
|
632
|
+
echo " Edit context/architecture.md for architectural guardrails."
|
|
633
|
+
echo " Add files to context/agent-overrides/ for per-agent rules."
|
|
617
634
|
echo ""
|
|
618
635
|
}
|
|
619
636
|
|
package/bin/forge-spawn.sh
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# - Manual (prints instructions)
|
|
11
11
|
#
|
|
12
12
|
|
|
13
|
-
set -
|
|
13
|
+
set -euo pipefail
|
|
14
14
|
|
|
15
15
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
16
|
FORGE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
@@ -21,13 +21,13 @@ CONFIG_FILE="$FORGE_ROOT/.forge/config.json"
|
|
|
21
21
|
# =============================================================================
|
|
22
22
|
|
|
23
23
|
# shellcheck source=lib/colors.sh
|
|
24
|
-
source "$SCRIPT_DIR/lib/colors.sh"
|
|
24
|
+
source "$SCRIPT_DIR/../src/lib/colors.sh"
|
|
25
25
|
# shellcheck source=lib/constants.sh
|
|
26
|
-
source "$SCRIPT_DIR/lib/constants.sh"
|
|
26
|
+
source "$SCRIPT_DIR/../src/lib/constants.sh"
|
|
27
27
|
# shellcheck source=lib/config.sh
|
|
28
|
-
source "$SCRIPT_DIR/lib/config.sh"
|
|
28
|
+
source "$SCRIPT_DIR/../src/lib/config.sh"
|
|
29
29
|
# shellcheck source=lib/agents.sh
|
|
30
|
-
source "$SCRIPT_DIR/lib/agents.sh"
|
|
30
|
+
source "$SCRIPT_DIR/../src/lib/agents.sh"
|
|
31
31
|
|
|
32
32
|
# Load agent configuration from JSON if available
|
|
33
33
|
if [[ -f "$FORGE_ROOT/$AGENTS_CONFIG" ]]; then
|
package/bin/forge.cmd
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
REM Vibe Forge - Windows Launcher
|
|
3
|
-
REM Wraps forge.sh for Windows compatibility
|
|
4
|
-
|
|
5
|
-
setlocal EnableDelayedExpansion
|
|
6
|
-
|
|
7
|
-
set "SCRIPT_DIR=%~dp0"
|
|
8
|
-
set "FORGE_ROOT=%SCRIPT_DIR%.."
|
|
9
|
-
set "CONFIG_FILE=%FORGE_ROOT%\.forge\config.json"
|
|
10
|
-
|
|
11
|
-
REM Check if this is init or help (doesn't require config)
|
|
12
|
-
set "CMD=%~1"
|
|
13
|
-
if "%CMD%"=="init" goto :find_bash
|
|
14
|
-
if "%CMD%"=="help" goto :find_bash
|
|
15
|
-
if "%CMD%"=="--help" goto :find_bash
|
|
16
|
-
if "%CMD%"=="-h" goto :find_bash
|
|
17
|
-
|
|
18
|
-
REM For other commands, check if initialized
|
|
19
|
-
if not exist "%CONFIG_FILE%" (
|
|
20
|
-
echo Error: Vibe Forge not initialized.
|
|
21
|
-
echo Run 'forge init' first.
|
|
22
|
-
exit /b 1
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
REM Extract git_bash_path from config using PowerShell for reliable JSON parsing
|
|
26
|
-
for /f "usebackq delims=" %%a in (`powershell -NoProfile -Command "(Get-Content '%CONFIG_FILE%' | ConvertFrom-Json).git_bash_path"`) do (
|
|
27
|
-
set "GIT_BASH_PATH=%%a"
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
REM Convert forward slashes to backslashes if needed
|
|
31
|
-
set "GIT_BASH_PATH=!GIT_BASH_PATH:/=\!"
|
|
32
|
-
|
|
33
|
-
REM Verify the path exists
|
|
34
|
-
if not exist "!GIT_BASH_PATH!" (
|
|
35
|
-
echo Error: Git Bash not found at: !GIT_BASH_PATH!
|
|
36
|
-
echo Please run 'forge init' again.
|
|
37
|
-
exit /b 1
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
goto :run_forge
|
|
41
|
-
|
|
42
|
-
:find_bash
|
|
43
|
-
REM Find Git Bash for init/help commands
|
|
44
|
-
set "GIT_BASH_PATH="
|
|
45
|
-
|
|
46
|
-
REM Check common paths
|
|
47
|
-
if exist "C:\Program Files\Git\bin\bash.exe" (
|
|
48
|
-
set "GIT_BASH_PATH=C:\Program Files\Git\bin\bash.exe"
|
|
49
|
-
goto :run_forge
|
|
50
|
-
)
|
|
51
|
-
if exist "C:\Program Files (x86)\Git\bin\bash.exe" (
|
|
52
|
-
set "GIT_BASH_PATH=C:\Program Files (x86)\Git\bin\bash.exe"
|
|
53
|
-
goto :run_forge
|
|
54
|
-
)
|
|
55
|
-
if exist "D:\Program Files\Git\bin\bash.exe" (
|
|
56
|
-
set "GIT_BASH_PATH=D:\Program Files\Git\bin\bash.exe"
|
|
57
|
-
goto :run_forge
|
|
58
|
-
)
|
|
59
|
-
if exist "D:\applications\git\bin\bash.exe" (
|
|
60
|
-
set "GIT_BASH_PATH=D:\applications\git\bin\bash.exe"
|
|
61
|
-
goto :run_forge
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
REM Try to find via where command
|
|
65
|
-
for /f "tokens=*" %%i in ('where git 2^>nul') do (
|
|
66
|
-
set "GIT_PATH=%%~dpi"
|
|
67
|
-
set "GIT_BASH_PATH=!GIT_PATH!..\bin\bash.exe"
|
|
68
|
-
if exist "!GIT_BASH_PATH!" goto :run_forge
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
REM Still not found
|
|
72
|
-
echo Error: Git Bash not found.
|
|
73
|
-
echo Please install Git from https://git-scm.com/downloads/win
|
|
74
|
-
exit /b 1
|
|
75
|
-
|
|
76
|
-
:run_forge
|
|
77
|
-
REM Set environment variable for Claude Code
|
|
78
|
-
set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH_PATH%"
|
|
79
|
-
|
|
80
|
-
REM Run the bash script with all arguments
|
|
81
|
-
"%GIT_BASH_PATH%" "%SCRIPT_DIR%forge.sh" %*
|
|
82
|
-
|
|
83
|
-
endlocal
|
|
1
|
+
@echo off
|
|
2
|
+
REM Vibe Forge - Windows Launcher
|
|
3
|
+
REM Wraps forge.sh for Windows compatibility
|
|
4
|
+
|
|
5
|
+
setlocal EnableDelayedExpansion
|
|
6
|
+
|
|
7
|
+
set "SCRIPT_DIR=%~dp0"
|
|
8
|
+
set "FORGE_ROOT=%SCRIPT_DIR%.."
|
|
9
|
+
set "CONFIG_FILE=%FORGE_ROOT%\.forge\config.json"
|
|
10
|
+
|
|
11
|
+
REM Check if this is init or help (doesn't require config)
|
|
12
|
+
set "CMD=%~1"
|
|
13
|
+
if "%CMD%"=="init" goto :find_bash
|
|
14
|
+
if "%CMD%"=="help" goto :find_bash
|
|
15
|
+
if "%CMD%"=="--help" goto :find_bash
|
|
16
|
+
if "%CMD%"=="-h" goto :find_bash
|
|
17
|
+
|
|
18
|
+
REM For other commands, check if initialized
|
|
19
|
+
if not exist "%CONFIG_FILE%" (
|
|
20
|
+
echo Error: Vibe Forge not initialized.
|
|
21
|
+
echo Run 'forge init' first.
|
|
22
|
+
exit /b 1
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
REM Extract git_bash_path from config using PowerShell for reliable JSON parsing
|
|
26
|
+
for /f "usebackq delims=" %%a in (`powershell -NoProfile -Command "(Get-Content '%CONFIG_FILE%' | ConvertFrom-Json).git_bash_path"`) do (
|
|
27
|
+
set "GIT_BASH_PATH=%%a"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
REM Convert forward slashes to backslashes if needed
|
|
31
|
+
set "GIT_BASH_PATH=!GIT_BASH_PATH:/=\!"
|
|
32
|
+
|
|
33
|
+
REM Verify the path exists
|
|
34
|
+
if not exist "!GIT_BASH_PATH!" (
|
|
35
|
+
echo Error: Git Bash not found at: !GIT_BASH_PATH!
|
|
36
|
+
echo Please run 'forge init' again.
|
|
37
|
+
exit /b 1
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
goto :run_forge
|
|
41
|
+
|
|
42
|
+
:find_bash
|
|
43
|
+
REM Find Git Bash for init/help commands
|
|
44
|
+
set "GIT_BASH_PATH="
|
|
45
|
+
|
|
46
|
+
REM Check common paths
|
|
47
|
+
if exist "C:\Program Files\Git\bin\bash.exe" (
|
|
48
|
+
set "GIT_BASH_PATH=C:\Program Files\Git\bin\bash.exe"
|
|
49
|
+
goto :run_forge
|
|
50
|
+
)
|
|
51
|
+
if exist "C:\Program Files (x86)\Git\bin\bash.exe" (
|
|
52
|
+
set "GIT_BASH_PATH=C:\Program Files (x86)\Git\bin\bash.exe"
|
|
53
|
+
goto :run_forge
|
|
54
|
+
)
|
|
55
|
+
if exist "D:\Program Files\Git\bin\bash.exe" (
|
|
56
|
+
set "GIT_BASH_PATH=D:\Program Files\Git\bin\bash.exe"
|
|
57
|
+
goto :run_forge
|
|
58
|
+
)
|
|
59
|
+
if exist "D:\applications\git\bin\bash.exe" (
|
|
60
|
+
set "GIT_BASH_PATH=D:\applications\git\bin\bash.exe"
|
|
61
|
+
goto :run_forge
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
REM Try to find via where command
|
|
65
|
+
for /f "tokens=*" %%i in ('where git 2^>nul') do (
|
|
66
|
+
set "GIT_PATH=%%~dpi"
|
|
67
|
+
set "GIT_BASH_PATH=!GIT_PATH!..\bin\bash.exe"
|
|
68
|
+
if exist "!GIT_BASH_PATH!" goto :run_forge
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
REM Still not found
|
|
72
|
+
echo Error: Git Bash not found.
|
|
73
|
+
echo Please install Git from https://git-scm.com/downloads/win
|
|
74
|
+
exit /b 1
|
|
75
|
+
|
|
76
|
+
:run_forge
|
|
77
|
+
REM Set environment variable for Claude Code
|
|
78
|
+
set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH_PATH%"
|
|
79
|
+
|
|
80
|
+
REM Run the bash script with all arguments
|
|
81
|
+
"%GIT_BASH_PATH%" "%SCRIPT_DIR%forge.sh" %*
|
|
82
|
+
|
|
83
|
+
endlocal
|
package/bin/forge.sh
CHANGED
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
# forge start <agent> - Start a specific worker agent
|
|
10
10
|
# forge spawn <agent> - Spawn agent in new terminal window/tab
|
|
11
11
|
# forge status - Show forge status
|
|
12
|
-
# forge
|
|
12
|
+
# forge doctor - Full environment diagnostics (alias: test)
|
|
13
13
|
# forge daemon - Start/stop the background daemon
|
|
14
14
|
# forge help - Show help
|
|
15
15
|
#
|
|
16
16
|
# Security Note:
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# See docs/security.md for
|
|
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
20
|
#
|
|
21
21
|
|
|
22
|
-
set -
|
|
22
|
+
set -euo pipefail
|
|
23
23
|
|
|
24
24
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
25
|
FORGE_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
@@ -30,15 +30,15 @@ CONFIG_FILE="$FORGE_ROOT/.forge/config.json"
|
|
|
30
30
|
# =============================================================================
|
|
31
31
|
|
|
32
32
|
# shellcheck source=lib/colors.sh
|
|
33
|
-
source "$SCRIPT_DIR/lib/colors.sh"
|
|
33
|
+
source "$SCRIPT_DIR/../src/lib/colors.sh"
|
|
34
34
|
# shellcheck source=lib/constants.sh
|
|
35
|
-
source "$SCRIPT_DIR/lib/constants.sh"
|
|
35
|
+
source "$SCRIPT_DIR/../src/lib/constants.sh"
|
|
36
36
|
# shellcheck source=lib/config.sh
|
|
37
|
-
source "$SCRIPT_DIR/lib/config.sh"
|
|
37
|
+
source "$SCRIPT_DIR/../src/lib/config.sh"
|
|
38
38
|
# shellcheck source=lib/json.sh
|
|
39
|
-
source "$SCRIPT_DIR/lib/json.sh"
|
|
39
|
+
source "$SCRIPT_DIR/../src/lib/json.sh"
|
|
40
40
|
# shellcheck source=lib/agents.sh
|
|
41
|
-
source "$SCRIPT_DIR/lib/agents.sh"
|
|
41
|
+
source "$SCRIPT_DIR/../src/lib/agents.sh"
|
|
42
42
|
|
|
43
43
|
# Load agent configuration from JSON if available
|
|
44
44
|
# This overwrites the fallback values in constants.sh
|
|
@@ -101,6 +101,39 @@ cmd_start() {
|
|
|
101
101
|
$(cat "$project_context")"
|
|
102
102
|
fi
|
|
103
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/../src/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
|
+
|
|
104
137
|
# Add startup instructions based on agent type
|
|
105
138
|
if [[ "$resolved" == "hub" ]]; then
|
|
106
139
|
# Planning Hub startup - Party Mode Team
|
|
@@ -131,12 +164,12 @@ You are autonomous - when assigned work exists, start it without asking permissi
|
|
|
131
164
|
fi
|
|
132
165
|
|
|
133
166
|
# Launch Claude Code with the personality
|
|
134
|
-
#
|
|
135
|
-
#
|
|
167
|
+
# Agents use project-level .claude/settings.json for permissions (allowlist + Heimdall hooks)
|
|
168
|
+
# instead of --dangerously-skip-permissions. See docs/security.md.
|
|
136
169
|
if [[ "$resolved" == "hub" ]]; then
|
|
137
|
-
claude --
|
|
170
|
+
claude --system-prompt "$system_prompt" "begin"
|
|
138
171
|
else
|
|
139
|
-
claude --
|
|
172
|
+
claude --system-prompt "$system_prompt" "startup"
|
|
140
173
|
fi
|
|
141
174
|
}
|
|
142
175
|
|
|
@@ -161,36 +194,182 @@ cmd_status() {
|
|
|
161
194
|
}
|
|
162
195
|
|
|
163
196
|
cmd_test() {
|
|
164
|
-
|
|
197
|
+
# Alias for doctor
|
|
198
|
+
cmd_doctor
|
|
199
|
+
}
|
|
165
200
|
|
|
201
|
+
cmd_doctor() {
|
|
166
202
|
echo ""
|
|
167
|
-
log_header "
|
|
203
|
+
log_header "🩺 Forge Doctor"
|
|
168
204
|
echo ""
|
|
169
205
|
|
|
170
|
-
|
|
171
|
-
|
|
206
|
+
local issues=0
|
|
207
|
+
|
|
208
|
+
# --- Dependencies ---
|
|
209
|
+
echo "Dependencies"
|
|
210
|
+
echo "────────────────────────────────────────────────"
|
|
211
|
+
|
|
172
212
|
if claude --version &> /dev/null; then
|
|
173
|
-
|
|
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"
|
|
174
250
|
else
|
|
175
|
-
|
|
176
|
-
exit $EXIT_DEPENDENCY_MISSING
|
|
251
|
+
log_warn "SQLite3: not found (daemon metrics disabled)"
|
|
177
252
|
fi
|
|
178
253
|
|
|
179
|
-
#
|
|
254
|
+
# --- Forge Config ---
|
|
180
255
|
echo ""
|
|
181
|
-
echo "
|
|
182
|
-
|
|
183
|
-
|
|
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
|
|
184
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)
|
|
185
357
|
if [[ "$test_output" == *"FORGE_TEST_OK"* || "$test_output" == *"test"* ]]; then
|
|
186
|
-
log_success "Personality
|
|
358
|
+
log_success "Personality injection: working"
|
|
187
359
|
else
|
|
188
|
-
log_warn "Personality
|
|
360
|
+
log_warn "Personality injection: response unexpected"
|
|
189
361
|
echo " Output: $test_output"
|
|
190
362
|
fi
|
|
191
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
|
|
192
372
|
echo ""
|
|
193
|
-
log_success "🔥 Setup validated!"
|
|
194
373
|
}
|
|
195
374
|
|
|
196
375
|
cmd_spawn() {
|
|
@@ -314,7 +493,7 @@ cmd_help() {
|
|
|
314
493
|
echo " start <agent> Start a specific worker agent (in current terminal)"
|
|
315
494
|
echo " spawn <agent> Spawn agent in new terminal window/tab"
|
|
316
495
|
echo " status Show current forge status"
|
|
317
|
-
echo "
|
|
496
|
+
echo " doctor Full environment diagnostics (alias: test)"
|
|
318
497
|
echo " daemon <action> Manage background daemon (start|stop|status|notifications|clear)"
|
|
319
498
|
echo " config <setting> View or change configuration settings"
|
|
320
499
|
echo " help Show this help message"
|
|
@@ -358,8 +537,8 @@ main() {
|
|
|
358
537
|
"status")
|
|
359
538
|
cmd_status
|
|
360
539
|
;;
|
|
361
|
-
"test")
|
|
362
|
-
|
|
540
|
+
"test"|"doctor")
|
|
541
|
+
cmd_doctor
|
|
363
542
|
;;
|
|
364
543
|
"daemon")
|
|
365
544
|
shift
|