@polka-codes/cli 0.8.11 → 0.8.12

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 (2) hide show
  1. package/dist/index.js +487 -239
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -38429,7 +38429,7 @@ var require_public_api4 = __commonJS((exports) => {
38429
38429
  });
38430
38430
 
38431
38431
  // src/index.ts
38432
- var import_config2 = __toESM(require_config(), 1);
38432
+ var import_config3 = __toESM(require_config(), 1);
38433
38433
 
38434
38434
  // ../../node_modules/commander/esm.mjs
38435
38435
  var import__ = __toESM(require_commander(), 1);
@@ -38447,13 +38447,15 @@ var {
38447
38447
  Help
38448
38448
  } = import__.default;
38449
38449
  // package.json
38450
- var version = "0.8.11";
38450
+ var version = "0.8.12";
38451
38451
 
38452
38452
  // ../core/src/AiService/AiServiceBase.ts
38453
38453
  class AiServiceBase {
38454
38454
  usageMeter;
38455
- constructor(usageMeter) {
38456
- this.usageMeter = usageMeter;
38455
+ options;
38456
+ constructor(options) {
38457
+ this.options = options;
38458
+ this.usageMeter = options.usageMeter;
38457
38459
  }
38458
38460
  async* send(systemPrompt, messages) {
38459
38461
  this.usageMeter.checkLimit();
@@ -41939,7 +41941,7 @@ class AnthropicService extends AiServiceBase {
41939
41941
  #client;
41940
41942
  model;
41941
41943
  constructor(options) {
41942
- super(options.usageMeter);
41944
+ super(options);
41943
41945
  this.#options = options;
41944
41946
  this.#client = new Anthropic({
41945
41947
  apiKey: options.apiKey,
@@ -47366,7 +47368,7 @@ class DeepSeekService extends AiServiceBase {
47366
47368
  #client;
47367
47369
  model;
47368
47370
  constructor(options) {
47369
- super(options.usageMeter);
47371
+ super(options);
47370
47372
  this.#client = new openai_default({
47371
47373
  baseURL: "https://api.deepseek.com/v1",
47372
47374
  apiKey: options.apiKey
@@ -47423,7 +47425,7 @@ class OllamaService extends AiServiceBase {
47423
47425
  #client;
47424
47426
  model;
47425
47427
  constructor(options) {
47426
- super(options.usageMeter);
47428
+ super(options);
47427
47429
  this.#client = new openai_default({
47428
47430
  baseURL: `${options.baseUrl || "http://localhost:11434"}/v1`,
47429
47431
  apiKey: "ollama"
@@ -47465,7 +47467,7 @@ class OpenRouterService extends AiServiceBase {
47465
47467
  #modelProviderInfo;
47466
47468
  model;
47467
47469
  constructor(options) {
47468
- super(options.usageMeter);
47470
+ super(options);
47469
47471
  if (!options.model) {
47470
47472
  throw new Error("OpenRouter requires a model");
47471
47473
  }
@@ -47757,73 +47759,98 @@ __export(exports_allTools, {
47757
47759
  writeToFile: () => writeToFile_default,
47758
47760
  updateKnowledge: () => updateKnowledge_default,
47759
47761
  searchFiles: () => searchFiles_default,
47760
- replaceInFile: () => replaceInFile_default,
47761
47762
  renameFile: () => renameFile_default,
47762
47763
  removeFile: () => removeFile_default,
47763
47764
  readFile: () => readFile_default,
47764
47765
  listFiles: () => listFiles_default,
47765
47766
  handOver: () => handOver_default,
47766
47767
  executeCommand: () => executeCommand_default,
47768
+ editFile: () => editFile_default,
47767
47769
  delegate: () => delegate_default,
47768
47770
  attemptCompletion: () => attemptCompletion_default,
47769
47771
  askFollowupQuestion: () => askFollowupQuestion_default
47770
47772
  });
47771
47773
 
47772
- // ../core/src/tools/utils/replaceInFile.ts
47773
- var replaceInFile = async (fileContent, diff) => {
47774
- const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
47775
- const blocks = [];
47776
- for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
47777
- blocks.push({ search: match[1], replace: match[2] });
47774
+ // ../core/src/tools/utils/editFile.ts
47775
+ var START_OF_FILE = "<<<START_OF_FILE>>>";
47776
+ var END_OF_FILE = "<<<END_OF_FILE>>>";
47777
+ var editFile = async (fileContent, operations) => {
47778
+ if (!operations || operations.length === 0) {
47779
+ throw new Error("At least one edit operation is required");
47778
47780
  }
47779
- if (blocks.length === 0) {
47780
- throw new Error("No valid diff blocks found.");
47781
- }
47782
- const findAndReplace = (content, search, replace) => {
47783
- let index = content.indexOf(search);
47784
- if (index !== -1) {
47785
- return content.slice(0, index) + replace + content.slice(index + search.length);
47786
- }
47787
- const trimmedSearch = search.trim();
47788
- const trimmedContent = content.trim();
47789
- const offset = content.indexOf(trimmedContent);
47790
- index = trimmedContent.indexOf(trimmedSearch);
47791
- if (index !== -1) {
47792
- const absoluteIndex = offset + index;
47793
- return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
47794
- }
47795
- const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
47796
- const normalizedContent = trimmedContent.replace(/\s+/g, " ");
47797
- index = normalizedContent.indexOf(normalizedSearch);
47798
- if (index !== -1) {
47799
- let runningIndex = 0;
47800
- let actualPos = offset;
47801
- for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
47802
- const segIndex = content.indexOf(segment, actualPos);
47803
- if (segIndex === -1) {
47804
- break;
47805
- }
47806
- if (runningIndex === 0) {
47807
- actualPos = segIndex;
47808
- } else {
47809
- actualPos = segIndex + segment.length;
47810
- }
47811
- runningIndex++;
47812
- }
47813
- const strippedSearch = trimmedSearch.replace(/\s+/g, "");
47814
- const endPos = actualPos;
47815
- const startPos = endPos - strippedSearch.length;
47816
- return content.slice(0, startPos) + replace + content.slice(endPos);
47817
- }
47818
- throw new Error(`Could not find the following text in file:
47819
- ${search}`);
47820
- };
47821
- let updatedFile = fileContent;
47822
- for (const { search, replace } of blocks) {
47823
- updatedFile = findAndReplace(updatedFile, search, replace);
47781
+ const originalLines = fileContent.split(`
47782
+ `);
47783
+ let updatedContent = fileContent;
47784
+ for (const operation of operations) {
47785
+ updatedContent = await applyEditOperation(updatedContent, operation, originalLines);
47824
47786
  }
47825
- return updatedFile;
47787
+ return updatedContent;
47826
47788
  };
47789
+ async function applyEditOperation(fileContent, operation, originalLines) {
47790
+ const { before_text, after_text, new_text, before_text_line_start, after_text_line_start } = operation;
47791
+ if (before_text === START_OF_FILE && after_text === END_OF_FILE) {
47792
+ return new_text;
47793
+ }
47794
+ if (before_text === START_OF_FILE) {
47795
+ if (!after_text) {
47796
+ return new_text + fileContent;
47797
+ }
47798
+ const afterIndex = findTextWithHint(fileContent, after_text, after_text_line_start, originalLines);
47799
+ return new_text + fileContent.slice(afterIndex);
47800
+ }
47801
+ if (after_text === END_OF_FILE) {
47802
+ if (!before_text) {
47803
+ return fileContent + new_text;
47804
+ }
47805
+ const beforeIndex = findTextWithHint(fileContent, before_text, before_text_line_start, originalLines);
47806
+ const beforeEndIndex = beforeIndex + before_text.length;
47807
+ return fileContent.slice(0, beforeEndIndex) + new_text;
47808
+ }
47809
+ if (before_text && after_text) {
47810
+ const beforeIndex = findTextWithHint(fileContent, before_text, before_text_line_start, originalLines);
47811
+ const beforeEndIndex = beforeIndex + before_text.length;
47812
+ const afterIndex = findTextWithHint(fileContent, after_text, after_text_line_start, originalLines, beforeEndIndex);
47813
+ return fileContent.slice(0, beforeEndIndex) + new_text + fileContent.slice(afterIndex);
47814
+ }
47815
+ if (before_text) {
47816
+ const beforeIndex = findTextWithHint(fileContent, before_text, before_text_line_start, originalLines);
47817
+ const beforeEndIndex = beforeIndex + before_text.length;
47818
+ return fileContent.slice(0, beforeEndIndex) + new_text + fileContent.slice(beforeEndIndex);
47819
+ }
47820
+ if (after_text) {
47821
+ const afterIndex = findTextWithHint(fileContent, after_text, after_text_line_start, originalLines);
47822
+ return fileContent.slice(0, afterIndex) + new_text + fileContent.slice(afterIndex);
47823
+ }
47824
+ throw new Error("Either before_text or after_text must be specified");
47825
+ }
47826
+ function findTextWithHint(content, searchText, lineHint, originalLines, startIndex = 0) {
47827
+ if (lineHint && lineHint > 0 && lineHint <= originalLines.length) {
47828
+ const hintIndex = getLineStartIndex(originalLines, lineHint - 1);
47829
+ const searchRadius = 5;
47830
+ const windowStart = Math.max(0, hintIndex - searchRadius * 50);
47831
+ const windowEnd = Math.min(content.length, hintIndex + searchRadius * 50);
47832
+ const windowContent = content.slice(windowStart, windowEnd);
47833
+ const relativeIndex = windowContent.indexOf(searchText);
47834
+ if (relativeIndex !== -1) {
47835
+ const absoluteIndex = windowStart + relativeIndex;
47836
+ if (absoluteIndex >= startIndex) {
47837
+ return absoluteIndex;
47838
+ }
47839
+ }
47840
+ }
47841
+ const index = content.indexOf(searchText, startIndex);
47842
+ if (index === -1) {
47843
+ throw new Error(`Could not find text: ${searchText}`);
47844
+ }
47845
+ return index;
47846
+ }
47847
+ function getLineStartIndex(lines, lineIndex) {
47848
+ let index = 0;
47849
+ for (let i2 = 0;i2 < lineIndex && i2 < lines.length; i2++) {
47850
+ index += lines[i2].length + 1;
47851
+ }
47852
+ return index;
47853
+ }
47827
47854
  // ../core/src/tools/utils/getArg.ts
47828
47855
  var getString = (args, name, defaultValue) => {
47829
47856
  if (typeof args !== "object" || Array.isArray(args)) {
@@ -47915,6 +47942,61 @@ var getArray = (args, name, defaultValue) => {
47915
47942
  }
47916
47943
  return [ret];
47917
47944
  };
47945
+ // ../core/src/tools/utils/replaceInFile.ts
47946
+ var replaceInFile = async (fileContent, diff) => {
47947
+ const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
47948
+ const blocks = [];
47949
+ for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
47950
+ blocks.push({ search: match[1], replace: match[2] });
47951
+ }
47952
+ if (blocks.length === 0) {
47953
+ throw new Error("No valid diff blocks found.");
47954
+ }
47955
+ const findAndReplace = (content, search, replace) => {
47956
+ let index = content.indexOf(search);
47957
+ if (index !== -1) {
47958
+ return content.slice(0, index) + replace + content.slice(index + search.length);
47959
+ }
47960
+ const trimmedSearch = search.trim();
47961
+ const trimmedContent = content.trim();
47962
+ const offset = content.indexOf(trimmedContent);
47963
+ index = trimmedContent.indexOf(trimmedSearch);
47964
+ if (index !== -1) {
47965
+ const absoluteIndex = offset + index;
47966
+ return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
47967
+ }
47968
+ const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
47969
+ const normalizedContent = trimmedContent.replace(/\s+/g, " ");
47970
+ index = normalizedContent.indexOf(normalizedSearch);
47971
+ if (index !== -1) {
47972
+ let runningIndex = 0;
47973
+ let actualPos = offset;
47974
+ for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
47975
+ const segIndex = content.indexOf(segment, actualPos);
47976
+ if (segIndex === -1) {
47977
+ break;
47978
+ }
47979
+ if (runningIndex === 0) {
47980
+ actualPos = segIndex;
47981
+ } else {
47982
+ actualPos = segIndex + segment.length;
47983
+ }
47984
+ runningIndex++;
47985
+ }
47986
+ const strippedSearch = trimmedSearch.replace(/\s+/g, "");
47987
+ const endPos = actualPos;
47988
+ const startPos = endPos - strippedSearch.length;
47989
+ return content.slice(0, startPos) + replace + content.slice(endPos);
47990
+ }
47991
+ throw new Error(`Could not find the following text in file:
47992
+ ${search}`);
47993
+ };
47994
+ let updatedFile = fileContent;
47995
+ for (const { search, replace } of blocks) {
47996
+ updatedFile = findAndReplace(updatedFile, search, replace);
47997
+ }
47998
+ return updatedFile;
47999
+ };
47918
48000
  // ../core/src/tools/askFollowupQuestion.ts
47919
48001
  var toolInfo = {
47920
48002
  name: "ask_followup_question",
@@ -48361,125 +48443,8 @@ var readFile_default = {
48361
48443
  handler: handler6,
48362
48444
  isAvailable: isAvailable6
48363
48445
  };
48364
- // ../core/src/tools/replaceInFile.ts
48365
- var toolInfo7 = {
48366
- name: "replace_in_file",
48367
- description: "Request to replace sections of content in an existing file using SEARCH/REPLACE blocks that define exact changes to specific parts of the file. This tool should be used when you need to make targeted changes to specific parts of a file.",
48368
- parameters: [
48369
- {
48370
- name: "path",
48371
- description: "The path of the file to modify",
48372
- required: true,
48373
- usageValue: "File path here"
48374
- },
48375
- {
48376
- name: "diff",
48377
- description: `One or more SEARCH/REPLACE blocks following this exact format:
48378
- \`\`\`
48379
- <<<<<<< SEARCH
48380
- [exact content to find]
48381
- =======
48382
- [new content to replace with]
48383
- >>>>>>> REPLACE
48384
- \`\`\`
48385
- Critical rules:
48386
- 1. SEARCH content must match the associated file section to find EXACTLY:
48387
- * Match character-for-character including whitespace, indentation, line endings
48388
- * Include all comments, docstrings, etc.
48389
- 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
48390
- * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
48391
- * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
48392
- * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
48393
- 3. Keep SEARCH/REPLACE blocks concise:
48394
- * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
48395
- * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
48396
- * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
48397
- * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
48398
- 4. Special operations:
48399
- * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
48400
- * To delete code: Use empty REPLACE section`,
48401
- required: true,
48402
- usageValue: "Search and replace blocks here"
48403
- }
48404
- ],
48405
- examples: [
48406
- {
48407
- description: "Request to replace sections of content in a file",
48408
- parameters: [
48409
- {
48410
- name: "path",
48411
- value: "src/main.js"
48412
- },
48413
- {
48414
- name: "diff",
48415
- value: `
48416
- <<<<<<< SEARCH
48417
- import React from 'react';
48418
- =======
48419
- import React, { useState } from 'react';
48420
- >>>>>>> REPLACE
48421
-
48422
- <<<<<<< SEARCH
48423
- function handleSubmit() {
48424
- saveData();
48425
- setLoading(false);
48426
- }
48427
-
48428
- =======
48429
- >>>>>>> REPLACE
48430
-
48431
- <<<<<<< SEARCH
48432
- return (
48433
- <div>
48434
- =======
48435
- function handleSubmit() {
48436
- saveData();
48437
- setLoading(false);
48438
- }
48439
-
48440
- return (
48441
- <div>
48442
- >>>>>>> REPLACE
48443
- `
48444
- }
48445
- ]
48446
- }
48447
- ],
48448
- permissionLevel: 2 /* Write */
48449
- };
48450
- var handler7 = async (provider, args) => {
48451
- if (!provider.readFile || !provider.writeFile) {
48452
- return {
48453
- type: "Error" /* Error */,
48454
- message: "Not possible to replace in file. Abort."
48455
- };
48456
- }
48457
- const path = getString(args, "path");
48458
- const diff = getString(args, "diff");
48459
- const fileContent = await provider.readFile(path);
48460
- if (fileContent == null) {
48461
- return {
48462
- type: "Error" /* Error */,
48463
- message: `<error><replace_in_file_path>${path}</replace_in_file_path><error_message>File not found</error_message></error>`
48464
- };
48465
- }
48466
- const result = await replaceInFile(fileContent, diff);
48467
- await provider.writeFile(path, result);
48468
- return {
48469
- type: "Reply" /* Reply */,
48470
- message: `<replace_in_file_path>${path}</replace_in_file_path>`
48471
- };
48472
- };
48473
- var isAvailable7 = (provider) => {
48474
- return !!provider.readFile && !!provider.writeFile;
48475
- };
48476
- var replaceInFile_default = {
48477
- ...toolInfo7,
48478
- handler: handler7,
48479
- isAvailable: isAvailable7
48480
- };
48481
48446
  // ../core/src/tools/searchFiles.ts
48482
- var toolInfo8 = {
48447
+ var toolInfo7 = {
48483
48448
  name: "search_files",
48484
48449
  description: "Request to perform a regex search across files in a specified directory, outputting context-rich results that include surrounding lines. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context.",
48485
48450
  parameters: [
@@ -48523,7 +48488,7 @@ var toolInfo8 = {
48523
48488
  ],
48524
48489
  permissionLevel: 1 /* Read */
48525
48490
  };
48526
- var handler8 = async (provider, args) => {
48491
+ var handler7 = async (provider, args) => {
48527
48492
  if (!provider.searchFiles) {
48528
48493
  return {
48529
48494
  type: "Error" /* Error */,
@@ -48546,18 +48511,18 @@ ${files.join(`
48546
48511
  `
48547
48512
  };
48548
48513
  };
48549
- var isAvailable8 = (provider) => {
48514
+ var isAvailable7 = (provider) => {
48550
48515
  return !!provider.searchFiles;
48551
48516
  };
48552
48517
  var searchFiles_default = {
48553
- ...toolInfo8,
48554
- handler: handler8,
48555
- isAvailable: isAvailable8
48518
+ ...toolInfo7,
48519
+ handler: handler7,
48520
+ isAvailable: isAvailable7
48556
48521
  };
48557
48522
  // ../core/src/tools/updateKnowledge.ts
48558
48523
  var import_yaml = __toESM(require_dist(), 1);
48559
48524
  import { join } from "node:path";
48560
- var toolInfo9 = {
48525
+ var toolInfo8 = {
48561
48526
  name: "update_knowledge",
48562
48527
  description: "Update knowledge in a knowledge.ai.yml file with smart merging capabilities. This tool lets you add, update, or remove information using path-based updates and special directives.",
48563
48528
  parameters: [
@@ -48734,7 +48699,7 @@ function deepMerge(target, source) {
48734
48699
  }
48735
48700
  return output;
48736
48701
  }
48737
- var handler9 = async (provider, args) => {
48702
+ var handler8 = async (provider, args) => {
48738
48703
  if (!provider.readFile || !provider.writeFile) {
48739
48704
  return {
48740
48705
  type: "Error" /* Error */,
@@ -48806,16 +48771,16 @@ var handler9 = async (provider, args) => {
48806
48771
  };
48807
48772
  }
48808
48773
  };
48809
- var isAvailable9 = (provider) => {
48774
+ var isAvailable8 = (provider) => {
48810
48775
  return !!provider.readFile && !!provider.writeFile;
48811
48776
  };
48812
48777
  var updateKnowledge_default = {
48813
- ...toolInfo9,
48814
- handler: handler9,
48815
- isAvailable: isAvailable9
48778
+ ...toolInfo8,
48779
+ handler: handler8,
48780
+ isAvailable: isAvailable8
48816
48781
  };
48817
48782
  // ../core/src/tools/writeToFile.ts
48818
- var toolInfo10 = {
48783
+ var toolInfo9 = {
48819
48784
  name: "write_to_file",
48820
48785
  description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file. Ensure that the output content does not include incorrect escaped character patterns such as `&lt;` and `&gt;`.",
48821
48786
  parameters: [
@@ -48860,7 +48825,7 @@ export default App;
48860
48825
  ],
48861
48826
  permissionLevel: 2 /* Write */
48862
48827
  };
48863
- var handler10 = async (provider, args) => {
48828
+ var handler9 = async (provider, args) => {
48864
48829
  if (!provider.writeFile) {
48865
48830
  return {
48866
48831
  type: "Error" /* Error */,
@@ -48875,16 +48840,16 @@ var handler10 = async (provider, args) => {
48875
48840
  message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
48876
48841
  };
48877
48842
  };
48878
- var isAvailable10 = (provider) => {
48843
+ var isAvailable9 = (provider) => {
48879
48844
  return !!provider.writeFile;
48880
48845
  };
48881
48846
  var writeToFile_default = {
48882
- ...toolInfo10,
48883
- handler: handler10,
48884
- isAvailable: isAvailable10
48847
+ ...toolInfo9,
48848
+ handler: handler9,
48849
+ isAvailable: isAvailable9
48885
48850
  };
48886
48851
  // ../core/src/tools/handOver.ts
48887
- var toolInfo11 = {
48852
+ var toolInfo10 = {
48888
48853
  name: "hand_over",
48889
48854
  description: "Hand over the current task to another agent to complete. This tool MUST NOT to be used with any other tool.",
48890
48855
  parameters: [
@@ -48938,7 +48903,7 @@ var toolInfo11 = {
48938
48903
  ],
48939
48904
  permissionLevel: 0 /* None */
48940
48905
  };
48941
- var handler11 = async (_provider, args) => {
48906
+ var handler10 = async (_provider, args) => {
48942
48907
  const agentName = getString(args, "agent_name");
48943
48908
  const task = getString(args, "task");
48944
48909
  const context = getString(args, "context", undefined);
@@ -48951,16 +48916,16 @@ var handler11 = async (_provider, args) => {
48951
48916
  files
48952
48917
  };
48953
48918
  };
48954
- var isAvailable11 = (_provider) => {
48919
+ var isAvailable10 = (_provider) => {
48955
48920
  return true;
48956
48921
  };
48957
48922
  var handOver_default = {
48958
- ...toolInfo11,
48959
- handler: handler11,
48960
- isAvailable: isAvailable11
48923
+ ...toolInfo10,
48924
+ handler: handler10,
48925
+ isAvailable: isAvailable10
48961
48926
  };
48962
48927
  // ../core/src/tools/removeFile.ts
48963
- var toolInfo12 = {
48928
+ var toolInfo11 = {
48964
48929
  name: "remove_file",
48965
48930
  description: "Request to remove a file at the specified path.",
48966
48931
  parameters: [
@@ -48984,7 +48949,7 @@ var toolInfo12 = {
48984
48949
  ],
48985
48950
  permissionLevel: 2 /* Write */
48986
48951
  };
48987
- var handler12 = async (provider, args) => {
48952
+ var handler11 = async (provider, args) => {
48988
48953
  if (!provider.removeFile) {
48989
48954
  return {
48990
48955
  type: "Error" /* Error */,
@@ -48998,27 +48963,27 @@ var handler12 = async (provider, args) => {
48998
48963
  message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
48999
48964
  };
49000
48965
  };
49001
- var isAvailable12 = (provider) => {
48966
+ var isAvailable11 = (provider) => {
49002
48967
  return !!provider.removeFile;
49003
48968
  };
49004
48969
  var removeFile_default = {
49005
- ...toolInfo12,
49006
- handler: handler12,
49007
- isAvailable: isAvailable12
48970
+ ...toolInfo11,
48971
+ handler: handler11,
48972
+ isAvailable: isAvailable11
49008
48973
  };
49009
48974
  // ../core/src/tools/renameFile.ts
49010
- var toolInfo13 = {
48975
+ var toolInfo12 = {
49011
48976
  name: "rename_file",
49012
48977
  description: "Request to rename a file from source path to target path.",
49013
48978
  parameters: [
49014
48979
  {
49015
- name: "sourcePath",
48980
+ name: "source_path",
49016
48981
  description: "The current path of the file",
49017
48982
  required: true,
49018
48983
  usageValue: "Source file path here"
49019
48984
  },
49020
48985
  {
49021
- name: "targetPath",
48986
+ name: "target_path",
49022
48987
  description: "The new path for the file",
49023
48988
  required: true,
49024
48989
  usageValue: "Target file path here"
@@ -49029,11 +48994,11 @@ var toolInfo13 = {
49029
48994
  description: "Request to rename a file",
49030
48995
  parameters: [
49031
48996
  {
49032
- name: "sourcePath",
48997
+ name: "source_path",
49033
48998
  value: "src/old-name.js"
49034
48999
  },
49035
49000
  {
49036
- name: "targetPath",
49001
+ name: "target_path",
49037
49002
  value: "src/new-name.js"
49038
49003
  }
49039
49004
  ]
@@ -49041,29 +49006,308 @@ var toolInfo13 = {
49041
49006
  ],
49042
49007
  permissionLevel: 2 /* Write */
49043
49008
  };
49044
- var handler13 = async (provider, args) => {
49009
+ var handler12 = async (provider, args) => {
49045
49010
  if (!provider.renameFile) {
49046
49011
  return {
49047
49012
  type: "Error" /* Error */,
49048
49013
  message: "Not possible to rename file. Abort."
49049
49014
  };
49050
49015
  }
49051
- const sourcePath = getString(args, "sourcePath");
49052
- const targetPath = getString(args, "targetPath");
49016
+ const sourcePath = getString(args, "source_path");
49017
+ const targetPath = getString(args, "target_path");
49053
49018
  await provider.renameFile(sourcePath, targetPath);
49054
49019
  return {
49055
49020
  type: "Reply" /* Reply */,
49056
49021
  message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
49057
49022
  };
49058
49023
  };
49059
- var isAvailable13 = (provider) => {
49024
+ var isAvailable12 = (provider) => {
49060
49025
  return !!provider.renameFile;
49061
49026
  };
49062
49027
  var renameFile_default = {
49028
+ ...toolInfo12,
49029
+ handler: handler12,
49030
+ isAvailable: isAvailable12
49031
+ };
49032
+ // ../core/src/tools/editFile.ts
49033
+ var toolInfo13 = {
49034
+ name: "edit_file",
49035
+ description: "Request to edit file contents using before/after text anchors with flexible operations. Supports multiple edit operations in a single call.",
49036
+ parameters: [
49037
+ {
49038
+ name: "path",
49039
+ description: "The path of the file to edit",
49040
+ required: true,
49041
+ usageValue: "File path here"
49042
+ },
49043
+ {
49044
+ name: "operations",
49045
+ description: "Edit operation with before_text, after_text, new_text, and optional line range hints",
49046
+ required: true,
49047
+ allowMultiple: true,
49048
+ children: [
49049
+ {
49050
+ name: "before_text",
49051
+ description: `Text to find as the start anchor (use ${START_OF_FILE} for file start)`,
49052
+ required: false,
49053
+ usageValue: "Text before the edit location"
49054
+ },
49055
+ {
49056
+ name: "after_text",
49057
+ description: `Text to find as the end anchor (use ${END_OF_FILE} for file end)`,
49058
+ required: false,
49059
+ usageValue: "Text after the edit location"
49060
+ },
49061
+ {
49062
+ name: "new_text",
49063
+ description: "Text to replace the content between before_text and after_text",
49064
+ required: true,
49065
+ usageValue: "New text content"
49066
+ },
49067
+ {
49068
+ name: "before_text_line_start",
49069
+ description: "Optional line number hint for before_text location (1-based)",
49070
+ required: false,
49071
+ usageValue: "10"
49072
+ },
49073
+ {
49074
+ name: "after_text_line_start",
49075
+ description: "Optional line number hint for after_text location (1-based)",
49076
+ required: false,
49077
+ usageValue: "20"
49078
+ }
49079
+ ],
49080
+ usageValue: "operations here"
49081
+ }
49082
+ ],
49083
+ examples: [
49084
+ {
49085
+ description: "Replace content between two text anchors",
49086
+ parameters: [
49087
+ {
49088
+ name: "path",
49089
+ value: "src/main.ts"
49090
+ },
49091
+ {
49092
+ name: "operations",
49093
+ value: {
49094
+ before_text: "function oldFunction() {",
49095
+ after_text: "}",
49096
+ new_text: `
49097
+ return "new implementation";
49098
+ `
49099
+ }
49100
+ }
49101
+ ]
49102
+ },
49103
+ {
49104
+ description: "Insert at start of file",
49105
+ parameters: [
49106
+ {
49107
+ name: "path",
49108
+ value: "src/header.ts"
49109
+ },
49110
+ {
49111
+ name: "operations",
49112
+ value: {
49113
+ before_text: START_OF_FILE,
49114
+ after_text: "export",
49115
+ new_text: `// File header comment
49116
+ `
49117
+ }
49118
+ }
49119
+ ]
49120
+ },
49121
+ {
49122
+ description: "Multiple operations in one call",
49123
+ parameters: [
49124
+ {
49125
+ name: "path",
49126
+ value: "src/utils.ts"
49127
+ },
49128
+ {
49129
+ name: "operations",
49130
+ value: [
49131
+ {
49132
+ before_text: "import React",
49133
+ after_text: 'from "react"',
49134
+ new_text: ", { useState }"
49135
+ },
49136
+ {
49137
+ before_text: "function Component() {",
49138
+ after_text: "return (",
49139
+ new_text: `
49140
+ const [state, setState] = useState(false);
49141
+ `
49142
+ }
49143
+ ]
49144
+ }
49145
+ ]
49146
+ }
49147
+ ],
49148
+ permissionLevel: 2 /* Write */
49149
+ };
49150
+ var handler13 = async (provider, args) => {
49151
+ if (!provider.readFile || !provider.writeFile) {
49152
+ return {
49153
+ type: "Error" /* Error */,
49154
+ message: "Not possible to edit file. Abort."
49155
+ };
49156
+ }
49157
+ const path = getString(args, "path");
49158
+ const operations = getArray(args, "operations");
49159
+ if (!operations || operations.length === 0) {
49160
+ return {
49161
+ type: "Error" /* Error */,
49162
+ message: `<error><edit_file_path>${path}</edit_file_path><error_message>At least one edit operation is required</error_message></error>`
49163
+ };
49164
+ }
49165
+ const fileContent = await provider.readFile(path);
49166
+ if (fileContent == null) {
49167
+ return {
49168
+ type: "Error" /* Error */,
49169
+ message: `<error><edit_file_path>${path}</edit_file_path><error_message>File not found</error_message></error>`
49170
+ };
49171
+ }
49172
+ try {
49173
+ const result = await editFile(fileContent, operations);
49174
+ await provider.writeFile(path, result);
49175
+ return {
49176
+ type: "Reply" /* Reply */,
49177
+ message: `<edit_file_path>${path}</edit_file_path>`
49178
+ };
49179
+ } catch (error) {
49180
+ return {
49181
+ type: "Error" /* Error */,
49182
+ message: `<error><edit_file_path>${path}</edit_file_path><error_message>${error instanceof Error ? error.message : String(error)}</error_message></error>`
49183
+ };
49184
+ }
49185
+ };
49186
+ var isAvailable13 = (provider) => {
49187
+ return !!provider.readFile && !!provider.writeFile;
49188
+ };
49189
+ var editFile_default = {
49063
49190
  ...toolInfo13,
49064
49191
  handler: handler13,
49065
49192
  isAvailable: isAvailable13
49066
49193
  };
49194
+ // ../core/src/tools/replaceInFile.ts
49195
+ var toolInfo14 = {
49196
+ name: "replace_in_file",
49197
+ description: "Request to replace sections of content in an existing file using SEARCH/REPLACE blocks that define exact changes to specific parts of the file. This tool should be used when you need to make targeted changes to specific parts of a file.",
49198
+ parameters: [
49199
+ {
49200
+ name: "path",
49201
+ description: "The path of the file to modify",
49202
+ required: true,
49203
+ usageValue: "File path here"
49204
+ },
49205
+ {
49206
+ name: "diff",
49207
+ description: `One or more SEARCH/REPLACE blocks following this exact format:
49208
+ \`\`\`
49209
+ <<<<<<< SEARCH
49210
+ [exact content to find]
49211
+ =======
49212
+ [new content to replace with]
49213
+ >>>>>>> REPLACE
49214
+ \`\`\`
49215
+ Critical rules:
49216
+ 1. SEARCH content must match the associated file section to find EXACTLY:
49217
+ * Match character-for-character including whitespace, indentation, line endings
49218
+ * Include all comments, docstrings, etc.
49219
+ 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
49220
+ * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
49221
+ * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
49222
+ * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
49223
+ 3. Keep SEARCH/REPLACE blocks concise:
49224
+ * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
49225
+ * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
49226
+ * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
49227
+ * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
49228
+ 4. Special operations:
49229
+ * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
49230
+ * To delete code: Use empty REPLACE section`,
49231
+ required: true,
49232
+ usageValue: "Search and replace blocks here"
49233
+ }
49234
+ ],
49235
+ examples: [
49236
+ {
49237
+ description: "Request to replace sections of content in a file",
49238
+ parameters: [
49239
+ {
49240
+ name: "path",
49241
+ value: "src/main.js"
49242
+ },
49243
+ {
49244
+ name: "diff",
49245
+ value: `
49246
+ <<<<<<< SEARCH
49247
+ import React from 'react';
49248
+ =======
49249
+ import React, { useState } from 'react';
49250
+ >>>>>>> REPLACE
49251
+
49252
+ <<<<<<< SEARCH
49253
+ function handleSubmit() {
49254
+ saveData();
49255
+ setLoading(false);
49256
+ }
49257
+
49258
+ =======
49259
+ >>>>>>> REPLACE
49260
+
49261
+ <<<<<<< SEARCH
49262
+ return (
49263
+ <div>
49264
+ =======
49265
+ function handleSubmit() {
49266
+ saveData();
49267
+ setLoading(false);
49268
+ }
49269
+
49270
+ return (
49271
+ <div>
49272
+ >>>>>>> REPLACE
49273
+ `
49274
+ }
49275
+ ]
49276
+ }
49277
+ ],
49278
+ permissionLevel: 2 /* Write */
49279
+ };
49280
+ var handler14 = async (provider, args) => {
49281
+ if (!provider.readFile || !provider.writeFile) {
49282
+ return {
49283
+ type: "Error" /* Error */,
49284
+ message: "Not possible to replace in file. Abort."
49285
+ };
49286
+ }
49287
+ const path = getString(args, "path");
49288
+ const diff = getString(args, "diff");
49289
+ const fileContent = await provider.readFile(path);
49290
+ if (fileContent == null) {
49291
+ return {
49292
+ type: "Error" /* Error */,
49293
+ message: `<error><replace_in_file_path>${path}</replace_in_file_path><error_message>File not found</error_message></error>`
49294
+ };
49295
+ }
49296
+ const result = await replaceInFile(fileContent, diff);
49297
+ await provider.writeFile(path, result);
49298
+ return {
49299
+ type: "Reply" /* Reply */,
49300
+ message: `<replace_in_file_path>${path}</replace_in_file_path>`
49301
+ };
49302
+ };
49303
+ var isAvailable14 = (provider) => {
49304
+ return !!provider.readFile && !!provider.writeFile;
49305
+ };
49306
+ var replaceInFile_default = {
49307
+ ...toolInfo14,
49308
+ handler: handler14,
49309
+ isAvailable: isAvailable14
49310
+ };
49067
49311
  // ../core/src/getAvailableTools.ts
49068
49312
  var getAvailableTools = ({
49069
49313
  provider: provider2,
@@ -49480,6 +49724,9 @@ ${instance.prompt}`;
49480
49724
  this.config = config;
49481
49725
  this.#policies = policies;
49482
49726
  }
49727
+ get parameters() {
49728
+ return this.ai.options.parameters;
49729
+ }
49483
49730
  get messages() {
49484
49731
  return this.#messages;
49485
49732
  }
@@ -49676,8 +49923,8 @@ ${instance.prompt}`;
49676
49923
  }
49677
49924
  async#invokeTool(name, args) {
49678
49925
  try {
49679
- const handler14 = this.handlers[name]?.handler;
49680
- if (!handler14) {
49926
+ const handler15 = this.handlers[name]?.handler;
49927
+ if (!handler15) {
49681
49928
  return {
49682
49929
  type: "Error" /* Error */,
49683
49930
  message: responsePrompts.errorInvokeTool(name, "Tool not found"),
@@ -49696,7 +49943,7 @@ ${instance.prompt}`;
49696
49943
  if (resp) {
49697
49944
  return resp;
49698
49945
  }
49699
- return await handler14(this.config.provider, args);
49946
+ return await handler15(this.config.provider, args);
49700
49947
  } catch (error) {
49701
49948
  return {
49702
49949
  type: "Error" /* Error */,
@@ -50035,7 +50282,7 @@ var editingFilesPrompt = (toolNamePrefix) => `
50035
50282
 
50036
50283
  EDITING FILES
50037
50284
 
50038
- You have access to two tools for working with files: **${toolNamePrefix}write_to_file** and **${toolNamePrefix}replace_in_file**. Understanding their roles and selecting the right one for the job will help ensure efficient and accurate modifications.
50285
+ You have two file-manipulation tools: **${toolNamePrefix}write_to_file** (full overwrite) and **${toolNamePrefix}edit_file** (targeted anchor-based edits). Choose the smallest safe operation for every change.
50039
50286
 
50040
50287
  # ${toolNamePrefix}write_to_file
50041
50288
 
@@ -50047,16 +50294,16 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
50047
50294
 
50048
50295
  - Initial file creation, such as when scaffolding a new project.
50049
50296
  - Overwriting large boilerplate files where you want to replace the entire content at once.
50050
- - When the complexity or number of changes would make ${toolNamePrefix}replace_in_file unwieldy or error-prone.
50297
+ - When the complexity or number of changes would make ${toolNamePrefix}edit_file unwieldy or error-prone.
50051
50298
  - When you need to completely restructure a file's content or change its fundamental organization.
50052
50299
 
50053
50300
  ## Important Considerations
50054
50301
 
50055
50302
  - Using ${toolNamePrefix}write_to_file requires providing the file's complete final content.
50056
- - If you only need to make small changes to an existing file, consider using ${toolNamePrefix}replace_in_file instead to avoid unnecessarily rewriting the entire file.
50303
+ - If you only need to make small changes to an existing file, consider using ${toolNamePrefix}edit_file instead to avoid unnecessarily rewriting the entire file.
50057
50304
  - While ${toolNamePrefix}write_to_file should not be your default choice, don't hesitate to use it when the situation truly calls for it.
50058
50305
 
50059
- # ${toolNamePrefix}replace_in_file
50306
+ # ${toolNamePrefix}edit_file
50060
50307
 
50061
50308
  ## Purpose
50062
50309
 
@@ -50075,10 +50322,10 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
50075
50322
 
50076
50323
  # Choosing the Appropriate Tool
50077
50324
 
50078
- - **Default to ${toolNamePrefix}replace_in_file** for most changes. It's the safer, more precise option that minimizes potential issues.
50325
+ - **Default to ${toolNamePrefix}edit_file** for most changes. It keeps diffs small and reduces risk.
50079
50326
  - **Use ${toolNamePrefix}write_to_file** when:
50080
50327
  - Creating new files
50081
- - The changes are so extensive that using ${toolNamePrefix}replace_in_file would be more complex or risky
50328
+ - The changes are so extensive that using ${toolNamePrefix}edit_file would be more complex or risky
50082
50329
  - You need to completely reorganize or restructure a file
50083
50330
  - The file is relatively small and the changes affect most of its content
50084
50331
  - You're generating boilerplate or template files
@@ -50086,11 +50333,12 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
50086
50333
  # Workflow Tips
50087
50334
 
50088
50335
  1. Before editing, assess the scope of your changes and decide which tool to use.
50089
- 2. For targeted edits, apply ${toolNamePrefix}replace_in_file with carefully crafted SEARCH/REPLACE blocks. If you need multiple changes, you can stack multiple SEARCH/REPLACE blocks within a single ${toolNamePrefix}replace_in_file call.
50336
+ 2. For targeted edits, apply ${toolNamePrefix}edit_file with carefully crafted before/after text anchors. If you need multiple changes, you can stack multiple operations within a single ${toolNamePrefix}edit_file call.
50090
50337
  3. For major overhauls or initial file creation, rely on ${toolNamePrefix}write_to_file.
50091
- 4. Once the file has been edited with either ${toolNamePrefix}write_to_file or ${toolNamePrefix}replace_in_file, the system will provide you with the final state of the modified file. Use this updated content as the reference point for any subsequent SEARCH/REPLACE operations, since it reflects any auto-formatting or user-applied changes.
50338
+ 4. Once the file has been edited with either ${toolNamePrefix}write_to_file or ${toolNamePrefix}edit_file, the system will provide you with the final state of the modified file. Use this updated content as the reference point for any subsequent operations, since it reflects any auto-formatting or user-applied changes.
50092
50339
 
50093
- By thoughtfully selecting between ${toolNamePrefix}write_to_file and ${toolNamePrefix}replace_in_file, you can make your file editing process smoother, safer, and more efficient.`;
50340
+ Picking the right tool keeps edits minimal, safe, and easy to review.
50341
+ `;
50094
50342
  var rules = (toolNamePrefix) => `
50095
50343
  ====
50096
50344
 
@@ -50101,10 +50349,10 @@ RULES
50101
50349
  For text files (e.g. README.md), append a footer with the same notice.
50102
50350
  - Never describe what changed inside code comments; comments must focus on purpose or usage only.
50103
50351
  - Before using ${toolNamePrefix}execute_command, consider SYSTEM INFORMATION to ensure commands suit the user's OS. If a command must run in a subdirectory, prepend a single \`cd childDir &&\` segment.
50104
- - Use ${toolNamePrefix}search_files for broad analysis, then ${toolNamePrefix}read_file to inspect context, and finally ${toolNamePrefix}replace_in_file or ${toolNamePrefix}write_to_file to modify.
50105
- - Prefer ${toolNamePrefix}replace_in_file for focused edits; choose ${toolNamePrefix}write_to_file for new files or complete rewrites.
50352
+ - Use ${toolNamePrefix}search_files for broad analysis, then ${toolNamePrefix}read_file to inspect context, and finally ${toolNamePrefix}edit_file or ${toolNamePrefix}write_to_file to modify.
50353
+ - Prefer ${toolNamePrefix}edit_file for focused edits; choose ${toolNamePrefix}write_to_file for new files or complete rewrites.
50106
50354
  - When creating a new file, look for existing files with similar content or patterns; if found, read them and use their structure or conventions as a reference.
50107
- - SEARCH blocks in ${toolNamePrefix}replace_in_file must match whole lines. If multiple blocks are needed, list them in file order.
50355
+ - Use before/after text anchors in ${toolNamePrefix}edit_file to target changes. If multiple operations are needed, list them in file order.
50108
50356
  - Do not guess unseen content. Read existing files first unless creating new ones.
50109
50357
  - Follow existing style, lint, and naming conventions. Ensure all changes compile and pass tests where applicable.
50110
50358
  - ALWAYS wait for the user's confirmation after each tool call before starting the next step.
@@ -59537,15 +59785,15 @@ function useKeypress(userHandler) {
59537
59785
  signal.current = userHandler;
59538
59786
  useEffect((rl) => {
59539
59787
  let ignore = false;
59540
- const handler14 = withUpdates((_input, event) => {
59788
+ const handler15 = withUpdates((_input, event) => {
59541
59789
  if (ignore)
59542
59790
  return;
59543
59791
  signal.current(event, rl);
59544
59792
  });
59545
- rl.input.on("keypress", handler14);
59793
+ rl.input.on("keypress", handler15);
59546
59794
  return () => {
59547
59795
  ignore = true;
59548
- rl.input.removeListener("keypress", handler14);
59796
+ rl.input.removeListener("keypress", handler15);
59549
59797
  };
59550
59798
  }, []);
59551
59799
  }
@@ -59727,16 +59975,16 @@ class Emitter {
59727
59975
 
59728
59976
  class SignalExitBase {
59729
59977
  }
59730
- var signalExitWrap = (handler14) => {
59978
+ var signalExitWrap = (handler15) => {
59731
59979
  return {
59732
59980
  onExit(cb, opts) {
59733
- return handler14.onExit(cb, opts);
59981
+ return handler15.onExit(cb, opts);
59734
59982
  },
59735
59983
  load() {
59736
- return handler14.load();
59984
+ return handler15.load();
59737
59985
  },
59738
59986
  unload() {
59739
- return handler14.unload();
59987
+ return handler15.unload();
59740
59988
  }
59741
59989
  };
59742
59990
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polka-codes/cli",
3
- "version": "0.8.11",
3
+ "version": "0.8.12",
4
4
  "license": "AGPL-3.0",
5
5
  "author": "github@polka.codes",
6
6
  "type": "module",