@polka-codes/runner 0.9.4 → 0.9.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 (2) hide show
  1. package/dist/index.js +273 -28
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -21008,7 +21008,7 @@ var {
21008
21008
  Help
21009
21009
  } = import__.default;
21010
21010
  // package.json
21011
- var version = "0.9.4";
21011
+ var version = "0.9.6";
21012
21012
 
21013
21013
  // src/runner.ts
21014
21014
  import { execSync } from "node:child_process";
@@ -32488,7 +32488,17 @@ var toolInfo7 = {
32488
32488
  return true;
32489
32489
  }
32490
32490
  return val;
32491
- }, exports_external.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" })
32491
+ }, exports_external.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" }),
32492
+ includeIgnored: exports_external.preprocess((val) => {
32493
+ if (typeof val === "string") {
32494
+ const lower = val.toLowerCase();
32495
+ if (lower === "false")
32496
+ return false;
32497
+ if (lower === "true")
32498
+ return true;
32499
+ }
32500
+ return val;
32501
+ }, exports_external.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
32492
32502
  }).meta({
32493
32503
  examples: [
32494
32504
  {
@@ -32509,8 +32519,8 @@ var handler7 = async (provider, args) => {
32509
32519
  message: "Not possible to list files. Abort."
32510
32520
  };
32511
32521
  }
32512
- const { path, maxCount, recursive } = toolInfo7.parameters.parse(args);
32513
- const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
32522
+ const { path, maxCount, recursive, includeIgnored } = toolInfo7.parameters.parse(args);
32523
+ const [files, limitReached] = await provider.listFiles(path, recursive, maxCount, includeIgnored);
32514
32524
  return {
32515
32525
  type: "Reply" /* Reply */,
32516
32526
  message: `<list_files_path>${path}</list_files_path>
@@ -32539,7 +32549,17 @@ var toolInfo8 = {
32539
32549
  return [];
32540
32550
  const values = Array.isArray(val) ? val : [val];
32541
32551
  return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
32542
- }, exports_external.array(exports_external.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" })
32552
+ }, exports_external.array(exports_external.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" }),
32553
+ includeIgnored: exports_external.preprocess((val) => {
32554
+ if (typeof val === "string") {
32555
+ const lower = val.toLowerCase();
32556
+ if (lower === "false")
32557
+ return false;
32558
+ if (lower === "true")
32559
+ return true;
32560
+ }
32561
+ return val;
32562
+ }, exports_external.boolean().optional().default(false)).describe("Whether to include ignored files. Use true to include files ignored by .gitignore.").meta({ usageValue: "true or false (optional)" })
32543
32563
  }).meta({
32544
32564
  examples: [
32545
32565
  {
@@ -32565,10 +32585,10 @@ var handler8 = async (provider, args) => {
32565
32585
  message: "Not possible to read file. Abort."
32566
32586
  };
32567
32587
  }
32568
- const { path: paths } = toolInfo8.parameters.parse(args);
32588
+ const { path: paths, includeIgnored } = toolInfo8.parameters.parse(args);
32569
32589
  const resp = [];
32570
32590
  for (const path of paths) {
32571
- const fileContent = await provider.readFile(path);
32591
+ const fileContent = await provider.readFile(path, includeIgnored);
32572
32592
  if (!fileContent) {
32573
32593
  resp.push(`<read_file_file_content path="${path}" file_not_found="true" />`);
32574
32594
  } else {
@@ -32576,7 +32596,7 @@ var handler8 = async (provider, args) => {
32576
32596
  if (isEmpty) {
32577
32597
  resp.push(`<read_file_file_content path="${path}" is_empty="true" />`);
32578
32598
  } else {
32579
- resp.push(`<read_file_file_conten path="${path}">${fileContent}</read_file_file_content>`);
32599
+ resp.push(`<read_file_file_content path="${path}">${fileContent}</read_file_file_content>`);
32580
32600
  }
32581
32601
  }
32582
32602
  }
@@ -32876,9 +32896,16 @@ var handler11 = async (provider, args) => {
32876
32896
  message: "Not possible to replace in file. Abort."
32877
32897
  };
32878
32898
  }
32899
+ const parsed = toolInfo11.parameters.safeParse(args);
32900
+ if (!parsed.success) {
32901
+ return {
32902
+ type: "Invalid" /* Invalid */,
32903
+ message: `Invalid arguments for replace_in_file: ${parsed.error.message}`
32904
+ };
32905
+ }
32906
+ const { path, diff } = parsed.data;
32879
32907
  try {
32880
- const { path, diff } = toolInfo11.parameters.parse(args);
32881
- const fileContent = await provider.readFile(path);
32908
+ const fileContent = await provider.readFile(path, false);
32882
32909
  if (fileContent == null) {
32883
32910
  return {
32884
32911
  type: "Error" /* Error */,
@@ -32955,8 +32982,15 @@ var handler12 = async (provider, args) => {
32955
32982
  message: "Not possible to search files. Abort."
32956
32983
  };
32957
32984
  }
32985
+ const parsed = toolInfo12.parameters.safeParse(args);
32986
+ if (!parsed.success) {
32987
+ return {
32988
+ type: "Invalid" /* Invalid */,
32989
+ message: `Invalid arguments for search_files: ${parsed.error.message}`
32990
+ };
32991
+ }
32992
+ const { path, regex, filePattern } = parsed.data;
32958
32993
  try {
32959
- const { path, regex, filePattern } = toolInfo12.parameters.parse(args);
32960
32994
  const files = await provider.searchFiles(path, regex, filePattern ?? "*");
32961
32995
  return {
32962
32996
  type: "Reply" /* Reply */,
@@ -32971,8 +33005,8 @@ ${files.join(`
32971
33005
  };
32972
33006
  } catch (error40) {
32973
33007
  return {
32974
- type: "Invalid" /* Invalid */,
32975
- message: `Invalid arguments for search_files: ${error40}`
33008
+ type: "Error" /* Error */,
33009
+ message: `Error searching files: ${error40}`
32976
33010
  };
32977
33011
  }
32978
33012
  };
@@ -56323,6 +56357,7 @@ ${instance.prompt}`;
56323
56357
  resetTimeout();
56324
56358
  const streamTextOptions = {
56325
56359
  model: this.ai,
56360
+ temperature: 0,
56326
56361
  messages,
56327
56362
  providerOptions: this.config.parameters?.providerOptions,
56328
56363
  onChunk: async ({ chunk }) => {
@@ -56391,6 +56426,14 @@ ${instance.prompt}`;
56391
56426
  }
56392
56427
  this.#messages.push(...respMessages);
56393
56428
  if (this.config.toolFormat === "native") {
56429
+ const assistantText = respMessages.map((msg) => {
56430
+ if (typeof msg.content === "string") {
56431
+ return msg.content;
56432
+ }
56433
+ return msg.content.map((part) => part.type === "text" || part.type === "reasoning" ? part.text : "").join("");
56434
+ }).join(`
56435
+ `);
56436
+ await this.#callback({ kind: "EndRequest" /* EndRequest */, agent: this, message: assistantText });
56394
56437
  return respMessages.flatMap((msg) => {
56395
56438
  if (msg.role === "assistant") {
56396
56439
  const content = msg.content;
@@ -56823,6 +56866,196 @@ var codeFixerAgentInfo = {
56823
56866
  "Tracking and reporting unfixed issues"
56824
56867
  ]
56825
56868
  };
56869
+
56870
+ // ../core/src/Agent/CoderAgent/prompts.ts
56871
+ var basePrompt2 = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.";
56872
+ var editingFilesPrompt = (toolNamePrefix) => `
56873
+ ====
56874
+
56875
+ EDITING FILES
56876
+
56877
+ You have two file-manipulation tools: **${toolNamePrefix}write_to_file** (full overwrite) and **${toolNamePrefix}replace_in_file** (targeted anchor-based edits). Choose the smallest safe operation for every change.
56878
+
56879
+ # ${toolNamePrefix}write_to_file
56880
+
56881
+ ## Purpose
56882
+
56883
+ - Create a new file, or overwrite the entire contents of an existing file.
56884
+
56885
+ ## When to Use
56886
+
56887
+ - Initial file creation, such as when scaffolding a new project.
56888
+ - Overwriting large boilerplate files where you want to replace the entire content at once.
56889
+ - When the complexity or number of changes would make ${toolNamePrefix}replace_in_file unwieldy or error-prone.
56890
+ - When you need to completely restructure a file's content or change its fundamental organization.
56891
+
56892
+ ## Important Considerations
56893
+
56894
+ - Using ${toolNamePrefix}write_to_file requires providing the file's complete final content.
56895
+ - 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.
56896
+ - While ${toolNamePrefix}write_to_file should not be your default choice, don't hesitate to use it when the situation truly calls for it.
56897
+
56898
+ # ${toolNamePrefix}replace_in_file
56899
+
56900
+ ## Purpose
56901
+
56902
+ - Make targeted edits to specific parts of an existing file without overwriting the entire file.
56903
+
56904
+ ## When to Use
56905
+
56906
+ - Small, localized changes like updating a few lines, function implementations, changing variable names, modifying a section of text, etc.
56907
+ - Targeted improvements where only specific portions of the file's content needs to be altered.
56908
+ - Especially useful for long files where much of the file will remain unchanged.
56909
+
56910
+ ## Advantages
56911
+
56912
+ - More efficient for minor edits, since you don't need to supply the entire file content.
56913
+ - Reduces the chance of errors that can occur when overwriting large files.
56914
+
56915
+ # Choosing the Appropriate Tool
56916
+
56917
+ - **Default to ${toolNamePrefix}replace_in_file** for most changes. It keeps diffs small and reduces risk.
56918
+ - **Use ${toolNamePrefix}write_to_file** when:
56919
+ - Creating new files
56920
+ - The changes are so extensive that using ${toolNamePrefix}replace_in_file would be more complex or risky
56921
+ - You need to completely reorganize or restructure a file
56922
+ - The file is relatively small and the changes affect most of its content
56923
+ - You're generating boilerplate or template files
56924
+
56925
+ # Workflow Tips
56926
+
56927
+ 1. Before editing, assess the scope of your changes and decide which tool to use.
56928
+ 2. For targeted edits, apply ${toolNamePrefix}replace_in_file with carefully crafted before/after text anchors. If you need multiple changes, you can stack multiple operations within a single ${toolNamePrefix}replace_in_file call.
56929
+ 3. For major overhauls or initial file creation, rely on ${toolNamePrefix}write_to_file.
56930
+ 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 operations, since it reflects any auto-formatting or user-applied changes.
56931
+
56932
+ Picking the right tool keeps edits minimal, safe, and easy to review.
56933
+ `;
56934
+ var rules = (toolNamePrefix) => `
56935
+ ====
56936
+
56937
+ RULES
56938
+
56939
+ - Work only with relative paths; you may \`cd\` into child directories but never use \`cd ..\`, root, or absolute paths.
56940
+ - When generating code, tests, or other comment-capable files, prepend a comment describing the file's purpose plus “generated by polka.codes”.
56941
+ For text files (e.g. README.md), append a footer with the same notice.
56942
+ - Never describe what changed inside code comments; comments must focus on purpose or usage only.
56943
+ - 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.
56944
+ - 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.
56945
+ - Prefer ${toolNamePrefix}replace_in_file for focused edits; choose ${toolNamePrefix}write_to_file for new files or complete rewrites.
56946
+ - 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.
56947
+ - Use before/after text anchors in ${toolNamePrefix}replace_in_file to target changes. If multiple operations are needed, list them in file order.
56948
+ - Do not guess unseen content. Read existing files first unless creating new ones.
56949
+ - Follow existing style, lint, and naming conventions. Ensure all changes compile and pass tests where applicable.
56950
+ - ALWAYS wait for the user's confirmation after each tool call before starting the next step.
56951
+ - The agent must never invoke more than 5 tools in a single response.
56952
+ - Do not end ${toolNamePrefix}attempt_completion output with questions or conversational prompts.
56953
+ - Avoid filler words like “Great”, “Certainly”, “Okay”, “Sure” at the start of responses; be direct and technical.
56954
+ - Keep inline documentation current as you edit.
56955
+ `;
56956
+ var objectives = (toolNamePrefix) => `
56957
+ ====
56958
+
56959
+ OBJECTIVE
56960
+
56961
+ You solve the user's task by working in small, verifiable steps.
56962
+
56963
+ 1. **Plan** - Parse the task, list clear goals, and order them logically.
56964
+ 2. **Think** - Wrap private reasoning in <thinking></thinking>.
56965
+ • Review project context.
56966
+ • Select the single best tool for the next goal.
56967
+ • Ensure every required parameter is available or can be inferred.
56968
+ 3. **Act** - Invoke one tool per step. Wait for the system's response (and user confirmation where required) before continuing.
56969
+ 4. **Iterate** - Repeat Plan → Think → Act until all goals are complete.
56970
+ 5. **Complete** - Use ${toolNamePrefix}attempt_completion to deliver the final result. Do not invite further discussion unless the user explicitly requests changes.
56971
+ `;
56972
+ var fullSystemPrompt4 = (info, tools, toolNamePrefix, instructions, scripts, useNativeTool) => `
56973
+ ${basePrompt2}
56974
+ ${useNativeTool ? "" : toolUsePrompt(tools, toolNamePrefix)}
56975
+ ${editingFilesPrompt(toolNamePrefix)}
56976
+ ${capabilities(toolNamePrefix)}
56977
+ ${rules(toolNamePrefix)}
56978
+ ${objectives(toolNamePrefix)}
56979
+ ${systemInformation(info)}
56980
+ ${customInstructions(instructions)}
56981
+ ${customScripts(scripts)}
56982
+ `;
56983
+
56984
+ // ../core/src/Agent/CoderAgent/index.ts
56985
+ class CoderAgent extends AgentBase {
56986
+ constructor(options) {
56987
+ const combinedTools = [...options.additionalTools ?? [], ...Object.values(exports_allTools)];
56988
+ const tools = getAvailableTools({
56989
+ provider: options.provider,
56990
+ allTools: combinedTools,
56991
+ hasAgent: (options.agents?.length ?? 0) > 0,
56992
+ permissionLevel: 3 /* Arbitrary */,
56993
+ interactive: true
56994
+ });
56995
+ const toolNamePrefix = options.toolFormat === "native" ? "" : "tool_";
56996
+ const systemPrompt = fullSystemPrompt4({
56997
+ os: options.os
56998
+ }, tools, toolNamePrefix, options.customInstructions ?? [], options.scripts ?? {}, options.toolFormat === "native");
56999
+ super(coderAgentInfo.name, options.ai, {
57000
+ systemPrompt,
57001
+ tools,
57002
+ toolNamePrefix,
57003
+ provider: options.provider,
57004
+ interactive: options.interactive,
57005
+ agents: options.agents,
57006
+ scripts: options.scripts,
57007
+ callback: options.callback,
57008
+ policies: options.policies,
57009
+ toolFormat: options.toolFormat,
57010
+ parameters: options.parameters ?? {},
57011
+ usageMeter: options.usageMeter ?? new UsageMeter
57012
+ });
57013
+ }
57014
+ async#runScript(scriptName, shouldReplyWithError) {
57015
+ const executeCommand = this.config.provider.executeCommand;
57016
+ if (!executeCommand) {
57017
+ return;
57018
+ }
57019
+ const script = this.config.scripts?.[scriptName];
57020
+ const command = typeof script === "string" ? script : script?.command;
57021
+ if (command) {
57022
+ try {
57023
+ const { exitCode, stdout, stderr } = await executeCommand(command, false);
57024
+ if (exitCode !== 0 && shouldReplyWithError) {
57025
+ return {
57026
+ type: "Reply" /* Reply */,
57027
+ message: responsePrompts.commandResult(command, exitCode, stdout, stderr)
57028
+ };
57029
+ }
57030
+ } catch (error81) {
57031
+ console.warn(`Failed to run ${scriptName} using command: ${command}`, error81);
57032
+ }
57033
+ }
57034
+ }
57035
+ async onBeforeInvokeTool(name17, _args) {
57036
+ if (name17 !== attemptCompletion_default.name) {
57037
+ return;
57038
+ }
57039
+ await this.#runScript("format", false);
57040
+ const checkResult = await this.#runScript("check", true);
57041
+ if (checkResult) {
57042
+ return checkResult;
57043
+ }
57044
+ const testResult = await this.#runScript("test", true);
57045
+ if (testResult) {
57046
+ return testResult;
57047
+ }
57048
+ }
57049
+ }
57050
+ var coderAgentInfo = {
57051
+ name: "coder",
57052
+ responsibilities: [
57053
+ "Editing and refactoring existing code.",
57054
+ "Creating new features or modules.",
57055
+ "Running tests and analyzing test results.",
57056
+ "Maintaining coding standards, lint rules, and general code quality."
57057
+ ]
57058
+ };
56826
57059
  // ../core/src/Agent/MultiAgent.ts
56827
57060
  class MultiAgent {
56828
57061
  #config;
@@ -57168,10 +57401,18 @@ Example Output:
57168
57401
  <tool_output>
57169
57402
  <tool_output_pr_title>Refactor Order Validation and Remove Debug Logs</tool_output_pr_title>
57170
57403
  <tool_output_pr_description>
57171
- closes #123
57404
+ Closes #123
57405
+
57406
+ **Context**:
57407
+ - Implementing changes for issue #123 - Focus on clean code and maintainability
57172
57408
 
57173
- This PR removes unnecessary debug print statements and updates order validation
57174
- to use the new validate_and_process method for improved maintainability.
57409
+ **Summary of Changes**:
57410
+ - Refactored order validation logic to use a new \`validate_and_process\` method.
57411
+ - Removed debug print statements from \`user_service.py\`.
57412
+
57413
+ **Highlights of Changed Code**:
57414
+ - \`order_service.py\`: Replaced direct call to \`process_order\` with \`validate_and_process\`.
57415
+ - \`user_service.py\`: Removed \`print("Debug info")\`.
57175
57416
  </tool_output_pr_description>
57176
57417
  </tool_output>
57177
57418
 
@@ -57472,6 +57713,7 @@ ${output}`,
57472
57713
  var executeTool = async (definition, ai, params, usageMeter) => {
57473
57714
  const resp = await generateText({
57474
57715
  model: ai,
57716
+ temperature: 0,
57475
57717
  system: definition.prompt,
57476
57718
  messages: [
57477
57719
  {
@@ -62819,13 +63061,16 @@ async function extendPatterns(basePatterns, dirPath) {
62819
63061
  function createIgnore(patterns) {
62820
63062
  return import_ignore.default().add(patterns);
62821
63063
  }
62822
- async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
62823
- let rootPatterns = [...DEFAULT_IGNORES, ...excludeFiles || []];
62824
- try {
62825
- const rootGitignore = await fs.readFile(join2(cwd, ".gitignore"), "utf8");
62826
- const lines = rootGitignore.split(/\r?\n/).filter(Boolean);
62827
- rootPatterns = [...rootPatterns, ...lines];
62828
- } catch {}
63064
+ async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles, includeIgnored) {
63065
+ let rootPatterns = [...excludeFiles || []];
63066
+ if (!includeIgnored) {
63067
+ rootPatterns.push(...DEFAULT_IGNORES);
63068
+ try {
63069
+ const rootGitignore = await fs.readFile(join2(cwd, ".gitignore"), "utf8");
63070
+ const lines = rootGitignore.split(/\r?\n/).filter(Boolean);
63071
+ rootPatterns = [...rootPatterns, ...lines];
63072
+ } catch {}
63073
+ }
62829
63074
  const results = [];
62830
63075
  const processedDirs = new Set;
62831
63076
  const queue = [
@@ -62838,7 +63083,7 @@ async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
62838
63083
  while (queue.length > 0) {
62839
63084
  const { path: currentPath, patterns: parentPatterns, relPath: currentRelPath } = queue.shift();
62840
63085
  processedDirs.add(currentRelPath);
62841
- const mergedPatterns = await extendPatterns(parentPatterns, currentPath);
63086
+ const mergedPatterns = includeIgnored ? parentPatterns : await extendPatterns(parentPatterns, currentPath);
62842
63087
  const folderIg = createIgnore(mergedPatterns);
62843
63088
  const entries = await fs.readdir(currentPath, { withFileTypes: true });
62844
63089
  entries.sort((a, b) => a.name.localeCompare(b.name));
@@ -62934,8 +63179,8 @@ async function searchFiles(path, regex, filePattern, cwd, excludeFiles) {
62934
63179
  var getProvider = (_agentName, _config, options = {}) => {
62935
63180
  const ig = import_ignore2.default().add(options.excludeFiles ?? []);
62936
63181
  const provider2 = {
62937
- readFile: async (path) => {
62938
- if (ig.ignores(path)) {
63182
+ readFile: async (path, includeIgnored) => {
63183
+ if (!includeIgnored && ig.ignores(path)) {
62939
63184
  throw new Error(`Not allow to access file ${path}`);
62940
63185
  }
62941
63186
  try {
@@ -62963,8 +63208,8 @@ var getProvider = (_agentName, _config, options = {}) => {
62963
63208
  }
62964
63209
  return await rename(sourcePath, targetPath);
62965
63210
  },
62966
- listFiles: async (path, recursive, maxCount) => {
62967
- return await listFiles(path, recursive, maxCount, process.cwd(), options.excludeFiles);
63211
+ listFiles: async (path, recursive, maxCount, includeIgnored) => {
63212
+ return await listFiles(path, recursive, maxCount, process.cwd(), options.excludeFiles, includeIgnored);
62968
63213
  },
62969
63214
  executeCommand: (command, _needApprove) => {
62970
63215
  return new Promise((resolve3, reject) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polka-codes/runner",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "license": "AGPL-3.0",
5
5
  "author": "github@polka.codes",
6
6
  "type": "module",
@@ -17,8 +17,8 @@
17
17
  "build": "bun build src/index.ts --outdir dist --target node"
18
18
  },
19
19
  "dependencies": {
20
- "@polka-codes/cli-shared": "0.9.1",
21
- "@polka-codes/core": "0.9.1",
20
+ "@polka-codes/cli-shared": "0.9.4",
21
+ "@polka-codes/core": "0.9.4",
22
22
  "commander": "^13.0.0",
23
23
  "dotenv": "^16.4.7",
24
24
  "ignore": "^7.0.3",