@event4u/agent-config 1.17.0 → 1.19.0

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.
Files changed (158) hide show
  1. package/.agent-src/commands/council/default.md +74 -76
  2. package/.agent-src/commands/feature/roadmap.md +22 -0
  3. package/.agent-src/commands/roadmap/create.md +38 -6
  4. package/.agent-src/commands/roadmap/execute.md +36 -9
  5. package/.agent-src/rules/agent-authority.md +1 -0
  6. package/.agent-src/rules/agent-docs.md +1 -0
  7. package/.agent-src/rules/analysis-skill-routing.md +1 -0
  8. package/.agent-src/rules/architecture.md +1 -0
  9. package/.agent-src/rules/artifact-drafting-protocol.md +1 -0
  10. package/.agent-src/rules/artifact-engagement-recording.md +1 -0
  11. package/.agent-src/rules/ask-when-uncertain.md +1 -0
  12. package/.agent-src/rules/augment-portability.md +1 -0
  13. package/.agent-src/rules/augment-source-of-truth.md +1 -0
  14. package/.agent-src/rules/autonomous-execution.md +1 -0
  15. package/.agent-src/rules/capture-learnings.md +1 -0
  16. package/.agent-src/rules/chat-history-cadence.md +34 -0
  17. package/.agent-src/rules/chat-history-ownership.md +1 -0
  18. package/.agent-src/rules/chat-history-visibility.md +1 -0
  19. package/.agent-src/rules/cli-output-handling.md +2 -2
  20. package/.agent-src/rules/command-suggestion-policy.md +1 -0
  21. package/.agent-src/rules/commit-conventions.md +1 -0
  22. package/.agent-src/rules/commit-policy.md +1 -0
  23. package/.agent-src/rules/context-hygiene.md +28 -0
  24. package/.agent-src/rules/direct-answers.md +18 -26
  25. package/.agent-src/rules/docker-commands.md +1 -0
  26. package/.agent-src/rules/docs-sync.md +1 -0
  27. package/.agent-src/rules/downstream-changes.md +1 -0
  28. package/.agent-src/rules/e2e-testing.md +1 -0
  29. package/.agent-src/rules/guidelines.md +1 -0
  30. package/.agent-src/rules/improve-before-implement.md +1 -0
  31. package/.agent-src/rules/language-and-tone.md +1 -0
  32. package/.agent-src/rules/laravel-translations.md +1 -0
  33. package/.agent-src/rules/markdown-safe-codeblocks.md +1 -0
  34. package/.agent-src/rules/minimal-safe-diff.md +1 -0
  35. package/.agent-src/rules/missing-tool-handling.md +1 -0
  36. package/.agent-src/rules/model-recommendation.md +1 -0
  37. package/.agent-src/rules/no-cheap-questions.md +15 -21
  38. package/.agent-src/rules/no-roadmap-references.md +1 -0
  39. package/.agent-src/rules/non-destructive-by-default.md +1 -0
  40. package/.agent-src/rules/onboarding-gate.md +33 -0
  41. package/.agent-src/rules/package-ci-checks.md +1 -0
  42. package/.agent-src/rules/php-coding.md +1 -0
  43. package/.agent-src/rules/preservation-guard.md +1 -0
  44. package/.agent-src/rules/review-routing-awareness.md +1 -0
  45. package/.agent-src/rules/reviewer-awareness.md +1 -0
  46. package/.agent-src/rules/roadmap-progress-sync.md +49 -0
  47. package/.agent-src/rules/role-mode-adherence.md +2 -2
  48. package/.agent-src/rules/rule-type-governance.md +29 -0
  49. package/.agent-src/rules/runtime-safety.md +1 -0
  50. package/.agent-src/rules/scope-control.md +1 -0
  51. package/.agent-src/rules/security-sensitive-stop.md +1 -0
  52. package/.agent-src/rules/size-enforcement.md +1 -0
  53. package/.agent-src/rules/skill-improvement-trigger.md +1 -0
  54. package/.agent-src/rules/skill-quality.md +1 -0
  55. package/.agent-src/rules/slash-command-routing-policy.md +39 -0
  56. package/.agent-src/rules/think-before-action.md +1 -0
  57. package/.agent-src/rules/token-efficiency.md +1 -0
  58. package/.agent-src/rules/tool-safety.md +1 -0
  59. package/.agent-src/rules/ui-audit-gate.md +1 -0
  60. package/.agent-src/rules/upstream-proposal.md +1 -0
  61. package/.agent-src/rules/user-interaction.md +1 -0
  62. package/.agent-src/rules/verify-before-complete.md +1 -0
  63. package/.agent-src/skills/roadmap-management/SKILL.md +29 -4
  64. package/.agent-src/skills/verify-completion-evidence/SKILL.md +8 -1
  65. package/.agent-src/templates/agent-settings.md +16 -0
  66. package/.agent-src/templates/roadmaps.md +12 -3
  67. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +9 -0
  68. package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +4 -0
  69. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +4 -0
  70. package/.agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.py +163 -0
  71. package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +111 -0
  72. package/.agent-src/templates/scripts/work_engine/hooks/settings.py +36 -0
  73. package/.agent-src/templates/scripts/work_engine/scoring/decision_trace.py +141 -0
  74. package/.agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +125 -0
  75. package/.claude-plugin/marketplace.json +1 -1
  76. package/CHANGELOG.md +97 -0
  77. package/README.md +20 -20
  78. package/config/agent-settings.template.yml +23 -0
  79. package/docs/architecture.md +1 -1
  80. package/docs/catalog.md +5 -2
  81. package/docs/contracts/adr-settings-sync-engine.md +127 -0
  82. package/docs/contracts/decision-trace-v1.md +146 -0
  83. package/docs/contracts/file-ownership-matrix.json +7 -0
  84. package/docs/contracts/hook-architecture-v1.md +213 -0
  85. package/docs/contracts/load-context-budget-model.md +80 -0
  86. package/docs/contracts/load-context-schema.md +20 -0
  87. package/docs/contracts/memory-visibility-v1.md +138 -0
  88. package/docs/contracts/one-off-script-lifecycle.md +109 -0
  89. package/docs/contracts/roadmap-complexity-standard.md +137 -0
  90. package/docs/contracts/rule-interactions.yml +22 -0
  91. package/docs/customization.md +1 -0
  92. package/docs/development.md +4 -1
  93. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  94. package/docs/guidelines/agent-infra/direct-answers-demos.md +145 -0
  95. package/docs/guidelines/agent-infra/layered-settings.md +32 -13
  96. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  97. package/package.json +1 -1
  98. package/scripts/agent-config +64 -0
  99. package/scripts/ai_council/bundler.py +3 -3
  100. package/scripts/ai_council/clients.py +24 -8
  101. package/scripts/ai_council/one_off_archive/2026-05/README.md +67 -0
  102. package/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +206 -0
  103. package/scripts/ai_council/{_one_off_roundtrip.py → one_off_archive/2026-05/_one_off_roundtrip.py} +13 -8
  104. package/scripts/ai_council/one_off_archive/2026-05/_one_off_tier_retrofit.py +180 -0
  105. package/scripts/ai_council/session.py +92 -0
  106. package/scripts/build_rule_trigger_matrix.py +360 -0
  107. package/scripts/capture_showcase_session.py +361 -0
  108. package/scripts/chat_history.py +11 -1
  109. package/scripts/check_always_budget.py +46 -2
  110. package/scripts/check_one_off_location.py +81 -0
  111. package/scripts/check_references.py +6 -0
  112. package/scripts/compress.py +5 -2
  113. package/scripts/context_hygiene_hook.py +181 -0
  114. package/scripts/council_cli.py +357 -0
  115. package/scripts/hook_manifest.yaml +184 -0
  116. package/scripts/hooks/__init__.py +1 -0
  117. package/scripts/hooks/augment-context-hygiene.sh +55 -0
  118. package/scripts/hooks/augment-dispatcher.sh +72 -0
  119. package/scripts/hooks/augment-onboarding-gate.sh +55 -0
  120. package/scripts/hooks/cline-dispatcher.sh +86 -0
  121. package/scripts/hooks/cursor-dispatcher.sh +76 -0
  122. package/scripts/hooks/dispatch_hook.py +348 -0
  123. package/scripts/hooks/envelope.py +98 -0
  124. package/scripts/hooks/gemini-dispatcher.sh +117 -0
  125. package/scripts/hooks/state_io.py +122 -0
  126. package/scripts/hooks/windsurf-dispatcher.sh +123 -0
  127. package/scripts/hooks_status.py +146 -0
  128. package/scripts/install.py +728 -51
  129. package/scripts/install.sh +1 -1
  130. package/scripts/lint_examples.py +98 -0
  131. package/scripts/lint_hook_manifest.py +216 -0
  132. package/scripts/lint_one_off_age.py +184 -0
  133. package/scripts/lint_roadmap_complexity.py +127 -0
  134. package/scripts/lint_rule_tiers.py +78 -0
  135. package/scripts/lint_showcase_sessions.py +148 -0
  136. package/scripts/minimal_safe_diff_hook.py +245 -0
  137. package/scripts/onboarding_gate_hook.py +142 -0
  138. package/scripts/readme_linter.py +12 -3
  139. package/scripts/roadmap_progress_hook.py +5 -0
  140. package/scripts/schemas/rule.schema.json +5 -0
  141. package/scripts/sync_agent_settings.py +32 -129
  142. package/scripts/sync_yaml_rt.py +734 -0
  143. package/scripts/verify_before_complete_hook.py +216 -0
  144. /package/scripts/ai_council/{_one_off_2a4_acceptance.py → one_off_archive/2026-05/_one_off_2a4_acceptance.py} +0 -0
  145. /package/scripts/ai_council/{_one_off_context_layer_v1_estimate.py → one_off_archive/2026-05/_one_off_context_layer_v1_estimate.py} +0 -0
  146. /package/scripts/ai_council/{_one_off_context_layer_v1_review.py → one_off_archive/2026-05/_one_off_context_layer_v1_review.py} +0 -0
  147. /package/scripts/ai_council/{_one_off_followups_review.py → one_off_archive/2026-05/_one_off_followups_review.py} +0 -0
  148. /package/scripts/ai_council/{_one_off_nondestructive_inline_audit.py → one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py} +0 -0
  149. /package/scripts/{_one_off_phase4_dispatch_latency.py → ai_council/one_off_archive/2026-05/_one_off_phase4_dispatch_latency.py} +0 -0
  150. /package/scripts/{_one_off_phase6_trigger_jaccard.py → ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py} +0 -0
  151. /package/scripts/ai_council/{_one_off_phase_2a_budget_rebalance.py → one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py} +0 -0
  152. /package/scripts/ai_council/{_one_off_phase_2a_post_revert.py → one_off_archive/2026-05/_one_off_phase_2a_post_revert.py} +0 -0
  153. /package/scripts/ai_council/{_one_off_rebalancing_audit.py → one_off_archive/2026-05/_one_off_rebalancing_audit.py} +0 -0
  154. /package/scripts/ai_council/{_one_off_rule_hardening_v1.py → one_off_archive/2026-05/_one_off_rule_hardening_v1.py} +0 -0
  155. /package/scripts/ai_council/{_one_off_structural_open_questions.py → one_off_archive/2026-05/_one_off_structural_open_questions.py} +0 -0
  156. /package/scripts/ai_council/{_one_off_structural_optimization.py → one_off_archive/2026-05/_one_off_structural_optimization.py} +0 -0
  157. /package/scripts/ai_council/{_one_off_structural_v3_gaps.py → one_off_archive/2026-05/_one_off_structural_v3_gaps.py} +0 -0
  158. /package/scripts/ai_council/{_one_off_structural_v3_review.py → one_off_archive/2026-05/_one_off_structural_v3_review.py} +0 -0
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env bash
2
+ # Windsurf (Cascade) universal hook trampoline (Phase 7.7,
3
+ # hook-architecture-v1.md).
4
+ #
5
+ # Routes Windsurf hook events — fired from either the project-scope
6
+ # `.windsurf/hooks.json` or the user-scope `~/.codeium/windsurf/hooks.json`
7
+ # — into the active workspace's `./agent-config dispatch:hook`.
8
+ #
9
+ # Windsurf event payload (per docs.windsurf.com/windsurf/cascade/hooks):
10
+ # { "agent_action_name": "<event>",
11
+ # "tool_info": { "cwd": "...", "file_path": "...", ... } }
12
+ #
13
+ # Workspace resolution — Windsurf does NOT pass a workspace_roots array
14
+ # the way Cursor/Cline do. Instead:
15
+ # 1. Project-scope hook → cwd is the workspace root (Cascade convention).
16
+ # `$PWD` containing `./agent-config` is the happy path.
17
+ # 2. User-scope hook → cwd may be the workspace, but for some events
18
+ # Windsurf executes from `$HOME` or a tmp dir. Fall back to:
19
+ # - tool_info.cwd from the JSON payload
20
+ # - tool_info.file_path → walk up to nearest .agent-settings.yml
21
+ # - $ROOT_WORKSPACE_PATH (only set on post_setup_worktree)
22
+ # 3. Bail silently when no resolution succeeds — concerns are
23
+ # observe-only at this layer; chat-history / roadmap-progress /
24
+ # context-hygiene never block, and onboarding-gate writes state,
25
+ # not exit code.
26
+ #
27
+ # Output — none. Windsurf does not consume stdout from hooks (post hooks
28
+ # are async, pre hooks block via exit code 2). We always exit 0 since
29
+ # none of our concerns block.
30
+
31
+ set -u
32
+
33
+ # Args from the platform's hooks.json command string:
34
+ # $1 = agent-config event name (session_start, stop, user_prompt_submit)
35
+ # $2 = Windsurf-native event name (pre_user_prompt, post_cascade_response, …)
36
+ EVENT="${1-}"
37
+ NATIVE_EVENT="${2-}"
38
+
39
+ if [ -z "$EVENT" ]; then
40
+ exit 0
41
+ fi
42
+
43
+ EVENT_DATA="$(cat)"
44
+
45
+ # 1. $PWD wins when it already looks like an agent-config workspace.
46
+ WORKSPACE=""
47
+ if [ -x "$PWD/agent-config" ] || [ -f "$PWD/.agent-settings.yml" ]; then
48
+ WORKSPACE="$PWD"
49
+ fi
50
+
51
+ # 2. Walk up from $PWD looking for .agent-settings.yml (covers
52
+ # sub-directory invocations).
53
+ if [ -z "$WORKSPACE" ]; then
54
+ candidate="$PWD"
55
+ while [ -n "$candidate" ] && [ "$candidate" != "/" ]; do
56
+ if [ -f "$candidate/.agent-settings.yml" ]; then
57
+ WORKSPACE="$candidate"
58
+ break
59
+ fi
60
+ candidate="$(dirname "$candidate")"
61
+ done
62
+ fi
63
+
64
+ # 3. Parse JSON tool_info for cwd / file_path.
65
+ if [ -z "$WORKSPACE" ]; then
66
+ if command -v jq >/dev/null 2>&1; then
67
+ EXTRACTED="$(printf '%s' "$EVENT_DATA" \
68
+ | jq -r '.tool_info.cwd // .tool_info.file_path // empty' 2>/dev/null)"
69
+ elif command -v python3 >/dev/null 2>&1; then
70
+ EXTRACTED="$(printf '%s' "$EVENT_DATA" | python3 -c '
71
+ import json, sys
72
+ try:
73
+ data = json.load(sys.stdin)
74
+ except Exception:
75
+ sys.exit(0)
76
+ info = data.get("tool_info") or {}
77
+ print(info.get("cwd") or info.get("file_path") or "")
78
+ ' 2>/dev/null)"
79
+ else
80
+ EXTRACTED=""
81
+ fi
82
+ EXTRACTED="${EXTRACTED%$'\r'}"
83
+ if [ -n "$EXTRACTED" ]; then
84
+ # Walk up looking for .agent-settings.yml.
85
+ candidate="$EXTRACTED"
86
+ if [ -f "$candidate" ]; then
87
+ candidate="$(dirname "$candidate")"
88
+ fi
89
+ while [ -n "$candidate" ] && [ "$candidate" != "/" ]; do
90
+ if [ -f "$candidate/.agent-settings.yml" ]; then
91
+ WORKSPACE="$candidate"
92
+ break
93
+ fi
94
+ candidate="$(dirname "$candidate")"
95
+ done
96
+ fi
97
+ fi
98
+
99
+ # 4. $ROOT_WORKSPACE_PATH is set only on post_setup_worktree.
100
+ if [ -z "$WORKSPACE" ] && [ -n "${ROOT_WORKSPACE_PATH-}" ]; then
101
+ if [ -f "$ROOT_WORKSPACE_PATH/.agent-settings.yml" ]; then
102
+ WORKSPACE="$ROOT_WORKSPACE_PATH"
103
+ fi
104
+ fi
105
+
106
+ if [ -z "$WORKSPACE" ] || [ ! -d "$WORKSPACE" ]; then
107
+ exit 0
108
+ fi
109
+
110
+ cd "$WORKSPACE" 2>/dev/null || exit 0
111
+
112
+ if [ ! -x ./agent-config ]; then
113
+ exit 0
114
+ fi
115
+
116
+ printf '%s' "$EVENT_DATA" \
117
+ | ./agent-config dispatch:hook \
118
+ --platform windsurf \
119
+ --event "$EVENT" \
120
+ --native-event "$NATIVE_EVENT" \
121
+ >/dev/null 2>&1 || true
122
+
123
+ exit 0
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env python3
2
+ """Print the runtime hook matrix per `docs/contracts/hook-architecture-v1.md`.
3
+
4
+ For each platform in `scripts/hook_manifest.yaml`, prints whether the
5
+ project-scope bridge files exist on disk, which (event → concerns)
6
+ bindings the manifest declares, and a one-line install hint when the
7
+ bridge is missing. Copilot has no native hook surface — its row carries
8
+ the `degraded: rule-only fallback` marker per Phase 7.12 / Round 2.
9
+
10
+ This is a **read-only** report. It never installs, modifies, or fires
11
+ anything; that is the contract callers depend on (`task hooks-status`,
12
+ post-install smoke, CI).
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import json
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ REPO_ROOT = Path(__file__).resolve().parents[1]
22
+ sys.path.insert(0, str(REPO_ROOT / "scripts" / "hooks"))
23
+
24
+ import dispatch_hook # noqa: E402 — reuse the manifest loader
25
+
26
+ # (label, project-relative bridge path, install hint).
27
+ # Path may be a directory (cline) — existence => any file inside.
28
+ PLATFORM_BRIDGES: dict[str, tuple[str, str]] = {
29
+ "augment": (".augment/settings.json", "scripts/install.py"),
30
+ "claude": (".claude/settings.json", "scripts/install.py"),
31
+ "cursor": (".cursor/hooks.json", "scripts/install.py"),
32
+ "cline": (".clinerules/hooks", "scripts/install.py"),
33
+ "windsurf": (".windsurf/hooks.json", "scripts/install.py"),
34
+ "gemini": (".gemini/settings.json", "scripts/install.py"),
35
+ "copilot": ("", "rule-only fallback (no hook surface)"),
36
+ }
37
+
38
+
39
+ def _bridge_status(project_root: Path, rel_path: str) -> str:
40
+ if not rel_path:
41
+ return "n/a"
42
+ target = project_root / rel_path
43
+ if target.is_dir():
44
+ return "installed" if any(target.iterdir()) else "empty"
45
+ return "installed" if target.is_file() else "missing"
46
+
47
+
48
+ def collect(project_root: Path, manifest: dict) -> dict:
49
+ """Build the runtime matrix as a plain dict — JSON-serialisable."""
50
+ platforms = manifest.get("platforms") or {}
51
+ rows: list[dict] = []
52
+ for platform in PLATFORM_BRIDGES:
53
+ rel, hint = PLATFORM_BRIDGES[platform]
54
+ block = platforms.get(platform) or {}
55
+ fallback_only = bool(block.get("fallback_only"))
56
+ bindings = (
57
+ {} if fallback_only
58
+ else {ev: list(c) for ev, c in block.items()
59
+ if isinstance(c, list)}
60
+ )
61
+ status = "degraded" if fallback_only else _bridge_status(project_root, rel)
62
+ rows.append({
63
+ "platform": platform,
64
+ "status": status,
65
+ "bridge_path": rel or None,
66
+ "fallback_only": fallback_only,
67
+ "bindings": bindings,
68
+ "hint": hint if status in {"missing", "empty", "degraded"} else None,
69
+ })
70
+ return {"schema_version": 1, "platforms": rows}
71
+
72
+
73
+ def _render_table(matrix: dict) -> str:
74
+ lines: list[str] = []
75
+ lines.append("agent-config hook matrix")
76
+ lines.append("=" * 60)
77
+ for row in matrix["platforms"]:
78
+ marker = {
79
+ "installed": "✅ ",
80
+ "missing": "❌ ",
81
+ "empty": "⚠️ ",
82
+ "degraded": "⚠️ ",
83
+ "n/a": "· ",
84
+ }.get(row["status"], "? ")
85
+ head = f"{marker}{row['platform']:<9} {row['status']}"
86
+ if row["bridge_path"]:
87
+ head += f" ({row['bridge_path']})"
88
+ lines.append(head)
89
+ if row["fallback_only"]:
90
+ lines.append(" degraded: rule-only fallback "
91
+ "— hooks are not auto-firing on this platform.")
92
+ continue
93
+ if not row["bindings"]:
94
+ lines.append(" (no bindings declared in manifest)")
95
+ continue
96
+ for event in sorted(row["bindings"]):
97
+ concerns = ", ".join(row["bindings"][event]) or "—"
98
+ lines.append(f" {event:<22} → {concerns}")
99
+ if row["hint"]:
100
+ lines.append(f" hint: run {row['hint']}")
101
+ lines.append("")
102
+ lines.append("Source of truth: scripts/hook_manifest.yaml")
103
+ lines.append("Contract: docs/contracts/hook-architecture-v1.md")
104
+ return "\n".join(lines)
105
+
106
+
107
+ def _final_exit_code(matrix: dict, strict: bool) -> int:
108
+ if not strict:
109
+ return 0
110
+ # Strict mode: any platform with declared bindings whose bridge is
111
+ # missing is a CI failure. `degraded`/`n/a` never fail (Copilot is
112
+ # an explicit no-hook platform; n/a means no bridge expected).
113
+ for row in matrix["platforms"]:
114
+ if row["status"] == "missing" and row["bindings"]:
115
+ return 1
116
+ return 0
117
+
118
+
119
+ def main(argv: list[str] | None = None) -> int:
120
+ parser = argparse.ArgumentParser(description=__doc__)
121
+ parser.add_argument("--format", choices=["table", "json"], default="table")
122
+ parser.add_argument("--project-root", default=".",
123
+ help="Project root to inspect (default: cwd)")
124
+ parser.add_argument("--manifest", default=str(dispatch_hook.MANIFEST_PATH))
125
+ parser.add_argument("--strict", action="store_true",
126
+ help="Exit non-zero if any platform with bindings is "
127
+ "missing its bridge (CI-friendly).")
128
+ args = parser.parse_args(argv)
129
+
130
+ manifest_path = Path(args.manifest)
131
+ if not manifest_path.exists():
132
+ sys.stderr.write(f"hooks_status: manifest missing at {manifest_path}\n")
133
+ return 2
134
+ manifest = dispatch_hook._load_yaml(manifest_path)
135
+ project_root = Path(args.project_root).resolve()
136
+ matrix = collect(project_root, manifest)
137
+
138
+ if args.format == "json":
139
+ print(json.dumps(matrix, indent=2, sort_keys=True))
140
+ else:
141
+ print(_render_table(matrix))
142
+ return _final_exit_code(matrix, args.strict)
143
+
144
+
145
+ if __name__ == "__main__":
146
+ raise SystemExit(main())