Matt Rubens пре 1 година
родитељ
комит
733e236725
12 измењених фајлова са 0 додато и 1103 уклоњено
  1. 0 110
      cli/README.md
  2. 0 10
      cli/api/mod.ts
  3. 0 147
      cli/api/providers/openrouter.ts
  4. 0 164
      cli/core/StandaloneAgent.ts
  5. 0 120
      cli/core/prompts.ts
  6. 0 40
      cli/deno.d.ts
  7. 0 13
      cli/deno.jsonc
  8. 0 87
      cli/deno.lock
  9. 0 21
      cli/deps.ts
  10. 0 123
      cli/mod.ts
  11. 0 225
      cli/tools/mod.ts
  12. 0 43
      cli/types.d.ts

+ 0 - 110
cli/README.md

@@ -1,110 +0,0 @@
-# Cline CLI
-
-A command-line interface for Cline, powered by Deno.
-
-## Installation
-
-1. Make sure you have [Deno](https://deno.land/) installed
-2. Install the CLI globally:
-   ```bash
-   cd cli
-   deno task install
-   ```
-
-If you get a PATH warning during installation, add Deno's bin directory to your PATH:
-```bash
-echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.bashrc  # or ~/.zshrc
-source ~/.bashrc  # or ~/.zshrc
-```
-
-## Usage
-
-```bash
-cline <task> [options]
-```
-
-### Security Model
-
-The CLI implements several security measures:
-
-1. File Operations:
-   - Read/write access limited to working directory (--allow-read=., --allow-write=.)
-   - Prevents access to files outside the project
-
-2. Command Execution:
-   - Strict allowlist of safe commands:
-     * npm (install, run, test, build)
-     * git (status, add, commit, push, pull, clone, checkout, branch)
-     * deno (run, test, fmt, lint, check, compile, bundle)
-     * ls (-l, -a, -la, -lh)
-     * cat, echo
-   - Interactive prompts for non-allowlisted commands:
-     * y - Run once
-     * n - Cancel execution
-     * always - Remember for session
-   - Clear warnings and command details shown
-   - Session-based memory for approved commands
-
-3. Required Permissions:
-   - --allow-read=. - Read files in working directory
-   - --allow-write=. - Write files in working directory
-   - --allow-run - Execute allowlisted commands
-   - --allow-net - Make API calls
-   - --allow-env - Access environment variables
-
-### Options
-
-- `-m, --model <model>` - LLM model to use (default: "anthropic/claude-3.5-sonnet")
-- `-k, --key <key>` - OpenRouter API key (required, or set OPENROUTER_API_KEY env var)
-- `-h, --help` - Display help for command
-
-### Examples
-
-Analyze code:
-```bash
-export OPENROUTER_API_KEY=sk-or-v1-...
-cline "Analyze this codebase"
-```
-
-Create files:
-```bash
-cline "Create a React component"
-```
-
-Run allowed command:
-```bash
-cline "Run npm install"
-```
-
-Run non-allowlisted command (will prompt for decision):
-```bash
-cline "Run yarn install"
-# Responds with:
-# Warning: Command not in allowlist
-# Command: yarn install
-# Do you want to run this command? (y/n/always)
-```
-
-## Development
-
-The CLI is built with Deno. Available tasks:
-
-```bash
-# Run in development mode
-deno task dev "your task here"
-
-# Install globally
-deno task install
-
-# Type check the code
-deno task check
-```
-
-### Security Features
-
-- File operations restricted to working directory
-- Command execution controlled by allowlist
-- Interactive prompts for unknown commands
-- Session-based command approval
-- Clear warnings and command details
-- Permission validation at runtime

+ 0 - 10
cli/api/mod.ts

@@ -1,10 +0,0 @@
-import type { ApiConfiguration, ApiHandler } from "../types.d.ts";
-import { OpenRouterHandler } from "./providers/openrouter.ts";
-
-// Re-export the ApiHandler interface
-export type { ApiHandler };
-
-export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
-  const { apiKey, model } = configuration;
-  return new OpenRouterHandler({ apiKey, model });
-}

+ 0 - 147
cli/api/providers/openrouter.ts

@@ -1,147 +0,0 @@
-import type { ApiStream, ModelInfo, Message, TextBlock } from "../../types.d.ts";
-
-interface OpenRouterOptions {
-  model: string;
-  apiKey: string;
-}
-
-export class OpenRouterHandler {
-  private apiKey: string;
-  private model: string;
-
-  constructor(options: OpenRouterOptions) {
-    this.apiKey = options.apiKey;
-    this.model = options.model;
-  }
-
-  async *createMessage(systemPrompt: string, messages: Message[]): ApiStream {
-    try {
-      // Convert our messages to OpenRouter format
-      const openRouterMessages = [
-        { role: "system", content: systemPrompt },
-        ...messages.map(msg => ({
-          role: msg.role,
-          content: Array.isArray(msg.content)
-            ? msg.content.map(c => c.text).join("\n")
-            : msg.content
-        }))
-      ];
-
-      const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
-        method: "POST",
-        headers: {
-          "Authorization": `Bearer ${this.apiKey}`,
-          "Content-Type": "application/json",
-          "HTTP-Referer": "https://github.com/RooVetGit/Roo-Cline",
-          "X-Title": "Roo Cline"
-        },
-        body: JSON.stringify({
-          model: this.model,
-          messages: openRouterMessages,
-          stream: true,
-          temperature: 0.7,
-          max_tokens: 4096
-        })
-      });
-
-      if (!response.ok) {
-        const errorData = await response.json().catch(() => null);
-        throw new Error(`OpenRouter API error: ${response.statusText}${errorData ? ` - ${JSON.stringify(errorData)}` : ""}`);
-      }
-
-      if (!response.body) {
-        throw new Error("No response body received");
-      }
-
-      const reader = response.body.getReader();
-      const decoder = new TextDecoder();
-      let buffer = "";
-      let content = "";
-
-      while (true) {
-        const { done, value } = await reader.read();
-        if (done) break;
-
-        // Add new chunk to buffer and split into lines
-        buffer += decoder.decode(value, { stream: true });
-        const lines = buffer.split("\n");
-        
-        // Process all complete lines
-        buffer = lines.pop() || ""; // Keep the last incomplete line in buffer
-        
-        for (const line of lines) {
-          if (line.trim() === "") continue;
-          if (line === "data: [DONE]") continue;
-          
-          if (line.startsWith("data: ")) {
-            try {
-              const data = JSON.parse(line.slice(6));
-              if (data.choices?.[0]?.delta?.content) {
-                const text = data.choices[0].delta.content;
-                content += text;
-                yield { type: "text", text };
-              }
-            } catch (e) {
-              // Ignore parse errors for incomplete chunks
-              continue;
-            }
-          }
-        }
-      }
-
-      // Process any remaining content in buffer
-      if (buffer.trim() && buffer.startsWith("data: ")) {
-        try {
-          const data = JSON.parse(buffer.slice(6));
-          if (data.choices?.[0]?.delta?.content) {
-            const text = data.choices[0].delta.content;
-            content += text;
-            yield { type: "text", text };
-          }
-        } catch (e) {
-          // Ignore parse errors for final incomplete chunk
-        }
-      }
-
-      // Estimate token usage (4 chars per token is a rough estimate)
-      const inputText = systemPrompt + messages.reduce((acc, msg) => 
-        acc + (typeof msg.content === "string" ? 
-          msg.content : 
-          msg.content.reduce((a, b) => a + b.text, "")), "");
-
-      const inputTokens = Math.ceil(inputText.length / 4);
-      const outputTokens = Math.ceil(content.length / 4);
-
-      yield {
-        type: "usage",
-        inputTokens,
-        outputTokens,
-        totalCost: this.calculateCost(inputTokens, outputTokens)
-      };
-
-    } catch (error) {
-      console.error("Error in OpenRouter API call:", error);
-      throw error;
-    }
-  }
-
-  getModel(): { id: string; info: ModelInfo } {
-    return {
-      id: this.model,
-      info: {
-        contextWindow: 128000, // This varies by model
-        supportsComputerUse: true,
-        inputPricePerToken: 0.000002, // Approximate, varies by model
-        outputPricePerToken: 0.000002
-      }
-    };
-  }
-
-  private calculateCost(inputTokens: number, outputTokens: number): number {
-    const { inputPricePerToken, outputPricePerToken } = this.getModel().info;
-    return (
-      (inputTokens * (inputPricePerToken || 0)) +
-      (outputTokens * (outputPricePerToken || 0))
-    );
-  }
-}

+ 0 - 164
cli/core/StandaloneAgent.ts

@@ -1,164 +0,0 @@
-import { blue, red, yellow } from "../deps.ts";
-import { ApiHandler } from "../api/mod.ts";
-import { executeCommand, readFile, writeFile, searchFiles, listFiles, listCodeDefinitions } from "../tools/mod.ts";
-import type { Message, TextBlock, ToolResult } from "../types.d.ts";
-
-interface AgentConfig {
-  api: ApiHandler;
-  systemPrompt: string;
-  workingDir: string;
-}
-
-export class StandaloneAgent {
-  private api: ApiHandler;
-  private systemPrompt: string;
-  private workingDir: string;
-  private conversationHistory: Message[] = [];
-
-  constructor(config: AgentConfig) {
-    this.api = config.api;
-    this.systemPrompt = config.systemPrompt;
-    this.workingDir = config.workingDir;
-  }
-
-  async runTask(task: string): Promise<void> {
-    this.conversationHistory.push({
-      role: "user",
-      content: [{ type: "text", text: `<task>\n${task}\n</task>` }]
-    });
-
-    let isTaskComplete = false;
-    const encoder = new TextEncoder();
-    
-    while (!isTaskComplete) {
-      const stream = this.api.createMessage(this.systemPrompt, this.conversationHistory);
-      let assistantMessage = "";
-      
-      console.log(blue("Thinking..."));
-      for await (const chunk of stream) {
-        if (chunk.type === "text") {
-          assistantMessage += chunk.text;
-          await Deno.stdout.write(encoder.encode(chunk.text));
-        }
-      }
-
-      this.conversationHistory.push({
-        role: "assistant",
-        content: [{ type: "text", text: assistantMessage }]
-      });
-
-      const toolResults = await this.executeTools(assistantMessage);
-      
-      if (toolResults.length > 0) {
-        this.conversationHistory.push({
-          role: "user",
-          content: toolResults.map(result => ({
-            type: "text",
-            text: `[${result.tool}] Result:${result.output}`
-          })) as TextBlock[]
-        });
-      } else {
-        if (assistantMessage.includes("<attempt_completion>")) {
-          isTaskComplete = true;
-        } else {
-          this.conversationHistory.push({
-            role: "user",
-            content: [{
-              type: "text",
-              text: "You must either use available tools to accomplish the task or call attempt_completion when the task is complete."
-            }]
-          });
-        }
-      }
-    }
-  }
-
-  private async executeTools(message: string): Promise<ToolResult[]> {
-    const results: ToolResult[] = [];
-    const toolRegex = /<(\w+)>\s*([\s\S]*?)\s*<\/\1>/g;
-    let match;
-    
-    while ((match = toolRegex.exec(message)) !== null) {
-      const [_, toolName, paramsXml] = match;
-      const params: Record<string, string> = {};
-      const paramRegex = /<(\w+)>\s*([\s\S]*?)\s*<\/\1>/g;
-      let paramMatch;
-      
-      while ((paramMatch = paramRegex.exec(paramsXml)) !== null) {
-        const [__, paramName, paramValue] = paramMatch;
-        params[paramName] = paramValue.trim();
-      }
-
-      let output: string;
-      try {
-        console.log(yellow(`\nExecuting: ${this.getToolDescription(toolName, params)}`));
-        
-        switch (toolName) {
-          case "execute_command":
-            output = await executeCommand(params.command);
-            break;
-          case "read_file":
-            output = await readFile(this.workingDir, params.path);
-            break;
-          case "write_to_file":
-            output = await writeFile(this.workingDir, params.path, params.content);
-            break;
-          case "search_files":
-            output = await searchFiles(this.workingDir, params.path, params.regex, params.file_pattern);
-            break;
-          case "list_files":
-            output = await listFiles(this.workingDir, params.path, params.recursive === "true");
-            break;
-          case "list_code_definition_names":
-            output = await listCodeDefinitions(this.workingDir, params.path);
-            break;
-          case "attempt_completion":
-            return results;
-          default:
-            console.warn(red(`Unknown tool: ${toolName}`));
-            continue;
-        }
-
-        results.push({
-          tool: toolName,
-          params,
-          output: output || "(No output)"
-        });
-
-        break;
-      } catch (error) {
-        const errorMessage = `Error executing ${toolName}: ${error instanceof Error ? error.message : String(error)}`;
-        console.error(red(errorMessage));
-        results.push({
-          tool: toolName,
-          params,
-          output: errorMessage
-        });
-        break;
-      }
-    }
-
-    return results;
-  }
-
-  private getToolDescription(toolName: string, params: Record<string, string>): string {
-    switch (toolName) {
-      case "execute_command":
-        return `Running command: ${params.command}`;
-      case "read_file":
-        return `Reading file: ${params.path}`;
-      case "write_to_file":
-        return `Writing to file: ${params.path}`;
-      case "search_files":
-        return `Searching for "${params.regex}" in ${params.path}`;
-      case "list_files":
-        return `Listing files in ${params.path}`;
-      case "list_code_definition_names":
-        return `Analyzing code in ${params.path}`;
-      case "attempt_completion":
-        return "Completing task";
-      default:
-        return toolName;
-    }
-  }
-}

+ 0 - 120
cli/core/prompts.ts

@@ -1,120 +0,0 @@
-import { join } from "https://deno.land/[email protected]/path/mod.ts";
-
-export const SYSTEM_PROMPT = async (cwd: string): Promise<string> => {
-    let rulesContent = "";
-    
-    // Load and combine rules from configuration files
-    const ruleFiles = ['.clinerules', '.cursorrules'];
-    for (const file of ruleFiles) {
-        const rulePath = join(cwd, file);
-        try {
-            const stat = await Deno.stat(rulePath);
-            if (stat.isFile) {
-                const content = await Deno.readTextFile(rulePath);
-                if (content.trim()) {
-                    rulesContent += `\n# Rules from ${file}:\n${content.trim()}\n\n`;
-                }
-            }
-        } catch (err) {
-            // Only ignore ENOENT (file not found) errors
-            if (!(err instanceof Deno.errors.NotFound)) {
-                throw err;
-            }
-        }
-    }
-
-    return `You are Cline, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.
-
-====
-
-TOOL USE
-
-You have access to tools that are executed upon approval. Use one tool per message and wait for the result before proceeding. Each tool must be used with proper XML-style formatting:
-
-<tool_name>
-<parameter1_name>value1</parameter1_name>
-<parameter2_name>value2</parameter2_name>
-</tool_name>
-
-# Available Tools
-
-## execute_command
-Description: Execute a CLI command on the system. Commands run in the current working directory: ${cwd}
-Parameters:
-- command: (required) The command to execute. Must be valid for the current OS.
-Usage:
-<execute_command>
-<command>command to run</command>
-</execute_command>
-
-## read_file
-Description: Read contents of a file. Supports text files and automatically extracts content from PDFs/DOCXs.
-Parameters:
-- path: (required) Path to file (relative to ${cwd})
-Usage:
-<read_file>
-<path>path to file</path>
-</read_file>
-
-## write_to_file
-Description: Write content to a file. Creates directories as needed. Will overwrite existing files.
-Parameters:
-- path: (required) Path to write to (relative to ${cwd})
-- content: (required) Complete file content. Must include ALL parts, even unchanged sections.
-Usage:
-<write_to_file>
-<path>path to file</path>
-<content>complete file content</content>
-</write_to_file>
-
-## search_files
-Description: Search files using regex patterns. Shows matches with surrounding context.
-Parameters:
-- path: (required) Directory to search (relative to ${cwd})
-- regex: (required) Rust regex pattern to search for
-- file_pattern: (optional) Glob pattern to filter files (e.g. "*.ts")
-Usage:
-<search_files>
-<path>directory to search</path>
-<regex>pattern to search</regex>
-<file_pattern>optional file pattern</file_pattern>
-</search_files>
-
-## list_code_definition_names
-Description: List code definitions (classes, functions, etc.) in source files.
-Parameters:
-- path: (required) Directory to analyze (relative to ${cwd})
-Usage:
-<list_code_definition_names>
-<path>directory to analyze</path>
-</list_code_definition_names>
-
-## attempt_completion
-Description: Signal task completion and present results.
-Parameters:
-- result: (required) Description of completed work
-- command: (optional) Command to demonstrate result
-Usage:
-<attempt_completion>
-<result>description of completed work</result>
-<command>optional demo command</command>
-</attempt_completion>
-
-# Guidelines
-
-1. Use one tool at a time and wait for results
-2. Provide complete file content when using write_to_file
-3. Be direct and technical in responses
-4. Present final results using attempt_completion
-5. Do not make assumptions about command success
-6. Do not make up commands that don't exist
-
-# Rules
-
-- Current working directory is: ${cwd}
-- Cannot cd to different directories
-- Must wait for confirmation after each tool use
-- Must provide complete file content when writing files
-- Be direct and technical, not conversational
-- Do not end messages with questions${rulesContent}`;
-};

+ 0 - 40
cli/deno.d.ts

@@ -1,40 +0,0 @@
-declare namespace Deno {
-  export const args: string[];
-  export function exit(code?: number): never;
-  export const env: {
-    get(key: string): string | undefined;
-  };
-  export function cwd(): string;
-  export function readTextFile(path: string): Promise<string>;
-  export function writeTextFile(path: string, data: string): Promise<void>;
-  export function mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
-  export function readDir(path: string): AsyncIterable<{
-    name: string;
-    isFile: boolean;
-    isDirectory: boolean;
-  }>;
-  export function stat(path: string): Promise<{
-    isFile: boolean;
-    isDirectory: boolean;
-  }>;
-  export class Command {
-    constructor(cmd: string, options?: {
-      args?: string[];
-      stdout?: "piped";
-      stderr?: "piped";
-    });
-    output(): Promise<{
-      stdout: Uint8Array;
-      stderr: Uint8Array;
-    }>;
-  }
-  export const permissions: {
-    query(desc: { name: string; path?: string }): Promise<{ state: "granted" | "denied" }>;
-  };
-  export const errors: {
-    PermissionDenied: typeof Error;
-  };
-  export const stdout: {
-    write(data: Uint8Array): Promise<number>;
-  };
-}

+ 0 - 13
cli/deno.jsonc

@@ -1,13 +0,0 @@
-{
-  "compilerOptions": {
-    "allowJs": true,
-    "strict": true,
-    "lib": ["deno.ns", "dom"]
-  },
-  "tasks": {
-    "start": "deno run --allow-read=. mod.ts",
-    "dev": "deno run --allow-read=. mod.ts",
-    "install": "deno install --allow-read --allow-write --allow-net --allow-env --allow-run --global --name cline mod.ts",
-    "check": "deno check mod.ts"
-  }
-}

+ 0 - 87
cli/deno.lock

@@ -1,87 +0,0 @@
-{
-  "version": "4",
-  "remote": {
-    "https://deno.land/[email protected]/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5",
-    "https://deno.land/[email protected]/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9",
-    "https://deno.land/[email protected]/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
-    "https://deno.land/[email protected]/flags/mod.ts": "9f13f3a49c54618277ac49195af934f1c7d235731bcf80fd33b8b234e6839ce9",
-    "https://deno.land/[email protected]/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a",
-    "https://deno.land/[email protected]/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8",
-    "https://deno.land/[email protected]/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2",
-    "https://deno.land/[email protected]/path/_common/common.ts": "ef73c2860694775fe8ffcbcdd387f9f97c7a656febf0daa8c73b56f4d8a7bd4c",
-    "https://deno.land/[email protected]/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c",
-    "https://deno.land/[email protected]/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
-    "https://deno.land/[email protected]/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b",
-    "https://deno.land/[email protected]/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf",
-    "https://deno.land/[email protected]/path/_common/glob_to_reg_exp.ts": "6cac16d5c2dc23af7d66348a7ce430e5de4e70b0eede074bdbcf4903f4374d8d",
-    "https://deno.land/[email protected]/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
-    "https://deno.land/[email protected]/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3",
-    "https://deno.land/[email protected]/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607",
-    "https://deno.land/[email protected]/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a",
-    "https://deno.land/[email protected]/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883",
-    "https://deno.land/[email protected]/path/_interface.ts": "a1419fcf45c0ceb8acdccc94394e3e94f99e18cfd32d509aab514c8841799600",
-    "https://deno.land/[email protected]/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15",
-    "https://deno.land/[email protected]/path/basename.ts": "5d341aadb7ada266e2280561692c165771d071c98746fcb66da928870cd47668",
-    "https://deno.land/[email protected]/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643",
-    "https://deno.land/[email protected]/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36",
-    "https://deno.land/[email protected]/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c",
-    "https://deno.land/[email protected]/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441",
-    "https://deno.land/[email protected]/path/format.ts": "42a2f3201343df77061207e6aaf78c95bafce7f711dcb7fe1e5840311c505778",
-    "https://deno.land/[email protected]/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069",
-    "https://deno.land/[email protected]/path/glob_to_regexp.ts": "7f30f0a21439cadfdae1be1bf370880b415e676097fda584a63ce319053b5972",
-    "https://deno.land/[email protected]/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7",
-    "https://deno.land/[email protected]/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141",
-    "https://deno.land/[email protected]/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a",
-    "https://deno.land/[email protected]/path/join_globs.ts": "5b3bf248b93247194f94fa6947b612ab9d3abd571ca8386cf7789038545e54a0",
-    "https://deno.land/[email protected]/path/mod.ts": "2821a1bb3a4148a0ffe79c92aa41aa9319fef73c6d6f5178f52b2c720d3eb02d",
-    "https://deno.land/[email protected]/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352",
-    "https://deno.land/[email protected]/path/normalize_glob.ts": "cc89a77a7d3b1d01053b9dcd59462b75482b11e9068ae6c754b5cf5d794b374f",
-    "https://deno.land/[email protected]/path/parse.ts": "65e8e285f1a63b714e19ef24b68f56e76934c3df0b6e65fd440d3991f4f8aefb",
-    "https://deno.land/[email protected]/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d",
-    "https://deno.land/[email protected]/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0",
-    "https://deno.land/[email protected]/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
-    "https://deno.land/[email protected]/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1",
-    "https://deno.land/[email protected]/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00",
-    "https://deno.land/[email protected]/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2",
-    "https://deno.land/[email protected]/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1",
-    "https://deno.land/[email protected]/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40",
-    "https://deno.land/[email protected]/path/posix/glob_to_regexp.ts": "76f012fcdb22c04b633f536c0b9644d100861bea36e9da56a94b9c589a742e8f",
-    "https://deno.land/[email protected]/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede",
-    "https://deno.land/[email protected]/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
-    "https://deno.land/[email protected]/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63",
-    "https://deno.land/[email protected]/path/posix/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25",
-    "https://deno.land/[email protected]/path/posix/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
-    "https://deno.land/[email protected]/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91",
-    "https://deno.land/[email protected]/path/posix/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6",
-    "https://deno.land/[email protected]/path/posix/parse.ts": "0b1fc4cb890dbb699ec1d2c232d274843b4a7142e1ad976b69fe51c954eb6080",
-    "https://deno.land/[email protected]/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c",
-    "https://deno.land/[email protected]/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf",
-    "https://deno.land/[email protected]/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf",
-    "https://deno.land/[email protected]/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0",
-    "https://deno.land/[email protected]/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add",
-    "https://deno.land/[email protected]/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d",
-    "https://deno.land/[email protected]/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b",
-    "https://deno.land/[email protected]/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40",
-    "https://deno.land/[email protected]/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808",
-    "https://deno.land/[email protected]/path/windows/basename.ts": "e2dbf31d1d6385bfab1ce38c333aa290b6d7ae9e0ecb8234a654e583cf22f8fe",
-    "https://deno.land/[email protected]/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
-    "https://deno.land/[email protected]/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5",
-    "https://deno.land/[email protected]/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9",
-    "https://deno.land/[email protected]/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef",
-    "https://deno.land/[email protected]/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6",
-    "https://deno.land/[email protected]/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01",
-    "https://deno.land/[email protected]/path/windows/glob_to_regexp.ts": "e45f1f89bf3fc36f94ab7b3b9d0026729829fabc486c77f414caebef3b7304f8",
-    "https://deno.land/[email protected]/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a",
-    "https://deno.land/[email protected]/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
-    "https://deno.land/[email protected]/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
-    "https://deno.land/[email protected]/path/windows/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25",
-    "https://deno.land/[email protected]/path/windows/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
-    "https://deno.land/[email protected]/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780",
-    "https://deno.land/[email protected]/path/windows/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6",
-    "https://deno.land/[email protected]/path/windows/parse.ts": "dbdfe2bc6db482d755b5f63f7207cd019240fcac02ad2efa582adf67ff10553a",
-    "https://deno.land/[email protected]/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7",
-    "https://deno.land/[email protected]/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972",
-    "https://deno.land/[email protected]/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e",
-    "https://deno.land/[email protected]/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c"
-  }
-}

+ 0 - 21
cli/deps.ts

@@ -1,21 +0,0 @@
-// Re-export standard library dependencies
-export { parse } from "https://deno.land/[email protected]/flags/mod.ts";
-export {
-  blue,
-  red,
-  gray,
-  yellow,
-  bold,
-} from "https://deno.land/[email protected]/fmt/colors.ts";
-export {
-  join,
-  dirname,
-} from "https://deno.land/[email protected]/path/mod.ts";
-
-// Export types
-export type {
-  ApiHandler,
-  AgentConfig,
-  OperationMode,
-  ToolResponse,
-} from "./types.d.ts";

+ 0 - 123
cli/mod.ts

@@ -1,123 +0,0 @@
-#!/usr/bin/env -S deno run --allow-read=. --allow-write=. --allow-run --allow-net --allow-env
-
-import { parse } from "./deps.ts";
-import { blue, red, gray, yellow, bold } from "./deps.ts";
-import { buildApiHandler } from "./api/mod.ts";
-import { StandaloneAgent } from "./core/StandaloneAgent.ts";
-import { SYSTEM_PROMPT } from "./core/prompts.ts";
-import type { ApiHandler, AgentConfig } from "./types.d.ts";
-
-// Parse command line arguments
-const args = parse(Deno.args, {
-  string: ["model", "key"],
-  boolean: ["help"],
-  alias: {
-    m: "model",
-    k: "key",
-    h: "help"
-  },
-  default: {
-    model: "anthropic/claude-3.5-sonnet"
-  },
-});
-
-if (args.help || Deno.args.length === 0) {
-  console.log(blue("\nCline - AI Coding Assistant\n"));
-  
-  console.log("Usage:");
-  console.log("  cline <task> [options]\n");
-
-  console.log("Required Permissions:");
-  console.log("  --allow-read=.     Read files in working directory");
-  console.log("  --allow-write=.    Write files in working directory");
-  console.log("  --allow-run        Execute commands (with interactive prompts)\n");
-  console.log("  --allow-net        Make API calls");
-  console.log("  --allow-env        Access environment variables\n");
-
-  console.log("Pre-approved Commands:");
-  console.log("  npm   - Package management (install, run, test, build)");
-  console.log("  git   - Version control (status, add, commit, push, pull, clone)");
-  console.log("  deno  - Deno runtime (run, test, fmt, lint, check)");
-  console.log("  ls    - List directory contents");
-  console.log("  cat   - Show file contents");
-  console.log("  echo  - Print text");
-  console.log("  find  - Search for files");
-  console.log("\nOther commands will prompt for confirmation before execution.\n");
-
-  console.log("Options:");
-  console.log("  -m, --model <model>  LLM model to use (default: \"anthropic/claude-3.5-sonnet\")");
-  console.log("  -k, --key <key>      OpenRouter API key (or set OPENROUTER_API_KEY env var)");
-  console.log("  -h, --help           Display help for command\n");
-  
-  console.log("Examples:");
-  console.log(gray("  # Run pre-approved command"));
-  console.log("  cline \"Run npm install\"\n");
-  
-  console.log(gray("  # Run command that requires confirmation"));
-  console.log("  cline \"Run yarn install\"\n");
-  
-  Deno.exit(0);
-}
-
-// Verify required permissions
-const requiredPermissions = [
-  { name: "read", path: "." },
-  { name: "write", path: "." },
-  { name: "run" },
-  { name: "net" },
-  { name: "env" }
-] as const;
-
-for (const permission of requiredPermissions) {
-  const status = await Deno.permissions.query(permission);
-  if (status.state !== "granted") {
-    console.error(red(`Error: Missing required permission`));
-    console.error(yellow(`Hint: Run with the following permissions:`));
-    console.error(yellow(`  deno run ${requiredPermissions.map(p => 
-      "path" in p ? `--allow-${p.name}=${p.path}` : `--allow-${p.name}`
-    ).join(" ")} cli/mod.ts ...\n`));
-    Deno.exit(1);
-  }
-}
-
-const task = args._[0] as string;
-const apiKey = args.key || Deno.env.get("OPENROUTER_API_KEY");
-
-if (!apiKey) {
-  console.error(red("Error: OpenRouter API key is required. Set it with --key or OPENROUTER_API_KEY env var"));
-  console.error(yellow("Get your API key from: https://openrouter.ai/keys"));
-  Deno.exit(1);
-}
-
-try {
-  const workingDir = Deno.cwd();
-
-  // Initialize API handler
-  const apiHandler = buildApiHandler({
-    model: args.model,
-    apiKey
-  });
-
-  // Create agent instance
-  const agent = new StandaloneAgent({
-    api: apiHandler,
-    systemPrompt: await SYSTEM_PROMPT(workingDir),
-    workingDir
-  });
-
-  // Run the task
-  console.log(blue(`\nStarting task: ${bold(task)}`));
-  console.log(gray(`Working directory: ${workingDir}`));
-  console.log(gray(`Model: ${args.model}`));
-  console.log(gray("---\n"));
-
-  await agent.runTask(task);
-
-} catch (error) {
-  if (error instanceof Error) {
-    console.error(red(`\nError: ${error.message}`));
-  } else {
-    console.error(red("\nAn unknown error occurred"));
-  }
-  Deno.exit(1);
-}

+ 0 - 225
cli/tools/mod.ts

@@ -1,225 +0,0 @@
-/// <reference lib="deno.ns" />
-import { join, dirname } from "https://deno.land/[email protected]/path/mod.ts";
-import { red, yellow, green } from "https://deno.land/[email protected]/fmt/colors.ts";
-import type { ToolResponse } from "../types.d.ts";
-
-interface CommandConfig {
-  desc: string;
-  args: readonly string[];
-}
-
-// Define allowed commands and their descriptions
-const ALLOWED_COMMANDS: Record<string, CommandConfig> = {
-  'npm': {
-    desc: "Node package manager",
-    args: ["install", "run", "test", "build"]
-  },
-  'git': {
-    desc: "Version control",
-    args: ["status", "add", "commit", "push", "pull", "clone", "checkout", "branch"]
-  },
-  'deno': {
-    desc: "Deno runtime",
-    args: ["run", "test", "fmt", "lint", "check", "compile", "bundle"]
-  },
-  'ls': {
-    desc: "List directory contents",
-    args: ["-l", "-a", "-la", "-lh"]
-  },
-  'cat': {
-    desc: "Show file contents",
-    args: []
-  },
-  'echo': {
-    desc: "Print text",
-    args: []
-  }
-};
-
-// Track commands that have been allowed for this session
-const alwaysAllowedCommands = new Set<string>();
-
-function isCommandAllowed(command: string): boolean {
-  // Split command into parts
-  const parts = command.trim().split(/\s+/);
-  if (parts.length === 0) return false;
-
-  // Get base command
-  const baseCmd = parts[0];
-  if (!(baseCmd in ALLOWED_COMMANDS)) return false;
-
-  // If command has arguments, check if they're allowed
-  if (parts.length > 1 && ALLOWED_COMMANDS[baseCmd].args.length > 0) {
-    const arg = parts[1];
-    return ALLOWED_COMMANDS[baseCmd].args.includes(arg);
-  }
-
-  return true;
-}
-
-async function promptForCommand(command: string): Promise<boolean> {
-  // Check if command has been previously allowed
-  if (alwaysAllowedCommands.has(command)) {
-    console.log(yellow("\nWarning: Running previously allowed command:"), red(command));
-    return true;
-  }
-
-  console.log(yellow("\nWarning: Command not in allowlist"));
-  console.log("Command:", red(command));
-  console.log("\nAllowed commands:");
-  Object.entries(ALLOWED_COMMANDS).forEach(([cmd, { desc, args }]) => {
-    console.log(`  ${green(cmd)}: ${desc}`);
-    if (args.length) {
-      console.log(`    Arguments: ${args.join(", ")}`);
-    }
-  });
-
-  const answer = prompt("\nDo you want to run this command? (y/n/always) ");
-  if (answer?.toLowerCase() === 'always') {
-    alwaysAllowedCommands.add(command);
-    return true;
-  }
-  return answer?.toLowerCase() === 'y';
-}
-
-export async function executeCommand(command: string): Promise<ToolResponse> {
-  try {
-    // Check if command is allowed
-    if (!isCommandAllowed(command)) {
-      // Prompt user for confirmation
-      const shouldRun = await promptForCommand(command);
-      if (!shouldRun) {
-        return "Command execution cancelled by user";
-      }
-      console.log(yellow("\nProceeding with command execution..."));
-    }
-
-    const process = new Deno.Command("sh", {
-      args: ["-c", command],
-      stdout: "piped",
-      stderr: "piped",
-    });
-    const { stdout, stderr } = await process.output();
-    const decoder = new TextDecoder();
-    return decoder.decode(stdout) + (stderr.length ? `\nStderr:\n${decoder.decode(stderr)}` : "");
-  } catch (error) {
-    return `Error executing command: ${error instanceof Error ? error.message : String(error)}`;
-  }
-}
-
-export async function readFile(workingDir: string, relativePath: string): Promise<ToolResponse> {
-  try {
-    const fullPath = join(workingDir, relativePath);
-    const content = await Deno.readTextFile(fullPath);
-    return content;
-  } catch (error) {
-    return `Error reading file: ${error instanceof Error ? error.message : String(error)}`;
-  }
-}
-
-export async function writeFile(workingDir: string, relativePath: string, content: string): Promise<ToolResponse> {
-  try {
-    const fullPath = join(workingDir, relativePath);
-    await Deno.mkdir(dirname(fullPath), { recursive: true });
-    await Deno.writeTextFile(fullPath, content);
-    return `Successfully wrote to ${relativePath}`;
-  } catch (error) {
-    return `Error writing file: ${error instanceof Error ? error.message : String(error)}`;
-  }
-}
-
-export async function searchFiles(
-  workingDir: string, 
-  searchPath: string, 
-  regex: string, 
-  filePattern?: string
-): Promise<ToolResponse> {
-  try {
-    const fullPath = join(workingDir, searchPath);
-    const results: string[] = [];
-    
-    const regexObj = new RegExp(regex, "g");
-    const patternObj = filePattern ? new RegExp(filePattern) : null;
-    
-    for await (const entry of Deno.readDir(fullPath)) {
-      if (entry.isFile && (!patternObj || patternObj.test(entry.name))) {
-        const filePath = join(fullPath, entry.name);
-        const content = await Deno.readTextFile(filePath);
-        const matches = content.match(regexObj);
-        if (matches) {
-          results.push(`File: ${entry.name}\nMatches:\n${matches.join("\n")}\n`);
-        }
-      }
-    }
-    
-    return results.join("\n") || "No matches found";
-  } catch (error) {
-    return `Error searching files: ${error instanceof Error ? error.message : String(error)}`;
-  }
-}
-
-export async function listFiles(workingDir: string, relativePath: string, recursive: boolean): Promise<ToolResponse> {
-  try {
-    const fullPath = join(workingDir, relativePath);
-    const files: string[] = [];
-
-    async function* walkDir(dir: string): AsyncGenerator<string> {
-      for await (const entry of Deno.readDir(dir)) {
-        const entryPath = join(dir, entry.name);
-        if (entry.isFile) {
-          yield entryPath.replace(fullPath + "/", "");
-        } else if (recursive && entry.isDirectory) {
-          yield* walkDir(entryPath);
-        }
-      }
-    }
-
-    for await (const file of walkDir(fullPath)) {
-      files.push(file);
-    }
-
-    return files.join("\n") || "No files found";
-  } catch (error) {
-    return `Error listing files: ${error instanceof Error ? error.message : String(error)}`;
-  }
-}
-
-export async function listCodeDefinitions(workingDir: string, relativePath: string): Promise<ToolResponse> {
-  try {
-    const fullPath = join(workingDir, relativePath);
-    const content = await Deno.readTextFile(fullPath);
-    
-    // Basic regex patterns for common code definitions
-    const patterns = {
-      function: /(?:function|const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?:=\s*(?:function|\([^)]*\)\s*=>)|[({])/g,
-      class: /class\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g,
-      method: /(?:async\s+)?([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\([^)]*\)\s*{/g,
-    };
-    
-    const definitions: Record<string, string[]> = {
-      functions: [],
-      classes: [],
-      methods: [],
-    };
-    
-    let match;
-    
-    while ((match = patterns.function.exec(content)) !== null) {
-      definitions.functions.push(match[1]);
-    }
-    
-    while ((match = patterns.class.exec(content)) !== null) {
-      definitions.classes.push(match[1]);
-    }
-    
-    while ((match = patterns.method.exec(content)) !== null) {
-      definitions.methods.push(match[1]);
-    }
-    
-    return Object.entries(definitions)
-      .map(([type, names]) => `${type}:\n${names.join("\n")}`)
-      .join("\n\n");
-  } catch (error) {
-    return `Error listing code definitions: ${error instanceof Error ? error.message : String(error)}`;
-  }
-}

+ 0 - 43
cli/types.d.ts

@@ -1,43 +0,0 @@
-export interface ApiHandler {
-  sendMessage(message: string): Promise<string>;
-  createMessage(systemPrompt: string, history: Message[]): AsyncIterable<MessageChunk>;
-}
-
-export interface AgentConfig {
-  api: ApiHandler;
-  systemPrompt: string;
-  workingDir: string;
-  debug?: boolean;
-}
-
-export type ToolResponse = string;
-
-export interface Message {
-  role: "user" | "assistant";
-  content: TextBlock[];
-}
-
-export interface TextBlock {
-  type: "text";
-  text: string;
-}
-
-export interface ToolResult {
-  tool: string;
-  params: Record<string, string>;
-  output: string;
-}
-
-export interface MessageChunk {
-  type: "text";
-  text: string;
-}
-
-export interface UsageBlock {
-  type: "usage";
-  usage: {
-    prompt_tokens: number;
-    completion_tokens: number;
-    total_tokens: number;
-  };
-}