lvkit 0.1.0__tar.gz → 0.2.1__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 (168) hide show
  1. {lvkit-0.1.0 → lvkit-0.2.1}/PKG-INFO +35 -28
  2. {lvkit-0.1.0 → lvkit-0.2.1}/README.md +32 -27
  3. {lvkit-0.1.0 → lvkit-0.2.1}/pyproject.toml +5 -2
  4. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/cli.py +64 -40
  5. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/subvi.py +4 -2
  6. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/pipeline.py +12 -0
  7. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/primitive_resolver.py +33 -9
  8. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-convert/SKILL.md +5 -5
  9. lvkit-0.2.1/src/lvkit/skill_templates/lvkit-describe/SKILL.md +66 -0
  10. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-idiomatic/SKILL.md +0 -19
  11. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_project_store.py +13 -12
  12. lvkit-0.1.0/src/lvkit/skill_templates/lvkit-describe/SKILL.md +0 -108
  13. {lvkit-0.1.0 → lvkit-0.2.1}/.gitignore +0 -0
  14. {lvkit-0.1.0 → lvkit-0.2.1}/.pre-commit-config.yaml +0 -0
  15. {lvkit-0.1.0 → lvkit-0.2.1}/LICENSE +0 -0
  16. {lvkit-0.1.0 → lvkit-0.2.1}/scripts/analyze_vi.py +0 -0
  17. {lvkit-0.1.0 → lvkit-0.2.1}/scripts/generate_docs.py +0 -0
  18. {lvkit-0.1.0 → lvkit-0.2.1}/scripts/generate_driver_data.py +0 -0
  19. {lvkit-0.1.0 → lvkit-0.2.1}/scripts/generate_python.py +0 -0
  20. {lvkit-0.1.0 → lvkit-0.2.1}/scripts/populate_vilib.py +0 -0
  21. {lvkit-0.1.0 → lvkit-0.2.1}/scripts/sync_skills.sh +0 -0
  22. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/__init__.py +0 -0
  23. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/_data.py +0 -0
  24. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/README.md +0 -0
  25. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/__init__.py +0 -0
  26. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/ast_optimizer.py +0 -0
  27. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/ast_utils.py +0 -0
  28. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/builder.py +0 -0
  29. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/class_builder.py +0 -0
  30. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/condition_builder.py +0 -0
  31. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/context.py +0 -0
  32. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/dataflow.py +0 -0
  33. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/error_handler.py +0 -0
  34. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/expressions.py +0 -0
  35. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/fragment.py +0 -0
  36. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/function.py +0 -0
  37. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/imports.py +0 -0
  38. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/__init__.py +0 -0
  39. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/base.py +0 -0
  40. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/case.py +0 -0
  41. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/compound.py +0 -0
  42. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/constant.py +0 -0
  43. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/invoke_node.py +0 -0
  44. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/loop.py +0 -0
  45. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/nmux.py +0 -0
  46. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/primitive.py +0 -0
  47. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/printf.py +0 -0
  48. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/property_node.py +0 -0
  49. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/sequence.py +0 -0
  50. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/stubs.py +0 -0
  51. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/unresolved.py +0 -0
  52. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/_index.json +0 -0
  53. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/daqmx.json +0 -0
  54. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nidcpower.json +0 -0
  55. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nidigital.json +0 -0
  56. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nidmm.json +0 -0
  57. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nifgen.json +0 -0
  58. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/niscope.json +0 -0
  59. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/niswitch.json +0 -0
  60. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/serial.json +0 -0
  61. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/visa.json +0 -0
  62. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/labview_error_codes.json +0 -0
  63. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/_index.json +0 -0
  64. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/array.json +0 -0
  65. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/file.json +0 -0
  66. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/string.json +0 -0
  67. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/time.json +0 -0
  68. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/variant.json +0 -0
  69. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/primitives-from-pdf.json +0 -0
  70. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/primitives.json +0 -0
  71. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/_index.json +0 -0
  72. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/_pending_terminals.json +0 -0
  73. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/_types.json +0 -0
  74. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/application-control.json +0 -0
  75. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/array.json +0 -0
  76. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/boolean.json +0 -0
  77. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/cluster.json +0 -0
  78. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/comparison.json +0 -0
  79. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/error-handling.json +0 -0
  80. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/file-io.json +0 -0
  81. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/numeric.json +0 -0
  82. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/other.json +0 -0
  83. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/string.json +0 -0
  84. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/structures.json +0 -0
  85. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/variant.json +0 -0
  86. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/__init__.py +0 -0
  87. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/generate.py +0 -0
  88. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/html_generator.py +0 -0
  89. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/template.css +0 -0
  90. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/utils.py +0 -0
  91. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/extractor.py +0 -0
  92. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/__init__.py +0 -0
  93. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/analysis.py +0 -0
  94. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/construction.py +0 -0
  95. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/core.py +0 -0
  96. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/describe.py +0 -0
  97. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/diff.py +0 -0
  98. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/flowchart.py +0 -0
  99. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/loading.py +0 -0
  100. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/models.py +0 -0
  101. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/operations.py +0 -0
  102. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/queries.py +0 -0
  103. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/labview_error.py +0 -0
  104. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/labview_error_codes.py +0 -0
  105. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/__init__.py +0 -0
  106. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/schemas.py +0 -0
  107. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/server.py +0 -0
  108. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/tools.py +0 -0
  109. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/models.py +0 -0
  110. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/__init__.py +0 -0
  111. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/constants.py +0 -0
  112. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/defaults.py +0 -0
  113. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/flags.py +0 -0
  114. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/front_panel.py +0 -0
  115. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/metadata.py +0 -0
  116. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/models.py +0 -0
  117. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/naming.py +0 -0
  118. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/node_types.py +0 -0
  119. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/__init__.py +0 -0
  120. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/base.py +0 -0
  121. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/case.py +0 -0
  122. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/constant.py +0 -0
  123. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/loop.py +0 -0
  124. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/sequence.py +0 -0
  125. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/type_mapping.py +0 -0
  126. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/type_resolution.py +0 -0
  127. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/utils.py +0 -0
  128. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/vi.py +0 -0
  129. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/project_store.py +0 -0
  130. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/py.typed +0 -0
  131. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/__init__.py +0 -0
  132. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-resolve-primitive/SKILL.md +0 -0
  133. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-resolve-vilib/SKILL.md +0 -0
  134. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/structure.py +0 -0
  135. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/terminal_collector.py +0 -0
  136. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/type_defaults.py +0 -0
  137. {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/vilib_resolver.py +0 -0
  138. {lvkit-0.1.0 → lvkit-0.2.1}/tests/__init__.py +0 -0
  139. {lvkit-0.1.0 → lvkit-0.2.1}/tests/conftest.py +0 -0
  140. {lvkit-0.1.0 → lvkit-0.2.1}/tests/helpers.py +0 -0
  141. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_ast_builder.py +0 -0
  142. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_ast_optimizer.py +0 -0
  143. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_case_parser.py +0 -0
  144. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_codegen_context.py +0 -0
  145. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_compound_codegen.py +0 -0
  146. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_condition_builder.py +0 -0
  147. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_constant_decoding.py +0 -0
  148. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_diff.py +0 -0
  149. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_driver_codegen.py +0 -0
  150. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_dynamic_dispatch.py +0 -0
  151. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_e2e_codegen.py +0 -0
  152. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_error_codegen.py +0 -0
  153. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_error_handling.py +0 -0
  154. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_graceful_degradation.py +0 -0
  155. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_loop_codegen.py +0 -0
  156. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_lvpy.py +0 -0
  157. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_naming.py +0 -0
  158. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_new_codegen.py +0 -0
  159. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_parallel_codegen.py +0 -0
  160. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_parser.py +0 -0
  161. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_parser_regression.py +0 -0
  162. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_sequence.py +0 -0
  163. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_soft_codegen.py +0 -0
  164. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_driven_fixes.py +0 -0
  165. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_fields.py +0 -0
  166. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_loading.py +0 -0
  167. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_mapping.py +0 -0
  168. {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_vi_graph.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lvkit
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: Understand and convert LabVIEW VIs to Python without a LabVIEW license
5
5
  Project-URL: Repository, https://github.com/pragmatest-dev/lvkit
6
6
  Project-URL: Issues, https://github.com/pragmatest-dev/lvkit/issues
@@ -28,6 +28,8 @@ Requires-Dist: mcp>=0.9.0
28
28
  Requires-Dist: networkx
29
29
  Requires-Dist: pydantic>=2.0.0
30
30
  Requires-Dist: pylabview
31
+ Provides-Extra: visualize
32
+ Requires-Dist: pyvis; extra == 'visualize'
31
33
  Description-Content-Type: text/markdown
32
34
 
33
35
  # lvkit
@@ -40,7 +42,6 @@ lvkit parses `.vi`, `.ctl`, `.lvclass`, and `.lvlib` files directly into queryab
40
42
 
41
43
  - [Quick Start](#quick-start)
42
44
  - [What you can do with it](#what-you-can-do-with-it)
43
- - [CLI Commands](#cli-commands)
44
45
  - [How it works](#how-it-works)
45
46
  - [AI and IDE integration](#ai-and-ide-integration)
46
47
  - [Cleanroom approach](#cleanroom-approach)
@@ -50,11 +51,29 @@ lvkit parses `.vi`, `.ctl`, `.lvclass`, and `.lvlib` files directly into queryab
50
51
 
51
52
  ```bash
52
53
  pip install lvkit
53
- lvkit init --skills all # create .lvkit/ + install Claude Code and Copilot skills
54
+ lvkit setup
54
55
  ```
55
56
 
56
- * Use `--skills claude` or `--skills copilot` to install for one AI agent only.
57
- * Use `lvkit init` alone if you don't want any AI agent skills installed.
57
+ For a global install: `pipx install lvkit` or `uv tool install lvkit`.
58
+
59
+ `lvkit setup` creates a `.lvkit/` resolution store and installs AI agent skills:
60
+
61
+ - Auto-detects Claude Code (`CLAUDE.md` / `.claude/`) and Copilot (`.github/copilot-instructions.md` / `.github/instructions/` / `.github/agents.md`)
62
+ - Pass `claude`, `copilot`, or `all` to be explicit
63
+ - Use `--no-skills` to create the `.lvkit/` store without installing any skills
64
+
65
+ | Command | Description |
66
+ |---------|-------------|
67
+ | `lvkit describe` | Human-readable VI description with signature and operations |
68
+ | `lvkit docs` | Generate cross-referenced HTML documentation |
69
+ | `lvkit diff` | Compare two VI versions — terminals, operations, wiring |
70
+ | `lvkit visualize` | Mermaid flowchart or interactive dependency graph |
71
+ | `lvkit generate` | Generate Python from a VI, library, or class (experimental — see [Cleanroom approach](#cleanroom-approach)) |
72
+ | `lvkit structure` | Inspect `.lvlib` or `.lvclass` structure |
73
+ | `lvkit setup` | Install AI agent skills; create `.lvkit/` resolution store |
74
+ | `lvkit mcp` | Start the MCP server for IDE integration |
75
+
76
+ `lvkit visualize --format interactive` requires `pip install lvkit[visualize]`. All other commands work on a bare `pip install lvkit`.
58
77
 
59
78
  ## What you can do with it
60
79
 
@@ -92,22 +111,7 @@ lvkit generate <input-path> -o <output-dir> [--search-path <libraries>] [--place
92
111
 
93
112
  `--placeholder-on-unresolved` lets the build succeed when mappings are missing — unresolved calls become inline `raise PrimitiveResolutionNeeded(...)` in the output so you can track them down at runtime.
94
113
 
95
- Coverage is incremental — see [Cleanroom approach](#cleanroom-approach) for what that means in practice.
96
-
97
- ## CLI Commands
98
-
99
- | Command | Description |
100
- |---------|-------------|
101
- | `lvkit describe` | Human-readable VI description with signature and operations |
102
- | `lvkit docs` | Generate cross-referenced HTML documentation |
103
- | `lvkit diff` | Compare two VI versions — terminals, operations, wiring |
104
- | `lvkit visualize` | Mermaid flowchart or interactive dependency graph |
105
- | `lvkit generate` | Generate Python from a VI, library, or class |
106
- | `lvkit structure` | Inspect `.lvlib` or `.lvclass` structure |
107
- | `lvkit init` | Create `.lvkit/` resolution store; install AI editor skills |
108
- | `lvkit mcp` | Start the MCP server for IDE integration |
109
-
110
- `lvkit visualize --format interactive` requires `pip install pyvis`. All other commands work on a bare `pip install lvkit`.
114
+ Coverage is incremental and results will vary — see [Cleanroom approach](#cleanroom-approach) for what that means in practice.
111
115
 
112
116
  ## How it works
113
117
 
@@ -125,17 +129,18 @@ See [`docs/graph-reference.md`](docs/graph-reference.md) for the full graph type
125
129
 
126
130
  The CLI works standalone from any terminal or CI script. For deeper IDE integration, lvkit ships two optional layers.
127
131
 
128
- **AI editor skills** — install lvkit's built-in workflows into Claude Code or Copilot so your AI can describe VIs, convert them, and resolve unknowns without you writing prompts. All five workflows call the CLI under the hood — no MCP server required.
132
+ **AI agent skills** — install lvkit's built-in workflows into Claude Code or Copilot so your AI agent can describe VIs, convert them, and resolve unknowns without you writing prompts. All five workflows call the CLI under the hood — no MCP server required.
129
133
 
130
134
  ```bash
131
- lvkit init --skills claude # installs .claude/skills/lvkit-*
132
- lvkit init --skills copilot # installs .github/prompts/ + router instruction
133
- lvkit init --skills all # both
135
+ lvkit setup # auto-detect from project layout
136
+ lvkit setup claude # installs .claude/skills/lvkit-*
137
+ lvkit setup copilot # installs .github/prompts/ + router instruction
138
+ lvkit setup all # both
134
139
  ```
135
140
 
136
141
  Five workflows ship: `lvkit-describe`, `lvkit-convert`, `lvkit-resolve-primitive`, `lvkit-resolve-vilib`, `lvkit-idiomatic`.
137
142
 
138
- **MCP server** — for interactive IDE sessions where your AI needs to load a graph, walk wires, and ask follow-up questions across multiple VIs:
143
+ **MCP server** — for interactive IDE sessions where your AI agent needs to load a graph, walk wires, and ask follow-up questions across multiple VIs:
139
144
 
140
145
  ```json
141
146
  {
@@ -168,11 +173,13 @@ Coverage is incremental. When `lvkit generate` encounters an unmapped primitive
168
173
 
169
174
  ### Project-local resolution store (`.lvkit/`)
170
175
 
171
- If you have a LabVIEW license, you can supplement the bundled mappings with a `.lvkit/` directory derived from your own install. lvkit reads `.lvkit/` first and falls back to its bundled data. The skills installed by `lvkit init` detect whether you're a lvkit maintainer or a downstream user and write mappings to the right destination.
176
+ You can supplement the bundled mappings with a `.lvkit/` directory in your project root. lvkit reads `.lvkit/` first and falls back to its bundled data.
177
+
178
+ Run `lvkit setup --no-skills` to create the store with a README that documents the file layout and JSON formats for adding primitive and vi.lib mappings manually.
172
179
 
173
180
  When `lvkit generate` hits an unknown, you have two options:
174
181
 
175
- 1. **Resolve up front** — install the resolve skills (`lvkit init --skills claude`) and let your AI editor write the mapping into `.lvkit/`.
182
+ 1. **Resolve up front** — run `lvkit setup` to install the resolve skills and let your AI agent write the mapping into `.lvkit/`.
176
183
  2. **Defer to runtime** — pass `--placeholder-on-unresolved`. lvkit emits an inline `raise PrimitiveResolutionNeeded(...)` in the generated Python with full diagnostic context. The build succeeds; runtime fails at the unresolved call.
177
184
 
178
185
  ## Development
@@ -8,7 +8,6 @@ lvkit parses `.vi`, `.ctl`, `.lvclass`, and `.lvlib` files directly into queryab
8
8
 
9
9
  - [Quick Start](#quick-start)
10
10
  - [What you can do with it](#what-you-can-do-with-it)
11
- - [CLI Commands](#cli-commands)
12
11
  - [How it works](#how-it-works)
13
12
  - [AI and IDE integration](#ai-and-ide-integration)
14
13
  - [Cleanroom approach](#cleanroom-approach)
@@ -18,11 +17,29 @@ lvkit parses `.vi`, `.ctl`, `.lvclass`, and `.lvlib` files directly into queryab
18
17
 
19
18
  ```bash
20
19
  pip install lvkit
21
- lvkit init --skills all # create .lvkit/ + install Claude Code and Copilot skills
20
+ lvkit setup
22
21
  ```
23
22
 
24
- * Use `--skills claude` or `--skills copilot` to install for one AI agent only.
25
- * Use `lvkit init` alone if you don't want any AI agent skills installed.
23
+ For a global install: `pipx install lvkit` or `uv tool install lvkit`.
24
+
25
+ `lvkit setup` creates a `.lvkit/` resolution store and installs AI agent skills:
26
+
27
+ - Auto-detects Claude Code (`CLAUDE.md` / `.claude/`) and Copilot (`.github/copilot-instructions.md` / `.github/instructions/` / `.github/agents.md`)
28
+ - Pass `claude`, `copilot`, or `all` to be explicit
29
+ - Use `--no-skills` to create the `.lvkit/` store without installing any skills
30
+
31
+ | Command | Description |
32
+ |---------|-------------|
33
+ | `lvkit describe` | Human-readable VI description with signature and operations |
34
+ | `lvkit docs` | Generate cross-referenced HTML documentation |
35
+ | `lvkit diff` | Compare two VI versions — terminals, operations, wiring |
36
+ | `lvkit visualize` | Mermaid flowchart or interactive dependency graph |
37
+ | `lvkit generate` | Generate Python from a VI, library, or class (experimental — see [Cleanroom approach](#cleanroom-approach)) |
38
+ | `lvkit structure` | Inspect `.lvlib` or `.lvclass` structure |
39
+ | `lvkit setup` | Install AI agent skills; create `.lvkit/` resolution store |
40
+ | `lvkit mcp` | Start the MCP server for IDE integration |
41
+
42
+ `lvkit visualize --format interactive` requires `pip install lvkit[visualize]`. All other commands work on a bare `pip install lvkit`.
26
43
 
27
44
  ## What you can do with it
28
45
 
@@ -60,22 +77,7 @@ lvkit generate <input-path> -o <output-dir> [--search-path <libraries>] [--place
60
77
 
61
78
  `--placeholder-on-unresolved` lets the build succeed when mappings are missing — unresolved calls become inline `raise PrimitiveResolutionNeeded(...)` in the output so you can track them down at runtime.
62
79
 
63
- Coverage is incremental — see [Cleanroom approach](#cleanroom-approach) for what that means in practice.
64
-
65
- ## CLI Commands
66
-
67
- | Command | Description |
68
- |---------|-------------|
69
- | `lvkit describe` | Human-readable VI description with signature and operations |
70
- | `lvkit docs` | Generate cross-referenced HTML documentation |
71
- | `lvkit diff` | Compare two VI versions — terminals, operations, wiring |
72
- | `lvkit visualize` | Mermaid flowchart or interactive dependency graph |
73
- | `lvkit generate` | Generate Python from a VI, library, or class |
74
- | `lvkit structure` | Inspect `.lvlib` or `.lvclass` structure |
75
- | `lvkit init` | Create `.lvkit/` resolution store; install AI editor skills |
76
- | `lvkit mcp` | Start the MCP server for IDE integration |
77
-
78
- `lvkit visualize --format interactive` requires `pip install pyvis`. All other commands work on a bare `pip install lvkit`.
80
+ Coverage is incremental and results will vary — see [Cleanroom approach](#cleanroom-approach) for what that means in practice.
79
81
 
80
82
  ## How it works
81
83
 
@@ -93,17 +95,18 @@ See [`docs/graph-reference.md`](docs/graph-reference.md) for the full graph type
93
95
 
94
96
  The CLI works standalone from any terminal or CI script. For deeper IDE integration, lvkit ships two optional layers.
95
97
 
96
- **AI editor skills** — install lvkit's built-in workflows into Claude Code or Copilot so your AI can describe VIs, convert them, and resolve unknowns without you writing prompts. All five workflows call the CLI under the hood — no MCP server required.
98
+ **AI agent skills** — install lvkit's built-in workflows into Claude Code or Copilot so your AI agent can describe VIs, convert them, and resolve unknowns without you writing prompts. All five workflows call the CLI under the hood — no MCP server required.
97
99
 
98
100
  ```bash
99
- lvkit init --skills claude # installs .claude/skills/lvkit-*
100
- lvkit init --skills copilot # installs .github/prompts/ + router instruction
101
- lvkit init --skills all # both
101
+ lvkit setup # auto-detect from project layout
102
+ lvkit setup claude # installs .claude/skills/lvkit-*
103
+ lvkit setup copilot # installs .github/prompts/ + router instruction
104
+ lvkit setup all # both
102
105
  ```
103
106
 
104
107
  Five workflows ship: `lvkit-describe`, `lvkit-convert`, `lvkit-resolve-primitive`, `lvkit-resolve-vilib`, `lvkit-idiomatic`.
105
108
 
106
- **MCP server** — for interactive IDE sessions where your AI needs to load a graph, walk wires, and ask follow-up questions across multiple VIs:
109
+ **MCP server** — for interactive IDE sessions where your AI agent needs to load a graph, walk wires, and ask follow-up questions across multiple VIs:
107
110
 
108
111
  ```json
109
112
  {
@@ -136,11 +139,13 @@ Coverage is incremental. When `lvkit generate` encounters an unmapped primitive
136
139
 
137
140
  ### Project-local resolution store (`.lvkit/`)
138
141
 
139
- If you have a LabVIEW license, you can supplement the bundled mappings with a `.lvkit/` directory derived from your own install. lvkit reads `.lvkit/` first and falls back to its bundled data. The skills installed by `lvkit init` detect whether you're a lvkit maintainer or a downstream user and write mappings to the right destination.
142
+ You can supplement the bundled mappings with a `.lvkit/` directory in your project root. lvkit reads `.lvkit/` first and falls back to its bundled data.
143
+
144
+ Run `lvkit setup --no-skills` to create the store with a README that documents the file layout and JSON formats for adding primitive and vi.lib mappings manually.
140
145
 
141
146
  When `lvkit generate` hits an unknown, you have two options:
142
147
 
143
- 1. **Resolve up front** — install the resolve skills (`lvkit init --skills claude`) and let your AI editor write the mapping into `.lvkit/`.
148
+ 1. **Resolve up front** — run `lvkit setup` to install the resolve skills and let your AI agent write the mapping into `.lvkit/`.
144
149
  2. **Defer to runtime** — pass `--placeholder-on-unresolved`. lvkit emits an inline `raise PrimitiveResolutionNeeded(...)` in the generated Python with full diagnostic context. The build succeeds; runtime fails at the unresolved call.
145
150
 
146
151
  ## Development
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "lvkit"
7
- version = "0.1.0"
7
+ version = "0.2.1"
8
8
  description = "Understand and convert LabVIEW VIs to Python without a LabVIEW license"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -45,6 +45,9 @@ dependencies = [
45
45
  "pydantic>=2.0.0",
46
46
  ]
47
47
 
48
+ [project.optional-dependencies]
49
+ visualize = ["pyvis"]
50
+
48
51
  [project.urls]
49
52
  Repository = "https://github.com/pragmatest-dev/lvkit"
50
53
  Issues = "https://github.com/pragmatest-dev/lvkit/issues"
@@ -64,7 +67,7 @@ dev = [
64
67
  [tool.hatch.build.targets.wheel]
65
68
  # Bundled JSON data and skill templates live INSIDE the package at
66
69
  # src/lvkit/data/ and src/lvkit/skill_templates/ so they ride along with
67
- # the wheel automatically. The resolvers and `lvkit init --skills` load
70
+ # the wheel automatically. The resolvers and `lvkit setup` load
68
71
  # them via paths relative to the package or via importlib.resources.
69
72
  packages = ["src/lvkit"]
70
73
 
@@ -249,30 +249,39 @@ def main() -> int:
249
249
  )
250
250
  _add_project_root_arg(diff_parser)
251
251
 
252
- # Init command - create .lvkit/ project store
253
- init_parser = subparsers.add_parser(
254
- "init",
255
- help="Initialize a project-local .lvkit/ resolution store",
252
+ # Setup command - install AI editor skills and create .lvkit/ store
253
+ setup_parser = subparsers.add_parser(
254
+ "setup",
255
+ help="Install AI editor skills and create project-local .lvkit/ store",
256
256
  )
257
- init_parser.add_argument(
257
+ setup_parser.add_argument(
258
258
  "directory",
259
259
  nargs="?",
260
260
  default=".",
261
261
  help="Directory in which to create .lvkit/ (default: current directory)",
262
262
  )
263
- init_parser.add_argument(
264
- "--skills",
263
+ setup_parser.add_argument(
264
+ "skills",
265
+ nargs="?",
265
266
  choices=["claude", "copilot", "all"],
266
267
  default=None,
267
268
  help=(
268
- "Also install lvkit's resolve workflows into your LLM editor: "
269
- "claude installs lvkit-prefixed Claude Code skills under "
270
- ".claude/skills/; copilot installs per-workflow prompts under "
271
- ".github/prompts/ plus a router at "
272
- ".github/instructions/lvkit.instructions.md; all does both."
269
+ "AI agent to install skills for: claude, copilot, or all. "
270
+ "Omit to auto-detect from project layout (CLAUDE.md / .claude/ "
271
+ "for Claude Code; .github/copilot-instructions.md / "
272
+ ".github/instructions/ / .github/agents.md for Copilot)."
273
273
  ),
274
274
  )
275
- init_parser.add_argument(
275
+ setup_parser.add_argument(
276
+ "--no-skills",
277
+ action="store_true",
278
+ help=(
279
+ "Create the .lvkit/ resolution store and README without installing "
280
+ "any AI editor skills. Use this if you want to add primitive or "
281
+ "vi.lib mappings manually."
282
+ ),
283
+ )
284
+ setup_parser.add_argument(
276
285
  "--force",
277
286
  action="store_true",
278
287
  help="Overwrite existing skill files even if they have local edits",
@@ -294,8 +303,8 @@ def main() -> int:
294
303
  return cmd_visualize(args)
295
304
  elif args.command == "diff":
296
305
  return cmd_diff(args)
297
- elif args.command == "init":
298
- return cmd_init(args)
306
+ elif args.command == "setup":
307
+ return cmd_setup(args)
299
308
  else:
300
309
  parser.print_help()
301
310
  return 0
@@ -397,7 +406,7 @@ def cmd_structure(args: argparse.Namespace) -> int:
397
406
  return 1
398
407
 
399
408
 
400
- def cmd_mcp(args: argparse.Namespace) -> int:
409
+ def cmd_mcp(_args: argparse.Namespace) -> int:
401
410
  """Handle the mcp command - run MCP server."""
402
411
  from .mcp.server import main as mcp_main
403
412
 
@@ -449,21 +458,52 @@ def cmd_describe(args: argparse.Namespace) -> int:
449
458
  return 1
450
459
 
451
460
 
452
- def cmd_init(args: argparse.Namespace) -> int:
453
- """Handle the init command create a project-local .lvkit/ store."""
461
+ def _detect_ai_editors(root: Path) -> list[str]:
462
+ """Detect which AI editors are configured in the project."""
463
+ editors = []
464
+ if (root / ".claude").is_dir() or (root / "CLAUDE.md").is_file():
465
+ editors.append("claude")
466
+ if (
467
+ (root / ".github" / "copilot-instructions.md").is_file()
468
+ or (root / ".github" / "instructions").is_dir()
469
+ or (root / ".github" / "agents.md").is_file()
470
+ ):
471
+ editors.append("copilot")
472
+ return editors
473
+
474
+
475
+ def cmd_setup(args: argparse.Namespace) -> int:
476
+ """Handle the setup command — install AI skills and create .lvkit/ store."""
454
477
  root = Path(args.directory).resolve()
455
478
  if not root.is_dir():
456
479
  print(f"Error: Not a directory: {root}", file=sys.stderr)
457
480
  return 1
458
481
 
459
482
  store = init_project_store(root)
460
- print(f"Initialized project store at {store}")
461
- print(f" README: {store / 'README.md'}")
483
+ print(f"Initialized .lvkit/ store at {store}")
484
+
485
+ if args.no_skills:
486
+ return 0
487
+
488
+ # Resolve which editors to install for
489
+ explicit = args.skills
490
+ if explicit == "all":
491
+ editors = ["claude", "copilot"]
492
+ elif explicit in ("claude", "copilot"):
493
+ editors = [explicit]
494
+ else:
495
+ # Auto-detect from project layout
496
+ editors = _detect_ai_editors(root)
497
+ if not editors:
498
+ print(
499
+ "No AI agent detected. If you add one later, run `lvkit setup` again. "
500
+ "If you have one that wasn't detected, run `lvkit setup claude` or "
501
+ "`lvkit setup copilot` to install skills explicitly."
502
+ )
503
+ return 0
462
504
 
463
- # Optional: install LLM editor skills
464
- skills = getattr(args, "skills", None)
465
505
  force = getattr(args, "force", False)
466
- if skills in ("claude", "all"):
506
+ if "claude" in editors:
467
507
  try:
468
508
  written = install_claude_skills(root, force=force)
469
509
  except FileExistsError as e:
@@ -475,7 +515,7 @@ def cmd_init(args: argparse.Namespace) -> int:
475
515
  print(f" {p}")
476
516
  else:
477
517
  print("Claude Code skills already up to date.")
478
- if skills in ("copilot", "all"):
518
+ if "copilot" in editors:
479
519
  try:
480
520
  copilot_written = install_copilot_skills(root, force=force)
481
521
  except FileExistsError as e:
@@ -488,22 +528,6 @@ def cmd_init(args: argparse.Namespace) -> int:
488
528
  else:
489
529
  print("Copilot files already up to date.")
490
530
 
491
- print()
492
- print("Next steps:")
493
- print(
494
- " - Create .lvkit/primitives.json to override primitive mappings"
495
- " (use lvkit's bundled primitives.json as a reference)"
496
- )
497
- print(
498
- " - Add vi.lib mappings to .lvkit/vilib/<category>.json and register them"
499
- " in .lvkit/vilib/_index.json"
500
- )
501
- print(" - lvkit will check .lvkit/ before its bundled data when resolving.")
502
- if not skills:
503
- print(
504
- " - Run `lvkit init --skills all` to install resolve workflows"
505
- " into Claude Code and/or Copilot."
506
- )
507
531
  return 0
508
532
 
509
533
 
@@ -34,7 +34,7 @@ def generate(node: SubVIOperation, ctx: CodeGenContext) -> CodeFragment:
34
34
  # Look up VI — polymorphic variant if selected, otherwise base name
35
35
  vilib_vi = None
36
36
  if node.poly_variant_name:
37
- vilib_vi = _resolve_poly_variant(subvi_name, node, ctx)
37
+ vilib_vi = _resolve_poly_variant(subvi_name, node)
38
38
  if not vilib_vi:
39
39
  # Variant not in JSON — fail or emit inline raise
40
40
  return _emit_vilib_resolution(node, ctx, vilib_vi=None)
@@ -236,7 +236,7 @@ def _generate_inline(
236
236
  )
237
237
 
238
238
  def _resolve_poly_variant(
239
- base_name: str, node: Operation, ctx: CodeGenContext
239
+ base_name: str, node: Operation
240
240
  ) -> VIEntry | None:
241
241
  """Resolve a polymorphic VI to its specific variant.
242
242
 
@@ -367,6 +367,7 @@ def _build_arguments(
367
367
  ),
368
368
  available=[],
369
369
  vi_name=ctx.vi_name if ctx else None,
370
+ kind="vilib" if vilib_vi is not None else "subvi",
370
371
  )
371
372
 
372
373
  # Check if this parameter is an enum typedef - generate enum reference
@@ -521,6 +522,7 @@ def _build_output_bindings(
521
522
  ),
522
523
  available=[],
523
524
  vi_name=ctx.vi_name if ctx else None,
525
+ kind="vilib" if vilib_vi is not None else "subvi",
524
526
  )
525
527
 
526
528
  bindings[term_id] = f"{result_var}.{field}"
@@ -20,6 +20,7 @@ from typing import Any
20
20
  from lvkit.codegen import ClassBuilder, ClassConfig, build_module
21
21
  from lvkit.codegen.ast_utils import to_function_name, to_module_name
22
22
  from lvkit.graph import InMemoryVIGraph
23
+ from lvkit.project_store import find_project_store
23
24
  from lvkit.structure import parse_lvclass
24
25
  from lvkit.terminal_collector import get_collector
25
26
  from lvkit.vilib_resolver import VILibResolver
@@ -661,6 +662,17 @@ def {func_name}(*args, **kwargs) -> Any:
661
662
  print(f" stub: {stub_count}")
662
663
  print(f" error: {error_count}")
663
664
 
665
+ if error_count > 0:
666
+ store = find_project_store()
667
+ if store:
668
+ print(f"\n To resolve errors, add mappings to {store}/")
669
+ print(f" See {store / 'README.md'} for file formats and instructions.")
670
+ print(" AI agent skills can add these automatically — run `lvkit setup` if not installed.")
671
+ else:
672
+ print("\n To resolve errors:")
673
+ print(" - Run `lvkit setup` to install AI agent skills that resolve unknowns automatically.")
674
+ print(" - Or run `lvkit setup --no-skills` to create a .lvkit/ store for manual mappings.")
675
+
664
676
  # Save terminal observations for incremental collection
665
677
  collector = get_collector()
666
678
  if collector.data.get("observations"):
@@ -75,7 +75,9 @@ class PrimitiveResolutionNeeded(Exception):
75
75
  class TerminalResolutionNeeded(Exception):
76
76
  """Raised when a specific wired terminal cannot be resolved to a known index.
77
77
 
78
- The primitive definition exists, but a terminal's index doesn't match.
78
+ kind="primitive": a built-in LabVIEW primitive with a missing terminal index
79
+ kind="vilib": a vilib VI with a missing terminal index in data/vilib/
80
+ kind="subvi": a user project VI whose terminal name could not be resolved
79
81
  """
80
82
 
81
83
  def __init__(
@@ -86,6 +88,7 @@ class TerminalResolutionNeeded(Exception):
86
88
  terminal_type: str | None,
87
89
  available: list[dict[str, str | int | None]],
88
90
  vi_name: str | None = None,
91
+ kind: str = "primitive",
89
92
  ):
90
93
  self.prim_id = str(prim_id)
91
94
  self.prim_name = prim_name
@@ -93,13 +96,20 @@ class TerminalResolutionNeeded(Exception):
93
96
  self.terminal_type = terminal_type
94
97
  self.available = available
95
98
  self.vi_name = vi_name
99
+ self.kind = kind
96
100
  super().__init__(self._format_message())
97
101
 
98
102
  def _format_message(self) -> str:
99
- msg = (
100
- f"Terminal resolution needed for primitive"
101
- f" {self.prim_id} ({self.prim_name}).\n"
102
- )
103
+ if self.kind == "vilib":
104
+ header = f"Terminal resolution needed for vilib VI '{self.prim_name}'."
105
+ elif self.kind == "subvi":
106
+ header = f"Terminal resolution needed for project VI '{self.prim_name}'."
107
+ else:
108
+ header = (
109
+ f"Terminal resolution needed for primitive"
110
+ f" {self.prim_id} ({self.prim_name})."
111
+ )
112
+ msg = header + "\n"
103
113
  if self.vi_name:
104
114
  msg += f" In VI: {self.vi_name}\n"
105
115
  msg += (
@@ -114,10 +124,24 @@ class TerminalResolutionNeeded(Exception):
114
124
  )
115
125
  if not self.available:
116
126
  msg += " (none available)\n"
117
- msg += (
118
- f"\n Fix: add/update terminal in data/primitives.json"
119
- f" under primitive {self.prim_id}"
120
- )
127
+ if self.kind == "vilib":
128
+ msg += (
129
+ f"\n Fix: add/update terminal index in"
130
+ f" .lvkit/data/vilib/<category>.json (project-local)"
131
+ f" or data/vilib/<category>.json (upstream)"
132
+ f" under VI '{self.prim_name}'"
133
+ )
134
+ elif self.kind == "subvi":
135
+ msg += (
136
+ f"\n Fix: ensure '{self.prim_name}' is reachable via --search-path"
137
+ f" and its terminal names are present in the VI's front panel"
138
+ )
139
+ else:
140
+ msg += (
141
+ f"\n Fix: add primitive {self.prim_id} to"
142
+ f" .lvkit/data/primitives.json (project-local)"
143
+ f" or data/primitives.json (upstream)"
144
+ )
121
145
  return msg
122
146
 
123
147
 
@@ -107,11 +107,11 @@ lvkit mcp # Start MCP server for IDE integration
107
107
  The MCP server (`lvkit mcp`) provides tools for interactive exploration:
108
108
 
109
109
  **Session:**
110
- - `load_vi` — Load VI into persistent graph
111
- - `list_loaded_vis` — List loaded VIs
110
+ - `load` — Load VI into persistent graph
111
+ - `list_loaded` — List loaded VIs
112
112
 
113
113
  **Exploration:**
114
- - `describe_vi` — Human-readable VI overview (signature, SubVIs, control flow)
114
+ - `describe` — Human-readable VI overview (signature, SubVIs, control flow)
115
115
  - `get_operations` — Execution order with nested structures
116
116
  - `get_dataflow` — Wire connections, optionally filtered by operation
117
117
  - `get_structure` — Case/loop/sequence details
@@ -120,11 +120,11 @@ The MCP server (`lvkit mcp`) provides tools for interactive exploration:
120
120
  **Generation:**
121
121
  - `generate_ast_code` — Deterministic Python from loaded VI
122
122
  - `generate_python` — Full pipeline: load + generate + write files
123
- - `get_vi_context` — Raw VI context as JSON
123
+ - `get_context` — Raw VI context as JSON
124
124
 
125
125
  **Documentation:**
126
126
  - `generate_documents` — Create HTML documentation
127
- - `analyze_vi` — Parse and return VI structure
127
+ - `analyze` — Parse and return VI structure
128
128
 
129
129
  ## Related Skills
130
130
 
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: lvkit-describe
3
+ description: Describe what a LabVIEW VI does — signature, operations, dataflow, structures, constants. Works via CLI or MCP.
4
+ allowed-tools: Bash, Read, Grep
5
+ ---
6
+
7
+ # Describe VI
8
+
9
+ Run `lvkit describe` on the VI:
10
+
11
+ ```bash
12
+ lvkit describe "<vi-path>" --search-path "<library-path>"
13
+ ```
14
+
15
+ Add `--chart` to also print a Mermaid flowchart:
16
+
17
+ ```bash
18
+ lvkit describe "<vi-path>" --search-path "<library-path>" --chart
19
+ ```
20
+
21
+ **Report to the user using this format:**
22
+
23
+ ```
24
+ # <VI name>
25
+
26
+ **What it does:** <1-2 sentence interpretation — purpose, key behavior, notable observations>
27
+
28
+ **Signature:** `<function signature>`
29
+
30
+ | Input | Type | Default |
31
+ |---|---|---|
32
+ | <name> | <type> | <default or —> |
33
+
34
+ | Output | Type |
35
+ |---|---|
36
+ | <name> | <type> |
37
+
38
+ **Control flow:** <brief description — frames, loops, cases>
39
+ <bulleted breakdown if the structure has meaningful steps>
40
+
41
+ | Constant | Type | Value |
42
+ |---|---|---|
43
+ | <inferred name or purpose> | <type> | <value> |
44
+
45
+ | Dependency | Description |
46
+ |---|---|
47
+ | <VI name> | <what it does> |
48
+
49
+ **Notable:** <surprising things, naming quirks, caveats — omit section if nothing to say>
50
+ ```
51
+
52
+ Rules:
53
+ - Omit any table that has no rows (e.g. no inputs → no inputs table)
54
+ - Collapse repeated dependencies: `DAQmx Write.vi ×3`
55
+ - Use judgment on Constants — infer purpose from context, omit trivial ones
56
+ - Interpretation leads; raw data follows
57
+
58
+ ## MCP alternative
59
+
60
+ If MCP tools are available, use them directly:
61
+
62
+ - `load` → `describe` → `get_operations` → `get_dataflow` → `get_structure` → `get_constants`
63
+
64
+ ## Note
65
+
66
+ `lvkit describe` never requires resolution to succeed. Unknown primitives and vi.lib VIs render as `[prim N]` / their bare name.