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.
- {lvkit-0.1.0 → lvkit-0.2.1}/PKG-INFO +35 -28
- {lvkit-0.1.0 → lvkit-0.2.1}/README.md +32 -27
- {lvkit-0.1.0 → lvkit-0.2.1}/pyproject.toml +5 -2
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/cli.py +64 -40
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/subvi.py +4 -2
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/pipeline.py +12 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/primitive_resolver.py +33 -9
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-convert/SKILL.md +5 -5
- lvkit-0.2.1/src/lvkit/skill_templates/lvkit-describe/SKILL.md +66 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-idiomatic/SKILL.md +0 -19
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_project_store.py +13 -12
- lvkit-0.1.0/src/lvkit/skill_templates/lvkit-describe/SKILL.md +0 -108
- {lvkit-0.1.0 → lvkit-0.2.1}/.gitignore +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/.pre-commit-config.yaml +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/LICENSE +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/scripts/analyze_vi.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/scripts/generate_docs.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/scripts/generate_driver_data.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/scripts/generate_python.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/scripts/populate_vilib.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/scripts/sync_skills.sh +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/_data.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/README.md +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/ast_optimizer.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/ast_utils.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/builder.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/class_builder.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/condition_builder.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/context.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/dataflow.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/error_handler.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/expressions.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/fragment.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/function.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/imports.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/base.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/case.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/compound.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/constant.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/invoke_node.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/loop.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/nmux.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/primitive.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/printf.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/property_node.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/nodes/sequence.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/stubs.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/codegen/unresolved.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/_index.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/daqmx.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nidcpower.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nidigital.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nidmm.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/nifgen.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/niscope.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/niswitch.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/serial.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/drivers/visa.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/labview_error_codes.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/_index.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/array.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/file.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/string.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/time.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/openg/variant.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/primitives-from-pdf.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/primitives.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/_index.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/_pending_terminals.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/_types.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/application-control.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/array.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/boolean.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/cluster.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/comparison.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/error-handling.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/file-io.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/numeric.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/other.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/string.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/structures.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/data/vilib/variant.json +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/generate.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/html_generator.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/template.css +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/docs/utils.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/extractor.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/analysis.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/construction.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/core.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/describe.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/diff.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/flowchart.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/loading.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/models.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/operations.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/graph/queries.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/labview_error.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/labview_error_codes.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/schemas.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/server.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/mcp/tools.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/models.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/constants.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/defaults.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/flags.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/front_panel.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/metadata.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/models.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/naming.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/node_types.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/base.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/case.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/constant.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/loop.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/nodes/sequence.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/type_mapping.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/type_resolution.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/utils.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/parser/vi.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/project_store.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/py.typed +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-resolve-primitive/SKILL.md +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/skill_templates/lvkit-resolve-vilib/SKILL.md +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/structure.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/terminal_collector.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/type_defaults.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/src/lvkit/vilib_resolver.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/__init__.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/conftest.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/helpers.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_ast_builder.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_ast_optimizer.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_case_parser.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_codegen_context.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_compound_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_condition_builder.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_constant_decoding.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_diff.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_driver_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_dynamic_dispatch.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_e2e_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_error_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_error_handling.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_graceful_degradation.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_loop_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_lvpy.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_naming.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_new_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_parallel_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_parser.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_parser_regression.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_sequence.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_soft_codegen.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_driven_fixes.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_fields.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_loading.py +0 -0
- {lvkit-0.1.0 → lvkit-0.2.1}/tests/test_type_mapping.py +0 -0
- {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
|
|
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
|
|
54
|
+
lvkit setup
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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
|
|
132
|
-
lvkit
|
|
133
|
-
lvkit
|
|
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
|
-
|
|
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
|
|
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
|
|
20
|
+
lvkit setup
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
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
|
|
100
|
-
lvkit
|
|
101
|
-
lvkit
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
#
|
|
253
|
-
|
|
254
|
-
"
|
|
255
|
-
help="
|
|
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
|
-
|
|
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
|
-
|
|
264
|
-
"
|
|
263
|
+
setup_parser.add_argument(
|
|
264
|
+
"skills",
|
|
265
|
+
nargs="?",
|
|
265
266
|
choices=["claude", "copilot", "all"],
|
|
266
267
|
default=None,
|
|
267
268
|
help=(
|
|
268
|
-
"
|
|
269
|
-
"
|
|
270
|
-
".
|
|
271
|
-
".github/
|
|
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
|
-
|
|
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 == "
|
|
298
|
-
return
|
|
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(
|
|
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
|
|
453
|
-
"""
|
|
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
|
|
461
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
f"Terminal resolution needed for
|
|
101
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
- `
|
|
111
|
-
- `
|
|
110
|
+
- `load` — Load VI into persistent graph
|
|
111
|
+
- `list_loaded` — List loaded VIs
|
|
112
112
|
|
|
113
113
|
**Exploration:**
|
|
114
|
-
- `
|
|
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
|
-
- `
|
|
123
|
+
- `get_context` — Raw VI context as JSON
|
|
124
124
|
|
|
125
125
|
**Documentation:**
|
|
126
126
|
- `generate_documents` — Create HTML documentation
|
|
127
|
-
- `
|
|
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.
|