@rennii/deepseek-cli 1.0.1 → 1.0.2
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/deepseek-cli.js +33 -11
- package/package.json +1 -1
- package/test-deepseek-cli.js +7 -0
package/deepseek-cli.js
CHANGED
|
@@ -174,6 +174,12 @@ function matchingCommands(prefix) {
|
|
|
174
174
|
return COMMAND_SUGGESTIONS.filter(([command]) => command.startsWith(prefix.toLowerCase()));
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
function selectedCommand(prefix, selected = 0) {
|
|
178
|
+
const matches = matchingCommands(prefix);
|
|
179
|
+
if (!matches.length) return null;
|
|
180
|
+
return matches[((selected % matches.length) + matches.length) % matches.length][0];
|
|
181
|
+
}
|
|
182
|
+
|
|
177
183
|
function parseSseEvent(event, state, onDelta) {
|
|
178
184
|
if (event.response_message_id != null) state.parentMessageId = event.response_message_id;
|
|
179
185
|
const path = event.p;
|
|
@@ -355,20 +361,22 @@ class TerminalUI {
|
|
|
355
361
|
].join("\n"));
|
|
356
362
|
}
|
|
357
363
|
|
|
358
|
-
showCommandSuggestions(prefix) {
|
|
359
|
-
const
|
|
360
|
-
|
|
364
|
+
showCommandSuggestions(prefix, selected = 0) {
|
|
365
|
+
const matches = matchingCommands(prefix);
|
|
366
|
+
const active = matches.length ? ((selected % matches.length) + matches.length) % matches.length : 0;
|
|
367
|
+
const suggestions = matches.map(([command, description], index) =>
|
|
368
|
+
`${index === active ? `${CYAN}›${RESET}` : " "} ${CYAN}${command.slice(0, prefix.length)}${RESET}${DIM}${command.slice(prefix.length)}${RESET} ${DIM}${description}${RESET}`,
|
|
361
369
|
);
|
|
362
370
|
this.write(`\x1b[s\n\x1b[J${suggestions.join("\n")}\x1b[u`);
|
|
363
371
|
}
|
|
364
372
|
|
|
365
373
|
clearCommandSuggestions() { this.write("\x1b[J"); }
|
|
366
374
|
|
|
367
|
-
completeCommand(characters) {
|
|
375
|
+
completeCommand(characters, selected = 0) {
|
|
368
376
|
const prefix = characters.join("");
|
|
369
|
-
const
|
|
370
|
-
if (
|
|
371
|
-
const suffix =
|
|
377
|
+
const command = selectedCommand(prefix, selected);
|
|
378
|
+
if (!command || command === prefix.toLowerCase()) return false;
|
|
379
|
+
const suffix = command.slice(prefix.length);
|
|
372
380
|
characters.push(...suffix);
|
|
373
381
|
this.write(`${DIM}${suffix}${RESET}`);
|
|
374
382
|
this.clearCommandSuggestions();
|
|
@@ -385,6 +393,7 @@ class TerminalUI {
|
|
|
385
393
|
const reader = new RawReader();
|
|
386
394
|
const characters = [];
|
|
387
395
|
let pending = null;
|
|
396
|
+
let selectedSuggestion = 0;
|
|
388
397
|
reader.open();
|
|
389
398
|
try {
|
|
390
399
|
while (true) {
|
|
@@ -394,7 +403,7 @@ class TerminalUI {
|
|
|
394
403
|
const character = chunk[index];
|
|
395
404
|
if (character === "\u0003") throw new UserInterrupted();
|
|
396
405
|
if (character === "\r" || character === "\n") {
|
|
397
|
-
if (characters[0] === "/" && !characters.includes("\n") && this.completeCommand(characters)) continue;
|
|
406
|
+
if (characters[0] === "/" && !characters.includes("\n") && this.completeCommand(characters, selectedSuggestion)) continue;
|
|
398
407
|
if (characters[0] === "/") this.clearCommandSuggestions();
|
|
399
408
|
if (index === chunk.length - 1) {
|
|
400
409
|
const next = await reader.next(120);
|
|
@@ -413,18 +422,31 @@ class TerminalUI {
|
|
|
413
422
|
characters.pop();
|
|
414
423
|
this.write("\b \b");
|
|
415
424
|
}
|
|
416
|
-
|
|
425
|
+
selectedSuggestion = 0;
|
|
426
|
+
if (characters[0] === "/" && !characters.includes("\n")) this.showCommandSuggestions(characters.join(""), selectedSuggestion);
|
|
417
427
|
else if (!characters.length) this.clearCommandSuggestions();
|
|
418
428
|
continue;
|
|
419
429
|
}
|
|
420
430
|
if (character === "\u001b") {
|
|
431
|
+
const sequence = chunk.slice(index, index + 3);
|
|
432
|
+
const direction = sequence === "\u001b[A" ? -1 : sequence === "\u001b[B" ? 1 : 0;
|
|
433
|
+
if (direction && characters[0] === "/" && !characters.includes("\n")) {
|
|
434
|
+
const matches = matchingCommands(characters.join(""));
|
|
435
|
+
if (matches.length) {
|
|
436
|
+
selectedSuggestion = (selectedSuggestion + direction + matches.length) % matches.length;
|
|
437
|
+
this.showCommandSuggestions(characters.join(""), selectedSuggestion);
|
|
438
|
+
}
|
|
439
|
+
index += 2;
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
421
442
|
while (index + 1 < chunk.length && !/[A-Za-z~]/.test(chunk[index + 1])) index += 1;
|
|
422
443
|
continue;
|
|
423
444
|
}
|
|
424
445
|
if (character >= " ") {
|
|
425
446
|
characters.push(character);
|
|
426
447
|
this.write(character);
|
|
427
|
-
|
|
448
|
+
selectedSuggestion = 0;
|
|
449
|
+
if (characters[0] === "/" && !characters.includes("\n")) this.showCommandSuggestions(characters.join(""), selectedSuggestion);
|
|
428
450
|
}
|
|
429
451
|
}
|
|
430
452
|
}
|
|
@@ -818,7 +840,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
818
840
|
await cli.run();
|
|
819
841
|
}
|
|
820
842
|
|
|
821
|
-
module.exports = { DATA_DIR, DeepSeekCLI, RUNTIME_DATA, SessionStore, bootstrapDataDirectory, extractCommands, formatCommandFeedback, main, matchingCommands, newLocalSession, parseSseEvent, sessionPickerLine };
|
|
843
|
+
module.exports = { DATA_DIR, DeepSeekCLI, RUNTIME_DATA, SessionStore, bootstrapDataDirectory, extractCommands, formatCommandFeedback, main, matchingCommands, newLocalSession, parseSseEvent, selectedCommand, sessionPickerLine };
|
|
822
844
|
|
|
823
845
|
if (require.main === module) {
|
|
824
846
|
main().catch((error) => {
|
package/package.json
CHANGED
package/test-deepseek-cli.js
CHANGED
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
matchingCommands,
|
|
15
15
|
newLocalSession,
|
|
16
16
|
parseSseEvent,
|
|
17
|
+
selectedCommand,
|
|
17
18
|
sessionPickerLine,
|
|
18
19
|
} = require("./deepseek-cli");
|
|
19
20
|
|
|
@@ -21,6 +22,12 @@ test("filters slash commands by typed prefix", () => {
|
|
|
21
22
|
assert.deepEqual(matchingCommands("/res").map(([command]) => command), ["/resume"]);
|
|
22
23
|
});
|
|
23
24
|
|
|
25
|
+
test("selects a slash-command suggestion by arrow position", () => {
|
|
26
|
+
assert.equal(selectedCommand("/", 0), "/login");
|
|
27
|
+
assert.equal(selectedCommand("/", 1), "/logout");
|
|
28
|
+
assert.equal(selectedCommand("/res", 0), "/resume");
|
|
29
|
+
});
|
|
30
|
+
|
|
24
31
|
test("login opens the official DeepSeek page", async () => {
|
|
25
32
|
const directory = mkdtempSync(join(tmpdir(), "deepseek-cli-"));
|
|
26
33
|
try {
|