torusguard 1.3.5 → 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 (194) hide show
  1. package/.torusguard/.manifest.json +37 -36
  2. package/.torusguard/runs/report-latest.html +5862 -315
  3. package/.torusguard/runs/results-latest.sarif +20 -0
  4. package/.torusguard/runs/run-20260918-104221-audit/findings.json +1 -0
  5. package/.torusguard/runs/run-20260918-104221-audit/findings.md +8 -0
  6. package/.torusguard/runs/run-20260918-104221-audit/manifest.json +12 -0
  7. package/.torusguard/runs/run-20260918-104221-audit/summary.md +5 -0
  8. package/.torusguard/runs/run-20260918-104236-audit/findings.json +2314 -0
  9. package/.torusguard/runs/run-20260918-104236-audit/findings.md +960 -0
  10. package/.torusguard/runs/run-20260918-104236-audit/manifest.json +12 -0
  11. package/.torusguard/runs/run-20260918-104236-audit/summary.md +5 -0
  12. package/.torusguard/runs/run-20260918-105723-audit/findings.json +2382 -0
  13. package/.torusguard/runs/run-20260918-105723-audit/findings.md +960 -0
  14. package/.torusguard/runs/run-20260918-105723-audit/manifest.json +12 -0
  15. package/.torusguard/runs/run-20260918-105723-audit/summary.md +5 -0
  16. package/.torusguard/runs/run-20260918-105731-audit/findings.json +1 -0
  17. package/.torusguard/runs/run-20260918-105731-audit/findings.md +8 -0
  18. package/.torusguard/runs/run-20260918-105731-audit/manifest.json +12 -0
  19. package/.torusguard/runs/run-20260918-105731-audit/summary.md +5 -0
  20. package/.torusguard/runs/run-20260918-105940-audit/findings.json +1 -0
  21. package/.torusguard/runs/run-20260918-105940-audit/findings.md +8 -0
  22. package/.torusguard/runs/run-20260918-105940-audit/manifest.json +13 -0
  23. package/.torusguard/runs/run-20260918-105940-audit/remediation.md +7 -0
  24. package/.torusguard/runs/run-20260918-105940-audit/summary.md +5 -0
  25. package/.torusguard/runs/run-20260919-145701-audit/findings.json +1 -0
  26. package/.torusguard/runs/run-20260919-145701-audit/findings.md +8 -0
  27. package/.torusguard/runs/run-20260919-145701-audit/manifest.json +12 -0
  28. package/.torusguard/runs/run-20260919-145701-audit/summary.md +5 -0
  29. package/.torusguard/runs/run-20260919-151729-audit/findings.json +1 -0
  30. package/.torusguard/runs/run-20260919-151729-audit/findings.md +8 -0
  31. package/.torusguard/runs/run-20260919-151729-audit/manifest.json +13 -0
  32. package/.torusguard/runs/run-20260919-151729-audit/remediation.md +7 -0
  33. package/.torusguard/runs/run-20260919-151729-audit/summary.md +5 -0
  34. package/.torusguard/runs/run-20260919-152340-audit/findings.json +1 -0
  35. package/.torusguard/runs/run-20260919-152340-audit/findings.md +8 -0
  36. package/.torusguard/runs/run-20260919-152340-audit/manifest.json +12 -0
  37. package/.torusguard/runs/run-20260919-152340-audit/summary.md +5 -0
  38. package/.torusguard/runs/run-20260919-152345-audit/findings.json +1 -0
  39. package/.torusguard/runs/run-20260919-152345-audit/findings.md +8 -0
  40. package/.torusguard/runs/run-20260919-152345-audit/manifest.json +12 -0
  41. package/.torusguard/runs/run-20260919-152345-audit/summary.md +5 -0
  42. package/.torusguard/runs/run-20260919-153500-audit/findings.json +1 -0
  43. package/.torusguard/runs/run-20260919-153500-audit/findings.md +8 -0
  44. package/.torusguard/runs/run-20260919-153500-audit/manifest.json +12 -0
  45. package/.torusguard/runs/run-20260919-153500-audit/summary.md +5 -0
  46. package/.torusguard/scripts/__pycache__/apply_runner.cpython-314.pyc +0 -0
  47. package/.torusguard/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
  48. package/.torusguard/scripts/__pycache__/diff_guard.cpython-314.pyc +0 -0
  49. package/.torusguard/scripts/__pycache__/finding_scorer.cpython-314.pyc +0 -0
  50. package/.torusguard/scripts/__pycache__/harden_runner.cpython-314.pyc +0 -0
  51. package/.torusguard/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
  52. package/.torusguard/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
  53. package/.torusguard/scripts/__pycache__/memory_engine.cpython-314.pyc +0 -0
  54. package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-314.pyc +0 -0
  55. package/.torusguard/scripts/__pycache__/recheck_runner.cpython-314.pyc +0 -0
  56. package/.torusguard/scripts/__pycache__/recipes_runner.cpython-314.pyc +0 -0
  57. package/.torusguard/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
  58. package/.torusguard/scripts/__pycache__/run_manager.cpython-314.pyc +0 -0
  59. package/.torusguard/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
  60. package/.torusguard/scripts/__pycache__/stack_detect.cpython-314.pyc +0 -0
  61. package/.torusguard/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
  62. package/.torusguard/scripts/apply_runner.py +108 -9
  63. package/.torusguard/scripts/audit_runner.py +336 -24
  64. package/.torusguard/scripts/harden_runner.py +124 -70
  65. package/.torusguard/scripts/html_reporter.py +3585 -648
  66. package/.torusguard/scripts/manifest_builder.py +2 -0
  67. package/.torusguard/scripts/recheck_runner.py +5 -4
  68. package/.torusguard/scripts/recipes_runner.py +91 -8
  69. package/.torusguard/scripts/report_sync.py +496 -73
  70. package/.torusguard/scripts/sarif_exporter.py +48 -8
  71. package/.torusguard/scripts/stack_detect.py +44 -2
  72. package/.torusguard/scripts/status_runner.py +267 -0
  73. package/.torusguard/scripts/term_ui.py +1 -1
  74. package/.torusguard/skills/torusguard/SKILL.md +75 -72
  75. package/.torusguard/skills/torusguard-apply/SKILL.md +84 -80
  76. package/.torusguard/skills/torusguard-audit/SKILL.md +87 -83
  77. package/.torusguard/skills/torusguard-authorize/SKILL.md +7 -2
  78. package/.torusguard/skills/torusguard-exploit-check/SKILL.md +7 -2
  79. package/.torusguard/skills/torusguard-full/SKILL.md +7 -2
  80. package/.torusguard/skills/torusguard-harden/SKILL.md +98 -94
  81. package/.torusguard/skills/torusguard-init/SKILL.md +68 -64
  82. package/.torusguard/skills/torusguard-recheck/SKILL.md +81 -77
  83. package/.torusguard/skills/torusguard-report/SKILL.md +93 -72
  84. package/.torusguard/skills/torusguard-status/SKILL.md +62 -58
  85. package/.torusguard/skills/torusguard-verify/SKILL.md +7 -2
  86. package/.torusguard/skills/torusguard-web-validate/SKILL.md +7 -2
  87. package/.torusguard/workflows/apply.md +1 -1
  88. package/.torusguard/workflows/audit.md +1 -1
  89. package/.torusguard/workflows/authorize.md +1 -1
  90. package/.torusguard/workflows/exploit-check.md +1 -1
  91. package/.torusguard/workflows/harden.md +1 -1
  92. package/.torusguard/workflows/init.md +1 -1
  93. package/.torusguard/workflows/memory.md +1 -1
  94. package/.torusguard/workflows/recheck.md +1 -1
  95. package/.torusguard/workflows/report.md +1 -1
  96. package/.torusguard/workflows/status.md +1 -1
  97. package/.torusguard/workflows/verify.md +1 -1
  98. package/.torusguard/workflows/web-validate.md +1 -1
  99. package/README.md +115 -81
  100. package/bin/torusguard.js +244 -38
  101. package/package.json +6 -2
  102. package/skills/torusguard/SKILL.md +1 -1
  103. package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
  104. package/skills/torusguard/bootstrap.py +52 -8
  105. package/skills/torusguard/payload/.manifest.json +51 -36
  106. package/skills/torusguard/payload/scripts/__pycache__/apply_runner.cpython-314.pyc +0 -0
  107. package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
  108. package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
  109. package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  110. package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-314.pyc +0 -0
  111. package/skills/torusguard/payload/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
  112. package/skills/torusguard/payload/scripts/__pycache__/finding_scorer.cpython-314.pyc +0 -0
  113. package/skills/torusguard/payload/scripts/__pycache__/harden_runner.cpython-314.pyc +0 -0
  114. package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-311.pyc +0 -0
  115. package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
  116. package/skills/torusguard/payload/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
  117. package/skills/torusguard/payload/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
  118. package/skills/torusguard/payload/scripts/__pycache__/memory_engine.cpython-314.pyc +0 -0
  119. package/skills/torusguard/payload/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
  120. package/skills/torusguard/payload/scripts/__pycache__/monorepo_detector.cpython-314.pyc +0 -0
  121. package/skills/torusguard/payload/scripts/__pycache__/recheck_runner.cpython-314.pyc +0 -0
  122. package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-311.pyc +0 -0
  123. package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
  124. package/skills/torusguard/payload/scripts/__pycache__/rules_sync.cpython-311.pyc +0 -0
  125. package/skills/torusguard/payload/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
  126. package/skills/torusguard/payload/scripts/__pycache__/run_manager.cpython-314.pyc +0 -0
  127. package/skills/torusguard/payload/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
  128. package/skills/torusguard/payload/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
  129. package/skills/torusguard/payload/scripts/__pycache__/stack_detect.cpython-314.pyc +0 -0
  130. package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-311.pyc +0 -0
  131. package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
  132. package/skills/torusguard/payload/scripts/apply_runner.py +108 -9
  133. package/skills/torusguard/payload/scripts/audit_runner.py +336 -24
  134. package/skills/torusguard/payload/scripts/harden_runner.py +124 -70
  135. package/skills/torusguard/payload/scripts/html_reporter.py +3585 -648
  136. package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
  137. package/skills/torusguard/payload/scripts/recheck_runner.py +5 -4
  138. package/skills/torusguard/payload/scripts/recipes_runner.py +91 -8
  139. package/skills/torusguard/payload/scripts/report_sync.py +496 -73
  140. package/skills/torusguard/payload/scripts/sarif_exporter.py +48 -8
  141. package/skills/torusguard/payload/scripts/stack_detect.py +44 -2
  142. package/skills/torusguard/payload/scripts/status_runner.py +267 -0
  143. package/skills/torusguard/payload/scripts/term_ui.py +1 -1
  144. package/skills/torusguard/payload/skills/torusguard/SKILL.md +1 -1
  145. package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +1 -1
  146. package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +1 -1
  147. package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +1 -1
  148. package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +1 -1
  149. package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +1 -1
  150. package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +1 -1
  151. package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +1 -1
  152. package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +1 -1
  153. package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +40 -23
  154. package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +1 -1
  155. package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +1 -1
  156. package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +1 -1
  157. package/skills/torusguard/payload/workflows/apply.md +9 -1
  158. package/skills/torusguard/payload/workflows/audit.md +8 -2
  159. package/skills/torusguard/payload/workflows/authorize.md +1 -1
  160. package/skills/torusguard/payload/workflows/exploit-check.md +1 -1
  161. package/skills/torusguard/payload/workflows/harden.md +6 -1
  162. package/skills/torusguard/payload/workflows/init.md +7 -1
  163. package/skills/torusguard/payload/workflows/memory.md +1 -1
  164. package/skills/torusguard/payload/workflows/recheck.md +1 -1
  165. package/skills/torusguard/payload/workflows/recipes.md +55 -0
  166. package/skills/torusguard/payload/workflows/report.md +59 -55
  167. package/skills/torusguard/payload/workflows/status.md +4 -1
  168. package/skills/torusguard/payload/workflows/torusguard-apply.md +110 -0
  169. package/skills/torusguard/payload/workflows/torusguard-audit.md +105 -0
  170. package/skills/torusguard/payload/workflows/torusguard-authorize.md +96 -0
  171. package/skills/torusguard/payload/workflows/torusguard-exploit-check.md +98 -0
  172. package/skills/torusguard/payload/workflows/torusguard-harden.md +104 -0
  173. package/skills/torusguard/payload/workflows/torusguard-init.md +106 -0
  174. package/skills/torusguard/payload/workflows/torusguard-recheck.md +101 -0
  175. package/skills/torusguard/payload/workflows/torusguard-recipes.md +55 -0
  176. package/skills/torusguard/payload/workflows/torusguard-report.md +105 -0
  177. package/skills/torusguard/payload/workflows/torusguard-status.md +103 -0
  178. package/skills/torusguard/payload/workflows/torusguard-verify.md +100 -0
  179. package/skills/torusguard/payload/workflows/torusguard-web-validate.md +96 -0
  180. package/skills/torusguard/payload/workflows/torusguard.md +19 -0
  181. package/skills/torusguard/payload/workflows/verify.md +1 -1
  182. package/skills/torusguard/payload/workflows/web-validate.md +1 -1
  183. package/skills/torusguard-apply/SKILL.md +1 -1
  184. package/skills/torusguard-audit/SKILL.md +1 -1
  185. package/skills/torusguard-authorize/SKILL.md +1 -1
  186. package/skills/torusguard-exploit-check/SKILL.md +1 -1
  187. package/skills/torusguard-full/SKILL.md +1 -1
  188. package/skills/torusguard-harden/SKILL.md +1 -1
  189. package/skills/torusguard-init/SKILL.md +1 -1
  190. package/skills/torusguard-recheck/SKILL.md +1 -1
  191. package/skills/torusguard-report/SKILL.md +40 -23
  192. package/skills/torusguard-status/SKILL.md +1 -1
  193. package/skills/torusguard-verify/SKILL.md +1 -1
  194. package/skills/torusguard-web-validate/SKILL.md +1 -1
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';
@@ -151,7 +196,7 @@ function cardDivider(title = '', borderColor = CYAN, double = false) {
151
196
  return ` ${borderColor}${left}${h.repeat(71)}${right}${RESET}`;
152
197
  }
153
198
 
154
- function cardHeader(title, subtitle = '', version = 'v1.3.5', borderColor = CYAN) {
199
+ function cardHeader(title, subtitle = '', version = 'v1.3.6', borderColor = CYAN) {
155
200
  const top = ` ${borderColor}╭${'─'.repeat(71)}╮${RESET}`;
156
201
  const bottom = ` ${borderColor}╰${'─'.repeat(71)}╯${RESET}`;
157
202
  const empty = ` ${borderColor}│${' '.repeat(71)}│${RESET}`;
@@ -169,12 +214,13 @@ function cardHeader(title, subtitle = '', version = 'v1.3.5', 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.5'));
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`));
@@ -189,6 +235,7 @@ function printHelp() {
189
235
  console.log(cardDivider('AI & Memory Subcommands'));
190
236
  console.log(formatBoxLine(`${WHITE}rules sync${RESET} ${DIM}[--format all|cursor|claude|agent|windsurf]${RESET}`));
191
237
  console.log(formatBoxLine(`${WHITE}report --html${RESET} ${DIM}[--out <path>] Self-contained visual HTML dashboard${RESET}`));
238
+ console.log(formatBoxLine(`${WHITE}report --sarif${RESET} ${DIM}[--out <path>] OASIS SARIF v2.1.0 GitHub Scanning log${RESET}`));
192
239
  console.log(formatBoxLine(`${WHITE}memory context${RESET} ${DIM}[--role auditor|remediator|reviewer] [--file <f>]${RESET}`));
193
240
  console.log(formatBoxLine(`${WHITE}memory hook${RESET} ${DIM}[install|uninstall] Git pre-commit regression hook${RESET}`));
194
241
  console.log(formatBoxLine(`${WHITE}memory learn${RESET} ${DIM}[--commits <range>] Ingest security commit fixes${RESET}`));
@@ -197,6 +244,7 @@ function printHelp() {
197
244
  console.log(formatBoxLine(`${GRAY}--target <dir>${RESET} Target directory to analyze or scaffold ${DIM}(default: .)${RESET}`));
198
245
  console.log(formatBoxLine(`${GRAY}--force${RESET} Overwrite existing workspace and re-scaffold`));
199
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`));
200
248
  console.log(cardBorderBottom());
201
249
 
202
250
  console.log(`\n ${BOLD}AI Chat Commands:${RESET}`);
@@ -218,7 +266,18 @@ if (command === 'help' || command === '--help' || command === '-h') {
218
266
  }
219
267
 
220
268
  if (command === 'status') {
221
- 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');
222
281
  if (fs.existsSync(cfgPath)) {
223
282
  try {
224
283
  const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
@@ -250,7 +309,7 @@ if (command === 'status') {
250
309
  }
251
310
 
252
311
  console.log();
253
- console.log(cardHeader('🛡️ TORUSGUARD SECURITY POSTURE', '', 'v1.3.5'));
312
+ console.log(cardHeader('🛡️ TORUSGUARD SECURITY POSTURE', '', 'v1.3.6'));
254
313
  console.log(`\n ${BOLD}▸ Workspace:${RESET} ${GREEN}${cwd}${RESET}`);
255
314
  console.log(` ${BOLD}▸ Governance:${RESET} ${GREEN}Full Local Governance (.torusguard/)${RESET}`);
256
315
  console.log(` ${BOLD}▸ Living Report:${RESET} ${CYAN}security_report.md${RESET}\n`);
@@ -440,111 +499,258 @@ if (command === 'rules') {
440
499
 
441
500
  // Subcommand: audit
442
501
  if (command === 'audit') {
443
- 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');
444
505
  const fallbackAuditScript = path.join(rootDir, '.torusguard', 'scripts', 'audit_runner.py');
445
506
  const actualAuditScript = fs.existsSync(fallbackAuditScript) ? fallbackAuditScript : auditScript;
446
507
 
447
- const proc = spawnSync(pythonCmd, [actualAuditScript, ...args.slice(1)], { stdio: 'inherit', cwd });
508
+ const proc = spawnSync(pythonCmd, [actualAuditScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
448
509
  process.exit(proc.status !== null ? proc.status : 0);
449
510
  }
450
511
 
451
512
  // Subcommand: report
452
513
  if (command === 'report') {
453
- if (args.includes('--html') || args[1] === 'html') {
454
- const htmlScript = path.join(cwd, '.torusguard', 'scripts', 'html_reporter.py');
514
+ const wantHtml = args.includes('--html') || args[1] === 'html' || args.includes('--out');
515
+ const wantSarif = args.includes('--sarif') || (!wantHtml && args[1] !== 'html');
516
+
517
+ // Resolve target directory (supports --target and --root)
518
+ const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : (args.indexOf('--target') !== -1 ? args.indexOf('--target') : args.indexOf('-t'));
519
+ let targetRoot = cwd;
520
+ if (rootIdx !== -1 && args[rootIdx + 1]) {
521
+ targetRoot = path.resolve(cwd, args[rootIdx + 1]);
522
+ }
523
+
524
+ let exitCode = 0;
525
+
526
+ // 1. If SARIF export is requested
527
+ if (wantSarif) {
528
+ const sarifScript = path.join(targetRoot, '.torusguard', 'scripts', 'sarif_exporter.py');
529
+ const fallbackSarifScript = path.join(rootDir, '.torusguard', 'scripts', 'sarif_exporter.py');
530
+ const actualSarifScript = fs.existsSync(fallbackSarifScript) ? fallbackSarifScript : sarifScript;
531
+
532
+ const sarifArgs = [actualSarifScript, '--root', targetRoot];
533
+ const sarifOutIdx = args.indexOf('--sarif-out');
534
+ if (sarifOutIdx !== -1 && args[sarifOutIdx + 1]) {
535
+ sarifArgs.push('--output', args[sarifOutIdx + 1]);
536
+ } else if (!wantHtml) {
537
+ const outIdx = args.indexOf('--out');
538
+ if (outIdx !== -1 && args[outIdx + 1]) {
539
+ sarifArgs.push('--output', args[outIdx + 1]);
540
+ }
541
+ }
542
+ const runIdIdx = args.indexOf('--run');
543
+ if (runIdIdx !== -1 && args[runIdIdx + 1]) {
544
+ sarifArgs.push('--run-id', args[runIdIdx + 1]);
545
+ }
546
+
547
+ const proc = spawnSync(pythonCmd, sarifArgs, { stdio: 'inherit', cwd: targetRoot });
548
+ if (proc.status !== 0 && proc.status !== null) {
549
+ exitCode = proc.status;
550
+ }
551
+ }
552
+
553
+ // 2. If Visual HTML dashboard is requested
554
+ if (wantHtml) {
555
+ const htmlScript = path.join(targetRoot, '.torusguard', 'scripts', 'html_reporter.py');
455
556
  const fallbackHtmlScript = path.join(rootDir, '.torusguard', 'scripts', 'html_reporter.py');
456
557
  const actualHtmlScript = fs.existsSync(fallbackHtmlScript) ? fallbackHtmlScript : htmlScript;
457
558
 
458
- let pyArgs = [actualHtmlScript];
559
+ let pyArgs = [actualHtmlScript, '--root', targetRoot];
459
560
  const outIdx = args.indexOf('--out');
460
561
  if (outIdx !== -1 && args[outIdx + 1]) {
461
- pyArgs.push('--out', args[outIdx + 1]);
462
- }
463
- const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : args.indexOf('--target');
464
- if (rootIdx !== -1 && args[rootIdx + 1]) {
465
- pyArgs.push('--root', args[rootIdx + 1]);
562
+ pyArgs.push('--out', path.resolve(cwd, args[outIdx + 1]));
563
+ } else {
564
+ pyArgs.push('--out', path.join(targetRoot, 'report.html'));
466
565
  }
467
566
  if (args.includes('--json')) {
468
567
  pyArgs.push('--json');
469
568
  }
470
569
 
471
- const proc = spawnSync(pythonCmd, pyArgs, { stdio: 'inherit', cwd });
472
- process.exit(proc.status !== null ? proc.status : 0);
473
- } else {
474
- const sarifScript = path.join(cwd, '.torusguard', 'scripts', 'sarif_exporter.py');
475
- const fallbackSarifScript = path.join(rootDir, '.torusguard', 'scripts', 'sarif_exporter.py');
476
- const actualSarifScript = fs.existsSync(fallbackSarifScript) ? fallbackSarifScript : sarifScript;
477
-
478
- const proc = spawnSync(pythonCmd, [actualSarifScript, ...args.slice(1)], { stdio: 'inherit', cwd });
479
- process.exit(proc.status !== null ? proc.status : 0);
570
+ const proc = spawnSync(pythonCmd, pyArgs, { stdio: 'inherit', cwd: targetRoot });
571
+ if (proc.status !== 0 && proc.status !== null) {
572
+ exitCode = proc.status;
573
+ }
480
574
  }
575
+
576
+ process.exit(exitCode);
481
577
  }
482
578
 
483
579
  // Subcommand: harden
484
580
  if (command === 'harden') {
485
- 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');
486
584
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'harden_runner.py');
487
585
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
488
586
 
489
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
587
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
490
588
  process.exit(proc.status !== null ? proc.status : 0);
491
589
  }
492
590
 
493
591
  // Subcommand: apply
494
592
  if (command === 'apply') {
495
- 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');
496
596
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
497
597
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
498
598
 
499
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
599
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
500
600
  process.exit(proc.status !== null ? proc.status : 0);
501
601
  }
502
602
 
503
603
  // Subcommand: rollback
504
604
  if (command === 'rollback') {
505
- 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');
506
608
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
507
609
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
508
610
 
509
- 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 });
510
612
  process.exit(proc.status !== null ? proc.status : 0);
511
613
  }
512
614
 
513
615
  // Subcommand: recheck / verify
514
616
  if (command === 'recheck' || command === 'verify') {
515
- 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');
516
620
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recheck_runner.py');
517
621
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
518
622
 
519
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
623
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
520
624
  process.exit(proc.status !== null ? proc.status : 0);
521
625
  }
522
626
 
523
627
  // Subcommand: recipes
524
628
  if (command === 'recipes') {
525
- 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');
526
632
  const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recipes_runner.py');
527
633
  const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
528
634
 
529
- const proc = spawnSync(pythonCmd, [actualScript, ...args.slice(1)], { stdio: 'inherit', cwd });
635
+ const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
530
636
  process.exit(proc.status !== null ? proc.status : 0);
531
637
  }
532
638
 
533
639
  // Subcommand: init (scaffold workspace)
534
640
  if (command === 'init') {
641
+ const { target, remaining } = parseTargetAndArgs(args);
642
+ const targetDir = path.resolve(cwd, target);
535
643
  const localBootstrap = path.join(rootDir, 'skills', 'torusguard', 'bootstrap.py');
536
644
  const localInstall = path.join(rootDir, 'install.py');
537
645
  const scriptToRun = fs.existsSync(localBootstrap) ? localBootstrap : localInstall;
538
646
 
539
- const scriptArgs = [scriptToRun, '--full-commands', ...args.slice(1)];
647
+ const scriptArgs = [scriptToRun, '--full-commands', '--target', targetDir, ...remaining];
540
648
  const proc = spawnSync(pythonCmd, scriptArgs, {
541
649
  stdio: 'inherit',
542
- cwd: cwd,
650
+ cwd: targetDir,
543
651
  });
544
652
  process.exit(proc.status !== null ? proc.status : 0);
545
653
  }
546
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
+
547
745
  // Unknown command fallback
548
- console.error(`\n ${RED}✖ Unknown command:${RESET} ${WHITE}${command}${RESET}`);
549
- console.error(` Run ${GREEN}npx torusguard help${RESET} for available commands.\n`);
550
- 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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "torusguard",
3
- "version": "1.3.5",
3
+ "version": "1.4.0",
4
4
  "description": "Security guardrails, governed remediation, and authorized runtime validation for AI-built web applications.",
5
5
  "main": "bin/torusguard.js",
6
6
  "bin": {
@@ -17,8 +17,12 @@
17
17
  "scripts": {
18
18
  "test": "python harness/runner.py",
19
19
  "init": "node bin/torusguard.js init",
20
+ "status": "node bin/torusguard.js status",
20
21
  "audit": "node bin/torusguard.js audit",
21
- "status": "node bin/torusguard.js status"
22
+ "harden": "node bin/torusguard.js harden",
23
+ "apply": "node bin/torusguard.js apply",
24
+ "recipes": "node bin/torusguard.js recipes",
25
+ "update": "node bin/torusguard.js update"
22
26
  },
23
27
  "keywords": [
24
28
  "security",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: torusguard
3
3
  description: Universal autonomous security engine: 74 canonical rules across 18 families, polyglot stack detection across 16+ languages, Ponytail remediation bounds (<=35 add, <=25 del), standardized 75-column terminal UI, living security_report.md ground-truth ledger, SARIF v2.1.0 exports, and persistent security memory context.
4
- version: 1.3.5
4
+ version: 1.3.6
5
5
  ---
6
6
 
7
7
  # TorusGuard Master Security Engine & Command Router
@@ -135,7 +135,7 @@ def print_header():
135
135
  print(f"""
136
136
  {CYAN}╭─────────────────────────────────────────────────────────────────────────╮{RESET}
137
137
  {CYAN}│{RESET} {CYAN}│{RESET}
138
- {CYAN}│{RESET} {BOLD}{WHITE}🛡️ T O R U S G U A R D{RESET} {GRAY}v1.3.0{RESET} {CYAN}│{RESET}
138
+ {CYAN}│{RESET} {BOLD}{WHITE}🛡️ T O R U S G U A R D{RESET} {GRAY}v1.4.0{RESET} {CYAN}│{RESET}
139
139
  {CYAN}│{RESET} {DIM}Autonomous Security Engine for AI-Built Applications{RESET} {CYAN}│{RESET}
140
140
  {CYAN}│{RESET} {CYAN}│{RESET}
141
141
  {CYAN}╰─────────────────────────────────────────────────────────────────────────╯{RESET}
@@ -220,7 +220,7 @@ def print_already_initialized(target_root, cfg):
220
220
 
221
221
  {BOLD}▸ Project Root:{RESET} {GREEN}{target_root}{RESET}
222
222
  {BOLD}▸ Workspace:{RESET} {GREEN}.torusguard/{RESET} {DIM}(Already Initialized){RESET}
223
- {BOLD}▸ Version:{RESET} {CYAN}{cfg.get('version', '1.3.0')}{RESET}
223
+ {BOLD}▸ Version:{RESET} {CYAN}{cfg.get('version', '1.4.0')}{RESET}
224
224
  {BOLD}▸ Severity Floor:{RESET} {YELLOW}{cfg.get('severity_threshold', 'medium')}{RESET}
225
225
 
226
226
  {DIM}To refresh templates or re-scaffold, run:{RESET}
@@ -228,7 +228,7 @@ def print_already_initialized(target_root, cfg):
228
228
  """)
229
229
 
230
230
 
231
- def scaffold_workspace(target_root=None, force=False, full_commands=False):
231
+ def scaffold_workspace(target_root=None, force=False, full_commands=False, template=None, run_audit=False):
232
232
  """Scaffold the .torusguard workspace into the target project root."""
233
233
  target_root = Path(target_root or find_project_root()).resolve()
234
234
  torusguard_target = target_root / ".torusguard"
@@ -348,13 +348,18 @@ def scaffold_workspace(target_root=None, force=False, full_commands=False):
348
348
  "cards": []
349
349
  }, indent=2), encoding="utf-8")
350
350
 
351
- # Ensure target project root .gitignore excludes .torusguard/memory/
351
+ # Ensure target project root .gitignore excludes .torusguard/memory/ and report.html
352
352
  root_gitignore = target_root / ".gitignore"
353
353
  if root_gitignore.exists():
354
354
  try:
355
355
  gi_content = root_gitignore.read_text(encoding="utf-8")
356
+ to_add = []
356
357
  if ".torusguard/memory" not in gi_content:
357
- root_gitignore.write_text(gi_content.rstrip() + "\n\n# TorusGuard security memory (local only)\n.torusguard/memory/\n", encoding="utf-8")
358
+ to_add.append(".torusguard/memory/")
359
+ if "report.html" not in gi_content:
360
+ to_add.append("report.html")
361
+ if to_add:
362
+ root_gitignore.write_text(gi_content.rstrip() + "\n\n# TorusGuard local artifacts\n" + "\n".join(to_add) + "\n", encoding="utf-8")
358
363
  except Exception:
359
364
  pass
360
365
 
@@ -374,12 +379,26 @@ def scaffold_workspace(target_root=None, force=False, full_commands=False):
374
379
  except Exception:
375
380
  detected_stack = None
376
381
 
382
+ TEMPLATE_MAP = {
383
+ "golang": {"language": "Go", "framework": "Gin/Fiber", "data_layer": "database/sql"},
384
+ "go": {"language": "Go", "framework": "Gin/Fiber", "data_layer": "database/sql"},
385
+ "nextjs": {"language": "TypeScript", "framework": "Next.js", "data_layer": "Prisma ORM"},
386
+ "fastapi": {"language": "Python", "framework": "FastAPI", "data_layer": "SQLAlchemy"},
387
+ "express": {"language": "JavaScript", "framework": "Express", "data_layer": "Mongoose"},
388
+ "django": {"language": "Python", "framework": "Django", "data_layer": "Django ORM"},
389
+ "react": {"language": "JavaScript/TypeScript", "framework": "React / Vite", "data_layer": "Supabase"}
390
+ }
391
+ if template and template.lower() in TEMPLATE_MAP:
392
+ detected_stack = TEMPLATE_MAP[template.lower()]
393
+
377
394
  config_file = torusguard_target / "config" / "torusguard.json"
378
395
  if config_file.exists():
379
396
  try:
380
397
  with open(config_file, "r", encoding="utf-8") as f:
381
398
  cfg = json.load(f)
382
- if detected_stack and detected_stack.get("framework") != "None":
399
+ if template and template.lower() in TEMPLATE_MAP:
400
+ cfg["detected_stack"] = TEMPLATE_MAP[template.lower()]
401
+ elif detected_stack and detected_stack.get("framework") != "None":
383
402
  cfg["detected_stack"] = {
384
403
  "language": detected_stack.get("language"),
385
404
  "framework": detected_stack.get("framework"),
@@ -511,15 +530,40 @@ Parse the requested action from `$ARGUMENTS` (e.g. `audit`, `verify`, `web-valid
511
530
 
512
531
  # ── Success Card ────────────────────────────────────────────────────────
513
532
  print_success_card()
533
+
534
+ # ── Optional Immediate Audit ────────────────────────────────────────────
535
+ if run_audit:
536
+ audit_script = torusguard_target / "scripts" / "audit_runner.py"
537
+ if audit_script.is_file():
538
+ print(f"\n {CYAN}▸ Running immediate baseline security audit (--audit)...{RESET}\n")
539
+ try:
540
+ import importlib.util
541
+ spec = importlib.util.spec_from_file_location("audit_runner", str(audit_script))
542
+ if spec and spec.loader:
543
+ ar_mod = importlib.util.module_from_spec(spec)
544
+ spec.loader.exec_module(ar_mod)
545
+ if hasattr(ar_mod, "execute_audit"):
546
+ ar_mod.execute_audit(target_root)
547
+ except Exception as e:
548
+ print(f" {YELLOW}⚠ Immediate audit notice: {e}{RESET}")
549
+
514
550
  return True
515
551
 
516
552
 
517
553
  if __name__ == "__main__":
518
554
  parser = argparse.ArgumentParser(description="TorusGuard Autonomous Workspace Bootstrapper")
519
- parser.add_argument("--target", type=str, help="Target project root directory")
555
+ parser.add_argument("--target", "-t", type=str, help="Target project root directory")
520
556
  parser.add_argument("--force", action="store_true", help="Force overwrite existing workspace")
521
557
  parser.add_argument("--full-commands", action="store_true", help="Unlock and register all 11 individual slash commands")
558
+ parser.add_argument("--template", choices=["golang", "go", "nextjs", "fastapi", "express", "django", "react"], help="Pre-configure target framework stack template")
559
+ parser.add_argument("--audit", action="store_true", help="Execute immediate baseline audit post-initialization")
522
560
  args = parser.parse_args()
523
561
 
524
- success = scaffold_workspace(target_root=args.target, force=args.force, full_commands=args.full_commands)
562
+ success = scaffold_workspace(
563
+ target_root=args.target,
564
+ force=args.force,
565
+ full_commands=args.full_commands,
566
+ template=args.template,
567
+ run_audit=args.audit
568
+ )
525
569
  sys.exit(0 if success else 1)