@brainwav/diagram 1.0.7 → 1.1.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/.diagram/contracts/machine-command-coverage.json +73 -0
- package/.diagram/migration/finalization-policy.json +20 -0
- package/LICENSE +202 -21
- package/README.md +132 -339
- package/package.json +46 -13
- package/scripts/refresh-diagram-context.sh +274 -182
- package/src/analyzers/default-analyzer.js +11 -0
- package/src/analyzers/index.js +34 -0
- package/src/artifacts/agent-context.js +105 -0
- package/src/artifacts/artifact-budget.js +224 -0
- package/src/artifacts/brief.js +153 -0
- package/src/artifacts/evidence-manifest.js +206 -0
- package/src/artifacts/evidence-summary.js +29 -0
- package/src/commands/analyze.js +125 -0
- package/src/commands/changed.js +185 -0
- package/src/commands/context.js +110 -0
- package/src/commands/diff.js +142 -0
- package/src/commands/doctor.js +335 -0
- package/src/commands/explain.js +273 -0
- package/src/commands/generate-all.js +170 -0
- package/src/commands/generate-animated.js +50 -0
- package/src/commands/generate-video.js +65 -0
- package/src/commands/generate.js +522 -0
- package/src/commands/init.js +123 -0
- package/src/commands/output.js +76 -0
- package/src/commands/scan.js +624 -0
- package/src/commands/shared.js +396 -0
- package/src/commands/validate.js +328 -0
- package/src/commands/video-shared.js +105 -0
- package/src/commands/workflow-pr.js +26 -0
- package/src/confidence/pipeline.js +186 -0
- package/src/config/diagramrc.js +79 -0
- package/src/context/build-context-pack.js +291 -0
- package/src/context/normalize-diagram-manifest.js +282 -0
- package/src/core/analysis-generation-analyze-components.js +102 -0
- package/src/core/analysis-generation-analyze-dependencies.js +33 -0
- package/src/core/analysis-generation-analyze-files.js +48 -0
- package/src/core/analysis-generation-analyze-options.js +73 -0
- package/src/core/analysis-generation-analyze.js +63 -0
- package/src/core/analysis-generation-constants.js +53 -0
- package/src/core/analysis-generation-diagrams-core-architecture.js +105 -0
- package/src/core/analysis-generation-diagrams-core-dependency.js +68 -0
- package/src/core/analysis-generation-diagrams-core-sequence.js +142 -0
- package/src/core/analysis-generation-diagrams-core-shapes.js +104 -0
- package/src/core/analysis-generation-diagrams-core.js +12 -0
- package/src/core/analysis-generation-diagrams-empty.js +68 -0
- package/src/core/analysis-generation-diagrams-erd.js +59 -0
- package/src/core/analysis-generation-diagrams-limit.js +27 -0
- package/src/core/analysis-generation-diagrams-role-ai-agent.js +103 -0
- package/src/core/analysis-generation-diagrams-role-ai-context.js +186 -0
- package/src/core/analysis-generation-diagrams-role-ai.js +11 -0
- package/src/core/analysis-generation-diagrams-role-data.js +182 -0
- package/src/core/analysis-generation-diagrams-role-helpers.js +129 -0
- package/src/core/analysis-generation-diagrams-role-security.js +129 -0
- package/src/core/analysis-generation-diagrams-role.js +25 -0
- package/src/core/analysis-generation-diagrams.js +182 -0
- package/src/core/analysis-generation-role-tags-constants.js +55 -0
- package/src/core/analysis-generation-role-tags-imports.js +32 -0
- package/src/core/analysis-generation-role-tags-infer.js +49 -0
- package/src/core/analysis-generation-role-tags-match.js +19 -0
- package/src/core/analysis-generation-role-tags.js +7 -0
- package/src/core/analysis-generation-utils-core.js +308 -0
- package/src/core/analysis-generation-utils-graph.js +321 -0
- package/src/core/analysis-generation-utils-resolution.js +76 -0
- package/src/core/analysis-generation-utils.js +9 -0
- package/src/core/analysis-generation.js +44 -0
- package/src/diagram.js +180 -1760
- package/src/formatters/console.js +198 -0
- package/src/formatters/index.js +41 -0
- package/src/formatters/json.js +113 -0
- package/src/formatters/junit.js +123 -0
- package/src/graph.js +159 -0
- package/src/incremental/cache.js +210 -0
- package/src/ir/architecture-ir.js +48 -0
- package/src/migration/evidence.js +262 -0
- package/src/migration/finalization-policy.js +35 -0
- package/src/renderers/report-html.js +265 -0
- package/src/rules/factory.js +108 -0
- package/src/rules/types/base.js +54 -0
- package/src/rules/types/import-rule.js +286 -0
- package/src/rules.js +380 -0
- package/src/schema/erd-confidence.js +56 -0
- package/src/schema/erd-extractor.js +504 -0
- package/src/schema/erd-model.js +176 -0
- package/src/schema/rules-schema.js +170 -0
- package/src/utils/suggestions.js +67 -0
- package/src/video.js +4 -5
- package/src/workflow/git-helpers.js +576 -0
- package/src/workflow/pr-command.js +694 -0
- package/src/workflow/pr-impact.js +848 -0
- package/src/workflow/sort-utils.js +16 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const {
|
|
5
|
+
SUPPORTED_DIAGRAM_TYPES,
|
|
6
|
+
generateDiagramArtifact,
|
|
7
|
+
toManifestEntry,
|
|
8
|
+
} = require('../core/analysis-generation');
|
|
9
|
+
const {
|
|
10
|
+
resolveArtifactProfile,
|
|
11
|
+
applyArtifactBudget,
|
|
12
|
+
} = require('../artifacts/artifact-budget');
|
|
13
|
+
const {
|
|
14
|
+
createGenerateAllManifest,
|
|
15
|
+
writeJsonFile,
|
|
16
|
+
} = require('../artifacts/evidence-manifest');
|
|
17
|
+
const {
|
|
18
|
+
applyDiagramRcDefaults,
|
|
19
|
+
getDiagramRcFromProgram,
|
|
20
|
+
maybeWriteArchitectureIR,
|
|
21
|
+
resolveRootPathOrExit,
|
|
22
|
+
runAnalysisPipeline,
|
|
23
|
+
validateOutputPath,
|
|
24
|
+
} = require('./shared');
|
|
25
|
+
const { buildMachineEnvelope } = require('./output');
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Register the `generate-all [path]` CLI command which generates Mermaid diagram files for all supported diagram types and writes a manifest describing outputs and compaction decisions.
|
|
29
|
+
*
|
|
30
|
+
* The command analyses the target path, applies RC defaults, validates and resolves output and artifact profile, runs the analysis pipeline, optionally emits a typed architecture IR, generates diagrams for every supported type, applies an artifact budget to decide which diagrams to include/truncate/omit, writes `.mmd` files and a `manifest.json`, and emits either a machine-readable JSON envelope or human-friendly text output depending on the `--format` option.
|
|
31
|
+
*
|
|
32
|
+
* @param {import('commander').Command} program - Commander program instance to register the command on.
|
|
33
|
+
*/
|
|
34
|
+
function registerGenerateAllCommand(program) {
|
|
35
|
+
program
|
|
36
|
+
.command('generate-all [path]')
|
|
37
|
+
.description('Generate all diagram types')
|
|
38
|
+
.option('-O, --output-dir <dir>', 'Output directory', '.diagram')
|
|
39
|
+
.option('--artifact-profile <profile>', 'Artifact output profile (full, agent, ultra-compact)', 'full')
|
|
40
|
+
.option('-q, --quiet', 'Suppress non-essential logging', false)
|
|
41
|
+
.option('-p, --patterns <list>', 'File patterns')
|
|
42
|
+
.option('-e, --exclude <list>', 'Exclude patterns')
|
|
43
|
+
.option('-m, --max-files <n>', 'Max files to analyze')
|
|
44
|
+
.option('--analyzer <name>', 'Analyzer plugin to use', 'default')
|
|
45
|
+
.option('--emit-ir', 'Write typed architecture IR artifact', false)
|
|
46
|
+
.option('--incremental', 'Use incremental cache when available', false)
|
|
47
|
+
.option('-f, --format <type>', 'Output format (text, json)', 'text')
|
|
48
|
+
.option('--deterministic', 'Use deterministic machine output', false)
|
|
49
|
+
.action(async (targetPath, rawOptions) => {
|
|
50
|
+
const options = applyDiagramRcDefaults(rawOptions, getDiagramRcFromProgram(program), ['patterns', 'exclude', 'maxFiles']);
|
|
51
|
+
const root = resolveRootPathOrExit(targetPath);
|
|
52
|
+
let outDir;
|
|
53
|
+
let artifactProfile;
|
|
54
|
+
try {
|
|
55
|
+
outDir = validateOutputPath(options.outputDir, root);
|
|
56
|
+
artifactProfile = resolveArtifactProfile(options.artifactProfile);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error(chalk.red('❌ Configuration error:'), error.message);
|
|
59
|
+
process.exit(2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!options.quiet) {
|
|
63
|
+
console.error(chalk.blue('Analyzing'), root);
|
|
64
|
+
}
|
|
65
|
+
const pipeline = await runAnalysisPipeline(root, options, 'generate-all');
|
|
66
|
+
const data = pipeline.analysis;
|
|
67
|
+
const irPath = options.emitIr
|
|
68
|
+
? maybeWriteArchitectureIR(root, data, pipeline.analyzer, true)
|
|
69
|
+
: null;
|
|
70
|
+
|
|
71
|
+
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
72
|
+
|
|
73
|
+
const types = [...SUPPORTED_DIAGRAM_TYPES];
|
|
74
|
+
const generatedDiagrams = types.map((type) => {
|
|
75
|
+
const artifact = generateDiagramArtifact(data, type);
|
|
76
|
+
return {
|
|
77
|
+
type,
|
|
78
|
+
mermaid: artifact.mermaid,
|
|
79
|
+
metadata: artifact.metadata,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
const budgeted = applyArtifactBudget(generatedDiagrams, artifactProfile);
|
|
83
|
+
|
|
84
|
+
const staleMermaidFiles = fs
|
|
85
|
+
.readdirSync(outDir, { withFileTypes: true })
|
|
86
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.mmd'))
|
|
87
|
+
.map((entry) => path.join(outDir, entry.name));
|
|
88
|
+
for (const staleFile of staleMermaidFiles) {
|
|
89
|
+
fs.rmSync(staleFile, { force: true });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const manifest = createGenerateAllManifest({
|
|
93
|
+
root,
|
|
94
|
+
outDir,
|
|
95
|
+
artifactProfile,
|
|
96
|
+
budgeted,
|
|
97
|
+
deterministic: Boolean(options.deterministic),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
for (const entry of budgeted.included) {
|
|
101
|
+
const file = path.join(outDir, `${entry.type}.mmd`);
|
|
102
|
+
fs.writeFileSync(file, entry.mermaid);
|
|
103
|
+
const manifestEntry = toManifestEntry(entry.type, file, entry.mermaid, root, entry.metadata);
|
|
104
|
+
if (entry.truncated) {
|
|
105
|
+
manifestEntry.compacted = true;
|
|
106
|
+
manifestEntry.sourceBytes = entry.originalBytes;
|
|
107
|
+
manifestEntry.bytesSaved = entry.bytesSaved;
|
|
108
|
+
}
|
|
109
|
+
manifest.diagrams.push(manifestEntry);
|
|
110
|
+
if (!options.quiet) {
|
|
111
|
+
const truncationSuffix = entry.truncated ? chalk.yellow(' [truncated]') : '';
|
|
112
|
+
console.error(chalk.green('✅'), entry.type, '→', file, truncationSuffix);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
manifest.diagrams = manifest.diagrams.sort((a, b) => a.type.localeCompare(b.type));
|
|
117
|
+
const manifestPath = path.join(outDir, 'manifest.json');
|
|
118
|
+
writeJsonFile(manifestPath, manifest);
|
|
119
|
+
|
|
120
|
+
const formatStr = (options.format || 'text').toLowerCase();
|
|
121
|
+
if (formatStr === 'json') {
|
|
122
|
+
const payload = buildMachineEnvelope({
|
|
123
|
+
schemaVersion: '1.0',
|
|
124
|
+
command: 'generate-all',
|
|
125
|
+
rootPath: root,
|
|
126
|
+
deterministic: Boolean(options.deterministic),
|
|
127
|
+
data: {
|
|
128
|
+
manifest,
|
|
129
|
+
artifacts: {
|
|
130
|
+
manifestPath,
|
|
131
|
+
architectureIrPath: irPath,
|
|
132
|
+
},
|
|
133
|
+
analyzer: pipeline.analyzer,
|
|
134
|
+
incremental: pipeline.incremental,
|
|
135
|
+
},
|
|
136
|
+
agentSummary: {
|
|
137
|
+
changedComponents: data.components?.length || 0,
|
|
138
|
+
riskReasons: manifest.compaction.omittedTypes.length > 0 ? ['artifact_budget_omitted_types'] : [],
|
|
139
|
+
suggestedReviewerChecks: [
|
|
140
|
+
'Review omitted diagram types when using compact profiles.',
|
|
141
|
+
'Attach `.diagram/manifest.json` to CI artifacts for agent consumers.',
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!options.quiet) {
|
|
150
|
+
if (manifest.compaction.omittedTypes.length > 0) {
|
|
151
|
+
console.error(
|
|
152
|
+
chalk.yellow('⚠️ omitted diagrams:'),
|
|
153
|
+
manifest.compaction.omittedTypes.join(', ')
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
console.error(chalk.green('✅ manifest'), '→', manifestPath);
|
|
157
|
+
if (irPath) {
|
|
158
|
+
console.error(chalk.gray('IR artifact:'), irPath);
|
|
159
|
+
}
|
|
160
|
+
console.error(chalk.cyan('\n🔗 Preview all at: https://mermaid.live'));
|
|
161
|
+
console.log(chalk.cyan('\nNext steps:'));
|
|
162
|
+
console.log(' 1) Run `archscope context .` to refresh compact AI context pack files.');
|
|
163
|
+
console.log(' 2) Upload `.diagram` artifacts in CI for PR analysis workflows.');
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
registerGenerateAllCommand,
|
|
170
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const {
|
|
3
|
+
buildMermaidForMedia,
|
|
4
|
+
getVideoModule,
|
|
5
|
+
resolveMediaCommandContext,
|
|
6
|
+
} = require('./video-shared');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register the `generate-animated` CLI command on the provided program.
|
|
10
|
+
*
|
|
11
|
+
* The command generates an animated SVG from media files under a target path, accepting options
|
|
12
|
+
* for diagram type, output file, theme, include/exclude patterns and analysis limits; it resolves
|
|
13
|
+
* the command context, builds Mermaid content and writes the animated SVG.
|
|
14
|
+
*/
|
|
15
|
+
function registerGenerateAnimatedCommand(program) {
|
|
16
|
+
program
|
|
17
|
+
.command('generate-animated [path]')
|
|
18
|
+
.description('Generate animated SVG with CSS animations')
|
|
19
|
+
.option('-t, --type <type>', 'Diagram type', 'architecture')
|
|
20
|
+
.option('-o, --output <file>', 'Output file', 'diagram-animated.svg')
|
|
21
|
+
.option('--force', 'Overwrite output file if it exists', false)
|
|
22
|
+
.option('-q, --quiet', 'Suppress non-essential logging', false)
|
|
23
|
+
.option('--theme <theme>', 'Theme: default, dark, forest, neutral, light')
|
|
24
|
+
.option('-m, --max-files <n>', 'Max files to analyze')
|
|
25
|
+
.option('-p, --patterns <list>', 'File patterns (comma-separated)')
|
|
26
|
+
.option('-e, --exclude <list>', 'Exclude patterns')
|
|
27
|
+
.option('--format <type>', 'Output format (ignored for animated)', 'text')
|
|
28
|
+
.action(async (targetPath, rawOptions) => {
|
|
29
|
+
const { options, root, safeTheme, safeOutput } = resolveMediaCommandContext(
|
|
30
|
+
program,
|
|
31
|
+
targetPath,
|
|
32
|
+
rawOptions
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (!options.quiet) console.error(chalk.blue('✨ Generating animated SVG for'), root);
|
|
36
|
+
const mermaid = await buildMermaidForMedia(root, options);
|
|
37
|
+
const { generateAnimatedSVG } = getVideoModule('Animated output requires Playwright.');
|
|
38
|
+
await generateAnimatedSVG(mermaid, safeOutput, { theme: safeTheme });
|
|
39
|
+
|
|
40
|
+
if (!options.quiet) {
|
|
41
|
+
console.log(chalk.cyan('\nNext steps:'));
|
|
42
|
+
console.log(' 1) Run `archscope generate-video` when you need MP4/WebM output.');
|
|
43
|
+
console.log(' 2) Use `archscope doctor .` if Mermaid or Playwright toolchain checks fail.');
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
registerGenerateAnimatedCommand,
|
|
50
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const {
|
|
3
|
+
buildMermaidForMedia,
|
|
4
|
+
getVideoModule,
|
|
5
|
+
resolveMediaCommandContext,
|
|
6
|
+
} = require('./video-shared');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register the CLI subcommand `generate-video [path]` for producing an animated video from a diagram.
|
|
10
|
+
*
|
|
11
|
+
* The command accepts options for diagram type, output file, overwrite, verbosity, duration, FPS,
|
|
12
|
+
* dimensions, theme and analysis file patterns. When executed it resolves and validates the command
|
|
13
|
+
* context, builds a Mermaid representation of the diagram, loads the video generator (requires
|
|
14
|
+
* Playwright) and writes the resulting video to the specified output path using parsed numeric
|
|
15
|
+
* options for duration, fps, width and height.
|
|
16
|
+
*
|
|
17
|
+
* @param {import('commander').Command} program - Commander program instance to register the subcommand on.
|
|
18
|
+
*/
|
|
19
|
+
function registerGenerateVideoCommand(program) {
|
|
20
|
+
program
|
|
21
|
+
.command('generate-video [path]')
|
|
22
|
+
.description('Generate an animated video of the diagram')
|
|
23
|
+
.option('-t, --type <type>', 'Diagram type', 'architecture')
|
|
24
|
+
.option('-o, --output <file>', 'Output file (.mp4, .webm, .mov)', 'diagram.mp4')
|
|
25
|
+
.option('--force', 'Overwrite output file if it exists', false)
|
|
26
|
+
.option('-q, --quiet', 'Suppress non-essential logging', false)
|
|
27
|
+
.option('-d, --duration <sec>', 'Video duration in seconds', '5')
|
|
28
|
+
.option('-f, --fps <n>', 'Frames per second', '30')
|
|
29
|
+
.option('--width <n>', 'Video width', '1280')
|
|
30
|
+
.option('--height <n>', 'Video height', '720')
|
|
31
|
+
.option('--theme <theme>', 'Theme: default, dark, forest, neutral, light')
|
|
32
|
+
.option('-m, --max-files <n>', 'Max files to analyze')
|
|
33
|
+
.option('-p, --patterns <list>', 'File patterns (comma-separated)')
|
|
34
|
+
.option('-e, --exclude <list>', 'Exclude patterns')
|
|
35
|
+
.option('--format <type>', 'Output format (ignored for video)', 'text')
|
|
36
|
+
.action(async (targetPath, rawOptions) => {
|
|
37
|
+
const { options, root, safeTheme, safeOutput } = resolveMediaCommandContext(
|
|
38
|
+
program,
|
|
39
|
+
targetPath,
|
|
40
|
+
rawOptions
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!options.quiet) console.error(chalk.blue('🎬 Generating video for'), root);
|
|
44
|
+
const mermaid = await buildMermaidForMedia(root, options);
|
|
45
|
+
const { generateVideo } = getVideoModule('Video generation requires Playwright.');
|
|
46
|
+
|
|
47
|
+
await generateVideo(mermaid, safeOutput, {
|
|
48
|
+
duration: parseInt(options.duration, 10) || 5,
|
|
49
|
+
fps: parseInt(options.fps, 10) || 30,
|
|
50
|
+
width: parseInt(options.width, 10) || 1280,
|
|
51
|
+
height: parseInt(options.height, 10) || 720,
|
|
52
|
+
theme: safeTheme,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (!options.quiet) {
|
|
56
|
+
console.log(chalk.cyan('\nNext steps:'));
|
|
57
|
+
console.log(' 1) Run `archscope doctor .` if rendering quality/tooling is unstable in CI.');
|
|
58
|
+
console.log(' 2) Commit generated media only when required by your release workflow.');
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
registerGenerateVideoCommand,
|
|
65
|
+
};
|