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.
- package/AGENTS.md +4 -0
- package/README.md +20 -3
- package/dashboard/app/agents/page.tsx +4 -4
- package/dashboard/app/api/run-checks/route.ts +49 -22
- package/dashboard/app/api/settings/route.ts +11 -1
- package/dashboard/app/api/status/route.ts +14 -0
- package/dashboard/app/config/page.tsx +3 -3
- package/dashboard/app/globals.css +2 -9
- package/dashboard/app/layout.tsx +11 -5
- package/dashboard/app/page.tsx +43 -14
- package/dashboard/app/settings/page.tsx +62 -17
- package/dashboard/components/CheckCard.tsx +116 -0
- package/dashboard/components/CheckCardList.tsx +151 -0
- package/dashboard/components/Header.tsx +29 -0
- package/dashboard/components/SidebarMyShim.tsx +44 -0
- package/dashboard/components/StatusCard.tsx +4 -4
- package/dashboard/components/TriggerCommandos.tsx +100 -0
- package/dashboard/lib/checks.ts +116 -0
- package/dashboard/lib/presets.ts +41 -0
- package/dashboard/next-env.d.ts +5 -0
- package/dashboard/package.json +1 -1
- package/dashboard/scripts/find-port-and-dev.js +30 -0
- package/package.json +26 -2
- package/scripts/ai-code-review.sh +217 -0
- package/scripts/ai-deductive-review.js +142 -0
- package/scripts/cli.js +8 -1
- package/scripts/find-free-port.js +21 -0
- package/scripts/git-checked.sh +25 -9
- package/scripts/init.js +81 -4
- package/scripts/prepublish-clean.js +11 -0
- package/scripts/run-checks.sh +67 -0
- package/scripts/setup.js +1 -0
- package/scripts/shim-runner.js +194 -0
- package/templates/.dependency-cruiser.json +35 -0
- package/templates/.semgrep.example.yml +19 -0
- package/templates/eslint.complexity.json +12 -0
- package/templates/git-pre-push +13 -9
- package/templates/husky-pre-push +10 -7
- package/templates/stryker.config.json +16 -0
- package/dashboard/.next/cache/config.json +0 -7
- package/dashboard/.next/package.json +0 -1
- package/dashboard/.next/routes-manifest.json +0 -1
- package/dashboard/.next/trace +0 -1
- 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.).
|
|
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.
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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 = {
|
|
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-
|
|
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
|
|
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: #
|
|
7
|
-
--foreground: #
|
|
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 {
|
package/dashboard/app/layout.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
2
|
import "./globals.css";
|
|
3
|
-
import
|
|
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="
|
|
17
|
-
<body className="min-h-screen bg-
|
|
18
|
-
<
|
|
19
|
-
<
|
|
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
|
);
|
package/dashboard/app/page.tsx
CHANGED
|
@@ -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
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 (
|
|
451
|
+
<span>AI Review (Deductive 95%)</span>
|
|
407
452
|
</label>
|
|
408
453
|
</div>
|
|
409
454
|
</div>
|