grimoire-framework 1.0.8 โ 1.0.10
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/.grimoire/install-manifest.yaml +2 -2
- package/bin/commands/update.js +251 -0
- package/bin/grimoire-cli.js +211 -7
- package/package.json +1 -1
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
# - SHA256 hashes for change detection
|
|
8
8
|
# - File types for categorization
|
|
9
9
|
#
|
|
10
|
-
version: 1.0.
|
|
11
|
-
generated_at: "2026-02-
|
|
10
|
+
version: 1.0.10
|
|
11
|
+
generated_at: "2026-02-22T12:13:30.092Z"
|
|
12
12
|
generator: scripts/generate-install-manifest.js
|
|
13
13
|
file_count: 1011
|
|
14
14
|
files:
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* grimoire Smart Update Command
|
|
5
|
+
* Updates grimoire-framework preserving project customizations.
|
|
6
|
+
*
|
|
7
|
+
* Strategy:
|
|
8
|
+
* 1. Check installed vs latest version on npm
|
|
9
|
+
* 2. npm install grimoire-framework@latest
|
|
10
|
+
* 3. Selectively copy framework files (agents, rules, hooks)
|
|
11
|
+
* - OVERWRITE files that are part of the framework source
|
|
12
|
+
* - PRESERVE files that only exist in the project (custom agents, etc.)
|
|
13
|
+
* 4. Report what was updated/preserved
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const https = require('https');
|
|
19
|
+
const { execSync } = require('child_process');
|
|
20
|
+
|
|
21
|
+
// Framework source directories (relative to node_modules/grimoire-framework)
|
|
22
|
+
const FRAMEWORK_SYNC_DIRS = [
|
|
23
|
+
{ src: '.codex/agents', dest: '.codex/agents' },
|
|
24
|
+
{ src: '.gemini/rules/grimoire', dest: '.gemini/rules/grimoire' },
|
|
25
|
+
{ src: '.cursor/rules/agents', dest: '.cursor/rules/agents' },
|
|
26
|
+
{ src: '.claude/commands/grimoire', dest: '.claude/commands/grimoire' },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Fetch latest version from npm registry
|
|
31
|
+
*/
|
|
32
|
+
function getLatestVersion() {
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
const req = https.get(
|
|
35
|
+
'https://registry.npmjs.org/grimoire-framework/latest',
|
|
36
|
+
{ timeout: 10000 },
|
|
37
|
+
(res) => {
|
|
38
|
+
let data = '';
|
|
39
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
40
|
+
res.on('end', () => {
|
|
41
|
+
try { resolve(JSON.parse(data).version || null); }
|
|
42
|
+
catch { resolve(null); }
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
req.on('error', () => resolve(null));
|
|
47
|
+
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get installed version from node_modules
|
|
53
|
+
*/
|
|
54
|
+
function getInstalledVersion(cwd) {
|
|
55
|
+
const pkgPath = path.join(cwd, 'node_modules', 'grimoire-framework', 'package.json');
|
|
56
|
+
if (fs.existsSync(pkgPath)) {
|
|
57
|
+
try { return JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version; }
|
|
58
|
+
catch { /* ignore */ }
|
|
59
|
+
}
|
|
60
|
+
// Fallback: check project package.json dependencies
|
|
61
|
+
const projPkg = path.join(cwd, 'package.json');
|
|
62
|
+
if (fs.existsSync(projPkg)) {
|
|
63
|
+
try {
|
|
64
|
+
const pkg = JSON.parse(fs.readFileSync(projPkg, 'utf8'));
|
|
65
|
+
return (pkg.dependencies || {})['grimoire-framework'] ||
|
|
66
|
+
(pkg.devDependencies || {})['grimoire-framework'] || null;
|
|
67
|
+
} catch { /* ignore */ }
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Compare semver strings. Returns: -1 (v1<v2), 0 (equal), 1 (v1>v2)
|
|
74
|
+
*/
|
|
75
|
+
function compareVersions(v1, v2) {
|
|
76
|
+
const parse = (v) => v.replace(/[^0-9.]/g, '').split('.').map(Number);
|
|
77
|
+
const [a, b] = [parse(v1), parse(v2)];
|
|
78
|
+
for (let i = 0; i < 3; i++) {
|
|
79
|
+
if ((a[i] || 0) > (b[i] || 0)) return 1;
|
|
80
|
+
if ((a[i] || 0) < (b[i] || 0)) return -1;
|
|
81
|
+
}
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Recursively get all .md files in a directory
|
|
87
|
+
*/
|
|
88
|
+
function listMdFiles(dir) {
|
|
89
|
+
if (!fs.existsSync(dir)) return [];
|
|
90
|
+
const results = [];
|
|
91
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
92
|
+
const full = path.join(dir, entry.name);
|
|
93
|
+
if (entry.isDirectory()) results.push(...listMdFiles(full));
|
|
94
|
+
else if (entry.name.endsWith('.md')) results.push(full);
|
|
95
|
+
}
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Sync a directory from framework source to project destination.
|
|
101
|
+
* - Overwrites files that exist in source (framework files)
|
|
102
|
+
* - Preserves files that only exist in destination (custom files)
|
|
103
|
+
* Returns stats: { updated, preserved, added }
|
|
104
|
+
*/
|
|
105
|
+
function syncDir(srcDir, destDir) {
|
|
106
|
+
const stats = { updated: [], preserved: [], added: [] };
|
|
107
|
+
|
|
108
|
+
if (!fs.existsSync(srcDir)) return stats;
|
|
109
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
110
|
+
|
|
111
|
+
// Get files in both dirs
|
|
112
|
+
const srcFiles = new Set(
|
|
113
|
+
fs.readdirSync(srcDir).filter(f => f.endsWith('.md') || f.endsWith('.json') || f.endsWith('.yaml'))
|
|
114
|
+
);
|
|
115
|
+
const destFiles = new Set(
|
|
116
|
+
fs.existsSync(destDir)
|
|
117
|
+
? fs.readdirSync(destDir).filter(f => f.endsWith('.md') || f.endsWith('.json') || f.endsWith('.yaml'))
|
|
118
|
+
: []
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Copy/overwrite source files to dest
|
|
122
|
+
for (const file of srcFiles) {
|
|
123
|
+
const srcFile = path.join(srcDir, file);
|
|
124
|
+
const destFile = path.join(destDir, file);
|
|
125
|
+
const existed = destFiles.has(file);
|
|
126
|
+
fs.copyFileSync(srcFile, destFile);
|
|
127
|
+
if (existed) stats.updated.push(file);
|
|
128
|
+
else stats.added.push(file);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Files in dest but NOT in source = custom files โ preserve (do nothing)
|
|
132
|
+
for (const file of destFiles) {
|
|
133
|
+
if (!srcFiles.has(file)) {
|
|
134
|
+
stats.preserved.push(file);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return stats;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Main run function called by the CLI
|
|
143
|
+
*/
|
|
144
|
+
async function run(args = []) {
|
|
145
|
+
const cwd = process.cwd();
|
|
146
|
+
const dryRun = args.includes('--dry-run') || args.includes('--check');
|
|
147
|
+
const force = args.includes('--force');
|
|
148
|
+
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
149
|
+
|
|
150
|
+
console.log('\n๐ฎ Grimoire Smart Update\n' + '='.repeat(40));
|
|
151
|
+
|
|
152
|
+
// 1. Get versions
|
|
153
|
+
const installed = getInstalledVersion(cwd);
|
|
154
|
+
process.stdout.write('๐ก Checking latest version on npm...');
|
|
155
|
+
const latest = await getLatestVersion();
|
|
156
|
+
console.log(latest ? ` v${latest}` : ' (offline)');
|
|
157
|
+
|
|
158
|
+
console.log(`๐ฆ Installed: ${installed ? `v${installed}` : 'โ not found in node_modules'}`);
|
|
159
|
+
console.log(`๐ฆ Latest: ${latest ? `v${latest}` : 'โ could not fetch'}\n`);
|
|
160
|
+
|
|
161
|
+
if (!installed) {
|
|
162
|
+
console.log('โ ๏ธ grimoire-framework not found in this project.\n Run: npx grimoire-framework install\n');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!latest) {
|
|
167
|
+
console.log('โ ๏ธ Could not reach npm registry. Check your internet connection.\n');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const cmp = compareVersions(installed.replace(/[\^~><=]/g, ''), latest);
|
|
172
|
+
|
|
173
|
+
if (cmp >= 0 && !force) {
|
|
174
|
+
console.log('โ
Already up to date! No update needed.\n');
|
|
175
|
+
console.log(' Use --force to reinstall anyway.\n');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (dryRun) {
|
|
180
|
+
console.log(`๐ DRY RUN โ would update v${installed} โ v${latest}\n`);
|
|
181
|
+
console.log(' Directories that would be synced:');
|
|
182
|
+
for (const { dest } of FRAMEWORK_SYNC_DIRS) {
|
|
183
|
+
console.log(` โข ${dest}`);
|
|
184
|
+
}
|
|
185
|
+
console.log('\n Custom files (only in project) would be PRESERVED.');
|
|
186
|
+
console.log(' Run without --dry-run to apply.\n');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 2. Update npm package
|
|
191
|
+
console.log(`โฌ๏ธ Updating grimoire-framework v${installed} โ v${latest}...`);
|
|
192
|
+
try {
|
|
193
|
+
execSync('npm install grimoire-framework@latest', {
|
|
194
|
+
cwd,
|
|
195
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
196
|
+
timeout: 120000,
|
|
197
|
+
});
|
|
198
|
+
console.log('โ
npm package updated.\n');
|
|
199
|
+
} catch (err) {
|
|
200
|
+
console.error(`โ npm install failed: ${err.message}\n`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 3. Sync framework files selectively
|
|
205
|
+
const frameworkRoot = path.join(cwd, 'node_modules', 'grimoire-framework');
|
|
206
|
+
|
|
207
|
+
if (!fs.existsSync(frameworkRoot)) {
|
|
208
|
+
console.log('โ Could not find grimoire-framework in node_modules after install.\n');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
console.log('๐ Syncing framework files...\n');
|
|
213
|
+
|
|
214
|
+
const totalStats = { updated: 0, added: 0, preserved: 0 };
|
|
215
|
+
const report = [];
|
|
216
|
+
|
|
217
|
+
for (const { src, dest } of FRAMEWORK_SYNC_DIRS) {
|
|
218
|
+
const srcPath = path.join(frameworkRoot, src);
|
|
219
|
+
const destPath = path.join(cwd, dest);
|
|
220
|
+
|
|
221
|
+
if (!fs.existsSync(srcPath)) {
|
|
222
|
+
if (verbose) console.log(` โญ๏ธ Skip (not in source): ${src}`);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const stats = syncDir(srcPath, destPath);
|
|
227
|
+
totalStats.updated += stats.updated.length;
|
|
228
|
+
totalStats.added += stats.added.length;
|
|
229
|
+
totalStats.preserved += stats.preserved.length;
|
|
230
|
+
|
|
231
|
+
report.push({ dir: dest, stats });
|
|
232
|
+
|
|
233
|
+
if (stats.updated.length || stats.added.length || stats.preserved.length) {
|
|
234
|
+
console.log(` ๐ ${dest}`);
|
|
235
|
+
if (stats.updated.length) console.log(` โ
Updated: ${stats.updated.join(', ')}`);
|
|
236
|
+
if (stats.added.length) console.log(` โ Added: ${stats.added.join(', ')}`);
|
|
237
|
+
if (stats.preserved.length) console.log(` ๐ Preserved: ${stats.preserved.join(', ')} (custom)`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 4. Summary
|
|
242
|
+
console.log('\n' + '='.repeat(40));
|
|
243
|
+
console.log(`โ
Updated to v${latest}\n`);
|
|
244
|
+
console.log(` ๐ Files updated: ${totalStats.updated}`);
|
|
245
|
+
console.log(` โ Files added: ${totalStats.added}`);
|
|
246
|
+
console.log(` ๐ Files preserved: ${totalStats.preserved} (custom โ untouched)\n`);
|
|
247
|
+
console.log(' Run: grimoire status to verify the framework is healthy.');
|
|
248
|
+
console.log(' Run: grimoire doctor for full diagnostics.\n');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
module.exports = { run };
|
package/bin/grimoire-cli.js
CHANGED
|
@@ -27,11 +27,19 @@ async function main() {
|
|
|
27
27
|
case 'agents':
|
|
28
28
|
handleAgents(args.slice(1));
|
|
29
29
|
break;
|
|
30
|
+
case 'status':
|
|
31
|
+
handleStatus();
|
|
32
|
+
break;
|
|
33
|
+
case 'whoami':
|
|
34
|
+
handleWhoami();
|
|
35
|
+
break;
|
|
36
|
+
case 'update':
|
|
37
|
+
await require('./commands/update').run(args.slice(1));
|
|
38
|
+
break;
|
|
30
39
|
case 'doctor':
|
|
31
|
-
|
|
40
|
+
handleDoctor();
|
|
32
41
|
break;
|
|
33
42
|
case 'install':
|
|
34
|
-
case 'update':
|
|
35
43
|
case 'validate':
|
|
36
44
|
case 'info':
|
|
37
45
|
console.log(`Delegating ${command} to core logic...`);
|
|
@@ -92,6 +100,14 @@ function handleAgents(args) {
|
|
|
92
100
|
const fallbackDir = path.join(baseDir, 'node_modules', 'grimoire-framework', '.codex', 'agents');
|
|
93
101
|
const dir = fs.existsSync(agentsDir) ? agentsDir : fs.existsSync(fallbackDir) ? fallbackDir : null;
|
|
94
102
|
|
|
103
|
+
// Agent name map (id -> art persona)
|
|
104
|
+
const agentNames = {
|
|
105
|
+
'dev': 'Da Vinci', 'qa': 'Dรผrer', 'sm': 'Monet', 'devops': 'Boccioni',
|
|
106
|
+
'ux-design-expert': 'Matisse', 'grimoire-master': 'Michelangelo',
|
|
107
|
+
'analyst': 'Vermeer', 'architect': 'Gaudรญ', 'data-engineer': 'Escher',
|
|
108
|
+
'pm': 'Raphael', 'po': 'Velรกzquez', 'squad-creator': 'Rodin',
|
|
109
|
+
};
|
|
110
|
+
|
|
95
111
|
if (sub === 'list' || !sub) {
|
|
96
112
|
if (!dir) {
|
|
97
113
|
console.log('\nโ ๏ธ No agents found. Run "npx grimoire-framework install" first.');
|
|
@@ -101,26 +117,214 @@ function handleAgents(args) {
|
|
|
101
117
|
.filter(f => f.endsWith('.md'))
|
|
102
118
|
.map(f => f.replace('.md', ''));
|
|
103
119
|
console.log('\n๐ง Grimoire Agents:');
|
|
104
|
-
list.forEach(a =>
|
|
105
|
-
|
|
120
|
+
list.forEach(a => {
|
|
121
|
+
const persona = agentNames[a] ? ` (${agentNames[a]})` : '';
|
|
122
|
+
console.log(` @${a}${persona}`);
|
|
123
|
+
});
|
|
124
|
+
console.log(`\n Total: ${list.length} agents | Invoke with @agentname in your IDE chat`);
|
|
106
125
|
} else {
|
|
107
126
|
console.log('Usage: grimoire agents list');
|
|
108
127
|
}
|
|
109
128
|
}
|
|
110
129
|
|
|
130
|
+
function handleStatus() {
|
|
131
|
+
const cwd = process.cwd();
|
|
132
|
+
const check = (p) => fs.existsSync(p);
|
|
133
|
+
const icon = (v) => v ? 'โ
' : 'โ';
|
|
134
|
+
|
|
135
|
+
// Detect project root (has .codex or .grimoire)
|
|
136
|
+
const hasCodex = check(path.join(cwd, '.codex'));
|
|
137
|
+
const hasGrimoire = check(path.join(cwd, '.grimoire'));
|
|
138
|
+
const hasGemini = check(path.join(cwd, '.gemini'));
|
|
139
|
+
const hasCursor = check(path.join(cwd, '.cursor'));
|
|
140
|
+
const hasClaude = check(path.join(cwd, '.claude'));
|
|
141
|
+
|
|
142
|
+
// Hooks check
|
|
143
|
+
const settingsPath = path.join(cwd, '.gemini', 'settings.json');
|
|
144
|
+
let hooks = [];
|
|
145
|
+
let hooksActive = false;
|
|
146
|
+
if (check(settingsPath)) {
|
|
147
|
+
try {
|
|
148
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
149
|
+
const h = settings.hooks || {};
|
|
150
|
+
hooks = Object.values(h).flat().filter(hook => hook && hook.command).map(h => h.command);
|
|
151
|
+
hooksActive = hooks.length > 0;
|
|
152
|
+
} catch (e) { /* ignore */ }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Agents count
|
|
156
|
+
const agentsDir = path.join(cwd, '.codex', 'agents');
|
|
157
|
+
const agentCount = check(agentsDir)
|
|
158
|
+
? fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).length
|
|
159
|
+
: 0;
|
|
160
|
+
|
|
161
|
+
// Memory check
|
|
162
|
+
const memDir = path.join(cwd, '.grimoire', 'memory');
|
|
163
|
+
const hasMemory = check(memDir);
|
|
164
|
+
|
|
165
|
+
// Session log (last agent used)
|
|
166
|
+
const sessionLog = path.join(cwd, '.grimoire', 'logs', 'session.log');
|
|
167
|
+
let lastAgent = null;
|
|
168
|
+
if (check(sessionLog)) {
|
|
169
|
+
try {
|
|
170
|
+
const lines = fs.readFileSync(sessionLog, 'utf8').trim().split('\n');
|
|
171
|
+
const last = lines.filter(l => l.includes('agent:')).pop();
|
|
172
|
+
if (last) lastAgent = last.split('agent:')[1]?.trim();
|
|
173
|
+
} catch (e) { /* ignore */ }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
console.log(`
|
|
177
|
+
๐ฎ Grimoire Framework Status
|
|
178
|
+
${'='.repeat(40)}
|
|
179
|
+
๐ Version: v${packageJson.version}
|
|
180
|
+
๐ Project: ${cwd}
|
|
181
|
+
|
|
182
|
+
๐ง Core
|
|
183
|
+
${icon(hasCodex)} .codex (agents & config)
|
|
184
|
+
${icon(hasGrimoire)} .grimoire (memory & metrics)
|
|
185
|
+
${icon(agentCount > 0)} Agents: ${agentCount} loaded
|
|
186
|
+
|
|
187
|
+
๐ช Hooks (Gemini CLI)
|
|
188
|
+
${icon(check(settingsPath))} settings.json
|
|
189
|
+
${icon(hooksActive)} Hooks active: ${hooksActive ? hooks.length + ' configured' : 'none found'}
|
|
190
|
+
|
|
191
|
+
๐ป IDE Integration
|
|
192
|
+
${icon(hasGemini)} .gemini (Gemini CLI rules)
|
|
193
|
+
${icon(hasCursor)} .cursor (Cursor rules)
|
|
194
|
+
${icon(hasClaude)} .claude (Claude commands)
|
|
195
|
+
|
|
196
|
+
๐พ Memory Layer
|
|
197
|
+
${icon(hasMemory)} Memory store ${hasMemory ? '(active)' : '(not initialized)'}
|
|
198
|
+
${lastAgent ? `
|
|
199
|
+
๐ง Last Agent: @${lastAgent}` : ''}
|
|
200
|
+
|
|
201
|
+
Run 'grimoire agents list' to see all agents.
|
|
202
|
+
Run 'grimoire whoami' to see session context.
|
|
203
|
+
`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function handleWhoami() {
|
|
207
|
+
const cwd = process.cwd();
|
|
208
|
+
|
|
209
|
+
// Detect IDE from environment
|
|
210
|
+
const inCursor = process.env.CURSOR_TRACE_ID || process.env.VSCODE_PID;
|
|
211
|
+
const inVSCode = process.env.VSCODE_PID && !inCursor;
|
|
212
|
+
const inGemini = process.env.GEMINI_CLI || process.env.CLOUD_SHELL;
|
|
213
|
+
const inClaude = process.env.CLAUDE_AGENT;
|
|
214
|
+
let ide = 'Unknown IDE';
|
|
215
|
+
if (inCursor) ide = 'Cursor';
|
|
216
|
+
else if (inVSCode) ide = 'VS Code';
|
|
217
|
+
else if (inGemini) ide = 'Gemini CLI';
|
|
218
|
+
else if (inClaude) ide = 'Claude';
|
|
219
|
+
|
|
220
|
+
// Detect project name
|
|
221
|
+
const projectPkg = path.join(cwd, 'package.json');
|
|
222
|
+
let projectName = path.basename(cwd);
|
|
223
|
+
if (fs.existsSync(projectPkg)) {
|
|
224
|
+
try { projectName = JSON.parse(fs.readFileSync(projectPkg, 'utf8')).name || projectName; } catch (e) { }
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Read grimoire config if exists
|
|
228
|
+
const configPath = path.join(cwd, '.grimoire', 'config.json');
|
|
229
|
+
let config = {};
|
|
230
|
+
if (fs.existsSync(configPath)) {
|
|
231
|
+
try { config = JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch (e) { }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Available agents with personas
|
|
235
|
+
const agentNames = {
|
|
236
|
+
'dev': 'Da Vinci', 'qa': 'Dรผrer', 'sm': 'Monet', 'devops': 'Boccioni',
|
|
237
|
+
'ux-design-expert': 'Matisse', 'grimoire-master': 'Michelangelo',
|
|
238
|
+
'analyst': 'Vermeer', 'architect': 'Gaudรญ', 'data-engineer': 'Escher',
|
|
239
|
+
'pm': 'Raphael', 'po': 'Velรกzquez', 'squad-creator': 'Rodin',
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const agentsDir = path.join(cwd, '.codex', 'agents');
|
|
243
|
+
const availableAgents = fs.existsSync(agentsDir)
|
|
244
|
+
? fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).map(f => f.replace('.md', ''))
|
|
245
|
+
: [];
|
|
246
|
+
|
|
247
|
+
const agentList = availableAgents
|
|
248
|
+
.map(a => agentNames[a] ? `@${a} (${agentNames[a]})` : `@${a}`)
|
|
249
|
+
.join(', ');
|
|
250
|
+
|
|
251
|
+
console.log(`
|
|
252
|
+
๐ง Grimoire โ Who Am I?
|
|
253
|
+
${'='.repeat(40)}
|
|
254
|
+
๐ You are: ${process.env.USER || process.env.USERNAME || 'unknown user'}
|
|
255
|
+
๐ Project: ${projectName}
|
|
256
|
+
๐ Directory: ${cwd}
|
|
257
|
+
๐ป IDE: ${ide}
|
|
258
|
+
๐ฎ Framework: Grimoire v${packageJson.version}
|
|
259
|
+
${config.squad ? `๐ฅ Squad: ${config.squad}` : ''}
|
|
260
|
+
|
|
261
|
+
๐ง Available Agents:
|
|
262
|
+
${agentList || '(none found โ run grimoire install)'}
|
|
263
|
+
|
|
264
|
+
๐ก How to activate an agent:
|
|
265
|
+
In your IDE chat, type: @dev or @qa or @grimoire-master
|
|
266
|
+
The agent will greet you by their persona name (Da Vinci, Dรผrer, etc.)
|
|
267
|
+
|
|
268
|
+
๐ง Framework vs CLI:
|
|
269
|
+
CLI commands โ Run in terminal: grimoire status | grimoire agents list
|
|
270
|
+
Agent chat โ Activate in IDE: @agentname (e.g. @dev, @qa)
|
|
271
|
+
These are DIFFERENT interfaces โ the CLI manages the framework,
|
|
272
|
+
agents respond inside your IDE's AI chat window.
|
|
273
|
+
`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function handleDoctor() {
|
|
277
|
+
const cwd = process.cwd();
|
|
278
|
+
const check = (p) => fs.existsSync(p);
|
|
279
|
+
const ok = (v, msg) => console.log(` ${v ? 'โ
' : 'โ'} ${msg}`);
|
|
280
|
+
|
|
281
|
+
console.log('\n๐ฅ Grimoire Doctor\n' + '='.repeat(40));
|
|
282
|
+
|
|
283
|
+
ok(check(path.join(cwd, '.codex', 'agents')), '.codex/agents directory exists');
|
|
284
|
+
ok(check(path.join(cwd, '.grimoire')), '.grimoire directory exists');
|
|
285
|
+
ok(check(path.join(cwd, '.gemini', 'settings.json')), '.gemini/settings.json (hooks configured)');
|
|
286
|
+
ok(check(path.join(cwd, '.gemini', 'rules')), '.gemini/rules (agent rules installed)');
|
|
287
|
+
ok(check(path.join(cwd, '.cursor', 'rules')), '.cursor/rules (Cursor integration)');
|
|
288
|
+
|
|
289
|
+
// Check package.json has grimoire
|
|
290
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
291
|
+
if (check(pkgPath)) {
|
|
292
|
+
try {
|
|
293
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
294
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
295
|
+
ok(!!deps['grimoire-framework'], 'grimoire-framework in package.json');
|
|
296
|
+
} catch (e) { ok(false, 'package.json readable'); }
|
|
297
|
+
} else {
|
|
298
|
+
ok(false, 'package.json found');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
console.log('\n Run \'grimoire status\' for full framework state.\n');
|
|
302
|
+
}
|
|
303
|
+
|
|
111
304
|
function showHelp() {
|
|
112
305
|
console.log(`
|
|
113
|
-
|
|
306
|
+
๐ฎ Grimoire Framework CLI v${packageJson.version}
|
|
307
|
+
|
|
308
|
+
The CLI manages your framework. Agents live in your IDE chat.
|
|
309
|
+
(These are DIFFERENT โ CLI = terminal, Agents = @agentname in IDE chat)
|
|
114
310
|
|
|
115
311
|
USAGE:
|
|
312
|
+
grimoire status # โจ Framework health & what's active
|
|
313
|
+
grimoire whoami # ๐ง Session context & how to use agents
|
|
116
314
|
grimoire install # Install/Reset setup
|
|
117
|
-
grimoire agents list # List available agents
|
|
315
|
+
grimoire agents list # List available agents (with personas)
|
|
118
316
|
grimoire squads list # List installed squads
|
|
119
317
|
grimoire memory [sub] # Manage persistent memory
|
|
120
318
|
grimoire metrics # View productivity metrics
|
|
121
|
-
grimoire doctor # Run diagnostics
|
|
319
|
+
grimoire doctor # Run diagnostics (checks + tips)
|
|
122
320
|
grimoire --version # Show version
|
|
123
321
|
grimoire --help # Show this help
|
|
322
|
+
|
|
323
|
+
QUICK START:
|
|
324
|
+
npx grimoire-framework install # Set up in a new project
|
|
325
|
+
grimoire status # Check everything is working
|
|
326
|
+
grimoire whoami # See available agents
|
|
327
|
+
Then in your IDE chat: @dev or @qa or @grimoire-master
|
|
124
328
|
`);
|
|
125
329
|
}
|
|
126
330
|
|