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
@@ -1,206 +1,241 @@
1
- #!/usr/bin/env bash
2
- #
3
- # Vibe Forge - Shared Constants
4
- # Source this file in other scripts: source "$SCRIPT_DIR/lib/constants.sh"
5
- #
6
- # NOTE: Agent configuration should be loaded from config/agents.json via
7
- # load_agents_from_json() in config.sh. The hardcoded values below are
8
- # fallback defaults for when JSON loading is not possible (e.g., tests).
9
- #
10
-
11
- # =============================================================================
12
- # Exit Codes
13
- # =============================================================================
14
- # Standardized exit codes for consistent error handling across scripts
15
- # Based on BSD sysexits.h conventions with project-specific additions
16
-
17
- EXIT_SUCCESS=0 # Successful execution
18
- EXIT_GENERAL_ERROR=1 # Generic/unspecified error
19
- EXIT_CONFIG_ERROR=2 # Configuration file missing/invalid
20
- EXIT_DEPENDENCY_MISSING=3 # Required dependency not found (Claude Code, Git Bash, etc.)
21
- EXIT_INVALID_ARGUMENT=4 # Invalid argument (unknown agent, unknown command)
22
- EXIT_RUNTIME_ERROR=5 # Runtime error (daemon conflict, spawn failed, etc.)
23
-
24
- # Timing
25
- POLL_INTERVAL=2 # seconds between daemon task checks
26
- NOTIFICATION_DEBOUNCE=1 # seconds to avoid notification spam
27
-
28
- # Daemon Configuration
29
- MAX_LOG_SIZE=1048576 # 1MB - log rotation threshold
30
- MAX_NOTIFY_ENTRIES=1000 # Maximum notification log entries before trimming
31
- STALE_STATUS_THRESHOLD=300 # 5 minutes - when worker status is considered stale
32
- MAINTENANCE_INTERVAL=100 # Daemon iterations between maintenance runs
33
- STALE_CLEANUP_MINUTES=30 # Remove agent status older than this (minutes)
34
- HISTORY_PRUNE_DAYS=7 # Remove status history older than this (days)
35
-
36
- # Directory structure (relative to FORGE_ROOT)
37
- CONFIG_DIR=".forge"
38
- TASKS_DIR="tasks"
39
- TASKS_PENDING="$TASKS_DIR/pending"
40
- TASKS_IN_PROGRESS="$TASKS_DIR/in-progress"
41
- TASKS_COMPLETED="$TASKS_DIR/completed"
42
- TASKS_REVIEW="$TASKS_DIR/review"
43
- TASKS_APPROVED="$TASKS_DIR/approved"
44
- TASKS_NEEDS_CHANGES="$TASKS_DIR/needs-changes"
45
- TASKS_MERGED="$TASKS_DIR/merged"
46
- TASKS_ATTENTION="$TASKS_DIR/attention"
47
- CONTEXT_DIR="context"
48
- AGENT_STATUS_DIR="$CONTEXT_DIR/agent-status"
49
- AGENTS_DIR="agents"
50
-
51
- # Config files
52
- AGENTS_CONFIG="config/agents.json"
53
-
54
- # =============================================================================
55
- # Agent Configuration (Fallback Defaults)
56
- # =============================================================================
57
- # These values are overwritten when load_agents_from_json() is called.
58
- # They exist as fallback for contexts where JSON loading isn't available.
59
-
60
- # Flag to track if agents were loaded from JSON
61
- AGENTS_LOADED="${AGENTS_LOADED:-false}"
62
-
63
- # Valid agent names (whitelist for security)
64
- # These are the ONLY valid canonical agent names
65
- # NOTE: Must stay in sync with config/agents.json (which is the source of truth)
66
- # Last sync: 2026-01-16
67
- VALID_AGENTS=(
68
- "hub"
69
- "sentinel"
70
- "anvil"
71
- "furnace"
72
- "crucible"
73
- "scribe"
74
- "herald"
75
- "ember"
76
- "aegis"
77
- "architect"
78
- )
79
-
80
- # Agent aliases map (for resolve_agent)
81
- # Format: alias=canonical
82
- # NOTE: Must stay in sync with config/agents.json (which is the source of truth)
83
- declare -A AGENT_ALIASES=(
84
- # Hub aliases (Chief Orchestrator)
85
- ["hub"]="hub"
86
- ["planning"]="hub"
87
- ["master"]="hub"
88
- ["forge-master"]="hub"
89
- # Sentinel aliases (Code Reviewer)
90
- ["sentinel"]="sentinel"
91
- ["review"]="sentinel"
92
- ["reviewer"]="sentinel"
93
- ["cr"]="sentinel"
94
- # Anvil aliases (Frontend)
95
- ["anvil"]="anvil"
96
- ["frontend"]="anvil"
97
- ["ui"]="anvil"
98
- ["fe"]="anvil"
99
- # Furnace aliases (Backend)
100
- ["furnace"]="furnace"
101
- ["backend"]="furnace"
102
- ["api"]="furnace"
103
- ["be"]="furnace"
104
- # Crucible aliases (Testing)
105
- ["crucible"]="crucible"
106
- ["test"]="crucible"
107
- ["testing"]="crucible"
108
- ["qa"]="crucible"
109
- ["tester"]="crucible"
110
- # Scribe aliases (Documentation)
111
- ["scribe"]="scribe"
112
- ["docs"]="scribe"
113
- ["documentation"]="scribe"
114
- ["doc"]="scribe"
115
- # Herald aliases (Release)
116
- ["herald"]="herald"
117
- ["release"]="herald"
118
- ["deploy"]="herald"
119
- ["deployment"]="herald"
120
- # Ember aliases (DevOps)
121
- ["ember"]="ember"
122
- ["devops"]="ember"
123
- ["ops"]="ember"
124
- ["infra"]="ember"
125
- ["infrastructure"]="ember"
126
- # Aegis aliases (Security)
127
- ["aegis"]="aegis"
128
- ["security"]="aegis"
129
- ["sec"]="aegis"
130
- ["appsec"]="aegis"
131
- # Architect aliases (System Design)
132
- ["architect"]="architect"
133
- ["arch"]="architect"
134
- ["design"]="architect"
135
- ["sage"]="architect"
136
- )
137
-
138
- # Agent display names
139
- declare -A AGENT_DISPLAY_NAMES=(
140
- ["hub"]="Planning Hub"
141
- ["sentinel"]="Sentinel"
142
- ["anvil"]="Anvil"
143
- ["furnace"]="Furnace"
144
- ["crucible"]="Crucible"
145
- ["scribe"]="Scribe"
146
- ["herald"]="Herald"
147
- ["ember"]="Ember"
148
- ["aegis"]="Aegis"
149
- ["architect"]="Architect"
150
- )
151
-
152
- # Agent roles
153
- declare -A AGENT_ROLES=(
154
- ["hub"]="Chief Orchestrator"
155
- ["sentinel"]="Code Reviewer"
156
- ["anvil"]="Frontend Developer"
157
- ["furnace"]="Backend Developer"
158
- ["crucible"]="Tester / QA"
159
- ["scribe"]="Documentation Specialist"
160
- ["herald"]="Release Manager"
161
- ["ember"]="DevOps Engineer"
162
- ["aegis"]="Security Specialist"
163
- ["architect"]="System Architect"
164
- )
165
-
166
- # Agent personality files (relative to FORGE_ROOT)
167
- declare -A AGENT_PERSONALITY_FILES=(
168
- ["hub"]="agents/planning-hub/personality.md"
169
- ["sentinel"]="agents/sentinel/personality.md"
170
- ["anvil"]="agents/anvil/personality.md"
171
- ["furnace"]="agents/furnace/personality.md"
172
- ["crucible"]="agents/crucible/personality.md"
173
- ["scribe"]="agents/scribe/personality.md"
174
- ["herald"]="agents/herald/personality.md"
175
- ["ember"]="agents/ember/personality.md"
176
- ["aegis"]="agents/aegis/personality.md"
177
- ["architect"]="agents/architect/personality.md"
178
- )
179
-
180
- # Agent icons
181
- declare -A AGENT_ICONS=(
182
- ["hub"]="⚒️"
183
- ["sentinel"]="🛡️"
184
- ["anvil"]="🔨"
185
- ["furnace"]="🔥"
186
- ["crucible"]="🧪"
187
- ["scribe"]="📜"
188
- ["herald"]="📯"
189
- ["ember"]="⚙️"
190
- ["aegis"]="🔒"
191
- ["architect"]="🏛️"
192
- )
193
-
194
- # Agent tab colors for Windows Terminal (hex format)
195
- declare -A AGENT_TAB_COLORS=(
196
- ["hub"]="#FF6B35"
197
- ["sentinel"]="#8B5CF6"
198
- ["anvil"]="#3B82F6"
199
- ["furnace"]="#EF4444"
200
- ["crucible"]="#10B981"
201
- ["scribe"]="#F59E0B"
202
- ["herald"]="#EC4899"
203
- ["ember"]="#F97316"
204
- ["aegis"]="#06B6D4"
205
- ["architect"]="#6366F1"
206
- )
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Vibe Forge - Shared Constants
4
+ # Source this file in other scripts: source "$SCRIPT_DIR/lib/constants.sh"
5
+ #
6
+ # NOTE: Agent configuration should be loaded from config/agents.json via
7
+ # load_agents_from_json() in config.sh. The hardcoded values below are
8
+ # fallback defaults for when JSON loading is not possible (e.g., tests).
9
+ #
10
+
11
+ # =============================================================================
12
+ # Exit Codes
13
+ # =============================================================================
14
+ # Standardized exit codes for consistent error handling across scripts
15
+ # Based on BSD sysexits.h conventions with project-specific additions
16
+
17
+ EXIT_SUCCESS=0 # Successful execution
18
+ EXIT_GENERAL_ERROR=1 # Generic/unspecified error
19
+ EXIT_CONFIG_ERROR=2 # Configuration file missing/invalid
20
+ EXIT_DEPENDENCY_MISSING=3 # Required dependency not found (Claude Code, Git Bash, etc.)
21
+ EXIT_INVALID_ARGUMENT=4 # Invalid argument (unknown agent, unknown command)
22
+ EXIT_RUNTIME_ERROR=5 # Runtime error (daemon conflict, spawn failed, etc.)
23
+
24
+ # Timing
25
+ POLL_INTERVAL=2 # seconds between daemon task checks
26
+ NOTIFICATION_DEBOUNCE=1 # seconds to avoid notification spam
27
+
28
+ # Daemon Configuration
29
+ MAX_LOG_SIZE=1048576 # 1MB - log rotation threshold
30
+ MAX_NOTIFY_ENTRIES=1000 # Maximum notification log entries before trimming
31
+ STALE_STATUS_THRESHOLD=300 # 5 minutes - when worker status is considered stale
32
+ MAINTENANCE_INTERVAL=100 # Daemon iterations between maintenance runs
33
+ STALE_CLEANUP_MINUTES=30 # Remove agent status older than this (minutes)
34
+ HISTORY_PRUNE_DAYS=7 # Remove status history older than this (days)
35
+
36
+ # Directory structure (relative to FORGE_ROOT)
37
+ CONFIG_DIR=".forge"
38
+ TASKS_DIR="tasks"
39
+ TASKS_PENDING="$TASKS_DIR/pending"
40
+ TASKS_IN_PROGRESS="$TASKS_DIR/in-progress"
41
+ TASKS_COMPLETED="$TASKS_DIR/completed"
42
+ TASKS_REVIEW="$TASKS_DIR/review"
43
+ TASKS_APPROVED="$TASKS_DIR/approved"
44
+ TASKS_NEEDS_CHANGES="$TASKS_DIR/needs-changes"
45
+ TASKS_MERGED="$TASKS_DIR/merged"
46
+ TASKS_ATTENTION="$TASKS_DIR/attention"
47
+ CONTEXT_DIR="context"
48
+ AGENT_STATUS_DIR="$CONTEXT_DIR/agent-status"
49
+ AGENTS_DIR="agents"
50
+
51
+ # Config files
52
+ AGENTS_CONFIG="config/agents.json"
53
+
54
+ # =============================================================================
55
+ # Agent Configuration (Fallback Defaults)
56
+ # =============================================================================
57
+ # These values are overwritten when load_agents_from_json() is called.
58
+ # They exist as fallback for contexts where JSON loading isn't available.
59
+
60
+ # Flag to track if agents were loaded from JSON
61
+ AGENTS_LOADED="${AGENTS_LOADED:-false}"
62
+
63
+ # Valid agent names (whitelist for security)
64
+ # These are the ONLY valid canonical agent names
65
+ # NOTE: Must stay in sync with config/agents.json (which is the source of truth)
66
+ # Last sync: 2026-04-03 (added loki, renamed sentinel→temper)
67
+ VALID_AGENTS=(
68
+ "hub"
69
+ "temper"
70
+ "anvil"
71
+ "furnace"
72
+ "crucible"
73
+ "scribe"
74
+ "herald"
75
+ "ember"
76
+ "aegis"
77
+ "architect"
78
+ "pixel"
79
+ "oracle"
80
+ "loki"
81
+ )
82
+
83
+ # Agent aliases map (for resolve_agent)
84
+ # Format: alias=canonical
85
+ # NOTE: Must stay in sync with config/agents.json (which is the source of truth)
86
+ declare -A AGENT_ALIASES=(
87
+ # Hub aliases (Chief Orchestrator)
88
+ ["hub"]="hub"
89
+ ["planning"]="hub"
90
+ ["master"]="hub"
91
+ ["forge-master"]="hub"
92
+ # Temper aliases (Code Reviewer)
93
+ ["temper"]="temper"
94
+ ["review"]="temper"
95
+ ["reviewer"]="temper"
96
+ ["cr"]="temper"
97
+ # Anvil aliases (Frontend)
98
+ ["anvil"]="anvil"
99
+ ["frontend"]="anvil"
100
+ ["ui"]="anvil"
101
+ ["fe"]="anvil"
102
+ # Furnace aliases (Backend)
103
+ ["furnace"]="furnace"
104
+ ["backend"]="furnace"
105
+ ["api"]="furnace"
106
+ ["be"]="furnace"
107
+ # Crucible aliases (Testing)
108
+ ["crucible"]="crucible"
109
+ ["test"]="crucible"
110
+ ["testing"]="crucible"
111
+ ["qa"]="crucible"
112
+ ["tester"]="crucible"
113
+ # Scribe aliases (Documentation)
114
+ ["scribe"]="scribe"
115
+ ["docs"]="scribe"
116
+ ["documentation"]="scribe"
117
+ ["doc"]="scribe"
118
+ # Herald aliases (Release)
119
+ ["herald"]="herald"
120
+ ["release"]="herald"
121
+ ["deploy"]="herald"
122
+ ["deployment"]="herald"
123
+ # Ember aliases (DevOps)
124
+ ["ember"]="ember"
125
+ ["devops"]="ember"
126
+ ["ops"]="ember"
127
+ ["infra"]="ember"
128
+ ["infrastructure"]="ember"
129
+ # Aegis aliases (Security)
130
+ ["aegis"]="aegis"
131
+ ["security"]="aegis"
132
+ ["sec"]="aegis"
133
+ ["appsec"]="aegis"
134
+ # Architect aliases (System Design)
135
+ ["architect"]="architect"
136
+ ["arch"]="architect"
137
+ ["sage"]="architect"
138
+ # Pixel aliases (UX Design)
139
+ # NOTE: "design" intentionally removed — ambiguous with architect's technical design domain
140
+ ["pixel"]="pixel"
141
+ ["ux"]="pixel"
142
+ ["ui-design"]="pixel"
143
+ ["user-experience"]="pixel"
144
+ # Oracle aliases (Product / Requirements)
145
+ ["oracle"]="oracle"
146
+ ["product"]="oracle"
147
+ ["po"]="oracle"
148
+ ["requirements"]="oracle"
149
+ ["req"]="oracle"
150
+ ["analyst"]="oracle"
151
+ # Loki aliases (Lateral Thinker)
152
+ ["loki"]="loki"
153
+ ["trickster"]="loki"
154
+ ["contrarian"]="loki"
155
+ ["brainstorm"]="loki"
156
+ )
157
+
158
+ # Agent display names
159
+ declare -A AGENT_DISPLAY_NAMES=(
160
+ ["hub"]="Planning Hub"
161
+ ["temper"]="Temper"
162
+ ["anvil"]="Anvil"
163
+ ["furnace"]="Furnace"
164
+ ["crucible"]="Crucible"
165
+ ["scribe"]="Scribe"
166
+ ["herald"]="Herald"
167
+ ["ember"]="Ember"
168
+ ["aegis"]="Aegis"
169
+ ["architect"]="Architect"
170
+ ["pixel"]="Pixel"
171
+ ["oracle"]="Oracle"
172
+ ["loki"]="Loki"
173
+ )
174
+
175
+ # Agent roles
176
+ declare -A AGENT_ROLES=(
177
+ ["hub"]="Chief Orchestrator"
178
+ ["temper"]="Code Reviewer"
179
+ ["anvil"]="Frontend Developer"
180
+ ["furnace"]="Backend Developer"
181
+ ["crucible"]="Tester / QA"
182
+ ["scribe"]="Documentation Specialist"
183
+ ["herald"]="Release Manager"
184
+ ["ember"]="DevOps Engineer"
185
+ ["aegis"]="Security Specialist"
186
+ ["architect"]="System Architect"
187
+ ["pixel"]="UX Designer"
188
+ ["oracle"]="Product Owner / Requirements Analyst"
189
+ ["loki"]="Lateral Thinker"
190
+ )
191
+
192
+ # Agent personality files (relative to FORGE_ROOT)
193
+ declare -A AGENT_PERSONALITY_FILES=(
194
+ ["hub"]="agents/planning-hub/personality.md"
195
+ ["temper"]="agents/temper/personality.md"
196
+ ["anvil"]="agents/anvil/personality.md"
197
+ ["furnace"]="agents/furnace/personality.md"
198
+ ["crucible"]="agents/crucible/personality.md"
199
+ ["scribe"]="agents/scribe/personality.md"
200
+ ["herald"]="agents/herald/personality.md"
201
+ ["ember"]="agents/ember/personality.md"
202
+ ["aegis"]="agents/aegis/personality.md"
203
+ ["architect"]="agents/architect/personality.md"
204
+ ["pixel"]="agents/pixel/personality.md"
205
+ ["oracle"]="agents/oracle/personality.md"
206
+ ["loki"]="agents/loki/personality.md"
207
+ )
208
+
209
+ # Agent icons
210
+ declare -A AGENT_ICONS=(
211
+ ["hub"]="⚒️"
212
+ ["temper"]="⚖️"
213
+ ["anvil"]="🔨"
214
+ ["furnace"]="🔥"
215
+ ["crucible"]="🧪"
216
+ ["scribe"]="📜"
217
+ ["herald"]="📯"
218
+ ["ember"]="⚙️"
219
+ ["aegis"]="🔒"
220
+ ["architect"]="🏛️"
221
+ ["pixel"]="🎨"
222
+ ["oracle"]="🔮"
223
+ ["loki"]="🎭"
224
+ )
225
+
226
+ # Agent tab colors for Windows Terminal (hex format)
227
+ declare -A AGENT_TAB_COLORS=(
228
+ ["hub"]="#FF6B35"
229
+ ["temper"]="#8B5CF6"
230
+ ["anvil"]="#3B82F6"
231
+ ["furnace"]="#EF4444"
232
+ ["crucible"]="#10B981"
233
+ ["scribe"]="#F59E0B"
234
+ ["herald"]="#EC4899"
235
+ ["ember"]="#F97316"
236
+ ["aegis"]="#06B6D4"
237
+ ["architect"]="#6366F1"
238
+ ["pixel"]="#D946EF"
239
+ ["oracle"]="#FBBF24"
240
+ ["loki"]="#7C3AED"
241
+ )
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # bin/lib/daemon/budgets.sh
4
+ #
5
+ # Token budget warnings (T2-F1)
6
+ #
7
+ # Monitors agent session duration as a proxy for token consumption.
8
+ # Claude Code sessions don't expose token counts externally, so we
9
+ # estimate from how long an agent has been continuously "working" on
10
+ # a single task. Agents working beyond the warning threshold get an
11
+ # attention file so the user knows to check on them.
12
+ #
13
+ # Dependencies: database.sh, constants.sh
14
+ # Globals required: FORGE_ROOT, FORGE_DB, TASKS_ATTENTION, LOG_FILE
15
+
16
+ # Prevent double-sourcing
17
+ [[ -n "${_DAEMON_BUDGETS_LOADED:-}" ]] && return 0
18
+ _DAEMON_BUDGETS_LOADED=1
19
+
20
+ # Thresholds (seconds)
21
+ TOKEN_WARN_DURATION=${TOKEN_WARN_DURATION:-5400} # 90 minutes
22
+ TOKEN_URGENT_DURATION=${TOKEN_URGENT_DURATION:-7200} # 2 hours
23
+
24
+ # Track which agents we've already warned about (reset when they go idle)
25
+ declare -A _budget_warned 2>/dev/null || true
26
+
27
+ check_token_budgets() {
28
+ local now_epoch
29
+ now_epoch=$(date +%s)
30
+
31
+ # Query agents currently in "working" status
32
+ local rows
33
+ rows=$(sqlite3 "$FORGE_DB" \
34
+ "SELECT agent, task, updated_at FROM agent_status WHERE status='working';" 2>/dev/null) || return 0
35
+
36
+ [[ -z "$rows" ]] && return 0
37
+
38
+ while IFS='|' read -r agent task updated; do
39
+ [[ -z "$agent" || -z "$updated" ]] && continue
40
+
41
+ # Calculate how long agent has been working
42
+ local updated_epoch duration
43
+ updated_epoch=$(date -d "$updated" +%s 2>/dev/null || echo "0")
44
+ [[ "$updated_epoch" -eq 0 ]] && continue
45
+ duration=$((now_epoch - updated_epoch))
46
+
47
+ # Skip if we already warned for this agent+task combo
48
+ local warn_key="${agent}:${task}"
49
+ [[ "${_budget_warned[$warn_key]:-}" == "1" ]] && continue
50
+
51
+ local urgency=""
52
+ if [[ "$duration" -ge "$TOKEN_URGENT_DURATION" ]]; then
53
+ urgency="urgent"
54
+ elif [[ "$duration" -ge "$TOKEN_WARN_DURATION" ]]; then
55
+ urgency="normal"
56
+ fi
57
+
58
+ [[ -z "$urgency" ]] && continue
59
+
60
+ # Create attention file
61
+ local attention_dir="$FORGE_ROOT/$TASKS_ATTENTION"
62
+ mkdir -p "$attention_dir"
63
+
64
+ local duration_min=$((duration / 60))
65
+ local attention_file="$attention_dir/token-budget-${agent}.md"
66
+
67
+ # Don't overwrite if attention file already exists
68
+ if [[ -f "$attention_file" ]]; then
69
+ _budget_warned[$warn_key]=1
70
+ continue
71
+ fi
72
+
73
+ cat > "$attention_file" << BUDGET
74
+ ---
75
+ agent: $agent
76
+ created: $(date -Iseconds)
77
+ type: budget-warning
78
+ urgency: $urgency
79
+ ---
80
+
81
+ ## Issue
82
+
83
+ Token budget warning: **$agent** has been working on \`$task\` for ${duration_min} minutes.
84
+
85
+ Long-running sessions risk context degradation. Consider:
86
+ - Check if the agent is stuck or looping
87
+ - Use \`/compact-context\` in the agent's session
88
+ - Split remaining work into a new task for a fresh session
89
+ BUDGET
90
+
91
+ _budget_warned[$warn_key]=1
92
+ echo "[$(date -Iseconds)] TOKEN BUDGET: $agent working ${duration_min}m on $task ($urgency)" >> "$LOG_FILE"
93
+ done <<< "$rows"
94
+
95
+ # Clear warnings for agents that are no longer working
96
+ for key in "${!_budget_warned[@]}"; do
97
+ local agent_part="${key%%:*}"
98
+ local still_working
99
+ still_working=$(sqlite3 "$FORGE_DB" \
100
+ "SELECT COUNT(*) FROM agent_status WHERE agent='$agent_part' AND status='working';" 2>/dev/null || echo "0")
101
+ if [[ "$still_working" -eq 0 ]]; then
102
+ unset "_budget_warned[$key]"
103
+ # Clean up attention file if agent finished
104
+ rm -f "$FORGE_ROOT/$TASKS_ATTENTION/token-budget-${agent_part}.md" 2>/dev/null
105
+ fi
106
+ done
107
+ }