@pikaa-ai/pikaa 0.3.16 → 0.3.19

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.
package/dist/cli.js CHANGED
@@ -742,9 +742,11 @@ async function captureWorldState(cwd) {
742
742
  };
743
743
  }
744
744
  function formatWorldStatePrompt(state) {
745
+ const isWindows = process.platform === "win32";
746
+ const platformNote = isWindows ? `Platform: Windows (${state.os}). Shell is cmd.exe / PowerShell. POSIX commands (grep, find, cat, sed, awk) are NOT supported in shell. ALWAYS use native grep_search, find_files, and read_file tools.` : `Platform: ${state.os}`;
745
747
  const parts = [
746
748
  `Current Working Directory: ${state.cwd}`,
747
- `Platform: ${state.os}`
749
+ platformNote
748
750
  ];
749
751
  if (state.gitBranch) {
750
752
  parts.push(`Git Branch: ${state.gitBranch}`);
@@ -6429,7 +6431,7 @@ function parsePatch(oldSrc, newSrc, contextLines = 3) {
6429
6431
  // package.json
6430
6432
  var package_default = {
6431
6433
  name: "@pikaa-ai/pikaa",
6432
- version: "0.3.16",
6434
+ version: "0.3.19",
6433
6435
  description: "PIKAA CLI - AI coding agent that runs locally in your terminal.",
6434
6436
  main: "./dist/index.js",
6435
6437
  module: "./dist/index.js",
@@ -6986,12 +6988,23 @@ ${preview}${more}`);
6986
6988
  }
6987
6989
 
6988
6990
  // src/cli/ui/line-editor.ts
6991
+ import readline2 from "readline";
6992
+
6993
+ // src/cli/ui/keypress.ts
6989
6994
  import readline from "readline";
6990
6995
  var keypressEventsInitialized = false;
6991
- function ensureKeypressInitialized() {
6996
+ var listeners = new Set;
6997
+ function initGlobalKeypress() {
6992
6998
  if (!keypressEventsInitialized && process.stdin.isTTY) {
6993
6999
  readline.emitKeypressEvents(process.stdin);
6994
7000
  keypressEventsInitialized = true;
7001
+ process.stdin.on("keypress", (str, key) => {
7002
+ for (const listener of Array.from(listeners)) {
7003
+ try {
7004
+ listener(str, key);
7005
+ } catch {}
7006
+ }
7007
+ });
6995
7008
  process.on("exit", () => {
6996
7009
  if (process.stdin.isTTY) {
6997
7010
  try {
@@ -7001,7 +7014,15 @@ function ensureKeypressInitialized() {
7001
7014
  });
7002
7015
  }
7003
7016
  }
7017
+ function addGlobalKeypressListener(listener) {
7018
+ initGlobalKeypress();
7019
+ listeners.add(listener);
7020
+ return () => {
7021
+ listeners.delete(listener);
7022
+ };
7023
+ }
7004
7024
 
7025
+ // src/cli/ui/line-editor.ts
7005
7026
  class InteractiveLineEditor {
7006
7027
  promptSymbol;
7007
7028
  cwd;
@@ -7052,14 +7073,13 @@ class InteractiveLineEditor {
7052
7073
  async readLine() {
7053
7074
  if (!process.stdin.isTTY) {
7054
7075
  return new Promise((resolve17) => {
7055
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
7076
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
7056
7077
  rl.question(this.promptSymbol, (answer) => {
7057
7078
  rl.close();
7058
7079
  resolve17(answer);
7059
7080
  });
7060
7081
  });
7061
7082
  }
7062
- ensureKeypressInitialized();
7063
7083
  return new Promise((resolve17) => {
7064
7084
  let buffer = "";
7065
7085
  let cursor = 0;
@@ -7067,6 +7087,7 @@ class InteractiveLineEditor {
7067
7087
  let scrollTop = 0;
7068
7088
  let popupDismissed = false;
7069
7089
  let lastCursorRowFromTop = 0;
7090
+ let unsubscribeKeypress = null;
7070
7091
  if (process.stdin.isTTY) {
7071
7092
  try {
7072
7093
  process.stdin.setRawMode(true);
@@ -7244,7 +7265,10 @@ class InteractiveLineEditor {
7244
7265
  if (process.stdout && typeof process.stdout.removeListener === "function") {
7245
7266
  process.stdout.removeListener("resize", onResize);
7246
7267
  }
7247
- process.stdin.removeListener("keypress", onKeypress);
7268
+ if (unsubscribeKeypress) {
7269
+ unsubscribeKeypress();
7270
+ unsubscribeKeypress = null;
7271
+ }
7248
7272
  if (process.stdin.isTTY) {
7249
7273
  try {
7250
7274
  process.stdin.setRawMode(false);
@@ -7284,12 +7308,15 @@ class InteractiveLineEditor {
7284
7308
  process.stdout.write(`\x1B[${lastCursorRowFromTop}A`);
7285
7309
  }
7286
7310
  process.stdout.write("\r\x1B[J");
7311
+ if (unsubscribeKeypress) {
7312
+ unsubscribeKeypress();
7313
+ unsubscribeKeypress = null;
7314
+ }
7287
7315
  if (process.stdin.isTTY) {
7288
7316
  try {
7289
7317
  process.stdin.setRawMode(false);
7290
7318
  } catch {}
7291
7319
  }
7292
- process.stdin.removeListener("keypress", onKeypress);
7293
7320
  if (this.onInterrupt) {
7294
7321
  this.onInterrupt();
7295
7322
  }
@@ -7428,7 +7455,7 @@ class InteractiveLineEditor {
7428
7455
  redraw();
7429
7456
  }
7430
7457
  };
7431
- process.stdin.on("keypress", onKeypress);
7458
+ unsubscribeKeypress = addGlobalKeypressListener(onKeypress);
7432
7459
  const RULE_COLOR = "\x1B[38;2;60;60;68m";
7433
7460
  process.stdout.write(`
7434
7461
  ${RULE_COLOR}${getRule()}\x1B[0m
@@ -7439,31 +7466,27 @@ class InteractiveLineEditor {
7439
7466
  }
7440
7467
 
7441
7468
  // src/cli/ui/prompt.ts
7442
- import readline2 from "readline";
7469
+ import readline3 from "readline";
7443
7470
  async function promptChoice(config) {
7444
7471
  const { message, choices, defaultIndex = 0 } = config;
7445
7472
  if (!process.stdin.isTTY) {
7446
7473
  if (!process.stdin.readable) {
7447
- return choices[defaultIndex]?.value ?? choices[0].value;
7474
+ const def = choices[defaultIndex] || choices[0];
7475
+ return def ? def.value : "";
7448
7476
  }
7449
7477
  return new Promise((resolve17) => {
7450
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
7451
- const hint = choices.map((c3) => c3.isDefault ? `[${c3.key.toUpperCase()}]` : `[${c3.key}]`).join("/");
7452
- let resolved = false;
7453
- const doResolve = (val) => {
7454
- if (!resolved) {
7455
- resolved = true;
7456
- rl.close();
7457
- resolve17(val);
7458
- }
7459
- };
7460
- rl.question(`${message} ${hint}: `, (answer) => {
7478
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
7479
+ const promptText = ` ${message} (${choices.map((c3) => `[${c3.key}] ${c3.label}`).join(", ")}): `;
7480
+ rl.question(promptText, (answer) => {
7481
+ rl.close();
7461
7482
  const trimmed = answer.trim().toLowerCase();
7462
- const matched = choices.find((c3) => c3.key.toLowerCase() === trimmed);
7463
- doResolve(matched ? matched.value : choices[defaultIndex].value);
7464
- });
7465
- rl.on("close", () => {
7466
- doResolve(choices[defaultIndex].value);
7483
+ const match = choices.find((c3) => c3.key.toLowerCase() === trimmed);
7484
+ if (match) {
7485
+ resolve17(match.value);
7486
+ } else {
7487
+ const def = choices[defaultIndex] || choices[0];
7488
+ resolve17(def ? def.value : "");
7489
+ }
7467
7490
  });
7468
7491
  });
7469
7492
  }
@@ -7471,7 +7494,6 @@ async function promptChoice(config) {
7471
7494
  let selectedIndex = defaultIndex;
7472
7495
  if (selectedIndex < 0 || selectedIndex >= choices.length)
7473
7496
  selectedIndex = 0;
7474
- readline2.emitKeypressEvents(process.stdin);
7475
7497
  const wasRaw = process.stdin.isRaw;
7476
7498
  try {
7477
7499
  process.stdin.setRawMode(true);
@@ -7489,8 +7511,12 @@ async function promptChoice(config) {
7489
7511
  process.stdout.write(`\r\x1B[2K ${style.bold(message)}
7490
7512
  \r\x1B[2K${parts.join(" ")}`);
7491
7513
  };
7514
+ let unsubscribe = null;
7492
7515
  const cleanup = (confirmedChoice) => {
7493
- process.stdin.removeListener("keypress", onKeypress);
7516
+ if (unsubscribe) {
7517
+ unsubscribe();
7518
+ unsubscribe = null;
7519
+ }
7494
7520
  try {
7495
7521
  process.stdin.setRawMode(wasRaw ?? false);
7496
7522
  } catch {}
@@ -7502,21 +7528,12 @@ async function promptChoice(config) {
7502
7528
  if (!key)
7503
7529
  return;
7504
7530
  if (key.ctrl && key.name === "c") {
7505
- cleanup(choices.find((c3) => c3.key.toLowerCase() === "n") || choices[defaultIndex]);
7531
+ const def = choices[defaultIndex] || choices[0];
7532
+ cleanup(def);
7506
7533
  return;
7507
7534
  }
7508
- if (key.name === "escape") {
7509
- cleanup(choices.find((c3) => c3.key.toLowerCase() === "n") || choices[defaultIndex]);
7510
- return;
7511
- }
7512
- if (key.name === "return" || key.name === "enter") {
7513
- cleanup(choices[selectedIndex]);
7514
- return;
7515
- }
7516
- if (key.name === "left") {
7535
+ if (key.name === "left" || key.name === "up" || key.name === "h" || key.name === "k") {
7517
7536
  selectedIndex = (selectedIndex - 1 + choices.length) % choices.length;
7518
- process.stdout.write("\x1B[1A");
7519
- render();
7520
7537
  return;
7521
7538
  }
7522
7539
  if (key.name === "right" || key.name === "tab") {
@@ -7573,7 +7590,6 @@ async function promptToolApproval(params) {
7573
7590
  }
7574
7591
  return new Promise((resolve17) => {
7575
7592
  let selectedIndex = 1;
7576
- readline2.emitKeypressEvents(process.stdin);
7577
7593
  const wasRaw = process.stdin.isRaw;
7578
7594
  try {
7579
7595
  process.stdin.setRawMode(true);
@@ -7582,8 +7598,12 @@ async function promptToolApproval(params) {
7582
7598
  const render = () => {
7583
7599
  renderCard(selectedIndex);
7584
7600
  };
7601
+ let unsubscribe = null;
7585
7602
  const cleanup = (val) => {
7586
- process.stdin.removeListener("keypress", onKeypress);
7603
+ if (unsubscribe) {
7604
+ unsubscribe();
7605
+ unsubscribe = null;
7606
+ }
7587
7607
  try {
7588
7608
  process.stdin.setRawMode(wasRaw ?? false);
7589
7609
  } catch {}
@@ -7642,7 +7662,7 @@ async function promptToolApproval(params) {
7642
7662
  return;
7643
7663
  }
7644
7664
  };
7645
- process.stdin.on("keypress", onKeypress);
7665
+ unsubscribe = addGlobalKeypressListener(onKeypress);
7646
7666
  render();
7647
7667
  });
7648
7668
  }
@@ -7672,7 +7692,7 @@ async function promptUserQuestion(params) {
7672
7692
  return options[0] || "yes";
7673
7693
  }
7674
7694
  return new Promise((resolve17) => {
7675
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
7695
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
7676
7696
  const promptLabel = options.length > 0 ? `Select [1-${options.length}] or type custom response: ` : `Your response: `;
7677
7697
  rl.question(` ${style.bold(promptLabel)}`, (answer) => {
7678
7698
  rl.close();
@@ -7741,7 +7761,6 @@ async function promptInteractiveList(config) {
7741
7761
  let selectedIndex = Math.max(0, Math.min(defaultIndex, items.length - 1));
7742
7762
  let scrollTop = 0;
7743
7763
  let renderedLines = 0;
7744
- readline2.emitKeypressEvents(process.stdin);
7745
7764
  const wasRaw = process.stdin.isRaw;
7746
7765
  try {
7747
7766
  process.stdin.setRawMode(true);
@@ -7818,6 +7837,7 @@ async function promptInteractiveList(config) {
7818
7837
  process.stdout.write(buffer);
7819
7838
  renderedLines = lines.length;
7820
7839
  };
7840
+ let unsubscribe = null;
7821
7841
  const cleanup = (res) => {
7822
7842
  if (renderedLines > 0) {
7823
7843
  process.stdout.write(`\x1B[${renderedLines}A\r\x1B[J\x1B[?25h`);
@@ -7825,7 +7845,10 @@ async function promptInteractiveList(config) {
7825
7845
  } else {
7826
7846
  process.stdout.write("\x1B[?25h");
7827
7847
  }
7828
- process.stdin.removeListener("keypress", onKeypress);
7848
+ if (unsubscribe) {
7849
+ unsubscribe();
7850
+ unsubscribe = null;
7851
+ }
7829
7852
  try {
7830
7853
  process.stdin.setRawMode(wasRaw ?? false);
7831
7854
  } catch {}
@@ -7894,7 +7917,7 @@ async function promptInteractiveList(config) {
7894
7917
  render();
7895
7918
  }
7896
7919
  };
7897
- process.stdin.on("keypress", onKeypress);
7920
+ unsubscribe = addGlobalKeypressListener(onKeypress);
7898
7921
  render();
7899
7922
  });
7900
7923
  }
package/dist/index.js CHANGED
@@ -3793,9 +3793,11 @@ async function captureWorldState(cwd) {
3793
3793
  };
3794
3794
  }
3795
3795
  function formatWorldStatePrompt(state) {
3796
+ const isWindows = process.platform === "win32";
3797
+ const platformNote = isWindows ? `Platform: Windows (${state.os}). Shell is cmd.exe / PowerShell. POSIX commands (grep, find, cat, sed, awk) are NOT supported in shell. ALWAYS use native grep_search, find_files, and read_file tools.` : `Platform: ${state.os}`;
3796
3798
  const parts = [
3797
3799
  `Current Working Directory: ${state.cwd}`,
3798
- `Platform: ${state.os}`
3800
+ platformNote
3799
3801
  ];
3800
3802
  if (state.gitBranch) {
3801
3803
  parts.push(`Git Branch: ${state.gitBranch}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikaa-ai/pikaa",
3
- "version": "0.3.16",
3
+ "version": "0.3.19",
4
4
  "description": "PIKAA CLI - AI coding agent that runs locally in your terminal.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -2,7 +2,11 @@ You are Groupy, an expert autonomous AI coding assistant. You are running as a c
2
2
 
3
3
  ## General
4
4
 
5
- - When searching for text or files, prefer using `grep_search` and `find_files`.
5
+ - **CRITICAL: For searching, inspecting, reading, and editing code: ALWAYS use native tools (`grep_search`, `find_files`, `read_file`, `list_dir`, `apply_patch`, `write_file`).**
6
+ - **NEVER use the `shell` tool to run inspection/searching commands (e.g. `grep`, `find`, `cat`, `head`, `tail`, `sed`, `awk`, `ls`).**
7
+ * On Windows, shell commands like `grep` fail or exit with code 1.
8
+ * Native tools (`grep_search`, `find_files`, `read_file`) are structured, fast, and 100% cross-platform.
9
+ - The `shell` tool is reserved strictly for running build/test scripts (e.g. `bun test`, `pytest`, `cargo test`, `npm run build`), git operations, and package manager commands.
6
10
  - **NEVER generate an empty response.** Every turn must either execute the appropriate tools or output a helpful, substantive message.
7
11
  - When the user confirms or gives approval (e.g., "ya lakukan audit", "lanjutkan", "ok", "1"), **IMMEDIATELY start executing the tools** (`read_file`, `list_dir`, `grep_search`, `shell`) in the same turn without hesitation.
8
12