@grafema/cli 0.3.24 → 0.3.27
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/README.md +59 -45
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyzeAction.d.ts.map +1 -1
- package/dist/commands/analyzeAction.js +134 -3
- package/dist/commands/analyzeAction.js.map +1 -1
- package/dist/commands/doctor/checks.d.ts.map +1 -1
- package/dist/commands/doctor/checks.js +7 -3
- package/dist/commands/doctor/checks.js.map +1 -1
- package/dist/commands/export.d.ts +15 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +88 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/exportAction.d.ts +35 -0
- package/dist/commands/exportAction.d.ts.map +1 -0
- package/dist/commands/exportAction.js +58 -0
- package/dist/commands/exportAction.js.map +1 -0
- package/dist/commands/features.d.ts +13 -0
- package/dist/commands/features.d.ts.map +1 -0
- package/dist/commands/features.js +69 -0
- package/dist/commands/features.js.map +1 -0
- package/dist/commands/featuresAction.d.ts +82 -0
- package/dist/commands/featuresAction.d.ts.map +1 -0
- package/dist/commands/featuresAction.js +139 -0
- package/dist/commands/featuresAction.js.map +1 -0
- package/dist/commands/start.d.ts +12 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +294 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/trace.d.ts.map +1 -1
- package/dist/commands/trace.js +50 -30
- package/dist/commands/trace.js.map +1 -1
- package/dist/commands/upgrade.d.ts +3 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +279 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/package.json +4 -4
- package/src/cli.ts +11 -0
- package/src/commands/analyzeAction.ts +135 -2
- package/src/commands/doctor/checks.ts +4 -3
- package/src/commands/explore.tsx +29 -2
- package/src/commands/export.ts +102 -0
- package/src/commands/exportAction.ts +107 -0
- package/src/commands/features.ts +88 -0
- package/src/commands/featuresAction.ts +218 -0
- package/src/commands/start.ts +303 -0
- package/src/commands/trace.ts +49 -29
- package/src/commands/upgrade.ts +310 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { existsSync, readdirSync, lstatSync, unlinkSync, rmSync, statSync, mkdirSync, } from 'fs';
|
|
3
|
+
import { join, resolve } from 'path';
|
|
4
|
+
import { getGrafemaBinDir, DOWNLOADABLE_BINARIES, isBinaryCurrentVersion, downloadBinary, GRAFEMA_VERSION, } from '@grafema/util';
|
|
5
|
+
const COLORS = {
|
|
6
|
+
green: '\x1b[32m',
|
|
7
|
+
red: '\x1b[31m',
|
|
8
|
+
yellow: '\x1b[33m',
|
|
9
|
+
cyan: '\x1b[36m',
|
|
10
|
+
dim: '\x1b[2m',
|
|
11
|
+
bold: '\x1b[1m',
|
|
12
|
+
reset: '\x1b[0m',
|
|
13
|
+
};
|
|
14
|
+
const LANG_BINARIES = {
|
|
15
|
+
js: ['grafema-analyzer', 'grafema-resolve'],
|
|
16
|
+
python: ['grafema-python-analyzer', 'python-resolve'],
|
|
17
|
+
haskell: ['haskell-analyzer', 'haskell-resolve'],
|
|
18
|
+
rust: ['grafema-rust-resolve'],
|
|
19
|
+
java: ['grafema-java-analyzer', 'java-resolve', 'java-parser'],
|
|
20
|
+
kotlin: ['grafema-kotlin-analyzer', 'kotlin-resolve', 'kotlin-parser'],
|
|
21
|
+
go: ['grafema-go-analyzer', 'go-resolve', 'go-parser'],
|
|
22
|
+
cpp: ['grafema-cpp-analyzer', 'cpp-resolve'],
|
|
23
|
+
swift: ['grafema-swift-analyzer', 'swift-resolve', 'swift-parser'],
|
|
24
|
+
objc: ['grafema-objc-analyzer', 'objc-parser'],
|
|
25
|
+
beam: ['beam-analyzer', 'beam-resolve'],
|
|
26
|
+
};
|
|
27
|
+
const INFRASTRUCTURE = ['grafema-orchestrator', 'rfdb-server'];
|
|
28
|
+
const DOWNLOADABLE_SET = new Set(DOWNLOADABLE_BINARIES);
|
|
29
|
+
function formatBytes(bytes) {
|
|
30
|
+
if (bytes === 0)
|
|
31
|
+
return '0 B';
|
|
32
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
33
|
+
const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
|
34
|
+
const val = bytes / Math.pow(1024, i);
|
|
35
|
+
return `${val.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
|
|
36
|
+
}
|
|
37
|
+
function auditBinDir(binDir) {
|
|
38
|
+
const toClean = [];
|
|
39
|
+
const knownBinaries = [];
|
|
40
|
+
if (!existsSync(binDir))
|
|
41
|
+
return { toClean, knownBinaries };
|
|
42
|
+
for (const entry of readdirSync(binDir)) {
|
|
43
|
+
const fullPath = join(binDir, entry);
|
|
44
|
+
let stat;
|
|
45
|
+
try {
|
|
46
|
+
stat = lstatSync(fullPath);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (stat.isSymbolicLink() && !existsSync(fullPath)) {
|
|
52
|
+
toClean.push({ path: fullPath, name: entry, reason: 'broken symlink', size: 0 });
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (entry.startsWith('.build-hash.') || entry.endsWith('.downloading')) {
|
|
56
|
+
toClean.push({ path: fullPath, name: entry, reason: 'dev artifact', size: stat.size });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (entry.endsWith('.version')) {
|
|
60
|
+
const binaryName = entry.slice(0, -'.version'.length);
|
|
61
|
+
if (!existsSync(join(binDir, binaryName))) {
|
|
62
|
+
toClean.push({ path: fullPath, name: entry, reason: 'orphaned version file', size: stat.size });
|
|
63
|
+
}
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (entry === '.gitkeep')
|
|
67
|
+
continue;
|
|
68
|
+
if (DOWNLOADABLE_SET.has(entry)) {
|
|
69
|
+
knownBinaries.push(entry);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
toClean.push({ path: fullPath, name: entry, reason: 'unknown binary', size: stat.size });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { toClean, knownBinaries };
|
|
76
|
+
}
|
|
77
|
+
function getTargetBinaries(options, existingBinaries) {
|
|
78
|
+
if (options.all) {
|
|
79
|
+
return [...DOWNLOADABLE_BINARIES];
|
|
80
|
+
}
|
|
81
|
+
if (options.lang) {
|
|
82
|
+
const langs = options.lang.split(',').map(l => l.trim().toLowerCase());
|
|
83
|
+
const invalid = langs.filter(l => !LANG_BINARIES[l]);
|
|
84
|
+
if (invalid.length > 0) {
|
|
85
|
+
console.error(`${COLORS.red}Unknown languages: ${invalid.join(', ')}${COLORS.reset}`);
|
|
86
|
+
console.error(`Available: ${Object.keys(LANG_BINARIES).join(', ')}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const bins = new Set(INFRASTRUCTURE);
|
|
90
|
+
for (const lang of langs) {
|
|
91
|
+
for (const b of LANG_BINARIES[lang])
|
|
92
|
+
bins.add(b);
|
|
93
|
+
}
|
|
94
|
+
return [...bins];
|
|
95
|
+
}
|
|
96
|
+
const set = new Set(existingBinaries);
|
|
97
|
+
for (const b of INFRASTRUCTURE)
|
|
98
|
+
set.add(b);
|
|
99
|
+
return [...set];
|
|
100
|
+
}
|
|
101
|
+
function auditProjectDir(projectPath) {
|
|
102
|
+
const grafemaDir = join(projectPath, '.grafema');
|
|
103
|
+
if (!existsSync(grafemaDir))
|
|
104
|
+
return [];
|
|
105
|
+
const toClean = [];
|
|
106
|
+
const diagLog = join(grafemaDir, 'diagnostics.log');
|
|
107
|
+
if (existsSync(diagLog)) {
|
|
108
|
+
toClean.push({ path: diagLog, name: 'diagnostics.log', reason: 'old diagnostics', size: statSync(diagLog).size });
|
|
109
|
+
}
|
|
110
|
+
const oldDb = join(grafemaDir, 'grafema.rfdb');
|
|
111
|
+
const newDb = join(grafemaDir, 'graph.rfdb');
|
|
112
|
+
if (existsSync(oldDb) && existsSync(newDb)) {
|
|
113
|
+
let size = 0;
|
|
114
|
+
try {
|
|
115
|
+
for (const f of readdirSync(oldDb)) {
|
|
116
|
+
try {
|
|
117
|
+
size += statSync(join(oldDb, f)).size;
|
|
118
|
+
}
|
|
119
|
+
catch { /* skip */ }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch { /* skip */ }
|
|
123
|
+
toClean.push({ path: oldDb, name: 'grafema.rfdb/', reason: 'stale database (renamed to graph.rfdb)', size });
|
|
124
|
+
}
|
|
125
|
+
const logsDir = join(grafemaDir, 'logs');
|
|
126
|
+
if (existsSync(logsDir)) {
|
|
127
|
+
const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
|
|
128
|
+
try {
|
|
129
|
+
for (const f of readdirSync(logsDir)) {
|
|
130
|
+
const fp = join(logsDir, f);
|
|
131
|
+
try {
|
|
132
|
+
const s = statSync(fp);
|
|
133
|
+
if (s.isFile() && s.mtimeMs < thirtyDaysAgo) {
|
|
134
|
+
toClean.push({ path: fp, name: `logs/${f}`, reason: 'log older than 30 days', size: s.size });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch { /* skip */ }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch { /* skip */ }
|
|
141
|
+
}
|
|
142
|
+
return toClean;
|
|
143
|
+
}
|
|
144
|
+
export const upgradeCommand = new Command('upgrade')
|
|
145
|
+
.description('Clean stale artifacts and upgrade binaries to current version')
|
|
146
|
+
.option('-a, --all', 'Download all available binaries (not just existing)')
|
|
147
|
+
.option('-l, --lang <langs>', 'Comma-separated languages to install (js,python,rust,...)')
|
|
148
|
+
.option('-n, --dry-run', 'Preview changes without executing')
|
|
149
|
+
.option('-p, --project [path]', 'Also clean project .grafema/ artifacts')
|
|
150
|
+
.addHelpText('after', `
|
|
151
|
+
Examples:
|
|
152
|
+
grafema upgrade Clean + upgrade existing binaries
|
|
153
|
+
grafema upgrade --all Clean + download ALL available binaries
|
|
154
|
+
grafema upgrade --lang js,python Clean + ensure JS and Python analyzers
|
|
155
|
+
grafema upgrade --dry-run Preview what would be cleaned/upgraded
|
|
156
|
+
grafema upgrade --project Also clean .grafema/ in current directory
|
|
157
|
+
|
|
158
|
+
Available languages: ${Object.keys(LANG_BINARIES).join(', ')}`)
|
|
159
|
+
.action(async (options) => {
|
|
160
|
+
const dryRun = !!options.dryRun;
|
|
161
|
+
const prefix = dryRun ? `${COLORS.dim}[dry-run]${COLORS.reset} ` : '';
|
|
162
|
+
const binDir = getGrafemaBinDir();
|
|
163
|
+
console.log(`${COLORS.bold}Grafema Upgrade${COLORS.reset} ${COLORS.dim}v${GRAFEMA_VERSION}${COLORS.reset}`);
|
|
164
|
+
console.log();
|
|
165
|
+
if (!existsSync(binDir)) {
|
|
166
|
+
mkdirSync(binDir, { recursive: true });
|
|
167
|
+
}
|
|
168
|
+
// Phase 1+2: Audit and clean ~/.grafema/bin/
|
|
169
|
+
const { toClean, knownBinaries } = auditBinDir(binDir);
|
|
170
|
+
if (toClean.length > 0) {
|
|
171
|
+
console.log(`${COLORS.bold}Cleaning ~/.grafema/bin/${COLORS.reset}`);
|
|
172
|
+
for (const item of toClean) {
|
|
173
|
+
console.log(` ${prefix}${COLORS.red}✗${COLORS.reset} ${item.name} ${COLORS.dim}(${item.reason}, ${formatBytes(item.size)})${COLORS.reset}`);
|
|
174
|
+
if (!dryRun) {
|
|
175
|
+
try {
|
|
176
|
+
const s = lstatSync(item.path);
|
|
177
|
+
if (s.isDirectory()) {
|
|
178
|
+
rmSync(item.path, { recursive: true, force: true });
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
unlinkSync(item.path);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
console.log(` ${COLORS.yellow}warning: ${err instanceof Error ? err.message : err}${COLORS.reset}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
console.log();
|
|
190
|
+
}
|
|
191
|
+
// Phase 3: Upgrade binaries
|
|
192
|
+
const targets = getTargetBinaries(options, knownBinaries);
|
|
193
|
+
console.log(`${COLORS.bold}Upgrading binaries${COLORS.reset} ${COLORS.dim}(target: binaries-v${GRAFEMA_VERSION})${COLORS.reset}`);
|
|
194
|
+
let upgradedCount = 0;
|
|
195
|
+
let currentCount = 0;
|
|
196
|
+
let failedCount = 0;
|
|
197
|
+
for (const name of targets) {
|
|
198
|
+
const binaryPath = join(binDir, name);
|
|
199
|
+
if (existsSync(binaryPath) && isBinaryCurrentVersion(binaryPath)) {
|
|
200
|
+
currentCount++;
|
|
201
|
+
console.log(` ${COLORS.green}✓${COLORS.reset} ${name} ${COLORS.dim}-- current${COLORS.reset}`);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (dryRun) {
|
|
205
|
+
const status = existsSync(binaryPath) ? 'stale, would upgrade' : 'missing, would download';
|
|
206
|
+
console.log(` ${prefix}${COLORS.cyan}↓${COLORS.reset} ${name} ${COLORS.dim}(${status})${COLORS.reset}`);
|
|
207
|
+
upgradedCount++;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
process.stdout.write(` ${COLORS.cyan}↓${COLORS.reset} ${name} -- downloading...`);
|
|
212
|
+
const downloaded = await downloadBinary(name);
|
|
213
|
+
const size = statSync(downloaded).size;
|
|
214
|
+
process.stdout.write(`\r ${COLORS.green}✓${COLORS.reset} ${name} ${COLORS.dim}(${formatBytes(size)})${COLORS.reset} \n`);
|
|
215
|
+
upgradedCount++;
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
219
|
+
process.stdout.write(`\r ${COLORS.red}✗${COLORS.reset} ${name} -- ${msg} \n`);
|
|
220
|
+
failedCount++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
console.log();
|
|
224
|
+
// Phase 4: Project cleanup (optional)
|
|
225
|
+
let projectCleanedCount = 0;
|
|
226
|
+
let projectCleanedBytes = 0;
|
|
227
|
+
if (options.project !== undefined) {
|
|
228
|
+
const projectPath = typeof options.project === 'string' ? resolve(options.project) : resolve('.');
|
|
229
|
+
const projectActions = auditProjectDir(projectPath);
|
|
230
|
+
if (projectActions.length > 0) {
|
|
231
|
+
console.log(`${COLORS.bold}Cleaning project artifacts${COLORS.reset} ${COLORS.dim}(${projectPath}/.grafema/)${COLORS.reset}`);
|
|
232
|
+
for (const item of projectActions) {
|
|
233
|
+
console.log(` ${prefix}${COLORS.red}✗${COLORS.reset} ${item.name} ${COLORS.dim}(${item.reason}, ${formatBytes(item.size)})${COLORS.reset}`);
|
|
234
|
+
if (!dryRun) {
|
|
235
|
+
try {
|
|
236
|
+
const s = lstatSync(item.path);
|
|
237
|
+
if (s.isDirectory()) {
|
|
238
|
+
rmSync(item.path, { recursive: true, force: true });
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
unlinkSync(item.path);
|
|
242
|
+
}
|
|
243
|
+
projectCleanedCount++;
|
|
244
|
+
projectCleanedBytes += item.size;
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
console.log(` ${COLORS.yellow}warning: ${err instanceof Error ? err.message : err}${COLORS.reset}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
projectCleanedCount++;
|
|
252
|
+
projectCleanedBytes += item.size;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
console.log();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Summary
|
|
259
|
+
const parts = [];
|
|
260
|
+
if (toClean.length > 0) {
|
|
261
|
+
const totalCleaned = toClean.reduce((s, a) => s + a.size, 0);
|
|
262
|
+
parts.push(`cleaned ${toClean.length} files (${formatBytes(totalCleaned)})`);
|
|
263
|
+
}
|
|
264
|
+
if (upgradedCount > 0)
|
|
265
|
+
parts.push(`upgraded ${upgradedCount} binaries`);
|
|
266
|
+
if (currentCount > 0)
|
|
267
|
+
parts.push(`${currentCount} already current`);
|
|
268
|
+
if (failedCount > 0)
|
|
269
|
+
parts.push(`${COLORS.red}${failedCount} failed${COLORS.reset}`);
|
|
270
|
+
if (projectCleanedCount > 0)
|
|
271
|
+
parts.push(`project: ${projectCleanedCount} files (${formatBytes(projectCleanedBytes)})`);
|
|
272
|
+
if (parts.length === 0) {
|
|
273
|
+
console.log(`${COLORS.green}✓${COLORS.reset} Everything is up to date.`);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
console.log(`${COLORS.bold}Summary:${COLORS.reset} ${parts.join(', ')}`);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafema/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.27",
|
|
4
4
|
"description": "CLI for Grafema code analysis toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"commander": "^13.0.0",
|
|
37
37
|
"yaml": "^2.8.2",
|
|
38
|
-
"@grafema/
|
|
39
|
-
"@grafema/
|
|
40
|
-
"@grafema/
|
|
38
|
+
"@grafema/types": "0.3.27",
|
|
39
|
+
"@grafema/util": "0.3.27",
|
|
40
|
+
"@grafema/api": "0.3.27"
|
|
41
41
|
},
|
|
42
42
|
"optionalDependencies": {
|
|
43
43
|
"@grafema/grafema-darwin-arm64": "0.3.16",
|
package/src/cli.ts
CHANGED
|
@@ -35,6 +35,10 @@ import { fileCommand } from './commands/file.js';
|
|
|
35
35
|
import { setupSkillCommand } from './commands/setup-skill.js';
|
|
36
36
|
import { gitIngestCommand } from './commands/git-ingest.js';
|
|
37
37
|
import { registryCommand } from './commands/registry.js';
|
|
38
|
+
import { featuresCommand } from './commands/features.js';
|
|
39
|
+
import { exportCommand } from './commands/export.js';
|
|
40
|
+
import { startCommand, stopCommand } from './commands/start.js';
|
|
41
|
+
import { upgradeCommand } from './commands/upgrade.js';
|
|
38
42
|
|
|
39
43
|
// Read version from package.json
|
|
40
44
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -53,6 +57,10 @@ program.addCommand(wtfCommand);
|
|
|
53
57
|
program.addCommand(whoCommand);
|
|
54
58
|
program.addCommand(whyCommand);
|
|
55
59
|
|
|
60
|
+
// Lifecycle commands
|
|
61
|
+
program.addCommand(startCommand);
|
|
62
|
+
program.addCommand(stopCommand);
|
|
63
|
+
|
|
56
64
|
// Commands in logical order
|
|
57
65
|
program.addCommand(initCommand);
|
|
58
66
|
program.addCommand(analyzeCommand);
|
|
@@ -72,11 +80,14 @@ program.addCommand(coverageCommand);
|
|
|
72
80
|
program.addCommand(checkCommand);
|
|
73
81
|
program.addCommand(serverCommand);
|
|
74
82
|
program.addCommand(doctorCommand);
|
|
83
|
+
program.addCommand(upgradeCommand);
|
|
75
84
|
program.addCommand(schemaCommand);
|
|
76
85
|
program.addCommand(explainCommand);
|
|
77
86
|
program.addCommand(fileCommand);
|
|
78
87
|
program.addCommand(setupSkillCommand);
|
|
79
88
|
program.addCommand(gitIngestCommand);
|
|
80
89
|
program.addCommand(registryCommand);
|
|
90
|
+
program.addCommand(featuresCommand);
|
|
91
|
+
program.addCommand(exportCommand);
|
|
81
92
|
|
|
82
93
|
program.parse();
|
|
@@ -20,9 +20,20 @@ import {
|
|
|
20
20
|
ensureBinary,
|
|
21
21
|
ManifestGenerator,
|
|
22
22
|
ManifestResolver,
|
|
23
|
+
EffectsLookup,
|
|
23
24
|
GRAFEMA_VERSION,
|
|
24
25
|
getSchemaVersion,
|
|
25
26
|
} from '@grafema/util';
|
|
27
|
+
import { enrichBehaviors } from '@grafema/util/enrichers/behaviorEnricher';
|
|
28
|
+
import { enrichContracts } from '@grafema/util/enrichers/contractEnricher';
|
|
29
|
+
import { enrichLibraryCallbacks } from '@grafema/util/enrichers/libraryCallbackEnricher';
|
|
30
|
+
import { enrichPackageApis } from '@grafema/util/enrichers/packageApiEnricher';
|
|
31
|
+
import { enrichMcpToolDefinitions } from '@grafema/util/enrichers/mcpToolDefinitionEnricher';
|
|
32
|
+
import { enrichSpecedContracts } from '@grafema/util/enrichers/specedContractEnricher';
|
|
33
|
+
import { commanderExtractor } from '@grafema/util/enrichers/extractors/commanderExtractor';
|
|
34
|
+
import { mcpInputSchemaExtractor } from '@grafema/util/enrichers/extractors/mcpInputSchemaExtractor';
|
|
35
|
+
import { vscodeContributesExtractor } from '@grafema/util/enrichers/extractors/vscodeContributesExtractor';
|
|
36
|
+
import { httpRouteExtractor } from '@grafema/util/enrichers/extractors/httpRouteExtractor';
|
|
26
37
|
import type { LogLevel } from '@grafema/util';
|
|
27
38
|
import { scanExtensions, generateSmartConfig, writeConfig, updateGitignore, formatDetected } from '../utils/quickstart.js';
|
|
28
39
|
|
|
@@ -95,8 +106,8 @@ const EXT_TO_BINARIES: Record<string, string[]> = {
|
|
|
95
106
|
pyi: ['grafema-python-analyzer', 'python-resolve'],
|
|
96
107
|
// Haskell
|
|
97
108
|
hs: ['haskell-analyzer', 'haskell-resolve'],
|
|
98
|
-
// Rust
|
|
99
|
-
rs: ['grafema-rust-
|
|
109
|
+
// Rust (analyzer is native in-process inside orchestrator)
|
|
110
|
+
rs: ['grafema-rust-resolve'],
|
|
100
111
|
// Java
|
|
101
112
|
java: ['grafema-java-analyzer', 'java-resolve', 'java-parser'],
|
|
102
113
|
// Kotlin
|
|
@@ -322,6 +333,114 @@ export async function analyzeAction(path: string, options: { service?: string; e
|
|
|
322
333
|
info(` Nodes: ${stats.nodeCount}`);
|
|
323
334
|
info(` Edges: ${stats.edgeCount}`);
|
|
324
335
|
|
|
336
|
+
// Run library-callback enricher before manifest generation.
|
|
337
|
+
// Creates domain nodes (cli:command, mcp:tool, ...) and HANDLES edges
|
|
338
|
+
// for callbacks passed to library entry points (Commander, MCP SDK, ...).
|
|
339
|
+
// Reuses the effects-db loaded for ManifestGenerator.
|
|
340
|
+
const effectsDbPath = resolveEffectsDbPath(projectPath);
|
|
341
|
+
const effectsLookup = effectsDbPath
|
|
342
|
+
? EffectsLookup.load(effectsDbPath)
|
|
343
|
+
: EffectsLookup.empty();
|
|
344
|
+
try {
|
|
345
|
+
// RFDBServerBackend's RFDBClient field is private at compile time but
|
|
346
|
+
// accessible at runtime; the enricher only needs the wire-level client.
|
|
347
|
+
const client = (backend as unknown as { client: Parameters<typeof enrichLibraryCallbacks>[0] }).client;
|
|
348
|
+
if (client) {
|
|
349
|
+
const result = await enrichLibraryCallbacks(client, effectsLookup);
|
|
350
|
+
info(` Library callbacks: ${result.domainNodesCreated} domain nodes, ${result.handlesEdgesCreated} HANDLES edges (unresolved: ${result.unresolvedCalls})`);
|
|
351
|
+
}
|
|
352
|
+
} catch (err) {
|
|
353
|
+
debug(`Library callback enricher skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// MCP tool definition enricher — scans `packages/mcp/src/definitions/*-tools.ts`
|
|
357
|
+
// (or any matching tree under projectPath) and creates `mcp:tool` nodes for
|
|
358
|
+
// each defined tool. Complements libraryCallbackEnricher: that one captures
|
|
359
|
+
// the high-level setRequestHandler calls; this one captures the ~30+ tools
|
|
360
|
+
// dispatched by the switch statement inside the CallTool handler.
|
|
361
|
+
try {
|
|
362
|
+
const client = (backend as unknown as { client: Parameters<typeof enrichMcpToolDefinitions>[0] }).client;
|
|
363
|
+
if (client) {
|
|
364
|
+
const definitionsDir = join(projectPath, 'packages/mcp/src/definitions');
|
|
365
|
+
const result = await enrichMcpToolDefinitions(client, { definitionsDir });
|
|
366
|
+
if (result.toolNodesCreated > 0) {
|
|
367
|
+
info(` MCP tool defs: ${result.toolNodesCreated} mcp:tool nodes, ${result.handlesEdgesCreated} HANDLES edges (unresolved: ${result.unresolvedHandlers.length})`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
} catch (err) {
|
|
371
|
+
debug(`MCP tool definition enricher skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Contract enricher — for every FEATURE-class node (cli:command, mcp:tool,
|
|
375
|
+
// vscode:command) created by the L0 entry-point enrichers above, walk the
|
|
376
|
+
// HANDLES edge to the handler FUNCTION and extract a CONTRACT node carrying
|
|
377
|
+
// structured inputs/outputs/errors metadata. Must run AFTER the FEATURE
|
|
378
|
+
// creators (enrichLibraryCallbacks, enrichMcpToolDefinitions) so HANDLES
|
|
379
|
+
// edges already exist, and BEFORE generateManifest so contracts can flow
|
|
380
|
+
// into the manifest if needed.
|
|
381
|
+
try {
|
|
382
|
+
const client = (backend as unknown as { client: Parameters<typeof enrichContracts>[0] }).client;
|
|
383
|
+
if (client) {
|
|
384
|
+
const result = await enrichContracts(client);
|
|
385
|
+
info(` Contracts: ${result.contractsCreated} contracts (${result.inputsTotal} inputs, ${result.outputsTotal} outputs, ${result.errorsTotal} errors); ${result.featuresWithoutEntry} features lacked HANDLES edge`);
|
|
386
|
+
}
|
|
387
|
+
} catch (err) {
|
|
388
|
+
debug(`Contract enricher skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Speced-contract enricher — for every FEATURE node, run the registered
|
|
392
|
+
// per-category extractors (commander spec strings, MCP inputSchema, …)
|
|
393
|
+
// to produce SPECED_CONTRACT nodes carrying the user-facing interface.
|
|
394
|
+
// Distinct from the existing CONTRACT (handler signature scrape) which
|
|
395
|
+
// is implementation-side. See `_ai/research/feature-taxonomy.md` §1.3.
|
|
396
|
+
try {
|
|
397
|
+
const client = (backend as unknown as { client: Parameters<typeof enrichSpecedContracts>[0] }).client;
|
|
398
|
+
if (client) {
|
|
399
|
+
const result = await enrichSpecedContracts(client, [
|
|
400
|
+
commanderExtractor,
|
|
401
|
+
mcpInputSchemaExtractor,
|
|
402
|
+
vscodeContributesExtractor,
|
|
403
|
+
httpRouteExtractor,
|
|
404
|
+
]);
|
|
405
|
+
info(` Speced contracts: ${result.contractsCreated} (${result.inputsTotal} inputs); byCategory=${JSON.stringify(result.byCategory)}; missingExtractor=${result.featuresWithoutExtractor}, missingSpec=${result.featuresWithoutSpec}`);
|
|
406
|
+
}
|
|
407
|
+
} catch (err) {
|
|
408
|
+
debug(`Speced contract enricher skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Behavior enricher — for every FEATURE-class node, walk the HANDLES
|
|
412
|
+
// edge to the entry function and compute a transitive CALLS closure.
|
|
413
|
+
// Stores BEHAVIOR with hash + effects + summary (no COMPRISES edges —
|
|
414
|
+
// see skill `materialize-only-what-queries-need`). Pass 2 emits
|
|
415
|
+
// SHARES_BEHAVIOR_WITH between behaviors with identical hash.
|
|
416
|
+
try {
|
|
417
|
+
const client = (backend as unknown as { client: Parameters<typeof enrichBehaviors>[0] }).client;
|
|
418
|
+
if (client) {
|
|
419
|
+
const result = await enrichBehaviors(client, effectsLookup);
|
|
420
|
+
info(` Behaviors: ${result.behaviorsCreated} BEHAVIOR nodes, ${result.sharesBehaviorEdges} SHARES_BEHAVIOR_WITH edges (totalCoreNodes=${result.totalCoreNodes}, missingEntry=${result.featuresWithoutEntry})`);
|
|
421
|
+
}
|
|
422
|
+
} catch (err) {
|
|
423
|
+
debug(`Behavior enricher skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Package API enricher — for every monorepo package barrel
|
|
427
|
+
// (`packages/<pkg>/src/index.ts`), emit a `package:export` FEATURE node
|
|
428
|
+
// per EXPORT_BINDING and a HANDLES edge to the underlying definition.
|
|
429
|
+
// Surfaces inter-package public-API surfaces so the contract enricher
|
|
430
|
+
// (run already) can wire contracts onto these on the next pass; the
|
|
431
|
+
// benefit is realised by downstream consumers (manifest, GUI, agents).
|
|
432
|
+
try {
|
|
433
|
+
const client = (backend as unknown as { client: Parameters<typeof enrichPackageApis>[0] }).client;
|
|
434
|
+
if (client) {
|
|
435
|
+
const result = await enrichPackageApis(client);
|
|
436
|
+
if (result.apiNodesCreated > 0) {
|
|
437
|
+
info(` Package APIs: ${result.apiNodesCreated} package:export nodes, ${result.handlesEdgesCreated} HANDLES edges across ${result.packagesScanned} barrels (unresolved: ${result.exportsWithoutHandler})`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
} catch (err) {
|
|
441
|
+
debug(`Package API enricher skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
442
|
+
}
|
|
443
|
+
|
|
325
444
|
// Generate manifest after successful analysis
|
|
326
445
|
try {
|
|
327
446
|
const manifestPath = await generateManifest(backend, projectPath, grafemaDir, debug);
|
|
@@ -381,6 +500,20 @@ export async function analyzeAction(path: string, options: { service?: string; e
|
|
|
381
500
|
}
|
|
382
501
|
}
|
|
383
502
|
|
|
503
|
+
/**
|
|
504
|
+
* Resolve effects-db directory: prefer the one shipped next to the CLI package,
|
|
505
|
+
* fall back to a project-local effects-db. Returns undefined if neither exists.
|
|
506
|
+
* Shared by both the library-callback enricher and ManifestGenerator.
|
|
507
|
+
*/
|
|
508
|
+
function resolveEffectsDbPath(projectPath: string): string | undefined {
|
|
509
|
+
const cliDir = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
510
|
+
const candidates = [
|
|
511
|
+
join(cliDir, 'effects-db'),
|
|
512
|
+
join(projectPath, 'effects-db'),
|
|
513
|
+
];
|
|
514
|
+
return candidates.find(p => existsSync(p));
|
|
515
|
+
}
|
|
516
|
+
|
|
384
517
|
/**
|
|
385
518
|
* Generate manifest.yaml after successful analysis.
|
|
386
519
|
* Reads package.json to determine package name and entry point,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Level 4: Informational - checkVersions
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { existsSync, readFileSync, statSync } from 'fs';
|
|
11
|
+
import { existsSync, readFileSync, statSync, unlinkSync } from 'fs';
|
|
12
12
|
import { join, dirname, delimiter } from 'path';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
14
|
import { createRequire } from 'module';
|
|
@@ -261,11 +261,12 @@ export async function checkServerStatus(
|
|
|
261
261
|
details: { version, socketPath },
|
|
262
262
|
};
|
|
263
263
|
} catch {
|
|
264
|
+
try { unlinkSync(socketPath); } catch { /* already gone */ }
|
|
264
265
|
return {
|
|
265
266
|
name: 'server',
|
|
266
267
|
status: 'warn',
|
|
267
|
-
message: '
|
|
268
|
-
recommendation: 'Run: grafema analyze (
|
|
268
|
+
message: 'Stale socket removed. Run grafema analyze to restart server.',
|
|
269
|
+
recommendation: 'Run: grafema analyze (starts fresh server)',
|
|
269
270
|
};
|
|
270
271
|
}
|
|
271
272
|
}
|
package/src/commands/explore.tsx
CHANGED
|
@@ -74,6 +74,7 @@ interface ExploreState {
|
|
|
74
74
|
// Code preview
|
|
75
75
|
showCodePreview: boolean;
|
|
76
76
|
codePreviewLines: string[];
|
|
77
|
+
showHelp: boolean;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
interface ExplorerProps {
|
|
@@ -108,6 +109,7 @@ function Explorer({ backend, startNode, projectPath }: ExplorerProps) {
|
|
|
108
109
|
viewMode: 'function',
|
|
109
110
|
showCodePreview: false,
|
|
110
111
|
codePreviewLines: [],
|
|
112
|
+
showHelp: false,
|
|
111
113
|
});
|
|
112
114
|
|
|
113
115
|
// Load data when currentNode changes
|
|
@@ -214,7 +216,7 @@ function Explorer({ backend, startNode, projectPath }: ExplorerProps) {
|
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
if (input === '?') {
|
|
217
|
-
|
|
219
|
+
setState(s => ({ ...s, showHelp: !s.showHelp }))
|
|
218
220
|
return;
|
|
219
221
|
}
|
|
220
222
|
|
|
@@ -745,10 +747,35 @@ function Explorer({ backend, startNode, projectPath }: ExplorerProps) {
|
|
|
745
747
|
</Box>
|
|
746
748
|
)}
|
|
747
749
|
|
|
750
|
+
{/* Help overlay */}
|
|
751
|
+
{state.showHelp && (
|
|
752
|
+
<Box
|
|
753
|
+
flexDirection="column"
|
|
754
|
+
borderStyle="single"
|
|
755
|
+
borderColor="cyan"
|
|
756
|
+
paddingX={1}
|
|
757
|
+
marginBottom={1}
|
|
758
|
+
>
|
|
759
|
+
<Text bold color="cyan"> Клавиши управления </Text>
|
|
760
|
+
<Text> q — выход</Text>
|
|
761
|
+
<Text> / — поиск</Text>
|
|
762
|
+
<Text> ? — помощь (это окно)</Text>
|
|
763
|
+
<Text> m — переключить режим (модули/функции)</Text>
|
|
764
|
+
<Text> Space — предпросмотр кода</Text>
|
|
765
|
+
<Text> ←/h — callers / fields / sources</Text>
|
|
766
|
+
<Text> →/l — callees / methods / targets</Text>
|
|
767
|
+
<Text> ↑/k — предыдущий элемент</Text>
|
|
768
|
+
<Text> ↓/j — следующий элемент</Text>
|
|
769
|
+
<Text> Enter — перейти к узлу</Text>
|
|
770
|
+
<Text> Bksp — назад</Text>
|
|
771
|
+
<Text> Tab — toggle callers/callees</Text>
|
|
772
|
+
</Box>
|
|
773
|
+
)}
|
|
774
|
+
|
|
748
775
|
{/* Help footer */}
|
|
749
776
|
<Box marginTop={1} borderStyle="single" borderColor="gray" paddingX={1}>
|
|
750
777
|
<Text color="gray">
|
|
751
|
-
↑↓: Select | ←→: Panel | Enter: Open | Backspace: Back | /: Search | m: Modules | Space: Code | o: Editor | q: Quit
|
|
778
|
+
↑↓: Select | ←→: Panel | Enter: Open | Backspace: Back | /: Search | m: Modules | Space: Code | o: Editor | ?: Help | q: Quit
|
|
752
779
|
</Text>
|
|
753
780
|
</Box>
|
|
754
781
|
</Box>
|