agileflow 2.94.1 → 2.95.0
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/CHANGELOG.md +15 -0
- package/lib/colors.generated.js +117 -0
- package/lib/colors.js +59 -109
- package/lib/generator-factory.js +333 -0
- package/lib/path-utils.js +49 -0
- package/lib/session-registry.js +25 -15
- package/lib/smart-json-file.js +40 -32
- package/lib/state-machine.js +286 -0
- package/package.json +1 -1
- package/scripts/agileflow-configure.js +7 -6
- package/scripts/archive-completed-stories.sh +86 -11
- package/scripts/babysit-context-restore.js +89 -0
- package/scripts/claude-tmux.sh +111 -5
- package/scripts/damage-control/bash-tool-damage-control.js +11 -247
- package/scripts/damage-control/edit-tool-damage-control.js +9 -249
- package/scripts/damage-control/write-tool-damage-control.js +9 -244
- package/scripts/generate-colors.js +314 -0
- package/scripts/lib/colors.generated.sh +82 -0
- package/scripts/lib/colors.sh +10 -70
- package/scripts/lib/configure-features.js +401 -0
- package/scripts/lib/context-loader.js +181 -52
- package/scripts/precompact-context.sh +54 -17
- package/scripts/session-coordinator.sh +2 -2
- package/scripts/session-manager.js +653 -10
- package/src/core/commands/audit.md +93 -0
- package/src/core/commands/auto.md +73 -0
- package/src/core/commands/babysit.md +169 -13
- package/src/core/commands/baseline.md +73 -0
- package/src/core/commands/batch.md +64 -0
- package/src/core/commands/blockers.md +60 -0
- package/src/core/commands/board.md +66 -0
- package/src/core/commands/choose.md +77 -0
- package/src/core/commands/ci.md +77 -0
- package/src/core/commands/compress.md +27 -1
- package/src/core/commands/configure.md +126 -10
- package/src/core/commands/council.md +74 -0
- package/src/core/commands/debt.md +72 -0
- package/src/core/commands/deploy.md +73 -0
- package/src/core/commands/deps.md +68 -0
- package/src/core/commands/docs.md +60 -0
- package/src/core/commands/feedback.md +68 -0
- package/src/core/commands/ideate.md +74 -0
- package/src/core/commands/impact.md +74 -0
- package/src/core/commands/install.md +529 -0
- package/src/core/commands/maintain.md +558 -0
- package/src/core/commands/metrics.md +75 -0
- package/src/core/commands/multi-expert.md +74 -0
- package/src/core/commands/packages.md +69 -0
- package/src/core/commands/readme-sync.md +64 -0
- package/src/core/commands/research/analyze.md +285 -121
- package/src/core/commands/research/import.md +281 -109
- package/src/core/commands/retro.md +76 -0
- package/src/core/commands/review.md +72 -0
- package/src/core/commands/rlm.md +83 -0
- package/src/core/commands/rpi.md +90 -0
- package/src/core/commands/session/cleanup.md +214 -12
- package/src/core/commands/session/end.md +155 -17
- package/src/core/commands/sprint.md +72 -0
- package/src/core/commands/story-validate.md +68 -0
- package/src/core/commands/template.md +69 -0
- package/src/core/commands/tests.md +83 -0
- package/src/core/commands/update.md +59 -0
- package/src/core/commands/validate-expertise.md +76 -0
- package/src/core/commands/velocity.md +74 -0
- package/src/core/commands/verify.md +91 -0
- package/src/core/commands/whats-new.md +69 -0
- package/src/core/commands/workflow.md +88 -0
- package/src/core/templates/command-documentation.md +187 -0
- package/tools/cli/commands/session.js +1171 -0
- package/tools/cli/commands/setup.js +2 -81
- package/tools/cli/installers/core/installer.js +0 -5
- package/tools/cli/installers/ide/claude-code.js +6 -0
- package/tools/cli/lib/config-manager.js +42 -5
|
@@ -1,254 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* write-tool-damage-control.js -
|
|
4
|
+
* write-tool-damage-control.js - PreToolUse hook for Write tool
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* to protected paths.
|
|
9
|
-
*
|
|
10
|
-
* Path protection levels:
|
|
11
|
-
* zeroAccessPaths: Cannot read, write, edit, or delete
|
|
12
|
-
* readOnlyPaths: Can read, cannot write or delete
|
|
13
|
-
* noDeletePaths: Can read and write, cannot delete (Write is allowed)
|
|
6
|
+
* Validates file paths against access control patterns in damage-control-patterns.yaml
|
|
7
|
+
* before allowing file writes. Part of AgileFlow's damage control system.
|
|
14
8
|
*
|
|
15
9
|
* Exit codes:
|
|
16
|
-
* 0
|
|
17
|
-
* 2
|
|
18
|
-
*
|
|
19
|
-
* Usage (as PreToolUse hook):
|
|
20
|
-
* node .claude/hooks/damage-control/write-tool-damage-control.js
|
|
10
|
+
* 0 - Allow operation
|
|
11
|
+
* 2 - Block operation
|
|
21
12
|
*
|
|
22
|
-
*
|
|
23
|
-
* CLAUDE_TOOL_INPUT - JSON string with tool input (contains "file_path")
|
|
24
|
-
* CLAUDE_PROJECT_DIR - Project root directory
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
const fs = require('fs');
|
|
28
|
-
const path = require('path');
|
|
29
|
-
|
|
30
|
-
// ANSI colors for output
|
|
31
|
-
const c = {
|
|
32
|
-
reset: '\x1b[0m',
|
|
33
|
-
bold: '\x1b[1m',
|
|
34
|
-
red: '\x1b[31m',
|
|
35
|
-
yellow: '\x1b[33m',
|
|
36
|
-
cyan: '\x1b[36m',
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Exit codes
|
|
40
|
-
const EXIT_ALLOW = 0;
|
|
41
|
-
const EXIT_BLOCK = 2;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Load path protection rules from patterns.yaml
|
|
45
|
-
*/
|
|
46
|
-
function loadPathRules(projectDir) {
|
|
47
|
-
const locations = [
|
|
48
|
-
path.join(projectDir, '.claude/hooks/damage-control/patterns.yaml'),
|
|
49
|
-
path.join(projectDir, '.agileflow/hooks/damage-control/patterns.yaml'),
|
|
50
|
-
path.join(projectDir, 'patterns.yaml'),
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
for (const loc of locations) {
|
|
54
|
-
if (fs.existsSync(loc)) {
|
|
55
|
-
try {
|
|
56
|
-
const content = fs.readFileSync(loc, 'utf8');
|
|
57
|
-
return parsePathRules(content);
|
|
58
|
-
} catch (e) {
|
|
59
|
-
console.error(`Warning: Could not parse ${loc}: ${e.message}`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return getDefaultPathRules();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Parse path rules from YAML content
|
|
13
|
+
* Usage: Configured as PreToolUse hook in .claude/settings.json
|
|
69
14
|
*/
|
|
70
|
-
function parsePathRules(content) {
|
|
71
|
-
const rules = {
|
|
72
|
-
zeroAccessPaths: [],
|
|
73
|
-
readOnlyPaths: [],
|
|
74
|
-
noDeletePaths: [],
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
let currentSection = null;
|
|
78
|
-
|
|
79
|
-
const lines = content.split('\n');
|
|
80
|
-
|
|
81
|
-
for (const line of lines) {
|
|
82
|
-
if (line.trim().startsWith('#') || line.trim() === '') continue;
|
|
83
|
-
|
|
84
|
-
if (line.match(/^zeroAccessPaths:/)) {
|
|
85
|
-
currentSection = 'zeroAccessPaths';
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
if (line.match(/^readOnlyPaths:/)) {
|
|
89
|
-
currentSection = 'readOnlyPaths';
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
if (line.match(/^noDeletePaths:/)) {
|
|
93
|
-
currentSection = 'noDeletePaths';
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (line.match(/^(bashToolPatterns|askPatterns|agileflowPatterns|config):/)) {
|
|
97
|
-
currentSection = null;
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (currentSection && rules[currentSection]) {
|
|
102
|
-
const pathMatch = line.match(/^\s+-\s*['"]?(.+?)['"]?\s*$/);
|
|
103
|
-
if (pathMatch) {
|
|
104
|
-
rules[currentSection].push(pathMatch[1]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return rules;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Default path rules if patterns.yaml not found
|
|
114
|
-
*/
|
|
115
|
-
function getDefaultPathRules() {
|
|
116
|
-
return {
|
|
117
|
-
zeroAccessPaths: ['~/.ssh/', '~/.aws/credentials', '.env', '.env.local', '.env.production'],
|
|
118
|
-
readOnlyPaths: ['/etc/', '~/.bashrc', '~/.zshrc', 'package-lock.json', 'yarn.lock', '.git/'],
|
|
119
|
-
noDeletePaths: ['.agileflow/', '.claude/', 'docs/09-agents/status.json', 'CLAUDE.md'],
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Expand home directory in path
|
|
125
|
-
*/
|
|
126
|
-
function expandHome(filePath) {
|
|
127
|
-
if (filePath.startsWith('~/')) {
|
|
128
|
-
return path.join(process.env.HOME || '', filePath.slice(2));
|
|
129
|
-
}
|
|
130
|
-
return filePath;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Check if a file path matches a pattern
|
|
135
|
-
*/
|
|
136
|
-
function pathMatches(filePath, pattern) {
|
|
137
|
-
const expandedPattern = expandHome(pattern);
|
|
138
|
-
const normalizedFile = path.normalize(filePath);
|
|
139
|
-
const normalizedPattern = path.normalize(expandedPattern);
|
|
140
|
-
|
|
141
|
-
// Exact match
|
|
142
|
-
if (normalizedFile === normalizedPattern) return true;
|
|
143
|
-
|
|
144
|
-
// Directory prefix match
|
|
145
|
-
if (pattern.endsWith('/')) {
|
|
146
|
-
if (normalizedFile.startsWith(normalizedPattern)) return true;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Glob pattern (**)
|
|
150
|
-
if (pattern.includes('**/')) {
|
|
151
|
-
const globPart = pattern.split('**/')[1];
|
|
152
|
-
if (normalizedFile.includes(globPart)) return true;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Wildcard at end
|
|
156
|
-
if (pattern.endsWith('*')) {
|
|
157
|
-
const prefix = normalizedPattern.slice(0, -1);
|
|
158
|
-
if (normalizedFile.startsWith(prefix)) return true;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Basename match
|
|
162
|
-
if (!pattern.includes('/') && !pattern.includes(path.sep)) {
|
|
163
|
-
const basename = path.basename(normalizedFile);
|
|
164
|
-
if (basename === pattern) return true;
|
|
165
|
-
if (pattern.endsWith('*')) {
|
|
166
|
-
const patternBase = pattern.slice(0, -1);
|
|
167
|
-
if (basename.startsWith(patternBase)) return true;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Check if file path is protected for writing
|
|
176
|
-
* Returns: { blocked: boolean, reason: string, level: string }
|
|
177
|
-
*/
|
|
178
|
-
function checkPath(filePath, rules) {
|
|
179
|
-
// Check zero access paths (blocked completely)
|
|
180
|
-
for (const pattern of rules.zeroAccessPaths) {
|
|
181
|
-
if (pathMatches(filePath, pattern)) {
|
|
182
|
-
return {
|
|
183
|
-
blocked: true,
|
|
184
|
-
reason: `Path is in zero-access protected list: ${pattern}`,
|
|
185
|
-
level: 'zero-access',
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Check read-only paths (cannot write)
|
|
191
|
-
for (const pattern of rules.readOnlyPaths) {
|
|
192
|
-
if (pathMatches(filePath, pattern)) {
|
|
193
|
-
return {
|
|
194
|
-
blocked: true,
|
|
195
|
-
reason: `Path is read-only: ${pattern}`,
|
|
196
|
-
level: 'read-only',
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// noDeletePaths allows writing, only blocks deletion
|
|
202
|
-
// so we don't block writes here
|
|
203
|
-
|
|
204
|
-
return { blocked: false, reason: null, level: null };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Main entry point
|
|
209
|
-
*/
|
|
210
|
-
function main() {
|
|
211
|
-
const toolInput = process.env.CLAUDE_TOOL_INPUT;
|
|
212
|
-
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
213
|
-
|
|
214
|
-
if (!toolInput) {
|
|
215
|
-
process.exit(EXIT_ALLOW);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
let input;
|
|
219
|
-
try {
|
|
220
|
-
input = JSON.parse(toolInput);
|
|
221
|
-
} catch (e) {
|
|
222
|
-
console.error('Error parsing CLAUDE_TOOL_INPUT:', e.message);
|
|
223
|
-
process.exit(EXIT_ALLOW);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const filePath = input.file_path;
|
|
227
|
-
if (!filePath) {
|
|
228
|
-
process.exit(EXIT_ALLOW);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Resolve to absolute path
|
|
232
|
-
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(projectDir, filePath);
|
|
233
|
-
|
|
234
|
-
// Load rules
|
|
235
|
-
const rules = loadPathRules(projectDir);
|
|
236
|
-
|
|
237
|
-
// Check path
|
|
238
|
-
const result = checkPath(absolutePath, rules);
|
|
239
|
-
|
|
240
|
-
if (result.blocked) {
|
|
241
|
-
console.error(`${c.red}${c.bold}BLOCKED${c.reset}: ${result.reason}`);
|
|
242
|
-
console.error(`${c.yellow}File: ${filePath}${c.reset}`);
|
|
243
|
-
console.error(`${c.cyan}This file is protected by damage control (${result.level}).${c.reset}`);
|
|
244
|
-
process.exit(EXIT_BLOCK);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
process.exit(EXIT_ALLOW);
|
|
248
|
-
}
|
|
249
15
|
|
|
250
|
-
|
|
251
|
-
main();
|
|
252
|
-
}
|
|
16
|
+
const { createPathHook } = require('../lib/damage-control-utils');
|
|
253
17
|
|
|
254
|
-
|
|
18
|
+
// Run the hook using factory
|
|
19
|
+
createPathHook('write')();
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* generate-colors.js - Generate color files from YAML config
|
|
5
|
+
*
|
|
6
|
+
* Reads config/colors.yaml and generates:
|
|
7
|
+
* - lib/colors.js (JavaScript module)
|
|
8
|
+
* - scripts/lib/colors.sh (Bash script)
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/generate-colors.js
|
|
12
|
+
* node scripts/generate-colors.js --check # Verify files are up-to-date
|
|
13
|
+
*
|
|
14
|
+
* This ensures a single source of truth for all color definitions.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { safeLoad } = require('../lib/yaml-utils');
|
|
20
|
+
|
|
21
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
22
|
+
const CONFIG_PATH = path.join(ROOT, 'config', 'colors.yaml');
|
|
23
|
+
const JS_OUTPUT = path.join(ROOT, 'lib', 'colors.generated.js');
|
|
24
|
+
const SH_OUTPUT = path.join(ROOT, 'scripts', 'lib', 'colors.generated.sh');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Load colors configuration from YAML
|
|
28
|
+
* @returns {Object} Colors configuration
|
|
29
|
+
*/
|
|
30
|
+
function loadConfig() {
|
|
31
|
+
const content = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
32
|
+
return safeLoad(content);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generate JavaScript module content
|
|
37
|
+
* @param {Object} config - Colors configuration
|
|
38
|
+
* @returns {string} JavaScript module content
|
|
39
|
+
*/
|
|
40
|
+
function generateJS(config) {
|
|
41
|
+
const lines = [
|
|
42
|
+
'/**',
|
|
43
|
+
' * colors.generated.js - Auto-generated from config/colors.yaml',
|
|
44
|
+
' *',
|
|
45
|
+
' * DO NOT EDIT THIS FILE DIRECTLY.',
|
|
46
|
+
' * Run: node scripts/generate-colors.js',
|
|
47
|
+
' *',
|
|
48
|
+
` * Generated: ${new Date().toISOString()}`,
|
|
49
|
+
' */',
|
|
50
|
+
'',
|
|
51
|
+
"'use strict';",
|
|
52
|
+
'',
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// Brand color
|
|
56
|
+
lines.push(`// Brand color`);
|
|
57
|
+
lines.push(`const BRAND_HEX = '${config.brand.hex}';`);
|
|
58
|
+
lines.push('');
|
|
59
|
+
|
|
60
|
+
// Modifiers
|
|
61
|
+
lines.push('// Modifiers');
|
|
62
|
+
lines.push('const modifiers = {');
|
|
63
|
+
for (const [name, code] of Object.entries(config.modifiers)) {
|
|
64
|
+
lines.push(` ${name}: '\\x1b[${code}m',`);
|
|
65
|
+
}
|
|
66
|
+
lines.push('};');
|
|
67
|
+
lines.push('');
|
|
68
|
+
|
|
69
|
+
// Standard colors
|
|
70
|
+
lines.push('// Standard ANSI colors');
|
|
71
|
+
lines.push('const standard = {');
|
|
72
|
+
for (const [name, code] of Object.entries(config.standard)) {
|
|
73
|
+
lines.push(` ${name}: '\\x1b[${code}m',`);
|
|
74
|
+
}
|
|
75
|
+
lines.push('};');
|
|
76
|
+
lines.push('');
|
|
77
|
+
|
|
78
|
+
// Bright colors
|
|
79
|
+
lines.push('// Bright ANSI colors');
|
|
80
|
+
lines.push('const bright = {');
|
|
81
|
+
for (const [name, code] of Object.entries(config.bright)) {
|
|
82
|
+
lines.push(` bright${name.charAt(0).toUpperCase() + name.slice(1)}: '\\x1b[${code}m',`);
|
|
83
|
+
}
|
|
84
|
+
lines.push('};');
|
|
85
|
+
lines.push('');
|
|
86
|
+
|
|
87
|
+
// 256-color palette
|
|
88
|
+
lines.push('// 256-color palette');
|
|
89
|
+
lines.push('const palette256 = {');
|
|
90
|
+
for (const [name, def] of Object.entries(config.palette256)) {
|
|
91
|
+
const comment = def.comment ? ` // ${def.comment}` : '';
|
|
92
|
+
lines.push(` ${name}: '\\x1b[${def.code}m',${comment}`);
|
|
93
|
+
}
|
|
94
|
+
lines.push('};');
|
|
95
|
+
lines.push('');
|
|
96
|
+
|
|
97
|
+
// Background colors
|
|
98
|
+
lines.push('// Background colors');
|
|
99
|
+
lines.push('const backgrounds = {');
|
|
100
|
+
for (const [name, code] of Object.entries(config.backgrounds)) {
|
|
101
|
+
lines.push(` bg${name.charAt(0).toUpperCase() + name.slice(1)}: '\\x1b[${code}m',`);
|
|
102
|
+
}
|
|
103
|
+
lines.push('};');
|
|
104
|
+
lines.push('');
|
|
105
|
+
|
|
106
|
+
// Brand color ANSI
|
|
107
|
+
lines.push('// Brand color ANSI');
|
|
108
|
+
lines.push(`const brand = '\\x1b[${config.brand.ansi}m';`);
|
|
109
|
+
lines.push('');
|
|
110
|
+
|
|
111
|
+
// High contrast colors
|
|
112
|
+
lines.push('// High-contrast mode colors (WCAG AAA)');
|
|
113
|
+
lines.push('const highContrast = {');
|
|
114
|
+
for (const [name, code] of Object.entries(config.highContrast)) {
|
|
115
|
+
lines.push(` ${name}: '\\x1b[${code}m',`);
|
|
116
|
+
}
|
|
117
|
+
lines.push('};');
|
|
118
|
+
lines.push('');
|
|
119
|
+
|
|
120
|
+
// Combined cStandard object (for backward compatibility)
|
|
121
|
+
lines.push('// Combined standard color palette');
|
|
122
|
+
lines.push('const cStandard = {');
|
|
123
|
+
lines.push(' ...modifiers,');
|
|
124
|
+
lines.push(' ...standard,');
|
|
125
|
+
lines.push(' ...bright,');
|
|
126
|
+
lines.push(' ...palette256,');
|
|
127
|
+
lines.push(' ...backgrounds,');
|
|
128
|
+
lines.push(' brand,');
|
|
129
|
+
lines.push(` orange: brand, // Alias`);
|
|
130
|
+
lines.push(' // Semantic aliases');
|
|
131
|
+
for (const [semantic, target] of Object.entries(config.semantic)) {
|
|
132
|
+
lines.push(` ${semantic}: standard.${target},`);
|
|
133
|
+
}
|
|
134
|
+
lines.push('};');
|
|
135
|
+
lines.push('');
|
|
136
|
+
|
|
137
|
+
// Exports
|
|
138
|
+
lines.push('module.exports = {');
|
|
139
|
+
lines.push(' BRAND_HEX,');
|
|
140
|
+
lines.push(' modifiers,');
|
|
141
|
+
lines.push(' standard,');
|
|
142
|
+
lines.push(' bright,');
|
|
143
|
+
lines.push(' palette256,');
|
|
144
|
+
lines.push(' backgrounds,');
|
|
145
|
+
lines.push(' brand,');
|
|
146
|
+
lines.push(' highContrast,');
|
|
147
|
+
lines.push(' cStandard,');
|
|
148
|
+
lines.push('};');
|
|
149
|
+
lines.push('');
|
|
150
|
+
|
|
151
|
+
return lines.join('\n');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Generate Bash script content
|
|
156
|
+
* @param {Object} config - Colors configuration
|
|
157
|
+
* @returns {string} Bash script content
|
|
158
|
+
*/
|
|
159
|
+
function generateSH(config) {
|
|
160
|
+
const lines = [
|
|
161
|
+
'#!/bin/bash',
|
|
162
|
+
'# colors.generated.sh - Auto-generated from config/colors.yaml',
|
|
163
|
+
'#',
|
|
164
|
+
'# DO NOT EDIT THIS FILE DIRECTLY.',
|
|
165
|
+
'# Run: node scripts/generate-colors.js',
|
|
166
|
+
'#',
|
|
167
|
+
`# Generated: ${new Date().toISOString()}`,
|
|
168
|
+
'#',
|
|
169
|
+
'# Usage: source "$(dirname "${BASH_SOURCE[0]}")/colors.generated.sh"',
|
|
170
|
+
'',
|
|
171
|
+
'# ============================================================================',
|
|
172
|
+
'# Modifiers',
|
|
173
|
+
'# ============================================================================',
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
for (const [name, code] of Object.entries(config.modifiers)) {
|
|
177
|
+
lines.push(`${name.toUpperCase()}="\\033[${code}m"`);
|
|
178
|
+
}
|
|
179
|
+
lines.push('');
|
|
180
|
+
|
|
181
|
+
lines.push('# ============================================================================');
|
|
182
|
+
lines.push('# Standard ANSI Colors');
|
|
183
|
+
lines.push('# ============================================================================');
|
|
184
|
+
for (const [name, code] of Object.entries(config.standard)) {
|
|
185
|
+
lines.push(`${name.toUpperCase()}="\\033[${code}m"`);
|
|
186
|
+
}
|
|
187
|
+
lines.push('');
|
|
188
|
+
|
|
189
|
+
lines.push('# ============================================================================');
|
|
190
|
+
lines.push('# Bright Variants');
|
|
191
|
+
lines.push('# ============================================================================');
|
|
192
|
+
for (const [name, code] of Object.entries(config.bright)) {
|
|
193
|
+
lines.push(`BRIGHT_${name.toUpperCase()}="\\033[${code}m"`);
|
|
194
|
+
}
|
|
195
|
+
lines.push('');
|
|
196
|
+
|
|
197
|
+
lines.push('# ============================================================================');
|
|
198
|
+
lines.push('# Semantic Aliases');
|
|
199
|
+
lines.push('# ============================================================================');
|
|
200
|
+
for (const [semantic, target] of Object.entries(config.semantic)) {
|
|
201
|
+
lines.push(`${semantic.toUpperCase()}="$${target.toUpperCase()}"`);
|
|
202
|
+
}
|
|
203
|
+
lines.push('');
|
|
204
|
+
|
|
205
|
+
lines.push('# ============================================================================');
|
|
206
|
+
lines.push('# 256-Color Palette');
|
|
207
|
+
lines.push('# ============================================================================');
|
|
208
|
+
for (const [name, def] of Object.entries(config.palette256)) {
|
|
209
|
+
const varName = name.replace(/([A-Z])/g, '_$1').toUpperCase();
|
|
210
|
+
const comment = def.comment ? ` # ${def.comment}` : '';
|
|
211
|
+
lines.push(`${varName}="\\033[${def.code}m"${comment}`);
|
|
212
|
+
}
|
|
213
|
+
lines.push('');
|
|
214
|
+
|
|
215
|
+
lines.push('# ============================================================================');
|
|
216
|
+
lines.push('# Brand Color');
|
|
217
|
+
lines.push('# ============================================================================');
|
|
218
|
+
lines.push(`BRAND="\\033[${config.brand.ansi}m"`);
|
|
219
|
+
lines.push('ORANGE="$BRAND" # Alias');
|
|
220
|
+
lines.push('');
|
|
221
|
+
|
|
222
|
+
lines.push('# ============================================================================');
|
|
223
|
+
lines.push('# Background Colors');
|
|
224
|
+
lines.push('# ============================================================================');
|
|
225
|
+
for (const [name, code] of Object.entries(config.backgrounds)) {
|
|
226
|
+
lines.push(`BG_${name.toUpperCase()}="\\033[${code}m"`);
|
|
227
|
+
}
|
|
228
|
+
lines.push('');
|
|
229
|
+
|
|
230
|
+
return lines.join('\n');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Main function
|
|
235
|
+
*/
|
|
236
|
+
function main() {
|
|
237
|
+
const checkMode = process.argv.includes('--check');
|
|
238
|
+
|
|
239
|
+
console.log('🎨 Color Generator');
|
|
240
|
+
console.log('==================');
|
|
241
|
+
console.log(`Config: ${CONFIG_PATH}`);
|
|
242
|
+
|
|
243
|
+
// Load configuration
|
|
244
|
+
const config = loadConfig();
|
|
245
|
+
console.log('✓ Loaded colors.yaml');
|
|
246
|
+
|
|
247
|
+
// Generate content
|
|
248
|
+
const jsContent = generateJS(config);
|
|
249
|
+
const shContent = generateSH(config);
|
|
250
|
+
|
|
251
|
+
if (checkMode) {
|
|
252
|
+
// Check if files are up-to-date
|
|
253
|
+
let upToDate = true;
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
const existingJS = fs.readFileSync(JS_OUTPUT, 'utf8');
|
|
257
|
+
// Compare without timestamp line
|
|
258
|
+
const normalizeJS = content =>
|
|
259
|
+
content
|
|
260
|
+
.split('\n')
|
|
261
|
+
.filter(line => !line.includes('Generated:'))
|
|
262
|
+
.join('\n');
|
|
263
|
+
if (normalizeJS(existingJS) !== normalizeJS(jsContent)) {
|
|
264
|
+
console.log('✗ lib/colors.generated.js is out of date');
|
|
265
|
+
upToDate = false;
|
|
266
|
+
} else {
|
|
267
|
+
console.log('✓ lib/colors.generated.js is up to date');
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
console.log('✗ lib/colors.generated.js does not exist');
|
|
271
|
+
upToDate = false;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const existingSH = fs.readFileSync(SH_OUTPUT, 'utf8');
|
|
276
|
+
const normalizeSH = content =>
|
|
277
|
+
content
|
|
278
|
+
.split('\n')
|
|
279
|
+
.filter(line => !line.includes('Generated:'))
|
|
280
|
+
.join('\n');
|
|
281
|
+
if (normalizeSH(existingSH) !== normalizeSH(shContent)) {
|
|
282
|
+
console.log('✗ scripts/lib/colors.generated.sh is out of date');
|
|
283
|
+
upToDate = false;
|
|
284
|
+
} else {
|
|
285
|
+
console.log('✓ scripts/lib/colors.generated.sh is up to date');
|
|
286
|
+
}
|
|
287
|
+
} catch {
|
|
288
|
+
console.log('✗ scripts/lib/colors.generated.sh does not exist');
|
|
289
|
+
upToDate = false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!upToDate) {
|
|
293
|
+
console.log('\nRun: node scripts/generate-colors.js');
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
console.log('\n✓ All color files are up to date');
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Write files
|
|
301
|
+
fs.writeFileSync(JS_OUTPUT, jsContent);
|
|
302
|
+
console.log(`✓ Generated ${JS_OUTPUT}`);
|
|
303
|
+
|
|
304
|
+
fs.writeFileSync(SH_OUTPUT, shContent);
|
|
305
|
+
console.log(`✓ Generated ${SH_OUTPUT}`);
|
|
306
|
+
|
|
307
|
+
console.log('\n✓ Color generation complete!');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (require.main === module) {
|
|
311
|
+
main();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
module.exports = { loadConfig, generateJS, generateSH };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# colors.generated.sh - Auto-generated from config/colors.yaml
|
|
3
|
+
#
|
|
4
|
+
# DO NOT EDIT THIS FILE DIRECTLY.
|
|
5
|
+
# Run: node scripts/generate-colors.js
|
|
6
|
+
#
|
|
7
|
+
# Generated: 2026-01-29T08:28:33.726Z
|
|
8
|
+
#
|
|
9
|
+
# Usage: source "$(dirname "${BASH_SOURCE[0]}")/colors.generated.sh"
|
|
10
|
+
|
|
11
|
+
# ============================================================================
|
|
12
|
+
# Modifiers
|
|
13
|
+
# ============================================================================
|
|
14
|
+
RESET="\033[0m"
|
|
15
|
+
BOLD="\033[1m"
|
|
16
|
+
DIM="\033[2m"
|
|
17
|
+
ITALIC="\033[3m"
|
|
18
|
+
UNDERLINE="\033[4m"
|
|
19
|
+
|
|
20
|
+
# ============================================================================
|
|
21
|
+
# Standard ANSI Colors
|
|
22
|
+
# ============================================================================
|
|
23
|
+
RED="\033[31m"
|
|
24
|
+
GREEN="\033[32m"
|
|
25
|
+
YELLOW="\033[33m"
|
|
26
|
+
BLUE="\033[34m"
|
|
27
|
+
MAGENTA="\033[35m"
|
|
28
|
+
CYAN="\033[36m"
|
|
29
|
+
WHITE="\033[37m"
|
|
30
|
+
BLACK="\033[30m"
|
|
31
|
+
|
|
32
|
+
# ============================================================================
|
|
33
|
+
# Bright Variants
|
|
34
|
+
# ============================================================================
|
|
35
|
+
BRIGHT_RED="\033[91m"
|
|
36
|
+
BRIGHT_GREEN="\033[92m"
|
|
37
|
+
BRIGHT_YELLOW="\033[93m"
|
|
38
|
+
BRIGHT_BLUE="\033[94m"
|
|
39
|
+
BRIGHT_MAGENTA="\033[95m"
|
|
40
|
+
BRIGHT_CYAN="\033[96m"
|
|
41
|
+
BRIGHT_WHITE="\033[97m"
|
|
42
|
+
BRIGHT_BLACK="\033[90m"
|
|
43
|
+
|
|
44
|
+
# ============================================================================
|
|
45
|
+
# Semantic Aliases
|
|
46
|
+
# ============================================================================
|
|
47
|
+
SUCCESS="$GREEN"
|
|
48
|
+
ERROR="$RED"
|
|
49
|
+
WARNING="$YELLOW"
|
|
50
|
+
INFO="$CYAN"
|
|
51
|
+
|
|
52
|
+
# ============================================================================
|
|
53
|
+
# 256-Color Palette
|
|
54
|
+
# ============================================================================
|
|
55
|
+
MINT_GREEN="\033[38;5;158m" # Healthy/success states
|
|
56
|
+
PEACH="\033[38;5;215m" # Warning states
|
|
57
|
+
CORAL="\033[38;5;203m" # Critical/error states
|
|
58
|
+
LIGHT_GREEN="\033[38;5;194m" # Session healthy
|
|
59
|
+
LIGHT_YELLOW="\033[38;5;228m" # Session warning
|
|
60
|
+
LIGHT_PINK="\033[38;5;210m" # Session critical
|
|
61
|
+
SKY_BLUE="\033[38;5;117m" # Directories/paths, ready states
|
|
62
|
+
LAVENDER="\033[38;5;147m" # Model info, story IDs
|
|
63
|
+
SOFT_GOLD="\033[38;5;222m" # Cost/money
|
|
64
|
+
TEAL="\033[38;5;80m" # Pending states
|
|
65
|
+
SLATE="\033[38;5;103m" # Secondary info
|
|
66
|
+
ROSE="\033[38;5;211m" # Blocked/critical accent
|
|
67
|
+
AMBER="\033[38;5;214m" # WIP/in-progress accent
|
|
68
|
+
POWDER="\033[38;5;153m" # Labels/headers
|
|
69
|
+
|
|
70
|
+
# ============================================================================
|
|
71
|
+
# Brand Color
|
|
72
|
+
# ============================================================================
|
|
73
|
+
BRAND="\033[38;2;232;104;58m"
|
|
74
|
+
ORANGE="$BRAND" # Alias
|
|
75
|
+
|
|
76
|
+
# ============================================================================
|
|
77
|
+
# Background Colors
|
|
78
|
+
# ============================================================================
|
|
79
|
+
BG_RED="\033[41m"
|
|
80
|
+
BG_GREEN="\033[42m"
|
|
81
|
+
BG_YELLOW="\033[43m"
|
|
82
|
+
BG_BLUE="\033[44m"
|