invar-tools 1.6.0__py3-none-any.whl → 1.7.1__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.
invar/shell/templates.py CHANGED
@@ -76,11 +76,18 @@ def copy_template(
76
76
 
77
77
  # @shell_complexity: Config addition with existing file detection
78
78
  def add_config(path: Path, console) -> Result[bool, str]:
79
- """Add configuration to project. Returns Success(True) if added, Success(False) if skipped."""
79
+ """Add configuration to project. Returns Success(True) if added, Success(False) if skipped.
80
+
81
+ DX-70: Creates .invar/config.toml instead of invar.toml for cleaner organization.
82
+ Backward compatible: still reads from invar.toml if it exists.
83
+ """
80
84
  pyproject = path / "pyproject.toml"
81
- invar_toml = path / "invar.toml"
85
+ invar_dir = path / ".invar"
86
+ invar_config = invar_dir / "config.toml"
87
+ legacy_invar_toml = path / "invar.toml"
82
88
 
83
89
  try:
90
+ # Priority 1: Add to pyproject.toml if it exists
84
91
  if pyproject.exists():
85
92
  content = pyproject.read_text()
86
93
  if "[tool.invar]" not in content:
@@ -90,9 +97,15 @@ def add_config(path: Path, console) -> Result[bool, str]:
90
97
  return Success(True)
91
98
  return Success(False)
92
99
 
93
- if not invar_toml.exists():
94
- invar_toml.write_text(_DEFAULT_INVAR_TOML)
95
- console.print("[green]Created[/green] invar.toml")
100
+ # Skip if legacy invar.toml exists (backward compatibility)
101
+ if legacy_invar_toml.exists():
102
+ return Success(False)
103
+
104
+ # Create .invar/config.toml (DX-70: new default location)
105
+ if not invar_config.exists():
106
+ invar_dir.mkdir(exist_ok=True)
107
+ invar_config.write_text(_DEFAULT_INVAR_TOML)
108
+ console.print("[green]Created[/green] .invar/config.toml")
96
109
  return Success(True)
97
110
 
98
111
  return Success(False)
@@ -187,30 +200,17 @@ def copy_skills_directory(dest: Path, console) -> Result[bool, str]:
187
200
  return Failure(f"Failed to copy skills: {e}")
188
201
 
189
202
 
190
- # Agent configuration for multi-agent support (DX-11, DX-17)
203
+ # Agent configuration - Claude Code only (DX-69: simplified, cursor/aider removed)
191
204
  AGENT_CONFIGS = {
192
205
  "claude": {
193
206
  "file": "CLAUDE.md",
194
207
  "template": "CLAUDE.md.template",
195
- "reference": '> **Protocol:** Follow [INVAR.md](./INVAR.md) for the Invar development methodology.\n',
196
- "check_pattern": "INVAR.md",
197
- },
198
- "cursor": {
199
- "file": ".cursorrules",
200
- "template": "cursorrules.template",
201
- "reference": "Follow the Invar Protocol in INVAR.md.\n\n",
202
- "check_pattern": "INVAR.md",
203
- },
204
- "aider": {
205
- "file": ".aider.conf.yml",
206
- "template": "aider.conf.yml.template",
207
- "reference": "# Follow the Invar Protocol in INVAR.md\nread:\n - INVAR.md\n",
208
208
  "check_pattern": "INVAR.md",
209
209
  },
210
210
  }
211
211
 
212
212
 
213
- # @shell_complexity: Agent config detection across multiple locations
213
+ # @shell_complexity: Multi-agent config detection with file existence checks
214
214
  def detect_agent_configs(path: Path) -> Result[dict[str, str], str]:
215
215
  """
216
216
  Detect existing agent configuration files.
@@ -244,61 +244,6 @@ def detect_agent_configs(path: Path) -> Result[dict[str, str], str]:
244
244
  return Failure(f"Failed to detect agent configs: {e}")
245
245
 
246
246
 
247
- # @shell_complexity: Reference addition with existing check
248
- def add_invar_reference(path: Path, agent: str, console) -> Result[bool, str]:
249
- """Add Invar reference to an existing agent config file."""
250
- if agent not in AGENT_CONFIGS:
251
- return Failure(f"Unknown agent: {agent}")
252
-
253
- config = AGENT_CONFIGS[agent]
254
- config_path = path / config["file"]
255
-
256
- if not config_path.exists():
257
- return Failure(f"Config file not found: {config['file']}")
258
-
259
- try:
260
- content = config_path.read_text()
261
- if config["check_pattern"] in content:
262
- return Success(False) # Already configured
263
-
264
- # Prepend reference
265
- new_content = config["reference"] + content
266
- config_path.write_text(new_content)
267
- console.print(f"[green]Updated[/green] {config['file']} (added Invar reference)")
268
- return Success(True)
269
- except OSError as e:
270
- return Failure(f"Failed to update {config['file']}: {e}")
271
-
272
-
273
- # @shell_complexity: Config creation with template selection
274
- def create_agent_config(path: Path, agent: str, console) -> Result[bool, str]:
275
- """
276
- Create agent config from template (DX-17).
277
-
278
- Creates full template file for agents that don't have an existing config.
279
- """
280
- if agent not in AGENT_CONFIGS:
281
- return Failure(f"Unknown agent: {agent}")
282
-
283
- config = AGENT_CONFIGS[agent]
284
- config_path = path / config["file"]
285
-
286
- if config_path.exists():
287
- return Success(False) # Already exists
288
-
289
- # Use template if available
290
- template_name = config.get("template")
291
- if template_name:
292
- result = copy_template(template_name, path, config["file"])
293
- if isinstance(result, Success) and result.unwrap():
294
- console.print(f"[green]Created[/green] {config['file']} (Invar workflow enforcement)")
295
- return Success(True)
296
- elif isinstance(result, Failure):
297
- return result
298
-
299
- return Success(False)
300
-
301
-
302
247
  # @shell_complexity: MCP server config with JSON manipulation
303
248
  def configure_mcp_server(path: Path, console) -> Result[list[str], str]:
304
249
  """
@@ -461,36 +406,28 @@ The server communicates via stdio and should be managed by your AI agent.
461
406
 
462
407
  # @shell_complexity: Git hooks installation with backup
463
408
  def install_hooks(path: Path, console) -> Result[bool, str]:
464
- """Install pre-commit hooks configuration and activate them."""
409
+ """Run 'pre-commit install' if config exists (file created by sync_templates)."""
465
410
  import subprocess
466
411
 
467
412
  pre_commit_config = path / ".pre-commit-config.yaml"
468
413
 
469
- if pre_commit_config.exists():
470
- console.print("[yellow]Skipped[/yellow] .pre-commit-config.yaml (already exists)")
414
+ if not pre_commit_config.exists():
415
+ # File should be created by sync_templates; skip if missing
471
416
  return Success(False)
472
417
 
473
- result = copy_template("pre-commit-config.yaml.template", path, ".pre-commit-config.yaml")
474
- if isinstance(result, Failure):
475
- return result
476
-
477
- if result.unwrap():
478
- console.print("[green]Created[/green] .pre-commit-config.yaml")
479
-
480
- # Auto-install hooks (Automatic > Opt-in)
481
- try:
482
- subprocess.run(
483
- ["pre-commit", "install"],
484
- cwd=path,
485
- check=True,
486
- capture_output=True,
487
- )
488
- console.print("[green]Installed[/green] pre-commit hooks")
489
- except FileNotFoundError:
490
- console.print("[dim]Run: pre-commit install (pre-commit not in PATH)[/dim]")
491
- except subprocess.CalledProcessError:
492
- console.print("[dim]Run: pre-commit install (not a git repo?)[/dim]")
493
-
418
+ # Auto-install hooks (Automatic > Opt-in)
419
+ try:
420
+ subprocess.run(
421
+ ["pre-commit", "install"],
422
+ cwd=path,
423
+ check=True,
424
+ capture_output=True,
425
+ )
426
+ console.print("[green]Installed[/green] pre-commit hooks")
494
427
  return Success(True)
428
+ except FileNotFoundError:
429
+ console.print("[dim]Run: pre-commit install (pre-commit not in PATH)[/dim]")
430
+ except subprocess.CalledProcessError:
431
+ console.print("[dim]Run: pre-commit install (not a git repo?)[/dim]")
495
432
 
496
433
  return Success(False)
@@ -1,3 +1,9 @@
1
+ ---
2
+ _invar:
3
+ version: "5.0"
4
+ type: command
5
+ ---
6
+
1
7
  # Audit
2
8
 
3
9
  Read-only code review. Reports issues without fixing them.
@@ -1,3 +1,9 @@
1
+ ---
2
+ _invar:
3
+ version: "5.0"
4
+ type: command
5
+ ---
6
+
1
7
  # Guard
2
8
 
3
9
  Run Invar verification on the project and report results.
@@ -1,3 +1,4 @@
1
+ # invar:begin
1
2
  # Invar Pre-commit Hooks v{{ version }}
2
3
  # Install: pre-commit install
3
4
  #
@@ -42,3 +43,4 @@ repos:
42
43
  pass_filenames: false
43
44
  stages: [pre-commit]
44
45
  types: [python]
46
+ # invar:end
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: invar-tools
3
- Version: 1.6.0
3
+ Version: 1.7.1
4
4
  Summary: AI-native software engineering tools with design-by-contract verification
5
5
  Project-URL: Homepage, https://github.com/tefx/invar
6
6
  Project-URL: Documentation, https://github.com/tefx/invar#readme
@@ -28,6 +28,7 @@ Requires-Dist: jinja2>=3.0
28
28
  Requires-Dist: mcp>=1.0
29
29
  Requires-Dist: pre-commit>=3.0
30
30
  Requires-Dist: pydantic>=2.0
31
+ Requires-Dist: questionary>=2.0
31
32
  Requires-Dist: returns>=0.20
32
33
  Requires-Dist: rich>=13.0
33
34
  Requires-Dist: typer>=0.9
@@ -129,35 +130,24 @@ Guard passed.
129
130
 
130
131
  **Why uvx?** Always uses latest version, doesn't pollute project dependencies, auto-detects your project's venv.
131
132
 
132
- ### 🆕 New Project
133
+ ### 🎯 Setup
133
134
 
134
135
  ```bash
135
- # 1. Enter your project directory
136
136
  cd your-project
137
137
 
138
- # 2. Initialize with Claude Code (full experience)
138
+ # Interactive mode - choose what to install
139
+ uvx invar-tools init
140
+
141
+ # Or quick setup for Claude Code (skip prompts)
139
142
  uvx invar-tools init --claude
140
143
 
141
- # 3. Add runtime contracts to your project
144
+ # Add runtime contracts to your project
142
145
  pip install invar-runtime
143
- # Or add to pyproject.toml: dependencies = ["invar-runtime"]
144
-
145
- # 4. Start coding with AI
146
146
  ```
147
147
 
148
- ### 📁 Existing Project
149
-
150
- ```bash
151
- cd your-project
152
-
153
- # Update managed files, preserve your customizations
154
- uvx invar-tools init --claude
155
-
156
- # Or without Claude Code integration
157
- uvx invar-tools init
158
- ```
148
+ **Safe and idempotent** — Run `invar init` anytime. It always **merges** with existing files, preserving your content.
159
149
 
160
- Invar's init is idempotent—safe to run multiple times. It detects existing configuration and updates only managed regions.
150
+ > 💡 **After `claude /init`?** Just run `invar init` again to restore Invar configuration.
161
151
 
162
152
  ### 💬 Example Interaction
163
153
 
@@ -375,39 +365,57 @@ AlphaCodium · Parsel · Reflexion · Clover
375
365
 
376
366
  ---
377
367
 
378
- ## 🖥️ Platform Experience
368
+ ## 🖥️ Agent Support
369
+
370
+ | Agent | Status | Setup |
371
+ |-------|--------|-------|
372
+ | **Claude Code** | ✅ Full | `invar init` → select Claude Code |
373
+ | **Pi / Cursor** | 🚧 In progress | `invar init` → select Other, include `AGENT.md` in prompt |
374
+ | **Other** | 📝 Manual | `invar init` → select Other, include `AGENT.md` in prompt |
379
375
 
380
- | Feature | Claude Code | Other Editors |
381
- |---------|-------------|---------------|
382
- | CLI verification (`invar guard`) | ✅ | ✅ |
383
- | Protocol document (INVAR.md) | ✅ | ✅ |
384
- | MCP tool integration | ✅ Auto-configured | Manual setup possible |
385
- | Workflow skills | ✅ Auto-configured | Include in system prompt |
386
- | Pre-commit hooks | ✅ | ✅ |
387
- | Sub-agent review | ✅ | — |
376
+ ### Claude Code (Full Experience)
388
377
 
389
- **Claude Code** provides the full experience—MCP tools, skill routing, and hooks are auto-configured by `invar init --claude`.
378
+ All features auto-configured:
379
+ - MCP tools (`invar_guard`, `invar_sig`, `invar_map`)
380
+ - Workflow skills (`/develop`, `/review`, `/investigate`, `/propose`)
381
+ - Claude Code hooks (tool guidance, verification reminders)
382
+ - Pre-commit hooks
390
383
 
391
- **Other editors** can achieve similar results by:
392
- 1. Adding INVAR.md content to system prompts
393
- 2. Manually configuring MCP servers (if supported)
394
- 3. Using CLI commands for verification
384
+ ### Pi / Cursor (In Progress)
385
+
386
+ Currently available:
387
+ - Protocol document (INVAR.md)
388
+ - CLI verification (`invar guard`)
389
+ - Pre-commit hooks
390
+ - MCP server (manual configuration)
391
+
392
+ ### Other Editors (Manual)
393
+
394
+ 1. Run `invar init` → select "Other (AGENT.md)"
395
+ 2. Include generated `AGENT.md` in your agent's prompt
396
+ 3. Configure MCP server if supported
397
+ 4. Use CLI commands (`invar guard`) for verification
395
398
 
396
399
  ---
397
400
 
398
401
  ## 📂 What Gets Installed
399
402
 
400
- `invar init --claude` creates:
403
+ `invar init` creates (select in interactive mode):
404
+
405
+ | File/Directory | Purpose | Category |
406
+ |----------------|---------|----------|
407
+ | `INVAR.md` | Protocol for AI agents | Required |
408
+ | `.invar/` | Config, context, examples | Required |
409
+ | `.pre-commit-config.yaml` | Verification before commit | Optional |
410
+ | `src/core/`, `src/shell/` | Recommended structure | Optional |
411
+ | `CLAUDE.md` | Agent instructions | Claude Code |
412
+ | `.claude/skills/` | Workflow automation | Claude Code |
413
+ | `.claude/commands/` | User commands (/audit, /guard) | Claude Code |
414
+ | `.claude/hooks/` | Tool guidance | Claude Code |
415
+ | `.mcp.json` | MCP server config | Claude Code |
416
+ | `AGENT.md` | Universal agent instructions | Other agents |
401
417
 
402
- | File/Directory | Purpose | Editable? |
403
- |----------------|---------|-----------|
404
- | `INVAR.md` | Protocol for AI agents | No (managed) |
405
- | `CLAUDE.md` | Project configuration | Yes |
406
- | `.claude/skills/` | Workflow skills | Yes |
407
- | `.claude/hooks/` | Tool call interception | Yes |
408
- | `.invar/examples/` | Reference patterns | No (managed) |
409
- | `.invar/context.md` | Project state, lessons | Yes |
410
- | `pyproject.toml` | `[tool.invar]` section | Yes |
418
+ **Note:** If `pyproject.toml` exists, Guard configuration goes there as `[tool.invar.guard]` instead of `.invar/config.toml`.
411
419
 
412
420
  **Recommended structure:**
413
421
 
@@ -473,7 +481,9 @@ rules = ["missing_contract", "shell_result"]
473
481
  | `invar guard` | Full verification (static + doctest + property + symbolic) |
474
482
  | `invar guard --changed` | Only git-modified files |
475
483
  | `invar guard --static` | Static analysis only (~0.5s) |
476
- | `invar init` | Initialize or update project |
484
+ | `invar init` | Initialize or update project (interactive) |
485
+ | `invar init --claude` | Quick setup for Claude Code |
486
+ | `invar uninstall` | Remove Invar from project (preserves user content) |
477
487
  | `invar sig <file>` | Show signatures and contracts |
478
488
  | `invar map` | Symbol map with reference counts |
479
489
  | `invar rules` | List all rules |
@@ -30,7 +30,7 @@ invar/core/tautology.py,sha256=Pmn__a0Bt55W0lAQo1G5q8Ory9KuE23dRknKw45xxbs,9221
30
30
  invar/core/template_parser.py,sha256=vH3H8OX55scZ1hWh3xoA8oJMhgleKufCOhkTvsSuu_4,14730
31
31
  invar/core/timeout_inference.py,sha256=BS2fJGmwOrLpYZUku4qrizgNDSIXVLFBslW-6sRAvpc,3451
32
32
  invar/core/trivial_detection.py,sha256=KYP8jJb7QDeusAxFdX5NAML_H0NL5wLgMeBWDQmNqfU,6086
33
- invar/core/utils.py,sha256=4ani-6XcWF__sD0c_tKcCA2FunaF2pYIfvR5BACWkDg,14168
33
+ invar/core/utils.py,sha256=PyW8dcTLUEFD81xcvkz-LNnCwjIQefn08OUh23fM_Po,14266
34
34
  invar/core/verification_routing.py,sha256=_jXi1txFCcUdnB3-Yavtuyk8N-XhEO_Vu_051Vuz27Y,5020
35
35
  invar/core/patterns/__init__.py,sha256=79a3ucN0BI54RnIOe49lngKASpADygs1hll9ROCrP6s,1429
36
36
  invar/core/patterns/detector.py,sha256=lZ2HPtDJDiGps8Y3e7jds3naZa1oGqDDscHRSX5Vv0s,8297
@@ -45,9 +45,9 @@ invar/mcp/__init__.py,sha256=n3S7QwMjSMqOMT8cI2jf9E0yZPjKmBOJyIYhq4WZ8TQ,226
45
45
  invar/mcp/__main__.py,sha256=ZcIT2U6xUyGOWucl4jq422BDE3lRLjqyxb9pFylRBdk,219
46
46
  invar/mcp/server.py,sha256=ay-w2YfSa1kTmBFx3x3jEgmNRC3NFEW0EYuZRt7M39w,12244
47
47
  invar/shell/__init__.py,sha256=FFw1mNbh_97PeKPcHIqQpQ7mw-JoIvyLM1yOdxLw5uk,204
48
- invar/shell/claude_hooks.py,sha256=kxkdF2gwTWcGpglccDi6-8IN1zRwelDG6Lg1VPYQgyA,12912
48
+ invar/shell/claude_hooks.py,sha256=KJAQ-a7-mvabJ2fgsC9wPMakvi7J43GCU6ZcpWwKYFg,16180
49
49
  invar/shell/config.py,sha256=6-kbo6--SxfROXoyU-v7InSLR8f_U1Mar_xEOdCXFkY,17633
50
- invar/shell/contract_coverage.py,sha256=2RiXC9RBV__cKLHu0KKOWRxEgYVQNNAPAdwBjYenNHQ,11780
50
+ invar/shell/contract_coverage.py,sha256=UPn-lEqrAFu00fl7v9PnSvNwS7KX3_SV1K_GhynQ9cw,12023
51
51
  invar/shell/coverage.py,sha256=m01o898IFIdBztEBQLwwL1Vt5PWrpUntO4lv4nWEkls,11344
52
52
  invar/shell/fs.py,sha256=wVD7DPWsCIJXuTyY_pi-5_LS82mXRdn_grJCOLn9zpU,3699
53
53
  invar/shell/git.py,sha256=s6RQxEDQuLrmK3mru88EoYP8__4hiFW8AozlcxmY47E,2784
@@ -59,18 +59,19 @@ invar/shell/pattern_integration.py,sha256=pRcjfq3NvMW_tvQCnaXZnD1k5AVEWK8CYOE2jN
59
59
  invar/shell/property_tests.py,sha256=N9JreyH5PqR89oF5yLcX7ZAV-Koyg5BKo-J05-GUPsA,9109
60
60
  invar/shell/subprocess_env.py,sha256=9oXl3eMEbzLsFEgMHqobEw6oW_wV0qMEP7pklwm58Pw,11453
61
61
  invar/shell/template_engine.py,sha256=IzOiGsKVFo0lDUdtg27wMzIJJKToclv151RDZuDnHHo,11027
62
- invar/shell/templates.py,sha256=l2En95E8jRVlojdQIqdZgRLVB43f_b1d_AJapKkozwA,15908
62
+ invar/shell/templates.py,sha256=30eT61HXPA6DmsgUyUqljZNGGtB9TSR-aAaI4fmKAco,13722
63
63
  invar/shell/testing.py,sha256=rTNBH0Okh2qtG9ohSXOz487baQ2gXrWT3s_WECW3HJs,11143
64
64
  invar/shell/commands/__init__.py,sha256=MEkKwVyjI9DmkvBpJcuumXo2Pg_FFkfEr-Rr3nrAt7A,284
65
- invar/shell/commands/guard.py,sha256=QJhL3vI_PzAPuGbi2GhxOdmHSIXtaoNuJxjgXTW3JRQ,21595
65
+ invar/shell/commands/guard.py,sha256=vDBGOFb9mQ1D8eXrMvQB505GpjO1XLeCLrv2ig9-6dU,21718
66
66
  invar/shell/commands/hooks.py,sha256=W-SOnT4VQyUvXwipozkJwgEYfiOJGz7wksrbcdWegUg,2356
67
- invar/shell/commands/init.py,sha256=UzHLfAP9ddIY32HrLd32nUveFcHnB0HlbMcIgtfob9Y,18297
67
+ invar/shell/commands/init.py,sha256=wAPPIDpoJyNOhrD09LldRg8w76mWv0r5qTcqlPWc920,13411
68
68
  invar/shell/commands/merge.py,sha256=nuvKo8m32-OL-SCQlS4SLKmOZxQ3qj-1nGCx1Pgzifw,8183
69
69
  invar/shell/commands/mutate.py,sha256=GwemiO6LlbGCBEQsBFnzZuKhF-wIMEl79GAMnKUWc8U,5765
70
70
  invar/shell/commands/perception.py,sha256=TyH_HpqyKkmE3-zcU4YyBG8ghwJaSFeRC-OQMVBDTbQ,3837
71
71
  invar/shell/commands/sync_self.py,sha256=nmqBry7V2_enKwy2zzHg8UoedZNicLe3yKDhjmBeZ68,3880
72
72
  invar/shell/commands/template_sync.py,sha256=wVZ-UvJ1wpN2UBcWMfbei0n46XHYx-zRbMA2oX6FSi4,13723
73
73
  invar/shell/commands/test.py,sha256=goMf-ovvzEyWQMheq4YlJ-mwK5-w3lDj0cq0IA_1-_c,4205
74
+ invar/shell/commands/uninstall.py,sha256=u1fqE2jCod2KxFMEYbtC4UFK1zuxzoaQKQzZdAjQcDE,17368
74
75
  invar/shell/commands/update.py,sha256=0V5F8vxQ6PHPHPVYDmxdRD7xXeQEFypiJMYpY5ryiek,1349
75
76
  invar/shell/prove/__init__.py,sha256=ZqlbmyMFJf6yAle8634jFuPRv8wNvHps8loMlOJyf8A,240
76
77
  invar/shell/prove/accept.py,sha256=cnY_6jzU1EBnpLF8-zWUWcXiSXtCwxPsXEYXsSVPG38,3717
@@ -79,17 +80,14 @@ invar/shell/prove/crosshair.py,sha256=4Z_iIYBlkp-I6FqSYZa89wWB09V4Ouw2PduYhTn6rf
79
80
  invar/shell/prove/hypothesis.py,sha256=QUclOOUg_VB6wbmHw8O2EPiL5qBOeBRqQeM04AVuLw0,9880
80
81
  invar/templates/CLAUDE.md.template,sha256=eaGU3SyRO_NEifw5b26k3srgQH4jyeujjCJ-HbM36_w,4913
81
82
  invar/templates/__init__.py,sha256=cb3ht8KPK5oBn5oG6HsTznujmo9WriJ_P--fVxJwycc,45
82
- invar/templates/aider.conf.yml.template,sha256=4xzSs3BXzFJvwdhnWbmzSY0yCbfx5oxqnV8ZjehqHBg,853
83
83
  invar/templates/context.md.template,sha256=FKyI1ghpqcf4wftyv9-auIFHor8Nm8lETN45Ja-L8Og,2386
84
- invar/templates/cursorrules.template,sha256=N6AiEJRJHGkHm2tswh3PnZ_07ozeyQQI8iEOGK5Aqoc,1023
85
84
  invar/templates/manifest.toml,sha256=cEe7yEOOeaLmOF-PrwZXxiPGjHhsSJYkWBKRHDmSbac,4268
86
- invar/templates/pre-commit-config.yaml.template,sha256=2qWY3E8iDUqi85jE_X7y0atE88YOlL5IZ93wkjCgQGo,1737
87
85
  invar/templates/proposal.md.template,sha256=UP7SpQ7gk8jVlHGLQCSQ5c-kCj1DBQEz8M-vEStK77I,1573
88
- invar/templates/commands/audit.md,sha256=eXBySlQrVyk054vYQWAZYzj-HgT2QXhpzziw6GlIeGM,4112
89
- invar/templates/commands/guard.md,sha256=PyeAKfrmlXsgbrTDypQqXmTDKK1JHKhHEQrHqftA7X0,1177
86
+ invar/templates/commands/audit.md,sha256=OrotO8420zTKnlNyAyL1Eos0VIaihzEU4AHdfDv68Oc,4162
87
+ invar/templates/commands/guard.md,sha256=N_C_AXd9kI85W1B0aTEycjiDp_jdaP8eeq8O0FQ_WQ8,1227
90
88
  invar/templates/config/CLAUDE.md.jinja,sha256=VbtDWxn3H8qiE9-DV1hlG3DJ-GcBQU4ZiUHbFh6Bxxk,7814
91
89
  invar/templates/config/context.md.jinja,sha256=_kJ8erEQNJMLDCKrv4BXWkO6OaGzE-zW9biCf7144aY,3103
92
- invar/templates/config/pre-commit.yaml.jinja,sha256=Qflmii8hngHciSgfa8mIlg3-E3D4b0xflm0-Q-cWcCc,1752
90
+ invar/templates/config/pre-commit.yaml.jinja,sha256=nUPxLxkTHAgZwhFAuOMDbZ8v0NQV9FlQPbr2MDEOsoA,1778
93
91
  invar/templates/examples/README.md,sha256=xMcJZ1KEcfLJi5Ope_4FIbqDWKK3mRleAgllvgeNT6I,572
94
92
  invar/templates/examples/conftest.py,sha256=uKA4NR7nyZWeSzY0URdZtw5zCcJpU32jNcaSKrI1Mxc,152
95
93
  invar/templates/examples/contracts.py,sha256=uqJ6Y1GADo246MjFKoLY-_2E74cfBQsLO4vTqYcR81c,3241
@@ -105,10 +103,10 @@ invar/templates/skills/develop/SKILL.md.jinja,sha256=3coPSZGh1-YKN9Xc_xcEkfEP3S0
105
103
  invar/templates/skills/investigate/SKILL.md.jinja,sha256=bOLdLMH5WUVBYOo4NpsfyvI6xx7I1lCNr_X-8bMe_kg,2744
106
104
  invar/templates/skills/propose/SKILL.md.jinja,sha256=_iDLYN6-cfzA8n0_8sv-Dnpm1xq9IIpcDyM10mU2WUA,2420
107
105
  invar/templates/skills/review/SKILL.md.jinja,sha256=e7HULz1jjLOlk2LYejQMk2F-cu7dDIwvh6lWNjx3j-Q,14123
108
- invar_tools-1.6.0.dist-info/METADATA,sha256=8_ISE8BAkc9wl7CmsPffsLT2mulMUhDAXF78v08ySPk,16964
109
- invar_tools-1.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
110
- invar_tools-1.6.0.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
111
- invar_tools-1.6.0.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
112
- invar_tools-1.6.0.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
113
- invar_tools-1.6.0.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
114
- invar_tools-1.6.0.dist-info/RECORD,,
106
+ invar_tools-1.7.1.dist-info/METADATA,sha256=dBk4N2qRISfYrc6Rr66eY08_me9Rqfyq34RDBCaEj1s,17600
107
+ invar_tools-1.7.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
108
+ invar_tools-1.7.1.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
109
+ invar_tools-1.7.1.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
110
+ invar_tools-1.7.1.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
111
+ invar_tools-1.7.1.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
112
+ invar_tools-1.7.1.dist-info/RECORD,,
@@ -1,31 +0,0 @@
1
- # Invar Protocol Configuration for Aider
2
- # Follow the Invar Protocol in INVAR.md
3
-
4
- # Auto-read protocol files at session start
5
- read:
6
- - INVAR.md
7
- - .invar/examples/contracts.py
8
- - .invar/examples/core_shell.py
9
- - .invar/context.md
10
-
11
- # System prompt addition
12
- system-prompt: |
13
- Follow the Invar Protocol in INVAR.md.
14
-
15
- ## Check-In
16
- Your first message MUST display:
17
- ✓ Check-In: [project] | [branch] | [clean/dirty]
18
-
19
- Read .invar/context.md first. Do NOT run guard/map at Check-In.
20
- This is your sign-in. No visible check-in = Session not started.
21
-
22
- ## Final
23
- Your last message MUST display:
24
- ✓ Final: guard PASS | 0 errors, 2 warnings
25
-
26
- Execute: invar guard
27
- This is your sign-out. Completes the Check-In/Final pair.
28
-
29
- ## Workflow (USBV)
30
- Understand → Specify → Build → Validate
31
- Inspect before Contract. Depth varies naturally.
@@ -1,40 +0,0 @@
1
- # Invar Protocol
2
-
3
- Follow the Invar Protocol in INVAR.md — includes Check-In, USBV workflow, and Task Completion requirements.
4
-
5
- ## Check-In
6
-
7
- Your first message MUST display:
8
-
9
- ```
10
- ✓ Check-In: [project] | [branch] | [clean/dirty]
11
- ```
12
-
13
- Actions:
14
- 1. Read `.invar/context.md` (Key Rules + Current State + Lessons Learned)
15
- 2. Show one-line status
16
-
17
- **Do NOT execute guard or map at Check-In.**
18
- Guard is for VALIDATE phase and Final only.
19
-
20
- This is your sign-in. The user sees it immediately.
21
- No visible check-in = Session not started.
22
-
23
- ## Final
24
-
25
- Your last message for an implementation task MUST display:
26
-
27
- ```
28
- ✓ Final: guard PASS | 0 errors, 2 warnings
29
- ```
30
-
31
- Execute `invar guard` and show this one-line summary.
32
-
33
- This is your sign-out. Completes the Check-In/Final pair.
34
-
35
- ## Quick Reference
36
-
37
- - Core (`**/core/**`): @pre/@post contracts, doctests, pure (no I/O)
38
- - Shell (`**/shell/**`): Result[T, E] return type
39
- - Workflow: Understand → Specify → Build → Validate (USBV)
40
- - Inspect before Contract. Depth varies naturally.
@@ -1,44 +0,0 @@
1
- # Invar Pre-commit Hooks
2
- # Install: pre-commit install
3
- #
4
- # Default runs full verification (static + doctests + CrossHair + Hypothesis).
5
- # Incremental mode makes this fast: ~5s first commit, ~2s subsequent (cached).
6
- #
7
- # Smart Guard: Detects rule-affecting file changes and runs full guard when needed.
8
- # Structure Protection: Warns if INVAR.md is modified directly.
9
-
10
- repos:
11
- - repo: local
12
- hooks:
13
- # Warn if INVAR.md is modified directly (use --no-verify if intentional)
14
- - id: invar-md-protected
15
- name: INVAR.md Protection
16
- entry: bash -c 'if git diff --cached --name-only | grep -q "^INVAR.md$"; then echo "Warning - INVAR.md was modified directly. Use git commit --no-verify if intentional."; exit 1; fi'
17
- language: system
18
- pass_filenames: false
19
- stages: [pre-commit]
20
-
21
- # Invar Guard (full verification by default)
22
- # Uses incremental mode: only verifies changed files, caches results
23
- # Smart mode: runs full guard when rule files change, --changed otherwise
24
- - id: invar-guard
25
- name: Invar Guard
26
- entry: bash -c '
27
- RULE_FILES="rule_meta.py rules.py contracts.py purity.py pyproject.toml"
28
- STAGED=$(git diff --cached --name-only)
29
- FULL=false
30
- for f in $RULE_FILES; do
31
- if echo "$STAGED" | grep -q "$f"; then FULL=true; break; fi
32
- done
33
- if [ "$FULL" = true ]; then
34
- echo "⚠️ Rule change detected - running FULL guard"
35
- invar guard
36
- else
37
- invar guard --changed
38
- fi
39
- '
40
- language: python
41
- additional_dependencies: ['invar-tools']
42
- pass_filenames: false
43
- stages: [pre-commit]
44
- types: [python]