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
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
+ }