victor-coding 0.13.0__tar.gz → 0.15.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 (159) hide show
  1. {victor_coding-0.13.0 → victor_coding-0.15.0}/PKG-INFO +4 -4
  2. {victor_coding-0.13.0 → victor_coding-0.15.0}/pyproject.toml +14 -10
  3. victor_coding-0.15.0/tests/test_coding_handlers.py +147 -0
  4. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_coding_vertical_workflows.py +38 -0
  5. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_enhanced_integration.py +1 -1
  6. victor_coding-0.15.0/tests/test_personas.py +143 -0
  7. victor_coding-0.15.0/tests/test_protocol_providers.py +68 -0
  8. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/assistant.py +1 -1
  9. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/ccg_builder.py +202 -27
  10. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/embeddings/__init__.py +7 -5
  11. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/indexer.py +10 -3
  12. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase_analyzer.py +41 -686
  13. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/composed_chains.py +1 -113
  14. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/conversation_enhanced.py +17 -159
  15. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/escape_hatches.py +5 -141
  16. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/handlers.py +12 -50
  17. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/base.py +152 -3
  18. victor_coding-0.15.0/victor_coding/languages/plugins/_ecmascript.py +208 -0
  19. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/additional.py +35 -488
  20. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/cpp.py +23 -150
  21. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/go.py +15 -96
  22. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/java.py +1 -73
  23. victor_coding-0.15.0/victor_coding/languages/plugins/javascript.py +163 -0
  24. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/python.py +8 -114
  25. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/rust.py +28 -68
  26. victor_coding-0.15.0/victor_coding/languages/plugins/typescript.py +171 -0
  27. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/protocols.py +42 -47
  28. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/safety_enhanced.py +22 -158
  29. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/teams/personas.py +96 -349
  30. victor_coding-0.15.0/victor_coding/tools/code_executor_tool.py +552 -0
  31. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/tools/code_search_tool.py +0 -2
  32. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding.egg-info/PKG-INFO +4 -4
  33. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding.egg-info/SOURCES.txt +4 -16
  34. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding.egg-info/requires.txt +3 -3
  35. victor_coding-0.13.0/victor_coding/codebase/embeddings/base.py +0 -247
  36. victor_coding-0.13.0/victor_coding/codebase/embeddings/lancedb_provider.py +0 -418
  37. victor_coding-0.13.0/victor_coding/codebase/embeddings/models.py +0 -530
  38. victor_coding-0.13.0/victor_coding/codebase/embeddings/proximadb_provider.py +0 -615
  39. victor_coding-0.13.0/victor_coding/codebase/embeddings/registry.py +0 -140
  40. victor_coding-0.13.0/victor_coding/codebase/graph/protocol.py +0 -110
  41. victor_coding-0.13.0/victor_coding/completion/__init__.py +0 -119
  42. victor_coding-0.13.0/victor_coding/completion/manager.py +0 -511
  43. victor_coding-0.13.0/victor_coding/completion/protocol.py +0 -51
  44. victor_coding-0.13.0/victor_coding/completion/provider.py +0 -363
  45. victor_coding-0.13.0/victor_coding/completion/providers/__init__.py +0 -25
  46. victor_coding-0.13.0/victor_coding/completion/providers/ai.py +0 -409
  47. victor_coding-0.13.0/victor_coding/completion/providers/lsp.py +0 -313
  48. victor_coding-0.13.0/victor_coding/completion/providers/snippet.py +0 -532
  49. victor_coding-0.13.0/victor_coding/completion/registry.py +0 -305
  50. victor_coding-0.13.0/victor_coding/editing/editor.py +0 -598
  51. victor_coding-0.13.0/victor_coding/languages/plugins/javascript.py +0 -372
  52. victor_coding-0.13.0/victor_coding/languages/plugins/typescript.py +0 -378
  53. victor_coding-0.13.0/victor_coding/tools/code_executor_tool.py +0 -600
  54. {victor_coding-0.13.0 → victor_coding-0.15.0}/LICENSE +0 -0
  55. {victor_coding-0.13.0 → victor_coding-0.15.0}/README.md +0 -0
  56. {victor_coding-0.13.0 → victor_coding-0.15.0}/setup.cfg +0 -0
  57. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_api_router_provider.py +0 -0
  58. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_coding_capabilities.py +0 -0
  59. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_coding_vertical_rl.py +0 -0
  60. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_coding_vertical_teams.py +0 -0
  61. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_extension_cache.py +0 -0
  62. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_framework_lsp_adapter.py +0 -0
  63. {victor_coding-0.13.0 → victor_coding-0.15.0}/tests/test_graph_backend_marker.py +0 -0
  64. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/__init__.py +0 -0
  65. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/api/__init__.py +0 -0
  66. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/api/router_provider.py +0 -0
  67. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/capabilities.py +0 -0
  68. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/__init__.py +0 -0
  69. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/architecture_analyzer.py +0 -0
  70. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/chunker.py +0 -0
  71. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/embeddings/chunker.py +0 -0
  72. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/graph/__init__.py +0 -0
  73. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/graph/registry.py +0 -0
  74. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/ignore_patterns.py +0 -0
  75. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/query_expander.py +0 -0
  76. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/symbol_extractor.py +0 -0
  77. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/symbol_resolver.py +0 -0
  78. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/symbol_store.py +0 -0
  79. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_analysis.py +0 -0
  80. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_extractor.py +0 -0
  81. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_manager.py +0 -0
  82. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/tree_sitter_service.py +0 -0
  83. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/codebase/unified_extractor.py +0 -0
  84. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/compat/__init__.py +0 -0
  85. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/compat/settings.py +0 -0
  86. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/coverage/__init__.py +0 -0
  87. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/coverage/manager.py +0 -0
  88. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/coverage/parser.py +0 -0
  89. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/coverage/parsers/__init__.py +0 -0
  90. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/coverage/protocol.py +0 -0
  91. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/coverage/visualizer.py +0 -0
  92. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/docgen/__init__.py +0 -0
  93. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/docgen/formatter.py +0 -0
  94. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/docgen/manager.py +0 -0
  95. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/docgen/parser.py +0 -0
  96. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/docgen/protocol.py +0 -0
  97. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/editing/__init__.py +0 -0
  98. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/enrichment.py +0 -0
  99. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/__init__.py +0 -0
  100. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/manager.py +0 -0
  101. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/__init__.py +0 -0
  102. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/plugins/config.py +0 -0
  103. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/registry.py +0 -0
  104. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/languages/tiers.py +0 -0
  105. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/lsp/__init__.py +0 -0
  106. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/lsp/client.py +0 -0
  107. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/lsp/config.py +0 -0
  108. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/lsp/framework_adapter.py +0 -0
  109. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/lsp/manager.py +0 -0
  110. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/middleware.py +0 -0
  111. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/mode_config.py +0 -0
  112. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/native/__init__.py +0 -0
  113. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/__init__.py +0 -0
  114. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/factory.py +0 -0
  115. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/protocols.py +0 -0
  116. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/registry.py +0 -0
  117. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/service_provider.py +0 -0
  118. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/settings.py +0 -0
  119. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/performance/wrappers.py +0 -0
  120. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/plugin.py +0 -0
  121. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/prompts.py +0 -0
  122. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/__init__.py +0 -0
  123. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/analyzer.py +0 -0
  124. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/manager.py +0 -0
  125. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/protocol.py +0 -0
  126. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/__init__.py +0 -0
  127. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/base.py +0 -0
  128. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/extract.py +0 -0
  129. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/refactor/transforms/rename.py +0 -0
  130. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/review/__init__.py +0 -0
  131. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/review/analyzers.py +0 -0
  132. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/review/manager.py +0 -0
  133. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/review/protocol.py +0 -0
  134. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/review/rules.py +0 -0
  135. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/rl/__init__.py +0 -0
  136. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/rl/config.py +0 -0
  137. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/rl/hooks.py +0 -0
  138. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/safety.py +0 -0
  139. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/service_provider.py +0 -0
  140. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/skills.py +0 -0
  141. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/teams/__init__.py +0 -0
  142. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/teams/specs.py +0 -0
  143. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/testgen/__init__.py +0 -0
  144. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/testgen/analyzer.py +0 -0
  145. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/testgen/generator.py +0 -0
  146. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/testgen/manager.py +0 -0
  147. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/testgen/protocol.py +0 -0
  148. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/tool_dependencies.py +0 -0
  149. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/tools/__init__.py +0 -0
  150. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/tools/code_intelligence_tool.py +0 -0
  151. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/tools/graph_tool.py +0 -0
  152. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/workflows/__init__.py +0 -0
  153. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/workflows/bugfix.py +0 -0
  154. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/workflows/feature.py +0 -0
  155. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/workflows/provider.py +0 -0
  156. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding/workflows/review.py +0 -0
  157. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding.egg-info/dependency_links.txt +0 -0
  158. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding.egg-info/entry_points.txt +0 -0
  159. {victor_coding-0.13.0 → victor_coding-0.15.0}/victor_coding.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: victor-coding
3
- Version: 0.13.0
3
+ Version: 0.15.0
4
4
  Summary: Coding vertical for Victor AI - Software development, debugging, and code generation
5
5
  Author-email: Vijaykumar Singh <vijay@anvaiops.com>
6
6
  Maintainer-email: Vijaykumar Singh <vijay@anvaiops.com>
@@ -18,7 +18,7 @@ Classifier: Topic :: Software Development
18
18
  Requires-Python: >=3.12
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
- Requires-Dist: victor-contracts[yaml]<1.0,>=0.6.0
21
+ Requires-Dist: victor-contracts[yaml]<1.0,>=0.11.0
22
22
  Requires-Dist: victor-codegraph[treesitter]>=0.1.0
23
23
  Requires-Dist: defusedxml<1.0,>=0.7
24
24
  Provides-Extra: runtime
@@ -30,12 +30,12 @@ Provides-Extra: codegraph
30
30
  Requires-Dist: victor-codegraph<1.0,>=0.1.0; extra == "codegraph"
31
31
  Provides-Extra: dev
32
32
  Requires-Dist: numpy<2.6,>=1.24; extra == "dev"
33
- Requires-Dist: pytest>=8.0; extra == "dev"
33
+ Requires-Dist: pytest<9.2,>=8.0; extra == "dev"
34
34
  Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
35
35
  Requires-Dist: pytest-cov>=4.1; extra == "dev"
36
36
  Requires-Dist: pytest-xdist>=3.0; extra == "dev"
37
37
  Requires-Dist: pytest-benchmark>=5.0; extra == "dev"
38
- Requires-Dist: black==26.10.0; extra == "dev"
38
+ Requires-Dist: black==26.10.1; extra == "dev"
39
39
  Requires-Dist: ruff>=0.5; extra == "dev"
40
40
  Requires-Dist: mypy==2.4.0; extra == "dev"
41
41
  Provides-Extra: native-dev
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "victor-coding"
10
- version = "0.13.0"
10
+ version = "0.15.0"
11
11
  description = "Coding vertical for Victor AI - Software development, debugging, and code generation"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.12"
@@ -34,7 +34,7 @@ classifiers = [
34
34
  "Topic :: Software Development",
35
35
  ]
36
36
  dependencies = [
37
- "victor-contracts[yaml]>=0.6.0,<1.0", # Definition-layer contract for external verticals
37
+ "victor-contracts[yaml]>=0.11.0,<1.0", # Definition-layer contract for external verticals
38
38
  "victor-codegraph[treesitter]>=0.1.0", # Shared code->CPG chunker (ADR-014); [treesitter] supplies the grammars the delegation parses JS/Go/TS/Rust with
39
39
  "defusedxml>=0.7,<1.0", # XXE-hardened XML parsing for coverage reports
40
40
  ]
@@ -47,10 +47,10 @@ native = [
47
47
  # Compatibility extra. Build the separate distribution from ./native;
48
48
  # see native/README.md. Installing this empty extra does not build Rust.
49
49
  ]
50
- # ProximaDB embedding provider (optional backend).
51
- # Imported lazily with graceful ImportError fallback in
52
- # victor_coding/codebase/embeddings/proximadb_provider.py. Pin kept identical
53
- # to victor-ai's proximadb extra so the backend version stays aligned.
50
+ # ProximaDB embedding backend (optional). The provider lives in victor-ai
51
+ # (victor/storage/vector_stores/proximadb_provider.py) and is resolved through
52
+ # victor_contracts.embeddings_runtime; this pass-through extra keeps the pin
53
+ # identical to victor-ai's proximadb extra.
54
54
  proximadb = [
55
55
  "proximadb>=0.4.1,<0.5",
56
56
  ]
@@ -62,12 +62,12 @@ codegraph = [
62
62
  ]
63
63
  dev = [
64
64
  "numpy>=1.24,<2.6", # Synthetic embeddings in indexer tests
65
- "pytest>=8.0",
65
+ "pytest>=8.0,<9.2", # pytest 9.2 (2026-10-27) removed Function._nodeid, which pytest-benchmark reads in fixture setup (verticals CI _nodeid AttributeErrors)
66
66
  "pytest-asyncio>=0.23",
67
67
  "pytest-cov>=4.1",
68
68
  "pytest-xdist>=3.0",
69
69
  "pytest-benchmark>=5.0",
70
- "black==26.10.0",
70
+ "black==26.10.1",
71
71
  "ruff>=0.5",
72
72
  "mypy==2.4.0",
73
73
  ]
@@ -143,7 +143,7 @@ coding-compaction = "victor_coding.protocols:CodingCompactionProvider"
143
143
  [tool.setuptools.packages.find]
144
144
  # Auto-discover all `victor_coding*` subpackages. An explicit `packages` list
145
145
  # here previously omitted nested subpackages (languages.plugins,
146
- # codebase.embeddings, codebase.graph, compat, completion.providers,
146
+ # codebase.embeddings, codebase.graph, compat,
147
147
  # coverage.parsers, native, performance, refactor.transforms), which silently
148
148
  # broke the published wheel (ModuleNotFoundError) while editable installs
149
149
  # worked — because the whole source tree is on sys.path under `-e`.
@@ -158,6 +158,11 @@ target-version = [
158
158
  ]
159
159
 
160
160
  [tool.ruff]
161
+ extend-exclude = [
162
+ # Parser input corpus for the golden tests: data, not code. Editing it
163
+ # shifts the pinned line numbers.
164
+ "tests/codebase/goldens/samples",
165
+ ]
161
166
  line-length = 100
162
167
  target-version = "py312"
163
168
 
@@ -166,7 +171,6 @@ select = ["E", "W", "F", "B", "C4"]
166
171
  ignore = [
167
172
  "E501", # line too long (handled by formatter)
168
173
  "E402", # module level import not at top of file (sometimes necessary)
169
- "F401", # unused imports (often intentional re-exports)
170
174
  "F811", # redefined while unused (type imports shadowing runtime)
171
175
  "B007", # loop control variable not used within loop body
172
176
  "B008", # do not perform function calls in argument defaults
@@ -0,0 +1,147 @@
1
+ # Copyright 2026 Vijaykumar Singh <vijay@anvaiops.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Pre-move characterization for victor-coding compute handlers (dedup F5).
16
+
17
+ Pins the observable contract before the envelope is extracted to the shared
18
+ kernel: command construction, output-key handling, the two handlers' DIFFERENT
19
+ failure policies (code_validation always COMPLETED with all_passed inside the
20
+ output; test_runner FAILED when the suite fails), and registration semantics.
21
+ """
22
+
23
+ from typing import Any, Dict
24
+ from unittest.mock import AsyncMock, MagicMock
25
+
26
+ import pytest
27
+
28
+ from victor_contracts.testing import MockComputeNode, MockToolResult, MockWorkflowContext
29
+ from victor_coding.handlers import HANDLERS, CodeValidationHandler, TestRunnerHandler
30
+
31
+
32
+ def registry(result: MockToolResult) -> MagicMock:
33
+ r = MagicMock()
34
+ r.execute = AsyncMock(return_value=result)
35
+ return r
36
+
37
+
38
+ class TestCodeValidationHandler:
39
+ @pytest.mark.asyncio
40
+ async def test_lint_check_passes_through_shell_command(self):
41
+ reg = registry(MockToolResult(success=True, output="clean"))
42
+ ctx = MockWorkflowContext()
43
+ node = MockComputeNode(
44
+ node_id="v1",
45
+ input_mapping={"files": ["a.py"], "checks": ["lint"]},
46
+ output_key="validation",
47
+ )
48
+ result = await CodeValidationHandler()(node, ctx, reg)
49
+ cmd = reg.execute.call_args.kwargs["command"]
50
+ assert cmd == "ruff check a.py"
51
+ assert result.status.value == "completed"
52
+ assert ctx.get("validation")["all_passed"] is True
53
+ assert ctx.get("validation")["checks"]["lint"]["passed"] is True
54
+
55
+ @pytest.mark.asyncio
56
+ async def test_failed_check_still_completes_with_all_passed_false(self):
57
+ """code_validation's fail policy: COMPLETED status, failure in output."""
58
+ reg = registry(MockToolResult(success=False, error="E501"))
59
+ ctx = MockWorkflowContext()
60
+ node = MockComputeNode(node_id="v2", input_mapping={"files": ["b.py"], "checks": ["lint"]})
61
+ result = await CodeValidationHandler()(node, ctx, reg)
62
+ assert result.status.value == "completed"
63
+ assert ctx.get("v2")["all_passed"] is False
64
+
65
+ @pytest.mark.asyncio
66
+ async def test_unknown_check_passes_with_message(self):
67
+ reg = registry(MockToolResult(success=True))
68
+ node = MockComputeNode(
69
+ node_id="v3", input_mapping={"files": ["x.py"], "checks": ["nonexistent"]}
70
+ )
71
+ ctx = MockWorkflowContext()
72
+ result = await CodeValidationHandler()(node, ctx, reg)
73
+ assert result.status.value == "completed"
74
+ assert ctx.get("v3")["checks"]["nonexistent"]["passed"] is True
75
+
76
+ @pytest.mark.asyncio
77
+ async def test_exception_is_contained_per_check(self):
78
+ """Actual behavior: _run_check catches exceptions and reports them as
79
+ failed checks — the node still COMPLETES (no outer try/except)."""
80
+ reg = MagicMock()
81
+ reg.execute = AsyncMock(side_effect=RuntimeError("boom"))
82
+ node = MockComputeNode(node_id="v4", input_mapping={"files": ["c.py"]})
83
+ ctx = MockWorkflowContext()
84
+ result = await CodeValidationHandler()(node, ctx, reg)
85
+ assert result.status.value == "completed"
86
+ assert ctx.get("v4")["all_passed"] is False
87
+ assert "boom" in ctx.get("v4")["checks"]["lint"]["error"]
88
+
89
+
90
+ class TestTestRunnerHandler:
91
+ @pytest.mark.asyncio
92
+ async def test_pytest_command_with_coverage(self):
93
+ reg = registry(MockToolResult(success=True, output="3 passed"))
94
+ node = MockComputeNode(
95
+ node_id="t1",
96
+ input_mapping={"test_path": "tests/", "framework": "pytest", "coverage": True},
97
+ output_key="test_results",
98
+ )
99
+ ctx = MockWorkflowContext()
100
+ result = await TestRunnerHandler()(node, ctx, reg)
101
+ cmd = reg.execute.call_args.kwargs["command"]
102
+ assert cmd == "pytest tests/ -v --cov --cov-report=json"
103
+ assert result.status.value == "completed"
104
+ assert ctx.get("test_results")["passed"] is True
105
+
106
+ @pytest.mark.asyncio
107
+ async def test_failed_suite_fails_the_node(self):
108
+ """test_runner's fail policy: FAILED status on suite failure (unlike
109
+ code_validation — the kernel must parameterize this)."""
110
+ reg = registry(MockToolResult(success=False, output="1 failed"))
111
+ node = MockComputeNode(node_id="t2", input_mapping={"framework": "pytest"})
112
+ ctx = MockWorkflowContext()
113
+ result = await TestRunnerHandler()(node, ctx, reg)
114
+ assert result.status.value == "failed"
115
+
116
+ @pytest.mark.asyncio
117
+ async def test_unittest_framework_command(self):
118
+ reg = registry(MockToolResult(success=True))
119
+ node = MockComputeNode(node_id="t3", input_mapping={"framework": "unittest"})
120
+ ctx = MockWorkflowContext()
121
+ await TestRunnerHandler()(node, ctx, reg)
122
+ cmd = reg.execute.call_args.kwargs["command"]
123
+ assert cmd.startswith("python -m unittest discover")
124
+
125
+
126
+ class TestRegistration:
127
+ def test_handlers_table_and_registrar_signature(self):
128
+ assert set(HANDLERS) == {"code_validation", "test_runner"}
129
+ # The UI introspects this signature; the kernel must keep it.
130
+ import inspect
131
+
132
+ from victor_coding.handlers import register_handlers
133
+
134
+ params = inspect.signature(register_handlers).parameters
135
+ assert "registrar" in params
136
+
137
+ def test_register_via_explicit_registrar(self):
138
+ entries: Dict[str, Any] = {}
139
+
140
+ class Registrar:
141
+ def __call__(self, name: str, handler: Any) -> None:
142
+ entries[name] = handler
143
+
144
+ from victor_coding.handlers import register_handlers
145
+
146
+ register_handlers(Registrar())
147
+ assert set(entries) == set(HANDLERS)
@@ -285,3 +285,41 @@ class TestWorkflowIntegration:
285
285
  # Most agent nodes should have allowed_tools
286
286
  # (not all require it, but most do)
287
287
  pass # Just ensure no crashes
288
+
289
+
290
+ class TestSharedEscapeHatches:
291
+ """Generic hatches come from the framework registry, not a local copy."""
292
+
293
+ SHARED = {
294
+ "complexity_check": "condition",
295
+ "complexity_assessment": "condition",
296
+ "format_implementation_plan": "transform",
297
+ }
298
+
299
+ def test_provider_resolves_the_shared_hatches(self):
300
+ config = CodingWorkflowProvider()._get_config()
301
+ for name, kind in self.SHARED.items():
302
+ registry = (
303
+ config.condition_registry if kind == "condition" else config.transform_registry
304
+ )
305
+ assert name in registry, f"{name} missing from the coding workflow {kind}s"
306
+ assert callable(registry[name])
307
+
308
+ def test_refactor_workflow_still_routes_on_complexity(self):
309
+ """refactor.yaml branches on complexity_assessment."""
310
+ config = CodingWorkflowProvider()._get_config()
311
+ assess = config.condition_registry["complexity_assessment"]
312
+ assert assess({"files_affected": list(range(30))}) in {
313
+ "high",
314
+ "complex",
315
+ "medium",
316
+ "low",
317
+ "simple",
318
+ }
319
+
320
+ def test_not_redefined_locally(self):
321
+ import victor_coding.escape_hatches as local
322
+
323
+ for name in self.SHARED:
324
+ assert not hasattr(local, name), f"{name} copied back into victor_coding.escape_hatches"
325
+ assert not set(self.SHARED) & (set(local.CONDITIONS) | set(local.TRANSFORMS))
@@ -300,7 +300,7 @@ class TestEnhancedCodingConversationManager:
300
300
  manager = EnhancedCodingConversationManager()
301
301
 
302
302
  assert manager._conversation_coordinator is not None
303
- assert isinstance(manager._coding_context, CodingContext)
303
+ assert isinstance(manager.get_coding_context(), CodingContext)
304
304
 
305
305
  def test_add_message(self):
306
306
  """Test adding a message."""
@@ -0,0 +1,143 @@
1
+ # Copyright 2026 Vijaykumar Singh <vijay@anvaiops.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Pre-move characterization for victor-coding personas (dedup F6).
16
+
17
+ Coding was the only personas vertical with NO test file. These pin the
18
+ observable contract before the kernel extraction: inventory, trait
19
+ normalization, prompt hints, backstory shape, helper semantics, and explicit-provider
20
+ registration (registration tuples included). Import-time registration was
21
+ removed by FEP-0042.
22
+ """
23
+
24
+ from victor_contracts.testing.personas import (
25
+ assert_explicit_persona_registration,
26
+ assert_import_registers_no_personas,
27
+ )
28
+ from victor_coding.teams.personas import (
29
+ CODING_PERSONAS,
30
+ CodingPersonaTraits,
31
+ CommunicationStyle,
32
+ DecisionStyle,
33
+ apply_persona_to_spec,
34
+ get_persona,
35
+ get_persona_by_expertise,
36
+ get_personas_for_role,
37
+ list_personas,
38
+ )
39
+
40
+
41
+ class TestInventory:
42
+ def test_eight_personas_with_expected_ids(self):
43
+ assert set(CODING_PERSONAS) == {
44
+ "code_archaeologist",
45
+ "security_auditor",
46
+ "architect",
47
+ "refactoring_strategist",
48
+ "craftsman",
49
+ "debugger",
50
+ "quality_guardian",
51
+ "test_specialist",
52
+ }
53
+
54
+ def test_every_persona_complete(self):
55
+ for pid, persona in CODING_PERSONAS.items():
56
+ assert persona.name, pid
57
+ assert persona.role in ("researcher", "planner", "executor", "reviewer"), pid
58
+ assert persona.expertise, pid
59
+ assert persona.strengths, pid
60
+ assert persona.approach, pid
61
+
62
+
63
+ class TestTraits:
64
+ def test_trait_scales_normalized(self):
65
+ traits = CodingPersonaTraits(attention_to_detail=2.0, risk_tolerance=-1.0, verbosity=0.5)
66
+ # values are stored as given (no clamping in the dataclass)
67
+ assert traits.attention_to_detail == 2.0
68
+ assert traits.risk_tolerance == -1.0
69
+
70
+ def test_prompt_hints_composition(self):
71
+ traits = CodingPersonaTraits(
72
+ communication_style=CommunicationStyle.CONCISE,
73
+ decision_style=DecisionStyle.CONSERVATIVE,
74
+ attention_to_detail=0.9,
75
+ risk_tolerance=0.1,
76
+ )
77
+ hints = traits.to_prompt_hints()
78
+ assert "brief" in hints.lower()
79
+ assert "proven" in hints.lower()
80
+ assert "edge cases" in hints.lower()
81
+ assert "thorough testing" in hints.lower()
82
+
83
+ def test_framework_traits_mapping(self):
84
+ traits = CodingPersonaTraits(attention_to_detail=0.8, risk_tolerance=0.4, verbosity=0.6)
85
+ fw = traits.to_framework_traits(name="X", role="executor", description="d", strengths=["s"])
86
+ assert fw.risk_tolerance == 0.4
87
+ assert fw.verbosity == 0.6
88
+ # coding's mapping: creativity = 1 - attention_to_detail
89
+ assert abs(fw.creativity - 0.2) < 1e-9
90
+ assert fw.custom_traits["decision_style"]
91
+ assert fw.custom_traits["attention_to_detail"] == 0.8
92
+
93
+
94
+ class TestPersonaSemantics:
95
+ def test_get_expertise_list_merges_primary_and_secondary(self):
96
+ p = get_persona("architect")
97
+ lst = p.get_expertise_list()
98
+ assert lst
99
+ assert all(isinstance(e, str) for e in lst)
100
+
101
+ def test_generate_backstory_shape(self):
102
+ story = get_persona("debugger").generate_backstory()
103
+ assert story.startswith("You are ")
104
+ assert "Bug Hunter" in story
105
+ assert story.endswith(".")
106
+
107
+ def test_helpers(self):
108
+ assert set(list_personas()) == set(CODING_PERSONAS)
109
+ planners = get_personas_for_role("planner")
110
+ assert planners
111
+ assert all(p.role == "planner" for p in planners)
112
+ found = get_persona_by_expertise(CODING_PERSONAS["architect"].expertise[0])
113
+ assert found
114
+
115
+ def test_apply_persona_to_spec_merges(self):
116
+ from victor_contracts import TeamMemberSpec
117
+
118
+ spec = TeamMemberSpec(role="planner", goal="ship", name="a1")
119
+ out = apply_persona_to_spec(spec, "architect")
120
+ # documented contract: same object, enhanced in place
121
+ assert out is spec
122
+ assert getattr(spec, "expertise", None) or getattr(spec, "backstory", None)
123
+ # unknown persona: unchanged spec returned
124
+ spec2 = TeamMemberSpec(role="planner", goal="ship", name="a2")
125
+ assert apply_persona_to_spec(spec2, "no_such_persona") is spec2
126
+
127
+
128
+ class TestPersonaRegistration:
129
+ """FEP-0042: personas reach the host through ``get_personas()`` on activation;
130
+ nothing registers at import, and the explicit-provider helper still works."""
131
+
132
+ def test_teams_import_registers_nothing_and_emits_no_deprecation(self):
133
+ assert_import_registers_no_personas("victor_coding.teams", "victor_coding.teams.personas")
134
+
135
+ def test_explicit_provider_helper_registers_every_persona_without_warning(self):
136
+ from victor_coding.teams.personas import _register_personas_with_framework
137
+
138
+ calls = assert_explicit_persona_registration(
139
+ _register_personas_with_framework, CODING_PERSONAS, "coding"
140
+ )
141
+ debugger = next(c for c in calls if c["name"] == "debugger")
142
+ assert debugger["category"] == "execution"
143
+ assert debugger["tags"] == ["debugging", "troubleshooting", "root-cause"]
@@ -0,0 +1,68 @@
1
+ # Copyright 2026 Vijaykumar Singh <vijay@anvaiops.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Pre-move characterization for victor-coding protocol providers (dedup F3)."""
16
+
17
+ from victor_coding.protocols import (
18
+ CodingPromptProvider,
19
+ CodingSafetyProvider,
20
+ CodingToolProvider,
21
+ CodingToolSelectionStrategy,
22
+ CodingWorkflowProvider,
23
+ )
24
+
25
+
26
+ class TestCodingToolProvider:
27
+ def test_tool_list_contract(self):
28
+ tools = CodingToolProvider().get_tools()
29
+ assert len(tools) == len(set(tools)), "duplicate tools"
30
+ for expected in ("read", "write", "shell", "grep", "code_search"):
31
+ assert expected in tools
32
+
33
+ def test_selection_strategy_stage_and_fallback(self):
34
+ strategy = CodingToolSelectionStrategy()
35
+ assert "grep" in strategy.get_tools_for_stage("understand", "coding")
36
+ # stage map membership (order is nondeterministic — set-built)
37
+ assert set(strategy.get_tools_for_stage("implement", "coding")) == {
38
+ "write", "shell", "edit",
39
+ }
40
+ # coding's fallback is [] (plus any task-type enhancements) — NOT the
41
+ # devops [read, shell]; per-vertical fallback is kernel data.
42
+ assert strategy.get_tools_for_stage("unknown_stage", "any") == []
43
+
44
+
45
+ class TestCodingSafetyProvider:
46
+ def test_extension_backed_surface(self):
47
+ provider = CodingSafetyProvider()
48
+ # coding's provider is extension-backed (not the devops pattern shape)
49
+ assert isinstance(provider.get_extensions(), list)
50
+ assert isinstance(provider.get_bash_patterns(), list)
51
+ assert isinstance(provider.get_file_patterns(), list)
52
+ assert isinstance(provider.get_tool_restrictions(), dict)
53
+
54
+
55
+ class TestCodingPromptAndWorkflowProviders:
56
+ def test_prompt_sections(self):
57
+ sections = CodingPromptProvider().get_system_prompt_sections()
58
+ assert isinstance(sections, dict) and sections
59
+ assert isinstance(CodingPromptProvider().get_prompt_contributors(), list)
60
+
61
+ def test_workflow_registry(self):
62
+ provider = CodingWorkflowProvider()
63
+ names = provider.list_workflows()
64
+ assert names == list(provider.get_workflows().keys())
65
+ assert sorted(names) == sorted(set(names)), "duplicate workflow names"
66
+ for name in names:
67
+ assert provider.get_workflow(name) is not None
68
+ assert provider.get_workflow("no_such_workflow") is None
@@ -498,7 +498,7 @@ You have access to 45+ tools. Use them efficiently to accomplish tasks."""
498
498
  def _load_editor():
499
499
  import importlib
500
500
 
501
- mod = importlib.import_module("victor_coding.editing.editor")
501
+ mod = importlib.import_module("victor_coding.editing")
502
502
  return mod.FileEditor()
503
503
 
504
504
  registrations.append((EditorProtocol, create_lazy_capability_proxy(_load_editor)))