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/lib/agents.sh
CHANGED
|
@@ -1,177 +1,177 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Vibe Forge - Agent Resolution and Validation
|
|
4
|
-
# Source this file in other scripts: source "$SCRIPT_DIR/lib/agents.sh"
|
|
5
|
-
#
|
|
6
|
-
# SECURITY: This module provides safe agent name resolution with whitelist validation.
|
|
7
|
-
# Never pass user input directly to shell commands - always resolve through these functions.
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
# Ensure constants are loaded
|
|
11
|
-
if [[ -z "${VALID_AGENTS+x}" ]]; then
|
|
12
|
-
echo "Error: constants.sh must be sourced before agents.sh" >&2
|
|
13
|
-
exit 1
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
# resolve_agent ALIAS
|
|
17
|
-
# Converts an agent alias to its canonical name.
|
|
18
|
-
# Returns: canonical name on stdout, empty string if not found
|
|
19
|
-
# Exit code: 0 if found, 1 if not found
|
|
20
|
-
#
|
|
21
|
-
# SECURITY: This function validates against a whitelist.
|
|
22
|
-
# The returned value is safe to use in file paths and commands.
|
|
23
|
-
resolve_agent() {
|
|
24
|
-
local input="$1"
|
|
25
|
-
|
|
26
|
-
# Normalize to lowercase for matching
|
|
27
|
-
local normalized
|
|
28
|
-
normalized=$(echo "$input" | tr '[:upper:]' '[:lower:]')
|
|
29
|
-
|
|
30
|
-
# Look up in alias map
|
|
31
|
-
local canonical="${AGENT_ALIASES[$normalized]:-}"
|
|
32
|
-
|
|
33
|
-
if [[ -n "$canonical" ]]; then
|
|
34
|
-
echo "$canonical"
|
|
35
|
-
return 0
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
return 1
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
# is_valid_agent AGENT
|
|
42
|
-
# Checks if an agent name is valid (either canonical or alias)
|
|
43
|
-
# Returns: 0 if valid, 1 if invalid
|
|
44
|
-
is_valid_agent() {
|
|
45
|
-
local agent="$1"
|
|
46
|
-
resolve_agent "$agent" >/dev/null 2>&1
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
# get_agent_personality_path FORGE_ROOT AGENT
|
|
50
|
-
# Returns the path to an agent's personality file.
|
|
51
|
-
# Uses AGENT_PERSONALITY_FILES from constants.sh (or loaded from agents.json)
|
|
52
|
-
# SECURITY: Validates agent name before constructing path.
|
|
53
|
-
# Returns: full path on stdout
|
|
54
|
-
# Exit code: 0 on success, 1 if agent invalid or file missing
|
|
55
|
-
get_agent_personality_path() {
|
|
56
|
-
local forge_root="$1"
|
|
57
|
-
local agent="$2"
|
|
58
|
-
|
|
59
|
-
# Resolve and validate agent
|
|
60
|
-
local canonical
|
|
61
|
-
canonical=$(resolve_agent "$agent") || {
|
|
62
|
-
return 1
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
# Get personality file path from configuration
|
|
66
|
-
local relative_path="${AGENT_PERSONALITY_FILES[$canonical]:-}"
|
|
67
|
-
if [[ -z "$relative_path" ]]; then
|
|
68
|
-
# Fallback: construct path if not in config
|
|
69
|
-
relative_path="agents/$canonical/personality.md"
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
local personality_path="$forge_root/$relative_path"
|
|
73
|
-
|
|
74
|
-
# Validate file exists
|
|
75
|
-
if [[ ! -f "$personality_path" ]]; then
|
|
76
|
-
return 1
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
# SECURITY: Verify the resolved path is within agents directory
|
|
80
|
-
local real_path
|
|
81
|
-
real_path=$(cd "$(dirname "$personality_path")" 2>/dev/null && pwd)/$(basename "$personality_path")
|
|
82
|
-
local agents_dir
|
|
83
|
-
agents_dir=$(cd "$forge_root/agents" 2>/dev/null && pwd)
|
|
84
|
-
|
|
85
|
-
if [[ "$real_path" != "$agents_dir"/* ]]; then
|
|
86
|
-
echo "Security error: Path traversal detected" >&2
|
|
87
|
-
return 1
|
|
88
|
-
fi
|
|
89
|
-
|
|
90
|
-
echo "$personality_path"
|
|
91
|
-
return 0
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
# show_available_agents
|
|
95
|
-
# Prints a formatted list of available agents with aliases
|
|
96
|
-
# Uses data from AGENT_DISPLAY_NAMES, AGENT_ROLES, and AGENT_ALIASES
|
|
97
|
-
show_available_agents() {
|
|
98
|
-
echo "Available agents:"
|
|
99
|
-
|
|
100
|
-
# Iterate over valid agents (excluding hub for user display)
|
|
101
|
-
for agent in "${VALID_AGENTS[@]}"; do
|
|
102
|
-
if [[ "$agent" == "hub" ]]; then
|
|
103
|
-
continue
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
# Get display info
|
|
107
|
-
local role="${AGENT_ROLES[$agent]:-}"
|
|
108
|
-
|
|
109
|
-
# Collect aliases for this agent
|
|
110
|
-
local aliases=()
|
|
111
|
-
for alias in "${!AGENT_ALIASES[@]}"; do
|
|
112
|
-
if [[ "${AGENT_ALIASES[$alias]}" == "$agent" && "$alias" != "$agent" ]]; then
|
|
113
|
-
aliases+=("$alias")
|
|
114
|
-
fi
|
|
115
|
-
done
|
|
116
|
-
|
|
117
|
-
# Format aliases (take first 3)
|
|
118
|
-
local alias_str=""
|
|
119
|
-
if [[ ${#aliases[@]} -gt 0 ]]; then
|
|
120
|
-
# Sort and take first 3
|
|
121
|
-
IFS=$'\n' sorted=($(printf '%s\n' "${aliases[@]}" | sort)); unset IFS
|
|
122
|
-
local display_aliases=("${sorted[@]:0:3}")
|
|
123
|
-
alias_str="($(IFS=", "; echo "${display_aliases[*]}"))"
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
# Print formatted line
|
|
127
|
-
printf " %-9s %-25s - %s\n" "$agent" "$alias_str" "$role"
|
|
128
|
-
done
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
# get_agent_display_name AGENT
|
|
132
|
-
# Returns the display name for an agent (e.g., "Anvil" for "anvil")
|
|
133
|
-
# Uses AGENT_DISPLAY_NAMES from constants.sh (or loaded from agents.json)
|
|
134
|
-
get_agent_display_name() {
|
|
135
|
-
local agent="$1"
|
|
136
|
-
local canonical
|
|
137
|
-
canonical=$(resolve_agent "$agent") || return 1
|
|
138
|
-
|
|
139
|
-
# Look up in AGENT_DISPLAY_NAMES array
|
|
140
|
-
local display_name="${AGENT_DISPLAY_NAMES[$canonical]:-}"
|
|
141
|
-
if [[ -n "$display_name" ]]; then
|
|
142
|
-
echo "$display_name"
|
|
143
|
-
else
|
|
144
|
-
# Fallback to canonical name with first letter capitalized
|
|
145
|
-
echo "${canonical^}"
|
|
146
|
-
fi
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
# get_agent_role AGENT
|
|
150
|
-
# Returns the role description for an agent
|
|
151
|
-
get_agent_role() {
|
|
152
|
-
local agent="$1"
|
|
153
|
-
local canonical
|
|
154
|
-
canonical=$(resolve_agent "$agent") || return 1
|
|
155
|
-
|
|
156
|
-
echo "${AGENT_ROLES[$canonical]:-}"
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
# get_agent_icon AGENT
|
|
160
|
-
# Returns the icon/emoji for an agent
|
|
161
|
-
get_agent_icon() {
|
|
162
|
-
local agent="$1"
|
|
163
|
-
local canonical
|
|
164
|
-
canonical=$(resolve_agent "$agent") || return 1
|
|
165
|
-
|
|
166
|
-
echo "${AGENT_ICONS[$canonical]:-}"
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
# get_agent_tab_color AGENT
|
|
170
|
-
# Returns the Windows Terminal tab color for an agent (hex format)
|
|
171
|
-
get_agent_tab_color() {
|
|
172
|
-
local agent="$1"
|
|
173
|
-
local canonical
|
|
174
|
-
canonical=$(resolve_agent "$agent") || return 1
|
|
175
|
-
|
|
176
|
-
echo "${AGENT_TAB_COLORS[$canonical]:-}"
|
|
177
|
-
}
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Vibe Forge - Agent Resolution and Validation
|
|
4
|
+
# Source this file in other scripts: source "$SCRIPT_DIR/lib/agents.sh"
|
|
5
|
+
#
|
|
6
|
+
# SECURITY: This module provides safe agent name resolution with whitelist validation.
|
|
7
|
+
# Never pass user input directly to shell commands - always resolve through these functions.
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
# Ensure constants are loaded
|
|
11
|
+
if [[ -z "${VALID_AGENTS+x}" ]]; then
|
|
12
|
+
echo "Error: constants.sh must be sourced before agents.sh" >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# resolve_agent ALIAS
|
|
17
|
+
# Converts an agent alias to its canonical name.
|
|
18
|
+
# Returns: canonical name on stdout, empty string if not found
|
|
19
|
+
# Exit code: 0 if found, 1 if not found
|
|
20
|
+
#
|
|
21
|
+
# SECURITY: This function validates against a whitelist.
|
|
22
|
+
# The returned value is safe to use in file paths and commands.
|
|
23
|
+
resolve_agent() {
|
|
24
|
+
local input="$1"
|
|
25
|
+
|
|
26
|
+
# Normalize to lowercase for matching
|
|
27
|
+
local normalized
|
|
28
|
+
normalized=$(echo "$input" | tr '[:upper:]' '[:lower:]')
|
|
29
|
+
|
|
30
|
+
# Look up in alias map
|
|
31
|
+
local canonical="${AGENT_ALIASES[$normalized]:-}"
|
|
32
|
+
|
|
33
|
+
if [[ -n "$canonical" ]]; then
|
|
34
|
+
echo "$canonical"
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
return 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# is_valid_agent AGENT
|
|
42
|
+
# Checks if an agent name is valid (either canonical or alias)
|
|
43
|
+
# Returns: 0 if valid, 1 if invalid
|
|
44
|
+
is_valid_agent() {
|
|
45
|
+
local agent="$1"
|
|
46
|
+
resolve_agent "$agent" >/dev/null 2>&1
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# get_agent_personality_path FORGE_ROOT AGENT
|
|
50
|
+
# Returns the path to an agent's personality file.
|
|
51
|
+
# Uses AGENT_PERSONALITY_FILES from constants.sh (or loaded from agents.json)
|
|
52
|
+
# SECURITY: Validates agent name before constructing path.
|
|
53
|
+
# Returns: full path on stdout
|
|
54
|
+
# Exit code: 0 on success, 1 if agent invalid or file missing
|
|
55
|
+
get_agent_personality_path() {
|
|
56
|
+
local forge_root="$1"
|
|
57
|
+
local agent="$2"
|
|
58
|
+
|
|
59
|
+
# Resolve and validate agent
|
|
60
|
+
local canonical
|
|
61
|
+
canonical=$(resolve_agent "$agent") || {
|
|
62
|
+
return 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Get personality file path from configuration
|
|
66
|
+
local relative_path="${AGENT_PERSONALITY_FILES[$canonical]:-}"
|
|
67
|
+
if [[ -z "$relative_path" ]]; then
|
|
68
|
+
# Fallback: construct path if not in config
|
|
69
|
+
relative_path="agents/$canonical/personality.md"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
local personality_path="$forge_root/$relative_path"
|
|
73
|
+
|
|
74
|
+
# Validate file exists
|
|
75
|
+
if [[ ! -f "$personality_path" ]]; then
|
|
76
|
+
return 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# SECURITY: Verify the resolved path is within agents directory
|
|
80
|
+
local real_path
|
|
81
|
+
real_path=$(cd "$(dirname "$personality_path")" 2>/dev/null && pwd)/$(basename "$personality_path")
|
|
82
|
+
local agents_dir
|
|
83
|
+
agents_dir=$(cd "$forge_root/agents" 2>/dev/null && pwd)
|
|
84
|
+
|
|
85
|
+
if [[ "$real_path" != "$agents_dir"/* ]]; then
|
|
86
|
+
echo "Security error: Path traversal detected" >&2
|
|
87
|
+
return 1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
echo "$personality_path"
|
|
91
|
+
return 0
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# show_available_agents
|
|
95
|
+
# Prints a formatted list of available agents with aliases
|
|
96
|
+
# Uses data from AGENT_DISPLAY_NAMES, AGENT_ROLES, and AGENT_ALIASES
|
|
97
|
+
show_available_agents() {
|
|
98
|
+
echo "Available agents:"
|
|
99
|
+
|
|
100
|
+
# Iterate over valid agents (excluding hub for user display)
|
|
101
|
+
for agent in "${VALID_AGENTS[@]}"; do
|
|
102
|
+
if [[ "$agent" == "hub" ]]; then
|
|
103
|
+
continue
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# Get display info
|
|
107
|
+
local role="${AGENT_ROLES[$agent]:-}"
|
|
108
|
+
|
|
109
|
+
# Collect aliases for this agent
|
|
110
|
+
local aliases=()
|
|
111
|
+
for alias in "${!AGENT_ALIASES[@]}"; do
|
|
112
|
+
if [[ "${AGENT_ALIASES[$alias]}" == "$agent" && "$alias" != "$agent" ]]; then
|
|
113
|
+
aliases+=("$alias")
|
|
114
|
+
fi
|
|
115
|
+
done
|
|
116
|
+
|
|
117
|
+
# Format aliases (take first 3)
|
|
118
|
+
local alias_str=""
|
|
119
|
+
if [[ ${#aliases[@]} -gt 0 ]]; then
|
|
120
|
+
# Sort and take first 3
|
|
121
|
+
IFS=$'\n' sorted=($(printf '%s\n' "${aliases[@]}" | sort)); unset IFS
|
|
122
|
+
local display_aliases=("${sorted[@]:0:3}")
|
|
123
|
+
alias_str="($(IFS=", "; echo "${display_aliases[*]}"))"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Print formatted line
|
|
127
|
+
printf " %-9s %-25s - %s\n" "$agent" "$alias_str" "$role"
|
|
128
|
+
done
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# get_agent_display_name AGENT
|
|
132
|
+
# Returns the display name for an agent (e.g., "Anvil" for "anvil")
|
|
133
|
+
# Uses AGENT_DISPLAY_NAMES from constants.sh (or loaded from agents.json)
|
|
134
|
+
get_agent_display_name() {
|
|
135
|
+
local agent="$1"
|
|
136
|
+
local canonical
|
|
137
|
+
canonical=$(resolve_agent "$agent") || return 1
|
|
138
|
+
|
|
139
|
+
# Look up in AGENT_DISPLAY_NAMES array
|
|
140
|
+
local display_name="${AGENT_DISPLAY_NAMES[$canonical]:-}"
|
|
141
|
+
if [[ -n "$display_name" ]]; then
|
|
142
|
+
echo "$display_name"
|
|
143
|
+
else
|
|
144
|
+
# Fallback to canonical name with first letter capitalized
|
|
145
|
+
echo "${canonical^}"
|
|
146
|
+
fi
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# get_agent_role AGENT
|
|
150
|
+
# Returns the role description for an agent
|
|
151
|
+
get_agent_role() {
|
|
152
|
+
local agent="$1"
|
|
153
|
+
local canonical
|
|
154
|
+
canonical=$(resolve_agent "$agent") || return 1
|
|
155
|
+
|
|
156
|
+
echo "${AGENT_ROLES[$canonical]:-}"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# get_agent_icon AGENT
|
|
160
|
+
# Returns the icon/emoji for an agent
|
|
161
|
+
get_agent_icon() {
|
|
162
|
+
local agent="$1"
|
|
163
|
+
local canonical
|
|
164
|
+
canonical=$(resolve_agent "$agent") || return 1
|
|
165
|
+
|
|
166
|
+
echo "${AGENT_ICONS[$canonical]:-}"
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# get_agent_tab_color AGENT
|
|
170
|
+
# Returns the Windows Terminal tab color for an agent (hex format)
|
|
171
|
+
get_agent_tab_color() {
|
|
172
|
+
local agent="$1"
|
|
173
|
+
local canonical
|
|
174
|
+
canonical=$(resolve_agent "$agent") || return 1
|
|
175
|
+
|
|
176
|
+
echo "${AGENT_TAB_COLORS[$canonical]:-}"
|
|
177
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent alias collision detector.
|
|
4
|
+
*
|
|
5
|
+
* Used by:
|
|
6
|
+
* - .husky/pre-commit (pre-commit hook)
|
|
7
|
+
* - .github/workflows/ci.yml (CI lint job)
|
|
8
|
+
* - bin/cli.js validateAgentsConfig() (forge init)
|
|
9
|
+
*
|
|
10
|
+
* Exit code 0: no collisions
|
|
11
|
+
* Exit code 1: collisions found (printed to stderr)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
|
|
17
|
+
const configPath = process.argv[2] || path.join(__dirname, '..', '..', 'config', 'agents.json');
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(configPath)) {
|
|
20
|
+
// No agents.json is fine (e.g., fresh clone before setup)
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let config;
|
|
25
|
+
try {
|
|
26
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.error(`ERROR: Failed to parse ${configPath}: ${err.message}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const agents = config.agents || {};
|
|
33
|
+
const seen = {};
|
|
34
|
+
const dupes = [];
|
|
35
|
+
|
|
36
|
+
for (const [name, info] of Object.entries(agents)) {
|
|
37
|
+
for (const alias of [name, ...(info.aliases || [])]) {
|
|
38
|
+
if (seen[alias] && seen[alias] !== name) {
|
|
39
|
+
dupes.push(`${alias} (${seen[alias]} vs ${name})`);
|
|
40
|
+
}
|
|
41
|
+
seen[alias] = name;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (dupes.length) {
|
|
46
|
+
console.error(`ERROR: Alias collision in agents.json: ${dupes.join(', ')}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(`No alias collisions found (${Object.keys(agents).length} agents checked)`);
|
package/bin/lib/colors.sh
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Vibe Forge - Shared Color Definitions and Logging
|
|
4
|
-
# Source this file in other scripts: source "$SCRIPT_DIR/lib/colors.sh"
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
# Colors (only if terminal supports them)
|
|
8
|
-
if [[ -t 1 ]]; then
|
|
9
|
-
RED='\033[0;31m'
|
|
10
|
-
GREEN='\033[0;32m'
|
|
11
|
-
YELLOW='\033[1;33m'
|
|
12
|
-
BLUE='\033[0;34m'
|
|
13
|
-
CYAN='\033[0;36m'
|
|
14
|
-
NC='\033[0m'
|
|
15
|
-
else
|
|
16
|
-
RED=''
|
|
17
|
-
GREEN=''
|
|
18
|
-
YELLOW=''
|
|
19
|
-
BLUE=''
|
|
20
|
-
CYAN=''
|
|
21
|
-
NC=''
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
# Logging functions
|
|
25
|
-
log_error() {
|
|
26
|
-
echo -e "${RED}Error: $1${NC}" >&2
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
log_success() {
|
|
30
|
-
echo -e "${GREEN}✓ $1${NC}"
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
log_info() {
|
|
34
|
-
echo -e "${BLUE}ℹ $1${NC}"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
log_warn() {
|
|
38
|
-
echo -e "${YELLOW}⚠ $1${NC}"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
log_header() {
|
|
42
|
-
echo -e "${YELLOW}$1${NC}"
|
|
43
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
44
|
-
}
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Vibe Forge - Shared Color Definitions and Logging
|
|
4
|
+
# Source this file in other scripts: source "$SCRIPT_DIR/lib/colors.sh"
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
# Colors (only if terminal supports them)
|
|
8
|
+
if [[ -t 1 ]]; then
|
|
9
|
+
RED='\033[0;31m'
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
BLUE='\033[0;34m'
|
|
13
|
+
CYAN='\033[0;36m'
|
|
14
|
+
NC='\033[0m'
|
|
15
|
+
else
|
|
16
|
+
RED=''
|
|
17
|
+
GREEN=''
|
|
18
|
+
YELLOW=''
|
|
19
|
+
BLUE=''
|
|
20
|
+
CYAN=''
|
|
21
|
+
NC=''
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Logging functions
|
|
25
|
+
log_error() {
|
|
26
|
+
echo -e "${RED}Error: $1${NC}" >&2
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
log_success() {
|
|
30
|
+
echo -e "${GREEN}✓ $1${NC}"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
log_info() {
|
|
34
|
+
echo -e "${BLUE}ℹ $1${NC}"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
log_warn() {
|
|
38
|
+
echo -e "${YELLOW}⚠ $1${NC}"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
log_header() {
|
|
42
|
+
echo -e "${YELLOW}$1${NC}"
|
|
43
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
44
|
+
}
|