invar-tools 1.8.0__py3-none-any.whl → 1.11.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.
- invar/__init__.py +8 -0
- invar/core/doc_edit.py +187 -0
- invar/core/doc_parser.py +563 -0
- invar/core/language.py +88 -0
- invar/core/models.py +106 -0
- invar/core/patterns/detector.py +6 -1
- invar/core/patterns/p0_exhaustive.py +15 -3
- invar/core/patterns/p0_literal.py +15 -3
- invar/core/patterns/p0_newtype.py +15 -3
- invar/core/patterns/p0_nonempty.py +15 -3
- invar/core/patterns/p0_validation.py +15 -3
- invar/core/patterns/registry.py +5 -1
- invar/core/patterns/types.py +5 -1
- invar/core/property_gen.py +4 -0
- invar/core/rules.py +84 -18
- invar/core/sync_helpers.py +27 -1
- invar/core/ts_parsers.py +286 -0
- invar/core/ts_sig_parser.py +310 -0
- invar/mcp/handlers.py +408 -0
- invar/mcp/server.py +288 -143
- invar/node_tools/MANIFEST +7 -0
- invar/node_tools/__init__.py +51 -0
- invar/node_tools/fc-runner/cli.js +77 -0
- invar/node_tools/quick-check/cli.js +28 -0
- invar/node_tools/ts-analyzer/cli.js +480 -0
- invar/shell/claude_hooks.py +35 -12
- invar/shell/commands/doc.py +409 -0
- invar/shell/commands/guard.py +41 -1
- invar/shell/commands/init.py +154 -16
- invar/shell/commands/perception.py +157 -33
- invar/shell/commands/skill.py +187 -0
- invar/shell/commands/template_sync.py +65 -13
- invar/shell/commands/uninstall.py +60 -12
- invar/shell/commands/update.py +6 -14
- invar/shell/contract_coverage.py +1 -0
- invar/shell/doc_tools.py +459 -0
- invar/shell/fs.py +67 -13
- invar/shell/pi_hooks.py +6 -0
- invar/shell/prove/crosshair.py +3 -0
- invar/shell/prove/guard_ts.py +902 -0
- invar/shell/skill_manager.py +355 -0
- invar/shell/template_engine.py +28 -4
- invar/shell/templates.py +4 -4
- invar/templates/claude-md/python/critical-rules.md +33 -0
- invar/templates/claude-md/python/quick-reference.md +24 -0
- invar/templates/claude-md/typescript/critical-rules.md +40 -0
- invar/templates/claude-md/typescript/quick-reference.md +24 -0
- invar/templates/claude-md/universal/check-in.md +25 -0
- invar/templates/claude-md/universal/skills.md +73 -0
- invar/templates/claude-md/universal/workflow.md +55 -0
- invar/templates/commands/{audit.md → audit.md.jinja} +18 -1
- invar/templates/config/AGENT.md.jinja +58 -0
- invar/templates/config/CLAUDE.md.jinja +16 -209
- invar/templates/config/context.md.jinja +19 -0
- invar/templates/examples/{README.md → python/README.md} +2 -0
- invar/templates/examples/{conftest.py → python/conftest.py} +1 -1
- invar/templates/examples/{contracts.py → python/contracts.py} +81 -4
- invar/templates/examples/python/core_shell.py +227 -0
- invar/templates/examples/python/functional.py +613 -0
- invar/templates/examples/typescript/README.md +31 -0
- invar/templates/examples/typescript/contracts.ts +163 -0
- invar/templates/examples/typescript/core_shell.ts +374 -0
- invar/templates/examples/typescript/functional.ts +601 -0
- invar/templates/examples/typescript/workflow.md +95 -0
- invar/templates/hooks/PostToolUse.sh.jinja +10 -1
- invar/templates/hooks/PreToolUse.sh.jinja +38 -0
- invar/templates/hooks/Stop.sh.jinja +1 -1
- invar/templates/hooks/UserPromptSubmit.sh.jinja +7 -0
- invar/templates/hooks/pi/invar.ts.jinja +9 -0
- invar/templates/manifest.toml +7 -6
- invar/templates/onboard/assessment.md.jinja +214 -0
- invar/templates/onboard/patterns/python.md +347 -0
- invar/templates/onboard/patterns/typescript.md +452 -0
- invar/templates/onboard/roadmap.md.jinja +168 -0
- invar/templates/protocol/INVAR.md.jinja +51 -0
- invar/templates/protocol/python/architecture-examples.md +41 -0
- invar/templates/protocol/python/contracts-syntax.md +56 -0
- invar/templates/protocol/python/markers.md +44 -0
- invar/templates/protocol/python/tools.md +24 -0
- invar/templates/protocol/python/troubleshooting.md +38 -0
- invar/templates/protocol/typescript/architecture-examples.md +52 -0
- invar/templates/protocol/typescript/contracts-syntax.md +73 -0
- invar/templates/protocol/typescript/markers.md +48 -0
- invar/templates/protocol/typescript/tools.md +65 -0
- invar/templates/protocol/typescript/troubleshooting.md +104 -0
- invar/templates/protocol/universal/architecture.md +36 -0
- invar/templates/protocol/universal/completion.md +14 -0
- invar/templates/protocol/universal/contracts-concept.md +37 -0
- invar/templates/protocol/universal/header.md +17 -0
- invar/templates/protocol/universal/session.md +17 -0
- invar/templates/protocol/universal/six-laws.md +10 -0
- invar/templates/protocol/universal/usbv.md +14 -0
- invar/templates/protocol/universal/visible-workflow.md +25 -0
- invar/templates/skills/develop/SKILL.md.jinja +85 -3
- invar/templates/skills/extensions/_registry.yaml +93 -0
- invar/templates/skills/extensions/acceptance/SKILL.md +383 -0
- invar/templates/skills/extensions/invar-onboard/SKILL.md +448 -0
- invar/templates/skills/extensions/invar-onboard/patterns/python.md +347 -0
- invar/templates/skills/extensions/invar-onboard/patterns/typescript.md +452 -0
- invar/templates/skills/extensions/invar-onboard/templates/assessment.md.jinja +214 -0
- invar/templates/skills/extensions/invar-onboard/templates/roadmap.md.jinja +168 -0
- invar/templates/skills/extensions/security/SKILL.md +382 -0
- invar/templates/skills/extensions/security/patterns/_common.yaml +126 -0
- invar/templates/skills/extensions/security/patterns/python.yaml +155 -0
- invar/templates/skills/extensions/security/patterns/typescript.yaml +194 -0
- invar/templates/skills/review/SKILL.md.jinja +220 -248
- {invar_tools-1.8.0.dist-info → invar_tools-1.11.0.dist-info}/METADATA +336 -12
- invar_tools-1.11.0.dist-info/RECORD +178 -0
- invar/templates/examples/core_shell.py +0 -127
- invar/templates/protocol/INVAR.md +0 -310
- invar_tools-1.8.0.dist-info/RECORD +0 -116
- /invar/templates/examples/{workflow.md → python/workflow.md} +0 -0
- {invar_tools-1.8.0.dist-info → invar_tools-1.11.0.dist-info}/WHEEL +0 -0
- {invar_tools-1.8.0.dist-info → invar_tools-1.11.0.dist-info}/entry_points.txt +0 -0
- {invar_tools-1.8.0.dist-info → invar_tools-1.11.0.dist-info}/licenses/LICENSE +0 -0
- {invar_tools-1.8.0.dist-info → invar_tools-1.11.0.dist-info}/licenses/LICENSE-GPL +0 -0
- {invar_tools-1.8.0.dist-info → invar_tools-1.11.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Invar Core/Shell Separation Examples
|
|
3
|
-
|
|
4
|
-
Reference patterns for Core vs Shell architecture.
|
|
5
|
-
Managed by Invar - do not edit directly.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
|
|
10
|
-
# For lambda-based contracts, use deal directly
|
|
11
|
-
# invar_runtime.pre/post are for Contract objects (NonEmpty, IsInstance, etc.)
|
|
12
|
-
from deal import post, pre
|
|
13
|
-
from returns.result import Failure, Result, Success
|
|
14
|
-
|
|
15
|
-
# =============================================================================
|
|
16
|
-
# CORE: Pure Logic (no I/O)
|
|
17
|
-
# =============================================================================
|
|
18
|
-
# Location: src/*/core/
|
|
19
|
-
# Requirements: @pre/@post, doctests, no I/O imports
|
|
20
|
-
# =============================================================================
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# @invar:allow shell_result: Example file - demonstrates Core pattern
|
|
24
|
-
# @shell_orchestration: Example file - demonstrates Core pattern
|
|
25
|
-
@pre(lambda content: content is not None) # Accepts any string including empty
|
|
26
|
-
@post(lambda result: all(line.strip() == line and line for line in result)) # No whitespace, non-empty
|
|
27
|
-
def parse_lines(content: str) -> list[str]:
|
|
28
|
-
"""
|
|
29
|
-
Parse content into non-empty lines.
|
|
30
|
-
|
|
31
|
-
>>> parse_lines("a\\nb\\nc")
|
|
32
|
-
['a', 'b', 'c']
|
|
33
|
-
>>> parse_lines("")
|
|
34
|
-
[]
|
|
35
|
-
>>> parse_lines(" \\n ") # Edge: whitespace only
|
|
36
|
-
[]
|
|
37
|
-
"""
|
|
38
|
-
return [line.strip() for line in content.split("\n") if line.strip()]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# @invar:allow shell_result: Example file - demonstrates Core pattern
|
|
42
|
-
# @shell_orchestration: Example file - demonstrates Core pattern
|
|
43
|
-
@pre(lambda items: all(isinstance(i, str) for i in items)) # All items must be strings
|
|
44
|
-
@post(lambda result: all(v > 0 for v in result.values())) # All counts are positive
|
|
45
|
-
def count_items(items: list[str]) -> dict[str, int]:
|
|
46
|
-
"""
|
|
47
|
-
Count occurrences of each item.
|
|
48
|
-
|
|
49
|
-
>>> sorted(count_items(['a', 'b', 'a']).items())
|
|
50
|
-
[('a', 2), ('b', 1)]
|
|
51
|
-
>>> count_items([])
|
|
52
|
-
{}
|
|
53
|
-
"""
|
|
54
|
-
counts: dict[str, int] = {}
|
|
55
|
-
for item in items:
|
|
56
|
-
counts[item] = counts.get(item, 0) + 1
|
|
57
|
-
return counts
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# =============================================================================
|
|
61
|
-
# SHELL: I/O Operations
|
|
62
|
-
# =============================================================================
|
|
63
|
-
# Location: src/*/shell/
|
|
64
|
-
# Requirements: Result[T, E] return type, calls Core for logic
|
|
65
|
-
# =============================================================================
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def read_file(path: Path) -> Result[str, str]:
|
|
69
|
-
"""
|
|
70
|
-
Read file content.
|
|
71
|
-
|
|
72
|
-
Shell handles I/O, returns Result for error handling.
|
|
73
|
-
"""
|
|
74
|
-
try:
|
|
75
|
-
return Success(path.read_text())
|
|
76
|
-
except FileNotFoundError:
|
|
77
|
-
return Failure(f"File not found: {path}")
|
|
78
|
-
except PermissionError:
|
|
79
|
-
return Failure(f"Permission denied: {path}")
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def count_lines_in_file(path: Path) -> Result[dict[str, int], str]:
|
|
83
|
-
"""
|
|
84
|
-
Count lines in file - demonstrates Core/Shell integration.
|
|
85
|
-
|
|
86
|
-
Shell reads file → Core parses content → Shell returns result.
|
|
87
|
-
"""
|
|
88
|
-
# Shell: I/O operation
|
|
89
|
-
content_result = read_file(path)
|
|
90
|
-
|
|
91
|
-
if isinstance(content_result, Failure):
|
|
92
|
-
return content_result
|
|
93
|
-
|
|
94
|
-
content = content_result.unwrap()
|
|
95
|
-
|
|
96
|
-
# Core: Pure logic (no I/O)
|
|
97
|
-
lines = parse_lines(content)
|
|
98
|
-
counts = count_items(lines)
|
|
99
|
-
|
|
100
|
-
# Shell: Return result
|
|
101
|
-
return Success(counts)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# =============================================================================
|
|
105
|
-
# ANTI-PATTERNS
|
|
106
|
-
# =============================================================================
|
|
107
|
-
|
|
108
|
-
# DON'T: I/O in Core
|
|
109
|
-
# def parse_file(path: Path): # BAD: Path in Core
|
|
110
|
-
# content = path.read_text() # BAD: I/O in Core # noqa: ERA001
|
|
111
|
-
# return parse_lines(content) # noqa: ERA001
|
|
112
|
-
|
|
113
|
-
# DO: Core receives content, not paths
|
|
114
|
-
# def parse_content(content: str): # GOOD: receives data
|
|
115
|
-
# return parse_lines(content) # noqa: ERA001
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
# DON'T: Missing Result in Shell
|
|
119
|
-
# def load_config(path: Path) -> dict: # BAD: no Result type
|
|
120
|
-
# return json.loads(path.read_text()) # Exceptions not handled # noqa: ERA001
|
|
121
|
-
|
|
122
|
-
# DO: Return Result[T, E]
|
|
123
|
-
# def load_config(path: Path) -> Result[dict, str]: # GOOD
|
|
124
|
-
# try: # noqa: ERA001
|
|
125
|
-
# return Success(json.loads(path.read_text())) # noqa: ERA001
|
|
126
|
-
# except Exception as e: # noqa: ERA001
|
|
127
|
-
# return Failure(str(e)) # noqa: ERA001
|
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
3
|
-
│ INVAR-MANAGED FILE - DO NOT EDIT DIRECTLY │
|
|
4
|
-
│ │
|
|
5
|
-
│ This file is managed by Invar. Changes may be lost on │
|
|
6
|
-
│ `invar update`. Add project content to CLAUDE.md instead. │
|
|
7
|
-
└─────────────────────────────────────────────────────────────┘
|
|
8
|
-
|
|
9
|
-
License: CC-BY-4.0 (Creative Commons Attribution 4.0 International)
|
|
10
|
-
https://creativecommons.org/licenses/by/4.0/
|
|
11
|
-
|
|
12
|
-
You are free to share and adapt this document, provided you give
|
|
13
|
-
appropriate credit to the Invar project.
|
|
14
|
-
-->
|
|
15
|
-
# The Invar Protocol v5.0
|
|
16
|
-
|
|
17
|
-
> **"Trade structure for safety."**
|
|
18
|
-
|
|
19
|
-
## Six Laws
|
|
20
|
-
|
|
21
|
-
| Law | Principle |
|
|
22
|
-
|-----|-----------|
|
|
23
|
-
| 1. Separation | Core (pure logic) / Shell (I/O) physically separate |
|
|
24
|
-
| 2. Contract Complete | @pre/@post + doctests uniquely determine implementation |
|
|
25
|
-
| 3. Context Economy | map → sig → code (only read what's needed) |
|
|
26
|
-
| 4. Decompose First | Break into sub-functions before implementing |
|
|
27
|
-
| 5. Verify Reflectively | Fail → Reflect (why?) → Fix → Verify |
|
|
28
|
-
| 6. Integrate Fully | Local correct ≠ Global correct; verify all paths |
|
|
29
|
-
|
|
30
|
-
## Core/Shell Architecture
|
|
31
|
-
|
|
32
|
-
| Zone | Location | Requirements |
|
|
33
|
-
|------|----------|--------------|
|
|
34
|
-
| Core | `**/core/**` | @pre/@post, pure (no I/O), doctests |
|
|
35
|
-
| Shell | `**/shell/**` | `Result[T, E]` return type |
|
|
36
|
-
|
|
37
|
-
**Forbidden in Core:** `os`, `sys`, `subprocess`, `pathlib`, `open`, `requests`, `datetime.now`
|
|
38
|
-
|
|
39
|
-
### Decision Tree: Core vs Shell
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Does this function...
|
|
43
|
-
│
|
|
44
|
-
├─ Read or write files? ──────────────────→ Shell
|
|
45
|
-
├─ Make network requests? ─────────────────→ Shell
|
|
46
|
-
├─ Access current time (datetime.now)? ────→ Shell OR inject as parameter
|
|
47
|
-
├─ Generate random values? ────────────────→ Shell OR inject as parameter
|
|
48
|
-
├─ Print to console? ──────────────────────→ Shell (return data, Shell logs)
|
|
49
|
-
├─ Access environment variables? ──────────→ Shell
|
|
50
|
-
│
|
|
51
|
-
└─ None of the above? ─────────────────────→ Core
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Pattern:** Inject impure values as parameters:
|
|
55
|
-
```python
|
|
56
|
-
# Core: receives 'now' as parameter (pure)
|
|
57
|
-
def is_expired(expiry: datetime, now: datetime) -> bool:
|
|
58
|
-
return now > expiry
|
|
59
|
-
|
|
60
|
-
# Shell calls with actual time
|
|
61
|
-
expired = is_expired(token.expiry, datetime.now())
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Core Example (Pure Logic)
|
|
65
|
-
|
|
66
|
-
```python
|
|
67
|
-
from deal import pre, post
|
|
68
|
-
|
|
69
|
-
@pre(lambda price, discount: price > 0 and 0 <= discount <= 1)
|
|
70
|
-
@post(lambda result: result >= 0)
|
|
71
|
-
def discounted_price(price: float, discount: float) -> float:
|
|
72
|
-
"""
|
|
73
|
-
>>> discounted_price(100, 0.2)
|
|
74
|
-
80.0
|
|
75
|
-
>>> discounted_price(100, 0) # Edge: no discount
|
|
76
|
-
100.0
|
|
77
|
-
"""
|
|
78
|
-
return price * (1 - discount)
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
**Self-test:** Can someone else write the exact same function from just @pre/@post + doctests?
|
|
82
|
-
|
|
83
|
-
## Shell Example (I/O Operations)
|
|
84
|
-
|
|
85
|
-
```python
|
|
86
|
-
from pathlib import Path
|
|
87
|
-
from returns.result import Result, Success, Failure
|
|
88
|
-
|
|
89
|
-
def read_config(path: Path) -> Result[dict, str]:
|
|
90
|
-
"""Shell: handles I/O, returns Result for error handling."""
|
|
91
|
-
try:
|
|
92
|
-
import json
|
|
93
|
-
return Success(json.loads(path.read_text()))
|
|
94
|
-
except FileNotFoundError:
|
|
95
|
-
return Failure(f"File not found: {path}")
|
|
96
|
-
except json.JSONDecodeError as e:
|
|
97
|
-
return Failure(f"Invalid JSON: {e}")
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Pattern:** Shell reads file → passes content to Core → returns Result.
|
|
101
|
-
|
|
102
|
-
More examples: `.invar/examples/`
|
|
103
|
-
|
|
104
|
-
## Contract Rules
|
|
105
|
-
|
|
106
|
-
### Lambda Signature (Critical)
|
|
107
|
-
|
|
108
|
-
```python
|
|
109
|
-
# WRONG: Lambda only takes first parameter
|
|
110
|
-
@pre(lambda x: x >= 0)
|
|
111
|
-
def calculate(x: int, y: int = 0): ...
|
|
112
|
-
|
|
113
|
-
# CORRECT: Lambda must include ALL parameters (even defaults)
|
|
114
|
-
@pre(lambda x, y=0: x >= 0)
|
|
115
|
-
def calculate(x: int, y: int = 0): ...
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Guard's `param_mismatch` rule catches this as ERROR.
|
|
119
|
-
|
|
120
|
-
### Meaningful Contracts
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
# Redundant - type hints already check this
|
|
124
|
-
@pre(lambda x: isinstance(x, int))
|
|
125
|
-
def calc(x: int): ...
|
|
126
|
-
|
|
127
|
-
# Meaningful - checks business logic
|
|
128
|
-
@pre(lambda x: x > 0)
|
|
129
|
-
def calc(x: int): ...
|
|
130
|
-
|
|
131
|
-
# Meaningful - checks relationship between params
|
|
132
|
-
@pre(lambda start, end: start < end)
|
|
133
|
-
def process_range(start: int, end: int): ...
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### @post Scope
|
|
137
|
-
|
|
138
|
-
```python
|
|
139
|
-
# WRONG: @post cannot access function parameters
|
|
140
|
-
@post(lambda result: result > x) # 'x' not available!
|
|
141
|
-
def calc(x: int) -> int: ...
|
|
142
|
-
|
|
143
|
-
# CORRECT: @post can only use 'result'
|
|
144
|
-
@post(lambda result: result >= 0)
|
|
145
|
-
def calc(x: int) -> int: ...
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Check-In (Required)
|
|
149
|
-
|
|
150
|
-
Your first message MUST display:
|
|
151
|
-
|
|
152
|
-
```
|
|
153
|
-
✓ Check-In: [project] | [branch] | [clean/dirty]
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
Actions:
|
|
157
|
-
1. Read `.invar/context.md` (Key Rules + Current State + Lessons Learned)
|
|
158
|
-
2. Show one-line status
|
|
159
|
-
|
|
160
|
-
**Do NOT execute guard or map at Check-In.**
|
|
161
|
-
Guard is for VALIDATE phase and Final only.
|
|
162
|
-
|
|
163
|
-
This is your sign-in. The user sees it immediately.
|
|
164
|
-
No visible check-in = Session not started.
|
|
165
|
-
|
|
166
|
-
## USBV Workflow (DX-32)
|
|
167
|
-
|
|
168
|
-
**U**nderstand → **S**pecify → **B**uild → **V**alidate
|
|
169
|
-
|
|
170
|
-
| Phase | Purpose | Activities |
|
|
171
|
-
|-------|---------|------------|
|
|
172
|
-
| UNDERSTAND | Know what and why | Intent, Inspect (invar sig/map), Constraints |
|
|
173
|
-
| SPECIFY | Define boundaries | @pre/@post, Design decomposition, Doctests |
|
|
174
|
-
| BUILD | Write code | Implement leaves, Compose |
|
|
175
|
-
| VALIDATE | Confirm correctness | invar guard, Review Gate, Reflect |
|
|
176
|
-
|
|
177
|
-
**Key:** Inspect before Contract. Depth varies naturally. Iterate when needed.
|
|
178
|
-
|
|
179
|
-
**Review Gate:** When Guard triggers `review_suggested` (escape hatches ≥3, security paths, low coverage), invoke `/review` before completion.
|
|
180
|
-
|
|
181
|
-
## Visible Workflow (DX-30)
|
|
182
|
-
|
|
183
|
-
For complex tasks (3+ functions), show 3 checkpoints in TodoList:
|
|
184
|
-
|
|
185
|
-
```
|
|
186
|
-
□ [UNDERSTAND] Task description, codebase context, constraints
|
|
187
|
-
□ [SPECIFY] Contracts (@pre/@post) and design decomposition
|
|
188
|
-
□ [VALIDATE] Guard results, Review Gate if triggered, integration status
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**BUILD is internal work** — not shown in TodoList.
|
|
192
|
-
|
|
193
|
-
**Show contracts before code.** Example:
|
|
194
|
-
|
|
195
|
-
```python
|
|
196
|
-
[SPECIFY] calculate_discount:
|
|
197
|
-
@pre(lambda price, rate: price > 0 and 0 <= rate <= 1)
|
|
198
|
-
@post(lambda result: result >= 0)
|
|
199
|
-
def calculate_discount(price: float, rate: float) -> float: ...
|
|
200
|
-
|
|
201
|
-
[BUILD] Now coding...
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
**When to use:** New features (3+ functions), architectural changes, Core modifications.
|
|
205
|
-
**Skip for:** Single-line fixes, documentation, trivial refactoring.
|
|
206
|
-
|
|
207
|
-
## Task Completion
|
|
208
|
-
|
|
209
|
-
A task is complete only when ALL conditions are met:
|
|
210
|
-
- Check-In displayed: `✓ Check-In: [project] | [branch] | [clean/dirty]`
|
|
211
|
-
- Intent explicitly stated
|
|
212
|
-
- Contract written before implementation
|
|
213
|
-
- Final displayed: `✓ Final: guard PASS | <errors>, <warnings>`
|
|
214
|
-
- User requirement satisfied
|
|
215
|
-
|
|
216
|
-
**Missing any = Task incomplete.**
|
|
217
|
-
|
|
218
|
-
## Markers
|
|
219
|
-
|
|
220
|
-
### Entry Points
|
|
221
|
-
|
|
222
|
-
Entry points are framework callbacks (`@app.route`, `@app.command`) at Shell boundary.
|
|
223
|
-
- **Exempt** from `Result[T, E]` — must match framework signature
|
|
224
|
-
- **Keep thin** (max 15 lines) — delegate to Shell functions that return Result
|
|
225
|
-
|
|
226
|
-
Auto-detected by decorators. For custom callbacks:
|
|
227
|
-
|
|
228
|
-
```python
|
|
229
|
-
# @shell:entry
|
|
230
|
-
def on_custom_event(data: dict) -> dict:
|
|
231
|
-
result = handle_event(data)
|
|
232
|
-
return result.unwrap_or({"error": "failed"})
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Shell Complexity
|
|
236
|
-
|
|
237
|
-
When shell function complexity is justified:
|
|
238
|
-
|
|
239
|
-
```python
|
|
240
|
-
# @shell_complexity: Subprocess with error classification
|
|
241
|
-
def run_external_tool(...): ...
|
|
242
|
-
|
|
243
|
-
# @shell_orchestration: Multi-step pipeline coordination
|
|
244
|
-
def process_batch(...): ...
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Architecture Escape Hatch
|
|
248
|
-
|
|
249
|
-
When rule violation has valid architectural justification:
|
|
250
|
-
|
|
251
|
-
```python
|
|
252
|
-
# @invar:allow shell_result: Framework callback signature fixed
|
|
253
|
-
def flask_handler(): ...
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**Valid rule names for @invar:allow:**
|
|
257
|
-
- `shell_result` — Shell function without Result return type
|
|
258
|
-
- `entry_point_too_thick` — Entry point exceeds 15 lines
|
|
259
|
-
- `forbidden_import` — I/O import in Core (rare, justify carefully)
|
|
260
|
-
|
|
261
|
-
Run `invar rules` for complete rule catalog with hints.
|
|
262
|
-
|
|
263
|
-
## Commands
|
|
264
|
-
|
|
265
|
-
```bash
|
|
266
|
-
invar guard # Full: static + doctests + CrossHair + Hypothesis
|
|
267
|
-
invar guard --static # Static only (quick debug, ~0.5s)
|
|
268
|
-
invar guard --changed # Modified files only
|
|
269
|
-
invar guard --coverage # Collect branch coverage
|
|
270
|
-
invar guard -c # Contract coverage only (DX-63)
|
|
271
|
-
invar sig <file> # Show contracts + signatures
|
|
272
|
-
invar map --top 10 # Most-referenced symbols
|
|
273
|
-
invar rules # List all rules with detection/hints (JSON)
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## Configuration
|
|
277
|
-
|
|
278
|
-
```toml
|
|
279
|
-
# pyproject.toml or invar.toml
|
|
280
|
-
[tool.invar.guard]
|
|
281
|
-
core_paths = ["src/myapp/core"] # Default: ["src/core", "core"]
|
|
282
|
-
shell_paths = ["src/myapp/shell"] # Default: ["src/shell", "shell"]
|
|
283
|
-
max_file_lines = 500 # Default: 500 (warning at 80%)
|
|
284
|
-
max_function_lines = 50 # Default: 50
|
|
285
|
-
# Doctest lines are excluded from size calculations
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## Troubleshooting
|
|
289
|
-
|
|
290
|
-
### Size Limits (Agent Quick Reference)
|
|
291
|
-
|
|
292
|
-
| Rule | Limit | Fix |
|
|
293
|
-
|------|-------|-----|
|
|
294
|
-
| `function_too_long` | **50 lines** | Extract helper: `_impl()` + main with docstring |
|
|
295
|
-
| `file_too_long` | **500 lines** | Split by responsibility |
|
|
296
|
-
| `entry_point_too_thick` | **15 lines** | Delegate to Shell functions |
|
|
297
|
-
|
|
298
|
-
*Doctest lines excluded from counts. Limits configurable in `pyproject.toml`.*
|
|
299
|
-
|
|
300
|
-
### Common Errors
|
|
301
|
-
|
|
302
|
-
| Symptom | Cause | Fix |
|
|
303
|
-
|---------|-------|-----|
|
|
304
|
-
| `param_mismatch` error | Lambda missing params | Include ALL params (even defaults) |
|
|
305
|
-
| `shell_result` error | Shell func no Result | Add Result[T,E] or @invar:allow |
|
|
306
|
-
| `is_failure()` not found | Wrong Result check | Use `isinstance(result, Failure)` |
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
*Protocol v5.0 — USBV workflow (DX-32) | [Examples](.invar/examples/)*
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
invar/__init__.py,sha256=HV5W2nywevBhAMgF7TIHdBoiFY4ETWVLBYAt_gZCPHU,1520
|
|
2
|
-
invar/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
invar/core/__init__.py,sha256=01TgQ2bqTFV4VFdksfqXYPa2WUqo-DpUWUkEcIUXFb4,218
|
|
4
|
-
invar/core/contracts.py,sha256=SOyF1KeJ6hrEwfQ09UzMt881OJKDXRbPTslKA6HzdKg,19085
|
|
5
|
-
invar/core/entry_points.py,sha256=1p6GRGTp9kA9spNkGKidFLlzLPheh6JO2XFb68Cr0sE,12209
|
|
6
|
-
invar/core/extraction.py,sha256=mScqEMEEQdsd-Z0jx9g3scK6Z1vI9l-ESjggXPIWHZ4,6112
|
|
7
|
-
invar/core/format_specs.py,sha256=P299aRHFMXyow8STwsvaT6Bg2ALPs2wSy7SByiRZZ-A,5610
|
|
8
|
-
invar/core/format_strategies.py,sha256=LifL97JbsF8WEkVNmQpq2htyFUC3pW21myAjtRGpSxU,5774
|
|
9
|
-
invar/core/formatter.py,sha256=rCGZhMpl4dPLrztgKDkNtAvnv2vKfomyIHl_6fThuno,11293
|
|
10
|
-
invar/core/hypothesis_strategies.py,sha256=_MfjG7KxkmJvuPsczr_1JayR_YmiDzU2jJ8fQPoKGgs,16517
|
|
11
|
-
invar/core/inspect.py,sha256=l1knohwpLRHSNySPUjyeBHJusnU0vYiQGj4dMVgQZIo,4381
|
|
12
|
-
invar/core/lambda_helpers.py,sha256=Ap1y7N0wpgCgPHwrs2pd7zD9Qq4Ptfd2iTliprXIkME,6457
|
|
13
|
-
invar/core/models.py,sha256=1bbhLijXHSe-o5SXQhbJgq8_EqPOOgsGKIrnWRwwtYM,13200
|
|
14
|
-
invar/core/must_use.py,sha256=7HnnbT53lb4dOT-1mL64pz0JbQYytuw4eejNVe7iWKY,5496
|
|
15
|
-
invar/core/parser.py,sha256=ucVpGziVzUvbkXT1n_SgOrYdStDEcNBqLuRGqK3_M5g,9205
|
|
16
|
-
invar/core/postcondition_scope.py,sha256=ykjVNqZZ1zItBmI7ebgmLW5vFGE-vpaLRTvSgWaJMgM,5245
|
|
17
|
-
invar/core/property_gen.py,sha256=_IvBJNUqd8pwu7wXuIProZn5RZksqFdmtXt3GnLU6Vo,14033
|
|
18
|
-
invar/core/purity.py,sha256=dt5dFy5V8Ch93iBJF5OuKUr1jjfimfY3oHLQD8KmLHw,12036
|
|
19
|
-
invar/core/purity_heuristics.py,sha256=vsgphC1XPIFtsoLB0xvp--AyaJHqlh83LyKXYda4pWc,4546
|
|
20
|
-
invar/core/references.py,sha256=64yGIdj9vL72Y4uUhJsi9pztZkuMnLN-7OcOziyxYMo,6339
|
|
21
|
-
invar/core/review_trigger.py,sha256=4GGHUmgbVsQJAob4OO6A8G7KrLcNMwNOuqHiT6Jc7cs,14085
|
|
22
|
-
invar/core/rule_meta.py,sha256=il_KUTjSlW1MOVgLguuLDS9wEdyqUe3CDvUx4gQjACo,10180
|
|
23
|
-
invar/core/rules.py,sha256=6MvqO4dQXYwYe3ICp1bT2s_33O7FkpGwUzOrgHL16X4,19962
|
|
24
|
-
invar/core/shell_analysis.py,sha256=i2A9SMqBI3Rb4Ai0QNTM7awIkSJIY6yZJVWS72lv0bY,6457
|
|
25
|
-
invar/core/shell_architecture.py,sha256=98EVdBFIs8tO-i9jKuzdmv7fLB4PKnyI-vKh5lxnB98,6538
|
|
26
|
-
invar/core/strategies.py,sha256=2DPl0z2p_CBNd4RlSbZzTeAy6Dq6cpCiBCB2p5qHHkk,8798
|
|
27
|
-
invar/core/suggestions.py,sha256=LCg2Dy9EHh_n1t9jATRZ0gTkgJkAEZk3vp2nuuCyr-s,15129
|
|
28
|
-
invar/core/sync_helpers.py,sha256=kd6VyFAcpKfkVcbDk3GaBi2n0EWOGICz4VmdxwbshfI,7523
|
|
29
|
-
invar/core/tautology.py,sha256=Pmn__a0Bt55W0lAQo1G5q8Ory9KuE23dRknKw45xxbs,9221
|
|
30
|
-
invar/core/template_helpers.py,sha256=E1UT7ct0DaUFlfHr9oTBvW4xfxAiS81rbmZHSucPw4c,881
|
|
31
|
-
invar/core/template_parser.py,sha256=vH3H8OX55scZ1hWh3xoA8oJMhgleKufCOhkTvsSuu_4,14730
|
|
32
|
-
invar/core/timeout_inference.py,sha256=BS2fJGmwOrLpYZUku4qrizgNDSIXVLFBslW-6sRAvpc,3451
|
|
33
|
-
invar/core/trivial_detection.py,sha256=KYP8jJb7QDeusAxFdX5NAML_H0NL5wLgMeBWDQmNqfU,6086
|
|
34
|
-
invar/core/utils.py,sha256=PyW8dcTLUEFD81xcvkz-LNnCwjIQefn08OUh23fM_Po,14266
|
|
35
|
-
invar/core/verification_routing.py,sha256=_jXi1txFCcUdnB3-Yavtuyk8N-XhEO_Vu_051Vuz27Y,5020
|
|
36
|
-
invar/core/patterns/__init__.py,sha256=79a3ucN0BI54RnIOe49lngKASpADygs1hll9ROCrP6s,1429
|
|
37
|
-
invar/core/patterns/detector.py,sha256=lZ2HPtDJDiGps8Y3e7jds3naZa1oGqDDscHRSX5Vv0s,8297
|
|
38
|
-
invar/core/patterns/p0_exhaustive.py,sha256=yK51l4VkriOUA6i6ujeNY3SDlogArVSW2SqtnAaMl0Y,6905
|
|
39
|
-
invar/core/patterns/p0_literal.py,sha256=eazGzNvTpDSeuZJZg9H4_1vukXREKO9GgzCQUSqAKVc,10705
|
|
40
|
-
invar/core/patterns/p0_newtype.py,sha256=T9T6vxgtRXrt2Ym_KNWuHeLNOUKFoMfqu7oE1IUAhCo,7562
|
|
41
|
-
invar/core/patterns/p0_nonempty.py,sha256=H5SXU0XNaW4H_gTw0NFN4cXckbPyTqAUl1KgGvVX9uM,10681
|
|
42
|
-
invar/core/patterns/p0_validation.py,sha256=AuPI7j2MRqBulXPCnAGVbPO2p1DVPjrM1avrIrgyCwQ,9563
|
|
43
|
-
invar/core/patterns/registry.py,sha256=XuwRBPnV5-5uMFsn66pjZV-qDkIVZezt3YH540Gi8Qs,7422
|
|
44
|
-
invar/core/patterns/types.py,sha256=d5wqYJUVF3PHYL5lv6DZnB3PWcZ_MWn7q3-PxrToAEc,5385
|
|
45
|
-
invar/mcp/__init__.py,sha256=n3S7QwMjSMqOMT8cI2jf9E0yZPjKmBOJyIYhq4WZ8TQ,226
|
|
46
|
-
invar/mcp/__main__.py,sha256=ZcIT2U6xUyGOWucl4jq422BDE3lRLjqyxb9pFylRBdk,219
|
|
47
|
-
invar/mcp/server.py,sha256=ay-w2YfSa1kTmBFx3x3jEgmNRC3NFEW0EYuZRt7M39w,12244
|
|
48
|
-
invar/shell/__init__.py,sha256=FFw1mNbh_97PeKPcHIqQpQ7mw-JoIvyLM1yOdxLw5uk,204
|
|
49
|
-
invar/shell/claude_hooks.py,sha256=KJAQ-a7-mvabJ2fgsC9wPMakvi7J43GCU6ZcpWwKYFg,16180
|
|
50
|
-
invar/shell/config.py,sha256=6-kbo6--SxfROXoyU-v7InSLR8f_U1Mar_xEOdCXFkY,17633
|
|
51
|
-
invar/shell/contract_coverage.py,sha256=UPn-lEqrAFu00fl7v9PnSvNwS7KX3_SV1K_GhynQ9cw,12023
|
|
52
|
-
invar/shell/coverage.py,sha256=m01o898IFIdBztEBQLwwL1Vt5PWrpUntO4lv4nWEkls,11344
|
|
53
|
-
invar/shell/fs.py,sha256=wVD7DPWsCIJXuTyY_pi-5_LS82mXRdn_grJCOLn9zpU,3699
|
|
54
|
-
invar/shell/git.py,sha256=s6RQxEDQuLrmK3mru88EoYP8__4hiFW8AozlcxmY47E,2784
|
|
55
|
-
invar/shell/guard_helpers.py,sha256=QeYgbW0lgUa9Z_RCjAMG7UJdiMzz5cW48Lb2u-qgQi8,15114
|
|
56
|
-
invar/shell/guard_output.py,sha256=v3gG5P-_47nIFo8eAMKwdA_hLf2KZ0cQ-45Z6JjKp4w,12520
|
|
57
|
-
invar/shell/mcp_config.py,sha256=-hC7Y5BGuVs285b6gBARk7ZyzVxHwPgXSyt_GoN0jfs,4580
|
|
58
|
-
invar/shell/mutation.py,sha256=Lfyk2b8j8-hxAq-iwAgQeOhr7Ci6c5tRF1TXe3CxQCs,8914
|
|
59
|
-
invar/shell/pattern_integration.py,sha256=pRcjfq3NvMW_tvQCnaXZnD1k5AVEWK8CYOE2jN6VTro,7842
|
|
60
|
-
invar/shell/pi_hooks.py,sha256=ln71f6SkjQ_7pMt6_udzeqgRaRIk3Y11XobLURBP2v0,6597
|
|
61
|
-
invar/shell/property_tests.py,sha256=N9JreyH5PqR89oF5yLcX7ZAV-Koyg5BKo-J05-GUPsA,9109
|
|
62
|
-
invar/shell/subprocess_env.py,sha256=9oXl3eMEbzLsFEgMHqobEw6oW_wV0qMEP7pklwm58Pw,11453
|
|
63
|
-
invar/shell/template_engine.py,sha256=IzOiGsKVFo0lDUdtg27wMzIJJKToclv151RDZuDnHHo,11027
|
|
64
|
-
invar/shell/templates.py,sha256=30eT61HXPA6DmsgUyUqljZNGGtB9TSR-aAaI4fmKAco,13722
|
|
65
|
-
invar/shell/testing.py,sha256=rTNBH0Okh2qtG9ohSXOz487baQ2gXrWT3s_WECW3HJs,11143
|
|
66
|
-
invar/shell/commands/__init__.py,sha256=MEkKwVyjI9DmkvBpJcuumXo2Pg_FFkfEr-Rr3nrAt7A,284
|
|
67
|
-
invar/shell/commands/guard.py,sha256=vDBGOFb9mQ1D8eXrMvQB505GpjO1XLeCLrv2ig9-6dU,21718
|
|
68
|
-
invar/shell/commands/hooks.py,sha256=W-SOnT4VQyUvXwipozkJwgEYfiOJGz7wksrbcdWegUg,2356
|
|
69
|
-
invar/shell/commands/init.py,sha256=ASl01hIYW3Dt_d5XhYPwDfdRujbKvBGfK8B9Sf4eXq0,15117
|
|
70
|
-
invar/shell/commands/merge.py,sha256=nuvKo8m32-OL-SCQlS4SLKmOZxQ3qj-1nGCx1Pgzifw,8183
|
|
71
|
-
invar/shell/commands/mutate.py,sha256=GwemiO6LlbGCBEQsBFnzZuKhF-wIMEl79GAMnKUWc8U,5765
|
|
72
|
-
invar/shell/commands/perception.py,sha256=TyH_HpqyKkmE3-zcU4YyBG8ghwJaSFeRC-OQMVBDTbQ,3837
|
|
73
|
-
invar/shell/commands/sync_self.py,sha256=nmqBry7V2_enKwy2zzHg8UoedZNicLe3yKDhjmBeZ68,3880
|
|
74
|
-
invar/shell/commands/template_sync.py,sha256=wVZ-UvJ1wpN2UBcWMfbei0n46XHYx-zRbMA2oX6FSi4,13723
|
|
75
|
-
invar/shell/commands/test.py,sha256=goMf-ovvzEyWQMheq4YlJ-mwK5-w3lDj0cq0IA_1-_c,4205
|
|
76
|
-
invar/shell/commands/uninstall.py,sha256=Q2tDbGLUf0PC2xxWqmuBYwfxX7IuSQ_SmyxvwYcDyPo,18102
|
|
77
|
-
invar/shell/commands/update.py,sha256=0V5F8vxQ6PHPHPVYDmxdRD7xXeQEFypiJMYpY5ryiek,1349
|
|
78
|
-
invar/shell/prove/__init__.py,sha256=ZqlbmyMFJf6yAle8634jFuPRv8wNvHps8loMlOJyf8A,240
|
|
79
|
-
invar/shell/prove/accept.py,sha256=cnY_6jzU1EBnpLF8-zWUWcXiSXtCwxPsXEYXsSVPG38,3717
|
|
80
|
-
invar/shell/prove/cache.py,sha256=jbNdrvfLjvK7S0iqugErqeabb4YIbQuwIlcSRyCKbcg,4105
|
|
81
|
-
invar/shell/prove/crosshair.py,sha256=4Z_iIYBlkp-I6FqSYZa89wWB09V4Ouw2PduYhTn6rfw,16525
|
|
82
|
-
invar/shell/prove/hypothesis.py,sha256=QUclOOUg_VB6wbmHw8O2EPiL5qBOeBRqQeM04AVuLw0,9880
|
|
83
|
-
invar/templates/CLAUDE.md.template,sha256=eaGU3SyRO_NEifw5b26k3srgQH4jyeujjCJ-HbM36_w,4913
|
|
84
|
-
invar/templates/__init__.py,sha256=cb3ht8KPK5oBn5oG6HsTznujmo9WriJ_P--fVxJwycc,45
|
|
85
|
-
invar/templates/context.md.template,sha256=FKyI1ghpqcf4wftyv9-auIFHor8Nm8lETN45Ja-L8Og,2386
|
|
86
|
-
invar/templates/manifest.toml,sha256=afovCokbqEh0nyDGdIp1LqTUslJdC8T2HY6MV-NvegY,4331
|
|
87
|
-
invar/templates/proposal.md.template,sha256=UP7SpQ7gk8jVlHGLQCSQ5c-kCj1DBQEz8M-vEStK77I,1573
|
|
88
|
-
invar/templates/commands/audit.md,sha256=OrotO8420zTKnlNyAyL1Eos0VIaihzEU4AHdfDv68Oc,4162
|
|
89
|
-
invar/templates/commands/guard.md,sha256=N_C_AXd9kI85W1B0aTEycjiDp_jdaP8eeq8O0FQ_WQ8,1227
|
|
90
|
-
invar/templates/config/AGENT.md.jinja,sha256=tadNeX5G_XLLdbLiG1JSQm_Xjmt1kAJ3IrTaw_sDU9g,5275
|
|
91
|
-
invar/templates/config/CLAUDE.md.jinja,sha256=VbtDWxn3H8qiE9-DV1hlG3DJ-GcBQU4ZiUHbFh6Bxxk,7814
|
|
92
|
-
invar/templates/config/context.md.jinja,sha256=_kJ8erEQNJMLDCKrv4BXWkO6OaGzE-zW9biCf7144aY,3103
|
|
93
|
-
invar/templates/config/pre-commit.yaml.jinja,sha256=nUPxLxkTHAgZwhFAuOMDbZ8v0NQV9FlQPbr2MDEOsoA,1778
|
|
94
|
-
invar/templates/examples/README.md,sha256=xMcJZ1KEcfLJi5Ope_4FIbqDWKK3mRleAgllvgeNT6I,572
|
|
95
|
-
invar/templates/examples/conftest.py,sha256=uKA4NR7nyZWeSzY0URdZtw5zCcJpU32jNcaSKrI1Mxc,152
|
|
96
|
-
invar/templates/examples/contracts.py,sha256=uqJ6Y1GADo246MjFKoLY-_2E74cfBQsLO4vTqYcR81c,3241
|
|
97
|
-
invar/templates/examples/core_shell.py,sha256=ckor-7ZoaF7n8gVjnIO0CXlBjKGcVwmOGSDJbaXCSrM,4247
|
|
98
|
-
invar/templates/examples/workflow.md,sha256=jAopzQH1xE9_leJFdav4oj1AkI46-a2q4L8RQCkDknw,2334
|
|
99
|
-
invar/templates/hooks/PostToolUse.sh.jinja,sha256=H-lzVaEMvlr0uoO2LxrGNpWrBtyUkHmYrhtWmCqdAjI,2967
|
|
100
|
-
invar/templates/hooks/PreToolUse.sh.jinja,sha256=D39PaT1eFSjz_Av16xK1atoBZbhLI8tLp8L12zkG-3k,2334
|
|
101
|
-
invar/templates/hooks/Stop.sh.jinja,sha256=3S6lLeAGIu5aPQVRz4jjFS9AfjCD9DdS_jagmkw-x8Q,960
|
|
102
|
-
invar/templates/hooks/UserPromptSubmit.sh.jinja,sha256=eAQqQ-XdOCyhLpF5_1r1z7C-Ej9GQ5Isqbu_2LAtsno,2302
|
|
103
|
-
invar/templates/hooks/__init__.py,sha256=RnnMoQA-8eqbr8Y_1Vu9B8h5vAz4C-vmo8wgdcGYrz0,43
|
|
104
|
-
invar/templates/hooks/pi/invar.ts.jinja,sha256=D1TRxHuNkmjhICPOxjcyoRUZryyz7MpfIvBLjm-krjA,2234
|
|
105
|
-
invar/templates/protocol/INVAR.md,sha256=ppQhb_-R5YaXAqW1WDMOcXptx-CrAQI_xYxld7YljK8,9998
|
|
106
|
-
invar/templates/skills/develop/SKILL.md.jinja,sha256=kCKXTgHtfqED__Udn3dM6OxG0FQZx1NsjFhHtDNExJA,12558
|
|
107
|
-
invar/templates/skills/investigate/SKILL.md.jinja,sha256=cp6TBEixBYh1rLeeHOR1yqEnFqv1NZYePORMnavLkQI,3231
|
|
108
|
-
invar/templates/skills/propose/SKILL.md.jinja,sha256=6BuKiCqO1AEu3VtzMHy1QWGqr_xqG9eJlhbsKT4jev4,3463
|
|
109
|
-
invar/templates/skills/review/SKILL.md.jinja,sha256=OvKoomS4MJHYbTuWSZjmeS_q_Wh6uNHzjXaewj6ELEg,14596
|
|
110
|
-
invar_tools-1.8.0.dist-info/METADATA,sha256=51-iej0SZ6ramV9uMvwlxBUZYbXTQAUc1Mi5GHJGvDw,18295
|
|
111
|
-
invar_tools-1.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
112
|
-
invar_tools-1.8.0.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
|
|
113
|
-
invar_tools-1.8.0.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
|
|
114
|
-
invar_tools-1.8.0.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
|
|
115
|
-
invar_tools-1.8.0.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
|
|
116
|
-
invar_tools-1.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|