Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e23adad
build(code-analysis): add java-parser dependency
CheeseMiao0520 Oct 24, 2026
882d9d6
feat(code-analysis): parse Java sources and measure method complexity
CheeseMiao0520 Oct 24, 2026
709d835
feat(code-analysis): resolve Java type dependencies conservatively
CheeseMiao0520 Oct 24, 2026
54e9ecd
feat(code-analysis): integrate Java into the analysis pipeline
CheeseMiao0520 Oct 24, 2026
08b3255
docs(code-analysis): document Java support and limitations
CheeseMiao0520 Oct 24, 2026
241bc52
build: refresh package for Java code analysis
CheeseMiao0520 Oct 24, 2026
529d7e9
feat(code-analysis): resolve Java class bodies through analyzed super…
CheeseMiao0520 Oct 24, 2026
19d0ae6
feat(code-analysis): group Java modules by build module or package
CheeseMiao0520 Oct 24, 2026
363c868
fix(code-analysis): keep JS/TS and Python trees with Java sources in …
CheeseMiao0520 Oct 24, 2026
de4bce6
fix(code-analysis): call unresolved Java records dependency records
CheeseMiao0520 Oct 24, 2026
5a65da8
build: refresh package for Java resolution and module grouping
CheeseMiao0520 Oct 24, 2026
22ed111
ci: run the Code Analysis module suite in full regression
CheeseMiao0520 Oct 24, 2026
05b712e
feat(code-analysis): open Java bodies under common JDK supertypes
CheeseMiao0520 Oct 24, 2026
4b4e0e1
docs(code-analysis): state the Java grouping contract
CheeseMiao0520 Oct 24, 2026
4fc2738
build: refresh package for Java JDK supertypes and CI coverage
CheeseMiao0520 Oct 24, 2026
412abb4
fix(code-analysis): infer Java JDK supertypes only from single-type i…
CheeseMiao0520 Oct 25, 2026
b21b90b
build: refresh package for Java JDK supertype narrowing
CheeseMiao0520 Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ jobs:
- name: Verify community Hermes adapter
if: matrix.shard == 2
run: node --test integrations/hermes-agent/test/plugin-contract.test.mjs
# The root runner enumerates only test/; the module suite lives with the module.
- name: Code Analysis module suite
if: matrix.shard == 1
run: npm --prefix archify run test:code-analysis
- name: Run a complete regression shard
run: node scripts/run-tests.mjs --shard=${{ matrix.shard }}/2

Expand Down
Binary file modified archify.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion archify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ When reporting verification details, distinguish artifact checks, browser eviden

## Code Analysis (architecture diagrams that must reflect real code)

For coupling, circular dependencies, and hub modules, use Code Analysis on a validated architecture candidate: `node bin/archify.mjs code-analysis serve <repo-root> --ir <candidate.json> --out <dir> [--language ts|py]`. It delivers first, installs its dependencies on first use, and analyzes only after the reader opens the printed URL and clicks **Code Analysis**. For a terminal or CI run without a diagram, use `node bin/archify.mjs code-analysis check <repo-root> [--baseline baseline.json] [--fail-on warning]`; it exits 1 when an open finding reaches the gate.
For coupling, circular dependencies, and hub modules, use Code Analysis on a validated architecture candidate: `node bin/archify.mjs code-analysis serve <repo-root> --ir <candidate.json> --out <dir> [--language ts|py|java]`. It delivers first, installs its dependencies on first use, and analyzes only after the reader opens the printed URL and clicks **Code Analysis**. For a terminal or CI run without a diagram, use `node bin/archify.mjs code-analysis check <repo-root> [--baseline baseline.json] [--fail-on warning]`; it exits 1 when an open finding reaches the gate.

Analysis describes the working tree, not a committed snapshot. Keep authored commit evidence separate; never pin uncommitted content to HEAD. Use verified `sources` or an explicit `--map` to associate components with modules. Source panels retain the extracted text. If the architecture JSON changes, regenerate the diagram before analysis. Findings describe static evidence, not proven runtime failures. Read `modules/code-analysis/docs/USAGE.md` for the workflow and `modules/code-analysis/README.md` for options.

Expand Down
8 changes: 4 additions & 4 deletions archify/bin/archify.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2190,10 +2190,10 @@ function invalidProvenance(artifactPath, sidecar, reason, evidence = {}) {
}

const COMMAND_USAGE = {
start: '<repo-root> --ir <architecture.json> [--out <dir>] [--language ts|py] [--map file] [--config file] [--baseline file] [--quality standard|showcase]',
start: '<repo-root> --ir <architecture.json> [--out <dir>] [--language ts|py|java] [--map file] [--config file] [--baseline file] [--quality standard|showcase]',
'code-analysis': [
'serve <repo-root> --ir <architecture.json> --out <dir> [--language ts|py] [--map file] [--config file] [--baseline file] [--quality standard|showcase]',
'check <repo-root> [--language ts|py] [--config file] [--baseline file] [--compare findings.json] [--out dir] [--fail-on error|warning|info|never] [--new-only] [--update-baseline] [--reason text] [--json]',
'serve <repo-root> --ir <architecture.json> --out <dir> [--language ts|py|java] [--map file] [--config file] [--baseline file] [--quality standard|showcase]',
'check <repo-root> [--language ts|py|java] [--config file] [--baseline file] [--compare findings.json] [--out dir] [--fail-on error|warning|info|never] [--new-only] [--update-baseline] [--reason text] [--json]',
'task <analysis-dir> --finding <id> [--finding <id> …] [--root <repo-root>] [--command cmd] [--format md|json] [--out file] [--require-valid]',
'task --verify <task.json> --root <repo-root> [--format md|json] [--out file] [--require-valid]',
],
Expand Down Expand Up @@ -7227,7 +7227,7 @@ try {
break;
case 'start': {
if (!args.length || args[0] === '--help' || args[0] === '-h') {
console.log('Usage: archify start <repo-root> --ir <architecture.json> [--out <dir>] [--language ts|py] [--map file] [--config file] [--baseline file] [--quality standard|showcase]');
console.log('Usage: archify start <repo-root> --ir <architecture.json> [--out <dir>] [--language ts|py|java] [--map file] [--config file] [--baseline file] [--quality standard|showcase]');
break;
}
const { startAnalysisView } = await import('../modules/code-analysis/bin/serve.mjs');
Expand Down
11 changes: 6 additions & 5 deletions archify/modules/code-analysis/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ The server serves the diagram on a loopback address with a Code Analysis button.

`lib/analysis.mjs` coordinates four stages:

1. **Extract facts** (`extract/`): select the Python or JS/TS adapter, read source files, and record files, imports, available symbol information, and unresolved dependencies. Python uses an AST extractor; JS/TS uses the TypeScript Compiler API. Each run selects one language.
2. **Build the module graph** (`graphs/module.mjs`): group files by explicit configuration, package boundaries, or directory depth; aggregate dependencies between modules; calculate file ownership and module metrics. Root-level files form individual modules. Test and generated roles are excluded by default and counted in the output.
3. **Evaluate rules** (`evaluate/`): run the import-cycle, module coupling-cycle, and hub rules; function complexity (Python and JS/TS); and architecture-boundary rules when the config declares them. Findings include severity, subjects, and supporting evidence. Configured rule suppression is counted in the summary.
1. **Extract facts** (`extract/`): select the Python, JS/TS or Java adapter, read source files, and record files, imports, available symbol information, and unresolved dependencies. Python uses an AST extractor; JS/TS uses the TypeScript Compiler API; Java uses `java-parser` CSTs reduced to a declaration/reference index one file at a time. Each run selects one language.
2. **Build the module graph** (`graphs/module.mjs`): group files by explicit configuration, package boundaries, or directory depth (Java: build modules, or packages in a single-module build); aggregate dependencies between modules; calculate file ownership and module metrics. Root-level files form individual modules. Test and generated roles are excluded by default and counted in the output.
3. **Evaluate rules** (`evaluate/`): run the import-cycle, module coupling-cycle, and hub rules; function complexity (Python, JS/TS and Java); and architecture-boundary rules when the config declares them. Java cycles describe structural dependencies, without inferring class initialization risk. Findings include severity, subjects, and supporting evidence. Configured rule suppression is counted in the summary.
4. **Build the analysis view** (`overlay/inject.mjs`): map authored components to code modules using source references or an explicit mapping, then add findings and source navigation to a copy of the delivered page.

The orchestrator validates intermediate data against JSON schemas. It also checks that supplied raw facts and module graph data agree on repository metadata, file ownership, and dependency aggregates.
Expand All @@ -49,11 +49,12 @@ Source references with line numbers show a nine-line context window and highligh
- `config/`: default source inclusion, exclusions, and file-role patterns.
- `extract/py/`: Python extraction and adapter integration.
- `extract/ts/`: JavaScript and TypeScript extraction.
- `extract/java/`: Java parsing, conservative source dependency resolution, and method/constructor metrics. See [Java support](docs/JAVA.md).
- `extract/shared/`: file, Git metadata, matching, diagnostics, semantics, and schema helpers.
- `graphs/`: module grouping and dependency aggregation.
- `evaluate/rules/coupling/`: import-cycle, module-cycle, and hub rules.
- `evaluate/rules/architecture/`: opt-in layer boundary rules declared in the config.
- `evaluate/rules/complexity/`: function complexity and nesting thresholds (Python and JS/TS functions, measured by each extractor; JS/TS in `extract/ts/functions.mjs`).
- `evaluate/rules/complexity/`: shared function complexity and nesting thresholds; measurements come from each language extractor.
- `lib/`: pipeline orchestration, config merging, intermediate-data checks, review (`review.mjs`: baseline, run comparison and comparability), AI tasks (`task.mjs`: task model and Markdown rendering) and evidence checks (`evidence.mjs`: captured source against the working tree).
- `bin/check.mjs`: headless analysis for terminals and CI; `bin/task.mjs`: AI task export and evidence check; `bin/analyze-run.mjs`: one analysis run in a child process for the server.
- `overlay/`: mapping and browser presentation.
Expand All @@ -80,7 +81,7 @@ The analysis HTML embeds source context for mapped and evidence files and can di

## Runtime dependencies and boundaries

The module uses `typescript` for JS/TS parsing and `ajv` for JSON schema checks. Python analysis also requires a Python interpreter. Archify's installation installs module dependencies; the server can install missing dependencies on first use.
The module uses `typescript` for JS/TS parsing, `java-parser` for Java parsing, and `ajv` for JSON schema checks. Python analysis also requires a Python interpreter. Java analysis requires no JVM. Archify's installation installs module dependencies; the server can install missing dependencies on first use.

The local server checks the request host and requires the matching origin and per-server token for analysis requests. Embedded source collection is bounded to the analyzed source root. The `serve`, `check`, and `task` entry points all initialize missing module dependencies before loading the analysis libraries, including in a freshly extracted package.

Expand Down
19 changes: 12 additions & 7 deletions archify/modules/code-analysis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Start Archify with `npm start -- "/path/to/project" --ir architecture.json` from
[Quick start guide](docs/USAGE.md) — installation, startup, and viewing analysis results.

Code Analysis is Archify's integrated static code analysis module, imported from
Bauify (commit 4bb811c) and maintained here. It reads a repository's imports
(Python and JS/TS), folds files into modules, checks import cycles, coupling,
Bauify (commit 4bb811c) and maintained here. It reads source dependencies
(Python, JS/TS and Java), folds files into modules, checks import cycles, coupling,
function complexity and configured architecture boundaries, and shows the result on the architecture diagram Archify delivered — as an
extra layer the reader switches on, never as a change to the diagram itself.

Expand Down Expand Up @@ -35,11 +35,11 @@ From the `archify/` package directory:
node bin/archify.mjs code-analysis serve /path/to/repo --ir architecture.json --out out/analysis --language py
```

No separate setup: the first run installs the module's two dependencies
(typescript, ajv) into `modules/code-analysis/node_modules`; `npm ci` in
No separate setup: the first run installs the module's parser and schema dependencies
(typescript, java-parser, ajv) into `modules/code-analysis/node_modules`; `npm ci` in
`archify/` does the same through its `postinstall`. Open the URL the command
prints and keep the process running. Options:
`--language ts|py` (required when the tree has both), `--map overlay-map.json`
`--language ts|py|java` (required when the scan matches both JS/TS and Python, or Java beside them under a root Maven/Gradle build file), `--map overlay-map.json`
(`{"componentId": ["moduleId", …]}` when the IR's `sources` do not say which
modules a component stands for), `--config file.json` (thresholds, include /
exclude, roles), `--quality standard|showcase` (passed to `archify deliver`).
Expand All @@ -52,12 +52,17 @@ layer, self-contained. Click **Re-analyze** for a fresh analysis after changing
source code or the `--config` file; only a changed architecture JSON needs a
restart. The previous run is kept in `analysis.previous/` and compared with.

The local process exists because a standalone HTML cannot run the Python /
TypeScript extractor. It listens only on loopback and accepts analysis requests
The local process exists because a standalone HTML cannot run the source
extractors. It listens only on loopback and accepts analysis requests
only from its own page; browser requests cannot select repository or output
paths. Python analysis requires Python 3; `BAUIFY_PYTHON` can select its
executable. The analyzed code is never executed.

Java analysis runs in Node.js without a JDK. It extracts source dependencies and
method/constructor complexity; it does not build the project or resolve Maven,
Gradle, Spring, generated symbols or runtime class loading. See
[Java support and limitations](docs/JAVA.md) for resolution and syntax coverage.

Findings describe working-tree facts with evidence (file, line, import, captured source) and grade
potential import-time risks without claiming that execution is safe or that a runtime failure is proven. See
[ARCHITECTURE.md](ARCHITECTURE.md) and the [technical guide](docs/TECH-GUIDE.md).
Expand Down
4 changes: 2 additions & 2 deletions archify/modules/code-analysis/bin/check.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url';
import { DiagnosticError, fail, receipt } from '../extract/shared/diagnostics.mjs';

export const USAGE = `Usage:
archify code-analysis check <repo-root> [--language ts|py] [--config file.json]
archify code-analysis check <repo-root> [--language ts|py|java] [--config file.json]
[--baseline baseline.json] [--compare findings.json] [--out dir]
[--fail-on error|warning|info|never] [--new-only]
[--update-baseline] [--reason text] [--json]
Expand Down Expand Up @@ -124,7 +124,7 @@ export function formatText(r) {
const lines = [];
const c = r.counts;
lines.push(`Code analysis: ${r.verdict} — ${c.findings} finding${c.findings === 1 ? '' : 's'} (${c.error} error, ${c.warning} warning, ${c.info} info open; ${c.accepted} accepted)`);
lines.push(` ${r.language === 'py' ? 'Python' : 'JS/TS'} · ${r.files} files · rules: ${r.rules.join(', ')}`);
lines.push(` ${({ py: 'Python', ts: 'JS/TS', java: 'Java' })[r.language] || r.language} · ${r.files} files · rules: ${r.rules.join(', ')}`);
if (r.review.comparison) {
const c = r.review.comparison;
lines.push(` Since the previous run: ${c.new} new, ${c.notDetected} no longer detected, ${c.evidenceChanged} with changed evidence`);
Expand Down
7 changes: 3 additions & 4 deletions archify/modules/code-analysis/bin/serve.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,12 @@ export function runWorker(options) {
});
}

// The module's two dependencies (typescript for the JS/TS extractor, ajv for
// schema checks) live in its own package. Archify itself needs no install, and
// Parser and schema dependencies live in the module's own package. Archify itself needs no install, and
// the skill is often used from a plain copy of the folder, so the first `serve`
// installs them on demand instead of asking for a separate setup step.
export async function ensureDependencies(root = moduleRoot) {
root = fs.realpathSync(root);
const missingPackages = () => ['typescript', 'ajv'].filter(name => !fs.existsSync(path.join(root, 'node_modules', name, 'package.json')));
const missingPackages = () => ['typescript', 'ajv', 'java-parser'].filter(name => !fs.existsSync(path.join(root, 'node_modules', name, 'package.json')));
// Installed, read-only copies need no lock file. An active installer must
// finish even if its package manifests have already appeared.
if (!missingPackages().length && !fs.existsSync(path.join(root, '.code-analysis-install.lock'))) return false;
Expand All @@ -78,7 +77,7 @@ export async function ensureDependencies(root = moduleRoot) {

export const USAGE = `Usage:
archify code-analysis serve <repo-root> --ir <architecture.json> --out <dir>
[--language ts|py] [--map overlay-map.json] [--config file.json]
[--language ts|py|java] [--map overlay-map.json] [--config file.json]
[--baseline baseline.json] [--quality standard|showcase]

Delivers the authored diagram with Archify, serves it on a local port, and runs the
Expand Down
4 changes: 3 additions & 1 deletion archify/modules/code-analysis/config/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
"schema_version": 1,
"include": [
"**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
"**/*.py"
"**/*.py",
"**/*.java"
],
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/build/**",
"**/target/**/*.java",
"**/coverage/**",
"**/*.d.ts",
"**/venv/**",
Expand Down
Loading
Loading