@polka-codes/cli 0.4.10 → 0.5.1

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 +532 -407
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10053,15 +10053,15 @@ var require_route = __commonJS((exports, module) => {
10053
10053
  };
10054
10054
  }
10055
10055
  function wrapConversion(toModel, graph) {
10056
- const path2 = [graph[toModel].parent, toModel];
10056
+ const path = [graph[toModel].parent, toModel];
10057
10057
  let fn = conversions[graph[toModel].parent][toModel];
10058
10058
  let cur = graph[toModel].parent;
10059
10059
  while (graph[cur].parent) {
10060
- path2.unshift(graph[cur].parent);
10060
+ path.unshift(graph[cur].parent);
10061
10061
  fn = link(conversions[graph[cur].parent][cur], fn);
10062
10062
  cur = graph[cur].parent;
10063
10063
  }
10064
- fn.conversion = path2;
10064
+ fn.conversion = path;
10065
10065
  return fn;
10066
10066
  }
10067
10067
  module.exports = function(fromModel) {
@@ -24629,7 +24629,7 @@ var {
24629
24629
  Help
24630
24630
  } = import__.default;
24631
24631
  // package.json
24632
- var version = "0.4.10";
24632
+ var version = "0.5.1";
24633
24633
 
24634
24634
  // ../../node_modules/@anthropic-ai/sdk/version.mjs
24635
24635
  var VERSION = "0.36.2";
@@ -33262,7 +33262,7 @@ var toolInfo = {
33262
33262
  },
33263
33263
  {
33264
33264
  name: "options",
33265
- description: "A comma separated list of possible answers to the question. If not provided, the user will be prompted to provide an answer.",
33265
+ description: "A comma separated list of possible answers to the question. Ordered by preference. If not provided, the user will be prompted to provide an answer.",
33266
33266
  required: false,
33267
33267
  usageValue: "A comma separated list of possible answers (optional)"
33268
33268
  }
@@ -34874,8 +34874,80 @@ class MultiAgent {
34874
34874
 
34875
34875
  // ../core/src/Agent/index.ts
34876
34876
  var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo];
34877
+ // ../core/src/AiTool/createNewProject.ts
34878
+ var prompt = `You are an AiTool designed to assist users in creating new projects. Follow these guidelines:
34879
+
34880
+ 1. **Gather Information:**
34881
+ - Begin by asking the user for essential project details, including:
34882
+ - Project type (e.g., web, mobile, desktop, etc.)
34883
+ - Desired programming languages
34884
+ - Preferred frameworks or libraries
34885
+ - Build tools and package manager preferences
34886
+ - Testing frameworks and patterns
34887
+ - Code style and linting preferences
34888
+ - Any additional specifications or requirements
34889
+
34890
+ 2. **Clarification & Confirmation:**
34891
+ - Do not make any decisions or assumptions on behalf of the user.
34892
+ - Ask clarifying questions if any detail is ambiguous.
34893
+ - Confirm each piece of information with the user before proceeding to the next step.
34894
+
34895
+ 3. **Avoid Redundancy:**
34896
+ - Do not repeat questions or details that have already been confirmed.
34897
+ - Keep interactions concise and focused on gathering complete and accurate details.
34898
+
34899
+ 4. **Generate Configuration:**
34900
+ - Based on the collected information, generate a .polkacodes.yml configuration file that includes:
34901
+ - scripts section with common development commands (test, format, check, etc.)
34902
+ - rules section reflecting project conventions and tools
34903
+ - excludeFiles section for sensitive and generated files
34904
+ - Example structure:
34905
+ \`\`\`yaml
34906
+ scripts:
34907
+ test:
34908
+ command: "[test-command]"
34909
+ description: "Run tests"
34910
+ format:
34911
+ command: "[format-command]"
34912
+ description: "Format code"
34913
+ check:
34914
+ command: "[check-command]"
34915
+ description: "Check code"
34916
+
34917
+ rules:
34918
+ - "[package-manager-rule]"
34919
+ - "[testing-framework-rule]"
34920
+ - "[code-style-rule]"
34921
+ - "[other-rule]"
34922
+
34923
+ excludeFiles:
34924
+ - ".env"
34925
+ - ".env.*"
34926
+ \`\`\`
34927
+
34928
+ 5. **Handover to Coder Agent:**
34929
+ - Once all required information is collected and validated by the user, compile:
34930
+ 1. The final project specifications
34931
+ 2. The .polkacodes.yml configuration content
34932
+ - Clearly hand over these details to the coder agent, instructing them to:
34933
+ 1. Create the new project based on the confirmed specifications
34934
+ 2. Include the .polkacodes.yml file in the project root
34935
+ 3. Ensure all specified tools and configurations are properly set up`;
34936
+ var createNewProject_default = {
34937
+ name: "createNewProject",
34938
+ description: "Creates a new project",
34939
+ prompt,
34940
+ formatInput: (params) => {
34941
+ return `<project_name>${params}</project_name>`;
34942
+ },
34943
+ parseOutput: (output) => {
34944
+ return output.trim();
34945
+ },
34946
+ agent: "architect"
34947
+ };
34948
+
34877
34949
  // ../core/src/AiTool/generateGitCommitMessage.ts
34878
- var prompt = `
34950
+ var prompt2 = `
34879
34951
  You are an advanced assistant specialized in creating concise and accurate Git commit messages. When you receive:
34880
34952
  - A Git diff inside the <tool_input> tag.
34881
34953
  - Additional user-supplied context inside the <tool_input_context> tag (if any).
@@ -34910,7 +34982,7 @@ Follow the same structure for any new input. Never repeat questions; focus on ge
34910
34982
  var generateGitCommitMessage_default = {
34911
34983
  name: "generateGitCommitMessage",
34912
34984
  description: "Generates git commit messages from git diff output",
34913
- prompt,
34985
+ prompt: prompt2,
34914
34986
  formatInput: (params) => {
34915
34987
  let ret = `<tool_input>
34916
34988
  ${params.diff}
@@ -34935,7 +35007,7 @@ ${output}`);
34935
35007
  };
34936
35008
 
34937
35009
  // ../core/src/AiTool/generateGithubPullRequestDetails.ts
34938
- var prompt2 = `
35010
+ var prompt3 = `
34939
35011
  # Generate Github Pull Request Details
34940
35012
 
34941
35013
  You are given:
@@ -35019,7 +35091,7 @@ Use the above format whenever you receive <tool_input> that may include a branch
35019
35091
  var generateGithubPullRequestDetails_default = {
35020
35092
  name: "generateGithubPullRequestDetails",
35021
35093
  description: "Generates a GitHub pull request title and description from git commits",
35022
- prompt: prompt2,
35094
+ prompt: prompt3,
35023
35095
  formatInput: (params) => {
35024
35096
  return `<tool_input>
35025
35097
  <tool_input_branch_name>${params.branchName}</tool_input_branch_name>${params.context ? `
@@ -35052,7 +35124,7 @@ ${output}`);
35052
35124
  };
35053
35125
 
35054
35126
  // ../core/src/AiTool/generateProjectConfig.ts
35055
- var prompt3 = `You are an analyzer agent responsible for examining project files and generating appropriate polkacodes configuration. Your task is to:
35127
+ var prompt4 = `You are an analyzer agent responsible for examining project files and generating appropriate polkacodes configuration. Your task is to:
35056
35128
 
35057
35129
  1. Read and analyze the provided files using tool_read_file to understand:
35058
35130
  - Build tools and package manager (e.g., bun, npm)
@@ -35119,7 +35191,7 @@ The configuration should accurately reflect the project's structure, tools, and
35119
35191
  var generateProjectConfig_default = {
35120
35192
  name: "generateProjectConfig",
35121
35193
  description: "Analyzes project files to generate polkacodes config sections",
35122
- prompt: prompt3,
35194
+ prompt: prompt4,
35123
35195
  formatInput: (params) => {
35124
35196
  return `<tool_input>
35125
35197
  ${params.join(`
@@ -35170,6 +35242,7 @@ var makeAgentTool = (definition) => {
35170
35242
  var generateGitCommitMessage = makeTool(generateGitCommitMessage_default);
35171
35243
  var generateGithubPullRequestDetails = makeTool(generateGithubPullRequestDetails_default);
35172
35244
  var generateProjectConfig = makeAgentTool(generateProjectConfig_default);
35245
+ var createNewProject = makeAgentTool(createNewProject_default);
35173
35246
  // src/Chat.ts
35174
35247
  import readline from "node:readline";
35175
35248
 
@@ -35309,357 +35382,6 @@ import { spawn as spawn2 } from "node:child_process";
35309
35382
  import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
35310
35383
  import { dirname } from "node:path";
35311
35384
 
35312
- // src/utils/listFiles.ts
35313
- var import_ignore = __toESM(require_ignore(), 1);
35314
- import { promises as fs2 } from "node:fs";
35315
- import { join, relative, resolve } from "node:path";
35316
- var DEFAULT_IGNORES = [
35317
- "__pycache__",
35318
- ".DS_Store",
35319
- ".env",
35320
- ".git",
35321
- ".idea",
35322
- ".svn",
35323
- ".temp",
35324
- ".vscode",
35325
- "coverage",
35326
- "dist",
35327
- "node_modules",
35328
- "out",
35329
- "Thumbs.db"
35330
- ];
35331
- async function extendPatterns(basePatterns, dirPath) {
35332
- try {
35333
- const gitignorePath = join(dirPath, ".gitignore");
35334
- const content = await fs2.readFile(gitignorePath, "utf8");
35335
- const lines = content.split(/\r?\n/).filter(Boolean);
35336
- return [...basePatterns, ...lines];
35337
- } catch {
35338
- return basePatterns;
35339
- }
35340
- }
35341
- function createIgnore(patterns) {
35342
- return import_ignore.default().add(patterns);
35343
- }
35344
- async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
35345
- let rootPatterns = [...DEFAULT_IGNORES, ...excludeFiles || []];
35346
- try {
35347
- const rootGitignore = await fs2.readFile(join(cwd, ".gitignore"), "utf8");
35348
- const lines = rootGitignore.split(/\r?\n/).filter(Boolean);
35349
- rootPatterns = [...rootPatterns, ...lines];
35350
- } catch {
35351
- }
35352
- const results = [];
35353
- const queue = [{ path: resolve(dirPath), patterns: rootPatterns }];
35354
- while (queue.length > 0) {
35355
- const { path: currentPath, patterns: parentPatterns } = queue.shift();
35356
- const mergedPatterns = await extendPatterns(parentPatterns, currentPath);
35357
- const folderIg = createIgnore(mergedPatterns);
35358
- const entries = await fs2.readdir(currentPath, { withFileTypes: true });
35359
- for (const entry of entries) {
35360
- const fullPath = join(currentPath, entry.name);
35361
- const relPath = relative(cwd, fullPath).replace(/\\/g, "/");
35362
- if (folderIg.ignores(relPath)) {
35363
- continue;
35364
- }
35365
- if (entry.isDirectory()) {
35366
- if (recursive) {
35367
- queue.push({ path: fullPath, patterns: mergedPatterns });
35368
- }
35369
- } else {
35370
- results.push(relPath);
35371
- if (results.length >= maxCount) {
35372
- results.sort();
35373
- return [results, true];
35374
- }
35375
- }
35376
- }
35377
- }
35378
- results.sort();
35379
- return [results, false];
35380
- }
35381
-
35382
- // src/utils/searchFiles.ts
35383
- import { spawn } from "node:child_process";
35384
-
35385
- // ../../node_modules/@vscode/ripgrep/lib/index.js
35386
- var __dirname = "/Users/xiliangchen/projects/polka-codes/node_modules/@vscode/ripgrep/lib";
35387
- var path = __require("path");
35388
- var $rgPath = path.join(__dirname, `../bin/rg${process.platform === "win32" ? ".exe" : ""}`);
35389
-
35390
- // src/utils/searchFiles.ts
35391
- async function searchFiles(path2, regex, filePattern, cwd, excludeFiles) {
35392
- const args = [
35393
- "--line-number",
35394
- "--context=5",
35395
- "--color=never",
35396
- "--with-filename",
35397
- "--smart-case"
35398
- ];
35399
- if (filePattern && filePattern !== "*") {
35400
- args.push("--glob", filePattern);
35401
- }
35402
- if (excludeFiles) {
35403
- for (const pattern of excludeFiles) {
35404
- args.push("--ignore-file", pattern);
35405
- }
35406
- }
35407
- args.push(regex, path2);
35408
- return new Promise((resolve2, reject) => {
35409
- const results = [];
35410
- const rg = spawn($rgPath, args, {
35411
- cwd,
35412
- stdio: ["ignore", "pipe", "pipe"]
35413
- });
35414
- rg.stdout.on("data", (data) => {
35415
- const lines = data.toString().split(`
35416
- `).filter(Boolean);
35417
- results.push(...lines);
35418
- });
35419
- rg.stderr.on("data", (data) => {
35420
- const err = data.toString();
35421
- if (!err.startsWith("WARNING:")) {
35422
- console.warn(err);
35423
- }
35424
- });
35425
- rg.on("error", (error) => {
35426
- reject(new Error(`Failed to execute ripgrep: ${error.message}`));
35427
- });
35428
- rg.on("close", (code) => {
35429
- if (code !== 0 && code !== 1) {
35430
- reject(new Error(`Ripgrep process exited with code ${code}`));
35431
- return;
35432
- }
35433
- resolve2(results);
35434
- });
35435
- });
35436
- }
35437
-
35438
- // src/provider.ts
35439
- var getProvider = (agentName, config, options = {}) => {
35440
- const ig = import_ignore2.default().add(options.excludeFiles ?? []);
35441
- const provider2 = {
35442
- readFile: async (path2) => {
35443
- if (ig.ignores(path2)) {
35444
- throw new Error(`Not allow to access file ${path2}`);
35445
- }
35446
- return await readFile(path2, "utf8");
35447
- },
35448
- writeFile: async (path2, content) => {
35449
- if (ig.ignores(path2)) {
35450
- throw new Error(`Not allow to access file ${path2}`);
35451
- }
35452
- await mkdir(dirname(path2), { recursive: true });
35453
- return await writeFile(path2, content, "utf8");
35454
- },
35455
- removeFile: async (path2) => {
35456
- if (ig.ignores(path2)) {
35457
- throw new Error(`Not allow to access file ${path2}`);
35458
- }
35459
- return await unlink(path2);
35460
- },
35461
- renameFile: async (sourcePath, targetPath) => {
35462
- if (ig.ignores(sourcePath) || ig.ignores(targetPath)) {
35463
- throw new Error(`Not allow to access file ${sourcePath} or ${targetPath}`);
35464
- }
35465
- return await rename(sourcePath, targetPath);
35466
- },
35467
- listFiles: async (path2, recursive, maxCount) => {
35468
- return await listFiles(path2, recursive, maxCount, dirname(path2), options.excludeFiles);
35469
- },
35470
- searchFiles: async (path2, regex, filePattern) => {
35471
- return await searchFiles(path2, regex, filePattern, dirname(path2), options.excludeFiles);
35472
- },
35473
- executeCommand: (command, needApprove) => {
35474
- return new Promise((resolve2, reject) => {
35475
- options.command?.onStarted(command);
35476
- const child = spawn2(command, [], {
35477
- shell: true,
35478
- stdio: "pipe"
35479
- });
35480
- let stdoutText = "";
35481
- let stderrText = "";
35482
- child.stdout.on("data", (data) => {
35483
- const dataStr = data.toString();
35484
- options.command?.onStdout(dataStr);
35485
- stdoutText += dataStr;
35486
- });
35487
- child.stderr.on("data", (data) => {
35488
- const dataStr = data.toString();
35489
- options.command?.onStderr(dataStr);
35490
- stderrText += dataStr;
35491
- });
35492
- child.on("close", (code) => {
35493
- options.command?.onExit(code ?? 0);
35494
- resolve2({
35495
- stdout: stdoutText,
35496
- stderr: stderrText,
35497
- exitCode: code ?? 0
35498
- });
35499
- });
35500
- child.on("error", (err) => {
35501
- options.command?.onError(err);
35502
- reject(err);
35503
- });
35504
- });
35505
- },
35506
- attemptCompletion: async (result) => {
35507
- return;
35508
- }
35509
- };
35510
- return provider2;
35511
- };
35512
-
35513
- // src/Runner.ts
35514
- class Runner {
35515
- #options;
35516
- #multiAgent;
35517
- #usageMeter;
35518
- constructor(options) {
35519
- this.#options = options;
35520
- this.#usageMeter = new UsageMeter({
35521
- maxCost: options.budget,
35522
- maxMessageCount: options.maxMessageCount
35523
- });
35524
- const service = createService(options.provider, {
35525
- apiKey: options.apiKey,
35526
- model: options.model,
35527
- usageMeter: this.#usageMeter,
35528
- enableCache: options.enableCache
35529
- });
35530
- let rules2 = options.config.rules;
35531
- if (typeof rules2 === "string") {
35532
- rules2 = [rules2];
35533
- }
35534
- const providerOptions = {
35535
- command: {
35536
- onStarted(command) {
35537
- console.log(`$ >>>> $ ${command}`);
35538
- },
35539
- onStdout(data) {
35540
- process.stdout.write(data);
35541
- },
35542
- onStderr(data) {
35543
- process.stderr.write(data);
35544
- },
35545
- onExit(code) {
35546
- console.log(`$ <<<< $ Command exited with code: ${code}`);
35547
- },
35548
- onError(error) {
35549
- console.log(`$ <<<< $ Command error: ${error}`);
35550
- }
35551
- },
35552
- excludeFiles: options.config.excludeFiles
35553
- };
35554
- const platform = os.platform();
35555
- const agents = [coderAgentInfo, architectAgentInfo];
35556
- this.#multiAgent = new MultiAgent({
35557
- createAgent: async (name) => {
35558
- const agentName = name.trim().toLowerCase();
35559
- switch (agentName) {
35560
- case coderAgentInfo.name:
35561
- return new CoderAgent({
35562
- ai: service,
35563
- os: platform,
35564
- customInstructions: rules2,
35565
- scripts: options.config.scripts,
35566
- provider: getProvider("coder", options.config, providerOptions),
35567
- interactive: options.interactive,
35568
- agents
35569
- });
35570
- case architectAgentInfo.name:
35571
- return new ArchitectAgent({
35572
- ai: service,
35573
- os: platform,
35574
- customInstructions: rules2,
35575
- scripts: options.config.scripts,
35576
- provider: getProvider("architect", options.config, providerOptions),
35577
- interactive: options.interactive,
35578
- agents
35579
- });
35580
- case analyzerAgentInfo.name:
35581
- return new AnalyzerAgent({
35582
- ai: service,
35583
- os: platform,
35584
- customInstructions: rules2,
35585
- scripts: options.config.scripts,
35586
- provider: getProvider("analyzer", options.config, providerOptions),
35587
- interactive: options.interactive,
35588
- agents
35589
- });
35590
- default:
35591
- throw new Error(`Unknown agent: ${name}`);
35592
- }
35593
- },
35594
- getContext: async (name, context, files) => {
35595
- let ret = await this.#defaultContext(name);
35596
- const unreadableFiles = [];
35597
- if (files) {
35598
- for (const file of files) {
35599
- try {
35600
- const fileContent = await readFile2(file, "utf8");
35601
- ret += `
35602
- <file_content path="${file}">${fileContent}</file_content>`;
35603
- } catch (error) {
35604
- console.warn(`Failed to read file: ${file}`, error);
35605
- unreadableFiles.push(file);
35606
- }
35607
- }
35608
- if (unreadableFiles.length > 0) {
35609
- ret += `
35610
- <unreadable_files>
35611
- `;
35612
- for (const file of unreadableFiles) {
35613
- ret += `${file}
35614
- `;
35615
- }
35616
- ret += "</unreadable_files>";
35617
- }
35618
- }
35619
- if (context) {
35620
- ret += `
35621
-
35622
- ${context}`;
35623
- }
35624
- return ret;
35625
- }
35626
- });
35627
- }
35628
- async#defaultContext(name) {
35629
- const cwd = process.cwd();
35630
- const agentConfig = this.#options.config.agents?.[name] ?? this.#options.config.agents?.default ?? {};
35631
- const maxFileCount = agentConfig.initialContext?.maxFileCount ?? 200;
35632
- const excludes = agentConfig.initialContext?.excludes ?? [];
35633
- const finalExcludes = excludes.concat(this.#options.config.excludeFiles ?? []);
35634
- const [fileList, limited] = await listFiles(cwd, true, maxFileCount, cwd, finalExcludes);
35635
- const fileContext = `<files>
35636
- ${fileList.join(`
35637
- `)}${limited ? `
35638
- <files_truncated>true</files_truncated>` : ""}
35639
- </files>`;
35640
- return `<now_date>${new Date().toISOString()}</now_date>${fileContext}`;
35641
- }
35642
- async startTask(task) {
35643
- const agentName = architectAgentInfo.name;
35644
- const [exitReason, info] = await this.#multiAgent.startTask({
35645
- agentName,
35646
- task,
35647
- context: await this.#defaultContext(agentName),
35648
- callback: this.#options.eventCallback
35649
- });
35650
- return [exitReason, info];
35651
- }
35652
- async continueTask(message, taskInfo) {
35653
- return await this.#multiAgent.continueTask(message, taskInfo, this.#options.eventCallback);
35654
- }
35655
- get usage() {
35656
- return this.#usageMeter.usage;
35657
- }
35658
- printUsage() {
35659
- this.#usageMeter.printUsage();
35660
- }
35661
- }
35662
-
35663
35385
  // ../../node_modules/@inquirer/core/dist/esm/lib/key.js
35664
35386
  var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p";
35665
35387
  var isDownKey = (key) => key.name === "down" || key.name === "j" || key.ctrl && key.name === "n";
@@ -36220,15 +35942,15 @@ function useKeypress(userHandler) {
36220
35942
  const signal = useRef(userHandler);
36221
35943
  signal.current = userHandler;
36222
35944
  useEffect((rl) => {
36223
- let ignore3 = false;
35945
+ let ignore = false;
36224
35946
  const handler13 = withUpdates((_input, event) => {
36225
- if (ignore3)
35947
+ if (ignore)
36226
35948
  return;
36227
35949
  signal.current(event, rl);
36228
35950
  });
36229
35951
  rl.input.on("keypress", handler13);
36230
35952
  return () => {
36231
- ignore3 = true;
35953
+ ignore = true;
36232
35954
  rl.input.removeListener("keypress", handler13);
36233
35955
  };
36234
35956
  }, []);
@@ -36583,11 +36305,11 @@ class ScreenManager {
36583
36305
  render(content, bottomContent = "") {
36584
36306
  const promptLine = lastLine(content);
36585
36307
  const rawPromptLine = import_strip_ansi.default(promptLine);
36586
- let prompt4 = rawPromptLine;
36308
+ let prompt5 = rawPromptLine;
36587
36309
  if (this.rl.line.length > 0) {
36588
- prompt4 = prompt4.slice(0, -this.rl.line.length);
36310
+ prompt5 = prompt5.slice(0, -this.rl.line.length);
36589
36311
  }
36590
- this.rl.setPrompt(prompt4);
36312
+ this.rl.setPrompt(prompt5);
36591
36313
  this.cursorPos = this.rl.getCursorPos();
36592
36314
  const width = readlineWidth();
36593
36315
  content = breakLines(content, width);
@@ -36628,13 +36350,13 @@ class ScreenManager {
36628
36350
  // ../../node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.js
36629
36351
  class PromisePolyfill extends Promise {
36630
36352
  static withResolver() {
36631
- let resolve2;
36353
+ let resolve;
36632
36354
  let reject;
36633
36355
  const promise = new Promise((res, rej) => {
36634
- resolve2 = res;
36356
+ resolve = res;
36635
36357
  reject = rej;
36636
36358
  });
36637
- return { promise, resolve: resolve2, reject };
36359
+ return { promise, resolve, reject };
36638
36360
  }
36639
36361
  }
36640
36362
 
@@ -36657,7 +36379,7 @@ function getCallSites() {
36657
36379
  function createPrompt(view) {
36658
36380
  const callSites = getCallSites();
36659
36381
  const callerFilename = callSites[1]?.getFileName?.();
36660
- const prompt4 = (config, context = {}) => {
36382
+ const prompt5 = (config, context = {}) => {
36661
36383
  const { input = process.stdin, signal } = context;
36662
36384
  const cleanups = new Set;
36663
36385
  const output = new import_mute_stream.default;
@@ -36668,7 +36390,7 @@ function createPrompt(view) {
36668
36390
  output
36669
36391
  });
36670
36392
  const screen = new ScreenManager(rl);
36671
- const { promise, resolve: resolve2, reject } = PromisePolyfill.withResolver();
36393
+ const { promise, resolve, reject } = PromisePolyfill.withResolver();
36672
36394
  const cancel = () => reject(new CancelPromptError);
36673
36395
  if (signal) {
36674
36396
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -36692,7 +36414,7 @@ function createPrompt(view) {
36692
36414
  cycle(() => {
36693
36415
  try {
36694
36416
  const nextView = view(config, (value) => {
36695
- setImmediate(() => resolve2(value));
36417
+ setImmediate(() => resolve(value));
36696
36418
  });
36697
36419
  if (nextView === undefined) {
36698
36420
  throw new Error(`Prompt functions must return a string.
@@ -36718,7 +36440,7 @@ function createPrompt(view) {
36718
36440
  }).then(() => promise), { cancel });
36719
36441
  });
36720
36442
  };
36721
- return prompt4;
36443
+ return prompt5;
36722
36444
  }
36723
36445
  // ../../node_modules/@inquirer/core/dist/esm/lib/Separator.js
36724
36446
  var import_yoctocolors_cjs2 = __toESM(require_yoctocolors_cjs(), 1);
@@ -37030,6 +36752,376 @@ ${theme.style.description(selectedChoice.description)}` : ``;
37030
36752
  return `${[prefix, message, helpTipTop].filter(Boolean).join(" ")}
37031
36753
  ${page}${helpTipBottom}${choiceDescription}${import_ansi_escapes3.default.cursorHide}`;
37032
36754
  });
36755
+ // src/utils/listFiles.ts
36756
+ var import_ignore = __toESM(require_ignore(), 1);
36757
+ import { promises as fs2 } from "node:fs";
36758
+ import { join, relative, resolve } from "node:path";
36759
+ var DEFAULT_IGNORES = [
36760
+ "__pycache__",
36761
+ ".DS_Store",
36762
+ ".env",
36763
+ ".git",
36764
+ ".idea",
36765
+ ".svn",
36766
+ ".temp",
36767
+ ".vscode",
36768
+ "coverage",
36769
+ "dist",
36770
+ "node_modules",
36771
+ "out",
36772
+ "Thumbs.db"
36773
+ ];
36774
+ async function extendPatterns(basePatterns, dirPath) {
36775
+ try {
36776
+ const gitignorePath = join(dirPath, ".gitignore");
36777
+ const content = await fs2.readFile(gitignorePath, "utf8");
36778
+ const lines2 = content.split(/\r?\n/).filter(Boolean);
36779
+ return [...basePatterns, ...lines2];
36780
+ } catch {
36781
+ return basePatterns;
36782
+ }
36783
+ }
36784
+ function createIgnore(patterns) {
36785
+ return import_ignore.default().add(patterns);
36786
+ }
36787
+ async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
36788
+ let rootPatterns = [...DEFAULT_IGNORES, ...excludeFiles || []];
36789
+ try {
36790
+ const rootGitignore = await fs2.readFile(join(cwd, ".gitignore"), "utf8");
36791
+ const lines2 = rootGitignore.split(/\r?\n/).filter(Boolean);
36792
+ rootPatterns = [...rootPatterns, ...lines2];
36793
+ } catch {
36794
+ }
36795
+ const results = [];
36796
+ const queue = [{ path: resolve(dirPath), patterns: rootPatterns }];
36797
+ while (queue.length > 0) {
36798
+ const { path: currentPath, patterns: parentPatterns } = queue.shift();
36799
+ const mergedPatterns = await extendPatterns(parentPatterns, currentPath);
36800
+ const folderIg = createIgnore(mergedPatterns);
36801
+ const entries = await fs2.readdir(currentPath, { withFileTypes: true });
36802
+ for (const entry of entries) {
36803
+ const fullPath = join(currentPath, entry.name);
36804
+ const relPath = relative(cwd, fullPath).replace(/\\/g, "/");
36805
+ if (folderIg.ignores(relPath)) {
36806
+ continue;
36807
+ }
36808
+ if (entry.isDirectory()) {
36809
+ if (recursive) {
36810
+ queue.push({ path: fullPath, patterns: mergedPatterns });
36811
+ }
36812
+ } else {
36813
+ results.push(relPath);
36814
+ if (results.length >= maxCount) {
36815
+ results.sort();
36816
+ return [results, true];
36817
+ }
36818
+ }
36819
+ }
36820
+ }
36821
+ results.sort();
36822
+ return [results, false];
36823
+ }
36824
+
36825
+ // src/utils/searchFiles.ts
36826
+ import { spawn } from "node:child_process";
36827
+
36828
+ // ../../node_modules/@vscode/ripgrep/lib/index.js
36829
+ var __dirname = "/Users/xiliangchen/projects/polka-codes/node_modules/@vscode/ripgrep/lib";
36830
+ var path = __require("path");
36831
+ var $rgPath = path.join(__dirname, `../bin/rg${process.platform === "win32" ? ".exe" : ""}`);
36832
+
36833
+ // src/utils/searchFiles.ts
36834
+ async function searchFiles(path2, regex, filePattern, cwd, excludeFiles) {
36835
+ const args = [
36836
+ "--line-number",
36837
+ "--context=5",
36838
+ "--color=never",
36839
+ "--with-filename",
36840
+ "--smart-case"
36841
+ ];
36842
+ if (filePattern && filePattern !== "*") {
36843
+ args.push("--glob", filePattern);
36844
+ }
36845
+ if (excludeFiles) {
36846
+ for (const pattern of excludeFiles) {
36847
+ args.push("--ignore-file", pattern);
36848
+ }
36849
+ }
36850
+ args.push(regex, path2);
36851
+ return new Promise((resolve2, reject) => {
36852
+ const results = [];
36853
+ const rg = spawn($rgPath, args, {
36854
+ cwd,
36855
+ stdio: ["ignore", "pipe", "pipe"]
36856
+ });
36857
+ rg.stdout.on("data", (data) => {
36858
+ const lines2 = data.toString().split(`
36859
+ `).filter(Boolean);
36860
+ results.push(...lines2);
36861
+ });
36862
+ rg.stderr.on("data", (data) => {
36863
+ const err = data.toString();
36864
+ if (!err.startsWith("WARNING:")) {
36865
+ console.warn(err);
36866
+ }
36867
+ });
36868
+ rg.on("error", (error) => {
36869
+ reject(new Error(`Failed to execute ripgrep: ${error.message}`));
36870
+ });
36871
+ rg.on("close", (code) => {
36872
+ if (code !== 0 && code !== 1) {
36873
+ reject(new Error(`Ripgrep process exited with code ${code}`));
36874
+ return;
36875
+ }
36876
+ resolve2(results);
36877
+ });
36878
+ });
36879
+ }
36880
+
36881
+ // src/provider.ts
36882
+ var getProvider = (agentName, config, options = {}) => {
36883
+ const ig = import_ignore2.default().add(options.excludeFiles ?? []);
36884
+ const provider2 = {
36885
+ readFile: async (path2) => {
36886
+ if (ig.ignores(path2)) {
36887
+ throw new Error(`Not allow to access file ${path2}`);
36888
+ }
36889
+ return await readFile(path2, "utf8");
36890
+ },
36891
+ writeFile: async (path2, content) => {
36892
+ if (ig.ignores(path2)) {
36893
+ throw new Error(`Not allow to access file ${path2}`);
36894
+ }
36895
+ await mkdir(dirname(path2), { recursive: true });
36896
+ return await writeFile(path2, content, "utf8");
36897
+ },
36898
+ removeFile: async (path2) => {
36899
+ if (ig.ignores(path2)) {
36900
+ throw new Error(`Not allow to access file ${path2}`);
36901
+ }
36902
+ return await unlink(path2);
36903
+ },
36904
+ renameFile: async (sourcePath, targetPath) => {
36905
+ if (ig.ignores(sourcePath) || ig.ignores(targetPath)) {
36906
+ throw new Error(`Not allow to access file ${sourcePath} or ${targetPath}`);
36907
+ }
36908
+ return await rename(sourcePath, targetPath);
36909
+ },
36910
+ listFiles: async (path2, recursive, maxCount) => {
36911
+ return await listFiles(path2, recursive, maxCount, dirname(path2), options.excludeFiles);
36912
+ },
36913
+ searchFiles: async (path2, regex, filePattern) => {
36914
+ return await searchFiles(path2, regex, filePattern, dirname(path2), options.excludeFiles);
36915
+ },
36916
+ executeCommand: (command, needApprove) => {
36917
+ return new Promise((resolve2, reject) => {
36918
+ options.command?.onStarted(command);
36919
+ const child = spawn2(command, [], {
36920
+ shell: true,
36921
+ stdio: "pipe"
36922
+ });
36923
+ let stdoutText = "";
36924
+ let stderrText = "";
36925
+ child.stdout.on("data", (data) => {
36926
+ const dataStr = data.toString();
36927
+ options.command?.onStdout(dataStr);
36928
+ stdoutText += dataStr;
36929
+ });
36930
+ child.stderr.on("data", (data) => {
36931
+ const dataStr = data.toString();
36932
+ options.command?.onStderr(dataStr);
36933
+ stderrText += dataStr;
36934
+ });
36935
+ child.on("close", (code) => {
36936
+ options.command?.onExit(code ?? 0);
36937
+ resolve2({
36938
+ stdout: stdoutText,
36939
+ stderr: stderrText,
36940
+ exitCode: code ?? 0
36941
+ });
36942
+ });
36943
+ child.on("error", (err) => {
36944
+ options.command?.onError(err);
36945
+ reject(err);
36946
+ });
36947
+ });
36948
+ },
36949
+ askFollowupQuestion: async (question, answerOptions) => {
36950
+ if (options.interactive) {
36951
+ if (answerOptions.length === 0) {
36952
+ return await esm_default3({ message: question });
36953
+ }
36954
+ const otherMessage = "Other (enter text)";
36955
+ answerOptions.push(otherMessage);
36956
+ const answer = await esm_default5({
36957
+ message: question,
36958
+ choices: answerOptions.map((option) => ({ name: option, value: option }))
36959
+ });
36960
+ if (answer === otherMessage) {
36961
+ return await esm_default3({ message: "Enter your answer:" });
36962
+ }
36963
+ return answer;
36964
+ }
36965
+ return answerOptions[0] ?? "<warning>This is non-interactive mode, no answer can be provided.</warning>";
36966
+ },
36967
+ attemptCompletion: async (result) => {
36968
+ return;
36969
+ }
36970
+ };
36971
+ return provider2;
36972
+ };
36973
+
36974
+ // src/Runner.ts
36975
+ class Runner {
36976
+ #options;
36977
+ #multiAgent;
36978
+ #usageMeter;
36979
+ constructor(options) {
36980
+ this.#options = options;
36981
+ this.#usageMeter = new UsageMeter({
36982
+ maxCost: options.budget,
36983
+ maxMessageCount: options.maxMessageCount
36984
+ });
36985
+ const service = createService(options.provider, {
36986
+ apiKey: options.apiKey,
36987
+ model: options.model,
36988
+ usageMeter: this.#usageMeter,
36989
+ enableCache: options.enableCache
36990
+ });
36991
+ let rules2 = options.config.rules;
36992
+ if (typeof rules2 === "string") {
36993
+ rules2 = [rules2];
36994
+ }
36995
+ const providerOptions = {
36996
+ command: {
36997
+ onStarted(command) {
36998
+ console.log(`$ >>>> $ ${command}`);
36999
+ },
37000
+ onStdout(data) {
37001
+ process.stdout.write(data);
37002
+ },
37003
+ onStderr(data) {
37004
+ process.stderr.write(data);
37005
+ },
37006
+ onExit(code) {
37007
+ console.log(`$ <<<< $ Command exited with code: ${code}`);
37008
+ },
37009
+ onError(error) {
37010
+ console.log(`$ <<<< $ Command error: ${error}`);
37011
+ }
37012
+ },
37013
+ excludeFiles: options.config.excludeFiles,
37014
+ interactive: options.interactive
37015
+ };
37016
+ const platform = os.platform();
37017
+ const agents = [coderAgentInfo, architectAgentInfo];
37018
+ this.#multiAgent = new MultiAgent({
37019
+ createAgent: async (name) => {
37020
+ const agentName = name.trim().toLowerCase();
37021
+ switch (agentName) {
37022
+ case coderAgentInfo.name:
37023
+ return new CoderAgent({
37024
+ ai: service,
37025
+ os: platform,
37026
+ customInstructions: rules2,
37027
+ scripts: options.config.scripts,
37028
+ provider: getProvider("coder", options.config, providerOptions),
37029
+ interactive: options.interactive,
37030
+ agents
37031
+ });
37032
+ case architectAgentInfo.name:
37033
+ return new ArchitectAgent({
37034
+ ai: service,
37035
+ os: platform,
37036
+ customInstructions: rules2,
37037
+ scripts: options.config.scripts,
37038
+ provider: getProvider("architect", options.config, providerOptions),
37039
+ interactive: options.interactive,
37040
+ agents
37041
+ });
37042
+ case analyzerAgentInfo.name:
37043
+ return new AnalyzerAgent({
37044
+ ai: service,
37045
+ os: platform,
37046
+ customInstructions: rules2,
37047
+ scripts: options.config.scripts,
37048
+ provider: getProvider("analyzer", options.config, providerOptions),
37049
+ interactive: options.interactive,
37050
+ agents
37051
+ });
37052
+ default:
37053
+ throw new Error(`Unknown agent: ${name}`);
37054
+ }
37055
+ },
37056
+ getContext: async (name, context, files) => {
37057
+ let ret = await this.#defaultContext(name);
37058
+ const unreadableFiles = [];
37059
+ if (files) {
37060
+ for (const file of files) {
37061
+ try {
37062
+ const fileContent = await readFile2(file, "utf8");
37063
+ ret += `
37064
+ <file_content path="${file}">${fileContent}</file_content>`;
37065
+ } catch (error) {
37066
+ console.warn(`Failed to read file: ${file}`, error);
37067
+ unreadableFiles.push(file);
37068
+ }
37069
+ }
37070
+ if (unreadableFiles.length > 0) {
37071
+ ret += `
37072
+ <unreadable_files>
37073
+ `;
37074
+ for (const file of unreadableFiles) {
37075
+ ret += `${file}
37076
+ `;
37077
+ }
37078
+ ret += "</unreadable_files>";
37079
+ }
37080
+ }
37081
+ if (context) {
37082
+ ret += `
37083
+
37084
+ ${context}`;
37085
+ }
37086
+ return ret;
37087
+ }
37088
+ });
37089
+ }
37090
+ async#defaultContext(name) {
37091
+ const cwd = process.cwd();
37092
+ const agentConfig = this.#options.config.agents?.[name] ?? this.#options.config.agents?.default ?? {};
37093
+ const maxFileCount = agentConfig.initialContext?.maxFileCount ?? 200;
37094
+ const excludes = agentConfig.initialContext?.excludes ?? [];
37095
+ const finalExcludes = excludes.concat(this.#options.config.excludeFiles ?? []);
37096
+ const [fileList, limited] = await listFiles(cwd, true, maxFileCount, cwd, finalExcludes);
37097
+ const fileContext = `<files>
37098
+ ${fileList.join(`
37099
+ `)}${limited ? `
37100
+ <files_truncated>true</files_truncated>` : ""}
37101
+ </files>`;
37102
+ return `<now_date>${new Date().toISOString()}</now_date>${fileContext}`;
37103
+ }
37104
+ async startTask(task) {
37105
+ const agentName = architectAgentInfo.name;
37106
+ const [exitReason, info] = await this.#multiAgent.startTask({
37107
+ agentName,
37108
+ task,
37109
+ context: await this.#defaultContext(agentName),
37110
+ callback: this.#options.eventCallback
37111
+ });
37112
+ return [exitReason, info];
37113
+ }
37114
+ async continueTask(message, taskInfo) {
37115
+ return await this.#multiAgent.continueTask(message, taskInfo, this.#options.eventCallback);
37116
+ }
37117
+ get usage() {
37118
+ return this.#usageMeter.usage;
37119
+ }
37120
+ printUsage() {
37121
+ this.#usageMeter.printUsage();
37122
+ }
37123
+ }
37124
+
37033
37125
  // src/configPrompt.ts
37034
37126
  var fetchOllamaModels = async () => {
37035
37127
  try {
@@ -41888,6 +41980,10 @@ ${event.systemPrompt}`);
41888
41980
  var runChat = async (opts, command) => {
41889
41981
  const options = command?.parent?.opts() ?? opts ?? {};
41890
41982
  const { config, providerConfig, maxMessageCount, verbose, budget } = parseOptions(options);
41983
+ if (!process.stdin.isTTY) {
41984
+ console.error("Error: Terminal is not interactive. Please run this command in an interactive terminal.");
41985
+ process.exit(1);
41986
+ }
41891
41987
  let { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("coder") ?? {};
41892
41988
  if (!provider2) {
41893
41989
  const newConfig = await configPrompt({ provider: provider2, model, apiKey });
@@ -42613,8 +42709,8 @@ ${result.response}`);
42613
42709
  });
42614
42710
 
42615
42711
  // src/commands/init.ts
42616
- import os4 from "node:os";
42617
42712
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
42713
+ import os4 from "node:os";
42618
42714
  import { dirname as dirname2 } from "node:path";
42619
42715
  var import_lodash3 = __toESM(require_lodash(), 1);
42620
42716
  var initCommand = new Command("init").description("Initialize polkacodes configuration").option("-g, --global", "Use global config");
@@ -42852,48 +42948,77 @@ var prCommand = new Command("pr").description("Create a GitHub pull request").ar
42852
42948
  });
42853
42949
 
42854
42950
  // src/commands/task.ts
42855
- async function runTask(task, _options, command) {
42856
- const { config, providerConfig } = parseOptions(command.opts());
42857
- const { provider: provider2, model, apiKey } = providerConfig.getConfigForCommand("task") ?? {};
42951
+ var readStdin = async (timeoutMs = 30000) => {
42952
+ if (process.stdin.isTTY) {
42953
+ return "";
42954
+ }
42955
+ return new Promise((resolve2, reject) => {
42956
+ let input = "";
42957
+ let timeoutId = undefined;
42958
+ const cleanup = () => {
42959
+ if (timeoutId)
42960
+ clearTimeout(timeoutId);
42961
+ process.stdin.removeAllListeners();
42962
+ process.stdin.resume();
42963
+ };
42964
+ timeoutId = setTimeout(() => {
42965
+ cleanup();
42966
+ reject(new Error("Stdin read timeout"));
42967
+ }, timeoutMs);
42968
+ process.stdin.on("data", (chunk) => {
42969
+ input += chunk.toString();
42970
+ });
42971
+ process.stdin.on("end", () => {
42972
+ cleanup();
42973
+ if (!input) {
42974
+ reject(new Error("Empty stdin input"));
42975
+ return;
42976
+ }
42977
+ resolve2(input);
42978
+ });
42979
+ process.stdin.on("error", (err) => {
42980
+ cleanup();
42981
+ reject(err);
42982
+ });
42983
+ });
42984
+ };
42985
+ async function runTask(taskArg, _options, command) {
42986
+ let task = taskArg;
42987
+ if (!task) {
42988
+ try {
42989
+ const stdinInput = await readStdin();
42990
+ if (stdinInput) {
42991
+ task = stdinInput;
42992
+ } else {
42993
+ runChat({}, command);
42994
+ return;
42995
+ }
42996
+ } catch (error) {
42997
+ console.error("Error reading stdin:", error);
42998
+ process.exit(1);
42999
+ }
43000
+ }
43001
+ const { config, providerConfig, verbose, maxMessageCount, budget } = parseOptions(command.opts());
43002
+ const { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("architect") ?? {};
42858
43003
  if (!provider2 || !model) {
42859
43004
  console.error("Provider and model must be configured");
42860
43005
  process.exit(1);
42861
43006
  }
42862
- if (!task) {
42863
- await runChat({}, command);
42864
- return;
42865
- }
43007
+ console.log("Provider:", provider2);
43008
+ console.log("Model:", model);
42866
43009
  const runner = new Runner({
42867
43010
  provider: provider2,
42868
43011
  model,
42869
43012
  apiKey,
42870
43013
  config,
42871
- maxMessageCount: 100,
42872
- budget: 10,
42873
- interactive: true,
42874
- eventCallback: printEvent(1),
43014
+ maxMessageCount,
43015
+ budget,
43016
+ interactive: process.stdin.isTTY,
43017
+ eventCallback: printEvent(verbose),
42875
43018
  enableCache: true
42876
43019
  });
42877
- if (task) {
42878
- const [exitReason, info] = await runner.startTask(task);
42879
- switch (exitReason.type) {
42880
- case "UsageExceeded":
42881
- console.error("Task failed: Usage limit exceeded");
42882
- process.exit(1);
42883
- break;
42884
- case "WaitForUserInput":
42885
- break;
42886
- case "Exit" /* Exit */:
42887
- break;
42888
- case "Interrupted" /* Interrupted */:
42889
- console.error("Task interrupted:", exitReason.message);
42890
- process.exit(1);
42891
- break;
42892
- case "HandOver" /* HandOver */:
42893
- break;
42894
- }
42895
- runner.printUsage();
42896
- }
43020
+ await runner.startTask(task);
43021
+ runner.printUsage();
42897
43022
  }
42898
43023
 
42899
43024
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polka-codes/cli",
3
- "version": "0.4.10",
3
+ "version": "0.5.1",
4
4
  "license": "AGPL-3.0",
5
5
  "type": "module",
6
6
  "bin": {