@securityreviewai/securityreview-kit 0.1.50 → 0.1.52

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 (78) hide show
  1. package/README.md +105 -0
  2. package/bin/securityreview-kit.js +5 -0
  3. package/package.json +30 -24
  4. package/src/cli.js +109 -0
  5. package/src/commands/init.js +851 -0
  6. package/src/commands/status.js +99 -0
  7. package/src/commands/switch-project.js +207 -0
  8. package/src/generators/mcp/claude.js +85 -0
  9. package/src/generators/mcp/claude.test.js +64 -0
  10. package/src/generators/mcp/codex.js +70 -0
  11. package/src/generators/mcp/codex.test.js +43 -0
  12. package/src/generators/mcp/cursor.js +29 -0
  13. package/src/generators/mcp/cursor.test.js +50 -0
  14. package/src/generators/mcp/gemini.js +28 -0
  15. package/src/generators/mcp/vscode.js +29 -0
  16. package/src/generators/mcp/windsurf.js +27 -0
  17. package/src/generators/rules/antigravity.js +22 -0
  18. package/src/generators/rules/claude.js +87 -0
  19. package/src/generators/rules/claude.test.js +60 -0
  20. package/src/generators/rules/codex.js +141 -0
  21. package/src/generators/rules/codex.test.js +59 -0
  22. package/src/generators/rules/content.js +110 -0
  23. package/src/generators/rules/cursor.js +128 -0
  24. package/src/generators/rules/gemini.js +13 -0
  25. package/src/generators/rules/guardrails-init-profile.md +56 -0
  26. package/src/generators/rules/guardrails-profiler/SKILL.md +130 -0
  27. package/src/generators/rules/guardrails-profiler/references/signal-registry.json +514 -0
  28. package/src/generators/rules/guardrails-selection/references/category-threat-map.md +232 -0
  29. package/src/generators/rules/guardrails_rule.md +94 -0
  30. package/src/generators/rules/hooks.json +11 -0
  31. package/src/generators/rules/srai-profile.md +32 -0
  32. package/src/generators/rules/vscode.js +101 -0
  33. package/src/generators/rules/vscode.test.js +54 -0
  34. package/src/generators/rules/windsurf.js +13 -0
  35. package/src/utils/constants.js +95 -0
  36. package/src/utils/cursor-agent-path.js +67 -0
  37. package/src/utils/cursor-cli-permissions.js +28 -0
  38. package/src/utils/detect.js +27 -0
  39. package/src/utils/fs-helpers.js +82 -0
  40. package/src/utils/guardrails-profiler-bundle.js +84 -0
  41. package/src/utils/ide-cli-install.js +138 -0
  42. package/src/utils/profiler-agent.js +446 -0
  43. package/src/utils/profiler-agent.test.js +81 -0
  44. package/src/utils/srai.js +252 -0
  45. package/dist/api.js +0 -44
  46. package/dist/commands/guardrails.js +0 -13
  47. package/dist/commands/init.js +0 -88
  48. package/dist/commands/profile.js +0 -14
  49. package/dist/commands/status.js +0 -27
  50. package/dist/commands/sync.js +0 -6
  51. package/dist/config.js +0 -18
  52. package/dist/fs.js +0 -43
  53. package/dist/index.js +0 -44
  54. package/dist/profile.js +0 -113
  55. package/dist/scaffold/claude-code.js +0 -43
  56. package/dist/scaffold/codex.js +0 -41
  57. package/dist/scaffold/cursor.js +0 -45
  58. package/dist/scaffold/gemini.js +0 -10
  59. package/dist/scaffold/index.js +0 -22
  60. package/dist/scaffold/mcp.js +0 -15
  61. package/dist/scaffold/rules.js +0 -191
  62. package/dist/scaffold/vibreview.js +0 -30
  63. package/dist/scaffold/vscode.js +0 -28
  64. package/dist/scaffold/windsurf.js +0 -10
  65. package/dist/sync/index.js +0 -34
  66. package/dist/sync/payload.js +0 -23
  67. package/dist/sync/state.js +0 -12
  68. package/dist/types.js +0 -1
  69. package/templates/claude/CLAUDE.md +0 -13
  70. package/templates/claude/agents/guardrail_profiler.md +0 -12
  71. package/templates/claude/agents/threat_modeler.md +0 -5
  72. package/templates/claude/skills/vibreview/SKILL.md +0 -21
  73. package/templates/claude/skills/vibreview/guardrail_patterns.md +0 -12
  74. package/templates/cursor/rules/vibreview-security.mdc +0 -8
  75. /package/{templates/shared → src/generators/rules}/content.md +0 -0
  76. /package/{templates/shared/guardrails-selection.md → src/generators/rules/guardrails-selection/SKILL.md} +0 -0
  77. /package/{templates/shared/threat-modelling.md → src/generators/rules/skill.md} +0 -0
  78. /package/{templates/shared → src/generators/rules}/vibereview-sync/SKILL.md +0 -0
@@ -1,43 +0,0 @@
1
- import { join } from "node:path";
2
- import { readJson, writeJson, writeText, upsertBlock } from "../fs.js";
3
- import { mcpRemoteServerWithType } from "./mcp.js";
4
- import { SENTINEL_END, SENTINEL_START, claudeRuleContent, guardrailsSelectionSkillContent, syncSkillContent, threatModelSkillContent } from "./rules.js";
5
- export async function scaffoldClaudeCode(cwd, config) {
6
- await writeMcpConfig(cwd, config);
7
- await writeClaudeSettings(cwd);
8
- await writeClaudeRules(cwd, config);
9
- }
10
- async function writeMcpConfig(cwd, config) {
11
- const path = join(cwd, ".mcp.json");
12
- const existing = (await readJson(path)) ?? {};
13
- const mcpServers = existing.mcpServers ?? {};
14
- mcpServers.vibreview = mcpRemoteServerWithType(config);
15
- await writeJson(path, { ...existing, mcpServers });
16
- }
17
- async function writeClaudeSettings(cwd) {
18
- const path = join(cwd, ".claude", "settings.json");
19
- const existing = (await readJson(path)) ?? {};
20
- const enabled = Array.isArray(existing.enabledMcpjsonServers) ? existing.enabledMcpjsonServers : [];
21
- const allow = Array.isArray(existing.permissions?.allow)
22
- ? existing.permissions.allow.filter((item) => typeof item === "string")
23
- : [];
24
- await writeJson(path, {
25
- ...existing,
26
- enabledMcpjsonServers: enabled.includes("vibreview") ? enabled : [...enabled, "vibreview"],
27
- permissions: {
28
- ...(typeof existing.permissions === "object" && existing.permissions ? existing.permissions : {}),
29
- allow: allow.includes("mcp__vibreview") ? allow : [...allow, "mcp__vibreview"],
30
- },
31
- });
32
- }
33
- async function writeClaudeRules(cwd, config) {
34
- const paths = {
35
- guardrailsSelectionSkillDir: ".claude/skills/guardrails-selection",
36
- threatModellingSkillDir: ".claude/skills/threat-modelling",
37
- vibereviewSyncSkillDir: ".claude/skills/vibereview-sync",
38
- };
39
- await upsertBlock(join(cwd, "CLAUDE.md"), SENTINEL_START, SENTINEL_END, claudeRuleContent(config));
40
- await writeText(join(cwd, ".claude", "skills", "guardrails-selection", "SKILL.md"), `${guardrailsSelectionSkillContent(config, paths)}\n`);
41
- await writeText(join(cwd, ".claude", "skills", "threat-modelling", "SKILL.md"), `${threatModelSkillContent(config, paths)}\n`);
42
- await writeText(join(cwd, ".claude", "skills", "vibereview-sync", "SKILL.md"), `${syncSkillContent(config)}\n`);
43
- }
@@ -1,41 +0,0 @@
1
- import { join } from "node:path";
2
- import { readText, upsertBlock, writeText } from "../fs.js";
3
- import { SENTINEL_END, SENTINEL_START, codexHooksContent, codexRuleContent, guardrailsSelectionSkillContent, syncSkillContent, threatModelSkillContent } from "./rules.js";
4
- export async function scaffoldCodex(cwd, config) {
5
- const paths = {
6
- guardrailsSelectionSkillDir: ".codex/skills/guardrails-selection",
7
- threatModellingSkillDir: ".codex/skills/threat-modelling",
8
- vibereviewSyncSkillDir: ".codex/skills/vibereview-sync",
9
- };
10
- await writeCodexConfig(cwd, config);
11
- await upsertBlock(join(cwd, ".codex", "AGENTS.md"), SENTINEL_START, SENTINEL_END, codexRuleContent(config));
12
- await writeText(join(cwd, ".codex", "hooks.json"), codexHooksContent(config));
13
- await writeText(join(cwd, ".codex", "skills", "guardrails-selection", "SKILL.md"), `${guardrailsSelectionSkillContent(config, paths)}\n`);
14
- await writeText(join(cwd, ".codex", "skills", "threat-modelling", "SKILL.md"), `${threatModelSkillContent(config, paths)}\n`);
15
- await writeText(join(cwd, ".codex", "skills", "vibereview-sync", "SKILL.md"), `${syncSkillContent(config)}\n`);
16
- }
17
- async function writeCodexConfig(cwd, config) {
18
- const path = join(cwd, ".codex", "config.toml");
19
- const existing = await readText(path);
20
- const serverBlock = `
21
- [mcp_servers.vibreview]
22
- command = "npx"
23
- args = ["-y", "mcp-remote@latest", "${config.server_url.replace(/\/$/, "")}/mcp", "--header", "Authorization:\${AUTH_HEADER}"]
24
- default_tools_approval_mode = "approve"
25
-
26
- [mcp_servers.vibreview.env]
27
- AUTH_HEADER = "Bearer ${escapeTomlString(config.api_key ?? "")}"
28
- `.trim();
29
- const updated = replaceTomlBlock(existing, serverBlock);
30
- await writeText(path, `${updated.trim()}\n`);
31
- }
32
- function replaceTomlBlock(existing, serverBlock) {
33
- if (!existing.trim())
34
- return serverBlock;
35
- if (!existing.includes("[mcp_servers.vibreview]"))
36
- return `${existing.trimEnd()}\n\n${serverBlock}`;
37
- return existing.replace(/\[mcp_servers\.vibreview][\s\S]*?(?=\n\[[^\]]+]|\s*$)/, serverBlock);
38
- }
39
- function escapeTomlString(value) {
40
- return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
41
- }
@@ -1,45 +0,0 @@
1
- import { join } from "node:path";
2
- import { readJson, writeJson, writeText } from "../fs.js";
3
- import { mcpRemoteServerWithType } from "./mcp.js";
4
- import { cursorHooksContent, cursorRuleContent, guardrailsSelectionSkillContent, syncSkillContent, threatModelSkillContent } from "./rules.js";
5
- export async function scaffoldCursor(cwd, config) {
6
- const paths = {
7
- guardrailsSelectionSkillDir: ".cursor/skills/guardrails-selection",
8
- threatModellingSkillDir: ".cursor/skills/threat-modelling",
9
- vibereviewSyncSkillDir: ".cursor/skills/vibereview-sync",
10
- };
11
- const mcpPath = join(cwd, ".cursor", "mcp.json");
12
- const existing = (await readJson(mcpPath)) ?? {};
13
- const mcpServers = existing.mcpServers ?? {};
14
- mcpServers.vibreview = mcpRemoteServerWithType(config);
15
- await writeJson(mcpPath, { ...existing, mcpServers });
16
- await writeText(join(cwd, ".cursor", "rules", "vibreview-security.mdc"), cursorRuleFile(config));
17
- await writeText(join(cwd, ".cursor", "hooks.json"), cursorHooksContent(config));
18
- await writeText(join(cwd, ".cursor", "skills", "guardrails-selection", "SKILL.md"), `${guardrailsSelectionSkillContent(config, paths)}\n`);
19
- await writeText(join(cwd, ".cursor", "skills", "threat-modelling", "SKILL.md"), `${threatModelSkillContent(config, paths)}\n`);
20
- await writeText(join(cwd, ".cursor", "skills", "vibereview-sync", "SKILL.md"), `${syncSkillContent(config)}\n`);
21
- await updateCursorAllowlist(cwd);
22
- }
23
- async function updateCursorAllowlist(cwd) {
24
- const path = join(cwd, ".cursor", "cli.json");
25
- const existing = (await readJson(path)) ?? {};
26
- const permissions = existing.permissions ?? {};
27
- const allow = Array.isArray(permissions.allow) ? permissions.allow.filter((item) => typeof item === "string") : [];
28
- const entry = "mcp(vibreview)";
29
- await writeJson(path, {
30
- ...existing,
31
- permissions: {
32
- ...permissions,
33
- allow: allow.includes(entry) ? allow : [...allow, entry],
34
- },
35
- });
36
- }
37
- function cursorRuleFile(config) {
38
- return `---
39
- description: VibeReview security workflow
40
- alwaysApply: true
41
- ---
42
-
43
- ${cursorRuleContent(config)}
44
- `;
45
- }
@@ -1,10 +0,0 @@
1
- import { join } from "node:path";
2
- import { readJson, writeJson } from "../fs.js";
3
- import { mcpRemoteServer } from "./mcp.js";
4
- export async function scaffoldGemini(cwd, config) {
5
- const path = join(cwd, ".gemini", "settings.json");
6
- const existing = (await readJson(path)) ?? {};
7
- const mcpServers = existing.mcpServers ?? {};
8
- mcpServers.vibreview = mcpRemoteServer(config);
9
- await writeJson(path, { ...existing, mcpServers });
10
- }
@@ -1,22 +0,0 @@
1
- import { scaffoldClaudeCode } from "./claude-code.js";
2
- import { scaffoldCodex } from "./codex.js";
3
- import { scaffoldCursor } from "./cursor.js";
4
- import { scaffoldGemini } from "./gemini.js";
5
- import { scaffoldVibeReview } from "./vibreview.js";
6
- import { scaffoldVSCode } from "./vscode.js";
7
- import { scaffoldWindsurf } from "./windsurf.js";
8
- export async function scaffoldProject(cwd, config) {
9
- await scaffoldVibeReview(cwd, config);
10
- if (config.ide.includes("claude_code"))
11
- await scaffoldClaudeCode(cwd, config);
12
- if (config.ide.includes("cursor"))
13
- await scaffoldCursor(cwd, config);
14
- if (config.ide.includes("vscode_copilot"))
15
- await scaffoldVSCode(cwd, config);
16
- if (config.ide.includes("codex"))
17
- await scaffoldCodex(cwd, config);
18
- if (config.ide.includes("gemini") || config.ide.includes("antigravity"))
19
- await scaffoldGemini(cwd, config);
20
- if (config.ide.includes("windsurf"))
21
- await scaffoldWindsurf(cwd, config);
22
- }
@@ -1,15 +0,0 @@
1
- export function mcpRemoteServer(config) {
2
- return {
3
- command: "npx",
4
- args: ["-y", "mcp-remote@latest", `${config.server_url.replace(/\/$/, "")}/mcp`, "--header", "Authorization:${AUTH_HEADER}"],
5
- env: {
6
- AUTH_HEADER: `Bearer ${config.api_key ?? ""}`,
7
- },
8
- };
9
- }
10
- export function mcpRemoteServerWithType(config) {
11
- return {
12
- type: "stdio",
13
- ...mcpRemoteServer(config),
14
- };
15
- }
@@ -1,191 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- const TOOL_PROJECT = "`vibreview_get_tenant_project`";
3
- const TOOL_GUARDRAILS = "`vibreview_get_guardrails`";
4
- const TOOL_SYNC = "`vibreview_ctm_sync_markdown`";
5
- export const SENTINEL_START = "<!-- securityreview-kit:start -->";
6
- export const SENTINEL_END = "<!-- securityreview-kit:end -->";
7
- export function ruleContent(config, paths) {
8
- return renderTemplate("content.md", config, paths);
9
- }
10
- export function claudeRuleContent(config) {
11
- return ruleContent(config, {
12
- guardrailsSelectionSkillDir: ".claude/skills/guardrails-selection",
13
- threatModellingSkillDir: ".claude/skills/threat-modelling",
14
- vibereviewSyncSkillDir: ".claude/skills/vibereview-sync",
15
- });
16
- }
17
- export function copilotRuleContent(config) {
18
- return ruleContent(config, {
19
- guardrailsSelectionSkillDir: ".github/skills/guardrails-selection",
20
- threatModellingSkillDir: ".github/skills/threat-modelling",
21
- vibereviewSyncSkillDir: ".github/skills/vibereview-sync",
22
- });
23
- }
24
- export function codexRuleContent(config) {
25
- return ruleContent(config, {
26
- guardrailsSelectionSkillDir: ".codex/skills/guardrails-selection",
27
- threatModellingSkillDir: ".codex/skills/threat-modelling",
28
- vibereviewSyncSkillDir: ".codex/skills/vibereview-sync",
29
- });
30
- }
31
- export function cursorRuleContent(config) {
32
- return ruleContent(config, {
33
- guardrailsSelectionSkillDir: ".cursor/skills/guardrails-selection",
34
- threatModellingSkillDir: ".cursor/skills/threat-modelling",
35
- vibereviewSyncSkillDir: ".cursor/skills/vibereview-sync",
36
- });
37
- }
38
- export function guardrailsSelectionSkillContent(config, paths = defaultPaths("cursor")) {
39
- return renderTemplate("guardrails-selection.md", config, paths);
40
- }
41
- export function threatModelSkillContent(config, paths = defaultPaths("cursor")) {
42
- return renderTemplate("threat-modelling.md", config, paths);
43
- }
44
- export function syncSkillContent(config, scanDir = ".vibreview/scans") {
45
- return renderTemplate("vibereview-sync/SKILL.md", config, defaultPaths("cursor")).replaceAll(".vibreview/scans/", `${scanDir.replace(/\/$/, "")}/`);
46
- }
47
- export function cursorHooksContent(config) {
48
- return JSON.stringify({
49
- version: 1,
50
- hooks: {
51
- sessionStart: [
52
- {
53
- command: `printf '%s\\n' '${jsonPayload(additionalContext(config)).replaceAll("'", "'\\''")}'`,
54
- timeout: 5,
55
- },
56
- ],
57
- },
58
- }, null, 2) + "\n";
59
- }
60
- export function codexHooksContent(config) {
61
- return JSON.stringify({
62
- hooks: {
63
- SessionStart: [
64
- {
65
- matcher: "startup|resume",
66
- hooks: [
67
- {
68
- type: "command",
69
- command: `printf '%s\\n' '${codexPayload(config, "SessionStart").replaceAll("'", "'\\''")}'`,
70
- timeout: 5,
71
- statusMessage: "Loading VibeReview security session policy",
72
- },
73
- ],
74
- },
75
- ],
76
- UserPromptSubmit: [
77
- {
78
- hooks: [
79
- {
80
- type: "command",
81
- command: `printf '%s\\n' '${codexPayload(config, "UserPromptSubmit").replaceAll("'", "'\\''")}'`,
82
- timeout: 5,
83
- statusMessage: "Refreshing VibeReview security session policy",
84
- },
85
- ],
86
- },
87
- ],
88
- },
89
- }, null, 2) + "\n";
90
- }
91
- export function vscodeHooksContent(config) {
92
- return JSON.stringify({
93
- hooks: {
94
- SessionStart: [
95
- {
96
- type: "command",
97
- command: `printf '%s\\n' '${codexPayload(config, "SessionStart").replaceAll("'", "'\\''")}'`,
98
- timeout: 5,
99
- },
100
- ],
101
- },
102
- }, null, 2) + "\n";
103
- }
104
- function additionalContext(config) {
105
- const project = projectContext(config);
106
- return [
107
- "## MANDATORY VIBEREVIEW SECURITY GATE",
108
- "",
109
- `Configured project: ${project.name} (${project.slug}, ${project.id})`,
110
- "",
111
- "For any request with security impact, follow this order:",
112
- "",
113
- `1. Resolve the tenant/project with ${TOOL_PROJECT} using project_id="${project.id}" or project_slug="${project.slug}".`,
114
- `2. Fetch VibeReview guardrails with ${TOOL_GUARDRAILS}, shortlist relevant guardrails, and preserve that shortlist.`,
115
- "3. Run PWNISMS threat modelling before implementation.",
116
- "4. Implement secure code using the threat model and shortlisted guardrails.",
117
- `5. Write one markdown artifact under .vibreview/scans/ and call ${TOOL_SYNC} immediately after writing it.`,
118
- "",
119
- "No deferral. No local profiling. The main agent owns the final markdown sync.",
120
- ].join("\\n");
121
- }
122
- function codexPayload(config, hookEventName) {
123
- return JSON.stringify({
124
- hookSpecificOutput: {
125
- hookEventName,
126
- additionalContext: additionalContext(config),
127
- },
128
- });
129
- }
130
- function jsonPayload(additionalContext) {
131
- return JSON.stringify({ additional_context: additionalContext });
132
- }
133
- function renderTemplate(templatePath, config, paths) {
134
- const project = projectContext(config);
135
- const template = readFileSync(new URL(`../../templates/shared/${templatePath}`, import.meta.url), "utf8").trim();
136
- return template
137
- .replaceAll("Configured SRAI project name: `<SRAI_PROJECT_NAME>`", [
138
- `Configured VibeReview project: \`${project.name}\``,
139
- `Project slug: \`${project.slug}\``,
140
- `Project id: \`${project.id}\``,
141
- ].join("\n"))
142
- .replaceAll("Configured SRAI project name: `<SRAI_PROJECT_NAME>`", `Configured VibeReview project: \`${project.name}\``)
143
- .replaceAll("name=\"<SRAI_PROJECT_NAME>\"", `project_id="${project.id}", project_slug="${project.slug}", project_name="${project.name}"`)
144
- .replaceAll("<SRAI_PROJECT_NAME>", project.name)
145
- .replaceAll("{{SRAI_PROJECT_NAME}}", project.name)
146
- .replaceAll("SRAI", "VibeReview")
147
- .replaceAll("srai", "vibreview")
148
- .replaceAll("security-review-mcp", "vibreview")
149
- .replaceAll("find_project_by_name", "vibreview_get_tenant_project")
150
- .replaceAll("list_projects", "vibreview_get_tenant_project")
151
- .replaceAll("create_project", "vibreview_get_tenant_project")
152
- .replaceAll("get_project", "vibreview_get_tenant_project")
153
- .replaceAll("get_guardrails", "vibreview_get_guardrails")
154
- .replaceAll("get_guardrail_by_id", "the exact returned guardrail entry")
155
- .replaceAll("sync_ai_ide_markdown", "vibreview_ctm_sync_markdown")
156
- .replaceAll("update_vibe_profile", "server-side repository profiling")
157
- .replaceAll("write_default_pack", "server-side guardrail pack selection")
158
- .replaceAll("`vibereview/`", "`.vibreview/scans/`")
159
- .replaceAll("vibereview/*.md", ".vibreview/scans/*.md")
160
- .replaceAll("vibereview/<chat_session_id>-<slugified-title-or-event-name>.md", ".vibreview/scans/<chat_session_id>-<slugified-title-or-event-name>.md")
161
- .replaceAll("under `vibereview/`", "under `.vibreview/scans/`")
162
- .replaceAll("in `vibereview/`", "in `.vibreview/scans/`")
163
- .replaceAll("`{{GUARDRAILS_SELECTION_SKILL_DIR}}/SKILL.md`", `\`${paths.guardrailsSelectionSkillDir}/SKILL.md\``)
164
- .replaceAll("`{{THREAT_MODELLING_SKILL_DIR}}/SKILL.md`", `\`${paths.threatModellingSkillDir}/SKILL.md\``)
165
- .replaceAll("`{{VIBEREVIEW_SYNC_SKILL_DIR}}/SKILL.md`", `\`${paths.vibereviewSyncSkillDir}/SKILL.md\``)
166
- .replaceAll("{{GUARDRAILS_SELECTION_SKILL_DIR}}", paths.guardrailsSelectionSkillDir)
167
- .replaceAll("{{THREAT_MODELLING_SKILL_DIR}}", paths.threatModellingSkillDir)
168
- .replaceAll("{{VIBEREVIEW_SYNC_SKILL_DIR}}", paths.vibereviewSyncSkillDir)
169
- .replaceAll("name=\"{{SRAI_PROJECT_NAME}}\"", `project_id="${project.id}"`)
170
- .replaceAll("name=\"<VibeReview_PROJECT_NAME>\"", `project_id="${project.id}", project_slug="${project.slug}", project_name="${project.name}"`)
171
- .replaceAll("The old profile walkthrough is no longer part of the agent workflow.", "Local profile walkthroughs are no longer part of the IDE workflow; profiling happens server-side after project creation.")
172
- .replaceAll("Profiler only | `server-side repository profiling`, `server-side guardrail pack selection` are used by init-time profiling, not normal coding tasks", "Profiler only | Server-side repository profiling and guardrail pack selection happen after project creation, not during normal IDE coding tasks");
173
- }
174
- function defaultPaths(ide) {
175
- const root = ide === "claude" ? ".claude/skills" : ide === "vscode" ? ".github/skills" : ide === "codex" ? ".codex/skills" : ".cursor/skills";
176
- return {
177
- guardrailsSelectionSkillDir: `${root}/guardrails-selection`,
178
- threatModellingSkillDir: `${root}/threat-modelling`,
179
- vibereviewSyncSkillDir: `${root}/vibereview-sync`,
180
- };
181
- }
182
- function projectContext(config) {
183
- return {
184
- id: sanitize(config.project_id || config.project_slug),
185
- slug: sanitize(config.project_slug),
186
- name: sanitize(config.project_name || config.project_slug),
187
- };
188
- }
189
- function sanitize(value) {
190
- return value.replace(/[\r\n`]/g, " ").trim();
191
- }
@@ -1,30 +0,0 @@
1
- import { join } from "node:path";
2
- import { CONFIG_DIR, SCANS_DIR, SYNC_STATE_PATH, writeConfig } from "../config.js";
3
- import { ensureDir, readJson, upsertBlock, writeJson } from "../fs.js";
4
- const GITIGNORE_START = "# BEGIN VibeReview";
5
- const GITIGNORE_END = "# END VibeReview";
6
- export async function scaffoldVibeReview(cwd, config) {
7
- await ensureDir(join(cwd, CONFIG_DIR));
8
- await ensureDir(join(cwd, SCANS_DIR));
9
- await writeConfig(cwd, config);
10
- const existingSyncState = await readJson(join(cwd, SYNC_STATE_PATH));
11
- if (!existingSyncState)
12
- await writeJson(join(cwd, SYNC_STATE_PATH), { version: 1, artifacts: {} });
13
- await upsertBlock(join(cwd, ".gitignore"), GITIGNORE_START, GITIGNORE_END, gitignoreEntries(config).join("\n"));
14
- }
15
- function gitignoreEntries(config) {
16
- const entries = [".vibreview/config.json", ".vibreview/sync-state.json", ".vibreview/scans/"];
17
- if (config.ide.includes("claude_code"))
18
- entries.push(".mcp.json");
19
- if (config.ide.includes("cursor"))
20
- entries.push(".cursor/mcp.json");
21
- if (config.ide.includes("vscode_copilot"))
22
- entries.push(".vscode/mcp.json");
23
- if (config.ide.includes("codex"))
24
- entries.push(".codex/config.toml");
25
- if (config.ide.includes("gemini") || config.ide.includes("antigravity"))
26
- entries.push(".gemini/settings.json");
27
- if (config.ide.includes("windsurf"))
28
- entries.push(".windsurf/mcp_config.json");
29
- return entries;
30
- }
@@ -1,28 +0,0 @@
1
- import { join } from "node:path";
2
- import { readJson, writeJson, writeText, upsertBlock } from "../fs.js";
3
- import { mcpRemoteServerWithType } from "./mcp.js";
4
- import { SENTINEL_END, SENTINEL_START, copilotRuleContent, guardrailsSelectionSkillContent, syncSkillContent, threatModelSkillContent, vscodeHooksContent } from "./rules.js";
5
- export async function scaffoldVSCode(cwd, config) {
6
- const paths = {
7
- guardrailsSelectionSkillDir: ".github/skills/guardrails-selection",
8
- threatModellingSkillDir: ".github/skills/threat-modelling",
9
- vibereviewSyncSkillDir: ".github/skills/vibereview-sync",
10
- };
11
- const settingsPath = join(cwd, ".vscode", "settings.json");
12
- const existing = (await readJson(settingsPath)) ?? {};
13
- await writeJson(settingsPath, {
14
- ...existing,
15
- "vibreview.serverUrl": config.server_url,
16
- "vibreview.projectSlug": config.project_slug,
17
- });
18
- const mcpPath = join(cwd, ".vscode", "mcp.json");
19
- const mcpConfig = (await readJson(mcpPath)) ?? {};
20
- const servers = mcpConfig.servers ?? {};
21
- servers.vibreview = mcpRemoteServerWithType(config);
22
- await writeJson(mcpPath, { ...mcpConfig, servers });
23
- await upsertBlock(join(cwd, ".github", "copilot-instructions.md"), SENTINEL_START, SENTINEL_END, copilotRuleContent(config));
24
- await writeText(join(cwd, ".github", "hooks", "vibreview-session-policy.json"), vscodeHooksContent(config));
25
- await writeText(join(cwd, ".github", "skills", "guardrails-selection", "SKILL.md"), `${guardrailsSelectionSkillContent(config, paths)}\n`);
26
- await writeText(join(cwd, ".github", "skills", "threat-modelling", "SKILL.md"), `${threatModelSkillContent(config, paths)}\n`);
27
- await writeText(join(cwd, ".github", "skills", "vibereview-sync", "SKILL.md"), `${syncSkillContent(config)}\n`);
28
- }
@@ -1,10 +0,0 @@
1
- import { join } from "node:path";
2
- import { readJson, writeJson } from "../fs.js";
3
- import { mcpRemoteServer } from "./mcp.js";
4
- export async function scaffoldWindsurf(cwd, config) {
5
- const path = join(cwd, ".windsurf", "mcp_config.json");
6
- const existing = (await readJson(path)) ?? {};
7
- const mcpServers = existing.mcpServers ?? {};
8
- mcpServers.vibreview = mcpRemoteServer(config);
9
- await writeJson(path, { ...existing, mcpServers });
10
- }
@@ -1,34 +0,0 @@
1
- import { readdir, readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { VibeReviewApiClient } from "../api.js";
4
- import { SCANS_DIR, readConfig, writeConfig } from "../config.js";
5
- import { buildSyncMarkdownPayload } from "./payload.js";
6
- import { readSyncState, writeSyncState } from "./state.js";
7
- export async function syncTelemetry(cwd, options = {}) {
8
- const config = await readConfig(cwd);
9
- if (!config)
10
- throw new Error("VibeReview is not initialized. Run `securityreview-kit init` first.");
11
- const scanDir = join(cwd, SCANS_DIR);
12
- const files = (await readdir(scanDir).catch(() => [])).filter((file) => file.endsWith(".md")).sort();
13
- const state = await readSyncState(cwd);
14
- const client = new VibeReviewApiClient(config);
15
- let synced = 0;
16
- let skipped = 0;
17
- for (const file of files) {
18
- const path = join(scanDir, file);
19
- const content = await readFile(path, "utf8");
20
- const payload = buildSyncMarkdownPayload(config.project_slug, path, content, config.ide[0]);
21
- const previous = state.artifacts[payload.artifact_id];
22
- if (!options.force && previous?.artifact_hash === payload.artifact_hash) {
23
- skipped++;
24
- continue;
25
- }
26
- await client.syncCTMMarkdown(config.project_slug, payload);
27
- const syncedAt = new Date().toISOString();
28
- state.artifacts[payload.artifact_id] = { artifact_hash: payload.artifact_hash, synced_at: syncedAt };
29
- synced++;
30
- }
31
- await writeSyncState(cwd, state);
32
- await writeConfig(cwd, { ...config, last_synced: new Date().toISOString() });
33
- return { synced, skipped };
34
- }
@@ -1,23 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { basename } from "node:path";
3
- export function artifactHash(content) {
4
- return createHash("sha256").update(content).digest("hex");
5
- }
6
- export function buildSyncMarkdownPayload(projectSlug, filePath, content, ide) {
7
- const hash = artifactHash(content);
8
- const artifactId = basename(filePath).replace(/\.md$/i, "");
9
- return {
10
- markdown: content,
11
- session_id: artifactId || randomUUID(),
12
- artifact_id: artifactId || hash.slice(0, 16),
13
- artifact_hash: hash,
14
- idempotency_key: `${projectSlug}:${artifactId}:${hash}`,
15
- generated_at: new Date().toISOString(),
16
- file_name: basename(filePath),
17
- ide,
18
- metadata: {
19
- source: "securityreview-kit",
20
- file_path: filePath,
21
- },
22
- };
23
- }
@@ -1,12 +0,0 @@
1
- import { join } from "node:path";
2
- import { SYNC_STATE_PATH } from "../config.js";
3
- import { readJson, writeJson } from "../fs.js";
4
- export async function readSyncState(cwd) {
5
- return ((await readJson(join(cwd, SYNC_STATE_PATH))) ?? {
6
- version: 1,
7
- artifacts: {},
8
- });
9
- }
10
- export async function writeSyncState(cwd, state) {
11
- await writeJson(join(cwd, SYNC_STATE_PATH), state);
12
- }
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,13 +0,0 @@
1
- # VibeReview Security Workflow
2
-
3
- When implementing or changing code in this repository:
4
-
5
- 1. Resolve the current tenant/project with `vibreview_get_tenant_project`.
6
- 2. Fetch the project's guardrail bundle with `vibreview_get_guardrails`.
7
- 3. Locally shortlist the guardrails relevant to the user's requested feature or change.
8
- 4. Before editing, write a concise threat model for the requested change.
9
- 5. Implement the change while preserving the shortlisted guardrails.
10
- 6. Record the review/threat-model outcome as one markdown artifact in `.vibreview/scans/`.
11
- 7. Sync the markdown artifact with `vibreview_ctm_sync_markdown`.
12
-
13
- Do not run local repository profiling from the IDE. VibeReview profiles the repository server-side after project creation and stores the relevant guardrails for this tenant/project in the MCP-backed KV cache.
@@ -1,12 +0,0 @@
1
- # Guardrail Selector
2
-
3
- Use this agent when a task needs careful guardrail selection before code changes.
4
-
5
- Do not profile the local repository from the IDE. VibeReview SaaS profiles repositories server-side after project creation and projects the required guardrails into the MCP/KV path.
6
-
7
- Workflow:
8
-
9
- 1. Call `vibreview_get_tenant_project`.
10
- 2. Call `vibreview_get_guardrails`.
11
- 3. Rank guardrails by direct relevance to the user request, changed files, data handled, entry points, auth/authorization boundaries, and external integrations.
12
- 4. Return the shortlisted guardrail IDs, names, and the reason each one applies.
@@ -1,5 +0,0 @@
1
- # Threat Modeler
2
-
3
- Placeholder agent definition for future VibeReview threat modeling automation.
4
-
5
- Before implementation, use `vibreview_get_tenant_project` and `vibreview_get_guardrails`, shortlist the relevant guardrails locally, and identify likely threats, mitigations, standards mappings, and residual risk. Keep the model concise enough to sync as one markdown artifact with `vibreview_ctm_sync_markdown`.
@@ -1,21 +0,0 @@
1
- # VibeReview Skill
2
-
3
- Use this skill for VibeReview-aware secure coding sessions.
4
-
5
- ## Fast Sync Rules
6
-
7
- - Write one telemetry artifact per task in `.vibreview/scans/`.
8
- - Keep the artifact readable markdown: task, threat model, selected guardrails, decisions, and follow-up risks.
9
- - Avoid pasting large diffs or full files into telemetry unless necessary.
10
- - Include guardrail IDs, affected files, and concise evidence when useful.
11
- - Call `vibreview_ctm_sync_markdown` immediately after implementation or threat model updates.
12
-
13
- ## Workflow
14
-
15
- 1. Load tenant/project context with `vibreview_get_tenant_project`.
16
- 2. Fetch guardrails with `vibreview_get_guardrails`.
17
- 3. Filter and rank the returned guardrails locally for the requested feature.
18
- 4. Threat model before editing.
19
- 5. Implement with guardrails applied.
20
- 6. Record markdown telemetry.
21
- 7. Sync with `vibreview_ctm_sync_markdown`.
@@ -1,12 +0,0 @@
1
- # Guardrail Patterns
2
-
3
- Fetch the project guardrail bundle with `vibreview_get_guardrails`, then filter locally against the feature request, touched files, framework, data flow, and threat model.
4
-
5
- - Authentication: login, sessions, password handling, MFA, tokens.
6
- - Authorization: role checks, object ownership, tenant isolation.
7
- - Persistence: database queries, ORM usage, migrations.
8
- - Validation: input parsing, bounds, schemas, file uploads.
9
- - Data Exposure: logs, errors, secrets, sensitive output.
10
- - Transport: TLS, headers, callbacks, API clients.
11
-
12
- For broad changes, build a shortlist before editing. Prefer guardrails with direct category, title, instruction, severity, or metadata matches. Keep the selected guardrail IDs in the `.vibreview/scans/` markdown artifact so VibeReview can connect the IDE-side work back to the server-side guardrail set.
@@ -1,8 +0,0 @@
1
- ---
2
- description: VibeReview security workflow
3
- alwaysApply: true
4
- ---
5
-
6
- Before security-relevant code changes, use `vibreview_get_tenant_project` to resolve the tenant/project, then call `vibreview_get_guardrails` to fetch the project guardrail bundle. Filter and rank the returned guardrails locally against the user's requested feature before implementing.
7
-
8
- Record one readable markdown artifact in `.vibreview/scans/` with the threat model, selected guardrail IDs, decisions, and important evidence. Sync it with `vibreview_ctm_sync_markdown`. Do not run local repository profiling; VibeReview handles profiling server-side after project creation.