Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
688 lines
22 KiB
TypeScript
688 lines
22 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { getAlignedPrompt } from "./autocomplete/promptDetector.ts";
|
|
import { getCommandToRecordOnEnter } from "./autocomplete/useTerminalAutocomplete.ts";
|
|
|
|
function createFakeTerm(lineText: string, cursorX: number) {
|
|
return {
|
|
buffer: {
|
|
active: {
|
|
cursorX,
|
|
cursorY: 0,
|
|
baseY: 0,
|
|
getLine(line: number) {
|
|
if (line !== 0) return undefined;
|
|
return {
|
|
isWrapped: false,
|
|
translateToString() {
|
|
return lineText;
|
|
},
|
|
};
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
function createWrappedFakeTerm(rows: string[], cursorY: number, cursorX: number, cols: number) {
|
|
return {
|
|
cols,
|
|
buffer: {
|
|
active: {
|
|
cursorX,
|
|
cursorY,
|
|
baseY: 0,
|
|
getLine(line: number) {
|
|
const lineText = rows[line];
|
|
if (lineText === undefined) return undefined;
|
|
return {
|
|
isWrapped: line > 0,
|
|
translateToString() {
|
|
return lineText;
|
|
},
|
|
};
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
|
|
test("records aligned short commands when standard prompt echo lags by one character", () => {
|
|
const cases = [
|
|
{ lineText: "$ l", typedInput: "ls" },
|
|
{ lineText: "$ c", typedInput: "cd" },
|
|
{ lineText: "prod-web> l", typedInput: "ls", promptText: "prod-web> " },
|
|
{ lineText: "prod> l", typedInput: "ls", promptText: "prod> " },
|
|
{ lineText: "prod.web> l", typedInput: "ls", promptText: "prod.web> " },
|
|
{ lineText: "user@host:~$ l", typedInput: "ls", promptText: "user@host:~$ " },
|
|
{ lineText: "[user@host ~]$ l", typedInput: "ls", promptText: "[user@host ~]$ " },
|
|
{ lineText: "➜ netcatty $ l", typedInput: "ls", promptText: "➜ netcatty $ " },
|
|
{ lineText: "➜ git l", typedInput: "ls", promptText: "➜ git " },
|
|
{ lineText: "➜ git np", typedInput: "npm", promptText: "➜ git " },
|
|
];
|
|
|
|
for (const { lineText, typedInput, promptText = "$ " } of cases) {
|
|
const result = getAlignedPrompt(createFakeTerm(lineText, lineText.length) as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.promptText, promptText, lineText);
|
|
assert.equal(result.prompt.userInput, typedInput, lineText);
|
|
assert.equal(result.alignedTyped, typedInput, lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, typedInput, true),
|
|
typedInput,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("records aligned typed input instead of lagging standard prompt input on Enter", () => {
|
|
const typedInput = "git status";
|
|
const term = createFakeTerm("$ git ", "$ git ".length);
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, typedInput, true),
|
|
typedInput,
|
|
);
|
|
});
|
|
|
|
test("does not record themed prompt decorations when typed input is unreliable", () => {
|
|
const cases = [
|
|
{
|
|
lineText: "➜ ~ git status",
|
|
promptText: "➜ ",
|
|
expectedUserInput: " ~ git status",
|
|
},
|
|
{
|
|
lineText: "➜ netcatty git:(main) ✗ git status",
|
|
promptText: "➜ ",
|
|
expectedUserInput: " netcatty git:(main) ✗ git status",
|
|
},
|
|
{
|
|
lineText: " ~ git status",
|
|
promptText: " ",
|
|
expectedUserInput: " ~ git status",
|
|
},
|
|
];
|
|
|
|
for (const { lineText, promptText, expectedUserInput } of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
"",
|
|
false,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.promptText, promptText, lineText);
|
|
assert.equal(result.prompt.userInput, expectedUserInput, lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, "", false),
|
|
null,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("records recognized themed prompts when typed input is unreliable", () => {
|
|
const cases = [
|
|
"➜ git status",
|
|
" git status",
|
|
"➜ netcatty $ git status",
|
|
"➜ netcatty git:(main) ✗ $ git status",
|
|
" ~ $ git status",
|
|
];
|
|
|
|
for (const lineText of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
"",
|
|
false,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.userInput, "git status", lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, "", false),
|
|
"git status",
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("aligns themed bare directory prompts with reliable typed input", () => {
|
|
const cases = [
|
|
{ dir: "netcatty", typedInput: "ls" },
|
|
{ dir: "git", typedInput: "ls" },
|
|
{ dir: "git", typedInput: "npm" },
|
|
{ dir: "git", typedInput: "git status" },
|
|
{ dir: "git", typedInput: "npm test" },
|
|
{ dir: "make", typedInput: "sudo" },
|
|
{ dir: "make", typedInput: "make build" },
|
|
{ dir: "make", typedInput: "git status" },
|
|
{ dir: "node", typedInput: "yarn" },
|
|
{ dir: "node", typedInput: "npm test" },
|
|
{ dir: "docker", typedInput: "git status" },
|
|
{ dir: "go", typedInput: "test" },
|
|
{ dir: "go", typedInput: "npm test" },
|
|
{ dir: "kubectl", typedInput: "sudo" },
|
|
{ dir: "kubectl", typedInput: "git status" },
|
|
];
|
|
|
|
for (const { dir, typedInput } of cases) {
|
|
const lineText = `➜ ${dir} ${typedInput}`;
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
typedInput,
|
|
true,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, dir);
|
|
assert.equal(result.prompt.promptText, `➜ ${dir} `, dir);
|
|
assert.equal(result.prompt.userInput, typedInput, dir);
|
|
assert.equal(result.alignedTyped, typedInput, dir);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, typedInput, true),
|
|
typedInput,
|
|
dir,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("records reliable typed input before shell echo appears", () => {
|
|
const cases = [
|
|
{ lineText: "$ ", typedInput: "ls" },
|
|
{ lineText: "server> ", typedInput: "exit" },
|
|
{ lineText: "staging> ", typedInput: "show dbs" },
|
|
{ lineText: "test> ", typedInput: "exit" },
|
|
{ lineText: "test> ", typedInput: "help" },
|
|
{ lineText: "test> ", typedInput: "show dbs" },
|
|
{ lineText: "➜ git ", typedInput: "npm" },
|
|
{ lineText: "➜ make ", typedInput: "sudo" },
|
|
{ lineText: "➜ node ", typedInput: "yarn" },
|
|
];
|
|
|
|
for (const { lineText, typedInput } of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
typedInput,
|
|
true,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, typedInput, true),
|
|
typedInput,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("does not record reliable typed input before interactive echo appears", () => {
|
|
const cases = [
|
|
{ lineText: "test> ", typedInput: "const x = 1" },
|
|
{ lineText: "test> ", typedInput: "await db.users.findOne()" },
|
|
{ lineText: "test> ", typedInput: "db" },
|
|
{ lineText: "rs0 [direct: primary] reporting> ", typedInput: "const x = 1" },
|
|
{ lineText: "rs0 [direct: primary] reporting> ", typedInput: "await db.users.findOne()" },
|
|
{ lineText: "rs0 [direct: primary] reporting> ", typedInput: "db.stats()" },
|
|
{ lineText: "Atlas a [primary] reporting> ", typedInput: "db.stats()" },
|
|
];
|
|
|
|
for (const { lineText, typedInput } of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
typedInput,
|
|
true,
|
|
);
|
|
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, typedInput, true),
|
|
null,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("detects themed bare directory prompts with standard terminators", () => {
|
|
const cases = [
|
|
{ lineText: "➜ git $ npm test", promptText: "➜ git $ ", typedInput: "npm test" },
|
|
{ lineText: "➜ make $ git status", promptText: "➜ make $ ", typedInput: "git status" },
|
|
];
|
|
|
|
for (const { lineText, promptText, typedInput } of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
"",
|
|
false,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.promptText, promptText, lineText);
|
|
assert.equal(result.prompt.userInput, typedInput, lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, "", false),
|
|
typedInput,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("does not record path-decorated themed prompts when typed input is unreliable", () => {
|
|
const cases = [
|
|
"➜ ~/repo git status",
|
|
" ~/repo git status",
|
|
];
|
|
|
|
for (const lineText of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
"",
|
|
false,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, "", false),
|
|
null,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("does not record partial themed prompt decorations when short command echo lags", () => {
|
|
const cases = [
|
|
{ lineText: "➜ ~ l", typedInput: "ls" },
|
|
{ lineText: "➜ ~ c", typedInput: "cd" },
|
|
{ lineText: "➜ ~ s", typedInput: "sudo" },
|
|
];
|
|
|
|
for (const { lineText, typedInput } of cases) {
|
|
const result = getAlignedPrompt(
|
|
createFakeTerm(lineText, lineText.length) as never,
|
|
typedInput,
|
|
true,
|
|
);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(
|
|
getCommandToRecordOnEnter(result.prompt, result.alignedTyped, typedInput, true),
|
|
null,
|
|
lineText,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("aligns typed input after a no-space root prompt when a short command echo lags by a word", () => {
|
|
const prompt = "root@host:~#";
|
|
const cases = [
|
|
{ echoedInput: "ls ", typedInput: "ls -la" },
|
|
{ echoedInput: "cd ", typedInput: "cd /tmp" },
|
|
];
|
|
|
|
for (const { echoedInput, typedInput } of cases) {
|
|
const lineText = `${prompt}${echoedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, typedInput);
|
|
assert.equal(result.prompt.promptText, prompt, typedInput);
|
|
assert.equal(result.prompt.userInput, typedInput, typedInput);
|
|
assert.equal(result.alignedTyped, typedInput, typedInput);
|
|
}
|
|
});
|
|
|
|
test("aligns typed input after a no-space root prompt when a short command echo lags by one character", () => {
|
|
const prompt = " root@stwo:~#";
|
|
const cases = [
|
|
{ echoedInput: "l", typedInput: "ls" },
|
|
{ echoedInput: "c", typedInput: "cd" },
|
|
];
|
|
|
|
for (const { echoedInput, typedInput } of cases) {
|
|
const lineText = `${prompt}${echoedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, typedInput);
|
|
assert.equal(result.prompt.promptText, prompt, typedInput);
|
|
assert.equal(result.prompt.userInput, typedInput, typedInput);
|
|
assert.equal(result.alignedTyped, typedInput, typedInput);
|
|
}
|
|
});
|
|
|
|
test("does not align stale typed input against unrelated prompt text", () => {
|
|
const term = createFakeTerm("$ ls", 4);
|
|
|
|
const result = getAlignedPrompt(term as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true);
|
|
assert.equal(result.prompt.promptText, "$ ");
|
|
assert.equal(result.prompt.userInput, "ls");
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not align stale typed input when the live command ends with it", () => {
|
|
const term = createFakeTerm("$ echo sudo", "$ echo sudo".length);
|
|
|
|
const result = getAlignedPrompt(term as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true);
|
|
assert.equal(result.prompt.promptText, "$ ");
|
|
assert.equal(result.prompt.userInput, "echo sudo");
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not align stale typed input after host prompt command symbols", () => {
|
|
const prompt = "user@host:~$ ";
|
|
const cases = [
|
|
`${prompt}echo # sudo`,
|
|
`${prompt}printf % sudo`,
|
|
`${prompt}echo $ sudo`,
|
|
];
|
|
|
|
for (const lineText of cases) {
|
|
const result = getAlignedPrompt(createFakeTerm(lineText, lineText.length) as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.promptText, prompt, lineText);
|
|
assert.equal(result.prompt.userInput, lineText.slice(prompt.length), lineText);
|
|
assert.equal(result.alignedTyped, null, lineText);
|
|
}
|
|
});
|
|
|
|
test("does not align stale typed input when the live path ends with it", () => {
|
|
const cases = [
|
|
"$ cd ~/sudo",
|
|
"$ echo /tmp/sudo",
|
|
"$ printf foo:sudo",
|
|
"$ cat ./sudo",
|
|
"$ run [sudo",
|
|
"$ cat > sudo",
|
|
"$ echo path#sudo",
|
|
"$ echo 100%sudo",
|
|
];
|
|
|
|
for (const lineText of cases) {
|
|
const result = getAlignedPrompt(createFakeTerm(lineText, lineText.length) as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.promptText, "$ ", lineText);
|
|
assert.equal(result.prompt.userInput, lineText.slice(2), lineText);
|
|
assert.equal(result.alignedTyped, null, lineText);
|
|
}
|
|
});
|
|
|
|
test("does not align stale typed input from partial echoes after a no-space prompt", () => {
|
|
const prompt = " root@stwo:~#";
|
|
const cases = [
|
|
`${prompt}s`,
|
|
`${prompt}sud`,
|
|
];
|
|
|
|
for (const lineText of cases) {
|
|
const result = getAlignedPrompt(createFakeTerm(lineText, lineText.length) as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false, lineText);
|
|
assert.equal(result.alignedTyped, null, lineText);
|
|
}
|
|
});
|
|
|
|
test("does not align stale typed input after no-space prompt command suffixes", () => {
|
|
const prompt = " root@stwo:~#";
|
|
const cases = [
|
|
`${prompt}cat > sudo`,
|
|
`${prompt}echo # sudo`,
|
|
`${prompt}echo $ sudo`,
|
|
`${prompt}printf % sudo`,
|
|
`${prompt}echo path#sudo`,
|
|
`${prompt}> sudo`,
|
|
`${prompt}# sudo`,
|
|
`${prompt}% sudo`,
|
|
`${prompt}$ sudo`,
|
|
];
|
|
cases.push("root#echo $ sudo", "root@host:~#make $ sudo");
|
|
|
|
for (const lineText of cases) {
|
|
const result = getAlignedPrompt(createFakeTerm(lineText, lineText.length) as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false, lineText);
|
|
assert.equal(result.alignedTyped, null, lineText);
|
|
}
|
|
});
|
|
|
|
test("does not align stale typed input from short standard prompt prefixes", () => {
|
|
for (const lineText of ["$ s", "$ su", "$ sud"]) {
|
|
const result = getAlignedPrompt(createFakeTerm(lineText, lineText.length) as never, "sudo", true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, lineText);
|
|
assert.equal(result.prompt.promptText, "$ ", lineText);
|
|
assert.equal(result.prompt.userInput, lineText.slice(2), lineText);
|
|
assert.equal(result.alignedTyped, null, lineText);
|
|
}
|
|
});
|
|
|
|
test("aligns wrapped typed input after a no-space root prompt", () => {
|
|
const prompt = " root@stwo:~#";
|
|
const typedInput = "printf 1234567890";
|
|
const cols = 20;
|
|
const firstInputSegmentLength = cols - prompt.length;
|
|
const rows = [
|
|
`${prompt}${typedInput.slice(0, firstInputSegmentLength)}`,
|
|
typedInput.slice(firstInputSegmentLength),
|
|
];
|
|
const term = createWrappedFakeTerm(rows, 1, rows[1].length, cols);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true);
|
|
assert.equal(result.prompt.promptText, prompt);
|
|
assert.equal(result.prompt.userInput, typedInput);
|
|
assert.equal(result.alignedTyped, typedInput);
|
|
});
|
|
|
|
test("aligns wrapped typed input after a no-space root prompt when shell echo lags", () => {
|
|
const prompt = " root@stwo:~#";
|
|
const typedInput = "printf 1234567890";
|
|
const echoedInput = typedInput.slice(0, -2);
|
|
const cols = 20;
|
|
const firstInputSegmentLength = cols - prompt.length;
|
|
const rows = [
|
|
`${prompt}${echoedInput.slice(0, firstInputSegmentLength)}`,
|
|
echoedInput.slice(firstInputSegmentLength),
|
|
];
|
|
const term = createWrappedFakeTerm(rows, 1, rows[1].length, cols);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true);
|
|
assert.equal(result.prompt.promptText, prompt);
|
|
assert.equal(result.prompt.userInput, typedInput);
|
|
assert.equal(result.alignedTyped, typedInput);
|
|
});
|
|
|
|
test("does not resurrect python REPL prompts during fallback alignment", () => {
|
|
const typedInput = "print('ok')";
|
|
const lineText = `>>> ${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect mysql REPL prompts during fallback alignment", () => {
|
|
const typedInput = "select 1";
|
|
const lineText = `mysql> ${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect mysql continuation prompts during fallback alignment", () => {
|
|
const prompts = [
|
|
" -> ",
|
|
" '> ",
|
|
" \"> ",
|
|
" `> ",
|
|
];
|
|
|
|
for (const prompt of prompts) {
|
|
const typedInput = "select 1";
|
|
const term = createFakeTerm(`${prompt}${typedInput}`, prompt.length + typedInput.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false, prompt);
|
|
assert.equal(result.alignedTyped, null, prompt);
|
|
}
|
|
});
|
|
|
|
test("does not resurrect redis-cli REPL prompts during fallback alignment", () => {
|
|
const prompts = [
|
|
"redis-cli> ",
|
|
"redis> ",
|
|
"127.0.0.1:6379> ",
|
|
"127.0.0.1:6379[1]> ",
|
|
"localhost:6379> ",
|
|
];
|
|
|
|
for (const prompt of prompts) {
|
|
const typedInput = "get key";
|
|
const term = createFakeTerm(`${prompt}${typedInput}`, prompt.length + typedInput.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false, prompt);
|
|
assert.equal(result.alignedTyped, null, prompt);
|
|
}
|
|
});
|
|
|
|
test("does not resurrect mariadb REPL prompts during fallback alignment", () => {
|
|
const typedInput = "select 1";
|
|
const prompt = "MariaDB [(none)]> ";
|
|
const term = createFakeTerm(`${prompt}${typedInput}`, prompt.length + typedInput.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect postgres REPL prompts during fallback alignment", () => {
|
|
for (const prompt of [
|
|
"postgres=# ",
|
|
"postgres=> ",
|
|
"postgres-# ",
|
|
"postgres'# ",
|
|
"postgres(# ",
|
|
"postgres*# ",
|
|
"postgres!# ",
|
|
"postgres^# ",
|
|
"postgres$tag$# ",
|
|
"postgres(> ",
|
|
"postgres*> ",
|
|
"postgres!> ",
|
|
"postgres^> ",
|
|
"postgres$tag$> ",
|
|
]) {
|
|
const typedInput = "select 1";
|
|
const term = createFakeTerm(`${prompt}${typedInput}`, prompt.length + typedInput.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false, prompt);
|
|
assert.equal(result.alignedTyped, null, prompt);
|
|
}
|
|
});
|
|
|
|
test("keeps host-style greater-than shell prompts", () => {
|
|
const prompt = "prod-web> ";
|
|
for (const typedInput of ["deploy", "exit", "show dbs", "use app", "it", "help", "print(1)"]) {
|
|
const term = createFakeTerm(`${prompt}${typedInput}`, prompt.length + typedInput.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true, typedInput);
|
|
assert.equal(result.prompt.promptText, prompt, typedInput);
|
|
assert.equal(result.prompt.userInput, typedInput, typedInput);
|
|
assert.equal(result.alignedTyped, typedInput, typedInput);
|
|
}
|
|
});
|
|
|
|
test("does not resurrect shell continuation prompts during fallback alignment", () => {
|
|
const typedInput = "echo ok";
|
|
const lineText = `> ${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect no-space python REPL prompts during fallback alignment", () => {
|
|
const typedInput = "print(1)";
|
|
const lineText = `>>>${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect no-space mysql REPL prompts during fallback alignment", () => {
|
|
const typedInput = "select 1";
|
|
const lineText = `mysql>${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect host-like no-space REPL prompts during fallback alignment", () => {
|
|
const typedInput = "select 1";
|
|
const lineText = `user@db>${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("does not resurrect no-space shell continuation prompts during fallback alignment", () => {
|
|
const typedInput = "echo ok";
|
|
const lineText = `>${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, false);
|
|
assert.equal(result.alignedTyped, null);
|
|
});
|
|
|
|
test("keeps typed command intact for PUA-only prompts when command text contains Powerline glyphs", () => {
|
|
const typedInput = "echo foo";
|
|
const lineText = ` root ~ ${typedInput}`;
|
|
const term = createFakeTerm(lineText, lineText.length);
|
|
|
|
const result = getAlignedPrompt(term as never, typedInput, true);
|
|
|
|
assert.equal(result.prompt.isAtPrompt, true);
|
|
assert.equal(result.prompt.promptText, " root ~ ");
|
|
assert.equal(result.prompt.userInput, typedInput);
|
|
assert.equal(result.alignedTyped, typedInput);
|
|
});
|