@polka-codes/cli 0.4.10 → 0.5.0

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 +447 -395
  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.0";
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
  }
@@ -35309,357 +35309,6 @@ import { spawn as spawn2 } from "node:child_process";
35309
35309
  import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
35310
35310
  import { dirname } from "node:path";
35311
35311
 
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
35312
  // ../../node_modules/@inquirer/core/dist/esm/lib/key.js
35664
35313
  var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p";
35665
35314
  var isDownKey = (key) => key.name === "down" || key.name === "j" || key.ctrl && key.name === "n";
@@ -36220,15 +35869,15 @@ function useKeypress(userHandler) {
36220
35869
  const signal = useRef(userHandler);
36221
35870
  signal.current = userHandler;
36222
35871
  useEffect((rl) => {
36223
- let ignore3 = false;
35872
+ let ignore = false;
36224
35873
  const handler13 = withUpdates((_input, event) => {
36225
- if (ignore3)
35874
+ if (ignore)
36226
35875
  return;
36227
35876
  signal.current(event, rl);
36228
35877
  });
36229
35878
  rl.input.on("keypress", handler13);
36230
35879
  return () => {
36231
- ignore3 = true;
35880
+ ignore = true;
36232
35881
  rl.input.removeListener("keypress", handler13);
36233
35882
  };
36234
35883
  }, []);
@@ -36628,13 +36277,13 @@ class ScreenManager {
36628
36277
  // ../../node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.js
36629
36278
  class PromisePolyfill extends Promise {
36630
36279
  static withResolver() {
36631
- let resolve2;
36280
+ let resolve;
36632
36281
  let reject;
36633
36282
  const promise = new Promise((res, rej) => {
36634
- resolve2 = res;
36283
+ resolve = res;
36635
36284
  reject = rej;
36636
36285
  });
36637
- return { promise, resolve: resolve2, reject };
36286
+ return { promise, resolve, reject };
36638
36287
  }
36639
36288
  }
36640
36289
 
@@ -36668,7 +36317,7 @@ function createPrompt(view) {
36668
36317
  output
36669
36318
  });
36670
36319
  const screen = new ScreenManager(rl);
36671
- const { promise, resolve: resolve2, reject } = PromisePolyfill.withResolver();
36320
+ const { promise, resolve, reject } = PromisePolyfill.withResolver();
36672
36321
  const cancel = () => reject(new CancelPromptError);
36673
36322
  if (signal) {
36674
36323
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -36692,7 +36341,7 @@ function createPrompt(view) {
36692
36341
  cycle(() => {
36693
36342
  try {
36694
36343
  const nextView = view(config, (value) => {
36695
- setImmediate(() => resolve2(value));
36344
+ setImmediate(() => resolve(value));
36696
36345
  });
36697
36346
  if (nextView === undefined) {
36698
36347
  throw new Error(`Prompt functions must return a string.
@@ -37030,6 +36679,376 @@ ${theme.style.description(selectedChoice.description)}` : ``;
37030
36679
  return `${[prefix, message, helpTipTop].filter(Boolean).join(" ")}
37031
36680
  ${page}${helpTipBottom}${choiceDescription}${import_ansi_escapes3.default.cursorHide}`;
37032
36681
  });
36682
+ // src/utils/listFiles.ts
36683
+ var import_ignore = __toESM(require_ignore(), 1);
36684
+ import { promises as fs2 } from "node:fs";
36685
+ import { join, relative, resolve } from "node:path";
36686
+ var DEFAULT_IGNORES = [
36687
+ "__pycache__",
36688
+ ".DS_Store",
36689
+ ".env",
36690
+ ".git",
36691
+ ".idea",
36692
+ ".svn",
36693
+ ".temp",
36694
+ ".vscode",
36695
+ "coverage",
36696
+ "dist",
36697
+ "node_modules",
36698
+ "out",
36699
+ "Thumbs.db"
36700
+ ];
36701
+ async function extendPatterns(basePatterns, dirPath) {
36702
+ try {
36703
+ const gitignorePath = join(dirPath, ".gitignore");
36704
+ const content = await fs2.readFile(gitignorePath, "utf8");
36705
+ const lines2 = content.split(/\r?\n/).filter(Boolean);
36706
+ return [...basePatterns, ...lines2];
36707
+ } catch {
36708
+ return basePatterns;
36709
+ }
36710
+ }
36711
+ function createIgnore(patterns) {
36712
+ return import_ignore.default().add(patterns);
36713
+ }
36714
+ async function listFiles(dirPath, recursive, maxCount, cwd, excludeFiles) {
36715
+ let rootPatterns = [...DEFAULT_IGNORES, ...excludeFiles || []];
36716
+ try {
36717
+ const rootGitignore = await fs2.readFile(join(cwd, ".gitignore"), "utf8");
36718
+ const lines2 = rootGitignore.split(/\r?\n/).filter(Boolean);
36719
+ rootPatterns = [...rootPatterns, ...lines2];
36720
+ } catch {
36721
+ }
36722
+ const results = [];
36723
+ const queue = [{ path: resolve(dirPath), patterns: rootPatterns }];
36724
+ while (queue.length > 0) {
36725
+ const { path: currentPath, patterns: parentPatterns } = queue.shift();
36726
+ const mergedPatterns = await extendPatterns(parentPatterns, currentPath);
36727
+ const folderIg = createIgnore(mergedPatterns);
36728
+ const entries = await fs2.readdir(currentPath, { withFileTypes: true });
36729
+ for (const entry of entries) {
36730
+ const fullPath = join(currentPath, entry.name);
36731
+ const relPath = relative(cwd, fullPath).replace(/\\/g, "/");
36732
+ if (folderIg.ignores(relPath)) {
36733
+ continue;
36734
+ }
36735
+ if (entry.isDirectory()) {
36736
+ if (recursive) {
36737
+ queue.push({ path: fullPath, patterns: mergedPatterns });
36738
+ }
36739
+ } else {
36740
+ results.push(relPath);
36741
+ if (results.length >= maxCount) {
36742
+ results.sort();
36743
+ return [results, true];
36744
+ }
36745
+ }
36746
+ }
36747
+ }
36748
+ results.sort();
36749
+ return [results, false];
36750
+ }
36751
+
36752
+ // src/utils/searchFiles.ts
36753
+ import { spawn } from "node:child_process";
36754
+
36755
+ // ../../node_modules/@vscode/ripgrep/lib/index.js
36756
+ var __dirname = "/Users/xiliangchen/projects/polka-codes/node_modules/@vscode/ripgrep/lib";
36757
+ var path = __require("path");
36758
+ var $rgPath = path.join(__dirname, `../bin/rg${process.platform === "win32" ? ".exe" : ""}`);
36759
+
36760
+ // src/utils/searchFiles.ts
36761
+ async function searchFiles(path2, regex, filePattern, cwd, excludeFiles) {
36762
+ const args = [
36763
+ "--line-number",
36764
+ "--context=5",
36765
+ "--color=never",
36766
+ "--with-filename",
36767
+ "--smart-case"
36768
+ ];
36769
+ if (filePattern && filePattern !== "*") {
36770
+ args.push("--glob", filePattern);
36771
+ }
36772
+ if (excludeFiles) {
36773
+ for (const pattern of excludeFiles) {
36774
+ args.push("--ignore-file", pattern);
36775
+ }
36776
+ }
36777
+ args.push(regex, path2);
36778
+ return new Promise((resolve2, reject) => {
36779
+ const results = [];
36780
+ const rg = spawn($rgPath, args, {
36781
+ cwd,
36782
+ stdio: ["ignore", "pipe", "pipe"]
36783
+ });
36784
+ rg.stdout.on("data", (data) => {
36785
+ const lines2 = data.toString().split(`
36786
+ `).filter(Boolean);
36787
+ results.push(...lines2);
36788
+ });
36789
+ rg.stderr.on("data", (data) => {
36790
+ const err = data.toString();
36791
+ if (!err.startsWith("WARNING:")) {
36792
+ console.warn(err);
36793
+ }
36794
+ });
36795
+ rg.on("error", (error) => {
36796
+ reject(new Error(`Failed to execute ripgrep: ${error.message}`));
36797
+ });
36798
+ rg.on("close", (code) => {
36799
+ if (code !== 0 && code !== 1) {
36800
+ reject(new Error(`Ripgrep process exited with code ${code}`));
36801
+ return;
36802
+ }
36803
+ resolve2(results);
36804
+ });
36805
+ });
36806
+ }
36807
+
36808
+ // src/provider.ts
36809
+ var getProvider = (agentName, config, options = {}) => {
36810
+ const ig = import_ignore2.default().add(options.excludeFiles ?? []);
36811
+ const provider2 = {
36812
+ readFile: async (path2) => {
36813
+ if (ig.ignores(path2)) {
36814
+ throw new Error(`Not allow to access file ${path2}`);
36815
+ }
36816
+ return await readFile(path2, "utf8");
36817
+ },
36818
+ writeFile: async (path2, content) => {
36819
+ if (ig.ignores(path2)) {
36820
+ throw new Error(`Not allow to access file ${path2}`);
36821
+ }
36822
+ await mkdir(dirname(path2), { recursive: true });
36823
+ return await writeFile(path2, content, "utf8");
36824
+ },
36825
+ removeFile: async (path2) => {
36826
+ if (ig.ignores(path2)) {
36827
+ throw new Error(`Not allow to access file ${path2}`);
36828
+ }
36829
+ return await unlink(path2);
36830
+ },
36831
+ renameFile: async (sourcePath, targetPath) => {
36832
+ if (ig.ignores(sourcePath) || ig.ignores(targetPath)) {
36833
+ throw new Error(`Not allow to access file ${sourcePath} or ${targetPath}`);
36834
+ }
36835
+ return await rename(sourcePath, targetPath);
36836
+ },
36837
+ listFiles: async (path2, recursive, maxCount) => {
36838
+ return await listFiles(path2, recursive, maxCount, dirname(path2), options.excludeFiles);
36839
+ },
36840
+ searchFiles: async (path2, regex, filePattern) => {
36841
+ return await searchFiles(path2, regex, filePattern, dirname(path2), options.excludeFiles);
36842
+ },
36843
+ executeCommand: (command, needApprove) => {
36844
+ return new Promise((resolve2, reject) => {
36845
+ options.command?.onStarted(command);
36846
+ const child = spawn2(command, [], {
36847
+ shell: true,
36848
+ stdio: "pipe"
36849
+ });
36850
+ let stdoutText = "";
36851
+ let stderrText = "";
36852
+ child.stdout.on("data", (data) => {
36853
+ const dataStr = data.toString();
36854
+ options.command?.onStdout(dataStr);
36855
+ stdoutText += dataStr;
36856
+ });
36857
+ child.stderr.on("data", (data) => {
36858
+ const dataStr = data.toString();
36859
+ options.command?.onStderr(dataStr);
36860
+ stderrText += dataStr;
36861
+ });
36862
+ child.on("close", (code) => {
36863
+ options.command?.onExit(code ?? 0);
36864
+ resolve2({
36865
+ stdout: stdoutText,
36866
+ stderr: stderrText,
36867
+ exitCode: code ?? 0
36868
+ });
36869
+ });
36870
+ child.on("error", (err) => {
36871
+ options.command?.onError(err);
36872
+ reject(err);
36873
+ });
36874
+ });
36875
+ },
36876
+ askFollowupQuestion: async (question, answerOptions) => {
36877
+ if (options.interactive) {
36878
+ if (answerOptions.length === 0) {
36879
+ return await esm_default3({ message: question });
36880
+ }
36881
+ const otherMessage = "Other (enter text)";
36882
+ answerOptions.push(otherMessage);
36883
+ const answer = await esm_default5({
36884
+ message: question,
36885
+ choices: answerOptions.map((option) => ({ name: option, value: option }))
36886
+ });
36887
+ if (answer === otherMessage) {
36888
+ return await esm_default3({ message: "Enter your answer:" });
36889
+ }
36890
+ return answer;
36891
+ }
36892
+ return answerOptions[0] ?? "<warning>This is non-interactive mode, no answer can be provided.</warning>";
36893
+ },
36894
+ attemptCompletion: async (result) => {
36895
+ return;
36896
+ }
36897
+ };
36898
+ return provider2;
36899
+ };
36900
+
36901
+ // src/Runner.ts
36902
+ class Runner {
36903
+ #options;
36904
+ #multiAgent;
36905
+ #usageMeter;
36906
+ constructor(options) {
36907
+ this.#options = options;
36908
+ this.#usageMeter = new UsageMeter({
36909
+ maxCost: options.budget,
36910
+ maxMessageCount: options.maxMessageCount
36911
+ });
36912
+ const service = createService(options.provider, {
36913
+ apiKey: options.apiKey,
36914
+ model: options.model,
36915
+ usageMeter: this.#usageMeter,
36916
+ enableCache: options.enableCache
36917
+ });
36918
+ let rules2 = options.config.rules;
36919
+ if (typeof rules2 === "string") {
36920
+ rules2 = [rules2];
36921
+ }
36922
+ const providerOptions = {
36923
+ command: {
36924
+ onStarted(command) {
36925
+ console.log(`$ >>>> $ ${command}`);
36926
+ },
36927
+ onStdout(data) {
36928
+ process.stdout.write(data);
36929
+ },
36930
+ onStderr(data) {
36931
+ process.stderr.write(data);
36932
+ },
36933
+ onExit(code) {
36934
+ console.log(`$ <<<< $ Command exited with code: ${code}`);
36935
+ },
36936
+ onError(error) {
36937
+ console.log(`$ <<<< $ Command error: ${error}`);
36938
+ }
36939
+ },
36940
+ excludeFiles: options.config.excludeFiles,
36941
+ interactive: options.interactive
36942
+ };
36943
+ const platform = os.platform();
36944
+ const agents = [coderAgentInfo, architectAgentInfo];
36945
+ this.#multiAgent = new MultiAgent({
36946
+ createAgent: async (name) => {
36947
+ const agentName = name.trim().toLowerCase();
36948
+ switch (agentName) {
36949
+ case coderAgentInfo.name:
36950
+ return new CoderAgent({
36951
+ ai: service,
36952
+ os: platform,
36953
+ customInstructions: rules2,
36954
+ scripts: options.config.scripts,
36955
+ provider: getProvider("coder", options.config, providerOptions),
36956
+ interactive: options.interactive,
36957
+ agents
36958
+ });
36959
+ case architectAgentInfo.name:
36960
+ return new ArchitectAgent({
36961
+ ai: service,
36962
+ os: platform,
36963
+ customInstructions: rules2,
36964
+ scripts: options.config.scripts,
36965
+ provider: getProvider("architect", options.config, providerOptions),
36966
+ interactive: options.interactive,
36967
+ agents
36968
+ });
36969
+ case analyzerAgentInfo.name:
36970
+ return new AnalyzerAgent({
36971
+ ai: service,
36972
+ os: platform,
36973
+ customInstructions: rules2,
36974
+ scripts: options.config.scripts,
36975
+ provider: getProvider("analyzer", options.config, providerOptions),
36976
+ interactive: options.interactive,
36977
+ agents
36978
+ });
36979
+ default:
36980
+ throw new Error(`Unknown agent: ${name}`);
36981
+ }
36982
+ },
36983
+ getContext: async (name, context, files) => {
36984
+ let ret = await this.#defaultContext(name);
36985
+ const unreadableFiles = [];
36986
+ if (files) {
36987
+ for (const file of files) {
36988
+ try {
36989
+ const fileContent = await readFile2(file, "utf8");
36990
+ ret += `
36991
+ <file_content path="${file}">${fileContent}</file_content>`;
36992
+ } catch (error) {
36993
+ console.warn(`Failed to read file: ${file}`, error);
36994
+ unreadableFiles.push(file);
36995
+ }
36996
+ }
36997
+ if (unreadableFiles.length > 0) {
36998
+ ret += `
36999
+ <unreadable_files>
37000
+ `;
37001
+ for (const file of unreadableFiles) {
37002
+ ret += `${file}
37003
+ `;
37004
+ }
37005
+ ret += "</unreadable_files>";
37006
+ }
37007
+ }
37008
+ if (context) {
37009
+ ret += `
37010
+
37011
+ ${context}`;
37012
+ }
37013
+ return ret;
37014
+ }
37015
+ });
37016
+ }
37017
+ async#defaultContext(name) {
37018
+ const cwd = process.cwd();
37019
+ const agentConfig = this.#options.config.agents?.[name] ?? this.#options.config.agents?.default ?? {};
37020
+ const maxFileCount = agentConfig.initialContext?.maxFileCount ?? 200;
37021
+ const excludes = agentConfig.initialContext?.excludes ?? [];
37022
+ const finalExcludes = excludes.concat(this.#options.config.excludeFiles ?? []);
37023
+ const [fileList, limited] = await listFiles(cwd, true, maxFileCount, cwd, finalExcludes);
37024
+ const fileContext = `<files>
37025
+ ${fileList.join(`
37026
+ `)}${limited ? `
37027
+ <files_truncated>true</files_truncated>` : ""}
37028
+ </files>`;
37029
+ return `<now_date>${new Date().toISOString()}</now_date>${fileContext}`;
37030
+ }
37031
+ async startTask(task) {
37032
+ const agentName = architectAgentInfo.name;
37033
+ const [exitReason, info] = await this.#multiAgent.startTask({
37034
+ agentName,
37035
+ task,
37036
+ context: await this.#defaultContext(agentName),
37037
+ callback: this.#options.eventCallback
37038
+ });
37039
+ return [exitReason, info];
37040
+ }
37041
+ async continueTask(message, taskInfo) {
37042
+ return await this.#multiAgent.continueTask(message, taskInfo, this.#options.eventCallback);
37043
+ }
37044
+ get usage() {
37045
+ return this.#usageMeter.usage;
37046
+ }
37047
+ printUsage() {
37048
+ this.#usageMeter.printUsage();
37049
+ }
37050
+ }
37051
+
37033
37052
  // src/configPrompt.ts
37034
37053
  var fetchOllamaModels = async () => {
37035
37054
  try {
@@ -41888,6 +41907,10 @@ ${event.systemPrompt}`);
41888
41907
  var runChat = async (opts, command) => {
41889
41908
  const options = command?.parent?.opts() ?? opts ?? {};
41890
41909
  const { config, providerConfig, maxMessageCount, verbose, budget } = parseOptions(options);
41910
+ if (!process.stdin.isTTY) {
41911
+ console.error("Error: Terminal is not interactive. Please run this command in an interactive terminal.");
41912
+ process.exit(1);
41913
+ }
41891
41914
  let { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("coder") ?? {};
41892
41915
  if (!provider2) {
41893
41916
  const newConfig = await configPrompt({ provider: provider2, model, apiKey });
@@ -42613,8 +42636,8 @@ ${result.response}`);
42613
42636
  });
42614
42637
 
42615
42638
  // src/commands/init.ts
42616
- import os4 from "node:os";
42617
42639
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
42640
+ import os4 from "node:os";
42618
42641
  import { dirname as dirname2 } from "node:path";
42619
42642
  var import_lodash3 = __toESM(require_lodash(), 1);
42620
42643
  var initCommand = new Command("init").description("Initialize polkacodes configuration").option("-g, --global", "Use global config");
@@ -42852,48 +42875,77 @@ var prCommand = new Command("pr").description("Create a GitHub pull request").ar
42852
42875
  });
42853
42876
 
42854
42877
  // src/commands/task.ts
42855
- async function runTask(task, _options, command) {
42856
- const { config, providerConfig } = parseOptions(command.opts());
42878
+ var readStdin = async (timeoutMs = 30000) => {
42879
+ if (process.stdin.isTTY) {
42880
+ return "";
42881
+ }
42882
+ return new Promise((resolve2, reject) => {
42883
+ let input = "";
42884
+ let timeoutId = undefined;
42885
+ const cleanup = () => {
42886
+ if (timeoutId)
42887
+ clearTimeout(timeoutId);
42888
+ process.stdin.removeAllListeners();
42889
+ process.stdin.resume();
42890
+ };
42891
+ timeoutId = setTimeout(() => {
42892
+ cleanup();
42893
+ reject(new Error("Stdin read timeout"));
42894
+ }, timeoutMs);
42895
+ process.stdin.on("data", (chunk) => {
42896
+ input += chunk.toString();
42897
+ });
42898
+ process.stdin.on("end", () => {
42899
+ cleanup();
42900
+ if (!input) {
42901
+ reject(new Error("Empty stdin input"));
42902
+ return;
42903
+ }
42904
+ resolve2(input);
42905
+ });
42906
+ process.stdin.on("error", (err) => {
42907
+ cleanup();
42908
+ reject(err);
42909
+ });
42910
+ });
42911
+ };
42912
+ async function runTask(taskArg, _options, command) {
42913
+ let task = taskArg;
42914
+ if (!task) {
42915
+ try {
42916
+ const stdinInput = await readStdin();
42917
+ if (stdinInput) {
42918
+ task = stdinInput;
42919
+ } else {
42920
+ runChat({}, command);
42921
+ return;
42922
+ }
42923
+ } catch (error) {
42924
+ console.error("Error reading stdin:", error);
42925
+ process.exit(1);
42926
+ }
42927
+ }
42928
+ const { config, providerConfig, verbose, maxMessageCount, budget } = parseOptions(command.opts());
42857
42929
  const { provider: provider2, model, apiKey } = providerConfig.getConfigForCommand("task") ?? {};
42858
42930
  if (!provider2 || !model) {
42859
42931
  console.error("Provider and model must be configured");
42860
42932
  process.exit(1);
42861
42933
  }
42862
- if (!task) {
42863
- await runChat({}, command);
42864
- return;
42865
- }
42934
+ console.log("Provider:", provider2);
42935
+ console.log("Model:", model);
42866
42936
  const runner = new Runner({
42867
42937
  provider: provider2,
42868
42938
  model,
42869
42939
  apiKey,
42870
42940
  config,
42871
- maxMessageCount: 100,
42872
- budget: 10,
42873
- interactive: true,
42874
- eventCallback: printEvent(1),
42941
+ maxMessageCount,
42942
+ budget,
42943
+ interactive: process.stdin.isTTY,
42944
+ eventCallback: printEvent(verbose),
42875
42945
  enableCache: true
42876
42946
  });
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
- }
42947
+ await runner.startTask(task);
42948
+ runner.printUsage();
42897
42949
  }
42898
42950
 
42899
42951
  // 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.0",
4
4
  "license": "AGPL-3.0",
5
5
  "type": "module",
6
6
  "bin": {