wikifier 4.5.0__tar.gz → 4.5.2__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/PKG-INFO +154 -0
- wikifier-4.5.2/README.md +122 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/skills/run.md +4 -2
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/__init__.py +1 -1
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/cli.py +42 -2
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/mcp/server.py +58 -30
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/parsers/javascript.py +15 -1
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/scripts/wikifier.sh +42 -9
- wikifier-4.5.2/wikifier.egg-info/PKG-INFO +154 -0
- wikifier-4.5.0/PKG-INFO +0 -165
- wikifier-4.5.0/README.md +0 -133
- wikifier-4.5.0/wikifier.egg-info/PKG-INFO +0 -165
- {wikifier-4.5.0 → wikifier-4.5.2}/CONTRIBUTING.md +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/LICENSE +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/MANIFEST.in +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/diagnostics.html +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/docs/spec.md +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/index.html +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/pyproject.toml +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/setup.cfg +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/tests/test_barrel_invalidation.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/tests/test_health.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/tests/test_import_cache.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/tests/test_parsers.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/__main__.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/contracts.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/daemon.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/diagnostics.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/health.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/import_cache.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/index.html +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/library.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/locking.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/mcp/__init__.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/parsers/__init__.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/parsers/bree.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/parsers/cdia.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/parsers/python.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/resolution.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/scripts/wikifier.bat +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/scripts/wikifier.ps1 +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier/serve.py +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier.egg-info/SOURCES.txt +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier.egg-info/dependency_links.txt +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier.egg-info/entry_points.txt +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier.egg-info/requires.txt +0 -0
- {wikifier-4.5.0 → wikifier-4.5.2}/wikifier.egg-info/top_level.txt +0 -0
wikifier-4.5.2/PKG-INFO
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wikifier
|
|
3
|
+
Version: 4.5.2
|
|
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
|
+
Author-email: Aron Amos <aron@example.com>
|
|
6
|
+
Maintainer: Aron Amos
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/IronAdamant/wikifier
|
|
9
|
+
Project-URL: Repository, https://github.com/IronAdamant/wikifier
|
|
10
|
+
Project-URL: Documentation, https://github.com/IronAdamant/wikifier#readme
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/IronAdamant/wikifier/issues
|
|
12
|
+
Keywords: wiki,documentation,llm,agent,mcp,codebase,health-matrix,zero-dependency,shell,token-efficient,autonomous,record-change,mark-green,agent-wiki,llm-tools,dependency-graph,monorepo
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
24
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
25
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Provides-Extra: mcp
|
|
30
|
+
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Wikifier
|
|
34
|
+
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
[](https://pypi.org/project/wikifier/)
|
|
37
|
+
[](https://github.com/IronAdamant/wikifier/stargazers)
|
|
38
|
+
|
|
39
|
+
**A zero-dependency codebase wiki for AI agents** — token-efficient maps so LLMs look things up instead of re-reading full sources.
|
|
40
|
+
|
|
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
|
+
|
|
43
|
+
Works from small scripts to large monorepos (Python + JavaScript/TypeScript imports, barrels, cycles, incremental updates).
|
|
44
|
+
|
|
45
|
+
## Why
|
|
46
|
+
|
|
47
|
+
Context windows are finite. Re-reading a large file to answer “what is this and who depends on it?” wastes tokens.
|
|
48
|
+
|
|
49
|
+
Wikifier keeps a small set of artifacts agents can query:
|
|
50
|
+
|
|
51
|
+
| Artifact | Role |
|
|
52
|
+
|----------|------|
|
|
53
|
+
| `file_health.md` | 🟢 / 🟡 / 🔴 matrix — what to trust, what to fix first |
|
|
54
|
+
| `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 from `record-change` |
|
|
57
|
+
|
|
58
|
+
Lookup beats re-ingest. That’s the whole idea.
|
|
59
|
+
|
|
60
|
+
## Quick start
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install wikifier # pure Python stdlib core — no runtime deps
|
|
64
|
+
pip install wikifier[mcp] # optional Model Context Protocol (MCP) server
|
|
65
|
+
|
|
66
|
+
cd /path/to/your/project
|
|
67
|
+
wikifier init
|
|
68
|
+
wikifier update-maps # dependency graph + library.md
|
|
69
|
+
wikifier check-changes
|
|
70
|
+
wikifier health --summary
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Always set an explicit root for external trees:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
WIKIFIER_PROJECT_ROOT=/abs/path/to/project wikifier check-changes
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Agent loop
|
|
80
|
+
|
|
81
|
+
Full protocol: [`skills/run.md`](skills/run.md).
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
wikifier check-changes
|
|
85
|
+
# prioritize 🔴 then 🟡 in file_health.md / pending_updates.md
|
|
86
|
+
# ... edit source ...
|
|
87
|
+
wikifier record-change "path/file.py" "why this changed" # required
|
|
88
|
+
# ... refresh that file’s wiki summary ...
|
|
89
|
+
wikifier mark-green "path/file.py"
|
|
90
|
+
wikifier update-maps # if imports/structure changed
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`record-change` logs intent a git diff can’t reconstruct for the next agent (or human).
|
|
94
|
+
|
|
95
|
+
## What you get
|
|
96
|
+
|
|
97
|
+
- **Import analysis** — Python + JS/TS (ESM, CommonJS, dynamic imports, path aliases, package exports); per-edge confidence; name-routed barrel expansion (precise leaves, not edge explosion)
|
|
98
|
+
- **Incremental pipeline** — pure-Python `update-maps`: dirty parse → import cache → reverse deps → cycles → `library.md`
|
|
99
|
+
- **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 (`get_project_status`, `get_dependencies`, `get_file_wiki`, `record_change`, …)
|
|
101
|
+
- **Zero core dependencies** — stdlib only; forks can add their own stack on top
|
|
102
|
+
|
|
103
|
+
## Performance (measured)
|
|
104
|
+
|
|
105
|
+
| Project | Scale | Full `update-maps` |
|
|
106
|
+
|---------|-------|--------------------|
|
|
107
|
+
| llama_index | ~3.8k Python files | ~8.5s |
|
|
108
|
+
| Babylon.js | ~3.9k TS files, barrel-heavy | ~4.5 min (scoped re-runs ~80s) |
|
|
109
|
+
| Large trees (e.g. LLVM-scale) | tens of thousands of files | candidate scan in seconds |
|
|
110
|
+
|
|
111
|
+
Tests: `python -m unittest discover tests` (stdlib only).
|
|
112
|
+
|
|
113
|
+
## Commands
|
|
114
|
+
|
|
115
|
+
| Command | Purpose |
|
|
116
|
+
|---------|---------|
|
|
117
|
+
| `wikifier init [--target DIR]` | Bootstrap project + human `index.html` |
|
|
118
|
+
| `wikifier check-changes` | Incremental scan → health / pending |
|
|
119
|
+
| `wikifier record-change <file> "reason"` | Log *why* (required after edits) |
|
|
120
|
+
| `wikifier mark-green <file>` | Mark wiki current |
|
|
121
|
+
| `wikifier update-maps [--directory=src/] [--max-files=N]` | Rebuild graph + `library.md` |
|
|
122
|
+
| `wikifier health [--summary\|--json]` | Health matrix (machine-friendly flags) |
|
|
123
|
+
| `wikifier cycles` | Circular deps + break hints |
|
|
124
|
+
| `wikifier monitor` / `daemon` | Background maintenance |
|
|
125
|
+
| `wikifier serve` | Localhost dashboard with Run/Stop |
|
|
126
|
+
|
|
127
|
+
Library: `from wikifier import check_changes, record_change, mark_green, health, update_maps`.
|
|
128
|
+
|
|
129
|
+
## MCP
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
WIKIFIER_PROJECT_ROOT=/abs/path/to/project wikifier-mcp
|
|
133
|
+
# or: python3 -m wikifier.mcp.server
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Setup and tool list: [`wikifier/mcp/README.md`](wikifier/mcp/README.md).
|
|
137
|
+
|
|
138
|
+
## Human dashboard (secondary)
|
|
139
|
+
|
|
140
|
+

|
|
141
|
+
|
|
142
|
+
`wikifier init` drops a single `index.html`. Prefer **`wikifier serve`** (e.g. http://localhost:8787/index.html) — `file://` can’t load project files. The markdown artifacts and CLI/MCP tools stay the source of truth; the UI is a read-only window.
|
|
143
|
+
|
|
144
|
+
## Scope
|
|
145
|
+
|
|
146
|
+
**In:** agent-maintained codebase wiki, dependency intelligence, token-saving lookup for LLMs and coding agents.
|
|
147
|
+
**Out:** general human documentation systems, IDE plugins, “docs for everyone” product growth.
|
|
148
|
+
|
|
149
|
+
## Links
|
|
150
|
+
|
|
151
|
+
- [PyPI](https://pypi.org/project/wikifier/) · [GitHub](https://github.com/IronAdamant/wikifier)
|
|
152
|
+
- Agent protocol: [`skills/run.md`](skills/run.md)
|
|
153
|
+
- Changelog: [`CHANGELOG.md`](CHANGELOG.md)
|
|
154
|
+
- Dogfood notes: `Findings/`
|
wikifier-4.5.2/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Wikifier
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://pypi.org/project/wikifier/)
|
|
5
|
+
[](https://github.com/IronAdamant/wikifier/stargazers)
|
|
6
|
+
|
|
7
|
+
**A zero-dependency codebase wiki for AI agents** — token-efficient maps so LLMs look things up instead of re-reading full sources.
|
|
8
|
+
|
|
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
|
+
|
|
11
|
+
Works from small scripts to large monorepos (Python + JavaScript/TypeScript imports, barrels, cycles, incremental updates).
|
|
12
|
+
|
|
13
|
+
## Why
|
|
14
|
+
|
|
15
|
+
Context windows are finite. Re-reading a large file to answer “what is this and who depends on it?” wastes tokens.
|
|
16
|
+
|
|
17
|
+
Wikifier keeps a small set of artifacts agents can query:
|
|
18
|
+
|
|
19
|
+
| Artifact | Role |
|
|
20
|
+
|----------|------|
|
|
21
|
+
| `file_health.md` | 🟢 / 🟡 / 🔴 matrix — what to trust, what to fix first |
|
|
22
|
+
| `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 from `record-change` |
|
|
25
|
+
|
|
26
|
+
Lookup beats re-ingest. That’s the whole idea.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install wikifier # pure Python stdlib core — no runtime deps
|
|
32
|
+
pip install wikifier[mcp] # optional Model Context Protocol (MCP) server
|
|
33
|
+
|
|
34
|
+
cd /path/to/your/project
|
|
35
|
+
wikifier init
|
|
36
|
+
wikifier update-maps # dependency graph + library.md
|
|
37
|
+
wikifier check-changes
|
|
38
|
+
wikifier health --summary
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Always set an explicit root for external trees:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
WIKIFIER_PROJECT_ROOT=/abs/path/to/project wikifier check-changes
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Agent loop
|
|
48
|
+
|
|
49
|
+
Full protocol: [`skills/run.md`](skills/run.md).
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
wikifier check-changes
|
|
53
|
+
# prioritize 🔴 then 🟡 in file_health.md / pending_updates.md
|
|
54
|
+
# ... edit source ...
|
|
55
|
+
wikifier record-change "path/file.py" "why this changed" # required
|
|
56
|
+
# ... refresh that file’s wiki summary ...
|
|
57
|
+
wikifier mark-green "path/file.py"
|
|
58
|
+
wikifier update-maps # if imports/structure changed
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`record-change` logs intent a git diff can’t reconstruct for the next agent (or human).
|
|
62
|
+
|
|
63
|
+
## What you get
|
|
64
|
+
|
|
65
|
+
- **Import analysis** — Python + JS/TS (ESM, CommonJS, dynamic imports, path aliases, package exports); per-edge confidence; name-routed barrel expansion (precise leaves, not edge explosion)
|
|
66
|
+
- **Incremental pipeline** — pure-Python `update-maps`: dirty parse → import cache → reverse deps → cycles → `library.md`
|
|
67
|
+
- **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 (`get_project_status`, `get_dependencies`, `get_file_wiki`, `record_change`, …)
|
|
69
|
+
- **Zero core dependencies** — stdlib only; forks can add their own stack on top
|
|
70
|
+
|
|
71
|
+
## Performance (measured)
|
|
72
|
+
|
|
73
|
+
| Project | Scale | Full `update-maps` |
|
|
74
|
+
|---------|-------|--------------------|
|
|
75
|
+
| llama_index | ~3.8k Python files | ~8.5s |
|
|
76
|
+
| Babylon.js | ~3.9k TS files, barrel-heavy | ~4.5 min (scoped re-runs ~80s) |
|
|
77
|
+
| Large trees (e.g. LLVM-scale) | tens of thousands of files | candidate scan in seconds |
|
|
78
|
+
|
|
79
|
+
Tests: `python -m unittest discover tests` (stdlib only).
|
|
80
|
+
|
|
81
|
+
## Commands
|
|
82
|
+
|
|
83
|
+
| Command | Purpose |
|
|
84
|
+
|---------|---------|
|
|
85
|
+
| `wikifier init [--target DIR]` | Bootstrap project + human `index.html` |
|
|
86
|
+
| `wikifier check-changes` | Incremental scan → health / pending |
|
|
87
|
+
| `wikifier record-change <file> "reason"` | Log *why* (required after edits) |
|
|
88
|
+
| `wikifier mark-green <file>` | Mark wiki current |
|
|
89
|
+
| `wikifier update-maps [--directory=src/] [--max-files=N]` | Rebuild graph + `library.md` |
|
|
90
|
+
| `wikifier health [--summary\|--json]` | Health matrix (machine-friendly flags) |
|
|
91
|
+
| `wikifier cycles` | Circular deps + break hints |
|
|
92
|
+
| `wikifier monitor` / `daemon` | Background maintenance |
|
|
93
|
+
| `wikifier serve` | Localhost dashboard with Run/Stop |
|
|
94
|
+
|
|
95
|
+
Library: `from wikifier import check_changes, record_change, mark_green, health, update_maps`.
|
|
96
|
+
|
|
97
|
+
## MCP
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
WIKIFIER_PROJECT_ROOT=/abs/path/to/project wikifier-mcp
|
|
101
|
+
# or: python3 -m wikifier.mcp.server
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Setup and tool list: [`wikifier/mcp/README.md`](wikifier/mcp/README.md).
|
|
105
|
+
|
|
106
|
+
## Human dashboard (secondary)
|
|
107
|
+
|
|
108
|
+

|
|
109
|
+
|
|
110
|
+
`wikifier init` drops a single `index.html`. Prefer **`wikifier serve`** (e.g. http://localhost:8787/index.html) — `file://` can’t load project files. The markdown artifacts and CLI/MCP tools stay the source of truth; the UI is a read-only window.
|
|
111
|
+
|
|
112
|
+
## Scope
|
|
113
|
+
|
|
114
|
+
**In:** agent-maintained codebase wiki, dependency intelligence, token-saving lookup for LLMs and coding agents.
|
|
115
|
+
**Out:** general human documentation systems, IDE plugins, “docs for everyone” product growth.
|
|
116
|
+
|
|
117
|
+
## Links
|
|
118
|
+
|
|
119
|
+
- [PyPI](https://pypi.org/project/wikifier/) · [GitHub](https://github.com/IronAdamant/wikifier)
|
|
120
|
+
- Agent protocol: [`skills/run.md`](skills/run.md)
|
|
121
|
+
- Changelog: [`CHANGELOG.md`](CHANGELOG.md)
|
|
122
|
+
- Dogfood notes: `Findings/`
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
**Formerly "Wikifier Skills & Commands". This is the authoritative, versioned specification for agent behavior when using Wikifier.**
|
|
4
4
|
|
|
5
|
-
**Version**: v0.6 (v4.2.0 real-pipeline + reliability update)
|
|
6
|
-
**Date**: 2026-06-10
|
|
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)
|
|
7
7
|
**Status**: Active. Supersedes v0.5.
|
|
8
8
|
**See also**: `README.md` (Intended Use section: strictly agent-to-agent wiki for token saving), M5-Dogfood-Assessment-Report.md, Findings/2026-06-10-Dogfood-Refactor-Validation.md, and the library in wikifier/.
|
|
9
9
|
|
|
10
|
+
**Package 4.5.x notes (additive; protocol still v0.6):** File Tree as primary structure view in `library.md` + dashboard pan/zoom graph; `wikifier serve` with real Run/Stop controls; Python parser no longer leaks `#`-comment text into edges; MCP `get_project_status` / `get_files_needing_attention` use library+emoji health statuses (not legacy `[GREEN]` tags). Full history: `CHANGELOG.md`.
|
|
11
|
+
|
|
10
12
|
**v0.6 migration notes (packages v4.2.0–v4.3.0)** — changes are additive or strictly-better defaults; v0.5 agent behavior keeps working:
|
|
11
13
|
- `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.
|
|
12
14
|
- `run_full_update`/`update_maps` returns gained additive fields: `files_parsed` (actual), `parseable_files`, `edges_persisted`, `files_skipped`, `cycles`, `library`. Tolerate additive fields as always.
|
|
@@ -683,8 +683,17 @@ def main():
|
|
|
683
683
|
filtered_argv.append(arg)
|
|
684
684
|
i += 1
|
|
685
685
|
|
|
686
|
-
# Micro-step 2 (A2 CLI wiring): detect streaming UX flags after parsing
|
|
687
|
-
|
|
686
|
+
# Micro-step 2 (A2 CLI wiring): detect streaming UX flags after parsing.
|
|
687
|
+
# --max-files / --directory are normal run_full_update scoping options and
|
|
688
|
+
# must NOT force the stream facade (agents expect batch JSON + files_skipped).
|
|
689
|
+
a2_flag_markers = (
|
|
690
|
+
"--stream", "--stream=",
|
|
691
|
+
"--resume", "--resume_token",
|
|
692
|
+
"--max-time", "--max_time",
|
|
693
|
+
"--progress",
|
|
694
|
+
"--partial",
|
|
695
|
+
"--format=stream",
|
|
696
|
+
)
|
|
688
697
|
has_a2_ux_flags = any(any(a == m or a.startswith(m) for m in a2_flag_markers) for a in filtered_argv)
|
|
689
698
|
|
|
690
699
|
if project_root:
|
|
@@ -710,6 +719,37 @@ def main():
|
|
|
710
719
|
print(f"[wikifier] health --{fmt} failed: {e}", file=sys.stderr)
|
|
711
720
|
return 1
|
|
712
721
|
|
|
722
|
+
# Mandatory workflow commands: pure-Python primary (updates file_health.json + md).
|
|
723
|
+
# Shell upsert_health only patches the .md and on macOS `realpath --relative-to`
|
|
724
|
+
# is unavailable, so it used to store absolute paths as health keys.
|
|
725
|
+
if filtered_argv:
|
|
726
|
+
_cmd0 = filtered_argv[0].replace("_", "-")
|
|
727
|
+
_args = filtered_argv[1:]
|
|
728
|
+
try:
|
|
729
|
+
if _cmd0 == "check-changes":
|
|
730
|
+
res = check_changes(project_root=project_root)
|
|
731
|
+
n = int(res.get("changes_detected") or 0)
|
|
732
|
+
print("[wikifier] Running incremental change detection...")
|
|
733
|
+
if n:
|
|
734
|
+
print(f"[wikifier] Detected {n} changed file(s). See pending_updates.md and file_health.md.")
|
|
735
|
+
else:
|
|
736
|
+
print("[wikifier] No new changes detected.")
|
|
737
|
+
if res.get("message"):
|
|
738
|
+
print(res["message"])
|
|
739
|
+
return 0 if res.get("success", True) else 1
|
|
740
|
+
if _cmd0 == "record-change" and len(_args) >= 2:
|
|
741
|
+
res = record_change(_args[0], " ".join(_args[1:]), project_root=project_root)
|
|
742
|
+
print(res.get("message") or res)
|
|
743
|
+
return 0 if res.get("success") else 1
|
|
744
|
+
if _cmd0 == "mark-green" and len(_args) >= 1:
|
|
745
|
+
reason = " ".join(_args[1:]) if len(_args) > 1 else ""
|
|
746
|
+
res = mark_green(_args[0], reason, project_root=project_root)
|
|
747
|
+
print(res.get("message") or res)
|
|
748
|
+
return 0 if res.get("success") else 1
|
|
749
|
+
except Exception as e:
|
|
750
|
+
print(f"[wikifier] Python-primary {_cmd0} failed: {e}", file=sys.stderr)
|
|
751
|
+
return 1
|
|
752
|
+
|
|
713
753
|
# Human sub-project: ensure dashboards are in the target (for MCP + human investigation)
|
|
714
754
|
# index.html = clean human view (chart + files + descriptions + copies); diagnostics.html for technical depth. Works alongside agent MCP/CLI use. No effect on agent SSOT or tools.
|
|
715
755
|
if project_root:
|
|
@@ -643,7 +643,8 @@ def health(
|
|
|
643
643
|
root = _get_effective_root(project_root)
|
|
644
644
|
|
|
645
645
|
try:
|
|
646
|
-
import
|
|
646
|
+
import importlib
|
|
647
|
+
health_module = importlib.import_module("wikifier.health")
|
|
647
648
|
|
|
648
649
|
if format == "summary":
|
|
649
650
|
summary = health_module.get_summary(root, directory)
|
|
@@ -744,7 +745,8 @@ def list_healable_stubs(
|
|
|
744
745
|
"""
|
|
745
746
|
root = _get_effective_root(project_root)
|
|
746
747
|
try:
|
|
747
|
-
import
|
|
748
|
+
import importlib
|
|
749
|
+
health_module = importlib.import_module("wikifier.health")
|
|
748
750
|
candidates = health_module.get_healable_stubs(
|
|
749
751
|
root, min_wiki_length=min_wiki_length, directory=directory
|
|
750
752
|
)
|
|
@@ -793,7 +795,8 @@ def heal_stubs(
|
|
|
793
795
|
"""
|
|
794
796
|
root = _get_effective_root(project_root)
|
|
795
797
|
try:
|
|
796
|
-
import
|
|
798
|
+
import importlib
|
|
799
|
+
health_module = importlib.import_module("wikifier.health")
|
|
797
800
|
count = health_module.heal_outdated_stubs(
|
|
798
801
|
root, min_wiki_length=min_wiki_length, dry_run=dry_run
|
|
799
802
|
)
|
|
@@ -1571,13 +1574,15 @@ def get_files_needing_attention(
|
|
|
1571
1574
|
root = _get_effective_root(project_root)
|
|
1572
1575
|
|
|
1573
1576
|
try:
|
|
1574
|
-
import
|
|
1577
|
+
import importlib
|
|
1578
|
+
health_module = importlib.import_module("wikifier.health")
|
|
1575
1579
|
|
|
1580
|
+
# Health matrix stores emoji statuses (🟢/🟡/🔴), not [RED]/[YELLOW] tags.
|
|
1576
1581
|
status_filter = None
|
|
1577
1582
|
if status == "red":
|
|
1578
|
-
status_filter = "
|
|
1583
|
+
status_filter = "🔴"
|
|
1579
1584
|
elif status == "yellow":
|
|
1580
|
-
status_filter = "
|
|
1585
|
+
status_filter = "🟡"
|
|
1581
1586
|
|
|
1582
1587
|
files = health_module.get_files_needing_attention(root, status_filter, directory)
|
|
1583
1588
|
|
|
@@ -1604,25 +1609,30 @@ def get_files_needing_attention(
|
|
|
1604
1609
|
if not files:
|
|
1605
1610
|
return "No files currently need attention."
|
|
1606
1611
|
|
|
1607
|
-
red = [f for f in files if "[RED]" in f] # This won't work well since we only have paths
|
|
1608
|
-
# Better: we don't have status here easily. Let's just list them.
|
|
1609
1612
|
return "Files needing attention:\n" + "\n".join(f"- {f}" for f in files)
|
|
1610
1613
|
|
|
1611
1614
|
except Exception:
|
|
1612
|
-
#
|
|
1615
|
+
# Library fallback — avoid shell text parsing ([RED] tags vs emoji).
|
|
1613
1616
|
root = _get_effective_root(project_root)
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
if "
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1617
|
+
try:
|
|
1618
|
+
import importlib
|
|
1619
|
+
health_module = importlib.import_module("wikifier.health")
|
|
1620
|
+
status_filter = "🔴" if status == "red" else ("🟡" if status == "yellow" else None)
|
|
1621
|
+
files = health_module.get_files_needing_attention(root, status_filter, directory)
|
|
1622
|
+
if format == "json":
|
|
1623
|
+
return {
|
|
1624
|
+
"project_root": str(root),
|
|
1625
|
+
"directory": directory or ".",
|
|
1626
|
+
"status_filter": status,
|
|
1627
|
+
"files": files,
|
|
1628
|
+
"count": len(files),
|
|
1629
|
+
"acs_low_conf_context": None,
|
|
1630
|
+
}
|
|
1631
|
+
if not files:
|
|
1632
|
+
return "No files currently need attention."
|
|
1633
|
+
return "Files needing attention:\n" + "\n".join(f"- {f}" for f in files)
|
|
1634
|
+
except Exception:
|
|
1635
|
+
return "No files currently need attention."
|
|
1626
1636
|
|
|
1627
1637
|
|
|
1628
1638
|
@mcp.tool()
|
|
@@ -1638,7 +1648,8 @@ def get_project_status(
|
|
|
1638
1648
|
root = _get_effective_root(project_root)
|
|
1639
1649
|
|
|
1640
1650
|
try:
|
|
1641
|
-
import
|
|
1651
|
+
import importlib
|
|
1652
|
+
health_module = importlib.import_module("wikifier.health")
|
|
1642
1653
|
summary = health_module.get_summary(root, directory)
|
|
1643
1654
|
pending = _read_file_safe("pending_updates.md", root=root)
|
|
1644
1655
|
|
|
@@ -1763,19 +1774,35 @@ Pending updates: {pending_count}
|
|
|
1763
1774
|
Use get_files_needing_attention() for the actual list. Use get_cycles(analysis=True) + get_dependencies(format="json") for ACS confidence_explanation Recommendations."""
|
|
1764
1775
|
|
|
1765
1776
|
except Exception:
|
|
1766
|
-
#
|
|
1777
|
+
# Prefer library summary over shell text parsing. Live health text uses
|
|
1778
|
+
# emoji (🟢/🟡/🔴); counting legacy [GREEN]/[YELLOW]/[RED] tags always
|
|
1779
|
+
# yielded zeros and lied to agents.
|
|
1767
1780
|
root = _get_effective_root(project_root)
|
|
1768
|
-
health = _run_wikifier_command("health", root=root)
|
|
1769
1781
|
pending = _read_file_safe("pending_updates.md", root=root)
|
|
1770
|
-
|
|
1771
|
-
red = health.count("[RED]")
|
|
1772
|
-
yellow = health.count("[YELLOW]")
|
|
1773
|
-
green = health.count("[GREEN]")
|
|
1774
1782
|
pending_count = len([l for l in pending.splitlines() if l.strip() and not l.startswith("#")])
|
|
1783
|
+
green = yellow = red = total = 0
|
|
1784
|
+
try:
|
|
1785
|
+
import importlib
|
|
1786
|
+
health_module = importlib.import_module("wikifier.health")
|
|
1787
|
+
summary = health_module.get_summary(root, directory)
|
|
1788
|
+
total = int(summary.get("total", 0) or 0)
|
|
1789
|
+
green = int(summary.get("green", 0) or 0)
|
|
1790
|
+
yellow = int(summary.get("yellow", 0) or 0)
|
|
1791
|
+
red = int(summary.get("red", 0) or 0)
|
|
1792
|
+
except Exception:
|
|
1793
|
+
# Last resort: emoji-aware (+ legacy tag) counts from health text.
|
|
1794
|
+
try:
|
|
1795
|
+
health_text = _run_wikifier_command("health", root=root)
|
|
1796
|
+
green = health_text.count("🟢") + health_text.count("[GREEN]")
|
|
1797
|
+
yellow = health_text.count("🟡") + health_text.count("[YELLOW]")
|
|
1798
|
+
red = health_text.count("🔴") + health_text.count("[RED]")
|
|
1799
|
+
total = green + yellow + red
|
|
1800
|
+
except Exception:
|
|
1801
|
+
pass
|
|
1775
1802
|
|
|
1776
1803
|
if format == "json":
|
|
1777
1804
|
return ProjectHealthSummary(
|
|
1778
|
-
total_files=green + yellow + red,
|
|
1805
|
+
total_files=total or (green + yellow + red),
|
|
1779
1806
|
green=green,
|
|
1780
1807
|
yellow=yellow,
|
|
1781
1808
|
red=red,
|
|
@@ -1884,7 +1911,8 @@ def suggest_next_actions(
|
|
|
1884
1911
|
root = _get_effective_root(project_root)
|
|
1885
1912
|
|
|
1886
1913
|
try:
|
|
1887
|
-
import
|
|
1914
|
+
import importlib
|
|
1915
|
+
health_module = importlib.import_module("wikifier.health")
|
|
1888
1916
|
summary = health_module.get_summary(root, directory)
|
|
1889
1917
|
red = summary["red"]
|
|
1890
1918
|
yellow = summary["yellow"]
|
|
@@ -938,7 +938,21 @@ def _follow_reexports(
|
|
|
938
938
|
if target_module.startswith('.'):
|
|
939
939
|
level = len(re.match(r'\.+', target_module).group())
|
|
940
940
|
resolved = _resolve_relative_import(current_file, target_module, level)
|
|
941
|
-
|
|
941
|
+
# Prefer central_resolve directly (R4); avoid the deprecated shim on the
|
|
942
|
+
# hot path so tests/production do not emit DeprecationWarning.
|
|
943
|
+
resolved_path = None
|
|
944
|
+
try:
|
|
945
|
+
if central_resolve is not None:
|
|
946
|
+
proj_root = _get_project_root_fallback(current_file.parent)
|
|
947
|
+
r = central_resolve(target_module, str(current_file), proj_root)
|
|
948
|
+
resolved_path = r.resolved_file
|
|
949
|
+
except Exception:
|
|
950
|
+
resolved_path = None
|
|
951
|
+
if not resolved_path:
|
|
952
|
+
# Silent legacy FS fallthrough (same body as deprecated shim tail).
|
|
953
|
+
with warnings.catch_warnings():
|
|
954
|
+
warnings.simplefilter("ignore", DeprecationWarning)
|
|
955
|
+
resolved_path = _try_resolve_relative_path(current_file, target_module)
|
|
942
956
|
if not resolved_path:
|
|
943
957
|
return [{
|
|
944
958
|
"module": resolved,
|
|
@@ -149,6 +149,29 @@ build_exclude_expr() {
|
|
|
149
149
|
fi
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
# Build find(1) exclude arguments from exclude_patterns.txt as a bash array.
|
|
153
|
+
# The string form from build_exclude_expr embeds literal quote characters and
|
|
154
|
+
# cannot be expanded safely into a find command without eval; this array form
|
|
155
|
+
# is what scan commands (check-changes, validate) must use.
|
|
156
|
+
EXCLUDE_FIND_ARGS=()
|
|
157
|
+
build_exclude_find_args() {
|
|
158
|
+
EXCLUDE_FIND_ARGS=()
|
|
159
|
+
[[ -f "$EXCLUDE_PATTERNS_FILE" ]] || return 0
|
|
160
|
+
local pat
|
|
161
|
+
local parts=()
|
|
162
|
+
while IFS= read -r pat; do
|
|
163
|
+
[[ -z "$pat" || "$pat" =~ ^[[:space:]]*# ]] && continue
|
|
164
|
+
pat=$(echo "$pat" | xargs)
|
|
165
|
+
[[ -z "$pat" ]] && continue
|
|
166
|
+
if ((${#parts[@]})); then parts+=(-o); fi
|
|
167
|
+
# dir-name patterns prune contents; -name catches file globs (*.pyc) and exact basenames
|
|
168
|
+
parts+=(-path "*/$pat/*" -o -path "*/$pat" -o -name "$pat")
|
|
169
|
+
done < "$EXCLUDE_PATTERNS_FILE"
|
|
170
|
+
if ((${#parts[@]})); then
|
|
171
|
+
EXCLUDE_FIND_ARGS=('!' '(' "${parts[@]}" ')')
|
|
172
|
+
fi
|
|
173
|
+
}
|
|
174
|
+
|
|
152
175
|
# Upsert a row in the Markdown health table (very simple but effective)
|
|
153
176
|
# We treat file_health.md as the single source of truth.
|
|
154
177
|
upsert_health() {
|
|
@@ -298,8 +321,7 @@ cmd_check_changes() {
|
|
|
298
321
|
echo "$last_ts" > "$LAST_CHECK_FILE"
|
|
299
322
|
fi
|
|
300
323
|
|
|
301
|
-
|
|
302
|
-
exclude=$(build_exclude_expr)
|
|
324
|
+
build_exclude_find_args
|
|
303
325
|
|
|
304
326
|
local changed=0
|
|
305
327
|
local changed_files_list=""
|
|
@@ -309,7 +331,6 @@ cmd_check_changes() {
|
|
|
309
331
|
[[ -z "$root" ]] && continue
|
|
310
332
|
[[ ! -e "$root" ]] && { log "Warning: monitored path does not exist: $root"; continue; }
|
|
311
333
|
|
|
312
|
-
# shellcheck disable=SC2086
|
|
313
334
|
while IFS= read -r -d '' file; do
|
|
314
335
|
# Skip the wikifier tool's own internal files
|
|
315
336
|
if [[ "$file" == *"/.wikifier_staging/"* || "$file" == *"/journal/"* || \
|
|
@@ -317,8 +338,16 @@ cmd_check_changes() {
|
|
|
317
338
|
continue
|
|
318
339
|
fi
|
|
319
340
|
|
|
341
|
+
# Portable project-relative path. GNU realpath --relative-to is not on
|
|
342
|
+
# macOS BSD realpath; falling back to the absolute path polluted health
|
|
343
|
+
# keys (and shell upsert only patched .md, not file_health.json).
|
|
320
344
|
local rel_file
|
|
321
|
-
|
|
345
|
+
case "$file" in
|
|
346
|
+
"$PROJECT_ROOT"/*) rel_file="${file#"$PROJECT_ROOT"/}" ;;
|
|
347
|
+
*)
|
|
348
|
+
rel_file=$(python3 -c "from pathlib import Path; import sys; print(Path(sys.argv[1]).resolve().relative_to(Path(sys.argv[2]).resolve()))" "$file" "$PROJECT_ROOT" 2>/dev/null || echo "$file")
|
|
349
|
+
;;
|
|
350
|
+
esac
|
|
322
351
|
|
|
323
352
|
upsert_health "$rel_file" "🟡 Yellow" "mtime changed since last check-changes (auto-detected)"
|
|
324
353
|
# Collect for delta barrel reports (Wave continuation: pass changed list to BRC get_reports for O(changed) + rich auto-Yellow only on relevant)
|
|
@@ -327,7 +356,7 @@ cmd_check_changes() {
|
|
|
327
356
|
write_journal "auto-detected" "$rel_file" "File mtime changed (check-changes)"
|
|
328
357
|
|
|
329
358
|
changed=$((changed + 1)) # set -e safe (((changed++)) returns 1 at 0)
|
|
330
|
-
done < <(find "$root" -type f -newermt "$last_ts" -print0 2>/dev/null || true)
|
|
359
|
+
done < <(find "$root" -type f ${EXCLUDE_FIND_ARGS[@]+"${EXCLUDE_FIND_ARGS[@]}"} -newermt "$last_ts" -print0 2>/dev/null || true)
|
|
331
360
|
done < <(get_monitored_paths)
|
|
332
361
|
|
|
333
362
|
date '+%Y-%m-%d %H:%M:%S' > "$LAST_CHECK_FILE"
|
|
@@ -550,14 +579,18 @@ cmd_validate() {
|
|
|
550
579
|
log "Validating that every monitored file has a health entry..."
|
|
551
580
|
|
|
552
581
|
local missing=0
|
|
553
|
-
|
|
554
|
-
exclude=$(build_exclude_expr)
|
|
582
|
+
build_exclude_find_args
|
|
555
583
|
|
|
556
584
|
while IFS= read -r root; do
|
|
557
585
|
[[ -z "$root" ]] && continue
|
|
558
|
-
find "$root" -type f ! -path "*/.git/*" ! -path "*/.wikifier_staging/*" 2>/dev/null | while read -r f; do
|
|
586
|
+
find "$root" -type f ! -path "*/.git/*" ! -path "*/.wikifier_staging/*" ${EXCLUDE_FIND_ARGS[@]+"${EXCLUDE_FIND_ARGS[@]}"} 2>/dev/null | while read -r f; do
|
|
559
587
|
local rel
|
|
560
|
-
|
|
588
|
+
case "$f" in
|
|
589
|
+
"$PROJECT_ROOT"/*) rel="${f#"$PROJECT_ROOT"/}" ;;
|
|
590
|
+
*)
|
|
591
|
+
rel=$(python3 -c "from pathlib import Path; import sys; print(Path(sys.argv[1]).resolve().relative_to(Path(sys.argv[2]).resolve()))" "$f" "$PROJECT_ROOT" 2>/dev/null || echo "$f")
|
|
592
|
+
;;
|
|
593
|
+
esac
|
|
561
594
|
if ! grep -qF "| $rel |" "$FILE_HEALTH" 2>/dev/null; then
|
|
562
595
|
echo "🔴 MISSING WIKI ENTRY: $rel"
|
|
563
596
|
((missing++)) || true
|