@polka-codes/cli 0.4.4 → 0.4.6

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 (3) hide show
  1. package/README.md +3 -4
  2. package/dist/index.js +419 -44
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -77,12 +77,11 @@ rules: |
77
77
 
78
78
  ### AI Configuration
79
79
 
80
- The default API provider is Ollama with 'maryasov/qwen2.5-coder-cline:7b' model.
81
-
82
- Supported providers (in recommended order):
80
+ Supported providers
83
81
  1. DeepSeek / `deepseek` (recommended)
84
82
  2. Anthropic / `anthropic` (Sonnet 3.5 recommended)
85
- 3. Ollama / `ollama`
83
+ 3. OpenRouter / `openrouter`
84
+ 4. Ollama / `ollama`
86
85
 
87
86
  Configure the AI service by creating a `.env` file in your project root:
88
87
 
package/dist/index.js CHANGED
@@ -24629,7 +24629,7 @@ var {
24629
24629
  Help
24630
24630
  } = import__.default;
24631
24631
  // package.json
24632
- var version = "0.4.4";
24632
+ var version = "0.4.6";
24633
24633
 
24634
24634
  // ../../node_modules/@anthropic-ai/sdk/version.mjs
24635
24635
  var VERSION = "0.36.2";
@@ -32890,17 +32890,169 @@ class OllamaService extends AiServiceBase {
32890
32890
  }
32891
32891
  }
32892
32892
 
32893
+ // ../core/src/AiService/OpenRouterService.ts
32894
+ class OpenRouterService extends AiServiceBase {
32895
+ #client;
32896
+ #apiKey;
32897
+ model;
32898
+ constructor(options) {
32899
+ super();
32900
+ if (!options.model) {
32901
+ throw new Error("OpenRouter requires a model");
32902
+ }
32903
+ if (!options.apiKey) {
32904
+ throw new Error("OpenRouter requires an API key");
32905
+ }
32906
+ this.#apiKey = options.apiKey;
32907
+ this.#client = new openai_default({
32908
+ baseURL: "https://openrouter.ai/api/v1",
32909
+ apiKey: options.apiKey,
32910
+ defaultHeaders: {
32911
+ "HTTP-Referer": "https://polka.codes",
32912
+ "X-Title": "Polka Codes"
32913
+ }
32914
+ });
32915
+ this.model = {
32916
+ id: options.model,
32917
+ info: {}
32918
+ };
32919
+ }
32920
+ async* send(systemPrompt, messages) {
32921
+ const openAiMessages = [
32922
+ { role: "system", content: systemPrompt },
32923
+ ...convertToOpenAiMessages(messages)
32924
+ ];
32925
+ switch (this.model.id) {
32926
+ case "anthropic/claude-3.5-sonnet":
32927
+ case "anthropic/claude-3.5-sonnet:beta":
32928
+ case "anthropic/claude-3.5-sonnet-20240620":
32929
+ case "anthropic/claude-3.5-sonnet-20240620:beta":
32930
+ case "anthropic/claude-3-5-haiku":
32931
+ case "anthropic/claude-3-5-haiku:beta":
32932
+ case "anthropic/claude-3-5-haiku-20241022":
32933
+ case "anthropic/claude-3-5-haiku-20241022:beta":
32934
+ case "anthropic/claude-3-haiku":
32935
+ case "anthropic/claude-3-haiku:beta":
32936
+ case "anthropic/claude-3-opus":
32937
+ case "anthropic/claude-3-opus:beta": {
32938
+ openAiMessages[0] = {
32939
+ role: "system",
32940
+ content: [
32941
+ {
32942
+ type: "text",
32943
+ text: systemPrompt,
32944
+ cache_control: { type: "ephemeral" }
32945
+ }
32946
+ ]
32947
+ };
32948
+ const lastTwoUserMessages = openAiMessages.filter((msg) => msg.role === "user").slice(-2);
32949
+ for (const msg of lastTwoUserMessages) {
32950
+ if (typeof msg.content === "string") {
32951
+ msg.content = [{ type: "text", text: msg.content }];
32952
+ }
32953
+ if (Array.isArray(msg.content)) {
32954
+ let lastTextPart = msg.content.filter((part) => part.type === "text").pop();
32955
+ if (!lastTextPart) {
32956
+ lastTextPart = { type: "text", text: "..." };
32957
+ msg.content.push(lastTextPart);
32958
+ }
32959
+ lastTextPart.cache_control = { type: "ephemeral" };
32960
+ }
32961
+ }
32962
+ break;
32963
+ }
32964
+ default:
32965
+ break;
32966
+ }
32967
+ let maxTokens;
32968
+ switch (this.model.id) {
32969
+ case "anthropic/claude-3.5-sonnet":
32970
+ case "anthropic/claude-3.5-sonnet:beta":
32971
+ case "anthropic/claude-3.5-sonnet-20240620":
32972
+ case "anthropic/claude-3.5-sonnet-20240620:beta":
32973
+ case "anthropic/claude-3-5-haiku":
32974
+ case "anthropic/claude-3-5-haiku:beta":
32975
+ case "anthropic/claude-3-5-haiku-20241022":
32976
+ case "anthropic/claude-3-5-haiku-20241022:beta":
32977
+ maxTokens = 8192;
32978
+ break;
32979
+ }
32980
+ let shouldApplyMiddleOutTransform = !this.model.info.supportsPromptCache;
32981
+ if (this.model.id === "deepseek/deepseek-chat") {
32982
+ shouldApplyMiddleOutTransform = true;
32983
+ }
32984
+ const stream = await this.#client.chat.completions.create({
32985
+ model: this.model.id,
32986
+ max_completion_tokens: maxTokens,
32987
+ messages: openAiMessages,
32988
+ temperature: 0,
32989
+ stream: true,
32990
+ transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : undefined,
32991
+ include_reasoning: true
32992
+ });
32993
+ let genId;
32994
+ for await (const chunk of stream) {
32995
+ if ("error" in chunk) {
32996
+ const error = chunk.error;
32997
+ console.error(`OpenRouter API Error: ${error?.code} - ${error?.message}`);
32998
+ throw new Error(`OpenRouter API Error ${error?.code}: ${error?.message}`);
32999
+ }
33000
+ if (!genId && chunk.id) {
33001
+ genId = chunk.id;
33002
+ }
33003
+ const delta = chunk.choices[0]?.delta;
33004
+ if (delta?.reasoning) {
33005
+ yield {
33006
+ type: "reasoning",
33007
+ text: delta.reasoning
33008
+ };
33009
+ }
33010
+ if (delta?.content) {
33011
+ yield {
33012
+ type: "text",
33013
+ text: delta.content
33014
+ };
33015
+ }
33016
+ }
33017
+ await new Promise((resolve) => setTimeout(resolve, 1000));
33018
+ const controller = new AbortController;
33019
+ const timeout = setTimeout(() => controller.abort(), 5000);
33020
+ try {
33021
+ const response = await fetch(`https://openrouter.ai/api/v1/generation?id=${genId}`, {
33022
+ headers: {
33023
+ Authorization: `Bearer ${this.#apiKey}`
33024
+ },
33025
+ signal: controller.signal
33026
+ });
33027
+ const responseBody = await response.json();
33028
+ const generation = responseBody.data;
33029
+ yield {
33030
+ type: "usage",
33031
+ inputTokens: generation?.native_tokens_prompt || 0,
33032
+ outputTokens: generation?.native_tokens_completion || 0,
33033
+ totalCost: generation?.total_cost || 0
33034
+ };
33035
+ } catch (error) {
33036
+ console.error("Error fetching OpenRouter generation details:", error);
33037
+ } finally {
33038
+ clearTimeout(timeout);
33039
+ }
33040
+ }
33041
+ }
33042
+
32893
33043
  // ../core/src/AiService/index.ts
32894
33044
  var AiServiceProvider;
32895
33045
  ((AiServiceProvider2) => {
32896
33046
  AiServiceProvider2["Anthropic"] = "anthropic";
32897
33047
  AiServiceProvider2["Ollama"] = "ollama";
32898
33048
  AiServiceProvider2["DeepSeek"] = "deepseek";
33049
+ AiServiceProvider2["OpenRouter"] = "openrouter";
32899
33050
  })(AiServiceProvider ||= {});
32900
33051
  var defaultModels = {
32901
33052
  ["anthropic" /* Anthropic */]: "claude-3-5-sonnet-20241022",
32902
33053
  ["ollama" /* Ollama */]: "maryasov/qwen2.5-coder-cline:7b",
32903
- ["deepseek" /* DeepSeek */]: "deepseek-chat"
33054
+ ["deepseek" /* DeepSeek */]: "deepseek-chat",
33055
+ ["openrouter" /* OpenRouter */]: "anthropic/claude-3.5-sonnet"
32904
33056
  };
32905
33057
  var createService = (provider, options) => {
32906
33058
  switch (provider) {
@@ -32910,6 +33062,8 @@ var createService = (provider, options) => {
32910
33062
  return new OllamaService(options);
32911
33063
  case "deepseek" /* DeepSeek */:
32912
33064
  return new DeepSeekService(options);
33065
+ case "openrouter" /* OpenRouter */:
33066
+ return new OpenRouterService(options);
32913
33067
  }
32914
33068
  };
32915
33069
  // ../core/src/tool.ts
@@ -33086,12 +33240,8 @@ var capabilities = (toolNamePrefix) => `
33086
33240
 
33087
33241
  CAPABILITIES
33088
33242
 
33089
- - You have access to a range of tools to aid you in your work. These tools help you effectively accomplish a wide range of tasks, such as writing code, making edits or improvements to existing files, understanding the current state of a project, performing system operations, and much more.
33090
- - When the user initially gives you a task, a recursive list of all filepaths in the current working directory will be included in environment_details. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further.
33091
- - You can use ${toolNamePrefix}search_files to perform regex searches across files in a specified directory, outputting context-rich results that include surrounding lines. This is particularly useful for understanding code patterns, finding specific implementations, or identifying areas that need refactoring.
33092
- - You can use the ${toolNamePrefix}list_code_definition_names tool to get an overview of source code definitions for all files at the top level of a specified directory. This can be particularly useful when you need to understand the broader context and relationships between certain parts of the code. You may need to call this tool multiple times to understand various parts of the codebase related to the task.
33093
- \t- For example, when asked to make edits or improvements you might analyze the file structure in the initial environment_details to get an overview of the project, then use ${toolNamePrefix}list_code_definition_names to get further insight using source code definitions for files located in relevant directories, then ${toolNamePrefix}read_file to examine the contents of relevant files, analyze the code and suggest improvements or make necessary edits, then use the ${toolNamePrefix}replace_in_file tool to implement changes. If you refactored code that could affect other parts of the codebase, you could use ${toolNamePrefix}search_files to ensure you update other files as needed.
33094
- - You can use the ${toolNamePrefix}execute_command tool to run commands on the user's computer whenever you feel it can help accomplish the user's task. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.`;
33243
+ - You have access to a range of tools to aid you in your work. These tools help you effectively accomplish a wide range of tasks.
33244
+ - When the user initially gives you a task, a recursive list of all filepaths in the current working directory will be included in context. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further.`;
33095
33245
  var systemInformation = (info) => `
33096
33246
  ====
33097
33247
 
@@ -33156,7 +33306,7 @@ ${joined}`;
33156
33306
  };
33157
33307
  var responsePrompts = {
33158
33308
  errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
33159
- requireUseTool: "Error: You must use a tool before proceeding",
33309
+ requireUseTool: "Error: You must use a tool before proceeding. Making sure the tool is invoked using xml tags.",
33160
33310
  toolResults: (tool, result) => `<tool_response>
33161
33311
  <tool_name>${tool}</tool_name>
33162
33312
  <tool_result>
@@ -33191,6 +33341,9 @@ ${agents}`;
33191
33341
  callback = () => {
33192
33342
  }
33193
33343
  }) {
33344
+ if (maxIterations < 1) {
33345
+ throw new Error("Max iterations must be greater than 0");
33346
+ }
33194
33347
  const taskInfo = {
33195
33348
  options: {
33196
33349
  maxIterations
@@ -33207,6 +33360,7 @@ ${agents}`;
33207
33360
  text += `
33208
33361
  <context>${context}</context>`;
33209
33362
  }
33363
+ callback({ kind: "StartTask" /* StartTask */, info: taskInfo, systemPrompt: this.config.systemPrompt });
33210
33364
  return await this.#processLoop(text, taskInfo, callback);
33211
33365
  }
33212
33366
  async#processLoop(userMessage, taskInfo, callback) {
@@ -33350,6 +33504,8 @@ __export(exports_allTools, {
33350
33504
  writeToFile: () => writeToFile_default,
33351
33505
  searchFiles: () => searchFiles_default,
33352
33506
  replaceInFile: () => replaceInFile_default,
33507
+ renameFile: () => renameFile_default,
33508
+ removeFile: () => removeFile_default,
33353
33509
  readFile: () => readFile_default,
33354
33510
  listFiles: () => listFiles_default,
33355
33511
  listCodeDefinitionNames: () => listCodeDefinitionNames_default,
@@ -33430,7 +33586,10 @@ var getStringArray = (args, name, defaultValue) => {
33430
33586
  }
33431
33587
  return defaultValue;
33432
33588
  }
33433
- return ret.split(",");
33589
+ if (ret === "") {
33590
+ return [];
33591
+ }
33592
+ return ret.split(",").map((s2) => s2.trim());
33434
33593
  };
33435
33594
  var getBoolean = (args, name, defaultValue) => {
33436
33595
  const ret = args[name];
@@ -34062,7 +34221,7 @@ var handler9 = async (provider, args) => {
34062
34221
  await provider.writeFile(path, content);
34063
34222
  return {
34064
34223
  type: "Reply" /* Reply */,
34065
- message: `<write_file_path>${path}</write_file_path><status>Success</status>`
34224
+ message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
34066
34225
  };
34067
34226
  };
34068
34227
  var isAvailable9 = (provider) => {
@@ -34099,7 +34258,7 @@ var toolInfo10 = {
34099
34258
  {
34100
34259
  name: "files",
34101
34260
  description: "The files relevant to the task",
34102
- required: true,
34261
+ required: false,
34103
34262
  usageValue: "Relevant files"
34104
34263
  }
34105
34264
  ],
@@ -34148,6 +34307,109 @@ var handOver_default = {
34148
34307
  handler: handler10,
34149
34308
  isAvailable: isAvailable10
34150
34309
  };
34310
+ // ../core/src/tools/removeFile.ts
34311
+ var toolInfo11 = {
34312
+ name: "remove_file",
34313
+ description: "Request to remove a file at the specified path.",
34314
+ parameters: [
34315
+ {
34316
+ name: "path",
34317
+ description: "The path of the file to remove",
34318
+ required: true,
34319
+ usageValue: "File path here"
34320
+ }
34321
+ ],
34322
+ examples: [
34323
+ {
34324
+ description: "Request to remove a file",
34325
+ parameters: [
34326
+ {
34327
+ name: "path",
34328
+ value: "src/main.js"
34329
+ }
34330
+ ]
34331
+ }
34332
+ ]
34333
+ };
34334
+ var handler11 = async (provider, args) => {
34335
+ if (!provider.removeFile) {
34336
+ return {
34337
+ type: "Error" /* Error */,
34338
+ message: "Not possible to remove file. Abort."
34339
+ };
34340
+ }
34341
+ const path = getString(args, "path");
34342
+ await provider.removeFile(path);
34343
+ return {
34344
+ type: "Reply" /* Reply */,
34345
+ message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
34346
+ };
34347
+ };
34348
+ var isAvailable11 = (provider) => {
34349
+ return !!provider.removeFile;
34350
+ };
34351
+ var removeFile_default = {
34352
+ ...toolInfo11,
34353
+ handler: handler11,
34354
+ isAvailable: isAvailable11
34355
+ };
34356
+ // ../core/src/tools/renameFile.ts
34357
+ var toolInfo12 = {
34358
+ name: "rename_file",
34359
+ description: "Request to rename a file from source path to target path.",
34360
+ parameters: [
34361
+ {
34362
+ name: "sourcePath",
34363
+ description: "The current path of the file",
34364
+ required: true,
34365
+ usageValue: "Source file path here"
34366
+ },
34367
+ {
34368
+ name: "targetPath",
34369
+ description: "The new path for the file",
34370
+ required: true,
34371
+ usageValue: "Target file path here"
34372
+ }
34373
+ ],
34374
+ examples: [
34375
+ {
34376
+ description: "Request to rename a file",
34377
+ parameters: [
34378
+ {
34379
+ name: "sourcePath",
34380
+ value: "src/old-name.js"
34381
+ },
34382
+ {
34383
+ name: "targetPath",
34384
+ value: "src/new-name.js"
34385
+ }
34386
+ ]
34387
+ }
34388
+ ]
34389
+ };
34390
+ var handler12 = async (provider, args) => {
34391
+ if (!provider.renameFile) {
34392
+ return {
34393
+ type: "Error" /* Error */,
34394
+ message: "Not possible to rename file. Abort."
34395
+ };
34396
+ }
34397
+ const sourcePath = getString(args, "sourcePath");
34398
+ const targetPath = getString(args, "targetPath");
34399
+ await provider.renameFile(sourcePath, targetPath);
34400
+ return {
34401
+ type: "Reply" /* Reply */,
34402
+ message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
34403
+ };
34404
+ };
34405
+ var isAvailable12 = (provider) => {
34406
+ return !!provider.renameFile;
34407
+ };
34408
+ var renameFile_default = {
34409
+ ...toolInfo12,
34410
+ handler: handler12,
34411
+ isAvailable: isAvailable12
34412
+ };
34151
34413
  // ../core/src/Agent/CoderAgent/prompts.ts
34152
34414
  var basePrompt = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.";
34153
34415
  var editingFilesPrompt = (toolNamePrefix) => `
@@ -34392,19 +34654,24 @@ class MultiAgent {
34392
34654
  get model() {
34393
34655
  return this.#activeAgent?.model;
34394
34656
  }
34395
- async#startTask(agentName, task, context, callback) {
34657
+ async#startTask(agentName, task, context, maxIterations, callback) {
34396
34658
  this.#activeAgent = await this.#config.createAgent(agentName);
34397
34659
  const [exitReason, info] = await this.#activeAgent.startTask({
34398
34660
  task,
34399
34661
  context,
34662
+ maxIterations,
34400
34663
  callback
34401
34664
  });
34402
34665
  if (typeof exitReason === "string") {
34403
34666
  return [exitReason, info];
34404
34667
  }
34405
34668
  if (exitReason.type === "HandOver") {
34669
+ const remainIteration = maxIterations - Math.floor(info.messages.length / 2);
34670
+ if (remainIteration < 1) {
34671
+ return ["MaxIterations", info];
34672
+ }
34406
34673
  const context2 = await this.#config.getContext(agentName, exitReason.context, exitReason.files);
34407
- const [exitReason2, info2] = await this.#startTask(exitReason.agentName, exitReason.task, context2, callback);
34674
+ const [exitReason2, info2] = await this.#startTask(exitReason.agentName, exitReason.task, context2, remainIteration, callback);
34408
34675
  info2.inputTokens += info.inputTokens;
34409
34676
  info2.outputTokens += info.outputTokens;
34410
34677
  info2.cacheWriteTokens += info.cacheWriteTokens;
@@ -34418,7 +34685,8 @@ class MultiAgent {
34418
34685
  if (this.#activeAgent) {
34419
34686
  throw new Error("An active agent already exists");
34420
34687
  }
34421
- return this.#startTask(options.agentName, options.task, options.context, options.callback);
34688
+ const maxIterations = options.maxIterations ?? 50;
34689
+ return this.#startTask(options.agentName, options.task, options.context, maxIterations, options.callback);
34422
34690
  }
34423
34691
  async continueTask(userMessage, taskInfo, callback = () => {
34424
34692
  }) {
@@ -34490,6 +34758,8 @@ ${output}`);
34490
34758
 
34491
34759
  // ../core/src/AiTool/generateGithubPullRequestDetails.ts
34492
34760
  var prompt2 = `
34761
+ # Generate Github Pull Request Details
34762
+
34493
34763
  You are given:
34494
34764
  - A branch name in <tool_input_branch_name>.
34495
34765
  - An optional context message in <tool_input_context> (which may or may not be present).
@@ -34502,10 +34772,30 @@ Your task:
34502
34772
  3. Produce a single GitHub Pull Request title.
34503
34773
  4. Produce a Pull Request description that explains the changes.
34504
34774
 
34775
+ Use the following template for the Pull Request description:
34776
+
34777
+ ---
34778
+ **Context (if provided)**:
34779
+ - Acknowledge any guiding concerns or instructions.
34780
+
34781
+ **Summary of Changes**:
34782
+ - Provide a concise list or overview of what changed.
34783
+
34784
+ **Highlights of Changed Code**:
34785
+ - Mention only the specific sections or functionalities updated, without showing full surrounding context.
34786
+
34787
+ **Additional Information (if needed)**:
34788
+ - Testing steps (if applicable).
34789
+ - Any notes or caveats.
34790
+
34791
+ ---
34792
+
34505
34793
  Output format:
34506
34794
  <tool_output>
34507
34795
  <tool_output_pr_title>YOUR PR TITLE HERE</tool_output_pr_title>
34508
- <tool_output_pr_description>YOUR PR DESCRIPTION HERE</tool_output_pr_description>
34796
+ <tool_output_pr_description>
34797
+ YOUR PR DESCRIPTION HERE
34798
+ </tool_output_pr_description>
34509
34799
  </tool_output>
34510
34800
 
34511
34801
  Below is an **example** of the input and output:
@@ -34527,7 +34817,7 @@ diff --git a/order_service.py b/order_service.py
34527
34817
  - if is_valid_order(order):
34528
34818
  - process_order(order)
34529
34819
  + validate_and_process(order)
34530
- </tool_input_commit_diff>
34820
+ </tool_input_commit_diff>
34531
34821
  </tool_input>
34532
34822
 
34533
34823
  Example Output:
@@ -34541,8 +34831,7 @@ to use the new validate_and_process method for improved maintainability.
34541
34831
 
34542
34832
  ---
34543
34833
 
34544
- Use the above format whenever you receive \`<tool_input>\` that may include a branch name, an optional context, aggregated commit messages in a single tag, and a combined diff in a single tag. Provide your final output strictly in \`<tool_output>\` with \`<tool_output_pr_title>\` and \`<tool_output_pr_description>\`.
34545
- Only highlight the changed code and avoid including the context around the changes in the description.
34834
+ Use the above format whenever you receive <tool_input> that may include a branch name, an optional context, aggregated commit messages in a single tag, and a combined diff in a single tag. Provide your final output strictly in <tool_output> with <tool_output_pr_title> and <tool_output_pr_description>. Only highlight the changed code and avoid including the context around the changes in the description.
34546
34835
  `;
34547
34836
  var generateGithubPullRequestDetails_default = {
34548
34837
  name: "generateGithubPullRequestDetails",
@@ -34730,7 +35019,7 @@ import os from "node:os";
34730
35019
  // src/provider.ts
34731
35020
  var import_ignore2 = __toESM(require_ignore(), 1);
34732
35021
  import { spawn as spawn2 } from "node:child_process";
34733
- import { mkdir, readFile, writeFile } from "node:fs/promises";
35022
+ import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
34734
35023
  import { dirname } from "node:path";
34735
35024
 
34736
35025
  // src/utils/listFiles.ts
@@ -34843,7 +35132,7 @@ async function searchFiles(path2, regex, filePattern, cwd, excludeFiles) {
34843
35132
  rg.stderr.on("data", (data) => {
34844
35133
  const err = data.toString();
34845
35134
  if (!err.startsWith("WARNING:")) {
34846
- console.error(err);
35135
+ console.warn(err);
34847
35136
  }
34848
35137
  });
34849
35138
  rg.on("error", (error) => {
@@ -34876,6 +35165,18 @@ var getProvider = (options) => {
34876
35165
  await mkdir(dirname(path2), { recursive: true });
34877
35166
  return await writeFile(path2, content, "utf8");
34878
35167
  },
35168
+ removeFile: async (path2) => {
35169
+ if (ig.ignores(path2)) {
35170
+ throw new Error(`Not allow to access file ${path2}`);
35171
+ }
35172
+ return await unlink(path2);
35173
+ },
35174
+ renameFile: async (sourcePath, targetPath) => {
35175
+ if (ig.ignores(sourcePath) || ig.ignores(targetPath)) {
35176
+ throw new Error(`Not allow to access file ${sourcePath} or ${targetPath}`);
35177
+ }
35178
+ return await rename(sourcePath, targetPath);
35179
+ },
34879
35180
  listFiles: async (path2, recursive, maxCount) => {
34880
35181
  return await listFiles(path2, recursive, maxCount, dirname(path2), options.excludeFiles);
34881
35182
  },
@@ -39229,7 +39530,7 @@ var readConfig = (path2) => {
39229
39530
 
39230
39531
  // src/options.ts
39231
39532
  function addSharedOptions(command) {
39232
- return command.option("-c --config <path>", "Path to config file").option("--api-provider <provider>", "API provider").option("--model <model>", "Model ID").option("--api-key <key>", "API key").option("--max-iterations <iterations>", "Maximum number of iterations to run. Default to 30", Number.parseInt);
39533
+ return command.option("-c --config <path>", "Path to config file").option("--api-provider <provider>", "API provider").option("--model <model>", "Model ID").option("--api-key <key>", "API key").option("--max-iterations <iterations>", "Maximum number of iterations to run. Default to 30", Number.parseInt).option("-v --verbose", "Enable verbose output. Use -v for level 1, -vv for level 2", (value, prev) => prev + 1, 0);
39233
39534
  }
39234
39535
 
39235
39536
  class ApiProviderConfig {
@@ -39298,6 +39599,7 @@ function parseOptions(options, cwd = process.cwd(), home = os2.homedir()) {
39298
39599
  });
39299
39600
  return {
39300
39601
  maxIterations: options.maxIterations ?? 30,
39602
+ verbose: options.verbose ?? 0,
39301
39603
  config,
39302
39604
  providerConfig
39303
39605
  };
@@ -39788,13 +40090,32 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
39788
40090
  var source_default = chalk;
39789
40091
 
39790
40092
  // src/utils/eventHandler.ts
39791
- var printEvent = (event) => {
40093
+ var printEvent = (verbose) => (event) => {
40094
+ let hadReasoning = false;
39792
40095
  switch (event.kind) {
40096
+ case "StartTask" /* StartTask */:
40097
+ if (verbose > 1) {
40098
+ console.log(`
40099
+ ====== System Prompt ======
40100
+ ${event.systemPrompt}`);
40101
+ console.log(`
40102
+
40103
+ ================
40104
+ `);
40105
+ }
40106
+ break;
39793
40107
  case "StartRequest" /* StartRequest */:
39794
40108
  console.log(`
39795
40109
 
39796
40110
  ======== New Request ========
39797
40111
  `);
40112
+ if (verbose) {
40113
+ console.log(event.userMessage);
40114
+ console.log(`
40115
+
40116
+ ======== Request Message Ended ========
40117
+ `);
40118
+ }
39798
40119
  break;
39799
40120
  case "EndRequest" /* EndRequest */:
39800
40121
  console.log(`
@@ -39805,10 +40126,17 @@ var printEvent = (event) => {
39805
40126
  case "Usage" /* Usage */:
39806
40127
  break;
39807
40128
  case "Text" /* Text */:
40129
+ if (hadReasoning) {
40130
+ process.stdout.write(`
40131
+
40132
+ `);
40133
+ hadReasoning = false;
40134
+ }
39808
40135
  process.stdout.write(event.newText);
39809
40136
  break;
39810
40137
  case "Reasoning" /* Reasoning */:
39811
40138
  process.stdout.write(source_default.dim(event.newText));
40139
+ hadReasoning = true;
39812
40140
  break;
39813
40141
  case "ToolUse" /* ToolUse */:
39814
40142
  break;
@@ -40404,15 +40732,15 @@ function useKeypress(userHandler) {
40404
40732
  signal.current = userHandler;
40405
40733
  useEffect((rl) => {
40406
40734
  let ignore3 = false;
40407
- const handler11 = withUpdates((_input, event) => {
40735
+ const handler13 = withUpdates((_input, event) => {
40408
40736
  if (ignore3)
40409
40737
  return;
40410
40738
  signal.current(event, rl);
40411
40739
  });
40412
- rl.input.on("keypress", handler11);
40740
+ rl.input.on("keypress", handler13);
40413
40741
  return () => {
40414
40742
  ignore3 = true;
40415
- rl.input.removeListener("keypress", handler11);
40743
+ rl.input.removeListener("keypress", handler13);
40416
40744
  };
40417
40745
  }, []);
40418
40746
  }
@@ -40594,16 +40922,16 @@ class Emitter {
40594
40922
 
40595
40923
  class SignalExitBase {
40596
40924
  }
40597
- var signalExitWrap = (handler11) => {
40925
+ var signalExitWrap = (handler13) => {
40598
40926
  return {
40599
40927
  onExit(cb, opts) {
40600
- return handler11.onExit(cb, opts);
40928
+ return handler13.onExit(cb, opts);
40601
40929
  },
40602
40930
  load() {
40603
- return handler11.load();
40931
+ return handler13.load();
40604
40932
  },
40605
40933
  unload() {
40606
- return handler11.unload();
40934
+ return handler13.unload();
40607
40935
  }
40608
40936
  };
40609
40937
  };
@@ -41257,6 +41585,9 @@ async function configPrompt(existingConfig) {
41257
41585
  case "deepseek" /* DeepSeek */:
41258
41586
  model = deepSeekDefaultModelId;
41259
41587
  break;
41588
+ case "openrouter" /* OpenRouter */:
41589
+ model = await esm_default3({ message: "Enter Model ID (Visit https://openrouter.ai/models for available models):" });
41590
+ break;
41260
41591
  }
41261
41592
  let apiKey;
41262
41593
  if (provider2 !== "ollama" /* Ollama */) {
@@ -41280,7 +41611,7 @@ async function printConfig(configPath) {
41280
41611
  }
41281
41612
  console.log($stringify(config));
41282
41613
  }
41283
- async function configCommand(options) {
41614
+ var configCommand = new Command("config").description("Configure global or local settings").option("-g, --global", "Use global config").option("-p, --print", "Print config").action(async (options) => {
41284
41615
  const globalConfigPath = getGlobalConfigPath();
41285
41616
  let configPath = options.global ? globalConfigPath : localConfigFileName;
41286
41617
  if (options.print) {
@@ -41367,12 +41698,11 @@ ${provider2.toUpperCase()}_API_KEY=${apiKey}`;
41367
41698
  mkdirSync(dirname2(configPath), { recursive: true });
41368
41699
  writeFileSync(configPath, $stringify(newConfig));
41369
41700
  console.log(`Config file saved at: ${configPath}`);
41370
- return;
41371
- }
41701
+ });
41372
41702
 
41373
41703
  // src/commands/chat.ts
41374
41704
  var runChat = async (options) => {
41375
- const { config, providerConfig, maxIterations } = parseOptions(options);
41705
+ const { config, providerConfig, maxIterations, verbose } = parseOptions(options);
41376
41706
  let { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("coder") ?? {};
41377
41707
  if (!provider2) {
41378
41708
  const newConfig = await configPrompt({ provider: provider2, model, apiKey });
@@ -41392,7 +41722,7 @@ var runChat = async (options) => {
41392
41722
  config: config ?? {},
41393
41723
  maxIterations,
41394
41724
  interactive: true,
41395
- eventCallback: printEvent
41725
+ eventCallback: printEvent(verbose)
41396
41726
  });
41397
41727
  let taskInfo;
41398
41728
  const chat2 = new Chat3({
@@ -42161,12 +42491,57 @@ var prCommand = new Command("pr").description("Create a GitHub pull request").ar
42161
42491
  });
42162
42492
 
42163
42493
  // src/commands/task.ts
42494
+ var readStdin = async (timeoutMs = 30000) => {
42495
+ if (process.stdin.isTTY) {
42496
+ return "";
42497
+ }
42498
+ return new Promise((resolve2, reject) => {
42499
+ let input = "";
42500
+ let timeoutId = undefined;
42501
+ const cleanup = () => {
42502
+ if (timeoutId)
42503
+ clearTimeout(timeoutId);
42504
+ process.stdin.removeAllListeners();
42505
+ process.stdin.resume();
42506
+ };
42507
+ timeoutId = setTimeout(() => {
42508
+ cleanup();
42509
+ reject(new Error("Stdin read timeout"));
42510
+ }, timeoutMs);
42511
+ process.stdin.on("data", (chunk) => {
42512
+ input += chunk.toString();
42513
+ });
42514
+ process.stdin.on("end", () => {
42515
+ cleanup();
42516
+ if (!input) {
42517
+ reject(new Error("Empty stdin input"));
42518
+ return;
42519
+ }
42520
+ resolve2(input);
42521
+ });
42522
+ process.stdin.on("error", (err) => {
42523
+ cleanup();
42524
+ reject(err);
42525
+ });
42526
+ });
42527
+ };
42164
42528
  var runTask = async (taskArg, options) => {
42165
- if (!taskArg) {
42166
- runChat(options);
42167
- return;
42529
+ let task = taskArg;
42530
+ if (!task) {
42531
+ try {
42532
+ const stdinInput = await readStdin();
42533
+ if (stdinInput) {
42534
+ task = stdinInput;
42535
+ } else {
42536
+ runChat(options);
42537
+ return;
42538
+ }
42539
+ } catch (error) {
42540
+ console.error("Error reading stdin:", error);
42541
+ process.exit(1);
42542
+ }
42168
42543
  }
42169
- const { providerConfig, config, maxIterations } = parseOptions(options);
42544
+ const { providerConfig, config, maxIterations, verbose } = parseOptions(options);
42170
42545
  let { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("coder") ?? {};
42171
42546
  if (!provider2) {
42172
42547
  const newConfig = await configPrompt({ provider: provider2, model, apiKey });
@@ -42183,18 +42558,18 @@ var runTask = async (taskArg, options) => {
42183
42558
  config: config ?? {},
42184
42559
  maxIterations,
42185
42560
  interactive: false,
42186
- eventCallback: printEvent
42561
+ eventCallback: printEvent(verbose)
42187
42562
  });
42188
- await runner.startTask(taskArg);
42563
+ await runner.startTask(task);
42189
42564
  runner.printUsage();
42190
42565
  };
42191
42566
 
42192
42567
  // src/index.ts
42193
42568
  var program2 = new Command;
42194
- program2.name("polka").description("Polka Codes CLI").version(version);
42195
- program2.command("chat").description("Start an interactive chat session").action(runChat);
42196
- program2.command("config").description("Configure global or local settings").option("-g, --global", "Use global config").option("-p, --print", "Print config").action(configCommand);
42569
+ program2.name("polka-codes").description("Polka Codes CLI").version(version);
42197
42570
  program2.argument("[task]", "The task to execute").action(runTask);
42571
+ program2.command("chat").description("Start an interactive chat session").action(runChat);
42572
+ program2.addCommand(configCommand);
42198
42573
  program2.addCommand(commitCommand);
42199
42574
  program2.addCommand(prCommand);
42200
42575
  addSharedOptions(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polka-codes/cli",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "license": "AGPL-3.0",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@inquirer/prompts": "^7.2.3",
20
- "@polka-codes/core": "0.4.3",
20
+ "@polka-codes/core": "0.4.5",
21
21
  "@vscode/ripgrep": "^1.15.10",
22
22
  "chalk": "^5.4.1",
23
23
  "commander": "^13.0.0",