invar-tools 1.12.0__py3-none-any.whl → 1.15.0__py3-none-any.whl

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.
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Invar Custom Tools for Pi Coding Agent
3
+ *
4
+ * Wraps Invar CLI commands as Pi tools for better LLM integration.
5
+ * Installed via: invar init --pi
6
+ */
7
+
8
+ import { Type } from "@sinclair/typebox";
9
+ import type { CustomToolFactory } from "@mariozechner/pi-coding-agent";
10
+
11
+ const factory: CustomToolFactory = (pi) => {
12
+ // Helper to check if invar is available
13
+ async function checkInvarInstalled(): Promise<boolean> {
14
+ try {
15
+ const result = await pi.exec("which", ["invar"]);
16
+ return result.exitCode === 0;
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ // Helper to validate path/target parameters (defense-in-depth)
23
+ function isValidPath(p: string): boolean {
24
+ // Reject shell metacharacters (including newline injection) and path traversal
25
+ if (/[;&|`$"'\\<>\n\r\0]/.test(p)) {
26
+ return false;
27
+ }
28
+ if (p.includes('..')) {
29
+ return false;
30
+ }
31
+ return true;
32
+ }
33
+
34
+ return [
35
+ // =========================================================================
36
+ // invar_guard - Smart verification (static + doctests + symbolic)
37
+ // =========================================================================
38
+ {
39
+ name: "invar_guard",
40
+ label: "Invar Guard",
41
+ description: "Verify code quality with static analysis, doctests, CrossHair symbolic execution, and Hypothesis testing. Use this instead of pytest/crosshair. By default checks git-modified files; use --all for full project check.",
42
+ parameters: Type.Object({
43
+ changed: Type.Optional(Type.Boolean({
44
+ description: "Check only git-modified files (default: true)",
45
+ default: true,
46
+ })),
47
+ contracts_only: Type.Optional(Type.Boolean({
48
+ description: "Contract coverage check only (skip tests)",
49
+ default: false,
50
+ })),
51
+ coverage: Type.Optional(Type.Boolean({
52
+ description: "Collect branch coverage from doctest + hypothesis",
53
+ default: false,
54
+ })),
55
+ strict: Type.Optional(Type.Boolean({
56
+ description: "Treat warnings as errors",
57
+ default: false,
58
+ })),
59
+ }),
60
+ async execute(toolCallId, params, onUpdate, ctx, signal) {
61
+ const installed = await checkInvarInstalled();
62
+ if (!installed) {
63
+ throw new Error("Invar not installed. Run: pip install invar-tools");
64
+ }
65
+
66
+ const args = ["guard"];
67
+
68
+ // Default is --changed (check modified files)
69
+ if (params.changed === false) {
70
+ args.push("--all");
71
+ }
72
+
73
+ if (params.contracts_only) {
74
+ args.push("-c");
75
+ }
76
+ if (params.coverage) {
77
+ args.push("--coverage");
78
+ }
79
+ if (params.strict) {
80
+ args.push("--strict");
81
+ }
82
+
83
+ const result = await pi.exec("invar", args, { cwd: pi.cwd, signal });
84
+
85
+ if (result.killed) {
86
+ throw new Error("Guard verification was cancelled");
87
+ }
88
+
89
+ const output = result.stdout + result.stderr;
90
+
91
+ return {
92
+ content: [{ type: "text", text: output || "Guard completed" }],
93
+ details: {
94
+ exitCode: result.exitCode,
95
+ passed: result.exitCode === 0,
96
+ },
97
+ };
98
+ },
99
+ },
100
+
101
+ // =========================================================================
102
+ // invar_sig - Show function signatures and contracts
103
+ // =========================================================================
104
+ {
105
+ name: "invar_sig",
106
+ label: "Invar Sig",
107
+ description: "Show function signatures and contracts (@pre/@post). Use this INSTEAD of Read() when you want to understand file structure without reading full implementation.",
108
+ parameters: Type.Object({
109
+ target: Type.String({
110
+ description: "File path or file::symbol path (e.g., 'src/foo.py' or 'src/foo.py::MyClass')",
111
+ }),
112
+ }),
113
+ async execute(toolCallId, params, onUpdate, ctx, signal) {
114
+ const installed = await checkInvarInstalled();
115
+ if (!installed) {
116
+ throw new Error("Invar not installed. Run: pip install invar-tools");
117
+ }
118
+
119
+ if (!isValidPath(params.target)) {
120
+ throw new Error("Invalid target path: contains unsafe characters or path traversal");
121
+ }
122
+
123
+ const result = await pi.exec("invar", ["sig", params.target], {
124
+ cwd: pi.cwd,
125
+ signal,
126
+ });
127
+
128
+ if (result.killed) {
129
+ throw new Error("Sig command was cancelled");
130
+ }
131
+
132
+ if (result.exitCode !== 0) {
133
+ throw new Error(`Failed to get signatures: ${result.stderr}`);
134
+ }
135
+
136
+ return {
137
+ content: [{ type: "text", text: result.stdout }],
138
+ details: {
139
+ target: params.target,
140
+ },
141
+ };
142
+ },
143
+ },
144
+
145
+ // =========================================================================
146
+ // invar_map - Symbol map with reference counts
147
+ // =========================================================================
148
+ {
149
+ name: "invar_map",
150
+ label: "Invar Map",
151
+ description: "Symbol map with reference counts. Use this INSTEAD of Grep for 'def ' to find entry points and most-referenced symbols.",
152
+ parameters: Type.Object({
153
+ path: Type.Optional(Type.String({
154
+ description: "Project path (default: current directory)",
155
+ default: ".",
156
+ })),
157
+ top: Type.Optional(Type.Number({
158
+ description: "Show top N symbols by reference count",
159
+ default: 10,
160
+ })),
161
+ }),
162
+ async execute(toolCallId, params, onUpdate, ctx, signal) {
163
+ const installed = await checkInvarInstalled();
164
+ if (!installed) {
165
+ throw new Error("Invar not installed. Run: pip install invar-tools");
166
+ }
167
+
168
+ if (params.path && params.path !== "." && !isValidPath(params.path)) {
169
+ throw new Error("Invalid path: contains unsafe characters or path traversal");
170
+ }
171
+
172
+ const args = ["map"];
173
+
174
+ if (params.path && params.path !== ".") {
175
+ args.push(params.path);
176
+ }
177
+
178
+ if (params.top) {
179
+ args.push("--top", params.top.toString());
180
+ }
181
+
182
+ const result = await pi.exec("invar", args, {
183
+ cwd: pi.cwd,
184
+ signal,
185
+ });
186
+
187
+ if (result.killed) {
188
+ throw new Error("Map command was cancelled");
189
+ }
190
+
191
+ if (result.exitCode !== 0) {
192
+ throw new Error(`Failed to generate map: ${result.stderr}`);
193
+ }
194
+
195
+ return {
196
+ content: [{ type: "text", text: result.stdout }],
197
+ details: {
198
+ path: params.path || ".",
199
+ top: params.top || 10,
200
+ },
201
+ };
202
+ },
203
+ },
204
+ ];
205
+ };
206
+
207
+ export default factory;
@@ -1,9 +1,9 @@
1
1
  ## Commands (Python)
2
2
 
3
3
  ```bash
4
- invar guard # Full: static + doctests + CrossHair + Hypothesis
4
+ invar guard # Check git-modified files (fast, default)
5
+ invar guard --all # Check entire project (CI, release)
5
6
  invar guard --static # Static only (quick debug, ~0.5s)
6
- invar guard --changed # Modified files only
7
7
  invar guard --coverage # Collect branch coverage
8
8
  invar guard -c # Contract coverage only (DX-63)
9
9
  invar sig <file> # Show contracts + signatures
@@ -11,6 +11,9 @@ invar map --top 10 # Most-referenced symbols
11
11
  invar rules # List all rules with detection/hints (JSON)
12
12
  ```
13
13
 
14
+ **Default behavior**: Checks git-modified files for fast feedback during development.
15
+ Use `--all` for comprehensive checks before release.
16
+
14
17
  ## Configuration (Python)
15
18
 
16
19
  ```toml
@@ -2,15 +2,18 @@
2
2
 
3
3
  ```bash
4
4
  # Verification (Python CLI - works for TypeScript)
5
- invar guard # Full: tsc + eslint + vitest + ts-analyzer
5
+ invar guard # Check git-modified files (fast, default)
6
+ invar guard --all # Check entire project (CI, release)
6
7
  invar guard --json # Agent-friendly v2.0 JSON output
7
- invar guard --changed # Modified files only
8
8
 
9
9
  # Analysis
10
10
  invar sig <file> # Show function signatures
11
11
  invar map --top 10 # Most-referenced symbols
12
12
  ```
13
13
 
14
+ **Default behavior**: Checks git-modified files for fast feedback during development.
15
+ Use `--all` for comprehensive checks before release.
16
+
14
17
  ## Guard Output (v2.0 JSON)
15
18
 
16
19
  ```json