@pikaa-ai/pikaa 0.3.15 → 0.3.18
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 +104 -78
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6429,7 +6429,7 @@ function parsePatch(oldSrc, newSrc, contextLines = 3) {
|
|
|
6429
6429
|
// package.json
|
|
6430
6430
|
var package_default = {
|
|
6431
6431
|
name: "@pikaa-ai/pikaa",
|
|
6432
|
-
version: "0.3.
|
|
6432
|
+
version: "0.3.18",
|
|
6433
6433
|
description: "PIKAA CLI - AI coding agent that runs locally in your terminal.",
|
|
6434
6434
|
main: "./dist/index.js",
|
|
6435
6435
|
module: "./dist/index.js",
|
|
@@ -6986,12 +6986,23 @@ ${preview}${more}`);
|
|
|
6986
6986
|
}
|
|
6987
6987
|
|
|
6988
6988
|
// src/cli/ui/line-editor.ts
|
|
6989
|
+
import readline2 from "readline";
|
|
6990
|
+
|
|
6991
|
+
// src/cli/ui/keypress.ts
|
|
6989
6992
|
import readline from "readline";
|
|
6990
6993
|
var keypressEventsInitialized = false;
|
|
6991
|
-
|
|
6994
|
+
var listeners = new Set;
|
|
6995
|
+
function initGlobalKeypress() {
|
|
6992
6996
|
if (!keypressEventsInitialized && process.stdin.isTTY) {
|
|
6993
6997
|
readline.emitKeypressEvents(process.stdin);
|
|
6994
6998
|
keypressEventsInitialized = true;
|
|
6999
|
+
process.stdin.on("keypress", (str, key) => {
|
|
7000
|
+
for (const listener of Array.from(listeners)) {
|
|
7001
|
+
try {
|
|
7002
|
+
listener(str, key);
|
|
7003
|
+
} catch {}
|
|
7004
|
+
}
|
|
7005
|
+
});
|
|
6995
7006
|
process.on("exit", () => {
|
|
6996
7007
|
if (process.stdin.isTTY) {
|
|
6997
7008
|
try {
|
|
@@ -7001,7 +7012,15 @@ function ensureKeypressInitialized() {
|
|
|
7001
7012
|
});
|
|
7002
7013
|
}
|
|
7003
7014
|
}
|
|
7015
|
+
function addGlobalKeypressListener(listener) {
|
|
7016
|
+
initGlobalKeypress();
|
|
7017
|
+
listeners.add(listener);
|
|
7018
|
+
return () => {
|
|
7019
|
+
listeners.delete(listener);
|
|
7020
|
+
};
|
|
7021
|
+
}
|
|
7004
7022
|
|
|
7023
|
+
// src/cli/ui/line-editor.ts
|
|
7005
7024
|
class InteractiveLineEditor {
|
|
7006
7025
|
promptSymbol;
|
|
7007
7026
|
cwd;
|
|
@@ -7052,21 +7071,21 @@ class InteractiveLineEditor {
|
|
|
7052
7071
|
async readLine() {
|
|
7053
7072
|
if (!process.stdin.isTTY) {
|
|
7054
7073
|
return new Promise((resolve17) => {
|
|
7055
|
-
const rl =
|
|
7074
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
7056
7075
|
rl.question(this.promptSymbol, (answer) => {
|
|
7057
7076
|
rl.close();
|
|
7058
7077
|
resolve17(answer);
|
|
7059
7078
|
});
|
|
7060
7079
|
});
|
|
7061
7080
|
}
|
|
7062
|
-
ensureKeypressInitialized();
|
|
7063
7081
|
return new Promise((resolve17) => {
|
|
7064
7082
|
let buffer = "";
|
|
7065
7083
|
let cursor = 0;
|
|
7066
7084
|
let selectedIndex = 0;
|
|
7067
7085
|
let scrollTop = 0;
|
|
7068
|
-
let renderedMenuLines = 0;
|
|
7069
7086
|
let popupDismissed = false;
|
|
7087
|
+
let lastCursorRowFromTop = 0;
|
|
7088
|
+
let unsubscribeKeypress = null;
|
|
7070
7089
|
if (process.stdin.isTTY) {
|
|
7071
7090
|
try {
|
|
7072
7091
|
process.stdin.setRawMode(true);
|
|
@@ -7129,20 +7148,21 @@ class InteractiveLineEditor {
|
|
|
7129
7148
|
if (scrollTop > maxScroll)
|
|
7130
7149
|
scrollTop = maxScroll;
|
|
7131
7150
|
};
|
|
7132
|
-
const clearMenu = () => {
|
|
7133
|
-
if (renderedMenuLines > 0) {
|
|
7134
|
-
process.stdout.write("\x1B[J");
|
|
7135
|
-
renderedMenuLines = 0;
|
|
7136
|
-
}
|
|
7137
|
-
};
|
|
7138
7151
|
const redraw = () => {
|
|
7139
|
-
|
|
7140
|
-
|
|
7152
|
+
const termCols = getTerminalCols();
|
|
7153
|
+
const visiblePromptWidth = this.promptSymbol.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
7154
|
+
if (lastCursorRowFromTop > 0) {
|
|
7155
|
+
process.stdout.write(`\x1B[${lastCursorRowFromTop}A`);
|
|
7156
|
+
}
|
|
7157
|
+
process.stdout.write("\r\x1B[J");
|
|
7158
|
+
process.stdout.write(`${this.promptSymbol}${buffer}`);
|
|
7159
|
+
const totalPromptChars = visiblePromptWidth + buffer.length;
|
|
7160
|
+
const promptRows = Math.max(1, Math.floor(totalPromptChars / termCols) + 1);
|
|
7141
7161
|
const slashMatches = getMatchingCommands();
|
|
7142
7162
|
const activeFile = getActiveFileQuery();
|
|
7143
7163
|
const fileMatches = activeFile ? getMatchingFiles(activeFile.query) : [];
|
|
7164
|
+
let menuRows = 0;
|
|
7144
7165
|
if (buffer.startsWith("/") && !popupDismissed && slashMatches.length > 0) {
|
|
7145
|
-
const termCols = getTerminalCols();
|
|
7146
7166
|
const BOX_WIDTH = Math.max(20, Math.min(termCols - 4, 120));
|
|
7147
7167
|
const maxVisible = Math.min(slashMatches.length, 7);
|
|
7148
7168
|
ensureVisible(slashMatches.length, maxVisible);
|
|
@@ -7173,10 +7193,8 @@ class InteractiveLineEditor {
|
|
|
7173
7193
|
process.stdout.write(`
|
|
7174
7194
|
\x1B[2K${line}`);
|
|
7175
7195
|
}
|
|
7176
|
-
|
|
7177
|
-
process.stdout.write(`\x1B[${renderedMenuLines}A`);
|
|
7196
|
+
menuRows = menuLines.length;
|
|
7178
7197
|
} else if (activeFile && !popupDismissed && fileMatches.length > 0) {
|
|
7179
|
-
const termCols = getTerminalCols();
|
|
7180
7198
|
const BOX_WIDTH = Math.max(20, Math.min(termCols - 4, 120));
|
|
7181
7199
|
const maxVisible = Math.min(fileMatches.length, 7);
|
|
7182
7200
|
ensureVisible(fileMatches.length, maxVisible);
|
|
@@ -7212,8 +7230,7 @@ class InteractiveLineEditor {
|
|
|
7212
7230
|
process.stdout.write(`
|
|
7213
7231
|
\x1B[2K${line}`);
|
|
7214
7232
|
}
|
|
7215
|
-
|
|
7216
|
-
process.stdout.write(`\x1B[${renderedMenuLines}A`);
|
|
7233
|
+
menuRows = menuLines.length;
|
|
7217
7234
|
} else {
|
|
7218
7235
|
const RULE_COLOR2 = "\x1B[38;2;60;60;68m";
|
|
7219
7236
|
const bottomRule = ` ${RULE_COLOR2}${getRule()}\x1B[0m`;
|
|
@@ -7221,16 +7238,20 @@ class InteractiveLineEditor {
|
|
|
7221
7238
|
process.stdout.write(`
|
|
7222
7239
|
\x1B[2K${bottomRule}
|
|
7223
7240
|
\x1B[2K${modeLine}`);
|
|
7224
|
-
|
|
7225
|
-
|
|
7241
|
+
menuRows = 2;
|
|
7242
|
+
}
|
|
7243
|
+
const cursorCharsFromTop = visiblePromptWidth + cursor;
|
|
7244
|
+
const cursorRow = Math.floor(cursorCharsFromTop / termCols);
|
|
7245
|
+
const cursorCol = cursorCharsFromTop % termCols;
|
|
7246
|
+
const moveUpRows = promptRows - 1 - cursorRow + menuRows;
|
|
7247
|
+
if (moveUpRows > 0) {
|
|
7248
|
+
process.stdout.write(`\x1B[${moveUpRows}A`);
|
|
7226
7249
|
}
|
|
7227
|
-
|
|
7228
|
-
const cursorCol = visiblePromptLength + cursor;
|
|
7250
|
+
process.stdout.write("\r");
|
|
7229
7251
|
if (cursorCol > 0) {
|
|
7230
|
-
process.stdout.write(`\
|
|
7231
|
-
} else {
|
|
7232
|
-
process.stdout.write("\r");
|
|
7252
|
+
process.stdout.write(`\x1B[${cursorCol}C`);
|
|
7233
7253
|
}
|
|
7254
|
+
lastCursorRowFromTop = cursorRow;
|
|
7234
7255
|
};
|
|
7235
7256
|
const onResize = () => {
|
|
7236
7257
|
redraw();
|
|
@@ -7242,19 +7263,25 @@ class InteractiveLineEditor {
|
|
|
7242
7263
|
if (process.stdout && typeof process.stdout.removeListener === "function") {
|
|
7243
7264
|
process.stdout.removeListener("resize", onResize);
|
|
7244
7265
|
}
|
|
7245
|
-
|
|
7246
|
-
|
|
7266
|
+
if (unsubscribeKeypress) {
|
|
7267
|
+
unsubscribeKeypress();
|
|
7268
|
+
unsubscribeKeypress = null;
|
|
7269
|
+
}
|
|
7247
7270
|
if (process.stdin.isTTY) {
|
|
7248
7271
|
try {
|
|
7249
7272
|
process.stdin.setRawMode(false);
|
|
7250
7273
|
} catch {}
|
|
7251
7274
|
}
|
|
7275
|
+
if (lastCursorRowFromTop > 0) {
|
|
7276
|
+
process.stdout.write(`\x1B[${lastCursorRowFromTop}A`);
|
|
7277
|
+
}
|
|
7278
|
+
process.stdout.write("\r\x1B[J");
|
|
7252
7279
|
if (result.trim().length > 0 && !result.startsWith("/")) {
|
|
7253
|
-
process.stdout.write(
|
|
7280
|
+
process.stdout.write(`${CliFormatter.formatClaudeUserPrompt(result)}
|
|
7254
7281
|
|
|
7255
7282
|
`);
|
|
7256
7283
|
} else {
|
|
7257
|
-
process.stdout.write(
|
|
7284
|
+
process.stdout.write(`
|
|
7258
7285
|
`);
|
|
7259
7286
|
}
|
|
7260
7287
|
resolve17(result);
|
|
@@ -7275,13 +7302,19 @@ class InteractiveLineEditor {
|
|
|
7275
7302
|
if (process.stdout && typeof process.stdout.removeListener === "function") {
|
|
7276
7303
|
process.stdout.removeListener("resize", onResize);
|
|
7277
7304
|
}
|
|
7278
|
-
|
|
7305
|
+
if (lastCursorRowFromTop > 0) {
|
|
7306
|
+
process.stdout.write(`\x1B[${lastCursorRowFromTop}A`);
|
|
7307
|
+
}
|
|
7308
|
+
process.stdout.write("\r\x1B[J");
|
|
7309
|
+
if (unsubscribeKeypress) {
|
|
7310
|
+
unsubscribeKeypress();
|
|
7311
|
+
unsubscribeKeypress = null;
|
|
7312
|
+
}
|
|
7279
7313
|
if (process.stdin.isTTY) {
|
|
7280
7314
|
try {
|
|
7281
7315
|
process.stdin.setRawMode(false);
|
|
7282
7316
|
} catch {}
|
|
7283
7317
|
}
|
|
7284
|
-
process.stdin.removeListener("keypress", onKeypress);
|
|
7285
7318
|
if (this.onInterrupt) {
|
|
7286
7319
|
this.onInterrupt();
|
|
7287
7320
|
}
|
|
@@ -7290,12 +7323,9 @@ class InteractiveLineEditor {
|
|
|
7290
7323
|
process.exit(0);
|
|
7291
7324
|
}
|
|
7292
7325
|
if (key.name === "escape") {
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
redraw();
|
|
7297
|
-
return;
|
|
7298
|
-
}
|
|
7326
|
+
popupDismissed = true;
|
|
7327
|
+
redraw();
|
|
7328
|
+
return;
|
|
7299
7329
|
}
|
|
7300
7330
|
if (key.ctrl && key.name === "d") {
|
|
7301
7331
|
cleanupAndResolve("/exit");
|
|
@@ -7423,7 +7453,7 @@ class InteractiveLineEditor {
|
|
|
7423
7453
|
redraw();
|
|
7424
7454
|
}
|
|
7425
7455
|
};
|
|
7426
|
-
|
|
7456
|
+
unsubscribeKeypress = addGlobalKeypressListener(onKeypress);
|
|
7427
7457
|
const RULE_COLOR = "\x1B[38;2;60;60;68m";
|
|
7428
7458
|
process.stdout.write(`
|
|
7429
7459
|
${RULE_COLOR}${getRule()}\x1B[0m
|
|
@@ -7434,31 +7464,27 @@ class InteractiveLineEditor {
|
|
|
7434
7464
|
}
|
|
7435
7465
|
|
|
7436
7466
|
// src/cli/ui/prompt.ts
|
|
7437
|
-
import
|
|
7467
|
+
import readline3 from "readline";
|
|
7438
7468
|
async function promptChoice(config) {
|
|
7439
7469
|
const { message, choices, defaultIndex = 0 } = config;
|
|
7440
7470
|
if (!process.stdin.isTTY) {
|
|
7441
7471
|
if (!process.stdin.readable) {
|
|
7442
|
-
|
|
7472
|
+
const def = choices[defaultIndex] || choices[0];
|
|
7473
|
+
return def ? def.value : "";
|
|
7443
7474
|
}
|
|
7444
7475
|
return new Promise((resolve17) => {
|
|
7445
|
-
const rl =
|
|
7446
|
-
const
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
if (!resolved) {
|
|
7450
|
-
resolved = true;
|
|
7451
|
-
rl.close();
|
|
7452
|
-
resolve17(val);
|
|
7453
|
-
}
|
|
7454
|
-
};
|
|
7455
|
-
rl.question(`${message} ${hint}: `, (answer) => {
|
|
7476
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7477
|
+
const promptText = ` ${message} (${choices.map((c3) => `[${c3.key}] ${c3.label}`).join(", ")}): `;
|
|
7478
|
+
rl.question(promptText, (answer) => {
|
|
7479
|
+
rl.close();
|
|
7456
7480
|
const trimmed = answer.trim().toLowerCase();
|
|
7457
|
-
const
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7481
|
+
const match = choices.find((c3) => c3.key.toLowerCase() === trimmed);
|
|
7482
|
+
if (match) {
|
|
7483
|
+
resolve17(match.value);
|
|
7484
|
+
} else {
|
|
7485
|
+
const def = choices[defaultIndex] || choices[0];
|
|
7486
|
+
resolve17(def ? def.value : "");
|
|
7487
|
+
}
|
|
7462
7488
|
});
|
|
7463
7489
|
});
|
|
7464
7490
|
}
|
|
@@ -7466,7 +7492,6 @@ async function promptChoice(config) {
|
|
|
7466
7492
|
let selectedIndex = defaultIndex;
|
|
7467
7493
|
if (selectedIndex < 0 || selectedIndex >= choices.length)
|
|
7468
7494
|
selectedIndex = 0;
|
|
7469
|
-
readline2.emitKeypressEvents(process.stdin);
|
|
7470
7495
|
const wasRaw = process.stdin.isRaw;
|
|
7471
7496
|
try {
|
|
7472
7497
|
process.stdin.setRawMode(true);
|
|
@@ -7484,8 +7509,12 @@ async function promptChoice(config) {
|
|
|
7484
7509
|
process.stdout.write(`\r\x1B[2K ${style.bold(message)}
|
|
7485
7510
|
\r\x1B[2K${parts.join(" ")}`);
|
|
7486
7511
|
};
|
|
7512
|
+
let unsubscribe = null;
|
|
7487
7513
|
const cleanup = (confirmedChoice) => {
|
|
7488
|
-
|
|
7514
|
+
if (unsubscribe) {
|
|
7515
|
+
unsubscribe();
|
|
7516
|
+
unsubscribe = null;
|
|
7517
|
+
}
|
|
7489
7518
|
try {
|
|
7490
7519
|
process.stdin.setRawMode(wasRaw ?? false);
|
|
7491
7520
|
} catch {}
|
|
@@ -7497,21 +7526,12 @@ async function promptChoice(config) {
|
|
|
7497
7526
|
if (!key)
|
|
7498
7527
|
return;
|
|
7499
7528
|
if (key.ctrl && key.name === "c") {
|
|
7500
|
-
|
|
7529
|
+
const def = choices[defaultIndex] || choices[0];
|
|
7530
|
+
cleanup(def);
|
|
7501
7531
|
return;
|
|
7502
7532
|
}
|
|
7503
|
-
if (key.name === "
|
|
7504
|
-
cleanup(choices.find((c3) => c3.key.toLowerCase() === "n") || choices[defaultIndex]);
|
|
7505
|
-
return;
|
|
7506
|
-
}
|
|
7507
|
-
if (key.name === "return" || key.name === "enter") {
|
|
7508
|
-
cleanup(choices[selectedIndex]);
|
|
7509
|
-
return;
|
|
7510
|
-
}
|
|
7511
|
-
if (key.name === "left") {
|
|
7533
|
+
if (key.name === "left" || key.name === "up" || key.name === "h" || key.name === "k") {
|
|
7512
7534
|
selectedIndex = (selectedIndex - 1 + choices.length) % choices.length;
|
|
7513
|
-
process.stdout.write("\x1B[1A");
|
|
7514
|
-
render();
|
|
7515
7535
|
return;
|
|
7516
7536
|
}
|
|
7517
7537
|
if (key.name === "right" || key.name === "tab") {
|
|
@@ -7568,7 +7588,6 @@ async function promptToolApproval(params) {
|
|
|
7568
7588
|
}
|
|
7569
7589
|
return new Promise((resolve17) => {
|
|
7570
7590
|
let selectedIndex = 1;
|
|
7571
|
-
readline2.emitKeypressEvents(process.stdin);
|
|
7572
7591
|
const wasRaw = process.stdin.isRaw;
|
|
7573
7592
|
try {
|
|
7574
7593
|
process.stdin.setRawMode(true);
|
|
@@ -7577,8 +7596,12 @@ async function promptToolApproval(params) {
|
|
|
7577
7596
|
const render = () => {
|
|
7578
7597
|
renderCard(selectedIndex);
|
|
7579
7598
|
};
|
|
7599
|
+
let unsubscribe = null;
|
|
7580
7600
|
const cleanup = (val) => {
|
|
7581
|
-
|
|
7601
|
+
if (unsubscribe) {
|
|
7602
|
+
unsubscribe();
|
|
7603
|
+
unsubscribe = null;
|
|
7604
|
+
}
|
|
7582
7605
|
try {
|
|
7583
7606
|
process.stdin.setRawMode(wasRaw ?? false);
|
|
7584
7607
|
} catch {}
|
|
@@ -7637,7 +7660,7 @@ async function promptToolApproval(params) {
|
|
|
7637
7660
|
return;
|
|
7638
7661
|
}
|
|
7639
7662
|
};
|
|
7640
|
-
|
|
7663
|
+
unsubscribe = addGlobalKeypressListener(onKeypress);
|
|
7641
7664
|
render();
|
|
7642
7665
|
});
|
|
7643
7666
|
}
|
|
@@ -7667,7 +7690,7 @@ async function promptUserQuestion(params) {
|
|
|
7667
7690
|
return options[0] || "yes";
|
|
7668
7691
|
}
|
|
7669
7692
|
return new Promise((resolve17) => {
|
|
7670
|
-
const rl =
|
|
7693
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7671
7694
|
const promptLabel = options.length > 0 ? `Select [1-${options.length}] or type custom response: ` : `Your response: `;
|
|
7672
7695
|
rl.question(` ${style.bold(promptLabel)}`, (answer) => {
|
|
7673
7696
|
rl.close();
|
|
@@ -7736,7 +7759,6 @@ async function promptInteractiveList(config) {
|
|
|
7736
7759
|
let selectedIndex = Math.max(0, Math.min(defaultIndex, items.length - 1));
|
|
7737
7760
|
let scrollTop = 0;
|
|
7738
7761
|
let renderedLines = 0;
|
|
7739
|
-
readline2.emitKeypressEvents(process.stdin);
|
|
7740
7762
|
const wasRaw = process.stdin.isRaw;
|
|
7741
7763
|
try {
|
|
7742
7764
|
process.stdin.setRawMode(true);
|
|
@@ -7813,6 +7835,7 @@ async function promptInteractiveList(config) {
|
|
|
7813
7835
|
process.stdout.write(buffer);
|
|
7814
7836
|
renderedLines = lines.length;
|
|
7815
7837
|
};
|
|
7838
|
+
let unsubscribe = null;
|
|
7816
7839
|
const cleanup = (res) => {
|
|
7817
7840
|
if (renderedLines > 0) {
|
|
7818
7841
|
process.stdout.write(`\x1B[${renderedLines}A\r\x1B[J\x1B[?25h`);
|
|
@@ -7820,7 +7843,10 @@ async function promptInteractiveList(config) {
|
|
|
7820
7843
|
} else {
|
|
7821
7844
|
process.stdout.write("\x1B[?25h");
|
|
7822
7845
|
}
|
|
7823
|
-
|
|
7846
|
+
if (unsubscribe) {
|
|
7847
|
+
unsubscribe();
|
|
7848
|
+
unsubscribe = null;
|
|
7849
|
+
}
|
|
7824
7850
|
try {
|
|
7825
7851
|
process.stdin.setRawMode(wasRaw ?? false);
|
|
7826
7852
|
} catch {}
|
|
@@ -7889,7 +7915,7 @@ async function promptInteractiveList(config) {
|
|
|
7889
7915
|
render();
|
|
7890
7916
|
}
|
|
7891
7917
|
};
|
|
7892
|
-
|
|
7918
|
+
unsubscribe = addGlobalKeypressListener(onKeypress);
|
|
7893
7919
|
render();
|
|
7894
7920
|
});
|
|
7895
7921
|
}
|