invar-tools 1.7.1__py3-none-any.whl → 1.10.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/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/template_helpers.py +32 -0
- invar/core/ts_parsers.py +286 -0
- invar/core/ts_sig_parser.py +307 -0
- 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/guard.py +36 -1
- invar/shell/commands/init.py +133 -7
- 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 +77 -12
- invar/shell/commands/update.py +6 -14
- invar/shell/contract_coverage.py +1 -0
- invar/shell/fs.py +66 -13
- invar/shell/pi_hooks.py +213 -0
- invar/shell/prove/guard_ts.py +899 -0
- invar/shell/skill_manager.py +353 -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 +256 -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 +82 -0
- invar/templates/manifest.toml +8 -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 +98 -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/investigate/SKILL.md.jinja +15 -0
- invar/templates/skills/propose/SKILL.md.jinja +33 -0
- invar/templates/skills/review/SKILL.md.jinja +346 -71
- {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/METADATA +326 -19
- invar_tools-1.10.0.dist-info/RECORD +173 -0
- invar/templates/examples/core_shell.py +0 -127
- invar/templates/protocol/INVAR.md +0 -310
- invar_tools-1.7.1.dist-info/RECORD +0 -112
- /invar/templates/examples/{workflow.md → python/workflow.md} +0 -0
- {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/WHEEL +0 -0
- {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/entry_points.txt +0 -0
- {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/licenses/LICENSE +0 -0
- {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/licenses/LICENSE-GPL +0 -0
- {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -48,11 +48,20 @@ is_git_repo() {
|
|
|
48
48
|
detect_changes() {
|
|
49
49
|
if is_git_repo; then
|
|
50
50
|
# Primary: Git-based detection (includes staged + unstaged)
|
|
51
|
+
{% if language == "python" -%}
|
|
51
52
|
{ git diff --name-only -- '*.py' 2>/dev/null; git diff --cached --name-only -- '*.py' 2>/dev/null; } | sort -u
|
|
53
|
+
{% elif language == "typescript" -%}
|
|
54
|
+
{ git diff --name-only -- '*.ts' '*.tsx' 2>/dev/null; git diff --cached --name-only -- '*.ts' '*.tsx' 2>/dev/null; } | sort -u
|
|
55
|
+
{% endif -%}
|
|
52
56
|
elif [[ -f "$LAST_CHECK_MARKER" ]]; then
|
|
53
57
|
# Fallback: Timestamp-based detection (approximate)
|
|
58
|
+
{% if language == "python" -%}
|
|
54
59
|
find . -name "*.py" -newer "$LAST_CHECK_MARKER" -type f 2>/dev/null | \
|
|
55
60
|
grep -v __pycache__ | grep -v '.venv' | head -20
|
|
61
|
+
{% elif language == "typescript" -%}
|
|
62
|
+
find . \( -name "*.ts" -o -name "*.tsx" \) -newer "$LAST_CHECK_MARKER" -type f 2>/dev/null | \
|
|
63
|
+
grep -v node_modules | grep -v dist | head -20
|
|
64
|
+
{% endif -%}
|
|
56
65
|
fi
|
|
57
66
|
# Update marker for next check
|
|
58
67
|
touch "$LAST_CHECK_MARKER" 2>/dev/null
|
|
@@ -68,7 +77,7 @@ fi
|
|
|
68
77
|
# ============================================
|
|
69
78
|
# Smart trigger evaluation
|
|
70
79
|
# ============================================
|
|
71
|
-
CHANGE_COUNT=$(wc -l < "$CHANGES_FILE"
|
|
80
|
+
CHANGE_COUNT=$([[ -f "$CHANGES_FILE" ]] && wc -l < "$CHANGES_FILE" | tr -d ' ' || echo 0)
|
|
72
81
|
LAST_TIME=$(cat "$LAST_GUARD" 2>/dev/null || echo 0)
|
|
73
82
|
NOW=$(date +%s)
|
|
74
83
|
ELAPSED=$((NOW - LAST_TIME))
|
|
@@ -22,6 +22,7 @@ else
|
|
|
22
22
|
fi
|
|
23
23
|
[[ -z "$CMD" ]] && exit 0
|
|
24
24
|
|
|
25
|
+
{% if language == "python" -%}
|
|
25
26
|
# ============================================
|
|
26
27
|
# pytest blocking with smart escape
|
|
27
28
|
# ============================================
|
|
@@ -70,5 +71,42 @@ if echo "$CMD" | grep -qE '\bcrosshair\b'; then
|
|
|
70
71
|
echo " Manual escape: INVAR_ALLOW_CROSSHAIR=1 crosshair ..."
|
|
71
72
|
exit 1
|
|
72
73
|
fi
|
|
74
|
+
{% elif language == "typescript" -%}
|
|
75
|
+
# ============================================
|
|
76
|
+
# jest/vitest blocking with smart escape
|
|
77
|
+
# ============================================
|
|
78
|
+
if echo "$CMD" | grep -qE '\bjest\b|\bvitest\b|npx\s+(jest|vitest)\b|npm\s+(run\s+)?test\b'; then
|
|
79
|
+
|
|
80
|
+
# Auto-escape 1: Debugging mode
|
|
81
|
+
if echo "$CMD" | grep -qE '\-\-inspect|\-\-debug'; then
|
|
82
|
+
echo "⚠️ Test debugging allowed. Run {{ guard_cmd }} after."
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Auto-escape 2: External/vendor tests
|
|
87
|
+
if echo "$CMD" | grep -qE 'vendor/|third_party/|external/'; then
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Auto-escape 3: Explicit coverage collection
|
|
92
|
+
if echo "$CMD" | grep -qE '\-\-coverage'; then
|
|
93
|
+
echo "⚠️ Test coverage allowed. Run {{ guard_cmd }} for contract verification."
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Auto-escape 4: Environment variable override
|
|
98
|
+
if [[ "$INVAR_ALLOW_JEST" == "1" ]]; then
|
|
99
|
+
exit 0
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Default: Block with helpful message
|
|
103
|
+
echo "❌ Use {{ guard_cmd }} instead of jest/vitest"
|
|
104
|
+
echo " {{ guard_cmd }} = tsc + eslint + vitest + fast-check"
|
|
105
|
+
echo ""
|
|
106
|
+
echo " Auto-allowed: --inspect (debug), --coverage"
|
|
107
|
+
echo " Manual escape: INVAR_ALLOW_JEST=1 jest ..."
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
{% endif -%}
|
|
73
111
|
|
|
74
112
|
exit 0
|
|
@@ -13,7 +13,7 @@ if [[ -f "$CHANGES_FILE" ]]; then
|
|
|
13
13
|
if [[ $CHANGE_COUNT -gt 0 ]]; then
|
|
14
14
|
echo ""
|
|
15
15
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
16
|
-
echo "⚠️ Invar: $CHANGE_COUNT
|
|
16
|
+
echo "⚠️ Invar: $CHANGE_COUNT {{ language | capitalize }} files not verified"
|
|
17
17
|
echo " Run before commit: {{ guard_cmd }} --changed"
|
|
18
18
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
19
19
|
fi
|
|
@@ -41,10 +41,17 @@ echo "$COUNT" > "$COUNT_FILE"
|
|
|
41
41
|
# Keyword triggers (independent of count)
|
|
42
42
|
# ============================================
|
|
43
43
|
|
|
44
|
+
{% if language == "python" -%}
|
|
44
45
|
# pytest intent → immediate correction
|
|
45
46
|
if echo "$USER_MESSAGE" | grep -qiE "run.*pytest|pytest.*test|用.*pytest"; then
|
|
46
47
|
echo "<system-reminder>Use {{ guard_cmd }}, not pytest.</system-reminder>"
|
|
47
48
|
fi
|
|
49
|
+
{% elif language == "typescript" -%}
|
|
50
|
+
# jest/vitest intent → immediate correction
|
|
51
|
+
if echo "$USER_MESSAGE" | grep -qiE "run.*jest|run.*vitest|npm.*test|用.*jest|用.*vitest"; then
|
|
52
|
+
echo "<system-reminder>Use {{ guard_cmd }}, not jest/vitest directly.</system-reminder>"
|
|
53
|
+
fi
|
|
54
|
+
{% endif -%}
|
|
48
55
|
|
|
49
56
|
# Implementation intent → workflow reminder (after warmup)
|
|
50
57
|
if [[ $COUNT -gt 3 ]]; then
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invar Pi Hook
|
|
3
|
+
* Protocol: v{{ protocol_version }} | Generated: {{ generated_date }}
|
|
4
|
+
* LX-04: Full feature parity with Claude Code hooks
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - pytest/crosshair blocking via tool_call
|
|
8
|
+
* - Protocol injection via pi.send() for long conversations
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
|
12
|
+
|
|
13
|
+
// Blocked commands (same as Claude Code)
|
|
14
|
+
{% if language == "python" -%}
|
|
15
|
+
const BLOCKED_CMDS = [/^pytest\b/, /^python\s+-m\s+pytest/, /^crosshair\b/];
|
|
16
|
+
const ALLOWED_FLAGS = [/--pdb/, /--cov/, /--debug/];
|
|
17
|
+
{% elif language == "typescript" -%}
|
|
18
|
+
const BLOCKED_CMDS = [/^jest\b/, /^vitest\b/, /^npx\s+(jest|vitest)\b/, /^npm\s+(run\s+)?test\b/];
|
|
19
|
+
const ALLOWED_FLAGS = [/--inspect/, /--coverage/, /--debug/];
|
|
20
|
+
{% endif -%}
|
|
21
|
+
|
|
22
|
+
// Protocol content for injection (escaped for JS)
|
|
23
|
+
const INVAR_PROTOCOL = `{{ invar_protocol_escaped }}`;
|
|
24
|
+
|
|
25
|
+
export default function (pi: HookAPI) {
|
|
26
|
+
let msgCount = 0;
|
|
27
|
+
|
|
28
|
+
// ============================================
|
|
29
|
+
// Session Management
|
|
30
|
+
// ============================================
|
|
31
|
+
pi.on("session", async (event) => {
|
|
32
|
+
// Reset count on session start/restore
|
|
33
|
+
if (event.reason === "start" || event.reason === "branch") {
|
|
34
|
+
msgCount = 0;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// ============================================
|
|
39
|
+
// Long Conversation Protocol Refresh
|
|
40
|
+
// ============================================
|
|
41
|
+
pi.on("agent_start", async () => {
|
|
42
|
+
msgCount++;
|
|
43
|
+
|
|
44
|
+
// Message 15: Lightweight checkpoint
|
|
45
|
+
if (msgCount === 15) {
|
|
46
|
+
pi.send(
|
|
47
|
+
"<system-reminder>Checkpoint: guard=verify, sig=contracts, USBV workflow.</system-reminder>"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Message 25+: Full protocol injection every 10 messages
|
|
52
|
+
if (msgCount >= 25 && msgCount % 10 === 0) {
|
|
53
|
+
pi.send(`<system-reminder>
|
|
54
|
+
=== Protocol Refresh (message ${msgCount}) ===
|
|
55
|
+
${INVAR_PROTOCOL}
|
|
56
|
+
</system-reminder>`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// ============================================
|
|
61
|
+
// pytest/crosshair Blocking
|
|
62
|
+
// ============================================
|
|
63
|
+
pi.on("tool_call", async (event) => {
|
|
64
|
+
if (event.toolName !== "bash") return;
|
|
65
|
+
const cmd = ((event.input as Record<string, unknown>).command as string || "").trim();
|
|
66
|
+
|
|
67
|
+
// Skip if not a blocked command
|
|
68
|
+
if (!BLOCKED_CMDS.some((p) => p.test(cmd))) return;
|
|
69
|
+
|
|
70
|
+
// Allow if has debug/test flags
|
|
71
|
+
if (ALLOWED_FLAGS.some((p) => p.test(cmd))) return;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
block: true,
|
|
75
|
+
{% if language == "python" -%}
|
|
76
|
+
reason: "Use `{{ guard_cmd }}` instead of pytest/crosshair.",
|
|
77
|
+
{% elif language == "typescript" -%}
|
|
78
|
+
reason: "Use `{{ guard_cmd }}` instead of jest/vitest.",
|
|
79
|
+
{% endif -%}
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
invar/templates/manifest.toml
CHANGED
|
@@ -49,11 +49,12 @@ extensions = { action = "preserve" }
|
|
|
49
49
|
# =============================================================================
|
|
50
50
|
|
|
51
51
|
[templates]
|
|
52
|
-
# Protocol files (
|
|
53
|
-
"INVAR.md" = { src = "protocol/INVAR.md", type = "
|
|
52
|
+
# Protocol files (Jinja2 composition - LX-05)
|
|
53
|
+
"INVAR.md" = { src = "protocol/INVAR.md.jinja", type = "jinja" }
|
|
54
54
|
|
|
55
55
|
# Config files (Jinja2 templates)
|
|
56
56
|
"CLAUDE.md" = { src = "config/CLAUDE.md.jinja", type = "jinja" }
|
|
57
|
+
"AGENT.md" = { src = "config/AGENT.md.jinja", type = "jinja" }
|
|
57
58
|
".invar/context.md" = { src = "config/context.md.jinja", type = "jinja" }
|
|
58
59
|
".pre-commit-config.yaml" = { src = "config/pre-commit.yaml.jinja", type = "jinja" }
|
|
59
60
|
|
|
@@ -63,12 +64,12 @@ extensions = { action = "preserve" }
|
|
|
63
64
|
".claude/skills/propose/SKILL.md" = { src = "skills/propose/SKILL.md.jinja", type = "jinja" }
|
|
64
65
|
".claude/skills/review/SKILL.md" = { src = "skills/review/SKILL.md.jinja", type = "jinja" }
|
|
65
66
|
|
|
66
|
-
# Commands (
|
|
67
|
-
".claude/commands/audit.md" = { src = "commands/audit.md", type = "
|
|
67
|
+
# Commands (Jinja2 templates for language-specific content)
|
|
68
|
+
".claude/commands/audit.md" = { src = "commands/audit.md.jinja", type = "jinja" }
|
|
68
69
|
".claude/commands/guard.md" = { src = "commands/guard.md", type = "copy" }
|
|
69
70
|
|
|
70
|
-
# Examples (directory copy)
|
|
71
|
-
".invar/examples/" = { src = "examples/", type = "
|
|
71
|
+
# Examples (language-aware directory copy - LX-05 hotfix)
|
|
72
|
+
".invar/examples/" = { src = "examples/{language}/", type = "copy_dir_lang" }
|
|
72
73
|
|
|
73
74
|
# =============================================================================
|
|
74
75
|
# Variables
|
|
@@ -77,6 +78,7 @@ extensions = { action = "preserve" }
|
|
|
77
78
|
[variables]
|
|
78
79
|
# Available for Jinja2 templates
|
|
79
80
|
syntax = "cli" # "cli" or "mcp"
|
|
81
|
+
language = "python" # "python" or "typescript" (LX-05)
|
|
80
82
|
version = "5.0"
|
|
81
83
|
project_name = "" # Set by init
|
|
82
84
|
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
{#
|
|
2
|
+
Expected variables:
|
|
3
|
+
- project_name: str
|
|
4
|
+
- timestamp: str
|
|
5
|
+
- invar_version: str
|
|
6
|
+
- language: str
|
|
7
|
+
- framework?: str (default "N/A")
|
|
8
|
+
- loc: int
|
|
9
|
+
- files: int
|
|
10
|
+
- test_type: str
|
|
11
|
+
- test_count: int
|
|
12
|
+
- compatibility: int (0-100)
|
|
13
|
+
- total_days: int
|
|
14
|
+
- risk_level: str ("Low" | "Medium" | "High")
|
|
15
|
+
- architecture_diagram: str
|
|
16
|
+
- dependency_map?: str
|
|
17
|
+
- current_error, gap_error: str
|
|
18
|
+
- current_validation, gap_validation: str
|
|
19
|
+
- current_separation, gap_separation: str
|
|
20
|
+
- current_test, gap_test: str
|
|
21
|
+
- error_patterns?: [{type: str, count: int, locations: [str]}]
|
|
22
|
+
- validation_patterns?: [{library: str, usage: str, files: [str]}]
|
|
23
|
+
- high_risk_areas?: [{name: str, reason: str, files: [str], impact: str}]
|
|
24
|
+
- blockers?: [{name: str, description: str, mitigation: str}]
|
|
25
|
+
- dependency_risks?: [{name: str, risk_level: str, reason: str}]
|
|
26
|
+
- phase1_days, phase2_days, phase3_days, phase4_days, phase5_days: int
|
|
27
|
+
- contract_type: str
|
|
28
|
+
- base_effort: float
|
|
29
|
+
- adjustments: [{factor: str, reason: str}]
|
|
30
|
+
- adjustment_formula: str
|
|
31
|
+
- recommendation: str
|
|
32
|
+
- result_library: str
|
|
33
|
+
- additional_prereqs?: [str]
|
|
34
|
+
- quick_wins?: [{name: str, description: str, effort: str, impact: str}]
|
|
35
|
+
- layers: [{name: str, files: int, loc: int, notes?: str}]
|
|
36
|
+
- priority_files: [{path: str, loc: int, current_state: str, target_state: str, dependencies?: [str]}]
|
|
37
|
+
#}
|
|
38
|
+
# Invar Onboarding Assessment
|
|
39
|
+
|
|
40
|
+
> Project: {{ project_name }}
|
|
41
|
+
> Assessed: {{ timestamp }}
|
|
42
|
+
> Invar Version: {{ invar_version }}
|
|
43
|
+
|
|
44
|
+
## 1. Summary
|
|
45
|
+
|
|
46
|
+
| Metric | Value |
|
|
47
|
+
|--------|-------|
|
|
48
|
+
| Primary Language | {{ language }} |
|
|
49
|
+
| Framework | {{ framework | default("N/A") }} |
|
|
50
|
+
| Code Size | {{ loc }} lines / {{ files }} files |
|
|
51
|
+
| Test Coverage | {{ test_type }}: {{ test_count }} tests |
|
|
52
|
+
| **Invar Compatibility** | **{{ compatibility }}%** |
|
|
53
|
+
| **Estimated Effort** | **{{ total_days }} days** |
|
|
54
|
+
| **Risk Level** | **{{ risk_level }}** |
|
|
55
|
+
|
|
56
|
+
## 2. Architecture Analysis
|
|
57
|
+
|
|
58
|
+
### 2.1 Layer Structure
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
{{ architecture_diagram }}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2.2 Dependency Map
|
|
65
|
+
|
|
66
|
+
{% if dependency_map %}
|
|
67
|
+
{{ dependency_map }}
|
|
68
|
+
{% else %}
|
|
69
|
+
*No complex dependencies detected.*
|
|
70
|
+
{% endif %}
|
|
71
|
+
|
|
72
|
+
## 3. Pattern Analysis
|
|
73
|
+
|
|
74
|
+
| Dimension | Current | Invar Target | Gap |
|
|
75
|
+
|-----------|---------|--------------|-----|
|
|
76
|
+
| Error Handling | {{ current_error }} | Result[T, E] / Result<T, E> | {{ gap_error }} |
|
|
77
|
+
| Validation | {{ current_validation }} | @pre/@post / Zod | {{ gap_validation }} |
|
|
78
|
+
| Core/Shell | {{ current_separation }} | Explicit separation | {{ gap_separation }} |
|
|
79
|
+
| Testing | {{ current_test }} | Doctest + Property | {{ gap_test }} |
|
|
80
|
+
|
|
81
|
+
### 3.1 Error Handling Details
|
|
82
|
+
|
|
83
|
+
{% if error_patterns %}
|
|
84
|
+
| Pattern | Count | Location |
|
|
85
|
+
|---------|-------|----------|
|
|
86
|
+
{% for pattern in error_patterns %}
|
|
87
|
+
| {{ pattern.type }} | {{ pattern.count }} | {{ pattern.locations | join(", ") }} |
|
|
88
|
+
{% endfor %}
|
|
89
|
+
{% else %}
|
|
90
|
+
*No error handling patterns detected.*
|
|
91
|
+
{% endif %}
|
|
92
|
+
|
|
93
|
+
### 3.2 Validation Details
|
|
94
|
+
|
|
95
|
+
{% if validation_patterns %}
|
|
96
|
+
| Library | Usage | Files |
|
|
97
|
+
|---------|-------|-------|
|
|
98
|
+
{% for pattern in validation_patterns %}
|
|
99
|
+
| {{ pattern.library }} | {{ pattern.usage }} | {{ pattern.files | join(", ") }} |
|
|
100
|
+
{% endfor %}
|
|
101
|
+
{% else %}
|
|
102
|
+
*No validation libraries detected.*
|
|
103
|
+
{% endif %}
|
|
104
|
+
|
|
105
|
+
## 4. Risk Assessment
|
|
106
|
+
|
|
107
|
+
### 4.1 High Risk Areas
|
|
108
|
+
|
|
109
|
+
{% if high_risk_areas %}
|
|
110
|
+
{% for area in high_risk_areas %}
|
|
111
|
+
- **{{ area.name }}**: {{ area.reason }}
|
|
112
|
+
- Files: {{ area.files | join(", ") }}
|
|
113
|
+
- Impact: {{ area.impact }}
|
|
114
|
+
{% endfor %}
|
|
115
|
+
{% else %}
|
|
116
|
+
*No high risk areas identified.*
|
|
117
|
+
{% endif %}
|
|
118
|
+
|
|
119
|
+
### 4.2 Blockers
|
|
120
|
+
|
|
121
|
+
{% if blockers %}
|
|
122
|
+
{% for blocker in blockers %}
|
|
123
|
+
- [ ] **{{ blocker.name }}**: {{ blocker.description }}
|
|
124
|
+
- Mitigation: {{ blocker.mitigation }}
|
|
125
|
+
{% endfor %}
|
|
126
|
+
{% else %}
|
|
127
|
+
*No blockers identified.*
|
|
128
|
+
{% endif %}
|
|
129
|
+
|
|
130
|
+
### 4.3 Dependency Risks
|
|
131
|
+
|
|
132
|
+
{% if dependency_risks %}
|
|
133
|
+
| Dependency | Risk | Reason |
|
|
134
|
+
|------------|------|--------|
|
|
135
|
+
{% for dep in dependency_risks %}
|
|
136
|
+
| {{ dep.name }} | {{ dep.risk_level }} | {{ dep.reason }} |
|
|
137
|
+
{% endfor %}
|
|
138
|
+
{% else %}
|
|
139
|
+
*No dependency risks identified.*
|
|
140
|
+
{% endif %}
|
|
141
|
+
|
|
142
|
+
## 5. Effort Breakdown
|
|
143
|
+
|
|
144
|
+
| Phase | Scope | Estimate |
|
|
145
|
+
|-------|-------|----------|
|
|
146
|
+
| Foundation | Error types, Result infrastructure | {{ phase1_days }} days |
|
|
147
|
+
| Core Extraction | Pure function isolation | {{ phase2_days }} days |
|
|
148
|
+
| Shell Refactor | I/O layer Result conversion | {{ phase3_days }} days |
|
|
149
|
+
| Contracts | {{ contract_type }} | {{ phase4_days }} days |
|
|
150
|
+
| Validation | Guard integration, test coverage | {{ phase5_days }} days |
|
|
151
|
+
| **Total** | | **{{ total_days }} days** |
|
|
152
|
+
|
|
153
|
+
### 5.1 Estimation Factors
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
Base effort: {{ base_effort }} days ({{ loc }} LOC / 100)
|
|
157
|
+
|
|
158
|
+
Adjustments:
|
|
159
|
+
{% for adj in adjustments %}
|
|
160
|
+
{{ adj.factor }} {{ adj.reason }}
|
|
161
|
+
{% endfor %}
|
|
162
|
+
|
|
163
|
+
Final: {{ base_effort }} {{ adjustment_formula }} = {{ total_days }} days
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 6. Recommendations
|
|
167
|
+
|
|
168
|
+
### 6.1 Suggested Approach
|
|
169
|
+
|
|
170
|
+
{{ recommendation }}
|
|
171
|
+
|
|
172
|
+
### 6.2 Prerequisites
|
|
173
|
+
|
|
174
|
+
- [ ] E2E test coverage > 80% for critical paths
|
|
175
|
+
- [ ] Result library installed ({{ result_library }})
|
|
176
|
+
- [ ] Error type hierarchy defined
|
|
177
|
+
{% for prereq in additional_prereqs %}
|
|
178
|
+
- [ ] {{ prereq }}
|
|
179
|
+
{% endfor %}
|
|
180
|
+
|
|
181
|
+
### 6.3 Quick Wins
|
|
182
|
+
|
|
183
|
+
{% if quick_wins %}
|
|
184
|
+
{% for win in quick_wins %}
|
|
185
|
+
1. **{{ win.name }}**: {{ win.description }}
|
|
186
|
+
- Effort: {{ win.effort }}
|
|
187
|
+
- Impact: {{ win.impact }}
|
|
188
|
+
{% endfor %}
|
|
189
|
+
{% else %}
|
|
190
|
+
*No quick wins identified.*
|
|
191
|
+
{% endif %}
|
|
192
|
+
|
|
193
|
+
## 7. File Analysis
|
|
194
|
+
|
|
195
|
+
### 7.1 Files by Layer (Proposed)
|
|
196
|
+
|
|
197
|
+
| Layer | Files | LOC | Notes |
|
|
198
|
+
|-------|-------|-----|-------|
|
|
199
|
+
{% for layer in layers %}
|
|
200
|
+
| {{ layer.name }} | {{ layer.files }} | {{ layer.loc }} | {{ layer.notes | default("") }} |
|
|
201
|
+
{% endfor %}
|
|
202
|
+
|
|
203
|
+
### 7.2 Migration Priority
|
|
204
|
+
|
|
205
|
+
{% for file in priority_files %}
|
|
206
|
+
{{ loop.index }}. `{{ file.path }}` ({{ file.loc }} lines)
|
|
207
|
+
- Current: {{ file.current_state }}
|
|
208
|
+
- Target: {{ file.target_state }}
|
|
209
|
+
- Dependencies: {{ file.dependencies | join(", ") | default("None") }}
|
|
210
|
+
{% endfor %}
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
*Generated by /invar-onboard*
|