agent-doc-system 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +269 -0
  2. package/README.md +38 -0
  3. package/adapters/ansible.mjs +1 -1
  4. package/adapters/cache.mjs +8 -2
  5. package/adapters/contract-consumers.mjs +1 -1
  6. package/adapters/database.mjs +18 -4
  7. package/adapters/events.mjs +1 -1
  8. package/adapters/github-actions.mjs +244 -85
  9. package/adapters/go.mjs +1 -1
  10. package/adapters/index.mjs +3 -1
  11. package/adapters/object-store.mjs +2 -2
  12. package/adapters/python.mjs +1142 -0
  13. package/adapters/resource-client.mjs +1 -1
  14. package/adapters/rust.mjs +987 -0
  15. package/adapters/typescript.mjs +1 -1
  16. package/bin/agentdoc.mjs +2 -2
  17. package/core/audit.mjs +5 -3
  18. package/core/codes.mjs +4 -0
  19. package/core/compile.mjs +124 -11
  20. package/core/dependents.mjs +42 -0
  21. package/core/discover.mjs +60 -9
  22. package/core/fsx.mjs +17 -0
  23. package/core/graph.mjs +1 -1
  24. package/core/impact.mjs +55 -44
  25. package/core/query.mjs +18 -8
  26. package/core/scaffold.mjs +87 -22
  27. package/core/sourcescan.mjs +11 -2
  28. package/core/toml.mjs +463 -140
  29. package/docs/ADAPTERS.md +196 -6
  30. package/docs/BENCHMARK.md +68 -0
  31. package/docs/CI.md +1 -1
  32. package/docs/EVALS.md +33 -2
  33. package/docs/MIGRATION.md +4 -2
  34. package/docs/QUERY.md +53 -4
  35. package/docs/SPEC.md +22 -0
  36. package/docs/ci/github-actions.yml +1 -1
  37. package/evals/harness.mjs +32 -6
  38. package/evals/scenarios/fixture-b-03-change-shared-lib.json +8 -1
  39. package/evals/scenarios/fixture-c-03-shared-vocabulary.json +7 -1
  40. package/evals/scenarios/fixture-e-01-change-shared-lib.json +14 -0
  41. package/evals/scenarios/fixture-e-02-change-manifest.json +9 -0
  42. package/evals/scenarios/fixture-e-03-local-module.json +9 -0
  43. package/evals/scenarios/fixture-e-04-ambiguous-crate.json +14 -0
  44. package/evals/scenarios/fixture-f-01-change-shared-lib.json +9 -0
  45. package/evals/scenarios/fixture-f-02-change-manifest.json +9 -0
  46. package/evals/scenarios/fixture-f-03-shadowed-import.json +9 -0
  47. package/evals/scenarios/fixture-f-04-nested-workspace.json +9 -0
  48. package/evals/scenarios/fixture-f-05-alembic-database.json +9 -0
  49. package/evals/scenarios/fixture-f-06-unittest-job.json +9 -0
  50. package/package.json +2 -1
  51. package/skills/agent-doc-system/references/create-migrate.md +13 -3
  52. package/templates/ci.yml +1 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,269 @@
1
+ # Changelog
2
+
3
+ All notable changes to AgentDoc are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
6
+ the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The
7
+ compiler version is the package version: a graph compiled by one release is
8
+ refused by the next with `AGENTDOC_COMPILER_MISMATCH` until it is recompiled.
9
+
10
+ ## [Unreleased]
11
+
12
+ ## [1.2.0] - 2026-10-27
13
+
14
+ Rust and Python are now supported at the same level as Node and Go. Before
15
+ this release, a Cargo crate or a Python package was invisible to the compiler:
16
+ `agentdoc audit` reported zero units, and a hand-written descriptor produced a
17
+ component with no language, no dependency edges and no verification commands.
18
+
19
+ The release also fixes how a change is routed. `impact` and `query` now follow
20
+ the components that depend on the changed one, not the ones it depends on, and
21
+ recommend those dependents' checks.
22
+
23
+ ### Added
24
+
25
+ - **`rust` adapter** ([#17]). Reads `Cargo.toml` and never runs Cargo or reads
26
+ `Cargo.lock`.
27
+ - A `[package]` is a unit. `[[bin]]`, `src/main.rs` or `src/bin/` make it
28
+ deployable; `[lib]` or `src/lib.rs` make it importable.
29
+ - Workspace members come from every `[workspace]` manifest, including one
30
+ below the repository root (`rust/Cargo.toml` next to other languages).
31
+ - Sibling crates become `buildDependsOn` / `testDependsOn` edges when the
32
+ manifest says so: a `path`, `workspace = true` resolved through the nearest
33
+ `[workspace.dependencies]`, or a `[patch.<registry>]` / `[replace]` path
34
+ redirect inside the repository. `use`, `extern crate` and `<crate>::` paths
35
+ add provenance to those edges but never create one, because Rust cannot
36
+ use a crate the manifest does not declare.
37
+ - Verification commands: `cargo test -p <name>` and `cargo clippy -p <name>`.
38
+ - Resource vocabulary: sqlx, diesel (`diesel.toml`), tokio-postgres,
39
+ deadpool, sea-orm, the `redis` crate and `aws-sdk-s3`.
40
+ - **`python` adapter** ([#18]). Reads `pyproject.toml` (PEP 621 and Poetry),
41
+ `setup.cfg`, `setup.py` and `requirements*.txt`. It never runs Python,
42
+ resolves a lockfile or inspects a virtualenv.
43
+ - Shape comes from evidence. An entrypoint (`[project.scripts]`,
44
+ `__main__.py`, `manage.py`, an ASGI/WSGI app object) makes a unit
45
+ deployable; a build backend plus a package makes it importable.
46
+ - uv workspace members come from the repository root and from workspaces
47
+ below it. A member with no build backend is still a unit.
48
+ - Sibling packages become edges from `[project] dependencies`,
49
+ `[tool.uv.sources]`, Poetry `path` dependencies, `-e <dir>` requirements,
50
+ and `import` / `from` statements. Dev groups and dev/test extras give
51
+ `testDependsOn`. An import that the importing unit provides itself, such
52
+ as a local `utils.py`, is not read as a sibling.
53
+ - Verification commands are derived only from evidence: `pytest`,
54
+ `python -m unittest discover` for unittest-only suites, `ruff check` and
55
+ `mypy`. `uv run` / `poetry run` is prefixed only when the lockfile names
56
+ the tool.
57
+ - Also derived: `requiresPython` when declared, and Alembic migrations as
58
+ database evidence.
59
+ - Resource vocabulary: SQLAlchemy, asyncpg, psycopg, Django `DATABASES`,
60
+ `redis.Redis` and boto3.
61
+ - `agentdoc init` enables `rust` and `python` when it finds their manifests.
62
+ `agentdoc scaffold` names crates and distributions from their manifests and
63
+ types them from their artifact shape: `service`, `library`, or `other` when
64
+ neither is proven. A virtual Cargo or uv workspace manifest is not scaffolded.
65
+ - A reproducible benchmark, `scripts/bench/run.mjs` ([docs/BENCHMARK.md]).
66
+ It clones four public repositories at pinned commits, runs a fresh
67
+ `init` → `scaffold` → `compile`, counts every hand edit the setup still
68
+ needs (zero for all four), checks that the graph is byte-identical across
69
+ compiles, and measures `query` answers.
70
+ - The routing evaluation reports **check selectivity**: the share of the
71
+ repository's checks that the answer for a change contains ([#43]). The
72
+ baseline's verification recall is now scored with the same rule as the
73
+ catalog's. It is 1.0 by construction, because the baseline runs every check.
74
+ - Rust and Python sample repositories (`fixtures/e-rust-workspace`,
75
+ `fixtures/f-python-workspace`), checked in CI and used to test context
76
+ routing ([#23]).
77
+
78
+ ### Changed
79
+
80
+ - **Change routing follows dependents** ([#30], [#25]).
81
+ - A change to a component reaches the components that depend on it,
82
+ transitively, through reverse `buildDependsOn` / `testDependsOn` edges.
83
+ Before, `impact` also listed the components it depends on as affected,
84
+ and did not follow transitive dependents.
85
+ - Dependencies stay visible as typed relations in `query`. They are no
86
+ longer reported as affected components.
87
+ - `query` and `impact` recommend the dependents' checks after the changed
88
+ component's own: every tier for build dependents, unit checks only for test
89
+ dependents.
90
+ - `impact` adds `recommendedVerificationTotal` and
91
+ `recommendedVerificationTruncated`, so a capped list is never mistaken for
92
+ the whole.
93
+ - **`query` markdown shows an entity's context** ([#28]). Resources and
94
+ Systems now list their `docs`, `CONSTRAINTS` and `runbooks`, as components
95
+ already did. Constraints are never capped by default. Docs and runbooks show
96
+ 12 paths each, and `--budget docs=…,constraints=…,runbooks=…` sets explicit
97
+ caps with a `[truncated: x of y]` marker.
98
+ - **`discovery.notUnitRoots` excludes a whole subtree from inferred units**
99
+ ([#27]). An adapter marker or a scaffold proposal at or below an excluded
100
+ root is no longer a unit. A hand-written descriptor below an excluded root
101
+ is still honoured. A descriptor exactly at an excluded root is refused with
102
+ a message that names the exclusion.
103
+ - **GitHub Actions checks are scoped to the components they run for**
104
+ ([#29]). A step becomes a component check only when its command is a
105
+ recognised test, lint or build invocation, scoped by `working-directory`,
106
+ `cd <dir> &&`, a path argument, a package selector (`--filter`, turbo, nx,
107
+ `make -C`) or a `paths:` filter. Repository scripts whose names say what
108
+ they check (`./scripts/test.sh`, `bash scripts/lint.sh`) are recognised
109
+ with the same scoping ([#40]). Anything else is a repository gate.
110
+ - Before, every step was attached to every component whose path or package
111
+ name appeared anywhere in the workflow, including multi-line ops scripts.
112
+ A shell `test -n` was also recorded as a unit test.
113
+ - `impact` on a workflow file now names the components and gates derived
114
+ from it, plus their dependents' checks.
115
+ - **The TOML reader conforms to TOML 1.0** ([#18], [#31]). It reads
116
+ `Cargo.toml`, `pyproject.toml` and `wrangler.toml`, and passes every case of
117
+ the official [toml-test](https://github.com/toml-lang/toml-test) 1.0.0
118
+ suite: 208 valid and 501 invalid documents. Before, it rejected valid
119
+ documents, such as multi-line strings and lowercase date-time delimiters,
120
+ which lost every fact in the file. It also accepted invalid ones, such as a
121
+ trailing comma in an inline table or a table declared twice. Invalid TOML
122
+ is rejected with `AGENTDOC_YAML_PARSE`.
123
+
124
+ ### Fixed
125
+
126
+ - **A unit nested inside another unit no longer leaks its facts into the
127
+ parent** ([#21]). Every per-unit scan stops at nested units, so each file
128
+ belongs to the deepest unit that contains it. Before, an enclosing unit also
129
+ claimed its nested unit's health routes, ports, capabilities, resource and
130
+ migration evidence, imports, contract consumers, TypeScript routes, Ansible
131
+ playbooks and test markers. This affects any layout with nested units, such
132
+ as a service containing a tool package, a Cargo root package with member
133
+ crates below it, or a uv workspace root with its own `[project]`.
134
+ - An Alembic `alembic/versions` directory was listed as a migration location
135
+ but never recognised. It now counts as migration evidence. The evidence file
136
+ is a qualifying `alembic.ini` or `[tool.alembic]` configuration when one
137
+ exists, and otherwise a revision file.
138
+ - A changed migration, including an Alembic revision, now lists the logical
139
+ database its component uses in `impact`'s `affectedResources` ([#30]).
140
+ Before, the list stayed empty.
141
+ - The audit no longer reports a document as orphaned when it is linked only
142
+ from a Resource's or System's `context` ([#28]).
143
+ - `agentdoc scaffold --write` no longer writes descriptors into directories
144
+ listed in `discovery.notUnitRoots` ([#27]).
145
+ - **A fresh setup compiles without hand edits** ([#37], [#38]).
146
+ - `scaffold` now types every unit from its artifact evidence: `service`,
147
+ `library`, or `other` when neither is proven. Before, a Node app without
148
+ `exports` or `main`, or a Go module, was written as `library` and failed
149
+ `validate` straight away.
150
+ - `init` now discovers descriptors with the `*/**/agentdoc.yaml` glob
151
+ instead of an explicit list, and `scaffold` covers every unit an adapter
152
+ declares, including workspace members under `examples/`.
153
+ - A `setup.py` unit is named after the distribution it declares, and the
154
+ `python` adapter reads `name`, `python_requires` and `install_requires`
155
+ inside a one-line `setup(…)` or `setuptools.setup(…)` call ([#41]).
156
+ - On the four public repositories used for benchmarking (tokio-rs/axum,
157
+ pydantic/pydantic-ai, fastapi/full-stack-fastapi-template and
158
+ t3-oss/create-t3-turbo), `init` + `scaffold --write` + `compile` now pass
159
+ with no edits other than choosing each component's placement.
160
+
161
+ ### Upgrading
162
+
163
+ - The compiler version is now `1.2.0`. A graph committed with 1.1.0 fails
164
+ `agentdoc check` with `AGENTDOC_COMPILER_MISMATCH`. Run `agentdoc compile`
165
+ and commit the graph.
166
+ - An existing catalog keeps its adapter list. To use the new adapters, add
167
+ `rust` and/or `python` to `adapters:` in `agentdoc/agentdoc.config.yaml`,
168
+ then run `agentdoc audit`: units that were invisible appear as
169
+ `AGENTDOC_COVERAGE_ZERO` until they have a descriptor.
170
+ `agentdoc scaffold --write` writes those descriptors.
171
+ - If your repository has nested units, recompiling removes facts that were
172
+ wrongly attributed to an enclosing component. Review the affected facts,
173
+ dependency edges and verification commands, and any descriptor or document
174
+ that relied on them.
175
+ - Tools that read `impact --json` will see fewer `affectedComponents`
176
+ (dependencies are gone) and more `recommendedVerification` entries
177
+ (dependents' checks).
178
+ - A unit inferred below a `notUnitRoots` entry, with no descriptor, is no
179
+ longer reported as `AGENTDOC_COVERAGE_ZERO`. If it should be a component,
180
+ write its descriptor, or remove the directory from `notUnitRoots`.
181
+ - If your workflows run checks for specific components, recompiling changes
182
+ which checks are attached to which component. Review the diff: checks that
183
+ were attached only because a path was mentioned elsewhere in the workflow
184
+ move to repository gates.
185
+ - Recompiling always updates the compiler version, source commit and input
186
+ hash. Review the other derived changes, especially in repositories with
187
+ nested units, Alembic migrations or Wrangler TOML manifests: a manifest the
188
+ old TOML reader could not parse now yields facts.
189
+
190
+ ## [1.1.0] - 2026-10-18
191
+
192
+ ### Added
193
+
194
+ - **MIGRATE gates normative requirements and section coverage** ([#5]).
195
+ Documentation checks now state their real scope, and the strict gate refuses
196
+ unverified requirements.
197
+ - **`ansible` adapter** ([#6]). Reads playbooks without running anything and
198
+ derives installed paths and managed services. A requirement with
199
+ `satisfiedBy: [ansible]` and the new `expects` field
200
+ (`installs: <path>` | `service: <name>`) is checked against them, so a missing
201
+ install ends in a conflict instead of `AGENTDOC_REQUIREMENT_UNVERIFIED`.
202
+ - `agentdoc <command> --help` lists each command's flags and exit codes ([#7]).
203
+
204
+ ### Changed
205
+
206
+ - **The CLI rejects unknown flags** ([#7]) and names the closest valid flag. A
207
+ typo such as `check --strcit` no longer silently runs a non-strict check.
208
+ Scripts that passed flags a command does not accept now exit 2.
209
+
210
+ ### Fixed
211
+
212
+ - A committed graph passes CI ([#11]). `check` no longer fails with
213
+ `AGENTDOC_GRAPH_FRESHNESS` after `compile` on a clean checkout, where the
214
+ graph file itself was counted as a changed input.
215
+ - A nested `.github/workflows` directory no longer fails `validate` ([#12]).
216
+ Only the repository-root directory is read, as GitHub does.
217
+
218
+ ### Upgrading
219
+
220
+ - A graph committed with 1.0.0 fails `agentdoc check` with
221
+ `AGENTDOC_COMPILER_MISMATCH` until it is recompiled.
222
+
223
+ ## [1.0.0] - 2026-09-29
224
+
225
+ First public release.
226
+
227
+ ### Added
228
+
229
+ - The machine-installed `agentdoc` CLI for Node 22, 24 and 26, with zero
230
+ runtime dependencies.
231
+ - A deterministic repository graph: repeated compiles of the same tree are
232
+ byte-identical.
233
+ - Evidence separation between AUTHORED documentation, DERIVED facts extracted
234
+ from code, and OBSERVED runtime evidence.
235
+ - A fail-closed authority model: contradictions surface as conflicts and are
236
+ never silently overwritten.
237
+ - `agentdoc query`, which routes minimal, budgeted context for a task, and
238
+ `agentdoc impact`, which reports what a change forces you to keep consistent.
239
+ - CREATE and MIGRATE workflows through `init`, `audit`, `scaffold`,
240
+ `validate`, `compile` and `check`.
241
+ - `agentdoc doctor` for machine diagnostics, and `agentdoc doctor --project`
242
+ for project health.
243
+ - An Agent Skill under `skills/agent-doc-system/`.
244
+
245
+ [Unreleased]: https://github.com/lbframe/agent-doc-system/compare/v1.2.0...HEAD
246
+ [1.2.0]: https://github.com/lbframe/agent-doc-system/compare/v1.1.0...v1.2.0
247
+ [1.1.0]: https://github.com/lbframe/agent-doc-system/compare/v1.0.0...v1.1.0
248
+ [1.0.0]: https://github.com/lbframe/agent-doc-system/releases/tag/v1.0.0
249
+ [docs/BENCHMARK.md]: docs/BENCHMARK.md
250
+ [#5]: https://github.com/lbframe/agent-doc-system/issues/5
251
+ [#6]: https://github.com/lbframe/agent-doc-system/issues/6
252
+ [#7]: https://github.com/lbframe/agent-doc-system/issues/7
253
+ [#11]: https://github.com/lbframe/agent-doc-system/issues/11
254
+ [#12]: https://github.com/lbframe/agent-doc-system/issues/12
255
+ [#17]: https://github.com/lbframe/agent-doc-system/issues/17
256
+ [#18]: https://github.com/lbframe/agent-doc-system/issues/18
257
+ [#21]: https://github.com/lbframe/agent-doc-system/issues/21
258
+ [#23]: https://github.com/lbframe/agent-doc-system/issues/23
259
+ [#25]: https://github.com/lbframe/agent-doc-system/issues/25
260
+ [#27]: https://github.com/lbframe/agent-doc-system/issues/27
261
+ [#28]: https://github.com/lbframe/agent-doc-system/issues/28
262
+ [#29]: https://github.com/lbframe/agent-doc-system/issues/29
263
+ [#30]: https://github.com/lbframe/agent-doc-system/issues/30
264
+ [#31]: https://github.com/lbframe/agent-doc-system/issues/31
265
+ [#37]: https://github.com/lbframe/agent-doc-system/issues/37
266
+ [#38]: https://github.com/lbframe/agent-doc-system/issues/38
267
+ [#40]: https://github.com/lbframe/agent-doc-system/issues/40
268
+ [#41]: https://github.com/lbframe/agent-doc-system/issues/41
269
+ [#43]: https://github.com/lbframe/agent-doc-system/issues/43
package/README.md CHANGED
@@ -69,6 +69,41 @@ AgentDoc turns scattered repository knowledge into task-specific context your co
69
69
 
70
70
  ![How AgentDoc works](docs/assets/readme/how-agentdoc-works.webp)
71
71
 
72
+ ## What it understands
73
+
74
+ AgentDoc reads manifests, contracts and configuration. It never runs your toolchain.
75
+
76
+ Support comes from adapters and from built-in contract validation (AsyncAPI needs no adapter).
77
+ - `agentdoc init` picks `node`, `go`, `rust`, `python`, `dockerfile` and `wrangler` from the files it finds.
78
+ - It always includes `database`, `openapi`, `events` and `github-actions`.
79
+ - Add the others in `agentdoc/agentdoc.config.yaml`.
80
+
81
+ | area | supported |
82
+ |---|---|
83
+ | languages & packages | Node (npm, pnpm workspaces, Turborepo), TypeScript, Go (modules, `go.work`), Rust (Cargo packages and workspaces), Python (`pyproject.toml` with PEP 621 or Poetry, uv workspaces, `setup.cfg` / `setup.py`, `requirements*.txt`) |
84
+ | contracts | OpenAPI, protobuf, GraphQL, AsyncAPI, OIDC discovery |
85
+ | deployment & CI | Dockerfile / Containerfile, `fly.toml`, `Procfile` and similar deploy configs, Cloudflare Wrangler, Ansible playbooks, GitHub Actions |
86
+ | resources | databases (migrations, ORM config, connection evidence), caches, object stores, event subjects |
87
+
88
+ For each language, AgentDoc derives:
89
+
90
+ - the units;
91
+ - whether each one is deployable or importable;
92
+ - dependency edges between sibling units;
93
+ - verification commands taken from the repository's own evidence (`go test`, `cargo test -p`, `pytest`, `python -m unittest`, npm scripts, …).
94
+
95
+ What every adapter derives, and what it deliberately cannot see, is in [docs/ADAPTERS.md](docs/ADAPTERS.md).
96
+
97
+ ## By the numbers
98
+
99
+ Measured, reproducible, and with no model in the loop. Method and caveats are in [docs/BENCHMARK.md](docs/BENCHMARK.md).
100
+
101
+ - **The right context: 100% vs. 58%.** Across 30 routing scenarios (Node, Go, Rust, Python), `query` + `impact` retrieves every fact the change needs. Reading only the touched component retrieves 58%. Noise stays under 9%, against 40%. Every check the change requires is in the answer, and that answer holds about half of the repository's checks (29% on the largest corpus), not all of them. The thresholds were fixed before the first run and have not moved since.
102
+ - **Seconds to map a real repository.** A fresh `init` → `scaffold` → `compile` takes 1.0–4.6 s on four public repositories, from 141 to 5,142 files (axum, pydantic-ai, full-stack-fastapi-template, create-t3-turbo). No edit was needed beyond choosing each component's placement.
103
+ - **A briefing, not a dump.** A `query` answer is about 100–260 tokens: what the change reaches, what to read, and which checks to run.
104
+ - **The same graph every time.** Compiles are byte-identical, and CI can verify it.
105
+ - **Small and strict.** Zero runtime dependencies, a package of about 285 kB packed, 21 adapters, and 709/709 cases on the official TOML 1.0 conformance suite.
106
+
72
107
  ## Install manually
73
108
 
74
109
  Requires Node.js 22+.
@@ -92,7 +127,10 @@ AgentDoc also ships with an Agent Skill at [`skills/agent-doc-system/`](skills/a
92
127
  - [Authority & conflicts](docs/AUTHORITY.md)
93
128
  - [CI & verification](docs/CI.md)
94
129
  - [Specification](docs/SPEC.md)
130
+ - [Adapters](docs/ADAPTERS.md)
131
+ - [Benchmark](docs/BENCHMARK.md)
95
132
  - [Agent Skill](skills/agent-doc-system/SKILL.md)
133
+ - [Changelog](CHANGELOG.md)
96
134
 
97
135
  ## License
98
136
 
@@ -132,7 +132,7 @@ function isYaml(f) {
132
132
 
133
133
  function playbooks(repo, root) {
134
134
  const out = [];
135
- for (const f of repo.walk(root)) {
135
+ for (const f of repo.walkUnit(root)) {
136
136
  if (!isYaml(f) || /(^|\/)(tasks|handlers|vars|defaults|meta|group_vars|host_vars|templates|files)\//.test(f.slice(root.length))) continue;
137
137
  const docs = parse(repo, f);
138
138
  if (!docs) continue;
@@ -1,7 +1,7 @@
1
1
  // Cache adapter: Redis / in-memory cache client evidence as a derived binding.
2
2
  import { Adapter } from "./registry.mjs";
3
3
 
4
- const CACHE_HINT = /(@upstash\/redis|ioredis|redis|go-redis|redis\.go|valkey|memcache|@memcached)/i;
4
+ const CACHE_HINT = /(@upstash\/redis|ioredis|redis\.Redis|redis|go-redis|redis\.go|valkey|memcache|@memcached)/i;
5
5
 
6
6
  export class CacheAdapter extends Adapter {
7
7
  static adapterName = "cache";
@@ -10,7 +10,13 @@ export class CacheAdapter extends Adapter {
10
10
  }
11
11
  extract(ctx, unit) {
12
12
  const { repo, prov, compRef } = ctx;
13
- const evFile = unit.goModule ? unit.root + "/go.mod" : unit.root + "/package.json";
13
+ const evFile = unit.goModule
14
+ ? unit.root + "/go.mod"
15
+ : unit.pythonManifest
16
+ ? unit.pythonManifest
17
+ : repo.exists(unit.root + "/package.json")
18
+ ? unit.root + "/package.json"
19
+ : unit.root + "/Cargo.toml";
14
20
  if (!repo.exists(evFile)) return {};
15
21
  const text = repo.readText(evFile);
16
22
  if (!CACHE_HINT.test(text)) return {};
@@ -18,7 +18,7 @@ const DOC_EXT = /\.(md|mdx|txt|adoc|rst)$/;
18
18
 
19
19
  export function contractReferenceSites(repo, unit) {
20
20
  const out = new Map(); // file -> true
21
- for (const f of repo.walk(unit.root)) {
21
+ for (const f of repo.walkUnit(unit.root)) {
22
22
  const base = path.posix.basename(f);
23
23
  if (DOC_EXT.test(f)) continue;
24
24
  if (f.includes("/docs/") || f.startsWith("docs/")) continue;
@@ -15,6 +15,9 @@ const ORM_CONFIG = [
15
15
  "prisma/schema.prisma", "schema.prisma",
16
16
  "knexfile.js", "knexfile.ts", "sequelize.config.js", "ormconfig.json",
17
17
  ];
18
+ // Probed only for a Cargo package. Adding it to the list above would record
19
+ // a new existence probe on every non-Rust unit and change those graphs.
20
+ const RUST_ORM_CONFIG = ["diesel.toml"];
18
21
 
19
22
  export class DatabaseAdapter extends Adapter {
20
23
  static adapterName = "database";
@@ -25,12 +28,23 @@ export class DatabaseAdapter extends Adapter {
25
28
  const { repo, prov, compRef } = ctx;
26
29
  const root = unit.root;
27
30
  const migrationDirs = findMigrationDirs(repo, root);
28
- const ormConfig = firstExistingFile(repo, root, ORM_CONFIG);
31
+ const ormConfig = firstExistingFile(repo, root, unit.cargoPackage ? ORM_CONFIG.concat(RUST_ORM_CONFIG) : ORM_CONFIG);
29
32
  if (!migrationDirs.length && !ormConfig) return {};
30
33
 
31
34
  let evidencePath = ormConfig;
32
35
  if (migrationDirs.length) {
33
- evidencePath = repo.walk(migrationDirs[0])[0] || migrationDirs[0];
36
+ evidencePath = repo.walkUnit(root, migrationDirs[0])[0] || migrationDirs[0];
37
+ }
38
+ const alembicDir = migrationDirs.find((d) => d === "alembic/versions" || d.endsWith("/alembic/versions"));
39
+ if (alembicDir) {
40
+ const ini = root + "/alembic.ini";
41
+ const pyproject = root + "/pyproject.toml";
42
+ if (repo.exists(ini)) {
43
+ const text = repo.readText(ini);
44
+ if (/^\s*\[alembic\]/m.test(text) || /^\s*script_location\s*=/m.test(text)) evidencePath = ini;
45
+ } else if (repo.exists(pyproject) && /\[tool\.alembic\]/.test(repo.readText(pyproject))) {
46
+ evidencePath = pyproject;
47
+ }
34
48
  }
35
49
  const pr = prov.add("observed", evidencePath, "migration-extractor", ["der:" + compRef + ":/bindings"]);
36
50
 
@@ -93,10 +107,10 @@ export class DatabaseAdapter extends Adapter {
93
107
  }
94
108
  }
95
109
 
96
- const POOL_HINT = /(createPool|new Pool|pg\.Pool|psycopg2?\.connect|sql\.Open|mysql\.createConnection|Pool\(|DataSource|prisma\.(datasource|client)|DATABASE_URL|DB_DSN)/;
110
+ const POOL_HINT = /(createPool|new Pool|pg\.Pool|PgPool|psycopg2?\.connect|asyncpg\.(?:connect|create_pool)|sql\.Open|mysql\.createConnection|Pool\(|DataSource|prisma\.(datasource|client)|DATABASE_URL|DB_DSN|sqlx::migrate!|tokio_postgres|tokio-postgres|deadpool|sea_orm|sea-orm|diesel::|create_engine\s*\(|\bDATABASES\s*=)/;
97
111
 
98
112
  function hasConnectionEvidence(ctx, unit) {
99
- for (const f of ctx.repo.walk(unit.root)) {
113
+ for (const f of ctx.repo.walkUnit(unit.root)) {
100
114
  if (/\.(ts|tsx|js|mjs|go|py|rb|java|kt|rs|ex|cs|php)$/.test(f)) {
101
115
  if (/(^|\/)(tests?|__tests__)\//.test(f)) continue;
102
116
  if (POOL_HINT.test(ctx.repo.readText(f))) return true;
@@ -70,7 +70,7 @@ export class EventsAdapter extends Adapter {
70
70
  if (other.component && visible.has(other.component.ref) && other.component.ref !== compRef) collectDecls(other.root);
71
71
  }
72
72
  const families = new Set();
73
- for (const f of repo.walk(unit.root)) {
73
+ for (const f of repo.walkUnit(unit.root)) {
74
74
  if (!SRC_EXT.test(f)) continue;
75
75
  if (TEST_PATH.test(f) || TEST_FILE.test(f)) continue;
76
76
  const text = repo.readText(f);