shimwrappercheck 0.2.0 → 0.3.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 (44) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +20 -3
  3. package/dashboard/app/agents/page.tsx +4 -4
  4. package/dashboard/app/api/run-checks/route.ts +49 -22
  5. package/dashboard/app/api/settings/route.ts +11 -1
  6. package/dashboard/app/api/status/route.ts +14 -0
  7. package/dashboard/app/config/page.tsx +3 -3
  8. package/dashboard/app/globals.css +2 -9
  9. package/dashboard/app/layout.tsx +11 -5
  10. package/dashboard/app/page.tsx +43 -14
  11. package/dashboard/app/settings/page.tsx +62 -17
  12. package/dashboard/components/CheckCard.tsx +116 -0
  13. package/dashboard/components/CheckCardList.tsx +151 -0
  14. package/dashboard/components/Header.tsx +29 -0
  15. package/dashboard/components/SidebarMyShim.tsx +44 -0
  16. package/dashboard/components/StatusCard.tsx +4 -4
  17. package/dashboard/components/TriggerCommandos.tsx +100 -0
  18. package/dashboard/lib/checks.ts +116 -0
  19. package/dashboard/lib/presets.ts +41 -0
  20. package/dashboard/next-env.d.ts +5 -0
  21. package/dashboard/package.json +1 -1
  22. package/dashboard/scripts/find-port-and-dev.js +30 -0
  23. package/package.json +26 -2
  24. package/scripts/ai-code-review.sh +217 -0
  25. package/scripts/ai-deductive-review.js +142 -0
  26. package/scripts/cli.js +8 -1
  27. package/scripts/find-free-port.js +21 -0
  28. package/scripts/git-checked.sh +25 -9
  29. package/scripts/init.js +81 -4
  30. package/scripts/prepublish-clean.js +11 -0
  31. package/scripts/run-checks.sh +67 -0
  32. package/scripts/setup.js +1 -0
  33. package/scripts/shim-runner.js +194 -0
  34. package/templates/.dependency-cruiser.json +35 -0
  35. package/templates/.semgrep.example.yml +19 -0
  36. package/templates/eslint.complexity.json +12 -0
  37. package/templates/git-pre-push +13 -9
  38. package/templates/husky-pre-push +10 -7
  39. package/templates/stryker.config.json +16 -0
  40. package/dashboard/.next/cache/config.json +0 -7
  41. package/dashboard/.next/package.json +0 -1
  42. package/dashboard/.next/routes-manifest.json +0 -1
  43. package/dashboard/.next/trace +0 -1
  44. package/dashboard/package-lock.json +0 -5307
package/AGENTS.md CHANGED
@@ -19,3 +19,7 @@ It can be edited via the dashboard (Config → AGENTS.md) so agents and humans s
19
19
 
20
20
  - Keep checks fast; run lint/type/build in `scripts/run-checks.sh`.
21
21
  - When changing shim behavior, update README and docs/SHIM_WRAPPER_CONCEPT.md if needed.
22
+
23
+ ## Hard Rules (optional tools)
24
+
25
+ For full shim checks (SAST, architecture, complexity, mutation, E2E, AI deductive review), projects can install: `dependency-cruiser`, `eslint-plugin-complexity`, `@stryker-mutator/core`, and optionally `semgrep` (CLI). Config templates live in `templates/` (e.g. `.dependency-cruiser.json`, `.semgrep.example.yml`, `stryker.config.json`, `eslint.complexity.json`). Run `npx shimwrappercheck init` to optionally copy these into the project.
package/README.md CHANGED
@@ -31,17 +31,23 @@ Run the full setup in one go (installs package if needed, then runs the wizard):
31
31
  npx shimwrappercheck setup
32
32
  ```
33
33
 
34
- This installs `shimwrappercheck` as a devDependency if missing, then runs the init wizard (Supabase/Git shims, which commands, AI review, hooks, run-checks.sh, etc.). At the end you get a link to start the dashboard to change settings later.
34
+ This installs `shimwrappercheck` as a devDependency if missing, then runs the init wizard (Supabase/Git shims, which commands, AI review, hooks, run-checks.sh, etc.). **After the wizard, the dashboard starts automatically and your browser opens at http://localhost:3000.**
35
35
 
36
36
  ## Dashboard (Web UI)
37
37
 
38
- A Next.js dashboard lets you manage presets, checks, config, and AGENTS.md:
38
+ A Next.js dashboard lets you manage presets, checks, config, and AGENTS.md. When you run `npx shimwrappercheck setup`, it starts automatically at the end and opens in your browser. **A free port is chosen automatically** (3000, 3001, 3002, …) so it never conflicts with other apps. To start it again later:
39
39
 
40
40
  ```bash
41
41
  cd node_modules/shimwrappercheck/dashboard && npm install && npm run dev
42
42
  ```
43
43
 
44
- Then open http://localhost:3000. You can:
44
+ Then open the URL shown in the terminal (e.g. http://localhost:3000). **In this repo** you can also run from the project root:
45
+
46
+ ```bash
47
+ npm run dashboard
48
+ ```
49
+
50
+ You can:
45
51
 
46
52
  - **Einstellungen**: Presets (Vibe Code default, custom presets), Supabase/Git command toggles (which commands run checks/hooks), check toggles (frontend, backend, AI review)
47
53
  - View status (config, presets file, AGENTS.md, run-checks script, hooks)
@@ -116,6 +122,17 @@ npm run supabase:checked -- functions deploy <function-name>
116
122
  npx supabase functions deploy <function-name>
117
123
  ```
118
124
 
125
+ ## Hard Rules (optional tools and configs)
126
+
127
+ For the full check pipeline (SAST, architecture, complexity, mutation testing, E2E, AI deductive review), install in your project:
128
+
129
+ - **dependency-cruiser**: `npm i -D dependency-cruiser` — enforces no circular deps and layer separation
130
+ - **eslint-plugin-complexity**: `npm i -D eslint-plugin-complexity` — cyclomatic complexity max 10 per function
131
+ - **Stryker**: `npm i -D @stryker-mutator/core` — mutation testing (min 80% score in full mode)
132
+ - **semgrep**: `pip install semgrep` or `brew install semgrep` (or use `npx semgrep`); optional SAST
133
+
134
+ Config templates are in `templates/`: `.dependency-cruiser.json`, `.semgrep.example.yml`, `stryker.config.json`, `eslint.complexity.json`. Copy into your project root or use the init wizard to optionally install them.
135
+
119
136
  ## Setup wizard (init)
120
137
 
121
138
  Run the interactive init to scan your codebase and configure the shim (or use `npx shimwrappercheck setup` to install + init in one step):
@@ -56,18 +56,18 @@ export default function AgentsPage() {
56
56
  }
57
57
 
58
58
  return (
59
- <div className="space-y-6">
59
+ <div className="space-y-6 text-white">
60
60
  <h1 className="text-3xl font-bold">AGENTS.md</h1>
61
- <p className="text-base-content/80">
61
+ <p className="text-neutral-300">
62
62
  Agent-Anweisungen für Cursor/Codex. Wird von Agents gelesen; hier bearbeitbar. Änderungen gelten sofort.
63
63
  </p>
64
64
  {!exists && (
65
- <div className="alert alert-info">
65
+ <div className="alert bg-neutral-800 border-neutral-600 text-neutral-300">
66
66
  <span>AGENTS.md existiert noch nicht. Beim Speichern wird sie im Projekt-Root angelegt.</span>
67
67
  </div>
68
68
  )}
69
69
  <textarea
70
- className="textarea textarea-bordered w-full font-mono text-sm min-h-[400px]"
70
+ className="textarea w-full font-mono text-sm min-h-[400px] bg-neutral-800 border-neutral-600 text-white"
71
71
  value={raw}
72
72
  onChange={(e) => setRaw(e.target.value)}
73
73
  placeholder="# Agent instructions..."
@@ -1,5 +1,5 @@
1
1
  /**
2
- * POST /api/run-checks – run scripts/run-checks.sh and return stdout/stderr.
2
+ * POST /api/run-checks – run Node orchestrator (npx shimwrappercheck run) or fallback to scripts/run-checks.sh.
3
3
  * Vercel-compatible; uses SHIM_PROJECT_ROOT. Runs in project root.
4
4
  */
5
5
  import { NextResponse } from "next/server";
@@ -11,34 +11,61 @@ import { getProjectRoot } from "@/lib/projectRoot";
11
11
 
12
12
  const execAsync = promisify(exec);
13
13
 
14
- type ExecResult = { stdout: string; stderr: string; code?: number };
15
-
16
14
  export async function POST() {
17
15
  try {
18
16
  const root = getProjectRoot();
19
- const scriptPath = path.join(root, "scripts", "run-checks.sh");
20
- if (!fs.existsSync(scriptPath)) {
21
- return NextResponse.json({
22
- error: "scripts/run-checks.sh not found",
23
- stdout: "",
24
- stderr: "",
25
- code: 1,
26
- });
27
- }
28
- const opts = { cwd: root, maxBuffer: 2 * 1024 * 1024, shell: "/bin/bash" };
17
+ const opts = { cwd: root, maxBuffer: 4 * 1024 * 1024, shell: "/bin/bash", env: { ...process.env, SHIM_PROJECT_ROOT: root } };
29
18
  let stdout = "";
30
19
  let stderr = "";
31
20
  let code = 0;
32
- try {
33
- const out = await execAsync(`bash "${scriptPath}"`, opts);
34
- stdout = out.stdout ?? "";
35
- stderr = out.stderr ?? "";
36
- } catch (e: unknown) {
37
- const err = e as { stdout?: string; stderr?: string; code?: number };
38
- stdout = err.stdout ?? "";
39
- stderr = err.stderr ?? (err instanceof Error ? err.message : String(e));
40
- code = err.code ?? 1;
21
+
22
+ const runnerPath = path.join(root, "scripts", "shim-runner.js");
23
+ const hasPackageRunner = fs.existsSync(path.join(root, "node_modules", "shimwrappercheck", "scripts", "shim-runner.js"));
24
+
25
+ if (fs.existsSync(runnerPath)) {
26
+ try {
27
+ const out = await execAsync(`node "${runnerPath}"`, opts);
28
+ stdout = out.stdout ?? "";
29
+ stderr = out.stderr ?? "";
30
+ } catch (e: unknown) {
31
+ const err = e as { stdout?: string; stderr?: string; code?: number };
32
+ stdout = err.stdout ?? "";
33
+ stderr = err.stderr ?? (err instanceof Error ? err.message : String(e));
34
+ code = err.code ?? 1;
35
+ }
36
+ } else if (hasPackageRunner) {
37
+ try {
38
+ const out = await execAsync("npx shimwrappercheck run", opts);
39
+ stdout = out.stdout ?? "";
40
+ stderr = out.stderr ?? "";
41
+ } catch (e: unknown) {
42
+ const err = e as { stdout?: string; stderr?: string; code?: number };
43
+ stdout = err.stdout ?? "";
44
+ stderr = err.stderr ?? (err instanceof Error ? err.message : String(e));
45
+ code = err.code ?? 1;
46
+ }
47
+ } else {
48
+ const scriptPath = path.join(root, "scripts", "run-checks.sh");
49
+ if (!fs.existsSync(scriptPath)) {
50
+ return NextResponse.json({
51
+ error: "scripts/run-checks.sh not found; install shimwrappercheck for full runner.",
52
+ stdout: "",
53
+ stderr: "",
54
+ code: 1,
55
+ });
56
+ }
57
+ try {
58
+ const out = await execAsync(`bash "${scriptPath}"`, { ...opts, maxBuffer: 2 * 1024 * 1024 });
59
+ stdout = out.stdout ?? "";
60
+ stderr = out.stderr ?? "";
61
+ } catch (e: unknown) {
62
+ const err = e as { stdout?: string; stderr?: string; code?: number };
63
+ stdout = err.stdout ?? "";
64
+ stderr = err.stderr ?? (err instanceof Error ? err.message : String(e));
65
+ code = err.code ?? 1;
66
+ }
41
67
  }
68
+
42
69
  return NextResponse.json({ stdout, stderr, code });
43
70
  } catch (err) {
44
71
  console.error("run-checks error:", err);
@@ -11,6 +11,7 @@ import {
11
11
  type Preset,
12
12
  DEFAULT_SETTINGS,
13
13
  DEFAULT_VIBE_CODE_PRESET,
14
+ DEFAULT_CHECK_TOGGLES,
14
15
  buildRcContent,
15
16
  SUPABASE_COMMAND_IDS,
16
17
  GIT_COMMAND_IDS,
@@ -27,13 +28,18 @@ function getRcPath(): string {
27
28
  }
28
29
 
29
30
  function parseRcToSettings(rawRc: string): Partial<SettingsData> {
30
- const checkToggles = { frontend: true, backend: true, aiReview: true };
31
+ const checkToggles = { ...DEFAULT_CHECK_TOGGLES };
31
32
  const argsMatch = rawRc.match(/SHIM_CHECKS_ARGS="([^"]*)"/);
32
33
  if (argsMatch) {
33
34
  const args = argsMatch[1];
34
35
  if (args.includes("--no-frontend")) checkToggles.frontend = false;
35
36
  if (args.includes("--no-backend")) checkToggles.backend = false;
36
37
  if (args.includes("--no-ai-review")) checkToggles.aiReview = false;
38
+ if (args.includes("--no-sast")) checkToggles.sast = false;
39
+ if (args.includes("--no-architecture")) checkToggles.architecture = false;
40
+ if (args.includes("--no-complexity")) checkToggles.complexity = false;
41
+ if (args.includes("--no-mutation")) checkToggles.mutation = false;
42
+ if (args.includes("--no-e2e")) checkToggles.e2e = false;
37
43
  }
38
44
  const enforceMatch = rawRc.match(/SHIM_ENFORCE_COMMANDS="([^"]*)"/);
39
45
  const hookMatch = rawRc.match(/SHIM_HOOK_COMMANDS="([^"]*)"/);
@@ -71,6 +77,8 @@ export async function GET() {
71
77
  if (parsed.presets?.length) settings.presets = parsed.presets;
72
78
  if (parsed.activePresetId) settings.activePresetId = parsed.activePresetId;
73
79
  if (parsed.checkToggles) settings.checkToggles = { ...DEFAULT_SETTINGS.checkToggles, ...parsed.checkToggles };
80
+ if (parsed.checkSettings) settings.checkSettings = { ...parsed.checkSettings };
81
+ if (Array.isArray(parsed.checkOrder)) settings.checkOrder = parsed.checkOrder;
74
82
  } catch {
75
83
  // use defaults
76
84
  }
@@ -105,6 +113,8 @@ export async function POST(request: NextRequest) {
105
113
  presets: body.presets,
106
114
  activePresetId: body.activePresetId ?? DEFAULT_SETTINGS.activePresetId,
107
115
  checkToggles: { ...DEFAULT_SETTINGS.checkToggles, ...body.checkToggles },
116
+ checkSettings: body.checkSettings ?? undefined,
117
+ checkOrder: Array.isArray(body.checkOrder) ? body.checkOrder : undefined,
108
118
  };
109
119
 
110
120
  const root = getProjectRoot();
@@ -14,19 +14,33 @@ export async function GET() {
14
14
  const hasPresets = fs.existsSync(path.join(root, ".shimwrappercheck-presets.json"));
15
15
  const hasAgents = fs.existsSync(path.join(root, "AGENTS.md"));
16
16
  const hasRunChecks = fs.existsSync(path.join(root, "scripts", "run-checks.sh"));
17
+ const hasRunner = fs.existsSync(path.join(root, "scripts", "shim-runner.js")) ||
18
+ fs.existsSync(path.join(root, "node_modules", "shimwrappercheck", "scripts", "shim-runner.js"));
17
19
  const hasHusky = fs.existsSync(path.join(root, ".husky", "pre-push"));
18
20
  const hasGitHook = fs.existsSync(path.join(root, ".git", "hooks", "pre-push"));
19
21
  const hasSupabase = fs.existsSync(path.join(root, "supabase", "config.toml"));
20
22
 
23
+ let lastError: { check?: string; message?: string; suggestion?: string; timestamp?: string } | null = null;
24
+ const lastErrorPath = path.join(root, ".shim", "last_error.json");
25
+ if (fs.existsSync(lastErrorPath)) {
26
+ try {
27
+ lastError = JSON.parse(fs.readFileSync(lastErrorPath, "utf8"));
28
+ } catch {
29
+ lastError = { message: "(parse error)" };
30
+ }
31
+ }
32
+
21
33
  return NextResponse.json({
22
34
  projectRoot: root,
23
35
  config: hasRc,
24
36
  presetsFile: hasPresets,
25
37
  agentsMd: hasAgents,
26
38
  runChecksScript: hasRunChecks,
39
+ shimRunner: hasRunner,
27
40
  prePushHusky: hasHusky,
28
41
  prePushGit: hasGitHook,
29
42
  supabase: hasSupabase,
43
+ lastError,
30
44
  });
31
45
  } catch (err) {
32
46
  console.error("status error:", err);
@@ -50,13 +50,13 @@ export default function ConfigPage() {
50
50
  }
51
51
 
52
52
  return (
53
- <div className="space-y-6">
53
+ <div className="space-y-6 text-white">
54
54
  <h1 className="text-3xl font-bold">Config (.shimwrappercheckrc)</h1>
55
- <p className="text-base-content/80">
55
+ <p className="text-neutral-300">
56
56
  Shell-Variablen und Kommentare. Wird beim nächsten Aufruf des Shims verwendet.
57
57
  </p>
58
58
  <textarea
59
- className="textarea textarea-bordered w-full font-mono text-sm min-h-[320px]"
59
+ className="textarea w-full font-mono text-sm min-h-[320px] bg-neutral-800 border-neutral-600 text-white"
60
60
  value={raw}
61
61
  onChange={(e) => setRaw(e.target.value)}
62
62
  placeholder="# shimwrappercheck config\nSHIM_ENFORCE_COMMANDS=\"functions,db,migration\"\n..."
@@ -3,15 +3,8 @@
3
3
  @tailwind utilities;
4
4
 
5
5
  :root {
6
- --background: #f8fafc;
7
- --foreground: #0f172a;
8
- }
9
-
10
- @media (prefers-color-scheme: dark) {
11
- :root {
12
- --background: #0f172a;
13
- --foreground: #f8fafc;
14
- }
6
+ --background: #0f0f0f;
7
+ --foreground: #fafafa;
15
8
  }
16
9
 
17
10
  body {
@@ -1,6 +1,7 @@
1
1
  import type { Metadata } from "next";
2
2
  import "./globals.css";
3
- import Nav from "@/components/Nav";
3
+ import Header from "@/components/Header";
4
+ import SidebarMyShim from "@/components/SidebarMyShim";
4
5
 
5
6
  export const metadata: Metadata = {
6
7
  title: "shimwrappercheck Dashboard",
@@ -13,10 +14,15 @@ export default function RootLayout({
13
14
  children: React.ReactNode;
14
15
  }>) {
15
16
  return (
16
- <html lang="de" data-theme="light">
17
- <body className="min-h-screen bg-base-200">
18
- <Nav />
19
- <main className="container mx-auto px-4 py-6">{children}</main>
17
+ <html lang="de" data-theme="dark">
18
+ <body className="min-h-screen bg-[#0f0f0f] text-white">
19
+ <Header />
20
+ <div className="flex">
21
+ <aside className="w-80 min-h-[calc(100vh-4rem)] border-r border-neutral-700 flex-shrink-0">
22
+ <SidebarMyShim />
23
+ </aside>
24
+ <main className="flex-1 p-6 overflow-auto">{children}</main>
25
+ </div>
20
26
  </body>
21
27
  </html>
22
28
  );
@@ -14,9 +14,11 @@ type Status = {
14
14
  presetsFile?: boolean;
15
15
  agentsMd?: boolean;
16
16
  runChecksScript?: boolean;
17
+ shimRunner?: boolean;
17
18
  prePushHusky?: boolean;
18
19
  prePushGit?: boolean;
19
20
  supabase?: boolean;
21
+ lastError?: { check?: string; message?: string; suggestion?: string; timestamp?: string } | null;
20
22
  };
21
23
 
22
24
  export default function DashboardPage() {
@@ -59,11 +61,28 @@ export default function DashboardPage() {
59
61
  }
60
62
 
61
63
  return (
62
- <div className="space-y-8">
63
- <h1 className="text-3xl font-bold">Dashboard</h1>
64
- <p className="text-base-content/80">
65
- Status und Aktionen für shimwrappercheck. AGENTS.md und Config können hier bearbeitet werden (auch für Agents).
66
- </p>
64
+ <div className="space-y-8 text-white">
65
+ <div className="flex items-center justify-between gap-4 flex-wrap">
66
+ <h1 className="text-2xl font-bold">Available Checks</h1>
67
+ <div className="relative">
68
+ <input
69
+ type="text"
70
+ placeholder="Suchen..."
71
+ className="input input-bordered input-sm bg-neutral-800 border-neutral-600 text-white w-56 pl-8"
72
+ />
73
+ <svg
74
+ className="absolute left-2 top-1/2 -translate-y-1/2 w-4 h-4 text-neutral-500 pointer-events-none"
75
+ fill="none"
76
+ stroke="currentColor"
77
+ viewBox="0 0 24 24"
78
+ >
79
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
80
+ </svg>
81
+ </div>
82
+ </div>
83
+ <div className="border border-neutral-600 rounded-lg bg-neutral-800/40 min-h-[320px] p-4">
84
+ {/* Platz für verfügbare Checks / Detail-Ansicht */}
85
+ </div>
67
86
 
68
87
  <div>
69
88
  <h2 className="text-xl font-semibold mb-4">Status</h2>
@@ -72,12 +91,22 @@ export default function DashboardPage() {
72
91
  <StatusCard label="Presets (.shimwrappercheck-presets.json)" ok={!!status.presetsFile} detail="Presets & Check-Toggles (Einstellungen)" />
73
92
  <StatusCard label="AGENTS.md" ok={!!status.agentsMd} detail="Agent-Anweisungen (über GUI bearbeitbar)" />
74
93
  <StatusCard label="scripts/run-checks.sh" ok={!!status.runChecksScript} />
94
+ <StatusCard label="Shim Runner" ok={!!status.shimRunner} detail="Node orchestrator (npx shimwrappercheck run)" />
75
95
  <StatusCard label="Husky pre-push" ok={!!status.prePushHusky} />
76
96
  <StatusCard label="Git pre-push Hook" ok={!!status.prePushGit} />
77
97
  <StatusCard label="Supabase" ok={!!status.supabase} />
78
98
  </div>
79
99
  {status.projectRoot && (
80
- <p className="mt-2 text-sm text-base-content/70">Projekt-Root: {status.projectRoot}</p>
100
+ <p className="mt-2 text-sm text-neutral-400">Projekt-Root: {status.projectRoot}</p>
101
+ )}
102
+ {status.lastError && (
103
+ <div className="mt-4 alert alert-warning shadow-lg">
104
+ <div>
105
+ <h3 className="font-bold">Letzter Check-Fehler (.shim/last_error.json)</h3>
106
+ <p className="text-sm">{status.lastError.check}: {status.lastError.message}</p>
107
+ {status.lastError.suggestion && <p className="text-sm opacity-90">Vorschlag: {status.lastError.suggestion}</p>}
108
+ </div>
109
+ </div>
81
110
  )}
82
111
  </div>
83
112
 
@@ -86,31 +115,31 @@ export default function DashboardPage() {
86
115
  <div className="flex flex-wrap gap-4">
87
116
  <button
88
117
  type="button"
89
- className="btn btn-primary"
118
+ className="btn btn-primary bg-primary text-primary-content"
90
119
  onClick={runChecks}
91
- disabled={running || !status.runChecksScript}
120
+ disabled={running || (!status.runChecksScript && !status.shimRunner)}
92
121
  >
93
122
  {running ? "Läuft…" : "Nur Checks ausführen"}
94
123
  </button>
95
- <Link href="/settings" className="btn btn-outline">
124
+ <Link href="/settings" className="btn btn-outline border-neutral-600 text-neutral-300">
96
125
  Einstellungen (Presets & Checks)
97
126
  </Link>
98
- <Link href="/config" className="btn btn-outline">
127
+ <Link href="/config" className="btn btn-outline border-neutral-600 text-neutral-300">
99
128
  Config (Raw)
100
129
  </Link>
101
- <Link href="/agents" className="btn btn-outline">
130
+ <Link href="/agents" className="btn btn-outline border-neutral-600 text-neutral-300">
102
131
  AGENTS.md bearbeiten
103
132
  </Link>
104
133
  </div>
105
134
  </div>
106
135
 
107
136
  {runResult && (
108
- <div className="card bg-base-100 shadow-md">
137
+ <div className="card bg-neutral-800 border border-neutral-600 shadow-md">
109
138
  <div className="card-body">
110
- <h3 className="card-title">
139
+ <h3 className="card-title text-white">
111
140
  Letzte Check-Ausgabe {runResult.code === 0 ? "(OK)" : "(Fehler)"}
112
141
  </h3>
113
- <pre className="bg-base-200 p-4 rounded-lg text-sm overflow-auto max-h-64 whitespace-pre-wrap">
142
+ <pre className="bg-neutral-900 p-4 rounded-lg text-sm overflow-auto max-h-64 whitespace-pre-wrap text-neutral-300">
114
143
  {runResult.stdout || "(keine Ausgabe)"}
115
144
  {runResult.stderr ? `\n${runResult.stderr}` : ""}
116
145
  </pre>
@@ -203,16 +203,16 @@ export default function SettingsPage() {
203
203
  }
204
204
 
205
205
  return (
206
- <div className="space-y-8">
206
+ <div className="space-y-8 text-white">
207
207
  <h1 className="text-3xl font-bold">Einstellungen</h1>
208
- <p className="text-base-content/80">
208
+ <p className="text-neutral-300">
209
209
  Preset wählen, Befehle (Supabase / GitHub) und Checks ein-/ausschalten. Speichern schreibt .shimwrappercheckrc.
210
210
  </p>
211
211
 
212
212
  {/* Preset selector */}
213
- <div className="card bg-base-100 shadow-md">
213
+ <div className="card bg-neutral-800 border border-neutral-600 shadow-md">
214
214
  <div className="card-body">
215
- <h2 className="card-title">Preset</h2>
215
+ <h2 className="card-title text-white">Preset</h2>
216
216
  <div className="flex flex-wrap gap-2 items-center">
217
217
  {settings.presets.map((p) => (
218
218
  <div key={p.id} className="flex items-center gap-1">
@@ -263,10 +263,10 @@ export default function SettingsPage() {
263
263
  {/* Active preset: providers (for custom) + command toggles */}
264
264
  <div className="space-y-6">
265
265
  {activePreset.id !== DEFAULT_VIBE_CODE_PRESET.id && (
266
- <div className="card bg-base-100 shadow-md">
266
+ <div className="card bg-neutral-800 border border-neutral-600 shadow-md">
267
267
  <div className="card-body">
268
- <h2 className="card-title">Provider in diesem Preset</h2>
269
- <p className="text-sm text-base-content/70">Provider hinzufügen (z. B. GitHub, Supabase).</p>
268
+ <h2 className="card-title text-white">Provider in diesem Preset</h2>
269
+ <p className="text-sm text-neutral-400">Provider hinzufügen (z. B. GitHub, Supabase).</p>
270
270
  <div className="flex gap-2 flex-wrap">
271
271
  {(["supabase", "git"] as const).map((prov) => (
272
272
  <div key={prov} className="flex items-center gap-1">
@@ -295,10 +295,10 @@ export default function SettingsPage() {
295
295
 
296
296
  {/* Supabase */}
297
297
  {activePreset.providers.includes("supabase") && (
298
- <div className="card bg-base-100 shadow-md">
298
+ <div className="card bg-neutral-800 border border-neutral-600 shadow-md">
299
299
  <div className="card-body">
300
- <h2 className="card-title">Supabase</h2>
301
- <p className="text-sm text-base-content/70">Für welche Befehle Checks und Hooks laufen.</p>
300
+ <h2 className="card-title text-white">Supabase</h2>
301
+ <p className="text-sm text-neutral-400">Für welche Befehle Checks und Hooks laufen.</p>
302
302
  <div className="overflow-x-auto">
303
303
  <table className="table table-sm">
304
304
  <thead>
@@ -350,10 +350,10 @@ export default function SettingsPage() {
350
350
 
351
351
  {/* Git */}
352
352
  {activePreset.providers.includes("git") && (
353
- <div className="card bg-base-100 shadow-md">
353
+ <div className="card bg-neutral-800 border border-neutral-600 shadow-md">
354
354
  <div className="card-body">
355
- <h2 className="card-title">GitHub (Git)</h2>
356
- <p className="text-sm text-base-content/70">Für welche Git-Befehle Checks laufen.</p>
355
+ <h2 className="card-title text-white">GitHub (Git)</h2>
356
+ <p className="text-sm text-neutral-400">Für welche Git-Befehle Checks laufen.</p>
357
357
  <div className="flex flex-wrap gap-4">
358
358
  {GIT_COMMAND_IDS.map((cmd) => (
359
359
  <label key={cmd} className="flex items-center gap-2 cursor-pointer">
@@ -373,10 +373,10 @@ export default function SettingsPage() {
373
373
  </div>
374
374
 
375
375
  {/* Check toggles */}
376
- <div className="card bg-base-100 shadow-md">
376
+ <div className="card bg-neutral-800 border border-neutral-600 shadow-md">
377
377
  <div className="card-body">
378
- <h2 className="card-title">Checks (run-checks.sh)</h2>
379
- <p className="text-sm text-base-content/70">Welche Schritte beim Check-Lauf ausgeführt werden.</p>
378
+ <h2 className="card-title text-white">Checks (Shim Runner / run-checks.sh)</h2>
379
+ <p className="text-sm text-neutral-400">Welche Schritte beim Check-Lauf ausgeführt werden.</p>
380
380
  <div className="flex flex-wrap gap-6">
381
381
  <label className="flex items-center gap-2 cursor-pointer">
382
382
  <input
@@ -396,6 +396,51 @@ export default function SettingsPage() {
396
396
  />
397
397
  <span>Backend (deno fmt/lint/audit)</span>
398
398
  </label>
399
+ <label className="flex items-center gap-2 cursor-pointer">
400
+ <input
401
+ type="checkbox"
402
+ className="toggle toggle-sm"
403
+ checked={settings.checkToggles.sast}
404
+ onChange={(e) => setCheckToggles("sast", e.target.checked)}
405
+ />
406
+ <span>SAST (semgrep)</span>
407
+ </label>
408
+ <label className="flex items-center gap-2 cursor-pointer">
409
+ <input
410
+ type="checkbox"
411
+ className="toggle toggle-sm"
412
+ checked={settings.checkToggles.architecture}
413
+ onChange={(e) => setCheckToggles("architecture", e.target.checked)}
414
+ />
415
+ <span>Architektur (dependency-cruiser)</span>
416
+ </label>
417
+ <label className="flex items-center gap-2 cursor-pointer">
418
+ <input
419
+ type="checkbox"
420
+ className="toggle toggle-sm"
421
+ checked={settings.checkToggles.complexity}
422
+ onChange={(e) => setCheckToggles("complexity", e.target.checked)}
423
+ />
424
+ <span>Komplexität (max 10)</span>
425
+ </label>
426
+ <label className="flex items-center gap-2 cursor-pointer">
427
+ <input
428
+ type="checkbox"
429
+ className="toggle toggle-sm"
430
+ checked={settings.checkToggles.mutation}
431
+ onChange={(e) => setCheckToggles("mutation", e.target.checked)}
432
+ />
433
+ <span>Mutation (Stryker ≥80%)</span>
434
+ </label>
435
+ <label className="flex items-center gap-2 cursor-pointer">
436
+ <input
437
+ type="checkbox"
438
+ className="toggle toggle-sm"
439
+ checked={settings.checkToggles.e2e}
440
+ onChange={(e) => setCheckToggles("e2e", e.target.checked)}
441
+ />
442
+ <span>E2E (Playwright)</span>
443
+ </label>
399
444
  <label className="flex items-center gap-2 cursor-pointer">
400
445
  <input
401
446
  type="checkbox"
@@ -403,7 +448,7 @@ export default function SettingsPage() {
403
448
  checked={settings.checkToggles.aiReview}
404
449
  onChange={(e) => setCheckToggles("aiReview", e.target.checked)}
405
450
  />
406
- <span>AI Review (Codex/Cursor)</span>
451
+ <span>AI Review (Deductive 95%)</span>
407
452
  </label>
408
453
  </div>
409
454
  </div>