dskcode 0.1.14 → 0.1.16
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/index.js +691 -186
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -487,9 +487,294 @@ async function promptForApiKey() {
|
|
|
487
487
|
});
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
// src/cli/skill-import.ts
|
|
491
|
+
import { createInterface as createInterface2 } from "readline";
|
|
492
|
+
import { existsSync as existsSync2, statSync, lstatSync } from "fs";
|
|
493
|
+
import { mkdir as mkdir2, readdir, cp, access, realpath, readFile as readFile2 } from "fs/promises";
|
|
494
|
+
import { join as join2 } from "path";
|
|
495
|
+
import chalk3 from "chalk";
|
|
496
|
+
function getClaudeSkillsDir() {
|
|
497
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
498
|
+
return join2(home, ".claude", "skills");
|
|
499
|
+
}
|
|
500
|
+
function getDskcodeSkillsDir() {
|
|
501
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
502
|
+
return join2(home, ".dskcode", "skills");
|
|
503
|
+
}
|
|
504
|
+
async function isSkillDir(dir) {
|
|
505
|
+
try {
|
|
506
|
+
await access(join2(dir, "SKILL.md"));
|
|
507
|
+
return true;
|
|
508
|
+
} catch {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
async function listClaudeSkills() {
|
|
513
|
+
const claudeDir = getClaudeSkillsDir();
|
|
514
|
+
if (!existsSync2(claudeDir)) return [];
|
|
515
|
+
let entries;
|
|
516
|
+
try {
|
|
517
|
+
entries = await readdir(claudeDir);
|
|
518
|
+
} catch {
|
|
519
|
+
return [];
|
|
520
|
+
}
|
|
521
|
+
const skills = [];
|
|
522
|
+
for (const name of entries) {
|
|
523
|
+
const full = join2(claudeDir, name);
|
|
524
|
+
const stat = statSync(full);
|
|
525
|
+
if (stat.isDirectory() && await isSkillDir(full)) {
|
|
526
|
+
skills.push(name);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return skills;
|
|
530
|
+
}
|
|
531
|
+
function askConfirm(question) {
|
|
532
|
+
const rl = createInterface2({
|
|
533
|
+
input: process.stdin,
|
|
534
|
+
output: process.stdout
|
|
535
|
+
});
|
|
536
|
+
return new Promise((resolve) => {
|
|
537
|
+
let resolved = false;
|
|
538
|
+
const cleanup = () => {
|
|
539
|
+
if (resolved) return;
|
|
540
|
+
resolved = true;
|
|
541
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
542
|
+
rl.close();
|
|
543
|
+
};
|
|
544
|
+
const onKeypress = (_, key) => {
|
|
545
|
+
if (key.ctrl && key.name === "c") {
|
|
546
|
+
cleanup();
|
|
547
|
+
resolve(false);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
process.stdin.on("keypress", onKeypress);
|
|
551
|
+
rl.question(question, (answer) => {
|
|
552
|
+
cleanup();
|
|
553
|
+
const trimmed = answer.trim().toLowerCase();
|
|
554
|
+
resolve(trimmed === "y" || trimmed === "yes");
|
|
555
|
+
});
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
async function importClaudeSkills(skillNames) {
|
|
559
|
+
const claudeDir = getClaudeSkillsDir();
|
|
560
|
+
const dskcodeDir = getDskcodeSkillsDir();
|
|
561
|
+
await mkdir2(dskcodeDir, { recursive: true });
|
|
562
|
+
const imported = [];
|
|
563
|
+
const skipped = [];
|
|
564
|
+
for (const name of skillNames) {
|
|
565
|
+
const src = join2(claudeDir, name);
|
|
566
|
+
const dest = join2(dskcodeDir, name);
|
|
567
|
+
if (existsSync2(dest)) {
|
|
568
|
+
skipped.push(name);
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
const realSrc = lstatSync(src).isSymbolicLink() ? await realpath(src) : src;
|
|
572
|
+
await cp(realSrc, dest, { recursive: true, dereference: true });
|
|
573
|
+
imported.push(name);
|
|
574
|
+
}
|
|
575
|
+
return { imported, skipped };
|
|
576
|
+
}
|
|
577
|
+
async function countDskcodeSkills() {
|
|
578
|
+
const dskcodeDir = getDskcodeSkillsDir();
|
|
579
|
+
if (!existsSync2(dskcodeDir)) return 0;
|
|
580
|
+
let entries;
|
|
581
|
+
try {
|
|
582
|
+
entries = await readdir(dskcodeDir);
|
|
583
|
+
} catch {
|
|
584
|
+
return 0;
|
|
585
|
+
}
|
|
586
|
+
let count = 0;
|
|
587
|
+
for (const name of entries) {
|
|
588
|
+
const full = join2(dskcodeDir, name);
|
|
589
|
+
if (statSync(full).isDirectory() && await isSkillDir(full)) {
|
|
590
|
+
count++;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return count;
|
|
594
|
+
}
|
|
595
|
+
function getProjectSkillDir(cwd) {
|
|
596
|
+
return join2(cwd, ".dskcode", "skill");
|
|
597
|
+
}
|
|
598
|
+
async function hasProjectLocalSkills(cwd) {
|
|
599
|
+
const count = await countProjectLocalSkills(cwd);
|
|
600
|
+
return count > 0;
|
|
601
|
+
}
|
|
602
|
+
async function countProjectLocalSkills(cwd) {
|
|
603
|
+
const skillDir = getProjectSkillDir(cwd);
|
|
604
|
+
if (!existsSync2(skillDir)) return 0;
|
|
605
|
+
let entries;
|
|
606
|
+
try {
|
|
607
|
+
entries = await readdir(skillDir);
|
|
608
|
+
} catch {
|
|
609
|
+
return 0;
|
|
610
|
+
}
|
|
611
|
+
let count = 0;
|
|
612
|
+
for (const name of entries) {
|
|
613
|
+
const full = join2(skillDir, name);
|
|
614
|
+
const stat = statSync(full);
|
|
615
|
+
if (stat.isDirectory() && await isSkillDir(full)) {
|
|
616
|
+
count++;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return count;
|
|
620
|
+
}
|
|
621
|
+
async function hasDskcodeSkills() {
|
|
622
|
+
const dskcodeDir = getDskcodeSkillsDir();
|
|
623
|
+
if (!existsSync2(dskcodeDir)) return false;
|
|
624
|
+
let entries;
|
|
625
|
+
try {
|
|
626
|
+
entries = await readdir(dskcodeDir);
|
|
627
|
+
} catch {
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
for (const name of entries) {
|
|
631
|
+
const full = join2(dskcodeDir, name);
|
|
632
|
+
const stat = statSync(full);
|
|
633
|
+
if (stat.isDirectory() && await isSkillDir(full)) {
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
async function promptImportClaudeSkills(cwd) {
|
|
640
|
+
if (cwd) {
|
|
641
|
+
const hasLocal = await hasProjectLocalSkills(cwd);
|
|
642
|
+
if (hasLocal) {
|
|
643
|
+
console.log(chalk3.dim(" \u68C0\u6D4B\u5230\u9879\u76EE\u672C\u5730 .dskcode/skill\uFF0C\u8DF3\u8FC7\u5BFC\u5165 Claude Code skill\n"));
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
const hasGlobal = await hasDskcodeSkills();
|
|
648
|
+
if (hasGlobal) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const skills = await listClaudeSkills();
|
|
652
|
+
if (skills.length === 0) return;
|
|
653
|
+
console.log(chalk3.cyan(`
|
|
654
|
+
\u2726 \u68C0\u6D4B\u5230\u4F60\u5728 Claude Code \u4E2D\u5B89\u88C5\u4E86 ${String(skills.length)} \u4E2A skill\uFF1A`));
|
|
655
|
+
const preview = skills.slice(0, 5).map((s) => chalk3.dim(` \xB7 ${s}`)).join("\n");
|
|
656
|
+
console.log(preview);
|
|
657
|
+
if (skills.length > 5) {
|
|
658
|
+
console.log(chalk3.dim(` \xB7 ...\u7B49 ${String(skills.length)} \u4E2A`));
|
|
659
|
+
}
|
|
660
|
+
console.log(chalk3.dim(` \u6E90\u76EE\u5F55: ${getClaudeSkillsDir()}`));
|
|
661
|
+
console.log(chalk3.dim(` \u76EE\u6807\u76EE\u5F55: ${getDskcodeSkillsDir()}
|
|
662
|
+
`));
|
|
663
|
+
const confirmed = await askConfirm(
|
|
664
|
+
` ${chalk3.cyan("\u{1F4E6}")} \u662F\u5426\u5C06\u8FD9\u4E9B skill \u5BFC\u5165\u5230 dskcode\uFF1F${chalk3.dim("[y/N] ")} `
|
|
665
|
+
);
|
|
666
|
+
if (!confirmed) {
|
|
667
|
+
console.log(chalk3.dim(" \u5DF2\u8DF3\u8FC7 skill \u5BFC\u5165\n"));
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
try {
|
|
671
|
+
const { imported, skipped } = await importClaudeSkills(skills);
|
|
672
|
+
if (imported.length > 0) {
|
|
673
|
+
console.log(
|
|
674
|
+
chalk3.green(` \u2714 \u5DF2\u5BFC\u5165 ${String(imported.length)} \u4E2A skill \u5230 ~/.dskcode/skills`)
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
if (skipped.length > 0) {
|
|
678
|
+
console.log(
|
|
679
|
+
chalk3.yellow(` \u26A0 ${String(skipped.length)} \u4E2A skill \u5DF2\u5B58\u5728\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${skipped.join(", ")}`)
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
console.log("");
|
|
683
|
+
} catch (err) {
|
|
684
|
+
console.log(
|
|
685
|
+
chalk3.red(` \u2716 \u5BFC\u5165 skill \u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`)
|
|
686
|
+
);
|
|
687
|
+
console.log(chalk3.dim(" \u4F60\u53EF\u4EE5\u7A0D\u540E\u624B\u52A8\u590D\u5236 ~/.claude/skills \u5230 ~/.dskcode/skills\n"));
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
async function listDskcodeSkills() {
|
|
691
|
+
const dskcodeDir = getDskcodeSkillsDir();
|
|
692
|
+
if (!existsSync2(dskcodeDir)) return [];
|
|
693
|
+
let entries;
|
|
694
|
+
try {
|
|
695
|
+
entries = await readdir(dskcodeDir);
|
|
696
|
+
} catch {
|
|
697
|
+
return [];
|
|
698
|
+
}
|
|
699
|
+
const skills = [];
|
|
700
|
+
for (const name of entries) {
|
|
701
|
+
const full = join2(dskcodeDir, name);
|
|
702
|
+
if (statSync(full).isDirectory() && await isSkillDir(full)) {
|
|
703
|
+
skills.push(name);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return skills;
|
|
707
|
+
}
|
|
708
|
+
async function listProjectSkills(cwd) {
|
|
709
|
+
const skillDir = getProjectSkillDir(cwd);
|
|
710
|
+
if (!existsSync2(skillDir)) return [];
|
|
711
|
+
let entries;
|
|
712
|
+
try {
|
|
713
|
+
entries = await readdir(skillDir);
|
|
714
|
+
} catch {
|
|
715
|
+
return [];
|
|
716
|
+
}
|
|
717
|
+
const skills = [];
|
|
718
|
+
for (const name of entries) {
|
|
719
|
+
const full = join2(skillDir, name);
|
|
720
|
+
if (statSync(full).isDirectory() && await isSkillDir(full)) {
|
|
721
|
+
skills.push(name);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return skills;
|
|
725
|
+
}
|
|
726
|
+
async function readSkillInfo(skillDir) {
|
|
727
|
+
try {
|
|
728
|
+
const content = await readFile2(join2(skillDir, "SKILL.md"), "utf-8");
|
|
729
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
730
|
+
if (!match) return null;
|
|
731
|
+
const frontMatter = match[1];
|
|
732
|
+
const nameMatch = frontMatter.match(/^name:\s*(.+)$/m);
|
|
733
|
+
const descMatch = frontMatter.match(/^description:\s*(.+)$/m);
|
|
734
|
+
return {
|
|
735
|
+
name: nameMatch?.[1]?.trim() ?? "",
|
|
736
|
+
description: descMatch?.[1]?.trim() ?? ""
|
|
737
|
+
};
|
|
738
|
+
} catch {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
async function getAllSkills(cwd) {
|
|
743
|
+
const [globalNames, localNames] = await Promise.all([
|
|
744
|
+
listDskcodeSkills(),
|
|
745
|
+
listProjectSkills(cwd)
|
|
746
|
+
]);
|
|
747
|
+
const seen = /* @__PURE__ */ new Set();
|
|
748
|
+
const allNames = [];
|
|
749
|
+
for (const name of [...localNames, ...globalNames]) {
|
|
750
|
+
if (!seen.has(name)) {
|
|
751
|
+
seen.add(name);
|
|
752
|
+
allNames.push(name);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
const dskcodeDir = getDskcodeSkillsDir();
|
|
756
|
+
const projectDir = getProjectSkillDir(cwd);
|
|
757
|
+
const results = [];
|
|
758
|
+
for (const name of allNames) {
|
|
759
|
+
const localPath = join2(projectDir, name);
|
|
760
|
+
let info = null;
|
|
761
|
+
if (existsSync2(localPath)) {
|
|
762
|
+
info = await readSkillInfo(localPath);
|
|
763
|
+
}
|
|
764
|
+
if (!info) {
|
|
765
|
+
const globalPath = join2(dskcodeDir, name);
|
|
766
|
+
if (existsSync2(globalPath)) {
|
|
767
|
+
info = await readSkillInfo(globalPath);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
results.push(info ?? { name, description: "" });
|
|
771
|
+
}
|
|
772
|
+
return results;
|
|
773
|
+
}
|
|
774
|
+
|
|
490
775
|
// src/cli/index.tsx
|
|
491
|
-
import { readFile as
|
|
492
|
-
import { join as
|
|
776
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
777
|
+
import { join as join5 } from "path";
|
|
493
778
|
|
|
494
779
|
// src/ui/RenderScope.tsx
|
|
495
780
|
import { render } from "ink";
|
|
@@ -531,7 +816,7 @@ var LOGO_LINES = [
|
|
|
531
816
|
];
|
|
532
817
|
|
|
533
818
|
// src/ui/ChatSession.tsx
|
|
534
|
-
import { Box as
|
|
819
|
+
import { Box as Box7, Text as Text8, useInput, Static } from "ink";
|
|
535
820
|
import TextInput from "ink-text-input";
|
|
536
821
|
import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
537
822
|
|
|
@@ -567,8 +852,8 @@ function useDoubleCtrlC(onExit) {
|
|
|
567
852
|
import { Box as Box4, Text as Text5 } from "ink";
|
|
568
853
|
|
|
569
854
|
// src/provider/cost-tracker.ts
|
|
570
|
-
import { mkdir as
|
|
571
|
-
import { join as
|
|
855
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
856
|
+
import { join as join3 } from "path";
|
|
572
857
|
var CostTracker = class {
|
|
573
858
|
#costDir;
|
|
574
859
|
#budgetLimit;
|
|
@@ -586,7 +871,7 @@ var CostTracker = class {
|
|
|
586
871
|
#flushInProgress = false;
|
|
587
872
|
constructor(options = {}) {
|
|
588
873
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
589
|
-
this.#costDir = options.costDir ??
|
|
874
|
+
this.#costDir = options.costDir ?? join3(home, ".dskcode", "costs");
|
|
590
875
|
this.#budgetLimit = options.budgetLimit ?? 0;
|
|
591
876
|
this.#tokenBudgetLimit = options.tokenBudgetLimit ?? 0;
|
|
592
877
|
this.#onBudgetExceeded = options.onBudgetExceeded;
|
|
@@ -800,9 +1085,9 @@ var CostTracker = class {
|
|
|
800
1085
|
}
|
|
801
1086
|
/** 从磁盘加载成本存储 */
|
|
802
1087
|
async #loadStore() {
|
|
803
|
-
const filePath =
|
|
1088
|
+
const filePath = join3(this.#costDir, "history.json");
|
|
804
1089
|
try {
|
|
805
|
-
const raw = await
|
|
1090
|
+
const raw = await readFile3(filePath, "utf-8");
|
|
806
1091
|
return JSON.parse(raw);
|
|
807
1092
|
} catch {
|
|
808
1093
|
return { version: 1, daily: {} };
|
|
@@ -819,8 +1104,8 @@ var CostTracker = class {
|
|
|
819
1104
|
for (const date of datesToRemove) {
|
|
820
1105
|
delete store.daily[date];
|
|
821
1106
|
}
|
|
822
|
-
await
|
|
823
|
-
const filePath =
|
|
1107
|
+
await mkdir3(this.#costDir, { recursive: true });
|
|
1108
|
+
const filePath = join3(this.#costDir, "history.json");
|
|
824
1109
|
await writeFile2(filePath, JSON.stringify(store, null, 2), "utf-8");
|
|
825
1110
|
}
|
|
826
1111
|
};
|
|
@@ -995,6 +1280,50 @@ function AssistantMessage({
|
|
|
995
1280
|
] });
|
|
996
1281
|
}
|
|
997
1282
|
|
|
1283
|
+
// src/ui/SkillSelector.tsx
|
|
1284
|
+
import { Box as Box5, Text as Text6 } from "ink";
|
|
1285
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1286
|
+
var HIGHLIGHT_COLOR = "#00bfff";
|
|
1287
|
+
function SkillSelector({ skills, input, selectedIndex }) {
|
|
1288
|
+
const match = input.match(/(?:^|\s)\/([^/]*)$/);
|
|
1289
|
+
if (!match) return null;
|
|
1290
|
+
const query = match[1].toLowerCase().trim();
|
|
1291
|
+
if (skills.length === 0) return null;
|
|
1292
|
+
const matched = !query && input.startsWith("/") ? skills.slice(0, 3) : skills.filter((s) => s.name.toLowerCase().includes(query)).slice(0, 3);
|
|
1293
|
+
if (query && matched.length > 0 && matched.some((s) => s.name.toLowerCase() === query)) return null;
|
|
1294
|
+
if (matched.length === 0) return null;
|
|
1295
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
|
|
1296
|
+
/* @__PURE__ */ jsx5(Text6, { color: "#808080", dimColor: true, children: "\u652F\u6301\u7684 Skill\uFF1A" }),
|
|
1297
|
+
matched.map((skill, i) => /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsxs5(Text6, { color: i === selectedIndex ? HIGHLIGHT_COLOR : "#808080", children: [
|
|
1298
|
+
i === selectedIndex ? " \u203A " : " ",
|
|
1299
|
+
skill.name
|
|
1300
|
+
] }) }, skill.name)),
|
|
1301
|
+
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
|
|
1302
|
+
] });
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// src/ui/FileSelector.tsx
|
|
1306
|
+
import { Box as Box6, Text as Text7 } from "ink";
|
|
1307
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1308
|
+
var HIGHLIGHT_COLOR2 = "#00ff41";
|
|
1309
|
+
function FileSelector({ files, input, selectedIndex }) {
|
|
1310
|
+
const match = input.match(/(?:^|\s)@([^@]*)$/);
|
|
1311
|
+
if (!match) return null;
|
|
1312
|
+
const query = match[1].toLowerCase().trim();
|
|
1313
|
+
if (files.length === 0) return null;
|
|
1314
|
+
const matched = !query && input.startsWith("@") ? files.slice(0, 5) : files.filter((f) => f.toLowerCase().includes(query)).slice(0, 5);
|
|
1315
|
+
if (query && matched.some((f) => f.toLowerCase() === query)) return null;
|
|
1316
|
+
if (matched.length === 0) return null;
|
|
1317
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
|
|
1318
|
+
/* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u9879\u76EE\u6587\u4EF6\uFF1A" }),
|
|
1319
|
+
matched.map((file, i) => /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs6(Text7, { color: i === selectedIndex ? HIGHLIGHT_COLOR2 : "#808080", children: [
|
|
1320
|
+
i === selectedIndex ? " \u203A " : " ",
|
|
1321
|
+
file
|
|
1322
|
+
] }) }, file)),
|
|
1323
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
|
|
1324
|
+
] });
|
|
1325
|
+
}
|
|
1326
|
+
|
|
998
1327
|
// src/provider/registry.ts
|
|
999
1328
|
var ProviderRegistry = class {
|
|
1000
1329
|
#factories = /* @__PURE__ */ new Map();
|
|
@@ -1389,7 +1718,7 @@ function getGradientColors(text, phase, stops) {
|
|
|
1389
1718
|
}
|
|
1390
1719
|
|
|
1391
1720
|
// src/ui/ChatSession.tsx
|
|
1392
|
-
import { Fragment, jsx as
|
|
1721
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1393
1722
|
var commandRegistry = /* @__PURE__ */ new Map();
|
|
1394
1723
|
function registerCommand(name, cmd) {
|
|
1395
1724
|
commandRegistry.set(name, cmd);
|
|
@@ -1435,7 +1764,9 @@ function pickRandom(arr) {
|
|
|
1435
1764
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
1436
1765
|
}
|
|
1437
1766
|
function ChatSession({
|
|
1438
|
-
|
|
1767
|
+
skillCount,
|
|
1768
|
+
skills = [],
|
|
1769
|
+
files = [],
|
|
1439
1770
|
toolCount,
|
|
1440
1771
|
verbose,
|
|
1441
1772
|
apiKey,
|
|
@@ -1473,6 +1804,9 @@ function ChatSession({
|
|
|
1473
1804
|
const [cmdTipIndex, setCmdTipIndex] = useState3(0);
|
|
1474
1805
|
const [cmdTipGradientColors, setCmdTipGradientColors] = useState3([]);
|
|
1475
1806
|
const cmdTipPhaseRef = useRef2(0);
|
|
1807
|
+
const [skillSelectIndex, setSkillSelectIndex] = useState3(0);
|
|
1808
|
+
const [fileSelectIndex, setFileSelectIndex] = useState3(0);
|
|
1809
|
+
const [inputKey, setInputKey] = useState3(0);
|
|
1476
1810
|
const [selectingModel, setSelectingModel] = useState3(false);
|
|
1477
1811
|
const [modelSelectIndex, setModelSelectIndex] = useState3(0);
|
|
1478
1812
|
const modelOptions = ["deepseek-v4-flash", "deepseek-v4-pro"];
|
|
@@ -1485,6 +1819,40 @@ function ChatSession({
|
|
|
1485
1819
|
const currentCostRef = useRef2(void 0);
|
|
1486
1820
|
const currentModelRef = useRef2(void 0);
|
|
1487
1821
|
const streamErrorRef = useRef2(void 0);
|
|
1822
|
+
useEffect3(() => {
|
|
1823
|
+
setSkillSelectIndex(0);
|
|
1824
|
+
setFileSelectIndex(0);
|
|
1825
|
+
}, [input]);
|
|
1826
|
+
const getFilteredSkills = useCallback2(
|
|
1827
|
+
(value) => {
|
|
1828
|
+
const match = value.match(/(?:^|\s)\/([^/]*)$/);
|
|
1829
|
+
if (!match) return [];
|
|
1830
|
+
const q = match[1].toLowerCase().trim();
|
|
1831
|
+
if (!q) {
|
|
1832
|
+
if (value.startsWith("/")) return skills.slice(0, 3);
|
|
1833
|
+
return [];
|
|
1834
|
+
}
|
|
1835
|
+
const matched = skills.filter((s) => s.name.toLowerCase().includes(q)).slice(0, 3);
|
|
1836
|
+
if (matched.some((s) => s.name.toLowerCase() === q)) return [];
|
|
1837
|
+
return matched;
|
|
1838
|
+
},
|
|
1839
|
+
[skills]
|
|
1840
|
+
);
|
|
1841
|
+
const getFilteredFiles = useCallback2(
|
|
1842
|
+
(value) => {
|
|
1843
|
+
const match = value.match(/(?:^|\s)@([^@]*)$/);
|
|
1844
|
+
if (!match) return [];
|
|
1845
|
+
const q = match[1].toLowerCase().trim();
|
|
1846
|
+
if (!q) {
|
|
1847
|
+
if (value.startsWith("@")) return files.slice(0, 5);
|
|
1848
|
+
return [];
|
|
1849
|
+
}
|
|
1850
|
+
const matched = files.filter((f) => f.toLowerCase().includes(q)).slice(0, 5);
|
|
1851
|
+
if (matched.some((f) => f.toLowerCase() === q)) return [];
|
|
1852
|
+
return matched;
|
|
1853
|
+
},
|
|
1854
|
+
[files]
|
|
1855
|
+
);
|
|
1488
1856
|
const { doubleCtrlC, handleCtrlC } = useDoubleCtrlC(() => {
|
|
1489
1857
|
process.exit(0);
|
|
1490
1858
|
});
|
|
@@ -1519,6 +1887,50 @@ function ChatSession({
|
|
|
1519
1887
|
}
|
|
1520
1888
|
return;
|
|
1521
1889
|
}
|
|
1890
|
+
const fileList = getFilteredFiles(input);
|
|
1891
|
+
const skillList = fileList.length === 0 ? getFilteredSkills(input) : [];
|
|
1892
|
+
if (fileList.length > 0) {
|
|
1893
|
+
if (key.upArrow) {
|
|
1894
|
+
setFileSelectIndex((prev) => (prev - 1 + fileList.length) % fileList.length);
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
if (key.downArrow) {
|
|
1898
|
+
setFileSelectIndex((prev) => (prev + 1) % fileList.length);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
if (key.tab) {
|
|
1902
|
+
const selected = fileList[fileSelectIndex];
|
|
1903
|
+
if (selected) {
|
|
1904
|
+
const atIdx = input.lastIndexOf("@");
|
|
1905
|
+
if (atIdx >= 0) {
|
|
1906
|
+
setInput(input.slice(0, atIdx) + "@" + selected + " ");
|
|
1907
|
+
setInputKey((k) => k + 1);
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
if (skillList.length > 0) {
|
|
1914
|
+
if (key.upArrow) {
|
|
1915
|
+
setSkillSelectIndex((prev) => (prev - 1 + skillList.length) % skillList.length);
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1918
|
+
if (key.downArrow) {
|
|
1919
|
+
setSkillSelectIndex((prev) => (prev + 1) % skillList.length);
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
if (key.tab) {
|
|
1923
|
+
const selected = skillList[skillSelectIndex];
|
|
1924
|
+
if (selected) {
|
|
1925
|
+
const slashIdx = input.lastIndexOf("/");
|
|
1926
|
+
if (slashIdx >= 0) {
|
|
1927
|
+
setInput(input.slice(0, slashIdx) + "/" + selected.name + " ");
|
|
1928
|
+
setInputKey((k) => k + 1);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1522
1934
|
if (key.ctrl && _input === "c") {
|
|
1523
1935
|
if (isStreaming) {
|
|
1524
1936
|
abortRef.current?.abort();
|
|
@@ -1531,7 +1943,7 @@ function ChatSession({
|
|
|
1531
1943
|
setInput(_input);
|
|
1532
1944
|
}
|
|
1533
1945
|
},
|
|
1534
|
-
[selectingModel, modelSelectIndex, modelOptions, activeModel, isStreaming, handleCtrlC, input]
|
|
1946
|
+
[selectingModel, modelSelectIndex, modelOptions, activeModel, isStreaming, handleCtrlC, input, skills, skillSelectIndex, fileSelectIndex, getFilteredSkills, getFilteredFiles]
|
|
1535
1947
|
)
|
|
1536
1948
|
);
|
|
1537
1949
|
useEffect3(() => {
|
|
@@ -1651,7 +2063,7 @@ function ChatSession({
|
|
|
1651
2063
|
const handleSubmit = useCallback2(async (value) => {
|
|
1652
2064
|
const trimmed = value.trim();
|
|
1653
2065
|
if (!trimmed) return;
|
|
1654
|
-
if (trimmed.startsWith("/")) {
|
|
2066
|
+
if (trimmed.startsWith("/") && trimmed.length > 1) {
|
|
1655
2067
|
if (trimmed.toLowerCase() === "/model") {
|
|
1656
2068
|
const curIdx = modelOptions.indexOf(activeModel);
|
|
1657
2069
|
setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
|
|
@@ -1797,7 +2209,7 @@ function ChatSession({
|
|
|
1797
2209
|
]);
|
|
1798
2210
|
}
|
|
1799
2211
|
}
|
|
1800
|
-
}, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls]);
|
|
2212
|
+
}, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills]);
|
|
1801
2213
|
useEffect3(() => {
|
|
1802
2214
|
if (!isStreaming && externalCostTracker) {
|
|
1803
2215
|
setTodayCost(externalCostTracker.todayTotalCost);
|
|
@@ -1812,26 +2224,26 @@ function ChatSession({
|
|
|
1812
2224
|
});
|
|
1813
2225
|
}
|
|
1814
2226
|
}, [currentUsage, streamingModel, currentCost]);
|
|
1815
|
-
return /* @__PURE__ */
|
|
1816
|
-
/* @__PURE__ */
|
|
1817
|
-
/* @__PURE__ */
|
|
2227
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
|
|
2228
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", marginBottom: 1, children: [
|
|
2229
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
|
|
1818
2230
|
const colorIndex = (i + offset) % CYBER_PALETTE.length;
|
|
1819
|
-
return /* @__PURE__ */
|
|
2231
|
+
return /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
|
|
1820
2232
|
}) }),
|
|
1821
|
-
/* @__PURE__ */
|
|
1822
|
-
/* @__PURE__ */
|
|
2233
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", justifyContent: "center", children: [
|
|
2234
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "#00ff41", children: [
|
|
1823
2235
|
" \u2714 ",
|
|
1824
|
-
"\u5DF2\
|
|
1825
|
-
|
|
1826
|
-
" \u4E2A
|
|
2236
|
+
"\u5DF2\u5C31\u7EEA ",
|
|
2237
|
+
skillCount,
|
|
2238
|
+
" \u4E2A Skill"
|
|
1827
2239
|
] }),
|
|
1828
|
-
/* @__PURE__ */
|
|
2240
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "#00ffff", children: [
|
|
1829
2241
|
" \u2139 ",
|
|
1830
2242
|
"\u5DF2\u5C31\u7EEA ",
|
|
1831
2243
|
toolCount,
|
|
1832
2244
|
" \u4E2A\u5DE5\u5177"
|
|
1833
2245
|
] }),
|
|
1834
|
-
/* @__PURE__ */
|
|
2246
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "#00ffff", children: [
|
|
1835
2247
|
" \u{1F527} \u6A21\u578B ",
|
|
1836
2248
|
SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
|
|
1837
2249
|
] }),
|
|
@@ -1839,40 +2251,40 @@ function ChatSession({
|
|
|
1839
2251
|
const tip = cmdTips[cmdTipIndex % cmdTips.length];
|
|
1840
2252
|
if (!tip) return null;
|
|
1841
2253
|
const text = `${tip.name} ${tip.desc}`;
|
|
1842
|
-
return /* @__PURE__ */
|
|
1843
|
-
/* @__PURE__ */
|
|
1844
|
-
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */
|
|
2254
|
+
return /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
2255
|
+
/* @__PURE__ */ jsx7(Text8, { color: "#808080", children: " \u{1F4A1} " }),
|
|
2256
|
+
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx7(Text8, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx7(Text8, { color: "#808080", children: text })
|
|
1845
2257
|
] });
|
|
1846
2258
|
})(),
|
|
1847
|
-
verbose ? /* @__PURE__ */
|
|
2259
|
+
verbose ? /* @__PURE__ */ jsx7(Text8, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
|
|
1848
2260
|
] }),
|
|
1849
|
-
/* @__PURE__ */
|
|
1850
|
-
balanceLoading && balance === null ? /* @__PURE__ */
|
|
1851
|
-
/* @__PURE__ */
|
|
1852
|
-
/* @__PURE__ */
|
|
2261
|
+
/* @__PURE__ */ jsxs7(Box7, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "flex-end", children: [
|
|
2262
|
+
balanceLoading && balance === null ? /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", children: [
|
|
2263
|
+
/* @__PURE__ */ jsx7(Text8, { color: "yellow", children: "\u{1F4B0} " }),
|
|
2264
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "yellow", children: [
|
|
1853
2265
|
"\u4F59\u989D \xA5",
|
|
1854
2266
|
balance.toFixed(2)
|
|
1855
2267
|
] })
|
|
1856
2268
|
] }) : null,
|
|
1857
|
-
todayCost !== null ? /* @__PURE__ */
|
|
1858
|
-
/* @__PURE__ */
|
|
1859
|
-
/* @__PURE__ */
|
|
2269
|
+
todayCost !== null ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", children: [
|
|
2270
|
+
/* @__PURE__ */ jsx7(Text8, { color: "cyan", children: "\u{1F4CA} " }),
|
|
2271
|
+
/* @__PURE__ */ jsxs7(Text8, { color: "cyan", children: [
|
|
1860
2272
|
"\u4ECA\u65E5 \xA5",
|
|
1861
2273
|
todayCost.toFixed(2)
|
|
1862
2274
|
] })
|
|
1863
2275
|
] }) : null
|
|
1864
2276
|
] })
|
|
1865
2277
|
] }),
|
|
1866
|
-
/* @__PURE__ */
|
|
1867
|
-
/* @__PURE__ */
|
|
2278
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
2279
|
+
/* @__PURE__ */ jsx7(Static, { items: displayMessages, children: (msg, i) => {
|
|
1868
2280
|
if (msg.role === "user") {
|
|
1869
|
-
return /* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */
|
|
1871
|
-
/* @__PURE__ */
|
|
2281
|
+
return /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
2282
|
+
/* @__PURE__ */ jsx7(Box7, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
|
|
2283
|
+
/* @__PURE__ */ jsx7(Box7, { flexGrow: 1, children: /* @__PURE__ */ jsx7(Text8, { wrap: "wrap", children: msg.content }) })
|
|
1872
2284
|
] }, i);
|
|
1873
2285
|
}
|
|
1874
2286
|
const detail = msg.assistantDetail;
|
|
1875
|
-
return /* @__PURE__ */
|
|
2287
|
+
return /* @__PURE__ */ jsx7(
|
|
1876
2288
|
AssistantMessage,
|
|
1877
2289
|
{
|
|
1878
2290
|
content: msg.content,
|
|
@@ -1886,7 +2298,7 @@ function ChatSession({
|
|
|
1886
2298
|
i
|
|
1887
2299
|
);
|
|
1888
2300
|
} }, staticKey),
|
|
1889
|
-
isStreaming && /* @__PURE__ */
|
|
2301
|
+
isStreaming && /* @__PURE__ */ jsx7(
|
|
1890
2302
|
AssistantMessage,
|
|
1891
2303
|
{
|
|
1892
2304
|
content: currentContent,
|
|
@@ -1894,25 +2306,25 @@ function ChatSession({
|
|
|
1894
2306
|
isStreaming: true
|
|
1895
2307
|
}
|
|
1896
2308
|
),
|
|
1897
|
-
isStreaming && !currentContent && currentToolCalls.length === 0 && /* @__PURE__ */
|
|
1898
|
-
!isStreaming && streamError && /* @__PURE__ */
|
|
2309
|
+
isStreaming && !currentContent && currentToolCalls.length === 0 && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ jsx7(Spinner, { type: "dots", label: "\u601D\u8003\u4E2D..." }) }),
|
|
2310
|
+
!isStreaming && streamError && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs7(Text8, { color: "red", children: [
|
|
1899
2311
|
"\u26A0 ",
|
|
1900
2312
|
streamError
|
|
1901
2313
|
] }) })
|
|
1902
2314
|
] }),
|
|
1903
|
-
selectingModel ? /* @__PURE__ */
|
|
1904
|
-
/* @__PURE__ */
|
|
1905
|
-
/* @__PURE__ */
|
|
1906
|
-
/* @__PURE__ */
|
|
2315
|
+
selectingModel ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
2316
|
+
/* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
|
|
2317
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
2318
|
+
/* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
|
|
1907
2319
|
modelOptions.map((id, i) => {
|
|
1908
2320
|
const meta = SUPPORTED_MODELS[id];
|
|
1909
2321
|
const isCurrent = id === activeModel;
|
|
1910
2322
|
const isSelected = i === modelSelectIndex;
|
|
1911
2323
|
const marker = isSelected ? " > " : " ";
|
|
1912
2324
|
const suffix = isCurrent ? " (\u5F53\u524D)" : "";
|
|
1913
|
-
return /* @__PURE__ */
|
|
1914
|
-
/* @__PURE__ */
|
|
1915
|
-
|
|
2325
|
+
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
2326
|
+
/* @__PURE__ */ jsxs7(
|
|
2327
|
+
Text8,
|
|
1916
2328
|
{
|
|
1917
2329
|
color: isSelected ? "#00ff41" : void 0,
|
|
1918
2330
|
bold: isSelected,
|
|
@@ -1923,40 +2335,43 @@ function ChatSession({
|
|
|
1923
2335
|
]
|
|
1924
2336
|
}
|
|
1925
2337
|
),
|
|
1926
|
-
isSelected && /* @__PURE__ */
|
|
2338
|
+
isSelected && /* @__PURE__ */ jsxs7(Text8, { color: "#808080", children: [
|
|
1927
2339
|
" \u2014 ",
|
|
1928
2340
|
id
|
|
1929
2341
|
] })
|
|
1930
2342
|
] }, id);
|
|
1931
2343
|
}),
|
|
1932
|
-
/* @__PURE__ */
|
|
2344
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
1933
2345
|
] }),
|
|
1934
|
-
/* @__PURE__ */
|
|
1935
|
-
] }) : /* @__PURE__ */
|
|
1936
|
-
/* @__PURE__ */
|
|
1937
|
-
/* @__PURE__ */
|
|
1938
|
-
/* @__PURE__ */
|
|
1939
|
-
/* @__PURE__ */
|
|
2346
|
+
/* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
|
|
2347
|
+
] }) : /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
2348
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
|
|
2349
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
2350
|
+
/* @__PURE__ */ jsx7(Box7, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
|
|
2351
|
+
/* @__PURE__ */ jsx7(Box7, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx7(Text8, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx7(Text8, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx7(Text8, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx7(Text8, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx7(
|
|
1940
2352
|
TextInput,
|
|
1941
2353
|
{
|
|
1942
2354
|
value: input,
|
|
1943
2355
|
onChange: setInput,
|
|
1944
2356
|
onSubmit: handleSubmit,
|
|
1945
2357
|
placeholder: ""
|
|
1946
|
-
}
|
|
2358
|
+
},
|
|
2359
|
+
inputKey
|
|
1947
2360
|
) })
|
|
1948
2361
|
] }),
|
|
1949
|
-
/* @__PURE__ */
|
|
2362
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
|
|
2363
|
+
/* @__PURE__ */ jsx7(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
|
|
2364
|
+
/* @__PURE__ */ jsx7(FileSelector, { files, input, selectedIndex: fileSelectIndex })
|
|
1950
2365
|
] }),
|
|
1951
|
-
doubleCtrlC && !isStreaming && /* @__PURE__ */
|
|
1952
|
-
isStreaming && /* @__PURE__ */
|
|
2366
|
+
doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
|
|
2367
|
+
isStreaming && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
|
|
1953
2368
|
] });
|
|
1954
2369
|
}
|
|
1955
2370
|
|
|
1956
2371
|
// src/ui/GamePicker.tsx
|
|
1957
|
-
import { Box as
|
|
2372
|
+
import { Box as Box8, Text as Text9, useInput as useInput2 } from "ink";
|
|
1958
2373
|
import { useState as useState4, useCallback as useCallback3 } from "react";
|
|
1959
|
-
import { jsx as
|
|
2374
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1960
2375
|
function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
1961
2376
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
1962
2377
|
const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
|
|
@@ -1984,18 +2399,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
|
1984
2399
|
[games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
|
|
1985
2400
|
)
|
|
1986
2401
|
);
|
|
1987
|
-
return /* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
1989
|
-
/* @__PURE__ */
|
|
2402
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2403
|
+
/* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
|
|
2404
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: games.map((game, index) => {
|
|
1990
2405
|
const isSelected = index === selectedIndex;
|
|
1991
|
-
return /* @__PURE__ */
|
|
1992
|
-
/* @__PURE__ */
|
|
1993
|
-
/* @__PURE__ */
|
|
1994
|
-
/* @__PURE__ */
|
|
2406
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
|
|
2407
|
+
/* @__PURE__ */ jsx8(Box8, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx8(Text9, { children: " " }) }),
|
|
2408
|
+
/* @__PURE__ */ jsx8(Box8, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
|
|
2409
|
+
/* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { color: "#888888", children: game.description }) })
|
|
1995
2410
|
] }, game.id);
|
|
1996
2411
|
}) }),
|
|
1997
|
-
/* @__PURE__ */
|
|
1998
|
-
doubleCtrlC && /* @__PURE__ */
|
|
2412
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
|
|
2413
|
+
doubleCtrlC && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
1999
2414
|
] });
|
|
2000
2415
|
}
|
|
2001
2416
|
|
|
@@ -2012,9 +2427,9 @@ function listGames() {
|
|
|
2012
2427
|
}
|
|
2013
2428
|
|
|
2014
2429
|
// src/game/brick-breaker/index.tsx
|
|
2015
|
-
import { Box as
|
|
2430
|
+
import { Box as Box9, Text as Text10, useInput as useInput3, render as render2 } from "ink";
|
|
2016
2431
|
import { useState as useState5, useEffect as useEffect4, useRef as useRef3, useCallback as useCallback4 } from "react";
|
|
2017
|
-
import { jsx as
|
|
2432
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2018
2433
|
var GAME_WIDTH = 40;
|
|
2019
2434
|
var GAME_HEIGHT = 18;
|
|
2020
2435
|
var PADDLE_WIDTH = 9;
|
|
@@ -2204,49 +2619,49 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
2204
2619
|
const board = buildBoard(s);
|
|
2205
2620
|
const def = getLevel(s.level);
|
|
2206
2621
|
void tick;
|
|
2207
|
-
return /* @__PURE__ */
|
|
2208
|
-
/* @__PURE__ */
|
|
2209
|
-
/* @__PURE__ */
|
|
2622
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
2623
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
|
|
2624
|
+
/* @__PURE__ */ jsx9(Box9, { width: 20, children: /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2210
2625
|
"\u5173\u5361 ",
|
|
2211
2626
|
s.level,
|
|
2212
2627
|
": ",
|
|
2213
|
-
/* @__PURE__ */
|
|
2628
|
+
/* @__PURE__ */ jsx9(Text10, { color: "cyan", children: def.desc })
|
|
2214
2629
|
] }) }),
|
|
2215
|
-
/* @__PURE__ */
|
|
2630
|
+
/* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2216
2631
|
"\u5206\u6570: ",
|
|
2217
|
-
/* @__PURE__ */
|
|
2632
|
+
/* @__PURE__ */ jsx9(Text10, { color: "yellow", children: String(s.score).padStart(3, "0") })
|
|
2218
2633
|
] }) }),
|
|
2219
|
-
/* @__PURE__ */
|
|
2634
|
+
/* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2220
2635
|
"\u751F\u547D: ",
|
|
2221
|
-
/* @__PURE__ */
|
|
2636
|
+
/* @__PURE__ */ jsx9(Text10, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
|
|
2222
2637
|
] }) }),
|
|
2223
|
-
/* @__PURE__ */
|
|
2638
|
+
/* @__PURE__ */ jsx9(Box9, { width: 10, children: /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2224
2639
|
"\u7816\u5757: ",
|
|
2225
|
-
/* @__PURE__ */
|
|
2640
|
+
/* @__PURE__ */ jsx9(Text10, { color: "cyan", children: aliveCount })
|
|
2226
2641
|
] }) }),
|
|
2227
|
-
/* @__PURE__ */
|
|
2642
|
+
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { color: s.paused ? "gray" : "green", children: [
|
|
2228
2643
|
"[",
|
|
2229
2644
|
s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
|
|
2230
2645
|
"]"
|
|
2231
2646
|
] }) })
|
|
2232
2647
|
] }),
|
|
2233
|
-
/* @__PURE__ */
|
|
2234
|
-
/* @__PURE__ */
|
|
2648
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
2649
|
+
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2235
2650
|
"\u250C",
|
|
2236
2651
|
"\u2500".repeat(GAME_WIDTH),
|
|
2237
2652
|
"\u2510"
|
|
2238
2653
|
] }),
|
|
2239
|
-
/* @__PURE__ */
|
|
2240
|
-
/* @__PURE__ */
|
|
2654
|
+
/* @__PURE__ */ jsx9(Text10, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
|
|
2655
|
+
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2241
2656
|
"\u2514",
|
|
2242
2657
|
"\u2500".repeat(GAME_WIDTH),
|
|
2243
2658
|
"\u2518"
|
|
2244
2659
|
] })
|
|
2245
2660
|
] }),
|
|
2246
|
-
selectingLevel && /* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2661
|
+
selectingLevel && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2662
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
|
|
2663
|
+
/* @__PURE__ */ jsx9(Box9, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx9(Box9, { width: 22, children: /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2664
|
+
/* @__PURE__ */ jsx9(Text10, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
|
|
2250
2665
|
". ",
|
|
2251
2666
|
lv.desc,
|
|
2252
2667
|
" (",
|
|
@@ -2255,16 +2670,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
2255
2670
|
lv.cols,
|
|
2256
2671
|
")"
|
|
2257
2672
|
] }) }, i)) }),
|
|
2258
|
-
/* @__PURE__ */
|
|
2673
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
|
|
2259
2674
|
] }),
|
|
2260
|
-
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */
|
|
2261
|
-
/* @__PURE__ */
|
|
2262
|
-
/* @__PURE__ */
|
|
2675
|
+
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
|
|
2676
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
|
|
2677
|
+
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2263
2678
|
" \u5206\u6570: ",
|
|
2264
|
-
/* @__PURE__ */
|
|
2679
|
+
/* @__PURE__ */ jsx9(Text10, { color: "yellow", children: s.score })
|
|
2265
2680
|
] })
|
|
2266
2681
|
] }),
|
|
2267
|
-
!selectingLevel && /* @__PURE__ */
|
|
2682
|
+
!selectingLevel && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
|
|
2268
2683
|
] });
|
|
2269
2684
|
}
|
|
2270
2685
|
var brick_breaker_default = {
|
|
@@ -2274,7 +2689,7 @@ var brick_breaker_default = {
|
|
|
2274
2689
|
play: async () => {
|
|
2275
2690
|
await new Promise((resolve) => {
|
|
2276
2691
|
const { unmount } = render2(
|
|
2277
|
-
/* @__PURE__ */
|
|
2692
|
+
/* @__PURE__ */ jsx9(BrickBreakerGame, { onExit: () => {
|
|
2278
2693
|
unmount();
|
|
2279
2694
|
resolve();
|
|
2280
2695
|
} })
|
|
@@ -2284,9 +2699,9 @@ var brick_breaker_default = {
|
|
|
2284
2699
|
};
|
|
2285
2700
|
|
|
2286
2701
|
// src/game/coder-check/index.tsx
|
|
2287
|
-
import { Box as
|
|
2702
|
+
import { Box as Box10, Text as Text11, useInput as useInput4, render as render3 } from "ink";
|
|
2288
2703
|
import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useCallback as useCallback5 } from "react";
|
|
2289
|
-
import { jsx as
|
|
2704
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2290
2705
|
var GAME_W = 66;
|
|
2291
2706
|
var GAME_H = 20;
|
|
2292
2707
|
var SCORE_H = 6;
|
|
@@ -2757,44 +3172,44 @@ function CoderCheck({ onExit: _onExit }) {
|
|
|
2757
3172
|
const scoreLines = buildScoreLines(scoreStr);
|
|
2758
3173
|
const view = buildGameView(s, scoreLines, scoreColor, s.message);
|
|
2759
3174
|
void tick;
|
|
2760
|
-
return /* @__PURE__ */
|
|
2761
|
-
/* @__PURE__ */
|
|
3175
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingX: 1, children: [
|
|
3176
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "row", children: /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2762
3177
|
"\u751F\u547D ",
|
|
2763
|
-
/* @__PURE__ */
|
|
3178
|
+
/* @__PURE__ */ jsx10(Text11, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
|
|
2764
3179
|
" ",
|
|
2765
3180
|
"\u901F\u5EA6 ",
|
|
2766
|
-
/* @__PURE__ */
|
|
3181
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
|
|
2767
3182
|
"Lv.",
|
|
2768
3183
|
Math.floor(s.speed * 10)
|
|
2769
3184
|
] })
|
|
2770
3185
|
] }) }),
|
|
2771
|
-
!s.gameOver && s.target && /* @__PURE__ */
|
|
3186
|
+
!s.gameOver && s.target && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2772
3187
|
"\u6253\u5B57: ",
|
|
2773
|
-
/* @__PURE__ */
|
|
2774
|
-
/* @__PURE__ */
|
|
3188
|
+
/* @__PURE__ */ jsx10(Text11, { color: "green", children: s.typed }),
|
|
3189
|
+
/* @__PURE__ */ jsx10(Text11, { color: "white", children: s.target.slice(s.typed.length) })
|
|
2775
3190
|
] }) }),
|
|
2776
|
-
/* @__PURE__ */
|
|
2777
|
-
/* @__PURE__ */
|
|
3191
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
3192
|
+
/* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2778
3193
|
"\u250C",
|
|
2779
3194
|
"\u2500".repeat(GAME_W),
|
|
2780
3195
|
"\u2510"
|
|
2781
3196
|
] }),
|
|
2782
|
-
view.map((row, i) => /* @__PURE__ */
|
|
2783
|
-
/* @__PURE__ */
|
|
3197
|
+
view.map((row, i) => /* @__PURE__ */ jsx10(Text11, { children: `\u2502${row}\u2502` }, i)),
|
|
3198
|
+
/* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2784
3199
|
"\u2514",
|
|
2785
3200
|
"\u2500".repeat(GAME_W),
|
|
2786
3201
|
"\u2518"
|
|
2787
3202
|
] })
|
|
2788
3203
|
] }),
|
|
2789
|
-
s.gameOver && /* @__PURE__ */
|
|
2790
|
-
/* @__PURE__ */
|
|
2791
|
-
/* @__PURE__ */
|
|
3204
|
+
s.gameOver && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
3205
|
+
/* @__PURE__ */ jsx10(Text11, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
|
|
3206
|
+
/* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2792
3207
|
" \u5F97\u5206: ",
|
|
2793
|
-
/* @__PURE__ */
|
|
3208
|
+
/* @__PURE__ */ jsx10(Text11, { color: "yellow", children: s.score }),
|
|
2794
3209
|
" r \u91CD\u5F00 q \u9000\u51FA"
|
|
2795
3210
|
] })
|
|
2796
3211
|
] }),
|
|
2797
|
-
/* @__PURE__ */
|
|
3212
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
|
|
2798
3213
|
] });
|
|
2799
3214
|
}
|
|
2800
3215
|
var coder_check_default = {
|
|
@@ -2804,7 +3219,7 @@ var coder_check_default = {
|
|
|
2804
3219
|
play: async () => {
|
|
2805
3220
|
await new Promise((resolve) => {
|
|
2806
3221
|
const { unmount } = render3(
|
|
2807
|
-
/* @__PURE__ */
|
|
3222
|
+
/* @__PURE__ */ jsx10(CoderCheck, { onExit: () => {
|
|
2808
3223
|
unmount();
|
|
2809
3224
|
resolve();
|
|
2810
3225
|
} })
|
|
@@ -2822,13 +3237,13 @@ function initGames() {
|
|
|
2822
3237
|
|
|
2823
3238
|
// src/cli/index.tsx
|
|
2824
3239
|
import { render as render4 } from "ink";
|
|
2825
|
-
import
|
|
3240
|
+
import chalk4 from "chalk";
|
|
2826
3241
|
|
|
2827
3242
|
// src/stock/StockList.tsx
|
|
2828
|
-
import { Box as
|
|
3243
|
+
import { Box as Box11, Text as Text12, useInput as useInput5 } from "ink";
|
|
2829
3244
|
import { useState as useState7, useCallback as useCallback6, useEffect as useEffect6 } from "react";
|
|
2830
3245
|
import asciichart from "asciichart";
|
|
2831
|
-
import { jsx as
|
|
3246
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2832
3247
|
var MINUTE_API = "https://web.ifzq.gtimg.cn/appstock/app/minute/query?code={code}&r=0.1";
|
|
2833
3248
|
function normalizeApiCode(code) {
|
|
2834
3249
|
if (code.startsWith("sh") || code.startsWith("sz")) return code;
|
|
@@ -3025,57 +3440,57 @@ function StockList({ codes, onExit, onBackToChat }) {
|
|
|
3025
3440
|
);
|
|
3026
3441
|
if (detailView) {
|
|
3027
3442
|
if (detailLoading) {
|
|
3028
|
-
return /* @__PURE__ */
|
|
3443
|
+
return /* @__PURE__ */ jsx11(Box11, { paddingLeft: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
|
|
3029
3444
|
}
|
|
3030
3445
|
return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
|
|
3031
3446
|
}
|
|
3032
|
-
return /* @__PURE__ */
|
|
3033
|
-
/* @__PURE__ */
|
|
3034
|
-
/* @__PURE__ */
|
|
3035
|
-
/* @__PURE__ */
|
|
3447
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
3448
|
+
/* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
3449
|
+
/* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ffff", children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
|
|
3450
|
+
/* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
|
|
3036
3451
|
" \u{1F550} ",
|
|
3037
3452
|
currentTime
|
|
3038
3453
|
] }),
|
|
3039
|
-
/* @__PURE__ */
|
|
3454
|
+
/* @__PURE__ */ jsx11(Text12, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
|
|
3040
3455
|
] }),
|
|
3041
|
-
/* @__PURE__ */
|
|
3042
|
-
/* @__PURE__ */
|
|
3043
|
-
/* @__PURE__ */
|
|
3044
|
-
/* @__PURE__ */
|
|
3045
|
-
/* @__PURE__ */
|
|
3046
|
-
/* @__PURE__ */
|
|
3047
|
-
/* @__PURE__ */
|
|
3048
|
-
/* @__PURE__ */
|
|
3049
|
-
/* @__PURE__ */
|
|
3050
|
-
/* @__PURE__ */
|
|
3456
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3457
|
+
/* @__PURE__ */ jsx11(Box11, { width: 3 }),
|
|
3458
|
+
/* @__PURE__ */ jsx11(Box11, { width: 9, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u4EE3\u7801" }) }),
|
|
3459
|
+
/* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u540D\u79F0" }) }),
|
|
3460
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
|
|
3461
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
3462
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
|
|
3463
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6700\u9AD8" }) }),
|
|
3464
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6700\u4F4E" }) }),
|
|
3465
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
|
|
3051
3466
|
] }),
|
|
3052
|
-
/* @__PURE__ */
|
|
3053
|
-
/* @__PURE__ */
|
|
3467
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
|
|
3468
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: stocks.map((stock, index) => {
|
|
3054
3469
|
const isSelected = index === selectedIndex;
|
|
3055
3470
|
const isUp = stock.changePercent >= 0;
|
|
3056
3471
|
const color = isUp ? "#ff1493" : "#00ff41";
|
|
3057
|
-
return /* @__PURE__ */
|
|
3058
|
-
/* @__PURE__ */
|
|
3059
|
-
/* @__PURE__ */
|
|
3060
|
-
/* @__PURE__ */
|
|
3061
|
-
/* @__PURE__ */
|
|
3062
|
-
/* @__PURE__ */
|
|
3472
|
+
return /* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3473
|
+
/* @__PURE__ */ jsx11(Box11, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ffff", children: "\u25B8 " }) : /* @__PURE__ */ jsx11(Text12, { children: " " }) }),
|
|
3474
|
+
/* @__PURE__ */ jsx11(Box11, { width: 9, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: isSelected ? "#00ffff" : "#ffffff", children: stock.code }) }),
|
|
3475
|
+
/* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { color: isSelected ? "#ffffff" : "#cccccc", children: stock.name }) }),
|
|
3476
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color, children: formatPrice(stock.price) }) }),
|
|
3477
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsxs11(Text12, { color, children: [
|
|
3063
3478
|
isUp ? "+" : "",
|
|
3064
3479
|
stock.changePercent.toFixed(2),
|
|
3065
3480
|
"%"
|
|
3066
3481
|
] }) }),
|
|
3067
|
-
/* @__PURE__ */
|
|
3482
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsxs11(Text12, { color, children: [
|
|
3068
3483
|
isUp ? "+" : "",
|
|
3069
3484
|
stock.changeAmount.toFixed(3)
|
|
3070
3485
|
] }) }),
|
|
3071
|
-
/* @__PURE__ */
|
|
3072
|
-
/* @__PURE__ */
|
|
3073
|
-
/* @__PURE__ */
|
|
3486
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { color: "#cccccc", children: formatPrice(stock.high) }) }),
|
|
3487
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: formatPrice(stock.low) }) }),
|
|
3488
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: formatAmount(stock.amount) }) })
|
|
3074
3489
|
] }, stock.code);
|
|
3075
3490
|
}) }),
|
|
3076
|
-
/* @__PURE__ */
|
|
3077
|
-
/* @__PURE__ */
|
|
3078
|
-
doubleCtrlC && /* @__PURE__ */
|
|
3491
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 q \u8FD4\u56DE` }) }),
|
|
3492
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ~/.dskcode/settings.json` }) }),
|
|
3493
|
+
doubleCtrlC && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
3079
3494
|
] });
|
|
3080
3495
|
}
|
|
3081
3496
|
function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
@@ -3093,33 +3508,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
3093
3508
|
raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
|
|
3094
3509
|
chartLines = raw.split("\n");
|
|
3095
3510
|
}
|
|
3096
|
-
return /* @__PURE__ */
|
|
3097
|
-
/* @__PURE__ */
|
|
3098
|
-
/* @__PURE__ */
|
|
3099
|
-
/* @__PURE__ */
|
|
3511
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingLeft: 1, children: [
|
|
3512
|
+
/* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
3513
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3514
|
+
/* @__PURE__ */ jsxs11(Text12, { bold: true, color: "#00ffff", children: [
|
|
3100
3515
|
" \u{1F4CA} ",
|
|
3101
3516
|
stock.name,
|
|
3102
3517
|
" "
|
|
3103
3518
|
] }),
|
|
3104
|
-
/* @__PURE__ */
|
|
3105
|
-
currentTime && /* @__PURE__ */
|
|
3519
|
+
/* @__PURE__ */ jsx11(Text12, { dimColor: true, children: stock.code }),
|
|
3520
|
+
currentTime && /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
|
|
3106
3521
|
" \u{1F550} ",
|
|
3107
3522
|
currentTime
|
|
3108
3523
|
] })
|
|
3109
3524
|
] }),
|
|
3110
|
-
/* @__PURE__ */
|
|
3525
|
+
/* @__PURE__ */ jsx11(Text12, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
|
|
3111
3526
|
] }),
|
|
3112
|
-
/* @__PURE__ */
|
|
3113
|
-
/* @__PURE__ */
|
|
3114
|
-
/* @__PURE__ */
|
|
3527
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3528
|
+
/* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
|
|
3529
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { bold: true, color: colorCode, children: [
|
|
3115
3530
|
arrow,
|
|
3116
3531
|
" ",
|
|
3117
3532
|
formatPrice(stock.price)
|
|
3118
3533
|
] }) })
|
|
3119
3534
|
] }),
|
|
3120
|
-
/* @__PURE__ */
|
|
3121
|
-
/* @__PURE__ */
|
|
3122
|
-
/* @__PURE__ */
|
|
3535
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3536
|
+
/* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
3537
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { color: colorCode, children: [
|
|
3123
3538
|
isUp ? "+" : "",
|
|
3124
3539
|
stock.changePercent.toFixed(2),
|
|
3125
3540
|
"%",
|
|
@@ -3128,13 +3543,93 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
3128
3543
|
stock.changeAmount.toFixed(3)
|
|
3129
3544
|
] }) })
|
|
3130
3545
|
] }),
|
|
3131
|
-
chartLines.length > 0 && /* @__PURE__ */
|
|
3132
|
-
/* @__PURE__ */
|
|
3546
|
+
chartLines.length > 0 && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: colorCode, children: line || " " }) }, i)) }),
|
|
3547
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
|
|
3133
3548
|
] });
|
|
3134
3549
|
}
|
|
3135
3550
|
|
|
3551
|
+
// src/utils/scan-files.ts
|
|
3552
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
3553
|
+
import { join as join4, relative } from "path";
|
|
3554
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
3555
|
+
"node_modules",
|
|
3556
|
+
".git",
|
|
3557
|
+
".svn",
|
|
3558
|
+
".hg",
|
|
3559
|
+
".dskcode",
|
|
3560
|
+
".claude",
|
|
3561
|
+
"dist",
|
|
3562
|
+
"build",
|
|
3563
|
+
".next",
|
|
3564
|
+
".turbo",
|
|
3565
|
+
".nx",
|
|
3566
|
+
"coverage",
|
|
3567
|
+
".cache",
|
|
3568
|
+
".nyc_output",
|
|
3569
|
+
".vscode",
|
|
3570
|
+
".idea",
|
|
3571
|
+
"__pycache__",
|
|
3572
|
+
".venv",
|
|
3573
|
+
"venv",
|
|
3574
|
+
".tox",
|
|
3575
|
+
"target",
|
|
3576
|
+
"vendor",
|
|
3577
|
+
"bower_components",
|
|
3578
|
+
"jspm_packages"
|
|
3579
|
+
]);
|
|
3580
|
+
var SOURCE_EXTS = /* @__PURE__ */ new Set([
|
|
3581
|
+
".ts",
|
|
3582
|
+
".tsx",
|
|
3583
|
+
".js",
|
|
3584
|
+
".jsx",
|
|
3585
|
+
".mjs",
|
|
3586
|
+
".cjs",
|
|
3587
|
+
".vue",
|
|
3588
|
+
".svelte",
|
|
3589
|
+
".astro",
|
|
3590
|
+
".css",
|
|
3591
|
+
".scss",
|
|
3592
|
+
".less",
|
|
3593
|
+
".html",
|
|
3594
|
+
".json",
|
|
3595
|
+
".md",
|
|
3596
|
+
".yaml",
|
|
3597
|
+
".yml",
|
|
3598
|
+
".toml"
|
|
3599
|
+
]);
|
|
3600
|
+
async function scanProjectFiles(baseDir, dir) {
|
|
3601
|
+
const currentDir = dir ?? baseDir;
|
|
3602
|
+
let entries;
|
|
3603
|
+
try {
|
|
3604
|
+
entries = await readdir2(currentDir, { withFileTypes: true });
|
|
3605
|
+
} catch {
|
|
3606
|
+
return [];
|
|
3607
|
+
}
|
|
3608
|
+
const files = [];
|
|
3609
|
+
const dirs = [];
|
|
3610
|
+
for (const entry of entries) {
|
|
3611
|
+
const name = entry.name;
|
|
3612
|
+
if (IGNORE_DIRS.has(name) || name.startsWith(".")) continue;
|
|
3613
|
+
if (entry.isDirectory()) {
|
|
3614
|
+
dirs.push(name);
|
|
3615
|
+
} else if (entry.isFile()) {
|
|
3616
|
+
const ext = name.slice(name.lastIndexOf(".")).toLowerCase();
|
|
3617
|
+
if (SOURCE_EXTS.has(ext)) {
|
|
3618
|
+
files.push(relative(baseDir, join4(currentDir, name)));
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
const nested = await Promise.all(
|
|
3623
|
+
dirs.map((d) => scanProjectFiles(baseDir, join4(currentDir, d)))
|
|
3624
|
+
);
|
|
3625
|
+
for (const n of nested) {
|
|
3626
|
+
files.push(...n);
|
|
3627
|
+
}
|
|
3628
|
+
return files;
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3136
3631
|
// src/cli/index.tsx
|
|
3137
|
-
import { jsx as
|
|
3632
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
3138
3633
|
var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
|
|
3139
3634
|
function createCli() {
|
|
3140
3635
|
const program2 = new Command();
|
|
@@ -3155,27 +3650,37 @@ function createCli() {
|
|
|
3155
3650
|
const key = await promptForApiKey();
|
|
3156
3651
|
if (!key) process.exit(1);
|
|
3157
3652
|
const savedPath = await saveApiKey(key);
|
|
3158
|
-
console.log(` ${
|
|
3653
|
+
console.log(` ${chalk4.green("\u2714")} API Key \u5DF2\u4FDD\u5B58\u5230 ${chalk4.dim(savedPath)}
|
|
3159
3654
|
`);
|
|
3160
3655
|
const result = await loadAndValidate();
|
|
3161
3656
|
ctx = { ...ctx, config: result.config };
|
|
3162
3657
|
}
|
|
3658
|
+
await promptImportClaudeSkills(process.cwd());
|
|
3163
3659
|
const costTracker = new CostTracker({
|
|
3164
3660
|
budgetLimit: ctx?.config.budgetLimit ?? 0,
|
|
3165
3661
|
tokenBudgetLimit: ctx?.config.tokenBudgetLimit ?? 0
|
|
3166
3662
|
});
|
|
3167
3663
|
startChat(ctx, costTracker);
|
|
3168
3664
|
});
|
|
3169
|
-
function startChat(ctx, costTracker) {
|
|
3665
|
+
async function startChat(ctx, costTracker) {
|
|
3666
|
+
const [globalSkillCount, localSkillCount, skills, files] = await Promise.all([
|
|
3667
|
+
countDskcodeSkills(),
|
|
3668
|
+
countProjectLocalSkills(process.cwd()),
|
|
3669
|
+
getAllSkills(process.cwd()),
|
|
3670
|
+
scanProjectFiles(process.cwd())
|
|
3671
|
+
]);
|
|
3672
|
+
const skillCount = globalSkillCount + localSkillCount;
|
|
3170
3673
|
const defaultProvider = ctx?.config.providers.find(
|
|
3171
3674
|
(p) => p.name === (ctx?.config.defaultProvider ?? "deepseek")
|
|
3172
3675
|
);
|
|
3173
3676
|
const model = defaultProvider?.model ?? "deepseek-v4-flash";
|
|
3174
3677
|
const chatApp = renderApp(
|
|
3175
|
-
/* @__PURE__ */
|
|
3678
|
+
/* @__PURE__ */ jsx12(
|
|
3176
3679
|
ChatSession,
|
|
3177
3680
|
{
|
|
3178
|
-
|
|
3681
|
+
skillCount,
|
|
3682
|
+
skills,
|
|
3683
|
+
files,
|
|
3179
3684
|
toolCount: ctx?.config.tools.length ?? 0,
|
|
3180
3685
|
verbose: ctx?.verbose ?? false,
|
|
3181
3686
|
apiKey: defaultProvider?.apiKey,
|
|
@@ -3188,7 +3693,7 @@ function createCli() {
|
|
|
3188
3693
|
initGames();
|
|
3189
3694
|
const games = listGames();
|
|
3190
3695
|
const { unmount } = render4(
|
|
3191
|
-
/* @__PURE__ */
|
|
3696
|
+
/* @__PURE__ */ jsx12(
|
|
3192
3697
|
GamePicker,
|
|
3193
3698
|
{
|
|
3194
3699
|
games,
|
|
@@ -3212,7 +3717,7 @@ function createCli() {
|
|
|
3212
3717
|
setImmediate(() => {
|
|
3213
3718
|
const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
|
|
3214
3719
|
const stockApp = renderApp(
|
|
3215
|
-
/* @__PURE__ */
|
|
3720
|
+
/* @__PURE__ */ jsx12(
|
|
3216
3721
|
StockList,
|
|
3217
3722
|
{
|
|
3218
3723
|
codes: defaultStockCodes,
|
|
@@ -3276,10 +3781,10 @@ compdef _dskcode_completion dskcode`);
|
|
|
3276
3781
|
program2.command("stock").description("\u67E5\u770B\u81EA\u9009\u80A1\u5B9E\u65F6\u884C\u60C5").argument("[codes...]", "\u80A1\u7968\u4EE3\u7801\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u5982 513090 600519").action(async function(codes) {
|
|
3277
3782
|
const ctx = this.dskcodeCtx;
|
|
3278
3783
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
3279
|
-
const globalConfigPath =
|
|
3784
|
+
const globalConfigPath = join5(home, ".dskcode", "settings.json");
|
|
3280
3785
|
let globalConfigHasStock = false;
|
|
3281
3786
|
try {
|
|
3282
|
-
const raw = await
|
|
3787
|
+
const raw = await readFile4(globalConfigPath, "utf-8");
|
|
3283
3788
|
const parsed = JSON.parse(raw);
|
|
3284
3789
|
const stock = parsed.stock;
|
|
3285
3790
|
globalConfigHasStock = Array.isArray(stock?.symbols) && stock.symbols.length > 0;
|
|
@@ -3292,14 +3797,14 @@ compdef _dskcode_completion dskcode`);
|
|
|
3292
3797
|
{ code: "sh601899" }
|
|
3293
3798
|
];
|
|
3294
3799
|
const savedPath = await saveStockConfig(defaultSymbols);
|
|
3295
|
-
console.log(`${
|
|
3296
|
-
console.log(`${
|
|
3800
|
+
console.log(`${chalk4.green("\u2714")} \u5DF2\u751F\u6210\u81EA\u9009\u80A1\u914D\u7F6E: ${chalk4.dim(savedPath)}`);
|
|
3801
|
+
console.log(`${chalk4.dim(" \u63D0\u793A: \u53EF\u7F16\u8F91\u4E0A\u8FF0\u6587\u4EF6\u81EA\u5B9A\u4E49\u81EA\u9009\u80A1\u5217\u8868")}
|
|
3297
3802
|
`);
|
|
3298
3803
|
}
|
|
3299
3804
|
const freshResult = await loadAndValidate();
|
|
3300
3805
|
const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
|
|
3301
3806
|
const app = renderApp(
|
|
3302
|
-
/* @__PURE__ */
|
|
3807
|
+
/* @__PURE__ */ jsx12(
|
|
3303
3808
|
StockList,
|
|
3304
3809
|
{
|
|
3305
3810
|
codes: codeList,
|
|
@@ -3328,7 +3833,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
3328
3833
|
}
|
|
3329
3834
|
const selectedGame = await new Promise((resolve) => {
|
|
3330
3835
|
const { unmount } = render4(
|
|
3331
|
-
/* @__PURE__ */
|
|
3836
|
+
/* @__PURE__ */ jsx12(
|
|
3332
3837
|
GamePicker,
|
|
3333
3838
|
{
|
|
3334
3839
|
games,
|
|
@@ -3347,7 +3852,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
3347
3852
|
});
|
|
3348
3853
|
if (selectedGame) {
|
|
3349
3854
|
console.log(`
|
|
3350
|
-
\u542F\u52A8\u6E38\u620F: ${
|
|
3855
|
+
\u542F\u52A8\u6E38\u620F: ${chalk4.green(selectedGame.name)}
|
|
3351
3856
|
`);
|
|
3352
3857
|
await selectedGame.play();
|
|
3353
3858
|
}
|