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.
Files changed (129) hide show
  1. package/.claude/commands/clear-attention.md +63 -63
  2. package/.claude/commands/compact-context.md +52 -0
  3. package/.claude/commands/configure-vcs.md +102 -102
  4. package/.claude/commands/forge.md +218 -171
  5. package/.claude/commands/need-help.md +77 -77
  6. package/.claude/commands/update-status.md +64 -64
  7. package/.claude/commands/worker-loop.md +106 -106
  8. package/.claude/hooks/worker-loop.js +217 -187
  9. package/.claude/scripts/setup-worker-loop.sh +45 -45
  10. package/.claude/settings.json +89 -0
  11. package/LICENSE +21 -21
  12. package/README.md +253 -232
  13. package/agents/aegis/personality.md +303 -269
  14. package/agents/anvil/personality.md +278 -240
  15. package/agents/architect/personality.md +260 -234
  16. package/agents/crucible/personality.md +362 -309
  17. package/agents/crucible-x/personality.md +210 -0
  18. package/agents/ember/personality.md +293 -265
  19. package/agents/flux/personality.md +248 -0
  20. package/agents/furnace/personality.md +342 -291
  21. package/agents/herald/personality.md +249 -247
  22. package/agents/loki/personality.md +108 -0
  23. package/agents/oracle/personality.md +284 -0
  24. package/agents/pixel/personality.md +140 -0
  25. package/agents/planning-hub/personality.md +473 -251
  26. package/agents/scribe/personality.md +253 -251
  27. package/agents/slag/personality.md +268 -0
  28. package/agents/temper/personality.md +270 -0
  29. package/bin/cli.js +372 -325
  30. package/bin/dashboard/api/agents.js +333 -0
  31. package/bin/dashboard/api/dispatch.js +507 -0
  32. package/bin/dashboard/api/tasks.js +416 -0
  33. package/bin/dashboard/public/assets/index-BpHfsx1r.js +2 -0
  34. package/bin/dashboard/public/assets/index-QODv4Zn9.css +1 -0
  35. package/bin/dashboard/public/index.html +14 -0
  36. package/bin/dashboard/server.js +645 -0
  37. package/bin/forge-daemon.sh +477 -851
  38. package/bin/forge-setup.sh +661 -645
  39. package/bin/forge-spawn.sh +164 -164
  40. package/bin/forge.cmd +83 -83
  41. package/bin/forge.sh +566 -387
  42. package/bin/lib/agents.sh +177 -177
  43. package/bin/lib/check-aliases.js +50 -0
  44. package/bin/lib/colors.sh +44 -44
  45. package/bin/lib/config.sh +347 -313
  46. package/bin/lib/constants.sh +241 -206
  47. package/bin/lib/daemon/budgets.sh +107 -0
  48. package/bin/lib/daemon/dependencies.sh +146 -0
  49. package/bin/lib/daemon/display.sh +128 -0
  50. package/bin/lib/daemon/notifications.sh +273 -0
  51. package/bin/lib/daemon/routing.sh +93 -0
  52. package/bin/lib/daemon/state.sh +163 -0
  53. package/bin/lib/daemon/sync.sh +103 -0
  54. package/bin/lib/database.sh +357 -305
  55. package/bin/lib/frontmatter.js +106 -0
  56. package/bin/lib/heimdall-setup.js +113 -0
  57. package/bin/lib/heimdall.js +265 -0
  58. package/bin/lib/json.sh +264 -258
  59. package/bin/lib/terminal.js +452 -446
  60. package/bin/lib/util.sh +126 -126
  61. package/bin/lib/vcs.js +349 -349
  62. package/config/agent-manifest.yaml +237 -243
  63. package/config/agents.json +207 -132
  64. package/config/task-template.md +159 -87
  65. package/config/task-types.yaml +111 -106
  66. package/config/templates/handoff-template.md +40 -0
  67. package/context/agent-overrides/README.md +41 -0
  68. package/context/architecture.md +42 -0
  69. package/context/modern-conventions.md +129 -129
  70. package/context/project-context-template.md +122 -122
  71. package/docs/agents.md +473 -409
  72. package/docs/architecture.md +194 -162
  73. package/docs/commands.md +451 -388
  74. package/docs/security.md +195 -144
  75. package/package.json +77 -50
  76. package/.claude/settings.local.json +0 -33
  77. package/agents/forge-master/capabilities.md +0 -144
  78. package/agents/forge-master/context-template.md +0 -128
  79. package/agents/forge-master/personality.md +0 -138
  80. package/agents/sentinel/personality.md +0 -194
  81. package/context/forge-state.yaml +0 -19
  82. package/docs/TODO.md +0 -150
  83. package/docs/getting-started.md +0 -243
  84. package/docs/npm-publishing.md +0 -95
  85. package/docs/workflows/README.md +0 -32
  86. package/docs/workflows/azure-devops.md +0 -108
  87. package/docs/workflows/bitbucket.md +0 -104
  88. package/docs/workflows/git-only.md +0 -130
  89. package/docs/workflows/gitea.md +0 -168
  90. package/docs/workflows/github.md +0 -103
  91. package/docs/workflows/gitlab.md +0 -105
  92. package/docs/workflows.md +0 -454
  93. package/tasks/completed/ARCH-001-duplicate-agent-config.md +0 -121
  94. package/tasks/completed/ARCH-002-mixed-bash-node-implementation.md +0 -88
  95. package/tasks/completed/ARCH-003-worker-loop-hook-duplication.md +0 -77
  96. package/tasks/completed/ARCH-009-test-organization.md +0 -78
  97. package/tasks/completed/ARCH-011-jq-vs-nodejs-json.md +0 -94
  98. package/tasks/completed/ARCH-012-tmp-files-in-root.md +0 -71
  99. package/tasks/completed/ARCH-013-exit-code-constants.md +0 -65
  100. package/tasks/completed/ARCH-014-sed-incompatibility.md +0 -96
  101. package/tasks/completed/ARCH-015-docs-todo-tracking.md +0 -83
  102. package/tasks/completed/CLEAN-001.md +0 -38
  103. package/tasks/completed/CLEAN-003.md +0 -47
  104. package/tasks/completed/CLEAN-004.md +0 -56
  105. package/tasks/completed/CLEAN-005.md +0 -75
  106. package/tasks/completed/CLEAN-006.md +0 -47
  107. package/tasks/completed/CLEAN-007.md +0 -34
  108. package/tasks/completed/CLEAN-008.md +0 -49
  109. package/tasks/completed/CLEAN-012.md +0 -58
  110. package/tasks/completed/CLEAN-013.md +0 -45
  111. package/tasks/completed/SEC-001-sql-injection-fix.md +0 -58
  112. package/tasks/completed/SEC-002-notification-injection-fix.md +0 -45
  113. package/tasks/completed/SEC-003-eval-injection-fix.md +0 -54
  114. package/tasks/completed/SEC-004-pid-race-condition-fix.md +0 -49
  115. package/tasks/completed/SEC-005-worker-loop-path-fix.md +0 -51
  116. package/tasks/completed/SEC-006-eval-agent-names.md +0 -55
  117. package/tasks/completed/SEC-007-spawn-escaping.md +0 -67
  118. package/tasks/pending/ARCH-004-git-bash-detection-duplication.md +0 -72
  119. package/tasks/pending/ARCH-005-missing-src-directory.md +0 -95
  120. package/tasks/pending/ARCH-006-task-template-location.md +0 -64
  121. package/tasks/pending/ARCH-007-daemon-monolith.md +0 -91
  122. package/tasks/pending/ARCH-008-forge-master-vs-hub.md +0 -81
  123. package/tasks/pending/ARCH-010-missing-index-files.md +0 -84
  124. package/tasks/pending/CLEAN-002.md +0 -29
  125. package/tasks/pending/CLEAN-009.md +0 -31
  126. package/tasks/pending/CLEAN-010.md +0 -30
  127. package/tasks/pending/CLEAN-011.md +0 -30
  128. package/tasks/pending/CLEAN-014.md +0 -32
  129. package/tasks/review/task-001.md +0 -78
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # bin/lib/daemon/state.sh
4
+ #
5
+ # Daemon state management - forge-state.yaml updates, attention tracking,
6
+ # adaptive polling
7
+ #
8
+ # Dependencies: database.sh, constants.sh
9
+ # Requires: sync.sh (for build_worker_status)
10
+ # Globals required: FORGE_ROOT, STATE_FILE, AGENT_STATUS_DIR,
11
+ # TASKS_PENDING, TASKS_IN_PROGRESS, TASKS_COMPLETED,
12
+ # TASKS_REVIEW, TASKS_APPROVED, TASKS_NEEDS_CHANGES,
13
+ # TASKS_MERGED, TASKS_ATTENTION
14
+
15
+ # Prevent double-sourcing
16
+ [[ -n "${_DAEMON_STATE_LOADED:-}" ]] && return 0
17
+ _DAEMON_STATE_LOADED=1
18
+
19
+ # Node.js frontmatter helper (RT-20260405-001 MEDIUM-5: replaces grep/cut YAML parsing)
20
+ FRONTMATTER_JS="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/frontmatter.js"
21
+
22
+ # Parse a single frontmatter field from a markdown file.
23
+ # Usage: fm_field <file> <field>
24
+ fm_field() {
25
+ node "$FRONTMATTER_JS" "$1" "$2" 2>/dev/null | sed -n "s/^${2}=//p"
26
+ }
27
+
28
+ # Parse a markdown section's first content line.
29
+ # Usage: fm_section <file> <heading>
30
+ fm_section() {
31
+ node "$FRONTMATTER_JS" --section "$1" "$2" 2>/dev/null
32
+ }
33
+
34
+ update_state() {
35
+ # Count tasks in each folder (using find with -maxdepth for safety)
36
+ local pending in_progress completed review approved needs_changes merged attention
37
+ pending=$(find "$FORGE_ROOT/$TASKS_PENDING" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
38
+ in_progress=$(find "$FORGE_ROOT/$TASKS_IN_PROGRESS" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
39
+ completed=$(find "$FORGE_ROOT/$TASKS_COMPLETED" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
40
+ review=$(find "$FORGE_ROOT/$TASKS_REVIEW" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
41
+ approved=$(find "$FORGE_ROOT/$TASKS_APPROVED" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
42
+ needs_changes=$(find "$FORGE_ROOT/$TASKS_NEEDS_CHANGES" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
43
+ merged=$(find "$FORGE_ROOT/$TASKS_MERGED" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
44
+ attention=$(find "$FORGE_ROOT/$TASKS_ATTENTION" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
45
+
46
+ local blocked=${BLOCKED_TASK_COUNT:-0}
47
+
48
+ # Build active task details for in-progress tasks
49
+ local active_tasks_details=""
50
+ if [[ "$in_progress" -gt 0 ]]; then
51
+ active_tasks_details=$(build_active_tasks)
52
+ fi
53
+
54
+ # Build attention details if any workers need help
55
+ local attention_details=""
56
+ if [[ "$attention" -gt 0 ]]; then
57
+ attention_details=$(build_attention_details)
58
+ fi
59
+
60
+ # Build blocked task details (T2-H2)
61
+ local blocked_details=""
62
+ if [[ "$blocked" -gt 0 ]]; then
63
+ blocked_details=$(build_blocked_tasks)
64
+ fi
65
+
66
+ # Build worker status from agent-status files
67
+ local worker_status=""
68
+ if [[ -d "$FORGE_ROOT/$AGENT_STATUS_DIR" ]]; then
69
+ worker_status=$(build_worker_status)
70
+ fi
71
+
72
+ # Write state file atomically (write to temp, then move)
73
+ local temp_state="${STATE_FILE}.tmp.$$"
74
+ cat > "$temp_state" << EOF
75
+ # Vibe Forge State
76
+ # Auto-updated by forge-daemon
77
+ # Last updated: $(date -Iseconds)
78
+
79
+ forge:
80
+ status: active
81
+ daemon_pid: $$
82
+
83
+ tasks:
84
+ pending: $pending
85
+ in_progress: $in_progress
86
+ completed: $completed
87
+ in_review: $review
88
+ approved: $approved
89
+ needs_changes: $needs_changes
90
+ merged: $merged
91
+ blocked: $blocked
92
+ attention_needed: $attention
93
+
94
+ $active_tasks_details
95
+ $attention_details
96
+ $blocked_details
97
+ $worker_status
98
+ last_updated: $(date -Iseconds)
99
+ EOF
100
+ mv "$temp_state" "$STATE_FILE"
101
+ }
102
+
103
+ build_attention_details() {
104
+ echo "attention:"
105
+ for attention_file in "$FORGE_ROOT/$TASKS_ATTENTION"/*.md; do
106
+ if [[ -f "$attention_file" && ! -L "$attention_file" ]]; then
107
+ local agent created issue
108
+ agent=$(fm_field "$attention_file" "agent")
109
+ created=$(fm_field "$attention_file" "created")
110
+ issue=$(fm_section "$attention_file" "Issue")
111
+ issue="${issue:-Needs attention}"
112
+
113
+ printf ' - agent: %s\n' "$agent"
114
+ printf ' since: %s\n' "$created"
115
+ printf ' issue: "%s"\n' "$issue"
116
+ fi
117
+ done
118
+ }
119
+
120
+ build_active_tasks() {
121
+ echo "active_tasks:"
122
+ for task_file in "$FORGE_ROOT/$TASKS_IN_PROGRESS"/*.md; do
123
+ if [[ -f "$task_file" && ! -L "$task_file" ]]; then
124
+ local task_id title assigned_to
125
+ task_id=$(fm_field "$task_file" "id")
126
+ title=$(fm_field "$task_file" "title")
127
+ assigned_to=$(fm_field "$task_file" "assigned_to")
128
+
129
+ task_id="${task_id:-$(basename "$task_file" .md)}"
130
+ title="${title:-Untitled}"
131
+ assigned_to="${assigned_to:-unassigned}"
132
+
133
+ printf ' - id: %s\n' "$task_id"
134
+ printf ' title: "%s"\n' "$title"
135
+ printf ' assigned_to: %s\n' "$assigned_to"
136
+ fi
137
+ done
138
+ }
139
+
140
+ # Determine daemon state based on activity (for adaptive polling)
141
+ determine_daemon_state() {
142
+ # Check if there are in-progress tasks
143
+ local in_progress_count
144
+ in_progress_count=$(find "$FORGE_ROOT/$TASKS_IN_PROGRESS" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
145
+
146
+ # Check if there are active workers
147
+ local active_workers
148
+ active_workers=$(db_count_active_workers 2>/dev/null || echo "0")
149
+
150
+ if [[ "$in_progress_count" -gt 0 ]] || [[ "$active_workers" -gt 0 ]]; then
151
+ echo "active"
152
+ else
153
+ echo "idle"
154
+ fi
155
+ }
156
+
157
+ # Get current poll interval in seconds (from DB, with fallback)
158
+ get_poll_interval() {
159
+ local interval_ms
160
+ interval_ms=$(db_get_poll_interval_ms 2>/dev/null || echo "30000")
161
+ # Convert ms to seconds (bash integer division)
162
+ echo $((interval_ms / 1000))
163
+ }
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # bin/lib/daemon/sync.sh
4
+ #
5
+ # Agent status synchronization functions - JSON files to SQLite
6
+ #
7
+ # Dependencies: json.sh, database.sh, constants.sh
8
+ # Globals required: FORGE_ROOT, FORGE_DB, AGENT_STATUS_DIR, LOG_FILE,
9
+ # STALE_STATUS_THRESHOLD
10
+
11
+ # Prevent double-sourcing
12
+ [[ -n "${_DAEMON_SYNC_LOADED:-}" ]] && return 0
13
+ _DAEMON_SYNC_LOADED=1
14
+
15
+ # Sync agent status from JSON files to SQLite (with mtime filtering)
16
+ sync_agent_status_to_db() {
17
+ local status_dir="$FORGE_ROOT/$AGENT_STATUS_DIR"
18
+
19
+ if [[ ! -d "$status_dir" ]]; then
20
+ return 0
21
+ fi
22
+
23
+ for status_file in "$status_dir"/*.json; do
24
+ if [[ -f "$status_file" && ! -L "$status_file" ]]; then
25
+ # Get file modification time
26
+ local file_mtime
27
+ file_mtime=$(stat -c %Y "$status_file" 2>/dev/null || stat -f %m "$status_file" 2>/dev/null || echo "0")
28
+
29
+ # Get agent name from filename
30
+ local agent_name
31
+ agent_name=$(basename "$status_file" .json)
32
+
33
+ # Check if file has changed since last read
34
+ local stored_mtime
35
+ stored_mtime=$(db_get_agent_mtime "$agent_name")
36
+
37
+ if [[ "$file_mtime" -gt "$stored_mtime" ]]; then
38
+ # File changed - parse and update DB
39
+ local agent status task message updated
40
+ agent=$(json_read "$status_file" "agent" "unknown")
41
+ status=$(json_read "$status_file" "status" "unknown")
42
+ task=$(json_read "$status_file" "task" "")
43
+ message=$(json_read "$status_file" "message" "" | head -c 80)
44
+ updated=$(json_read "$status_file" "updated" "")
45
+
46
+ # Check if status actually changed (T1-D3: record transitions)
47
+ local old_status
48
+ old_status=$(sqlite3 "$FORGE_DB" \
49
+ "SELECT status FROM agent_status WHERE agent = '$(db_escape "$agent")';" 2>/dev/null || echo "")
50
+ if [[ "$old_status" != "$status" && -n "$status" ]]; then
51
+ db_record_status_history "$agent" "$status" "$task"
52
+ fi
53
+
54
+ # Upsert to database
55
+ db_upsert_agent_status "$agent" "$status" "$task" "$message" "$updated" "$file_mtime"
56
+
57
+ echo "[$(date -Iseconds)] Synced status for $agent: $status" >> "$LOG_FILE"
58
+ fi
59
+ fi
60
+ done
61
+ }
62
+
63
+ # Build worker status from SQLite (for YAML output)
64
+ build_worker_status() {
65
+ local now_epoch
66
+ now_epoch=$(date +%s)
67
+ local stale_threshold=$STALE_STATUS_THRESHOLD
68
+
69
+ # Check if we have any agent status in DB
70
+ local agent_count
71
+ agent_count=$(sqlite3 "$FORGE_DB" "SELECT COUNT(*) FROM agent_status;" 2>/dev/null || echo "0")
72
+
73
+ if [[ "$agent_count" -eq 0 ]]; then
74
+ return 0
75
+ fi
76
+
77
+ echo "workers:"
78
+
79
+ # Read from database
80
+ while IFS='|' read -r agent status task message updated; do
81
+ local stale_marker=""
82
+
83
+ # Check if stale
84
+ if [[ -n "$updated" ]]; then
85
+ local updated_epoch age
86
+ updated_epoch=$(date -d "$updated" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%S" "${updated%Z}" +%s 2>/dev/null || echo "0")
87
+ age=$((now_epoch - updated_epoch))
88
+ if [[ "$age" -gt "$stale_threshold" ]]; then
89
+ stale_marker=" (stale)"
90
+ fi
91
+ fi
92
+
93
+ echo " - agent: $agent"
94
+ echo " status: $status$stale_marker"
95
+ if [[ -n "$task" ]]; then
96
+ echo " task: $task"
97
+ fi
98
+ if [[ -n "$message" ]]; then
99
+ echo " message: \"$message\""
100
+ fi
101
+ echo " updated: $updated"
102
+ done < <(db_get_all_agent_statuses)
103
+ }