torusguard 1.3.6 → 1.4.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 (81) hide show
  1. package/.torusguard/.manifest.json +9 -8
  2. package/.torusguard/runs/report-latest.html +3529 -364
  3. package/.torusguard/runs/run-20260918-105940-audit/manifest.json +2 -1
  4. package/.torusguard/runs/run-20260918-105940-audit/remediation.md +7 -0
  5. package/.torusguard/runs/run-20260919-145701-audit/findings.json +1 -0
  6. package/.torusguard/runs/run-20260919-145701-audit/findings.md +8 -0
  7. package/.torusguard/runs/run-20260919-145701-audit/manifest.json +12 -0
  8. package/.torusguard/runs/run-20260919-145701-audit/summary.md +5 -0
  9. package/.torusguard/runs/run-20260919-151729-audit/findings.json +1 -0
  10. package/.torusguard/runs/run-20260919-151729-audit/findings.md +8 -0
  11. package/.torusguard/runs/run-20260919-151729-audit/manifest.json +13 -0
  12. package/.torusguard/runs/run-20260919-151729-audit/remediation.md +7 -0
  13. package/.torusguard/runs/run-20260919-151729-audit/summary.md +5 -0
  14. package/.torusguard/runs/run-20260919-152340-audit/findings.json +1 -0
  15. package/.torusguard/runs/run-20260919-152340-audit/findings.md +8 -0
  16. package/.torusguard/runs/run-20260919-152340-audit/manifest.json +12 -0
  17. package/.torusguard/runs/run-20260919-152340-audit/summary.md +5 -0
  18. package/.torusguard/runs/run-20260919-152345-audit/findings.json +1 -0
  19. package/.torusguard/runs/run-20260919-152345-audit/findings.md +8 -0
  20. package/.torusguard/runs/run-20260919-152345-audit/manifest.json +12 -0
  21. package/.torusguard/runs/run-20260919-152345-audit/summary.md +5 -0
  22. package/.torusguard/runs/run-20260919-153500-audit/findings.json +1 -0
  23. package/.torusguard/runs/run-20260919-153500-audit/findings.md +8 -0
  24. package/.torusguard/runs/run-20260919-153500-audit/manifest.json +12 -0
  25. package/.torusguard/runs/run-20260919-153500-audit/summary.md +5 -0
  26. package/.torusguard/scripts/__pycache__/apply_runner.cpython-314.pyc +0 -0
  27. package/.torusguard/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
  28. package/.torusguard/scripts/__pycache__/harden_runner.cpython-314.pyc +0 -0
  29. package/.torusguard/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
  30. package/.torusguard/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
  31. package/.torusguard/scripts/__pycache__/recipes_runner.cpython-314.pyc +0 -0
  32. package/.torusguard/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
  33. package/.torusguard/scripts/apply_runner.py +101 -8
  34. package/.torusguard/scripts/audit_runner.py +116 -11
  35. package/.torusguard/scripts/harden_runner.py +122 -68
  36. package/.torusguard/scripts/html_reporter.py +1170 -253
  37. package/.torusguard/scripts/manifest_builder.py +2 -0
  38. package/.torusguard/scripts/recheck_runner.py +2 -1
  39. package/.torusguard/scripts/recipes_runner.py +91 -8
  40. package/.torusguard/scripts/report_sync.py +134 -7
  41. package/.torusguard/scripts/status_runner.py +267 -0
  42. package/README.md +108 -80
  43. package/bin/torusguard.js +190 -20
  44. package/package.json +6 -2
  45. package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
  46. package/skills/torusguard/bootstrap.py +45 -6
  47. package/skills/torusguard/payload/.manifest.json +29 -14
  48. package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
  49. package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
  50. package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
  51. package/skills/torusguard/payload/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
  52. package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
  53. package/skills/torusguard/payload/scripts/apply_runner.py +101 -8
  54. package/skills/torusguard/payload/scripts/audit_runner.py +116 -11
  55. package/skills/torusguard/payload/scripts/harden_runner.py +122 -68
  56. package/skills/torusguard/payload/scripts/html_reporter.py +1170 -253
  57. package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
  58. package/skills/torusguard/payload/scripts/recheck_runner.py +2 -1
  59. package/skills/torusguard/payload/scripts/recipes_runner.py +91 -8
  60. package/skills/torusguard/payload/scripts/report_sync.py +134 -7
  61. package/skills/torusguard/payload/scripts/status_runner.py +267 -0
  62. package/skills/torusguard/payload/workflows/apply.md +9 -1
  63. package/skills/torusguard/payload/workflows/audit.md +8 -2
  64. package/skills/torusguard/payload/workflows/harden.md +6 -1
  65. package/skills/torusguard/payload/workflows/init.md +7 -1
  66. package/skills/torusguard/payload/workflows/recipes.md +55 -0
  67. package/skills/torusguard/payload/workflows/report.md +59 -55
  68. package/skills/torusguard/payload/workflows/status.md +4 -1
  69. package/skills/torusguard/payload/workflows/torusguard-apply.md +110 -0
  70. package/skills/torusguard/payload/workflows/torusguard-audit.md +105 -0
  71. package/skills/torusguard/payload/workflows/torusguard-authorize.md +96 -0
  72. package/skills/torusguard/payload/workflows/torusguard-exploit-check.md +98 -0
  73. package/skills/torusguard/payload/workflows/torusguard-harden.md +104 -0
  74. package/skills/torusguard/payload/workflows/torusguard-init.md +106 -0
  75. package/skills/torusguard/payload/workflows/torusguard-recheck.md +101 -0
  76. package/skills/torusguard/payload/workflows/torusguard-recipes.md +55 -0
  77. package/skills/torusguard/payload/workflows/torusguard-report.md +105 -0
  78. package/skills/torusguard/payload/workflows/torusguard-status.md +103 -0
  79. package/skills/torusguard/payload/workflows/torusguard-verify.md +100 -0
  80. package/skills/torusguard/payload/workflows/torusguard-web-validate.md +96 -0
  81. package/skills/torusguard/payload/workflows/torusguard.md +19 -0
package/README.md CHANGED
@@ -9,15 +9,16 @@
9
9
  <strong>Zero Telemetry · Zero External Python Dependencies · Pure Standard-Library Architecture · 100% Local-First</strong>
10
10
  </p>
11
11
 
12
- [![npm version](https://img.shields.io/badge/npm-v1.3.6-cb3837.svg?style=flat-square&logo=npm)](https://www.npmjs.com/package/torusguard)
13
- [![GitHub Packages](https://img.shields.io/badge/GitHub%20Packages-v1.3.6-181717.svg?style=flat-square&logo=github)](https://github.com/githubmofo/TorusGuard/pkgs/npm/torusguard)
14
- [![Release](https://img.shields.io/badge/Release-v1.3.6-blue.svg?style=flat-square)](https://github.com/githubmofo/TorusGuard/releases/latest)
15
- [![Tests](https://img.shields.io/badge/Tests-120%2F120%20Passing-brightgreen.svg?style=flat-square)](harness/runner.py)
12
+ [![npm version](https://img.shields.io/badge/npm-v1.4.0-cb3837.svg?style=flat-square&logo=npm)](https://www.npmjs.com/package/torusguard)
13
+ [![GitHub Packages](https://img.shields.io/badge/GitHub%20Packages-v1.4.0-181717.svg?style=flat-square&logo=github)](https://github.com/githubmofo/TorusGuard/pkgs/npm/torusguard)
14
+ [![Release](https://img.shields.io/badge/Release-v1.4.0-blue.svg?style=flat-square)](https://github.com/githubmofo/TorusGuard/releases/latest)
15
+ [![Tests](https://img.shields.io/badge/Tests-133%2F133%20Passing-brightgreen.svg?style=flat-square)](harness/runner.py)
16
16
  [![Security Health](https://img.shields.io/badge/Health%20Score-100%2F100%20Hardened-brightgreen.svg?style=flat-square)](security_report.md)
17
17
  [![Rules Catalog](https://img.shields.io/badge/Rules%20Catalog-74%20Rules%20%7C%2018%20Families-indigo.svg?style=flat-square)](rules/)
18
18
  [![Terminal Standard](https://img.shields.io/badge/Terminal-75--col%20Standard-informational.svg?style=flat-square)](.torusguard/scripts/term_ui.py)
19
19
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](LICENSE)
20
20
  [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B%20(Zero%20Deps)-blue.svg?style=flat-square&logo=python&logoColor=white)](https://python.org)
21
+ [![Go 1.22+](https://img.shields.io/badge/Go-1.22%2B-00ADD8.svg?style=flat-square&logo=go&logoColor=white)](https://go.dev)
21
22
  [![Node.js 18+](https://img.shields.io/badge/Node.js-18%2B-339933.svg?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
22
23
  [![SARIF: v2.1.0](https://img.shields.io/badge/SARIF-v2.1.0%20OASIS-purple.svg?style=flat-square)](.torusguard/schemas/)
23
24
  [![OWASP: Top 10](https://img.shields.io/badge/OWASP-Top%2010%20Aligned-orange.svg?style=flat-square)](docs/architecture/SECURITY_ARCHITECTURE.md)
@@ -26,35 +27,8 @@
26
27
 
27
28
  ---
28
29
 
29
- ## 🛡️ The Architecture Behind the Emblem
30
-
31
- In the emblem above, the **central golden keyhole shield** represents unbreakable secret protection, authentication integrity, and tenant isolation. It is enveloped by a continuous, interlocking **torus ring**—symbolizing TorusGuard's closed-loop autonomous security lifecycle:
32
-
33
- ```mermaid
34
- flowchart LR
35
- subgraph Torus ["🔄 360° Closed-Loop Torus Lifecycle"]
36
- direction LR
37
- Detect["1. Detect (74 AST Rules)"] --> Verify["2. Verify (Evidence & Fingerprints)"]
38
- Verify --> Harden["3. Harden (Ponytail Protocol)"]
39
- Harden --> Apply["4. Apply (Human Gate & Snapshots)"]
40
- Apply --> Recheck["5. Recheck (Differential Closure)"]
41
- Recheck --> Memory["6. Memory (Golden Fix Recipes)"]
42
- Memory -.->|Continuous Guardrail| Detect
43
- end
44
-
45
- subgraph Shield ["🛡️ Central Golden Keyhole Shield"]
46
- direction TB
47
- Inv1["Browser-Code Truth: Zero Client Secrets"]
48
- Inv2["Tenant Partitioning: Scoped Lookups"]
49
- Inv3["Zero Bypasses: No verify=False"]
50
- Inv4["Living Source of Truth: security_report.md"]
51
- end
52
-
53
- Torus === Shield
54
- ```
55
-
56
- > **The Developer Reality:** AI coding assistants (Cursor, Claude Code, Copilot, Windsurf) build software at superhuman speed, but routinely leak private keys into client bundles, drop tenant partition filters, or inject raw user input into LLM system prompts.
57
- > **TorusGuard forms an unbroken local guardrail around your codebase.** It audits static ASTs, runtime-verifies exploitability with inert canaries, synthesizes minimal surgical diffs adhering to the **Ponytail Protocol** ($\le 35$ additions, $\le 25$ deletions), and eliminates hallucinations by maintaining a verifiable single source of truth in `security_report.md`.
30
+ > **The Developer Reality:** AI coding assistants (Cursor, Claude Code, Copilot, Windsurf, Antigravity) build software at superhuman speed, but routinely leak private keys into client bundles, drop tenant partition filters, or inject raw user input into LLM system prompts.
31
+ > **TorusGuard forms an unbroken local guardrail around your codebase.** It audits static ASTs across 74 rules, runtime-verifies exploitability with inert canaries, synthesizes minimal surgical diffs adhering to the **Ponytail Protocol** ($\le 35$ additions, $\le 25$ deletions), and eliminates hallucinations by maintaining a verifiable single source of truth in `security_report.md`.
58
32
 
59
33
  ---
60
34
 
@@ -63,18 +37,20 @@ flowchart LR
63
37
  1. [Developer Overview & Value Proposition](#-developer-overview--value-proposition)
64
38
  2. [End-to-End Autonomous Architecture](#-end-to-end-autonomous-architecture)
65
39
  3. [Why TorusGuard? (Traditional SAST vs. AI Coding vs. TorusGuard)](#-why-torusguard)
66
- 4. [Installation & Setup Guide (npm & CLI)](#-installation--setup-guide-npm--cli)
40
+ 4. [Installation & Setup Guide (npm, Go & CLI)](#-installation--setup-guide-npm-go--cli)
67
41
  5. [Quickstart: The 5-Step Core Lifecycle](#-quickstart-the-5-step-core-lifecycle)
68
42
  6. [Dual-Strategy Command Matrix (CLI & AI Chat Parity)](#-dual-strategy-command-matrix-cli--ai-chat-parity)
69
- 7. [74 Canonical Security Rules Catalog (18 Families Across 6 Pillars)](#-74-canonical-security-rules-catalog-18-families-across-6-pillars)
70
- 8. [Ponytail Remediation Protocol & Rollback Safety](#-ponytail-remediation-protocol--rollback-safety)
71
- 9. [Living Security Report Ground Truth (`security_report.md`)](#-living-security-report-ground-truth-security_reportmd)
72
- 10. [Visual HTML Dashboard & SARIF v2.1.0 Export](#-visual-html-dashboard--sarif-v210-export)
73
- 11. [AI Editor Guardrails Auto-Sync](#-ai-editor-guardrails-auto-sync)
74
- 12. [Monorepo Fleet Support & Git Pre-Commit Diff Guard](#-monorepo-fleet-support--git-pre-commit-diff-guard)
75
- 13. [Verification & Test Harness (120/120 Passing Harness Explained)](#-verification--test-harness)
76
- 14. [Security Policy & Responsible Disclosure](#-security-policy--responsible-disclosure)
77
- 15. [License](#-license)
43
+ 7. [Polyglot Go Engine & Native Runner](#-polyglot-go-engine--native-runner)
44
+ 8. [Package Self-Update Engine (`update`)](#-package-self-update-engine-update)
45
+ 9. [74 Canonical Security Rules Catalog (18 Families Across 6 Pillars)](#-74-canonical-security-rules-catalog-18-families-across-6-pillars)
46
+ 10. [Ponytail Remediation Protocol & Rollback Safety](#-ponytail-remediation-protocol--rollback-safety)
47
+ 11. [Living Security Report Ground Truth (`security_report.md`)](#-living-security-report-ground-truth-security_reportmd)
48
+ 12. [Visual HTML Dashboard & SARIF v2.1.0 Export](#-visual-html-dashboard--sarif-v210-export)
49
+ 13. [AI Editor Guardrails Auto-Sync](#-ai-editor-guardrails-auto-sync)
50
+ 14. [Monorepo Fleet Support & Git Pre-Commit Diff Guard](#-monorepo-fleet-support--git-pre-commit-diff-guard)
51
+ 15. [Verification & Test Harness (133/133 Passing Harness Explained)](#-verification--test-harness)
52
+ 16. [Security Policy & Responsible Disclosure](#-security-policy--responsible-disclosure)
53
+ 17. [License](#-license)
78
54
 
79
55
  ---
80
56
 
@@ -155,6 +131,7 @@ TorusGuard is designed to be effortless to adopt in any project. There are no co
155
131
  ### 📋 Prerequisites
156
132
  - **Node.js:** 18.0.0 or higher
157
133
  - **Python:** 3.10 or higher (**Pure standard library** — **zero `pip` dependencies required**)
134
+ - **Go (Optional):** 1.22 or higher (for native Go CLI compilation & Go module workflows)
158
135
 
159
136
  > [!IMPORTANT]
160
137
  > **Zero Pip Dependencies Guarantee:** TorusGuard's core Python engine relies strictly on the Python standard library (`pathlib`, `re`, `json`, `difflib`, `shutil`, `sys`, `os`, `argparse`, `hashlib`). You **never** need to create a Python virtualenv (`venv`), run `pip install`, or configure external wheels. It works out of the box with your system Python.
@@ -169,6 +146,7 @@ Run TorusGuard instantly in any repository without installing anything globally:
169
146
  npx torusguard init
170
147
  npx torusguard audit
171
148
  npx torusguard status
149
+ npx torusguard update
172
150
  ```
173
151
 
174
152
  ### 2. Project Dev Dependency
@@ -185,19 +163,32 @@ Add convenience scripts to your `package.json`:
185
163
  "security:audit": "torusguard audit",
186
164
  "security:harden": "torusguard harden",
187
165
  "security:recheck": "torusguard recheck",
188
- "security:status": "torusguard status"
166
+ "security:status": "torusguard status",
167
+ "security:update": "torusguard update"
189
168
  }
190
169
  }
191
170
  ```
192
171
 
193
- ### 3. Global Installation
172
+ ### 3. Native Go CLI Runner
173
+ For Go ecosystem developers, TorusGuard ships with a native Go runner module ([go.mod](go.mod)):
174
+
175
+ ```bash
176
+ # Run zero-dependency Go CLI entrypoint directly
177
+ go run cmd/torusguard/main.go audit
178
+
179
+ # Or install globally into your $GOPATH/bin
180
+ go install github.com/torusguard/torusguard/cmd/torusguard@latest
181
+ torusguard status
182
+ ```
183
+
184
+ ### 4. Global NPM Installation
194
185
  If you prefer having the `torusguard` binary available system-wide across all terminal sessions:
195
186
 
196
187
  ```bash
197
188
  npm install -g torusguard
198
189
  ```
199
190
 
200
- ### 4. AI Agent Skill Installation
191
+ ### 5. AI Agent Skill Installation
201
192
  Install TorusGuard as a native AI assistant skill for Cursor, Claude Code, Cline, or Antigravity:
202
193
 
203
194
  ```bash
@@ -207,7 +198,7 @@ npx skills add torusguard
207
198
  ---
208
199
 
209
200
  ### 🔍 What Happens on First Run (`init`)
210
- When you execute `npx torusguard init` in your repository:
201
+ When you execute `npx torusguard init` (or `npx torusguard init --template golang`) in your repository:
211
202
  1. **Polyglot Profiling:** Automatically detects 16+ languages (Go, Rust, Java, C#, PHP, Python, TypeScript) and 30+ frameworks without manual configuration.
212
203
  2. **Scaffolding:** Creates a local `.torusguard/` directory containing active security rules, schemas, and runners.
213
204
  3. **Editor Rules Synchronization:** Automatically compiles compact, language-specific guardrails into `.cursorrules`, `CLAUDE.md`, `.agent/rules/torusguard.md`, and `.windsurfrules` ($\le 300$ prompt tokens).
@@ -221,16 +212,16 @@ When you execute `npx torusguard init` in your repository:
221
212
  Run the complete autonomous governance cycle in 60 seconds from your terminal:
222
213
 
223
214
  ```bash
224
- # Step 1: Initialize workspace and profile stack
215
+ # Step 1: Initialize workspace and profile stack (optional: --template golang|nextjs|fastapi)
225
216
  npx torusguard init
226
217
 
227
- # Step 2: Run AST static security audit across 74 rules
218
+ # Step 2: Run AST static security audit across 74 rules (optional: --watch, --sarif)
228
219
  npx torusguard audit
229
220
 
230
- # Step 3: Synthesize minimal surgical candidate patches
221
+ # Step 3: Synthesize minimal surgical candidate patches (optional: --dry-run, --severity high)
231
222
  npx torusguard harden
232
223
 
233
- # Step 4: Review syntax-highlighted diffs and apply with rollback backup
224
+ # Step 4: Review syntax-highlighted diffs and apply with rollback backup (optional: --diff, --selective)
234
225
  npx torusguard apply
235
226
 
236
227
  # Step 5: Differentially recheck modified files to verify fix closure
@@ -243,37 +234,71 @@ npx torusguard recheck
243
234
 
244
235
  ## ⌨️ Dual-Strategy Command Matrix (CLI & AI Chat Parity)
245
236
 
246
- TorusGuard guarantees **100% operational parity** between terminal CLI execution and AI chat slash commands. Terminal outputs strictly adhere to a **75-column visual width** with Unicode emojis and ANSI stripping.
237
+ TorusGuard guarantees **100% operational parity** between terminal CLI execution and AI chat slash commands. Terminal outputs strictly adhere to a **75-column visual width** with Unicode emojis and ANSI stripping. All commands support `--target <dir>` / `-t <dir>` for monorepo and subproject isolation.
247
238
 
248
239
  ### 🔄 Core Remediation Lifecycle
249
240
 
250
241
  | Lifecycle Stage | Mode A: Terminal CLI | Mode B: AI Chat Command | Governed Action & Primary Artifact |
251
242
  |:---|:---|:---|:---|
252
- | **1. Init** | `npx torusguard init` | `/torusguard init` | Profiles workspace, activates rules, initializes `.torusguard/` |
253
- | **2. Audit** | `npx torusguard audit` | `/torusguard audit` | 74-rule AST scan, line-shift fingerprints, updates `security_report.md` |
254
- | **3. Harden** | `npx torusguard harden` | `/torusguard harden` | Synthesizes Ponytail diffs ($\le 35$ add, $\le 25$ del) into candidate bundles |
255
- | **4. Apply** | `npx torusguard apply [--yes]` | `/torusguard apply` | Human Gate, pre-apply `.bak` snapshots, Golden Fix distillation |
256
- | **5. Rollback**| `npx torusguard rollback` | `/torusguard rollback` | Instant restoration from pre-apply snapshots in `.torusguard/snapshots/` |
257
- | **6. Recheck** | `npx torusguard recheck` | `/torusguard recheck` | Differential AST re-scan; marks findings `RESOLVED 🟢` in living report |
243
+ | **1. Init** | `npx torusguard init [--template <name>] [--audit]` | `/torusguard init` | Profiles workspace, activates rules, scaffolds `.torusguard/` |
244
+ | **2. Status** | `npx torusguard status` | `/torusguard status` | 75-column diagnostic overview of health score, stack, memory & rules |
245
+ | **3. Audit** | `npx torusguard audit [--watch] [--sarif]` | `/torusguard audit` | 74-rule AST scan, line-shift fingerprints, throughput metrics, living ledger |
246
+ | **4. Verify** | `npx torusguard verify` | `/torusguard verify` | Asserts evidence sufficiency & live disk line-shift fingerprint matches |
247
+ | **5. Harden** | `npx torusguard harden [--dry-run] [--severity <s\>]` | `/torusguard harden` | Synthesizes Ponytail diffs ($\le 35$ add, $\le 25$ del) into candidate bundles |
248
+ | **6. Apply** | `npx torusguard apply [--diff] [--selective] [--yes]` | `/torusguard apply` | Human Gate, pre-apply `.bak` snapshots, Golden Fix distillation |
249
+ | **7. Rollback**| `npx torusguard rollback [--run <id>]` | `/torusguard rollback` | Instant restoration from pre-apply snapshots in `.torusguard/snapshots/` |
250
+ | **8. Recheck** | `npx torusguard recheck` | `/torusguard recheck` | Differential AST re-scan; marks findings `RESOLVED 🟢` in living report |
251
+ | **9. Recipes** | `npx torusguard recipes [--search <q>] [--export <p>]`| `/torusguard recipes` | Explores and exports verified Golden Fix patterns from `.torusguard/memory/` |
252
+ | **10. Report** | `npx torusguard report --html [--sarif]` | `/torusguard report` | Emits single-file dark-mode HTML posture dashboard & OASIS SARIF v2.1.0 |
253
+ | **11. Update** | `npx torusguard update [--install]` | `/torusguard update` | Verifies npm registry for latest versions and provides 1-command upgrade |
254
+ | **12. Rules Sync**| `npx torusguard rules sync` | `/torusguard rules sync`| Synchronizes prompt guardrails across Cursor, Claude, Antigravity, Windsurf |
255
+ | **13. Diff Guard**| `npx torusguard diff-guard [--install-hook]` | `/torusguard diff-guard`| Audits git diffs for security bypasses; binds pre-commit git hook |
256
+ | **14. Authorize** | `npx torusguard authorize` | `/torusguard authorize` | Target domain allowlisting, cryptographic ownership proof, TTL limits |
257
+ | **15. Validate** | `npx torusguard web-validate` | `/torusguard web-validate`| Authorized non-destructive HTTP probing with transparent audit headers |
258
+ | **16. Exploit** | `npx torusguard exploit-check` | `/torusguard exploit-check`| Bounded single-step exploitability confirmation using inert sentinels |
258
259
 
259
- ### 📊 Intelligence, Memory & Reporting
260
+ ---
260
261
 
261
- | Capability | Mode A: Terminal CLI | Mode B: AI Chat Command | Governed Action & Primary Artifact |
262
- |:---|:---|:---|:---|
263
- | **Status** | `npx torusguard status` | `/torusguard status` | 75-column diagnostic overview of health score, stack, memory & rules |
264
- | **Recipes** | `npx torusguard recipes` | `/torusguard recipes` | Explores verified Golden Fix patterns stored in `.torusguard/memory/` |
265
- | **Report** | `npx torusguard report --html` | `/torusguard report` | Emits single-file dark-mode HTML posture report & OASIS SARIF v2.1.0 |
266
- | **Rules Sync**| `npx torusguard rules sync` | `/torusguard rules sync`| Synchronizes prompt guardrails across Cursor, Claude, Antigravity, Windsurf |
267
- | **Diff Guard**| `npx torusguard diff-guard` | `/torusguard diff-guard`| Audits git diffs for security bypasses; `--install-hook` binds pre-commit |
262
+ ## 🐹 Polyglot Go Engine & Native Runner
268
263
 
269
- ### 🧪 Runtime Verification & Bounded Probing
264
+ TorusGuard v1.4.0 introduces native, zero-dependency Go ecosystem support:
270
265
 
271
- | Capability | Mode A: Terminal CLI | Mode B: AI Chat Command | Governed Action & Primary Artifact |
272
- |:---|:---|:---|:---|
273
- | **Authorize** | `npx torusguard authorize` | `/torusguard authorize` | Target domain allowlisting, cryptographic ownership proof, TTL limits |
274
- | **Verify** | `npx torusguard verify` | `/torusguard verify` | Asserts evidence sufficiency & live disk line-shift fingerprint matches |
275
- | **Validate** | `npx torusguard web-validate` | `/torusguard web-validate`| Authorized non-destructive HTTP probing with transparent audit headers |
276
- | **Exploit** | `npx torusguard exploit-check`| `/torusguard exploit-check`| Bounded single-step exploitability confirmation using inert sentinels |
266
+ ### 1. Go AST Invariant Security Rules
267
+ - **`TG-INPUT-002` (Raw SQL Concatenation):** Detects unparameterized string concatenation and `fmt.Sprintf` query interpolation in `database/sql`, `sqlx`, and GORM.
268
+ - **`TG-INPUT-006` (Path Traversal):** Detects unsanitized file reads (`os.Open`, `os.ReadFile`) using user request parameters.
269
+ - **`TG-SSRF-004` (Unbounded HTTP Requests):** Flags `&http.Client{}` and `http.DefaultClient` lacking explicit timeout boundaries to prevent connection pooling denial-of-service.
270
+ - **`TG-DIFF-001` (Security Bypasses):** Prevents insecure TLS validation (`InsecureSkipVerify: true`).
271
+ - **`TG-SUPPLY-001` (Supply Chain):** Asserts lockfile presence and cryptographic tracking for `go.sum`.
272
+
273
+ ### 2. Surgical Ponytail Remediation for Go
274
+ Patches for Go follow strict Ponytail line churn limits ($\le 35$ additions, $\le 25$ deletions):
275
+ ```go
276
+ // Example: TG-SSRF-004 Remediation
277
+ - client := &http.Client{}
278
+ + client := &http.Client{Timeout: 10 * time.Second}
279
+
280
+ // Example: TG-INPUT-006 Path Traversal Remediation
281
+ - data, err := os.ReadFile("/data/" + c.Query("file"))
282
+ + data, err := os.ReadFile(filepath.Join("/data", filepath.Base(c.Query("file"))))
283
+ ```
284
+
285
+ ---
286
+
287
+ ## 🔄 Package Self-Update Engine (`update`)
288
+
289
+ Keep your security guardrails continuously synchronized with the latest threat models:
290
+
291
+ ```bash
292
+ # Check registry for newer versions
293
+ npx torusguard update
294
+
295
+ # Automatically upgrade to latest version
296
+ npx torusguard update --install
297
+ ```
298
+
299
+ - **Zero-Dependency Registry Check:** Queries `https://registry.npmjs.org/torusguard/latest` natively.
300
+ - **SemVer Delta Analysis:** Displays current version against registry latest in standard 75-column cards.
301
+ - **Automated Upgrade Flow:** Executes package installation upon user authorization.
277
302
 
278
303
  ---
279
304
 
@@ -426,7 +451,7 @@ TorusGuard automatically discovers and profiles multi-package workspaces:
426
451
  ## 🧪 Verification & Test Harness
427
452
 
428
453
  ### What Happens When You Run `npm test`?
429
- TorusGuard enforces a strict **100% pass requirement across 120 test suites** before every release.
454
+ TorusGuard enforces a strict **100% pass requirement across 133 tests in 21 test suites** before every release.
430
455
  The test harness runs with **zero third-party dependencies** via standard Python 3:
431
456
 
432
457
  ```bash
@@ -441,11 +466,14 @@ npm test
441
466
  The test harness invokes `python harness/runner.py` directly using the Python standard library. It systematically verifies:
442
467
  1. **JSON Schema Validity:** 10 formal schemas (`finding`, `evidence`, `remediation`, `rule`, `lifecycle`, `provenance`, etc.).
443
468
  2. **74-Rule Catalog Integrity:** AST detection accuracy across all 18 security families.
444
- 3. **Line-Shift Fingerprinting:** Stable anchor matching across file edits without line number drift.
445
- 4. **Secret Redaction:** Stripe secret keys and JWT tokens safely masked.
446
- 5. **Deterministic Replay:** 3-pass differential validation across Django, DRF, FastAPI, Flask, and SQLAlchemy fixtures.
447
- 6. **Ponytail Patch Churn Bounds:** Verifying line budgets ($\le 35$ additions, $\le 25$ deletions).
448
- 7. **Living Security Report State Transitions:** Discovery (`OPEN 🔴`), Candidate (`CANDIDATE 🟡`), Applied (`APPLIED 🔵`), and Verified Closure (`RESOLVED 🟢`).
469
+ 3. **Polyglot Go Engine:** Go module definition, Go stack detection (Gin, Fiber, GORM), and Go AST rules (`TG-INPUT-002`, `TG-INPUT-006`, `TG-SSRF-004`).
470
+ 4. **Line-Shift Fingerprinting:** Stable anchor matching across file edits without line number drift.
471
+ 5. **Secret Redaction:** Stripe secret keys and JWT tokens safely masked.
472
+ 6. **Deterministic Replay:** 3-pass differential validation across Django, DRF, FastAPI, Flask, and SQLAlchemy fixtures.
473
+ 7. **Ponytail Patch Churn Bounds:** Verifying line budgets ($\le 35$ additions, $\le 25$ deletions).
474
+ 8. **Deepened Command Verification:** Audit watch loop & SARIF export, Harden dry-run & severity floor, Recipes search & export, Apply diff preview & snapshot ledger, and Bootstrap templates.
475
+ 9. **Living Security Report State Transitions:** Discovery (`OPEN 🔴`), Candidate (`CANDIDATE 🟡`), Applied (`APPLIED 🔵`), and Verified Closure (`RESOLVED 🟢`).
476
+ 10. **Cryptographic Manifest Parity:** 100% SHA-256 match across all indexed workspace files.
449
477
 
450
478
  ```bash
451
479
  # Run formal TorusGuard test harness
@@ -453,7 +481,7 @@ npm test
453
481
 
454
482
  # Expected Output:
455
483
  # ================================================================================
456
- # SUMMARY: 120 Passed | 0 Failed
484
+ # SUMMARY: 133 Passed | 0 Failed
457
485
  # ================================================================================
458
486
  ```
459
487
 
package/bin/torusguard.js CHANGED
@@ -15,6 +15,51 @@ const command = args[0] || 'init';
15
15
  const rootDir = path.resolve(__dirname, '..');
16
16
  const cwd = process.cwd();
17
17
 
18
+ // Parse version flag immediately
19
+ if (command === '--version' || command === '-v' || command === 'version') {
20
+ let ver = '1.4.0';
21
+ try {
22
+ const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8'));
23
+ ver = pkg.version || ver;
24
+ } catch (e) {}
25
+ console.log(`torusguard v${ver}`);
26
+ process.exit(0);
27
+ }
28
+
29
+ function parseTargetAndArgs(cliArgs) {
30
+ let target = '.';
31
+ const remaining = [];
32
+ for (let i = 1; i < cliArgs.length; i++) {
33
+ const a = cliArgs[i];
34
+ if (a === '--target' || a === '-t' || a === '--root') {
35
+ if (i + 1 < cliArgs.length) {
36
+ target = cliArgs[i + 1];
37
+ i++;
38
+ }
39
+ } else if (a.startsWith('--target=') || a.startsWith('--root=')) {
40
+ target = a.split('=')[1];
41
+ } else {
42
+ remaining.push(a);
43
+ }
44
+ }
45
+ if (target === '.' && remaining.length > 0 && !remaining[0].startsWith('-')) {
46
+ target = remaining.shift();
47
+ }
48
+ return { target, remaining };
49
+ }
50
+
51
+ function compareSemver(a, b) {
52
+ const pa = a.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
53
+ const pb = b.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
54
+ for (let i = 0; i < 3; i++) {
55
+ const na = pa[i] || 0;
56
+ const nb = pb[i] || 0;
57
+ if (na > nb) return 1;
58
+ if (na < nb) return -1;
59
+ }
60
+ return 0;
61
+ }
62
+
18
63
  // ─── ANSI Color Helpers ───────────────────────────────────────────────────────
19
64
  const BOLD = '\x1b[1m';
20
65
  const DIM = '\x1b[2m';
@@ -169,12 +214,13 @@ function cardHeader(title, subtitle = '', version = 'v1.3.6', borderColor = CYAN
169
214
 
170
215
  function printHelp() {
171
216
  console.log();
172
- console.log(cardHeader('🛡️ T O R U S G U A R D C L I', 'Autonomous Security Engine for AI-Built Applications', 'v1.3.6'));
217
+ console.log(cardHeader('🛡️ T O R U S G U A R D C L I', 'Autonomous Security Engine for AI-Built Applications', 'v1.4.0'));
173
218
  console.log(`\n ${BOLD}Usage:${RESET} ${GREEN}npx torusguard${RESET} ${WHITE}[command]${RESET} ${GRAY}[options]${RESET}\n`);
174
219
 
175
220
  console.log(cardBorderTop('Commands'));
176
221
  console.log(formatBoxLine(`${GREEN}init${RESET} Scaffold ${BOLD}.torusguard/${RESET} workspace + unlock slash commands`));
177
222
  console.log(formatBoxLine(`${GREEN}status${RESET} Display active security posture, memory, rules, & stack`));
223
+ console.log(formatBoxLine(`${GREEN}update${RESET} Check npm registry for updates (--install to auto-upgrade)`));
178
224
  console.log(formatBoxLine(`${GREEN}rules${RESET} Auto-sync memory to AI IDE rules (.cursorrules, CLAUDE.md)`));
179
225
  console.log(formatBoxLine(`${GREEN}memory${RESET} Manage persistent security memory (export, hook, learn)`));
180
226
  console.log(formatBoxLine(`${GREEN}audit${RESET} Run static AST security scan on target project`));
@@ -198,6 +244,7 @@ function printHelp() {
198
244
  console.log(formatBoxLine(`${GRAY}--target <dir>${RESET} Target directory to analyze or scaffold ${DIM}(default: .)${RESET}`));
199
245
  console.log(formatBoxLine(`${GRAY}--force${RESET} Overwrite existing workspace and re-scaffold`));
200
246
  console.log(formatBoxLine(`${GRAY}--yes, -y${RESET} Non-interactive auto-approval for patch application`));
247
+ console.log(formatBoxLine(`${GRAY}--version, -v${RESET} Display TorusGuard package version`));
201
248
  console.log(cardBorderBottom());
202
249
 
203
250
  console.log(`\n ${BOLD}AI Chat Commands:${RESET}`);
@@ -219,7 +266,18 @@ if (command === 'help' || command === '--help' || command === '-h') {
219
266
  }
220
267
 
221
268
  if (command === 'status') {
222
- const cfgPath = path.join(cwd, '.torusguard', 'config', 'torusguard.json');
269
+ const { target, remaining } = parseTargetAndArgs(args);
270
+ const targetDir = path.resolve(cwd, target);
271
+ const statusScript = path.join(targetDir, '.torusguard', 'scripts', 'status_runner.py');
272
+ const fallbackStatusScript = path.join(rootDir, '.torusguard', 'scripts', 'status_runner.py');
273
+ const actualStatusScript = fs.existsSync(statusScript) ? statusScript : fallbackStatusScript;
274
+
275
+ if (fs.existsSync(actualStatusScript)) {
276
+ const proc = spawnSync(pythonCmd, [actualStatusScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
277
+ process.exit(proc.status !== null ? proc.status : 0);
278
+ }
279
+
280
+ const cfgPath = path.join(targetDir, '.torusguard', 'config', 'torusguard.json');
223
281
  if (fs.existsSync(cfgPath)) {
224
282
  try {
225
283
  const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
@@ -441,11 +499,13 @@ if (command === 'rules') {
441
499
 
442
500
  // Subcommand: audit
443
501
  if (command === 'audit') {
444
- const auditScript = path.join(cwd, '.torusguard', 'scripts', 'audit_runner.py');
502
+ const { target, remaining } = parseTargetAndArgs(args);
503
+ const targetDir = path.resolve(cwd, target);
504
+ const auditScript = path.join(targetDir, '.torusguard', 'scripts', 'audit_runner.py');
445
505
  const fallbackAuditScript = path.join(rootDir, '.torusguard', 'scripts', 'audit_runner.py');
446
506
  const actualAuditScript = fs.existsSync(fallbackAuditScript) ? fallbackAuditScript : auditScript;
447
507
 
448
- const proc = spawnSync(pythonCmd, [actualAuditScript, ...args.slice(1)], { stdio: 'inherit', cwd });
508
+ const proc = spawnSync(pythonCmd, [actualAuditScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
449
509
  process.exit(proc.status !== null ? proc.status : 0);
450
510
  }
451
511
 
@@ -455,7 +515,7 @@ if (command === 'report') {
455
515
  const wantSarif = args.includes('--sarif') || (!wantHtml && args[1] !== 'html');
456
516
 
457
517
  // Resolve target directory (supports --target and --root)
458
- const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : args.indexOf('--target');
518
+ const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : (args.indexOf('--target') !== -1 ? args.indexOf('--target') : args.indexOf('-t'));
459
519
  let targetRoot = cwd;
460
520
  if (rootIdx !== -1 && args[rootIdx + 1]) {
461
521
  targetRoot = path.resolve(cwd, args[rootIdx + 1]);
@@ -518,69 +578,179 @@ if (command === 'report') {
518
578
 
519
579
  // Subcommand: harden
520
580
  if (command === 'harden') {
521
- const scriptPath = path.join(cwd, '.torusguard', 'scripts', 'harden_runner.py');
581
+ const { target, remaining } = parseTargetAndArgs(args);
582
+ const targetDir = path.resolve(cwd, target);
583
+ const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'harden_runner.py');
522
584
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'harden_runner.py');
523
585
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
524
586
 
525
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
587
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
526
588
  process.exit(proc.status !== null ? proc.status : 0);
527
589
  }
528
590
 
529
591
  // Subcommand: apply
530
592
  if (command === 'apply') {
531
- const scriptPath = path.join(cwd, '.torusguard', 'scripts', 'apply_runner.py');
593
+ const { target, remaining } = parseTargetAndArgs(args);
594
+ const targetDir = path.resolve(cwd, target);
595
+ const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'apply_runner.py');
532
596
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
533
597
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
534
598
 
535
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
599
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
536
600
  process.exit(proc.status !== null ? proc.status : 0);
537
601
  }
538
602
 
539
603
  // Subcommand: rollback
540
604
  if (command === 'rollback') {
541
- const scriptPath = path.join(cwd, '.torusguard', 'scripts', 'apply_runner.py');
605
+ const { target, remaining } = parseTargetAndArgs(args);
606
+ const targetDir = path.resolve(cwd, target);
607
+ const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'apply_runner.py');
542
608
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
543
609
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
544
610
 
545
- const proc = spawnSync(pythonCmd, [actualScript, '--rollback', ...args.slice(1)], { stdio: 'inherit', cwd });
611
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, '--rollback', ...remaining], { stdio: 'inherit', cwd: targetDir });
546
612
  process.exit(proc.status !== null ? proc.status : 0);
547
613
  }
548
614
 
549
615
  // Subcommand: recheck / verify
550
616
  if (command === 'recheck' || command === 'verify') {
551
- const scriptPath = path.join(cwd, '.torusguard', 'scripts', 'recheck_runner.py');
617
+ const { target, remaining } = parseTargetAndArgs(args);
618
+ const targetDir = path.resolve(cwd, target);
619
+ const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'recheck_runner.py');
552
620
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recheck_runner.py');
553
621
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
554
622
 
555
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
623
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
556
624
  process.exit(proc.status !== null ? proc.status : 0);
557
625
  }
558
626
 
559
627
  // Subcommand: recipes
560
628
  if (command === 'recipes') {
561
- const scriptPath = path.join(cwd, '.torusguard', 'scripts', 'recipes_runner.py');
629
+ const { target, remaining } = parseTargetAndArgs(args);
630
+ const targetDir = path.resolve(cwd, target);
631
+ const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'recipes_runner.py');
562
632
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recipes_runner.py');
563
633
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
564
634
 
565
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
635
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
566
636
  process.exit(proc.status !== null ? proc.status : 0);
567
637
  }
568
638
 
569
639
  // Subcommand: init (scaffold workspace)
570
640
  if (command === 'init') {
641
+ const { target, remaining } = parseTargetAndArgs(args);
642
+ const targetDir = path.resolve(cwd, target);
571
643
  const localBootstrap = path.join(rootDir, 'skills', 'torusguard', 'bootstrap.py');
572
644
  const localInstall = path.join(rootDir, 'install.py');
573
645
  const scriptToRun = fs.existsSync(localBootstrap) ? localBootstrap : localInstall;
574
646
 
575
- const scriptArgs = [scriptToRun, '--full-commands', ...args.slice(1)];
647
+ const scriptArgs = [scriptToRun, '--full-commands', '--target', targetDir, ...remaining];
576
648
  const proc = spawnSync(pythonCmd, scriptArgs, {
577
649
  stdio: 'inherit',
578
- cwd: cwd,
650
+ cwd: targetDir,
579
651
  });
580
652
  process.exit(proc.status !== null ? proc.status : 0);
581
653
  }
582
654
 
655
+ // Subcommand: update
656
+ if (command === 'update') {
657
+ const https = require('https');
658
+ const pkgJsonPath = path.join(rootDir, 'package.json');
659
+ let currentVersion = '1.4.0';
660
+ try {
661
+ if (fs.existsSync(pkgJsonPath)) {
662
+ currentVersion = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')).version || currentVersion;
663
+ }
664
+ } catch (e) {}
665
+
666
+ console.log();
667
+ console.log(cardHeader('🛡️ TORUSGUARD UPDATE CHECK', 'Package Distribution & Registry Verifier', `v${currentVersion}`));
668
+ console.log(`\n ${DIM}Checking npm registry for updates...${RESET}`);
669
+
670
+ const autoInstall = args.includes('--install') || args.includes('-i') || args.includes('--yes') || args.includes('-y');
671
+
672
+ function printUpdateOffline(reason) {
673
+ console.log();
674
+ console.log(cardBorderTop('Offline / Registry Unreachable', YELLOW));
675
+ console.log(formatBoxLine(`Current: ${WHITE}v${currentVersion}${RESET}`, 67, '│', YELLOW));
676
+ console.log(formatBoxLine(`Notice: ${DIM}${reason}${RESET}`, 67, '│', YELLOW));
677
+ console.log(formatBoxLine(`Manual: ${BOLD}${CYAN}npm update torusguard${RESET} or ${BOLD}${CYAN}npm i -g torusguard@latest${RESET}`, 67, '│', YELLOW));
678
+ console.log(cardBorderBottom(YELLOW));
679
+ console.log();
680
+ process.exit(0);
681
+ }
682
+
683
+ const req = https.get('https://registry.npmjs.org/torusguard/latest', {
684
+ headers: { 'User-Agent': `torusguard-cli/${currentVersion}` },
685
+ timeout: 6000
686
+ }, (res) => {
687
+ let raw = '';
688
+ res.on('data', chunk => raw += chunk);
689
+ res.on('end', () => {
690
+ try {
691
+ const data = JSON.parse(raw);
692
+ const latestVersion = data.version;
693
+ if (!latestVersion) {
694
+ printUpdateOffline('No version field returned in npm registry response');
695
+ return;
696
+ }
697
+
698
+ const isNewer = compareSemver(latestVersion, currentVersion) > 0;
699
+ console.log();
700
+ console.log(cardBorderTop('Version Telemetry', CYAN));
701
+ console.log(formatBoxLine(`Installed Version: ${WHITE}v${currentVersion}${RESET}`));
702
+ console.log(formatBoxLine(`Latest on NPM: ${BOLD}${GREEN}v${latestVersion}${RESET}`));
703
+ console.log(cardBorderBottom(CYAN));
704
+ console.log();
705
+
706
+ if (isNewer) {
707
+ console.log(cardBorderTop('Update Available', YELLOW, true));
708
+ console.log(formatBoxLine(`${YELLOW}A new version of TorusGuard is available!${RESET}`, 67, '║', YELLOW));
709
+ console.log(formatBoxLine(`Global: ${BOLD}${WHITE}npm install -g torusguard@latest${RESET}`, 67, '║', YELLOW));
710
+ console.log(formatBoxLine(`Local: ${BOLD}${WHITE}npm install torusguard@latest${RESET}`, 67, '║', YELLOW));
711
+ console.log(cardBorderBottom(YELLOW, true));
712
+ console.log();
713
+
714
+ if (autoInstall) {
715
+ console.log(` ${CYAN}Auto-installing latest version via npm...${RESET}`);
716
+ const npmProc = spawnSync('npm', ['install', '-g', 'torusguard@latest'], { stdio: 'inherit' });
717
+ if (npmProc.status === 0) {
718
+ console.log(`\n ${GREEN}✔ Successfully upgraded TorusGuard to v${latestVersion}!${RESET}\n`);
719
+ } else {
720
+ console.error(`\n ${RED}✖ Failed to auto-install update. Run: npm install -g torusguard@latest${RESET}\n`);
721
+ }
722
+ } else {
723
+ console.log(` ${DIM}Tip: Run with ${CYAN}npx torusguard update --install${DIM} to auto-upgrade.${RESET}\n`);
724
+ }
725
+ } else {
726
+ console.log(cardBorderTop('Status: Up To Date', GREEN, true));
727
+ console.log(formatBoxLine(`${GREEN}✔ TorusGuard is up to date (v${currentVersion})${RESET}`, 67, '║', GREEN));
728
+ console.log(cardBorderBottom(GREEN, true));
729
+ console.log();
730
+ }
731
+ process.exit(0);
732
+ } catch (err) {
733
+ printUpdateOffline(err.message);
734
+ }
735
+ });
736
+ });
737
+
738
+ req.on('error', (err) => printUpdateOffline(err.message));
739
+ req.on('timeout', () => {
740
+ req.destroy();
741
+ printUpdateOffline('npm registry request timed out (6000ms)');
742
+ });
743
+ }
744
+
583
745
  // Unknown command fallback
584
- console.error(`\n ${RED}✖ Unknown command:${RESET} ${WHITE}${command}${RESET}`);
585
- console.error(` Run ${GREEN}npx torusguard help${RESET} for available commands.\n`);
586
- process.exit(1);
746
+ const KNOWN_COMMANDS = new Set([
747
+ 'init', 'status', 'rules', 'memory', 'diff-guard', 'audit',
748
+ 'report', 'harden', 'apply', 'rollback', 'recheck', 'verify',
749
+ 'recipes', 'update', 'help', '--help', '-h', '--version', '-v', 'version'
750
+ ]);
751
+
752
+ if (!KNOWN_COMMANDS.has(command)) {
753
+ console.error(`\n ${RED}✖ Unknown command:${RESET} ${WHITE}${command}${RESET}`);
754
+ console.error(` Run ${GREEN}npx torusguard help${RESET} for available commands.\n`);
755
+ process.exit(1);
756
+ }