serpentine-parser 0.3.2__tar.gz → 0.5.0__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.
Files changed (83) hide show
  1. serpentine_parser-0.3.2/README.md → serpentine_parser-0.5.0/PKG-INFO +93 -0
  2. serpentine_parser-0.3.2/PKG-INFO → serpentine_parser-0.5.0/README.md +47 -34
  3. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/pyproject.toml +11 -2
  4. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/Cargo.lock +65 -54
  5. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/Cargo.toml +1 -1
  6. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/graph/builder.rs +5 -1
  7. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/__init__.py +1 -1
  8. serpentine_parser-0.5.0/src/serpentine/adapters.py +28 -0
  9. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/cache.py +83 -0
  10. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/cli.py +203 -156
  11. serpentine_parser-0.5.0/src/serpentine/domain/__init__.py +46 -0
  12. serpentine_parser-0.5.0/src/serpentine/mcp/__init__.py +3 -0
  13. serpentine_parser-0.5.0/src/serpentine/mcp/auth.py +150 -0
  14. serpentine_parser-0.5.0/src/serpentine/mcp/config.py +41 -0
  15. serpentine_parser-0.5.0/src/serpentine/mcp/prompts.py +48 -0
  16. serpentine_parser-0.5.0/src/serpentine/mcp/resources.py +49 -0
  17. serpentine_parser-0.5.0/src/serpentine/mcp/server.py +22 -0
  18. serpentine_parser-0.5.0/src/serpentine/mcp/tools.py +257 -0
  19. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/selector.py +15 -3
  20. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/server/app.py +3 -1
  21. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/server/routes.py +106 -62
  22. serpentine_parser-0.5.0/src/serpentine/services.py +343 -0
  23. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/skills/code-analysis.md +16 -8
  24. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/state.py +83 -19
  25. serpentine_parser-0.5.0/src/serpentine/static/assets/index-DgVKSbxY.js +32 -0
  26. serpentine_parser-0.5.0/src/serpentine/static/assets/index-Dmzvedun.css +1 -0
  27. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/static/index.html +2 -2
  28. serpentine_parser-0.5.0/src/serpentine/storage/__init__.py +4 -0
  29. serpentine_parser-0.5.0/src/serpentine/storage/base.py +8 -0
  30. serpentine_parser-0.5.0/src/serpentine/storage/factory.py +45 -0
  31. serpentine_parser-0.5.0/src/serpentine/storage/gcs.py +41 -0
  32. serpentine_parser-0.5.0/src/serpentine/storage/local.py +43 -0
  33. serpentine_parser-0.5.0/src/serpentine/storage/s3.py +59 -0
  34. serpentine_parser-0.5.0/src/serpentine/vcs/__init__.py +4 -0
  35. serpentine_parser-0.5.0/src/serpentine/vcs/backend.py +203 -0
  36. serpentine_parser-0.5.0/src/serpentine/vcs/factory.py +101 -0
  37. serpentine_parser-0.5.0/src/serpentine/vcs/github.py +166 -0
  38. serpentine_parser-0.5.0/src/serpentine/vcs/manager.py +120 -0
  39. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/watcher.py +1 -1
  40. serpentine_parser-0.3.2/src/serpentine/static/assets/index-CqW3OZBs.css +0 -1
  41. serpentine_parser-0.3.2/src/serpentine/static/assets/index-DGBMc5dK.js +0 -32
  42. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/LICENSE +0 -0
  43. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/CLAUDE.md +0 -0
  44. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/events.rs +0 -0
  45. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/graph/loaders.rs +0 -0
  46. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/graph/mod.rs +0 -0
  47. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/graph/pdg.rs +0 -0
  48. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/graph/resolvers.rs +0 -0
  49. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/javascript/config.rs +0 -0
  50. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/javascript/mod.rs +0 -0
  51. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/lib.rs +0 -0
  52. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/message_bus.rs +0 -0
  53. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/python/config.rs +0 -0
  54. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/python/mod.rs +0 -0
  55. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/rust_lang/config.rs +0 -0
  56. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/rust_lang/mod.rs +0 -0
  57. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/README.md +0 -0
  58. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/code_snippet.rs +0 -0
  59. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/decorators.rs +0 -0
  60. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/definitions.rs +0 -0
  61. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/event_counter.rs +0 -0
  62. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/imports.rs +0 -0
  63. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/mod.rs +0 -0
  64. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/pdg.rs +0 -0
  65. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/raw_bindings.rs +0 -0
  66. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/scope_tree.rs +0 -0
  67. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/types.rs +0 -0
  68. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/subscribers/uses.rs +0 -0
  69. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/terraform/config.rs +0 -0
  70. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/rust/src/terraform/mod.rs +0 -0
  71. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/_analyzer.pyi +0 -0
  72. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/config.py +0 -0
  73. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/server/__init__.py +0 -0
  74. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/server/websocket.py +0 -0
  75. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/skills/__init__.py +0 -0
  76. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/skills/agents-md.md +0 -0
  77. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/skills/copilot-instructions.md +0 -0
  78. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/skills/cursor-rules.md +0 -0
  79. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/static/assets/elk-worker.min-BqREE3LP.js +0 -0
  80. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/static/assets/layoutWorker-DEFCbISa.js +0 -0
  81. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/static/assets/mermaidExport-DphjeTrR.js +0 -0
  82. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/static/assets/svgToPng-C-twkIuO.js +0 -0
  83. {serpentine_parser-0.3.2 → serpentine_parser-0.5.0}/src/serpentine/static/logo.svg +0 -0
@@ -1,3 +1,48 @@
1
+ Metadata-Version: 2.4
2
+ Name: serpentine-parser
3
+ Version: 0.5.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Environment :: Console
6
+ Classifier: Environment :: Web Environment
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Rust
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Classifier: Topic :: Utilities
19
+ Requires-Dist: watchdog>=6.0.0
20
+ Requires-Dist: click>=8.1.0
21
+ Requires-Dist: starlette>=1.3.1
22
+ Requires-Dist: uvicorn[standard]>=0.30.0
23
+ Requires-Dist: websockets>=12.0
24
+ Requires-Dist: google-cloud-storage>=2.0 ; extra == 'gcs'
25
+ Requires-Dist: pygit2>=1.15 ; extra == 'git'
26
+ Requires-Dist: fastmcp>=2.0 ; extra == 'mcp'
27
+ Requires-Dist: httpx>=0.27 ; extra == 'mcp'
28
+ Requires-Dist: pyjwt[crypto]>=2.8 ; extra == 'mcp'
29
+ Requires-Dist: boto3>=1.34 ; extra == 's3'
30
+ Provides-Extra: gcs
31
+ Provides-Extra: git
32
+ Provides-Extra: hg
33
+ Provides-Extra: mcp
34
+ Provides-Extra: s3
35
+ Provides-Extra: svn
36
+ License-File: LICENSE
37
+ Summary: Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, Rust, and Terraform projects
38
+ Keywords: dependency-graph,visualization,static-analysis,python,javascript,rust,terraform,tree-sitter
39
+ Author: Christopher Garretty
40
+ Requires-Python: >=3.10
41
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
42
+ Project-URL: Homepage, https://github.com/serpentine-parser/serpentine
43
+ Project-URL: Issues, https://github.com/serpentine-parser/serpentine/issues
44
+ Project-URL: Repository, https://github.com/serpentine-parser/serpentine
45
+
1
46
  <p align="center">
2
47
  <img src="frontend/public/logo.svg" alt="Serpentine" width="64" />
3
48
  </p>
@@ -18,6 +63,7 @@ Serpentine builds a **code reference graph** for Python, JavaScript/TypeScript,
18
63
  - **Full reference resolution**: Traces calls, type annotations, assignments, and inheritance — not just import edges
19
64
  - **Interactive graph**: Expandable nodes, search, pan/zoom, collapsible modules
20
65
  - **Real-time updates**: File watcher pushes changes via WebSocket
66
+ - **VCS integration**: Compare any two git refs and see added, modified, and deleted nodes highlighted on the graph
21
67
  - **Agent-ready CLI**: Structured JSON output with selectors for use in AI agent workflows
22
68
 
23
69
  ### What counts as a code reference?
@@ -307,6 +353,52 @@ Each edge has a `from` and `to` field with node IDs, and a `type` field:
307
353
 
308
354
  ---
309
355
 
356
+ ## VCS Integration
357
+
358
+ When Serpentine is run inside a git repository, it automatically detects available refs (branches, tags, and recent commits) and enables the **compare** toolbar in the UI.
359
+
360
+ ### Comparing refs
361
+
362
+ Click the compare toolbar to select a baseline ref and a target ref. Serpentine analyzes the graph at each ref and overlays change status on every node:
363
+
364
+ | Status | Meaning |
365
+ |---|---|
366
+ | `modified` | Node exists in both refs but its dependencies changed |
367
+ | `added` | Node exists in the target ref but not the baseline |
368
+ | `deleted` | Node existed in the baseline ref but was removed |
369
+
370
+ Unchanged nodes remain visible for context.
371
+
372
+ ### Filtering by state
373
+
374
+ Use the `state:` selector method in the search bar to filter the graph to only changed nodes:
375
+
376
+ ```
377
+ state:modified
378
+ state:added
379
+ state:deleted
380
+ ```
381
+
382
+ Selectors compose with all graph operators:
383
+
384
+ ```
385
+ # All nodes modified on the current branch, plus their upstream dependencies
386
+ +state:modified
387
+
388
+ # Full connected component of every added node
389
+ @state:added
390
+ ```
391
+
392
+ ### Checkpoints
393
+
394
+ The **checkpoint** button marks the current live graph state as the comparison baseline. This is useful when you want to track changes made during a session rather than comparing against a git ref.
395
+
396
+ ### Configuration
397
+
398
+ Files excluded via `.serpentine.yml` (`exclude_dirs`, `exclude_patterns`) are excluded from VCS snapshot analysis as well — ensuring consistent results between live analysis and historical comparison.
399
+
400
+ ---
401
+
310
402
  ## Configuration
311
403
 
312
404
  Serpentine looks for `.serpentine.yml` or `serpentine.yml` in the project root. All settings are optional.
@@ -448,3 +540,4 @@ These three events are the minimum required for the graph builder to resolve all
448
540
  ## License
449
541
 
450
542
  [Apache 2.0](LICENSE)
543
+
@@ -1,36 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: serpentine-parser
3
- Version: 0.3.2
4
- Classifier: Development Status :: 4 - Beta
5
- Classifier: Environment :: Console
6
- Classifier: Environment :: Web Environment
7
- Classifier: Intended Audience :: Developers
8
- Classifier: License :: OSI Approved :: Apache Software License
9
- Classifier: Operating System :: OS Independent
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Classifier: Programming Language :: Python :: 3.14
16
- Classifier: Programming Language :: Rust
17
- Classifier: Topic :: Software Development :: Quality Assurance
18
- Classifier: Topic :: Utilities
19
- Requires-Dist: watchdog>=6.0.0
20
- Requires-Dist: click>=8.1.0
21
- Requires-Dist: starlette>=0.38.0
22
- Requires-Dist: uvicorn[standard]>=0.30.0
23
- Requires-Dist: websockets>=12.0
24
- License-File: LICENSE
25
- Summary: Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, Rust, and Terraform projects
26
- Keywords: dependency-graph,visualization,static-analysis,python,javascript,rust,terraform,tree-sitter
27
- Author: Christopher Garretty
28
- Requires-Python: >=3.10
29
- Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
30
- Project-URL: Homepage, https://github.com/serpentine-parser/serpentine
31
- Project-URL: Issues, https://github.com/serpentine-parser/serpentine/issues
32
- Project-URL: Repository, https://github.com/serpentine-parser/serpentine
33
-
34
1
  <p align="center">
35
2
  <img src="frontend/public/logo.svg" alt="Serpentine" width="64" />
36
3
  </p>
@@ -51,6 +18,7 @@ Serpentine builds a **code reference graph** for Python, JavaScript/TypeScript,
51
18
  - **Full reference resolution**: Traces calls, type annotations, assignments, and inheritance — not just import edges
52
19
  - **Interactive graph**: Expandable nodes, search, pan/zoom, collapsible modules
53
20
  - **Real-time updates**: File watcher pushes changes via WebSocket
21
+ - **VCS integration**: Compare any two git refs and see added, modified, and deleted nodes highlighted on the graph
54
22
  - **Agent-ready CLI**: Structured JSON output with selectors for use in AI agent workflows
55
23
 
56
24
  ### What counts as a code reference?
@@ -340,6 +308,52 @@ Each edge has a `from` and `to` field with node IDs, and a `type` field:
340
308
 
341
309
  ---
342
310
 
311
+ ## VCS Integration
312
+
313
+ When Serpentine is run inside a git repository, it automatically detects available refs (branches, tags, and recent commits) and enables the **compare** toolbar in the UI.
314
+
315
+ ### Comparing refs
316
+
317
+ Click the compare toolbar to select a baseline ref and a target ref. Serpentine analyzes the graph at each ref and overlays change status on every node:
318
+
319
+ | Status | Meaning |
320
+ |---|---|
321
+ | `modified` | Node exists in both refs but its dependencies changed |
322
+ | `added` | Node exists in the target ref but not the baseline |
323
+ | `deleted` | Node existed in the baseline ref but was removed |
324
+
325
+ Unchanged nodes remain visible for context.
326
+
327
+ ### Filtering by state
328
+
329
+ Use the `state:` selector method in the search bar to filter the graph to only changed nodes:
330
+
331
+ ```
332
+ state:modified
333
+ state:added
334
+ state:deleted
335
+ ```
336
+
337
+ Selectors compose with all graph operators:
338
+
339
+ ```
340
+ # All nodes modified on the current branch, plus their upstream dependencies
341
+ +state:modified
342
+
343
+ # Full connected component of every added node
344
+ @state:added
345
+ ```
346
+
347
+ ### Checkpoints
348
+
349
+ The **checkpoint** button marks the current live graph state as the comparison baseline. This is useful when you want to track changes made during a session rather than comparing against a git ref.
350
+
351
+ ### Configuration
352
+
353
+ Files excluded via `.serpentine.yml` (`exclude_dirs`, `exclude_patterns`) are excluded from VCS snapshot analysis as well — ensuring consistent results between live analysis and historical comparison.
354
+
355
+ ---
356
+
343
357
  ## Configuration
344
358
 
345
359
  Serpentine looks for `.serpentine.yml` or `serpentine.yml` in the project root. All settings are optional.
@@ -481,4 +495,3 @@ These three events are the minimum required for the graph builder to resolve all
481
495
  ## License
482
496
 
483
497
  [Apache 2.0](LICENSE)
484
-
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "serpentine-parser"
3
- version = "0.3.2"
3
+ version = "0.5.0"
4
4
  description = "Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, Rust, and Terraform projects"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -30,11 +30,19 @@ classifiers = [
30
30
  dependencies = [
31
31
  "watchdog>=6.0.0",
32
32
  "click>=8.1.0",
33
- "starlette>=0.38.0",
33
+ "starlette>=1.3.1",
34
34
  "uvicorn[standard]>=0.30.0",
35
35
  "websockets>=12.0",
36
36
  ]
37
37
 
38
+ [project.optional-dependencies]
39
+ mcp = ["fastmcp>=2.0", "httpx>=0.27", "PyJWT[crypto]>=2.8"]
40
+ git = ["pygit2>=1.15"]
41
+ gcs = ["google-cloud-storage>=2.0"]
42
+ s3 = ["boto3>=1.34"]
43
+ hg = []
44
+ svn = []
45
+
38
46
  [project.urls]
39
47
  Homepage = "https://github.com/serpentine-parser/serpentine"
40
48
  Repository = "https://github.com/serpentine-parser/serpentine"
@@ -65,4 +73,5 @@ dev = [
65
73
  "maturin>=1.9.4",
66
74
  "pre-commit>=4.6.0",
67
75
  "pytest>=8.0.0",
76
+ "hypothesis>=6.0",
68
77
  ]
@@ -4,18 +4,18 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "aho-corasick"
7
- version = "1.1.4"
7
+ version = "1.1.5"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
- checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
9
+ checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
10
10
  dependencies = [
11
11
  "memchr",
12
12
  ]
13
13
 
14
14
  [[package]]
15
15
  name = "cc"
16
- version = "1.2.65"
16
+ version = "1.4.3"
17
17
  source = "registry+https://github.com/rust-lang/crates.io-index"
18
- checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
18
+ checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d"
19
19
  dependencies = [
20
20
  "find-msvc-tools",
21
21
  "shlex",
@@ -23,9 +23,9 @@ dependencies = [
23
23
 
24
24
  [[package]]
25
25
  name = "crossbeam-deque"
26
- version = "0.8.6"
26
+ version = "0.8.7"
27
27
  source = "registry+https://github.com/rust-lang/crates.io-index"
28
- checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
28
+ checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
29
29
  dependencies = [
30
30
  "crossbeam-epoch",
31
31
  "crossbeam-utils",
@@ -33,24 +33,24 @@ dependencies = [
33
33
 
34
34
  [[package]]
35
35
  name = "crossbeam-epoch"
36
- version = "0.9.18"
36
+ version = "0.9.20"
37
37
  source = "registry+https://github.com/rust-lang/crates.io-index"
38
- checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
38
+ checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
39
39
  dependencies = [
40
40
  "crossbeam-utils",
41
41
  ]
42
42
 
43
43
  [[package]]
44
44
  name = "crossbeam-utils"
45
- version = "0.8.21"
45
+ version = "0.8.22"
46
46
  source = "registry+https://github.com/rust-lang/crates.io-index"
47
- checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
47
+ checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
48
48
 
49
49
  [[package]]
50
50
  name = "either"
51
- version = "1.16.0"
51
+ version = "1.17.0"
52
52
  source = "registry+https://github.com/rust-lang/crates.io-index"
53
- checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
53
+ checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
54
54
 
55
55
  [[package]]
56
56
  name = "equivalent"
@@ -60,9 +60,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
60
60
 
61
61
  [[package]]
62
62
  name = "find-msvc-tools"
63
- version = "0.1.9"
63
+ version = "0.1.11"
64
64
  source = "registry+https://github.com/rust-lang/crates.io-index"
65
- checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
65
+ checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
66
66
 
67
67
  [[package]]
68
68
  name = "hashbrown"
@@ -94,15 +94,15 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
94
94
 
95
95
  [[package]]
96
96
  name = "libc"
97
- version = "0.2.186"
97
+ version = "0.2.189"
98
98
  source = "registry+https://github.com/rust-lang/crates.io-index"
99
- checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
99
+ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
100
100
 
101
101
  [[package]]
102
102
  name = "memchr"
103
- version = "2.8.2"
103
+ version = "2.8.3"
104
104
  source = "registry+https://github.com/rust-lang/crates.io-index"
105
- checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
105
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
106
106
 
107
107
  [[package]]
108
108
  name = "once_cell"
@@ -112,24 +112,24 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
112
112
 
113
113
  [[package]]
114
114
  name = "portable-atomic"
115
- version = "1.13.1"
115
+ version = "1.15.0"
116
116
  source = "registry+https://github.com/rust-lang/crates.io-index"
117
- checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
117
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
118
118
 
119
119
  [[package]]
120
120
  name = "proc-macro2"
121
- version = "1.0.106"
121
+ version = "1.0.107"
122
122
  source = "registry+https://github.com/rust-lang/crates.io-index"
123
- checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
123
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
124
124
  dependencies = [
125
125
  "unicode-ident",
126
126
  ]
127
127
 
128
128
  [[package]]
129
129
  name = "pyo3"
130
- version = "0.29.0"
130
+ version = "0.29.2"
131
131
  source = "registry+https://github.com/rust-lang/crates.io-index"
132
- checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
132
+ checksum = "4688ddedf473e32662b9b067670129a8afb8c18e351482c70d62ba4a88171e8b"
133
133
  dependencies = [
134
134
  "libc",
135
135
  "once_cell",
@@ -141,18 +141,18 @@ dependencies = [
141
141
 
142
142
  [[package]]
143
143
  name = "pyo3-build-config"
144
- version = "0.29.0"
144
+ version = "0.29.2"
145
145
  source = "registry+https://github.com/rust-lang/crates.io-index"
146
- checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
146
+ checksum = "f41027e41b4bd03f6e60f9f417fe24a6341a6bb744edd62b6f709f2a52ea30e9"
147
147
  dependencies = [
148
148
  "target-lexicon",
149
149
  ]
150
150
 
151
151
  [[package]]
152
152
  name = "pyo3-ffi"
153
- version = "0.29.0"
153
+ version = "0.29.2"
154
154
  source = "registry+https://github.com/rust-lang/crates.io-index"
155
- checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
155
+ checksum = "e591a95526fead067432c3b3a33fc74770b87b1e04e73671090d9c2055a2b327"
156
156
  dependencies = [
157
157
  "libc",
158
158
  "pyo3-build-config",
@@ -160,33 +160,33 @@ dependencies = [
160
160
 
161
161
  [[package]]
162
162
  name = "pyo3-macros"
163
- version = "0.29.0"
163
+ version = "0.29.2"
164
164
  source = "registry+https://github.com/rust-lang/crates.io-index"
165
- checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
165
+ checksum = "73225868fc1cd84eef2c3c230ddb91273bf1de46aeb8a4248da76d32a0924a1c"
166
166
  dependencies = [
167
167
  "proc-macro2",
168
168
  "pyo3-macros-backend",
169
169
  "quote",
170
- "syn",
170
+ "syn 2.0.119",
171
171
  ]
172
172
 
173
173
  [[package]]
174
174
  name = "pyo3-macros-backend"
175
- version = "0.29.0"
175
+ version = "0.29.2"
176
176
  source = "registry+https://github.com/rust-lang/crates.io-index"
177
- checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
177
+ checksum = "571575aa3749fa6216757dd47d2a3e7ef360f329a40f0666a9fbd14889024952"
178
178
  dependencies = [
179
179
  "heck",
180
180
  "proc-macro2",
181
181
  "quote",
182
- "syn",
182
+ "syn 2.0.119",
183
183
  ]
184
184
 
185
185
  [[package]]
186
186
  name = "quote"
187
- version = "1.0.45"
187
+ version = "1.0.47"
188
188
  source = "registry+https://github.com/rust-lang/crates.io-index"
189
- checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
189
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
190
190
  dependencies = [
191
191
  "proc-macro2",
192
192
  ]
@@ -213,9 +213,9 @@ dependencies = [
213
213
 
214
214
  [[package]]
215
215
  name = "regex"
216
- version = "1.12.4"
216
+ version = "1.13.1"
217
217
  source = "registry+https://github.com/rust-lang/crates.io-index"
218
- checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
218
+ checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
219
219
  dependencies = [
220
220
  "aho-corasick",
221
221
  "memchr",
@@ -225,9 +225,9 @@ dependencies = [
225
225
 
226
226
  [[package]]
227
227
  name = "regex-automata"
228
- version = "0.4.14"
228
+ version = "0.4.18"
229
229
  source = "registry+https://github.com/rust-lang/crates.io-index"
230
- checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
230
+ checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
231
231
  dependencies = [
232
232
  "aho-corasick",
233
233
  "memchr",
@@ -242,9 +242,9 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
242
242
 
243
243
  [[package]]
244
244
  name = "serde"
245
- version = "1.0.228"
245
+ version = "1.0.229"
246
246
  source = "registry+https://github.com/rust-lang/crates.io-index"
247
- checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
247
+ checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
248
248
  dependencies = [
249
249
  "serde_core",
250
250
  "serde_derive",
@@ -252,29 +252,29 @@ dependencies = [
252
252
 
253
253
  [[package]]
254
254
  name = "serde_core"
255
- version = "1.0.228"
255
+ version = "1.0.229"
256
256
  source = "registry+https://github.com/rust-lang/crates.io-index"
257
- checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
257
+ checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
258
258
  dependencies = [
259
259
  "serde_derive",
260
260
  ]
261
261
 
262
262
  [[package]]
263
263
  name = "serde_derive"
264
- version = "1.0.228"
264
+ version = "1.0.229"
265
265
  source = "registry+https://github.com/rust-lang/crates.io-index"
266
- checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
266
+ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
267
267
  dependencies = [
268
268
  "proc-macro2",
269
269
  "quote",
270
- "syn",
270
+ "syn 3.0.3",
271
271
  ]
272
272
 
273
273
  [[package]]
274
274
  name = "serde_json"
275
- version = "1.0.150"
275
+ version = "1.0.151"
276
276
  source = "registry+https://github.com/rust-lang/crates.io-index"
277
- checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
277
+ checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
278
278
  dependencies = [
279
279
  "indexmap",
280
280
  "itoa",
@@ -286,7 +286,7 @@ dependencies = [
286
286
 
287
287
  [[package]]
288
288
  name = "serpentine"
289
- version = "0.3.2"
289
+ version = "0.5.0"
290
290
  dependencies = [
291
291
  "indexmap",
292
292
  "pyo3",
@@ -315,9 +315,20 @@ checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
315
315
 
316
316
  [[package]]
317
317
  name = "syn"
318
- version = "2.0.118"
318
+ version = "2.0.119"
319
+ source = "registry+https://github.com/rust-lang/crates.io-index"
320
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
321
+ dependencies = [
322
+ "proc-macro2",
323
+ "quote",
324
+ "unicode-ident",
325
+ ]
326
+
327
+ [[package]]
328
+ name = "syn"
329
+ version = "3.0.3"
319
330
  source = "registry+https://github.com/rust-lang/crates.io-index"
320
- checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
331
+ checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
321
332
  dependencies = [
322
333
  "proc-macro2",
323
334
  "quote",
@@ -408,6 +419,6 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
408
419
 
409
420
  [[package]]
410
421
  name = "zmij"
411
- version = "1.0.21"
422
+ version = "1.0.23"
412
423
  source = "registry+https://github.com/rust-lang/crates.io-index"
413
- checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
424
+ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "serpentine"
3
- version = "0.3.2"
3
+ version = "0.5.0"
4
4
  edition = "2021"
5
5
  license = "Apache-2.0"
6
6
 
@@ -233,7 +233,11 @@ impl GraphBuilder {
233
233
  children.retain(|c| c != qualname.as_str());
234
234
  }
235
235
  }
236
- self.hierarchy_children.shift_remove(qualname.as_str());
236
+ // Do NOT shift_remove hierarchy_children[qualname] here — other files
237
+ // may have registered children under this qualname (e.g. test_package.app
238
+ // registered as a child of test_package even when test_package is owned by
239
+ // a different file). write_node_json guards on definitions.contains_key(child)
240
+ // so orphaned empty entries are harmless.
237
241
  // Invalidate the per-node JSON fragment cache entry
238
242
  self.node_json_cache.remove(qualname.as_str());
239
243
  // Mark the top-level subtree dirty so snapshot rebuilds it
@@ -22,7 +22,7 @@ Or programmatically:
22
22
  app = create_app(state)
23
23
  """
24
24
 
25
- __version__ = "0.3.2"
25
+ __version__ = "0.5.0"
26
26
 
27
27
  from serpentine.server import create_app
28
28
  from serpentine.state import GraphStateManager
@@ -0,0 +1,28 @@
1
+ """
2
+ Infrastructure adapters implementing domain protocols.
3
+ """
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from serpentine.services import SourceProvider # noqa: F401 — re-export for convenience
9
+
10
+
11
+ class DiskSourceProvider:
12
+ """Reads files from the local filesystem."""
13
+ def get_file(self, path: str) -> str | None:
14
+ try:
15
+ return Path(path).read_text(encoding="utf-8")
16
+ except OSError:
17
+ return None
18
+
19
+
20
+ class VcsSourceProvider:
21
+ """Reads files from a VCS backend at a specific ref."""
22
+ def __init__(self, backend: Any, ref: str) -> None:
23
+ self._backend = backend
24
+ self._ref = ref
25
+
26
+ def get_file(self, path: str) -> str | None:
27
+ content = self._backend.get_file_at(self._ref, path)
28
+ return content.decode("utf-8", errors="replace") if content else None