mirror of
https://github.com/cline/cline.git
synced 2026-09-12 17:19:32 +08:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07e2d0d3f8 | ||
|
|
ba471b7db9 | ||
|
|
72e2c8de2b | ||
|
|
5e7257d218 | ||
|
|
dcef5b29d1 | ||
|
|
6b530e5950 | ||
|
|
26daf9cb48 |
@@ -39,6 +39,7 @@ Requires Node.js 22+.
|
||||
| Example | Description | Concepts |
|
||||
|---------|-------------|----------|
|
||||
| [code-review-bot](./code-review-bot) | AI code reviewer that reads git diffs and produces structured comments. | Multiple tools, `completesRun` lifecycle, `systemPrompt`, zod schemas |
|
||||
| [security-review-bot](./security-review-bot) | AI application security reviewer that reads git diffs and produces structured security findings. | Specialized agent prompts, multiple tools, security schemas, `completesRun` lifecycle |
|
||||
| [multi-agent](./multi-agent) | Web app that fans out to three specialist agents in parallel, streams results via SSE, then synthesizes a unified answer. | Concurrent agents, `Promise.all`, per-agent `subscribe()`, SSE streaming, agent composition |
|
||||
|
||||
### Advanced
|
||||
|
||||
@@ -167,7 +167,20 @@ fn push_notification(
|
||||
}
|
||||
|
||||
fn resolve_sidecar_script(workspace_root: &str, launch_cwd: &str) -> Option<PathBuf> {
|
||||
let candidates = [
|
||||
sidecar_script_candidates(workspace_root, launch_cwd)
|
||||
.into_iter()
|
||||
.find(|p| p.exists())
|
||||
}
|
||||
|
||||
fn sidecar_script_candidates(workspace_root: &str, launch_cwd: &str) -> Vec<PathBuf> {
|
||||
vec![
|
||||
PathBuf::from(workspace_root)
|
||||
.join("sdk")
|
||||
.join("apps")
|
||||
.join("examples")
|
||||
.join("menubar")
|
||||
.join("sidecar")
|
||||
.join("index.ts"),
|
||||
PathBuf::from(workspace_root)
|
||||
.join("sdk")
|
||||
.join("apps")
|
||||
@@ -182,8 +195,7 @@ fn resolve_sidecar_script(workspace_root: &str, launch_cwd: &str) -> Option<Path
|
||||
.join("sidecar")
|
||||
.join("index.ts"),
|
||||
PathBuf::from(launch_cwd).join("sidecar").join("index.ts"),
|
||||
];
|
||||
candidates.into_iter().find(|p| p.exists())
|
||||
]
|
||||
}
|
||||
|
||||
fn sidecar_binary_name() -> String {
|
||||
@@ -261,8 +273,13 @@ fn start_sidecar(
|
||||
.current_dir(workspace_root);
|
||||
c
|
||||
} else {
|
||||
let searched_paths = sidecar_script_candidates(workspace_root, launch_cwd)
|
||||
.into_iter()
|
||||
.map(|path| path.display().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
return Err(format!(
|
||||
"menubar sidecar not found under workspace_root={workspace_root}"
|
||||
"menubar sidecar not found under workspace_root={workspace_root}; searched: {searched_paths}"
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# Security Review Bot on git diffs
|
||||
|
||||
An AI-powered application security review agent that reads a git diff, analyzes it for security risk, and produces structured findings with severity, category, CWE/OWASP metadata, exploit scenarios, remediation guidance, and confidence levels.
|
||||
|
||||
This example is based on the `code-review-bot` example, but uses the `ClineCore` runtime instead of the lightweight `Agent` runtime. That means it can use ClineCore's built-in workspace tools, including `read_files` and `search_codebase`, while still adding custom security review tools through `extraTools`.
|
||||
|
||||
## Getting started
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
bun run build:sdk
|
||||
```
|
||||
|
||||
Set an API key:
|
||||
|
||||
```bash
|
||||
export CLINE_API_KEY="cline_..."
|
||||
```
|
||||
|
||||
Security review the last commit:
|
||||
|
||||
```bash
|
||||
bun dev
|
||||
```
|
||||
|
||||
Security review against a specific ref:
|
||||
|
||||
```bash
|
||||
bun dev main
|
||||
bun dev HEAD~5
|
||||
bun dev abc123
|
||||
```
|
||||
|
||||
Add run-specific review instructions with `--prompt` or `-p`:
|
||||
|
||||
```bash
|
||||
bun dev main --prompt "Focus on authorization bypasses and SSRF"
|
||||
bun dev HEAD~1 -p "Treat test-only secrets as low severity"
|
||||
```
|
||||
|
||||
You can also pass extra positional text after the ref; it will be appended as additional review instructions:
|
||||
|
||||
```bash
|
||||
bun dev main "Prioritize auth, secrets, and unsafe file access"
|
||||
```
|
||||
|
||||
## Review a specific repo
|
||||
|
||||
The bot reviews the git repository in the current working directory. To review a different repo, run the example command from that repo's directory and pass the ref you want to compare against.
|
||||
|
||||
Using Bun directly from another repo:
|
||||
|
||||
```bash
|
||||
cd /path/to/repo-you-want-to-review
|
||||
bun --cwd /path/to/cline/sdk/apps/examples/security-review-bot dev main
|
||||
```
|
||||
|
||||
With extra instructions:
|
||||
|
||||
```bash
|
||||
cd /path/to/repo-you-want-to-review
|
||||
bun --cwd /path/to/cline/sdk/apps/examples/security-review-bot dev main --prompt "Focus on payment and admin flows"
|
||||
```
|
||||
|
||||
Or build the example once and run the compiled JavaScript from any git repo:
|
||||
|
||||
```bash
|
||||
cd /path/to/cline/sdk/apps/examples/security-review-bot
|
||||
bun run build
|
||||
|
||||
cd /path/to/repo-you-want-to-review
|
||||
node /path/to/cline/sdk/apps/examples/security-review-bot/dist/index.js main
|
||||
```
|
||||
|
||||
The argument is passed to `git diff <ref>` in the target repo. Common examples:
|
||||
|
||||
```bash
|
||||
# Review all changes on your branch compared with main
|
||||
bun --cwd /path/to/cline/sdk/apps/examples/security-review-bot dev main
|
||||
|
||||
# Review the last commit
|
||||
bun --cwd /path/to/cline/sdk/apps/examples/security-review-bot dev HEAD~1
|
||||
|
||||
# Review changes since a release tag
|
||||
bun --cwd /path/to/cline/sdk/apps/examples/security-review-bot dev v1.2.3
|
||||
```
|
||||
|
||||
If you want to review uncommitted changes in a target repo, compare against the branch or commit you started from, for example:
|
||||
|
||||
```bash
|
||||
cd /path/to/repo-you-want-to-review
|
||||
bun --cwd /path/to/cline/sdk/apps/examples/security-review-bot dev main
|
||||
```
|
||||
|
||||
## What it does
|
||||
|
||||
1. Reads a `git diff` against the specified ref (defaults to `HEAD~1`)
|
||||
2. Starts a local `ClineCore` session with built-in tools enabled
|
||||
3. Lets the model use ClineCore's `read_files` and `search_codebase` tools for surrounding file context
|
||||
4. Adds two custom security review tools through `extraTools`:
|
||||
- `add_security_finding` - records a structured security finding with severity, category, exploit scenario, remediation, and confidence
|
||||
- `submit_security_review` - a completion tool that ends the run with a summary, overall risk rating, and merge-blocking decision
|
||||
5. Prints findings grouped by severity (`critical`, `high`, `medium`, `low`, `info`)
|
||||
|
||||
## Finding schema
|
||||
|
||||
Each finding includes:
|
||||
|
||||
- `file` and `line` - where the issue appears
|
||||
- `severity` - `critical`, `high`, `medium`, `low`, or `info`
|
||||
- `category` - security category such as `injection`, `authorization`, `secrets`, `ssrf`, `xss`, or `cryptography`
|
||||
- `cwe` and `owasp` - optional vulnerability taxonomy metadata
|
||||
- `title` and `description` - concise summary and risk explanation
|
||||
- `exploitScenario` - realistic abuse case
|
||||
- `remediation` - concrete fix or mitigation
|
||||
- `confidence` - `high`, `medium`, or `low`
|
||||
|
||||
## Concepts demonstrated
|
||||
|
||||
- Using `ClineCore.create()` and `cline.start()` for a local runtime session
|
||||
- Enabling selected ClineCore built-in tools, including `read_files` and `search_codebase`
|
||||
- Adding domain-specific custom tools with `extraTools`
|
||||
- `lifecycle: { completesRun: true }` to make a tool end the agent loop
|
||||
- Subscribing to `CoreSessionEvent` events with `cline.subscribe()`
|
||||
- Rendering parsed `agent_event` text/tool events instead of printing serialized `chunk` payloads
|
||||
- Cleaning up runtime resources with `cline.dispose()`
|
||||
- Processing structured results after the run completes
|
||||
|
||||
## Notes
|
||||
|
||||
This is an AI-assisted review tool, not a replacement for SAST, dependency scanning, secret scanning, manual threat modeling, or human security review. Treat findings as review input and verify them before acting.
|
||||
|
||||
For a general-purpose reviewer, see [code-review-bot](../code-review-bot). For a simpler starting point, see [quickstart](../quickstart).
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@cline/example-security-review-bot",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun run src/index.ts",
|
||||
"build:sdk": "bun run --cwd ../../.. build:sdk",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cline/sdk": "workspace:*",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import {
|
||||
type AgentEvent,
|
||||
type AgentTool,
|
||||
ClineCore,
|
||||
createTool,
|
||||
type ToolPolicy,
|
||||
} from "@cline/sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
const SecurityFindingSchema = z.object({
|
||||
file: z.string().describe("File path"),
|
||||
line: z.number().describe("Line number (approximate is fine)"),
|
||||
severity: z.enum(["critical", "high", "medium", "low", "info"]),
|
||||
category: z
|
||||
.enum([
|
||||
"authentication",
|
||||
"authorization",
|
||||
"injection",
|
||||
"secrets",
|
||||
"cryptography",
|
||||
"data_exposure",
|
||||
"ssrf",
|
||||
"xss",
|
||||
"deserialization",
|
||||
"path_traversal",
|
||||
"dependency",
|
||||
"logging_monitoring",
|
||||
"configuration",
|
||||
"other",
|
||||
])
|
||||
.describe("Security weakness category"),
|
||||
cwe: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Relevant CWE identifier, such as CWE-89, if known"),
|
||||
owasp: z.string().optional().describe("Relevant OWASP category, if known"),
|
||||
title: z.string().describe("Short finding title"),
|
||||
description: z.string().describe("What is vulnerable and why it matters"),
|
||||
exploitScenario: z
|
||||
.string()
|
||||
.describe("A realistic abuse case or exploit path"),
|
||||
remediation: z.string().describe("Concrete recommended fix or mitigation"),
|
||||
confidence: z.enum(["high", "medium", "low"]),
|
||||
});
|
||||
|
||||
const SecurityReviewResultSchema = z.object({
|
||||
summary: z.string().describe("Brief overall security assessment"),
|
||||
overallRisk: z.enum(["critical", "high", "medium", "low", "none"]),
|
||||
blockMerge: z
|
||||
.boolean()
|
||||
.describe("Whether the changes should be blocked from merging"),
|
||||
});
|
||||
|
||||
const findings: z.infer<typeof SecurityFindingSchema>[] = [];
|
||||
let reviewResult: z.infer<typeof SecurityReviewResultSchema> | undefined;
|
||||
|
||||
const repoRoot = (() => {
|
||||
try {
|
||||
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
||||
encoding: "utf-8",
|
||||
}).trim();
|
||||
} catch {
|
||||
console.error("Error: must be run from within a git repository.");
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
||||
const systemPrompt = `You are a senior application security engineer performing a focused security review of a git diff.
|
||||
|
||||
Your goal is to identify exploitable or defense-in-depth security issues introduced or modified by the diff. The repository root is ${repoRoot}. Use the read_files tool with absolute paths, or search_codebase, when you need surrounding code to determine whether a finding is real.
|
||||
|
||||
Focus on:
|
||||
- Authentication and authorization bypasses
|
||||
- Injection flaws, including SQL/NoSQL/command/template/LDAP injection
|
||||
- Cross-site scripting and unsafe HTML/script rendering
|
||||
- Server-side request forgery and unsafe URL fetching
|
||||
- Path traversal and unsafe file operations
|
||||
- Hardcoded secrets, tokens, private keys, and credential leakage
|
||||
- Cryptographic misuse, weak randomness, insecure hashing, or missing integrity checks
|
||||
- Sensitive data exposure in logs, errors, telemetry, APIs, or client bundles
|
||||
- Unsafe deserialization or dynamic code execution
|
||||
- Insecure dependency, environment, CORS, cookie, header, or cloud configuration changes
|
||||
- Missing validation, rate limits, audit logging, or security checks around sensitive operations
|
||||
|
||||
Only report actionable findings that are supported by the diff or file context. Do not report generic best practices unless they materially reduce a realistic risk. Prefer fewer high-quality findings over many speculative ones.
|
||||
|
||||
Severity guidance:
|
||||
- critical: likely remote code execution, auth bypass, mass data exposure, secret compromise, or trivially exploitable injection on sensitive data paths
|
||||
- high: practical privilege escalation, significant data exposure, SSRF with meaningful impact, or exploitable stored XSS
|
||||
- medium: plausible vulnerability requiring constraints, limited data exposure, missing authorization on lower-risk operations, or reflected XSS with user interaction
|
||||
- low: hardening issue with limited exploitability
|
||||
- info: noteworthy observation with minimal direct risk
|
||||
|
||||
For each real issue, call add_security_finding with clear evidence, exploit scenario, remediation, confidence, and CWE/OWASP metadata when applicable.
|
||||
|
||||
When you are done reviewing, call submit_security_review with a brief summary, an overall risk rating, and whether the changes should be blocked from merging.`;
|
||||
|
||||
const addSecurityFindingTool = createTool({
|
||||
name: "add_security_finding",
|
||||
description:
|
||||
"Add an actionable security finding on a specific file and line.",
|
||||
inputSchema: SecurityFindingSchema,
|
||||
async execute(input) {
|
||||
findings.push(input);
|
||||
return {
|
||||
success: true,
|
||||
message: `Security finding added (${findings.length} total)`,
|
||||
findingCount: findings.length,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const submitSecurityReviewTool = createTool({
|
||||
name: "submit_security_review",
|
||||
description: "Submit the completed security review with a risk summary.",
|
||||
inputSchema: SecurityReviewResultSchema,
|
||||
lifecycle: { completesRun: true },
|
||||
async execute(input) {
|
||||
reviewResult = input;
|
||||
return {
|
||||
success: true,
|
||||
summary: input.summary,
|
||||
overallRisk: input.overallRisk,
|
||||
blockMerge: input.blockMerge,
|
||||
findingCount: findings.length,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const securityReviewTools: AgentTool[] = [
|
||||
addSecurityFindingTool as AgentTool,
|
||||
submitSecurityReviewTool as AgentTool,
|
||||
];
|
||||
|
||||
const securityReviewToolPolicies = {
|
||||
"*": { autoApprove: true },
|
||||
read_files: { autoApprove: true },
|
||||
search_codebase: { autoApprove: true },
|
||||
add_security_finding: { autoApprove: true },
|
||||
submit_security_review: { autoApprove: true },
|
||||
run_commands: { enabled: false },
|
||||
fetch_web_content: { enabled: false },
|
||||
editor: { enabled: false },
|
||||
apply_patch: { enabled: false },
|
||||
skills: { enabled: false },
|
||||
ask_question: { enabled: false },
|
||||
} satisfies Record<string, ToolPolicy>;
|
||||
|
||||
let reasoningOpen = false;
|
||||
|
||||
function closeReasoning() {
|
||||
if (reasoningOpen) {
|
||||
process.stdout.write("\n");
|
||||
reasoningOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
function renderToolStart(
|
||||
event: Extract<AgentEvent, { type: "content_start" }>,
|
||||
) {
|
||||
const toolName = event.toolName ?? "unknown_tool";
|
||||
if (toolName === "add_security_finding") {
|
||||
const parsed = SecurityFindingSchema.safeParse(event.input);
|
||||
if (!parsed.success) {
|
||||
console.log(`\n[tool] ${toolName}`);
|
||||
return;
|
||||
}
|
||||
const input = parsed.data;
|
||||
const icon =
|
||||
input.severity === "critical"
|
||||
? "X"
|
||||
: input.severity === "high"
|
||||
? "!"
|
||||
: input.severity === "medium"
|
||||
? "~"
|
||||
: "i";
|
||||
console.log(
|
||||
`\n [${icon}] ${input.severity.toUpperCase()} ${input.file}:${input.line} - ${input.title}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\n[tool] ${toolName}`);
|
||||
}
|
||||
|
||||
function renderAgentEvent(event: AgentEvent) {
|
||||
switch (event.type) {
|
||||
case "content_start":
|
||||
if (event.contentType === "text" && event.text) {
|
||||
closeReasoning();
|
||||
process.stdout.write(event.text);
|
||||
return;
|
||||
}
|
||||
if (event.contentType === "reasoning") {
|
||||
if (event.redacted === true && !event.reasoning) {
|
||||
console.log("\n[thinking redacted]");
|
||||
return;
|
||||
}
|
||||
if (event.reasoning) {
|
||||
if (!reasoningOpen) {
|
||||
process.stdout.write("\n[thinking]\n");
|
||||
reasoningOpen = true;
|
||||
}
|
||||
process.stdout.write(event.reasoning);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.contentType === "tool") {
|
||||
closeReasoning();
|
||||
renderToolStart(event);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "content_end":
|
||||
if (event.contentType === "reasoning") {
|
||||
closeReasoning();
|
||||
return;
|
||||
}
|
||||
if (event.contentType === "tool" && event.error) {
|
||||
closeReasoning();
|
||||
console.log(
|
||||
`\n[tool failed] ${event.toolName ?? "unknown_tool"}: ${event.error}`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the diff to review
|
||||
const { ref, extraPrompt } = parseArgs(process.argv.slice(2));
|
||||
if (ref.startsWith("-")) {
|
||||
console.error(`Invalid ref: ${ref}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let diff: string;
|
||||
try {
|
||||
diff = execFileSync("git", ["diff", ref], {
|
||||
encoding: "utf-8",
|
||||
maxBuffer: 5 * 1024 * 1024,
|
||||
});
|
||||
} catch {
|
||||
console.error(`Failed to get diff for ref: ${ref}`);
|
||||
console.error("Usage: bun dev [git-ref]");
|
||||
console.error(" e.g. bun dev HEAD~3");
|
||||
console.error(" e.g. bun dev main");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!diff.trim()) {
|
||||
console.log("No diff found. Nothing to security review.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Security reviewing diff against ${ref} (${diff.split("\n").length} lines)...\n`,
|
||||
);
|
||||
if (extraPrompt) {
|
||||
console.log(`Additional review instructions: ${extraPrompt}\n`);
|
||||
}
|
||||
|
||||
const cline = await ClineCore.create({
|
||||
clientName: "security-review-bot",
|
||||
backendMode: "local",
|
||||
});
|
||||
|
||||
const unsubscribe = cline.subscribe((event) => {
|
||||
switch (event.type) {
|
||||
case "agent_event":
|
||||
renderAgentEvent(event.payload.event);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const prompt = `Security review this git diff.${
|
||||
extraPrompt ? `\n\nAdditional review instructions:\n${extraPrompt}` : ""
|
||||
}\n\n\`\`\`diff\n${diff}\n\`\`\``;
|
||||
|
||||
const result = await cline.start({
|
||||
source: "cli",
|
||||
interactive: false,
|
||||
prompt,
|
||||
config: {
|
||||
providerId: "cline",
|
||||
modelId: "anthropic/claude-sonnet-4.6",
|
||||
apiKey: process.env.CLINE_API_KEY,
|
||||
cwd: repoRoot,
|
||||
workspaceRoot: repoRoot,
|
||||
mode: "act",
|
||||
systemPrompt,
|
||||
maxIterations: 25,
|
||||
enableTools: true,
|
||||
enableSpawnAgent: false,
|
||||
enableAgentTeams: false,
|
||||
disableMcpSettingsTools: true,
|
||||
toolPolicies: securityReviewToolPolicies,
|
||||
},
|
||||
localRuntime: {
|
||||
extraTools: securityReviewTools,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("\n\n--- Security Review Complete ---\n");
|
||||
|
||||
if (reviewResult) {
|
||||
console.log(`Summary: ${reviewResult.summary}`);
|
||||
console.log(`Overall risk: ${reviewResult.overallRisk}`);
|
||||
console.log(`Block merge: ${reviewResult.blockMerge ? "yes" : "no"}\n`);
|
||||
}
|
||||
|
||||
if (findings.length === 0) {
|
||||
console.log("No actionable security findings identified.");
|
||||
} else {
|
||||
const severityOrder = [
|
||||
"critical",
|
||||
"high",
|
||||
"medium",
|
||||
"low",
|
||||
"info",
|
||||
] as const;
|
||||
|
||||
for (const severity of severityOrder) {
|
||||
const group = findings.filter((finding) => finding.severity === severity);
|
||||
if (group.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`${severity.toUpperCase()}: ${group.length}`);
|
||||
for (const finding of group) {
|
||||
const metadata = [finding.cwe, finding.owasp]
|
||||
.filter(Boolean)
|
||||
.join(" | ");
|
||||
console.log(
|
||||
` ${finding.file}:${finding.line} - ${finding.title}${metadata ? ` (${metadata})` : ""}`,
|
||||
);
|
||||
console.log(` Category: ${finding.category}`);
|
||||
console.log(` Confidence: ${finding.confidence}`);
|
||||
console.log(` Risk: ${finding.description}`);
|
||||
console.log(` Exploit: ${finding.exploitScenario}`);
|
||||
console.log(` Fix: ${finding.remediation}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const usage = result.result?.usage;
|
||||
console.log(
|
||||
`\nSession: ${result.sessionId} | Status: ${result.result?.finishReason ?? "unknown"} | Iterations: ${result.result?.iterations ?? 0} | Tokens: ${usage?.outputTokens ?? 0} output`,
|
||||
);
|
||||
} finally {
|
||||
unsubscribe();
|
||||
await cline.dispose();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.apps.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -186,6 +186,17 @@
|
||||
"typescript": "^5.9.3",
|
||||
},
|
||||
},
|
||||
"apps/examples/security-review-bot": {
|
||||
"name": "@cline/example-security-review-bot",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@cline/sdk": "workspace:*",
|
||||
"zod": "^4.3.6",
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3",
|
||||
},
|
||||
},
|
||||
"apps/examples/vscode": {
|
||||
"name": "@cline/vscode",
|
||||
"version": "0.0.0",
|
||||
@@ -611,6 +622,8 @@
|
||||
|
||||
"@cline/example-quickstart": ["@cline/example-quickstart@workspace:apps/examples/quickstart"],
|
||||
|
||||
"@cline/example-security-review-bot": ["@cline/example-security-review-bot@workspace:apps/examples/security-review-bot"],
|
||||
|
||||
"@cline/llms": ["@cline/llms@workspace:packages/llms"],
|
||||
|
||||
"@cline/menubar": ["@cline/menubar@workspace:apps/examples/menubar"],
|
||||
|
||||
Reference in New Issue
Block a user