wikifier 4.5.2__tar.gz → 4.5.4__tar.gz
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.
- {wikifier-4.5.2/wikifier.egg-info → wikifier-4.5.4}/PKG-INFO +43 -28
- {wikifier-4.5.2 → wikifier-4.5.4}/README.md +42 -27
- {wikifier-4.5.2 → wikifier-4.5.4}/skills/run.md +50 -21
- wikifier-4.5.4/tests/test_gap_closure.py +128 -0
- wikifier-4.5.4/tests/test_multi_lang_parsers.py +104 -0
- wikifier-4.5.4/tests/test_selftest_wrappers.py +39 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/__init__.py +15 -5
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/cli.py +233 -26
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/contracts.py +0 -227
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/daemon.py +37 -9
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/health.py +48 -15
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/import_cache.py +87 -54
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/mcp/server.py +23 -87
- wikifier-4.5.4/wikifier/parsers/__init__.py +23 -0
- wikifier-4.5.4/wikifier/parsers/_edge.py +71 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/parsers/bree.py +9 -29
- wikifier-4.5.4/wikifier/parsers/c_cpp.py +83 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/parsers/cdia.py +0 -112
- wikifier-4.5.4/wikifier/parsers/csharp.py +64 -0
- wikifier-4.5.4/wikifier/parsers/go_lang.py +87 -0
- wikifier-4.5.4/wikifier/parsers/java.py +64 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/parsers/javascript.py +8 -330
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/parsers/python.py +0 -44
- wikifier-4.5.4/wikifier/parsers/rust.py +133 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/resolution.py +0 -142
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/scripts/wikifier.sh +8 -2
- {wikifier-4.5.2 → wikifier-4.5.4/wikifier.egg-info}/PKG-INFO +43 -28
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier.egg-info/SOURCES.txt +15 -0
- wikifier-4.5.2/wikifier/parsers/__init__.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/CONTRIBUTING.md +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/LICENSE +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/MANIFEST.in +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/diagnostics.html +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/docs/spec.md +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/index.html +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/pyproject.toml +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/setup.cfg +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/tests/test_barrel_invalidation.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/tests/test_health.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/tests/test_import_cache.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/tests/test_parsers.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/__main__.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/diagnostics.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/index.html +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/library.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/locking.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/mcp/__init__.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/scripts/wikifier.bat +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/scripts/wikifier.ps1 +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier/serve.py +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier.egg-info/dependency_links.txt +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier.egg-info/entry_points.txt +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier.egg-info/requires.txt +0 -0
- {wikifier-4.5.2 → wikifier-4.5.4}/wikifier.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wikifier
|
|
3
|
-
Version: 4.5.
|
|
3
|
+
Version: 4.5.4
|
|
4
4
|
Summary: Zero-dependency agent-to-agent codebase wiki for LLMs and AI agents. Autonomously maintained via record-change and mark-green for token-efficient lookup of files, dependencies, health, and summaries — across tiny scripts to 50k+ monorepos. Optional MCP server with rich tools for agents.
|
|
5
5
|
Author-email: Aron Amos <aron@example.com>
|
|
6
6
|
Maintainer: Aron Amos
|
|
@@ -40,65 +40,75 @@ Dynamic: license-file
|
|
|
40
40
|
|
|
41
41
|
Wikifier is an **agent-to-agent** tool: it builds a living map of a project (health matrix, dependency graph, short file summaries) and agents keep that map current as they work. Humans can peek via a small dashboard; the product is the agent loop, not a general docs site or IDE.
|
|
42
42
|
|
|
43
|
-
Works from small scripts to large monorepos
|
|
43
|
+
Works from small scripts to large monorepos. **Deep import/include maps** (zero-dep regex parsers):
|
|
44
|
+
|
|
45
|
+
| Language | Extensions | Notes |
|
|
46
|
+
|----------|------------|--------|
|
|
47
|
+
| Python | `.py` | full ACS/CDIA path |
|
|
48
|
+
| JavaScript / TypeScript | `.js` `.ts` `.jsx` `.tsx` | barrels (BREE), dynamic/CDIA |
|
|
49
|
+
| Rust | `.rs` | `use` / `mod` / `extern crate` |
|
|
50
|
+
| Go | `.go` | `import` / import blocks |
|
|
51
|
+
| C / C++ | `.c` `.h` `.cpp` `.cc` `.cxx` `.hpp` `.hh` | `#include` (local + system) |
|
|
52
|
+
| C# | `.cs` | `using` namespaces |
|
|
53
|
+
| Java | `.java` | `import` / `import static` |
|
|
54
|
+
|
|
55
|
+
Health/journal still work for any monitored path. Parsers are **pragmatic regex** (not full cargo/`go.mod`/classpath/`-I` resolution). Prefer **lean `monitored_paths.txt`** on huge monorepos; raise dirty cap with `WIKIFIER_CHECK_CHANGES_MAX` (default 2000) only when needed.
|
|
44
56
|
|
|
45
57
|
## Why
|
|
46
58
|
|
|
47
59
|
Context windows are finite. Re-reading a large file to answer “what is this and who depends on it?” wastes tokens.
|
|
48
60
|
|
|
49
|
-
Wikifier keeps a small set of artifacts agents can query:
|
|
50
|
-
|
|
51
61
|
| Artifact | Role |
|
|
52
62
|
|----------|------|
|
|
53
63
|
| `file_health.md` | 🟢 / 🟡 / 🔴 matrix — what to trust, what to fix first |
|
|
54
64
|
| `library.md` | File tree, Mermaid dependency map, import tables, cycles + confidence |
|
|
55
|
-
| `*.wiki.md` | Short per-file “what this is for” notes (agent-maintained) |
|
|
56
|
-
| `journal/` | Semantic *why* trail
|
|
65
|
+
| `*.wiki.md` | Short per-file “what this is for” notes (**agent-maintained** prose) |
|
|
66
|
+
| `journal/` + `pending_updates.md` | Semantic *why* trail + work queue (audit, **not** a full issue tracker) |
|
|
57
67
|
|
|
58
|
-
|
|
68
|
+
**Map first, wiki depth second:** `update-maps` builds the structural map automatically. Rich per-file wiki text is filled by agents as they work — not a free full-repo “understand everything” pass on init.
|
|
59
69
|
|
|
60
|
-
##
|
|
70
|
+
## First run (bootstrap the map)
|
|
61
71
|
|
|
62
72
|
```bash
|
|
63
73
|
pip install wikifier # pure Python stdlib core — no runtime deps
|
|
64
74
|
pip install wikifier[mcp] # optional Model Context Protocol (MCP) server
|
|
65
75
|
|
|
66
76
|
cd /path/to/your/project
|
|
67
|
-
wikifier init
|
|
68
|
-
wikifier update-maps #
|
|
69
|
-
wikifier
|
|
70
|
-
wikifier
|
|
77
|
+
wikifier init # seeds + human index.html
|
|
78
|
+
wikifier update-maps # full structural map → library.md + import cache
|
|
79
|
+
wikifier health --summary # matrix counts
|
|
80
|
+
wikifier suggest-next # or MCP suggest_next_actions — 🔴/🟡 only
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
Always set an explicit root for external trees:
|
|
83
|
+
Always set an explicit root for external trees: `WIKIFIER_PROJECT_ROOT=/abs/path wikifier …`
|
|
74
84
|
|
|
75
|
-
|
|
76
|
-
WIKIFIER_PROJECT_ROOT=/abs/path/to/project wikifier check-changes
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Agent loop
|
|
85
|
+
## Steady state (only touch what needs it)
|
|
80
86
|
|
|
81
87
|
Full protocol: [`skills/run.md`](skills/run.md).
|
|
82
88
|
|
|
83
89
|
```bash
|
|
84
|
-
wikifier check-changes
|
|
85
|
-
# prioritize 🔴 then 🟡
|
|
86
|
-
# ... edit
|
|
90
|
+
wikifier check-changes # yellow dirty files; red ghosts (missing paths)
|
|
91
|
+
# prioritize 🔴 then 🟡 — do NOT re-wiki 🟢 Green files
|
|
92
|
+
# ... edit only those sources ...
|
|
87
93
|
wikifier record-change "path/file.py" "why this changed" # required
|
|
88
|
-
# ... refresh that file’s wiki summary ...
|
|
94
|
+
# ... refresh that file’s wiki summary only ...
|
|
89
95
|
wikifier mark-green "path/file.py"
|
|
90
|
-
wikifier update-maps # if imports/structure changed
|
|
96
|
+
wikifier update-maps # only if imports/structure changed
|
|
97
|
+
# removals:
|
|
98
|
+
wikifier record-deletion "path/gone.py" "why removed"
|
|
91
99
|
```
|
|
92
100
|
|
|
93
|
-
`
|
|
101
|
+
MCP **Core 6** (start every session): `get_project_status`, `check_changes`, `get_files_needing_attention`, `get_file_wiki`, `suggest_next_actions`, `record_change` / `mark_green`. Intel as needed: `get_dependencies`, `get_dependents`, `get_cycles`. Always pass `project_root=` for external trees.
|
|
94
102
|
|
|
95
103
|
## What you get
|
|
96
104
|
|
|
97
|
-
- **Import analysis** — Python
|
|
105
|
+
- **Import analysis** — Python, JS/TS (ESM/CJS, barrels), Rust, Go, C/C++ includes, C# usings; per-edge confidence; name-routed barrel expansion for TS/JS
|
|
98
106
|
- **Incremental pipeline** — pure-Python `update-maps`: dirty parse → import cache → reverse deps → cycles → `library.md`
|
|
107
|
+
- **Selective agent work** — health + suggest bias to 🔴/🟡 only; ACS *actionable* low-conf excludes stdlib/external noise
|
|
99
108
|
- **Scale** — reverse index + barrel invalidation so one edit doesn’t re-scan the monorepo
|
|
100
|
-
- **MCP tools** — optional server for Claude, Cursor, Cline, and other MCP clients
|
|
109
|
+
- **MCP tools** — optional server for Claude, Cursor, Cline, and other MCP clients
|
|
101
110
|
- **Zero core dependencies** — stdlib only; forks can add their own stack on top
|
|
111
|
+
- **Agent navigability** — short **AGENT MAP** docstrings on core modules; self-tests under `tests/` (not buried in parsers)
|
|
102
112
|
|
|
103
113
|
## Performance (measured)
|
|
104
114
|
|
|
@@ -118,13 +128,16 @@ Tests: `python -m unittest discover tests` (stdlib only).
|
|
|
118
128
|
| `wikifier check-changes` | Incremental scan → health / pending |
|
|
119
129
|
| `wikifier record-change <file> "reason"` | Log *why* (required after edits) |
|
|
120
130
|
| `wikifier mark-green <file>` | Mark wiki current |
|
|
131
|
+
| `wikifier record-deletion <file> "reason"` | Mark removed paths 🔴 + prune barrel refs |
|
|
132
|
+
| `wikifier suggest-next` | Next actions (🔴/🟡 only) |
|
|
121
133
|
| `wikifier update-maps [--directory=src/] [--max-files=N]` | Rebuild graph + `library.md` |
|
|
122
134
|
| `wikifier health [--summary\|--json]` | Health matrix (machine-friendly flags) |
|
|
135
|
+
| `wikifier validate` | Missing wiki rows + ghost paths |
|
|
123
136
|
| `wikifier cycles` | Circular deps + break hints |
|
|
124
|
-
| `wikifier monitor` / `daemon` | Background maintenance |
|
|
137
|
+
| `wikifier monitor` / `daemon` | Background maintenance (`WIKIFIER_DAEMON_MAPS=0` for check-only) |
|
|
125
138
|
| `wikifier serve` | Localhost dashboard with Run/Stop |
|
|
126
139
|
|
|
127
|
-
Library: `from wikifier import check_changes, record_change, mark_green,
|
|
140
|
+
Library: `from wikifier import check_changes, record_change, mark_green, suggest_next_actions, update_maps, health`.
|
|
128
141
|
|
|
129
142
|
## MCP
|
|
130
143
|
|
|
@@ -146,6 +159,8 @@ Setup and tool list: [`wikifier/mcp/README.md`](wikifier/mcp/README.md).
|
|
|
146
159
|
**In:** agent-maintained codebase wiki, dependency intelligence, token-saving lookup for LLMs and coding agents.
|
|
147
160
|
**Out:** general human documentation systems, IDE plugins, “docs for everyone” product growth.
|
|
148
161
|
|
|
162
|
+
**Agent navigability:** Prefer protocol ([`skills/run.md`](skills/run.md)) + MCP Core 6 over reading 20k LOC of parsers/cache. Production modules carry a short **AGENT MAP** docstring; self-tests live under `tests/` and `tests/selftest/`, not inline at the bottom of parsers.
|
|
163
|
+
|
|
149
164
|
## Links
|
|
150
165
|
|
|
151
166
|
- [PyPI](https://pypi.org/project/wikifier/) · [GitHub](https://github.com/IronAdamant/wikifier)
|
|
@@ -8,65 +8,75 @@
|
|
|
8
8
|
|
|
9
9
|
Wikifier is an **agent-to-agent** tool: it builds a living map of a project (health matrix, dependency graph, short file summaries) and agents keep that map current as they work. Humans can peek via a small dashboard; the product is the agent loop, not a general docs site or IDE.
|
|
10
10
|
|
|
11
|
-
Works from small scripts to large monorepos
|
|
11
|
+
Works from small scripts to large monorepos. **Deep import/include maps** (zero-dep regex parsers):
|
|
12
|
+
|
|
13
|
+
| Language | Extensions | Notes |
|
|
14
|
+
|----------|------------|--------|
|
|
15
|
+
| Python | `.py` | full ACS/CDIA path |
|
|
16
|
+
| JavaScript / TypeScript | `.js` `.ts` `.jsx` `.tsx` | barrels (BREE), dynamic/CDIA |
|
|
17
|
+
| Rust | `.rs` | `use` / `mod` / `extern crate` |
|
|
18
|
+
| Go | `.go` | `import` / import blocks |
|
|
19
|
+
| C / C++ | `.c` `.h` `.cpp` `.cc` `.cxx` `.hpp` `.hh` | `#include` (local + system) |
|
|
20
|
+
| C# | `.cs` | `using` namespaces |
|
|
21
|
+
| Java | `.java` | `import` / `import static` |
|
|
22
|
+
|
|
23
|
+
Health/journal still work for any monitored path. Parsers are **pragmatic regex** (not full cargo/`go.mod`/classpath/`-I` resolution). Prefer **lean `monitored_paths.txt`** on huge monorepos; raise dirty cap with `WIKIFIER_CHECK_CHANGES_MAX` (default 2000) only when needed.
|
|
12
24
|
|
|
13
25
|
## Why
|
|
14
26
|
|
|
15
27
|
Context windows are finite. Re-reading a large file to answer “what is this and who depends on it?” wastes tokens.
|
|
16
28
|
|
|
17
|
-
Wikifier keeps a small set of artifacts agents can query:
|
|
18
|
-
|
|
19
29
|
| Artifact | Role |
|
|
20
30
|
|----------|------|
|
|
21
31
|
| `file_health.md` | 🟢 / 🟡 / 🔴 matrix — what to trust, what to fix first |
|
|
22
32
|
| `library.md` | File tree, Mermaid dependency map, import tables, cycles + confidence |
|
|
23
|
-
| `*.wiki.md` | Short per-file “what this is for” notes (agent-maintained) |
|
|
24
|
-
| `journal/` | Semantic *why* trail
|
|
33
|
+
| `*.wiki.md` | Short per-file “what this is for” notes (**agent-maintained** prose) |
|
|
34
|
+
| `journal/` + `pending_updates.md` | Semantic *why* trail + work queue (audit, **not** a full issue tracker) |
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
**Map first, wiki depth second:** `update-maps` builds the structural map automatically. Rich per-file wiki text is filled by agents as they work — not a free full-repo “understand everything” pass on init.
|
|
27
37
|
|
|
28
|
-
##
|
|
38
|
+
## First run (bootstrap the map)
|
|
29
39
|
|
|
30
40
|
```bash
|
|
31
41
|
pip install wikifier # pure Python stdlib core — no runtime deps
|
|
32
42
|
pip install wikifier[mcp] # optional Model Context Protocol (MCP) server
|
|
33
43
|
|
|
34
44
|
cd /path/to/your/project
|
|
35
|
-
wikifier init
|
|
36
|
-
wikifier update-maps #
|
|
37
|
-
wikifier
|
|
38
|
-
wikifier
|
|
45
|
+
wikifier init # seeds + human index.html
|
|
46
|
+
wikifier update-maps # full structural map → library.md + import cache
|
|
47
|
+
wikifier health --summary # matrix counts
|
|
48
|
+
wikifier suggest-next # or MCP suggest_next_actions — 🔴/🟡 only
|
|
39
49
|
```
|
|
40
50
|
|
|
41
|
-
Always set an explicit root for external trees:
|
|
51
|
+
Always set an explicit root for external trees: `WIKIFIER_PROJECT_ROOT=/abs/path wikifier …`
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
WIKIFIER_PROJECT_ROOT=/abs/path/to/project wikifier check-changes
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Agent loop
|
|
53
|
+
## Steady state (only touch what needs it)
|
|
48
54
|
|
|
49
55
|
Full protocol: [`skills/run.md`](skills/run.md).
|
|
50
56
|
|
|
51
57
|
```bash
|
|
52
|
-
wikifier check-changes
|
|
53
|
-
# prioritize 🔴 then 🟡
|
|
54
|
-
# ... edit
|
|
58
|
+
wikifier check-changes # yellow dirty files; red ghosts (missing paths)
|
|
59
|
+
# prioritize 🔴 then 🟡 — do NOT re-wiki 🟢 Green files
|
|
60
|
+
# ... edit only those sources ...
|
|
55
61
|
wikifier record-change "path/file.py" "why this changed" # required
|
|
56
|
-
# ... refresh that file’s wiki summary ...
|
|
62
|
+
# ... refresh that file’s wiki summary only ...
|
|
57
63
|
wikifier mark-green "path/file.py"
|
|
58
|
-
wikifier update-maps # if imports/structure changed
|
|
64
|
+
wikifier update-maps # only if imports/structure changed
|
|
65
|
+
# removals:
|
|
66
|
+
wikifier record-deletion "path/gone.py" "why removed"
|
|
59
67
|
```
|
|
60
68
|
|
|
61
|
-
`
|
|
69
|
+
MCP **Core 6** (start every session): `get_project_status`, `check_changes`, `get_files_needing_attention`, `get_file_wiki`, `suggest_next_actions`, `record_change` / `mark_green`. Intel as needed: `get_dependencies`, `get_dependents`, `get_cycles`. Always pass `project_root=` for external trees.
|
|
62
70
|
|
|
63
71
|
## What you get
|
|
64
72
|
|
|
65
|
-
- **Import analysis** — Python
|
|
73
|
+
- **Import analysis** — Python, JS/TS (ESM/CJS, barrels), Rust, Go, C/C++ includes, C# usings; per-edge confidence; name-routed barrel expansion for TS/JS
|
|
66
74
|
- **Incremental pipeline** — pure-Python `update-maps`: dirty parse → import cache → reverse deps → cycles → `library.md`
|
|
75
|
+
- **Selective agent work** — health + suggest bias to 🔴/🟡 only; ACS *actionable* low-conf excludes stdlib/external noise
|
|
67
76
|
- **Scale** — reverse index + barrel invalidation so one edit doesn’t re-scan the monorepo
|
|
68
|
-
- **MCP tools** — optional server for Claude, Cursor, Cline, and other MCP clients
|
|
77
|
+
- **MCP tools** — optional server for Claude, Cursor, Cline, and other MCP clients
|
|
69
78
|
- **Zero core dependencies** — stdlib only; forks can add their own stack on top
|
|
79
|
+
- **Agent navigability** — short **AGENT MAP** docstrings on core modules; self-tests under `tests/` (not buried in parsers)
|
|
70
80
|
|
|
71
81
|
## Performance (measured)
|
|
72
82
|
|
|
@@ -86,13 +96,16 @@ Tests: `python -m unittest discover tests` (stdlib only).
|
|
|
86
96
|
| `wikifier check-changes` | Incremental scan → health / pending |
|
|
87
97
|
| `wikifier record-change <file> "reason"` | Log *why* (required after edits) |
|
|
88
98
|
| `wikifier mark-green <file>` | Mark wiki current |
|
|
99
|
+
| `wikifier record-deletion <file> "reason"` | Mark removed paths 🔴 + prune barrel refs |
|
|
100
|
+
| `wikifier suggest-next` | Next actions (🔴/🟡 only) |
|
|
89
101
|
| `wikifier update-maps [--directory=src/] [--max-files=N]` | Rebuild graph + `library.md` |
|
|
90
102
|
| `wikifier health [--summary\|--json]` | Health matrix (machine-friendly flags) |
|
|
103
|
+
| `wikifier validate` | Missing wiki rows + ghost paths |
|
|
91
104
|
| `wikifier cycles` | Circular deps + break hints |
|
|
92
|
-
| `wikifier monitor` / `daemon` | Background maintenance |
|
|
105
|
+
| `wikifier monitor` / `daemon` | Background maintenance (`WIKIFIER_DAEMON_MAPS=0` for check-only) |
|
|
93
106
|
| `wikifier serve` | Localhost dashboard with Run/Stop |
|
|
94
107
|
|
|
95
|
-
Library: `from wikifier import check_changes, record_change, mark_green,
|
|
108
|
+
Library: `from wikifier import check_changes, record_change, mark_green, suggest_next_actions, update_maps, health`.
|
|
96
109
|
|
|
97
110
|
## MCP
|
|
98
111
|
|
|
@@ -114,6 +127,8 @@ Setup and tool list: [`wikifier/mcp/README.md`](wikifier/mcp/README.md).
|
|
|
114
127
|
**In:** agent-maintained codebase wiki, dependency intelligence, token-saving lookup for LLMs and coding agents.
|
|
115
128
|
**Out:** general human documentation systems, IDE plugins, “docs for everyone” product growth.
|
|
116
129
|
|
|
130
|
+
**Agent navigability:** Prefer protocol ([`skills/run.md`](skills/run.md)) + MCP Core 6 over reading 20k LOC of parsers/cache. Production modules carry a short **AGENT MAP** docstring; self-tests live under `tests/` and `tests/selftest/`, not inline at the bottom of parsers.
|
|
131
|
+
|
|
117
132
|
## Links
|
|
118
133
|
|
|
119
134
|
- [PyPI](https://pypi.org/project/wikifier/) · [GitHub](https://github.com/IronAdamant/wikifier)
|
|
@@ -3,11 +3,19 @@
|
|
|
3
3
|
**Formerly "Wikifier Skills & Commands". This is the authoritative, versioned specification for agent behavior when using Wikifier.**
|
|
4
4
|
|
|
5
5
|
**Version**: v0.6 (v4.2.0 real-pipeline + reliability update; package current **4.5.x**)
|
|
6
|
-
**Date**: 2026-06-10 (package notes refreshed 2026-07-09)
|
|
6
|
+
**Date**: 2026-06-10 (package notes refreshed 2026-07-09; gap-closure contract 2026-07-09)
|
|
7
7
|
**Status**: Active. Supersedes v0.5.
|
|
8
|
-
**See also**: `README.md`
|
|
9
|
-
|
|
10
|
-
**Package 4.5.x notes (additive; protocol still v0.6):**
|
|
8
|
+
**See also**: `README.md`, `Findings/gap-closure-report.md`, and the library in wikifier/.
|
|
9
|
+
|
|
10
|
+
**Package 4.5.x + gap-closure notes (additive; protocol still v0.6):**
|
|
11
|
+
- File Tree + `wikifier serve`; MCP status/attention use library + emoji (not `[GREEN]` tags).
|
|
12
|
+
- **First-run:** `init` → `update-maps` → `health --summary` → `suggest_next_actions`. Map is automatic; wiki *prose* is agent-filled over time.
|
|
13
|
+
- **Steady-state selective work:** only 🔴/🟡 (never re-wiki 🟢 unless required). ACS suggestions use `actionable_low_conf_edges` (stdlib/external bare demoted).
|
|
14
|
+
- **Deletions:** `record-deletion` + check-changes ghost detection (missing paths → Red DELETED).
|
|
15
|
+
- **Languages:** deep import maps = Python, JS/TS, Rust, Go, C/C++, C#, Java (regex; not full toolchain resolution). journal/pending = audit queue, not Jira.
|
|
16
|
+
- **Huge monorepos:** lean `monitored_paths.txt` (package roots, not bare `.`). Optional `WIKIFIER_CHECK_CHANGES_MAX` (default 2000). `update-maps` seeds Yellow health stubs for newly parsed files (map-first).
|
|
17
|
+
- **Monitor:** optional background `monitor`/`daemon` for mtime heartbeat; agents still own wiki/mark-green.
|
|
18
|
+
- Health module: use `importlib.import_module("wikifier.health")` or `wikifier.health_module` — `from wikifier import health` is the *function*.
|
|
11
19
|
|
|
12
20
|
**v0.6 migration notes (packages v4.2.0–v4.3.0)** — changes are additive or strictly-better defaults; v0.5 agent behavior keeps working:
|
|
13
21
|
- `update-maps` (CLI) now runs the **pure-Python full pipeline**: every dirty file is parsed in-process, the canonical per-file cache is persisted, reverse deps + cycles + ACS are computed, and `library.md` is regenerated atomically. `--python-primary` is accepted but redundant; the in-shell first-pass was retired entirely (wikifier.sh's update-maps delegates to this pipeline; `--sh`/`--legacy-sh` are deprecated no-ops). Scoping is explicit via `--directory=`/`--max-files=` and reported in the result (`files_skipped`) — there are no silent caps.
|
|
@@ -24,33 +32,54 @@ This protocol + the Python package + MCP server form the bridge for consistent,
|
|
|
24
32
|
|
|
25
33
|
**This file is the primary contract for any LLM or agent operating Wikifier.**
|
|
26
34
|
|
|
35
|
+
## Agent architecture (navigability — G12)
|
|
36
|
+
|
|
37
|
+
Do **not** open megamodules (`javascript.py`, `import_cache.py`, `bree.py`) to decide workflow. Use this map:
|
|
38
|
+
|
|
39
|
+
| Need | Use |
|
|
40
|
+
|------|-----|
|
|
41
|
+
| First-run map | `init` → `update-maps` → `health --summary` → `suggest-next` |
|
|
42
|
+
| Steady-state | `check-changes` → edit 🔴/🟡 only → `record-change` → wiki → `mark-green` |
|
|
43
|
+
| Lookup | MCP Core 6: status, check_changes, needing_attention, get_file_wiki, suggest, record/mark |
|
|
44
|
+
| Deps / cycles | `get_dependencies`, `get_dependents`, `get_cycles` (json) |
|
|
45
|
+
| Deletion | `record-deletion` |
|
|
46
|
+
| Code entry | `wikifier/cli.py` (dispatch) + `wikifier/health.py` + parsers — self-tests live in `tests/` + `tests/selftest/` |
|
|
47
|
+
|
|
48
|
+
**CLI pure-Python vs shell:** mutators and maps prefer `python -m wikifier …`. Shell still owns `init`, `monitor`, `daemon`, `serve`, `journal`.
|
|
49
|
+
**Scope:** `monitored_paths` = change detection; `exclude_patterns` + optional `--directory` = map walk.
|
|
50
|
+
**Human HTML** is secondary observation only.
|
|
51
|
+
|
|
27
52
|
## Mandatory New-Session Rule
|
|
28
53
|
|
|
29
54
|
**Copy this exact block into the system prompt or the very first instruction of every new LLM session that uses Wikifier:**
|
|
30
55
|
|
|
31
56
|
```
|
|
32
|
-
You are now operating inside a Wikifier-managed codebase (Agent Protocol v0.6 —
|
|
57
|
+
You are now operating inside a Wikifier-managed codebase (Agent Protocol v0.6 — package 4.5.x).
|
|
58
|
+
|
|
59
|
+
This is strictly an agent-to-agent wiki for token saving: map lookup (health + file wikis + deps) instead of full sources; selective wiki updates; not a human docs product or Jira.
|
|
33
60
|
|
|
34
|
-
|
|
61
|
+
SELECTIVE WORK (mandatory): Only update/remove/re-wiki 🔴 Red and 🟡 Yellow files. Do not re-summarize 🟢 Green files or the whole tree. First-run builds the structural map; wiki depth is filled as you touch files.
|
|
35
62
|
|
|
36
|
-
FIRST ACTIONS
|
|
37
|
-
1.
|
|
38
|
-
2.
|
|
63
|
+
FIRST ACTIONS:
|
|
64
|
+
1. Prefer MCP tools when connected (get_project_status, get_file_wiki, check_changes, suggest_next_actions, get_dependencies, …). Always pass project_root= for external projects.
|
|
65
|
+
2. CLI/library fallback:
|
|
39
66
|
WIKIFIER_PROJECT_ROOT=/path/to/target python -m wikifier check-changes
|
|
40
|
-
python -m wikifier health --summary # or format=json/summary for machine use (token-efficient lookup)
|
|
41
|
-
... perform edit on source ...
|
|
42
|
-
python -m wikifier record-change "path/to/file" "concise semantic reason (why, not what). Include subid if agent work."
|
|
43
|
-
... write/update the wiki summary for the file ...
|
|
44
|
-
python -m wikifier mark-green "path/to/file" "Reason for Green (e.g. after autonomous agent update)."
|
|
45
|
-
if imports changed: python -m wikifier update-maps [--directory=src/] # pure-Python full pipeline by default (v4.2.0)
|
|
46
67
|
python -m wikifier health --summary
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
68
|
+
python -m wikifier suggest-next # or suggest_next_actions(format="json")
|
|
69
|
+
... edit only red/yellow sources ...
|
|
70
|
+
python -m wikifier record-change "path/to/file" "why (semantic). Include subid if agent work."
|
|
71
|
+
... update that file's wiki only ...
|
|
72
|
+
python -m wikifier mark-green "path/to/file" "reason"
|
|
73
|
+
if imports changed: python -m wikifier update-maps [--directory=src/]
|
|
74
|
+
if file removed: python -m wikifier record-deletion "path" "why"
|
|
75
|
+
python -m wikifier health --summary
|
|
76
|
+
3. Optional background: `python -m wikifier monitor` or daemon for mtime heartbeat — you still own wiki + mark-green.
|
|
77
|
+
4. Prioritize 🔴 then 🟡 from health/pending. Lookup greens via get_file_wiki; do not rewrite them.
|
|
78
|
+
5. Agent docs edits: record-change + mark-green.
|
|
79
|
+
6. Always explicit project_root / WIKIFIER_PROJECT_ROOT for external/multi-project work.
|
|
80
|
+
7. End turn: health + suggest_next_actions.
|
|
52
81
|
|
|
53
|
-
Never skip record-change —
|
|
82
|
+
Never skip record-change — semantic audit trail (journal + health + pending).
|
|
54
83
|
|
|
55
84
|
**M5+ notes (2026-06)**:
|
|
56
85
|
- External projects: always explicit root. CLI is battle-tested fallback (M5.1 MCP reliability: 60s timeout + better errors; M5 dogfood on alt BRC exact named services, 79k llvm, etc.).
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Gap-closure regressions (G4 ACS actionable, G5 health module, G7 ghosts/deletion)."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from tests._base import TempProjectTestCase
|
|
7
|
+
|
|
8
|
+
from wikifier import import_cache as ic
|
|
9
|
+
from wikifier import cli
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestHealthModuleImportG5(unittest.TestCase):
|
|
13
|
+
def test_importlib_health_is_module_with_get_summary(self):
|
|
14
|
+
mod = importlib.import_module("wikifier.health")
|
|
15
|
+
self.assertTrue(hasattr(mod, "get_summary"))
|
|
16
|
+
self.assertTrue(hasattr(mod, "find_ghost_entries"))
|
|
17
|
+
self.assertTrue(callable(mod.get_summary))
|
|
18
|
+
|
|
19
|
+
def test_health_module_alias_on_package(self):
|
|
20
|
+
import wikifier
|
|
21
|
+
self.assertTrue(hasattr(wikifier, "health_module"))
|
|
22
|
+
self.assertTrue(hasattr(wikifier.health_module, "get_summary"))
|
|
23
|
+
# Convenience function still exported as wikifier.health
|
|
24
|
+
self.assertTrue(callable(wikifier.health))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TestAcsActionableG4(TempProjectTestCase):
|
|
28
|
+
def test_external_noise_excluded_from_actionable_low_conf(self):
|
|
29
|
+
cache = {}
|
|
30
|
+
# Project-internal low-conf edge
|
|
31
|
+
ic.update_file_data(
|
|
32
|
+
cache,
|
|
33
|
+
"app.py",
|
|
34
|
+
mtime=1,
|
|
35
|
+
imports=["./util"],
|
|
36
|
+
resolved_pairs=[{
|
|
37
|
+
"raw": "./util",
|
|
38
|
+
"resolved": "util.py",
|
|
39
|
+
"resolved_path": "util.py",
|
|
40
|
+
"confidence_score": 0.4,
|
|
41
|
+
"confidence_reasons": ["base:low", "via_barrel"],
|
|
42
|
+
"confidence_explanation": "Base low. Recommendation: Review project edge.",
|
|
43
|
+
"diagnostic": {"category": "project"},
|
|
44
|
+
"resolution_metadata": {"strategy": "relative-fs"},
|
|
45
|
+
}],
|
|
46
|
+
)
|
|
47
|
+
# External/stdlib-style edge (noise)
|
|
48
|
+
ic.update_file_data(
|
|
49
|
+
cache,
|
|
50
|
+
"app.py",
|
|
51
|
+
mtime=1,
|
|
52
|
+
imports=["json", "./util"],
|
|
53
|
+
resolved_pairs=[
|
|
54
|
+
{
|
|
55
|
+
"raw": "./util",
|
|
56
|
+
"resolved": "util.py",
|
|
57
|
+
"resolved_path": "util.py",
|
|
58
|
+
"confidence_score": 0.4,
|
|
59
|
+
"confidence_reasons": ["base:low"],
|
|
60
|
+
"confidence_explanation": "Project low. Recommendation: Review.",
|
|
61
|
+
"resolution_metadata": {"strategy": "relative-fs"},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"raw": "json",
|
|
65
|
+
"resolved": "json",
|
|
66
|
+
"resolved_path": "",
|
|
67
|
+
"confidence_score": 0.48,
|
|
68
|
+
"confidence_reasons": ["base:medium", "no_resolved_path"],
|
|
69
|
+
"confidence_explanation": "stdlib. Recommendation: harden import.",
|
|
70
|
+
"diagnostic": {"category": "external_or_bare"},
|
|
71
|
+
"resolution_metadata": {"strategy": "python-bare-or-external"},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
)
|
|
75
|
+
# Note: update_file_data may replace pairs — set explicitly
|
|
76
|
+
cache["app.py"]["resolved_pairs"] = [
|
|
77
|
+
{
|
|
78
|
+
"raw": "./util",
|
|
79
|
+
"resolved": "util.py",
|
|
80
|
+
"resolved_path": "util.py",
|
|
81
|
+
"confidence_score": 0.4,
|
|
82
|
+
"confidence_reasons": ["base:low"],
|
|
83
|
+
"confidence_explanation": "Project low. Recommendation: Review.",
|
|
84
|
+
"resolution_metadata": {"strategy": "relative-fs"},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"raw": "json",
|
|
88
|
+
"resolved": "json",
|
|
89
|
+
"confidence_score": 0.48,
|
|
90
|
+
"confidence_reasons": ["base:medium"],
|
|
91
|
+
"confidence_explanation": "stdlib noise. Recommendation: ignore.",
|
|
92
|
+
"diagnostic": {"category": "external_or_bare"},
|
|
93
|
+
"resolution_metadata": {"strategy": "python-bare-or-external"},
|
|
94
|
+
},
|
|
95
|
+
]
|
|
96
|
+
summary = ic.compute_acs_summary(cache)
|
|
97
|
+
self.assertGreaterEqual(summary["low_conf_edges"], 1)
|
|
98
|
+
self.assertEqual(summary["actionable_low_conf_edges"], 1)
|
|
99
|
+
self.assertGreaterEqual(summary["external_noise_edges"], 1)
|
|
100
|
+
action = ic.get_low_confidence_edges(cache, actionable_only=True)
|
|
101
|
+
self.assertTrue(all(
|
|
102
|
+
(p.get("diagnostic") or {}).get("category") != "external_or_bare"
|
|
103
|
+
for p in action
|
|
104
|
+
))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TestGhostAndDeletionG7(TempProjectTestCase):
|
|
108
|
+
def test_find_ghost_and_record_deletion(self):
|
|
109
|
+
health_mod = importlib.import_module("wikifier.health")
|
|
110
|
+
self.write("keep.py", "x=1\n")
|
|
111
|
+
self.write("gone.py", "y=1\n")
|
|
112
|
+
health_mod.upsert_entry(self.root, "keep.py", "🟢 Green", "ok")
|
|
113
|
+
health_mod.upsert_entry(self.root, "gone.py", "🟢 Green", "ok")
|
|
114
|
+
(self.root / "gone.py").unlink()
|
|
115
|
+
|
|
116
|
+
ghosts = health_mod.find_ghost_entries(self.root)
|
|
117
|
+
self.assertIn("gone.py", ghosts)
|
|
118
|
+
self.assertNotIn("keep.py", ghosts)
|
|
119
|
+
|
|
120
|
+
res = cli.record_deletion("gone.py", "removed in cleanup", project_root=self.root)
|
|
121
|
+
self.assertTrue(res.get("success"))
|
|
122
|
+
entries = health_mod.load_health(self.root)["entries"]
|
|
123
|
+
self.assertIn("🔴", entries["gone.py"]["status"])
|
|
124
|
+
self.assertIn("DELETED", entries["gone.py"]["reason"])
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
if __name__ == "__main__":
|
|
128
|
+
unittest.main()
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Multi-language parser smoke tests (Rust, Go, C/C++, C#)."""
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from tests._base import TempProjectTestCase
|
|
7
|
+
|
|
8
|
+
from wikifier.parsers import rust, go_lang, c_cpp, csharp, java
|
|
9
|
+
from wikifier.cli import run_full_update, check_changes
|
|
10
|
+
import importlib
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestRustParser(TempProjectTestCase):
|
|
15
|
+
def test_use_and_mod(self):
|
|
16
|
+
self.write("lib.rs", "mod foo;\nuse crate::foo::Bar;\nuse std::io;\n")
|
|
17
|
+
self.write("foo.rs", "pub struct Bar;\n")
|
|
18
|
+
edges = rust.parse_rust_imports(str(self.root / "lib.rs"))
|
|
19
|
+
kinds = {e.get("statement_type") for e in edges}
|
|
20
|
+
self.assertIn("mod", kinds)
|
|
21
|
+
self.assertIn("use", kinds)
|
|
22
|
+
mod_e = next(e for e in edges if e.get("statement_type") == "mod")
|
|
23
|
+
self.assertTrue(mod_e.get("resolved_path") and mod_e["resolved_path"].endswith("foo.rs"))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TestGoParser(TempProjectTestCase):
|
|
27
|
+
def test_import_block(self):
|
|
28
|
+
self.write("main.go", 'package main\nimport (\n\t"fmt"\n\t"os"\n)\n')
|
|
29
|
+
edges = go_lang.parse_go_imports(str(self.root / "main.go"))
|
|
30
|
+
mods = {e["raw_module"] for e in edges}
|
|
31
|
+
self.assertIn("fmt", mods)
|
|
32
|
+
self.assertIn("os", mods)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestCParser(TempProjectTestCase):
|
|
36
|
+
def test_local_and_system_include(self):
|
|
37
|
+
self.write("a.c", '#include "b.h"\n#include <stdio.h>\n')
|
|
38
|
+
self.write("b.h", "int x;\n")
|
|
39
|
+
edges = c_cpp.parse_c_cpp_imports(str(self.root / "a.c"))
|
|
40
|
+
self.assertGreaterEqual(len(edges), 2)
|
|
41
|
+
local = next(e for e in edges if e["raw_module"] == "b.h")
|
|
42
|
+
self.assertTrue(local.get("resolved_path"))
|
|
43
|
+
sys_e = next(e for e in edges if e["raw_module"] == "stdio.h")
|
|
44
|
+
self.assertEqual((sys_e.get("diagnostic") or {}).get("category"), "external_or_bare")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TestCsharpParser(TempProjectTestCase):
|
|
48
|
+
def test_using(self):
|
|
49
|
+
self.write("A.cs", "using System;\nusing System.IO;\nusing MyApp.Core;\n")
|
|
50
|
+
edges = csharp.parse_csharp_imports(str(self.root / "A.cs"))
|
|
51
|
+
mods = {e["raw_module"] for e in edges}
|
|
52
|
+
self.assertIn("System", mods)
|
|
53
|
+
self.assertIn("MyApp.Core", mods)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TestJavaParser(TempProjectTestCase):
|
|
57
|
+
def test_import(self):
|
|
58
|
+
self.write("A.java", "import java.util.List;\nimport com.foo.Bar;\n")
|
|
59
|
+
edges = java.parse_java_imports(str(self.root / "A.java"))
|
|
60
|
+
mods = {e["raw_module"] for e in edges}
|
|
61
|
+
self.assertIn("java.util.List", mods)
|
|
62
|
+
self.assertIn("com.foo.Bar", mods)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestPipelineMultiLang(TempProjectTestCase):
|
|
66
|
+
def test_run_full_update_parses_all_langs(self):
|
|
67
|
+
self.write("a.py", "import os\n")
|
|
68
|
+
self.write("b.rs", "mod x;\n")
|
|
69
|
+
self.write("x.rs", "pub fn f() {}\n")
|
|
70
|
+
self.write("c.go", 'package p\nimport "fmt"\n')
|
|
71
|
+
self.write("d.c", '#include "e.h"\n')
|
|
72
|
+
self.write("e.h", "int y;\n")
|
|
73
|
+
self.write("f.cs", "using System;\n")
|
|
74
|
+
self.write("G.java", "import java.io.File;\n")
|
|
75
|
+
res = run_full_update(root=self.root, force_full=True, verbose=False)
|
|
76
|
+
self.assertTrue(res.get("success"))
|
|
77
|
+
self.assertGreaterEqual(res.get("files_parsed", 0), 5)
|
|
78
|
+
self.assertIn("languages_parsed", res)
|
|
79
|
+
self.assertGreaterEqual(res.get("health_stubs_seeded", 0), 1)
|
|
80
|
+
health_mod = importlib.import_module("wikifier.health")
|
|
81
|
+
entries = health_mod.load_health(self.root).get("entries") or {}
|
|
82
|
+
self.assertTrue(any(k.endswith((".py", ".rs", ".java", ".cs", ".go", ".c")) for k in entries))
|
|
83
|
+
|
|
84
|
+
def test_check_changes_cap_env(self):
|
|
85
|
+
self.write("monitored_paths.txt", ".\n")
|
|
86
|
+
for i in range(5):
|
|
87
|
+
self.write(f"f{i}.py", f"x={i}\n")
|
|
88
|
+
run_full_update(root=self.root, force_full=True, verbose=False)
|
|
89
|
+
import time
|
|
90
|
+
time.sleep(0.05)
|
|
91
|
+
for i in range(5):
|
|
92
|
+
(self.root / f"f{i}.py").write_text(f"x={i + 1}\n")
|
|
93
|
+
os.environ["WIKIFIER_CHECK_CHANGES_MAX"] = "2"
|
|
94
|
+
try:
|
|
95
|
+
r = check_changes(project_root=self.root)
|
|
96
|
+
self.assertTrue(r.get("success"))
|
|
97
|
+
self.assertLessEqual(r.get("changes_detected", 0), 2)
|
|
98
|
+
self.assertTrue(r.get("dirty_truncated") or (r.get("dirty_total") or 0) <= 2)
|
|
99
|
+
finally:
|
|
100
|
+
os.environ.pop("WIKIFIER_CHECK_CHANGES_MAX", None)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
unittest.main()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""G12: run extracted selftest harnesses via unittest (no harness in prod modules)."""
|
|
2
|
+
|
|
3
|
+
import runpy
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
SELFTEST = Path(__file__).resolve().parent / "selftest"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestExtractedSelftests(unittest.TestCase):
|
|
11
|
+
def _run(self, name: str):
|
|
12
|
+
path = SELFTEST / name
|
|
13
|
+
self.assertTrue(path.is_file(), f"missing {path}")
|
|
14
|
+
# Execute as __main__ so assert-based scripts raise on failure
|
|
15
|
+
try:
|
|
16
|
+
runpy.run_path(str(path), run_name="__main__")
|
|
17
|
+
except SystemExit as e:
|
|
18
|
+
if e.code not in (0, None):
|
|
19
|
+
self.fail(f"{name} exited with {e.code}")
|
|
20
|
+
|
|
21
|
+
def test_contracts_selftest(self):
|
|
22
|
+
self._run("run_contracts_selftest.py")
|
|
23
|
+
|
|
24
|
+
def test_python_parser_selftest(self):
|
|
25
|
+
self._run("run_python_parser_selftest.py")
|
|
26
|
+
|
|
27
|
+
def test_cdia_selftest(self):
|
|
28
|
+
self._run("run_cdia_selftest.py")
|
|
29
|
+
|
|
30
|
+
def test_resolution_selftest(self):
|
|
31
|
+
self._run("run_resolution_selftest.py")
|
|
32
|
+
|
|
33
|
+
def test_javascript_selftest(self):
|
|
34
|
+
# Heavier; still must pass for agent-navigable JS parser
|
|
35
|
+
self._run("run_javascript_selftest.py")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
unittest.main()
|