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 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 readFile3 } from "fs/promises";
492
- import { join as join3 } from "path";
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 Box5, Text as Text6, useInput, Static } from "ink";
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 mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
571
- import { join as join2 } from "path";
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 ?? join2(home, ".dskcode", "costs");
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 = join2(this.#costDir, "history.json");
1088
+ const filePath = join3(this.#costDir, "history.json");
804
1089
  try {
805
- const raw = await readFile2(filePath, "utf-8");
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 mkdir2(this.#costDir, { recursive: true });
823
- const filePath = join2(this.#costDir, "history.json");
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 jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
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
- providerCount,
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__ */ jsxs5(Box5, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
1816
- /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", marginBottom: 1, children: [
1817
- /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
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__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text6, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
2231
+ return /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
1820
2232
  }) }),
1821
- /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", justifyContent: "center", children: [
1822
- /* @__PURE__ */ jsxs5(Text6, { color: "#00ff41", children: [
2233
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", justifyContent: "center", children: [
2234
+ /* @__PURE__ */ jsxs7(Text8, { color: "#00ff41", children: [
1823
2235
  " \u2714 ",
1824
- "\u5DF2\u52A0\u8F7D ",
1825
- providerCount,
1826
- " \u4E2A Provider"
2236
+ "\u5DF2\u5C31\u7EEA ",
2237
+ skillCount,
2238
+ " \u4E2A Skill"
1827
2239
  ] }),
1828
- /* @__PURE__ */ jsxs5(Text6, { color: "#00ffff", children: [
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__ */ jsxs5(Text6, { color: "#00ffff", children: [
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__ */ jsxs5(Text6, { children: [
1843
- /* @__PURE__ */ jsx5(Text6, { color: "#808080", children: " \u{1F4A1} " }),
1844
- cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx5(Text6, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx5(Text6, { color: "#808080", children: text })
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__ */ jsx5(Text6, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
2259
+ verbose ? /* @__PURE__ */ jsx7(Text8, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
1848
2260
  ] }),
1849
- /* @__PURE__ */ jsxs5(Box5, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "flex-end", children: [
1850
- balanceLoading && balance === null ? /* @__PURE__ */ jsx5(Text6, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", children: [
1851
- /* @__PURE__ */ jsx5(Text6, { color: "yellow", children: "\u{1F4B0} " }),
1852
- /* @__PURE__ */ jsxs5(Text6, { color: "yellow", children: [
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__ */ jsxs5(Box5, { flexDirection: "row", children: [
1858
- /* @__PURE__ */ jsx5(Text6, { color: "cyan", children: "\u{1F4CA} " }),
1859
- /* @__PURE__ */ jsxs5(Text6, { color: "cyan", children: [
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__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1867
- /* @__PURE__ */ jsx5(Static, { items: displayMessages, children: (msg, i) => {
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__ */ jsxs5(Box5, { marginTop: 1, children: [
1870
- /* @__PURE__ */ jsx5(Box5, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx5(Text6, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
1871
- /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(Text6, { wrap: "wrap", children: msg.content }) })
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__ */ jsx5(
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__ */ jsx5(
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__ */ jsx5(Box5, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ jsx5(Spinner, { type: "dots", label: "\u601D\u8003\u4E2D..." }) }),
1898
- !isStreaming && streamError && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs5(Text6, { color: "red", children: [
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__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
1904
- /* @__PURE__ */ jsx5(Text6, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
1905
- /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1906
- /* @__PURE__ */ jsx5(Text6, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
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__ */ jsxs5(Box5, { children: [
1914
- /* @__PURE__ */ jsxs5(
1915
- Text6,
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__ */ jsxs5(Text6, { color: "#808080", children: [
2338
+ isSelected && /* @__PURE__ */ jsxs7(Text8, { color: "#808080", children: [
1927
2339
  " \u2014 ",
1928
2340
  id
1929
2341
  ] })
1930
2342
  ] }, id);
1931
2343
  }),
1932
- /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
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__ */ jsx5(Text6, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
1935
- ] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1936
- /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
1937
- /* @__PURE__ */ jsxs5(Box5, { children: [
1938
- /* @__PURE__ */ jsx5(Box5, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx5(Text6, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
1939
- /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx5(Text6, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx5(Text6, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx5(Text6, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx5(Text6, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx5(
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__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text6, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) })
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__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
1952
- isStreaming && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
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 Box6, Text as Text7, useInput as useInput2 } from "ink";
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 jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
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__ */ jsxs6(Box6, { flexDirection: "column", children: [
1988
- /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text7, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
1989
- /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: games.map((game, index) => {
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__ */ jsxs6(Box6, { flexDirection: "row", children: [
1992
- /* @__PURE__ */ jsx6(Box6, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx6(Text7, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx6(Text7, { children: " " }) }),
1993
- /* @__PURE__ */ jsx6(Box6, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx6(Text7, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
1994
- /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Text7, { color: "#888888", children: game.description }) })
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__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text7, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
1998
- doubleCtrlC && /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text7, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
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 Box7, Text as Text8, useInput as useInput3, render as render2 } from "ink";
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 jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
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__ */ jsxs7(Box7, { flexDirection: "column", children: [
2208
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", children: [
2209
- /* @__PURE__ */ jsx7(Box7, { width: 20, children: /* @__PURE__ */ jsxs7(Text8, { children: [
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__ */ jsx7(Text8, { color: "cyan", children: def.desc })
2628
+ /* @__PURE__ */ jsx9(Text10, { color: "cyan", children: def.desc })
2214
2629
  ] }) }),
2215
- /* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsxs7(Text8, { children: [
2630
+ /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { children: [
2216
2631
  "\u5206\u6570: ",
2217
- /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: String(s.score).padStart(3, "0") })
2632
+ /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: String(s.score).padStart(3, "0") })
2218
2633
  ] }) }),
2219
- /* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsxs7(Text8, { children: [
2634
+ /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { children: [
2220
2635
  "\u751F\u547D: ",
2221
- /* @__PURE__ */ jsx7(Text8, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
2636
+ /* @__PURE__ */ jsx9(Text10, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
2222
2637
  ] }) }),
2223
- /* @__PURE__ */ jsx7(Box7, { width: 10, children: /* @__PURE__ */ jsxs7(Text8, { children: [
2638
+ /* @__PURE__ */ jsx9(Box9, { width: 10, children: /* @__PURE__ */ jsxs9(Text10, { children: [
2224
2639
  "\u7816\u5757: ",
2225
- /* @__PURE__ */ jsx7(Text8, { color: "cyan", children: aliveCount })
2640
+ /* @__PURE__ */ jsx9(Text10, { color: "cyan", children: aliveCount })
2226
2641
  ] }) }),
2227
- /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text8, { color: s.paused ? "gray" : "green", children: [
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__ */ jsxs7(Box7, { flexDirection: "column", children: [
2234
- /* @__PURE__ */ jsxs7(Text8, { children: [
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__ */ jsx7(Text8, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
2240
- /* @__PURE__ */ jsxs7(Text8, { children: [
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__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2247
- /* @__PURE__ */ jsx7(Text8, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
2248
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx7(Box7, { width: 22, children: /* @__PURE__ */ jsxs7(Text8, { children: [
2249
- /* @__PURE__ */ jsx7(Text8, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
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__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
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__ */ jsxs7(Box7, { marginTop: 1, children: [
2261
- /* @__PURE__ */ jsx7(Text8, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
2262
- /* @__PURE__ */ jsxs7(Text8, { children: [
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__ */ jsx7(Text8, { color: "yellow", children: s.score })
2679
+ /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: s.score })
2265
2680
  ] })
2266
2681
  ] }),
2267
- !selectingLevel && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
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__ */ jsx7(BrickBreakerGame, { onExit: () => {
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 Box8, Text as Text9, useInput as useInput4, render as render3 } from "ink";
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 jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
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__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, children: [
2761
- /* @__PURE__ */ jsx8(Box8, { flexDirection: "row", children: /* @__PURE__ */ jsxs8(Text9, { children: [
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__ */ jsx8(Text9, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
3178
+ /* @__PURE__ */ jsx10(Text11, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
2764
3179
  " ",
2765
3180
  "\u901F\u5EA6 ",
2766
- /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
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__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text9, { children: [
3186
+ !s.gameOver && s.target && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { children: [
2772
3187
  "\u6253\u5B57: ",
2773
- /* @__PURE__ */ jsx8(Text9, { color: "green", children: s.typed }),
2774
- /* @__PURE__ */ jsx8(Text9, { color: "white", children: s.target.slice(s.typed.length) })
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__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
2777
- /* @__PURE__ */ jsxs8(Text9, { children: [
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__ */ jsx8(Text9, { children: `\u2502${row}\u2502` }, i)),
2783
- /* @__PURE__ */ jsxs8(Text9, { children: [
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__ */ jsxs8(Box8, { marginTop: 1, children: [
2790
- /* @__PURE__ */ jsx8(Text9, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
2791
- /* @__PURE__ */ jsxs8(Text9, { children: [
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__ */ jsx8(Text9, { color: "yellow", children: s.score }),
3208
+ /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: s.score }),
2794
3209
  " r \u91CD\u5F00 q \u9000\u51FA"
2795
3210
  ] })
2796
3211
  ] }),
2797
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
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__ */ jsx8(CoderCheck, { onExit: () => {
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 chalk3 from "chalk";
3240
+ import chalk4 from "chalk";
2826
3241
 
2827
3242
  // src/stock/StockList.tsx
2828
- import { Box as Box9, Text as Text10, useInput as useInput5 } from "ink";
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 jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
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__ */ jsx9(Box9, { paddingLeft: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
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__ */ jsxs9(Box9, { flexDirection: "column", children: [
3033
- /* @__PURE__ */ jsxs9(Box9, { marginBottom: 1, justifyContent: "space-between", children: [
3034
- /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ffff", children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
3035
- /* @__PURE__ */ jsxs9(Text10, { dimColor: true, children: [
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__ */ jsx9(Text10, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
3454
+ /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
3040
3455
  ] }),
3041
- /* @__PURE__ */ jsxs9(Box9, { children: [
3042
- /* @__PURE__ */ jsx9(Box9, { width: 3 }),
3043
- /* @__PURE__ */ jsx9(Box9, { width: 9, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u4EE3\u7801" }) }),
3044
- /* @__PURE__ */ jsx9(Box9, { width: 16, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u540D\u79F0" }) }),
3045
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
3046
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
3047
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
3048
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6700\u9AD8" }) }),
3049
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6700\u4F4E" }) }),
3050
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
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__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
3053
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: stocks.map((stock, index) => {
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__ */ jsxs9(Box9, { children: [
3058
- /* @__PURE__ */ jsx9(Box9, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ffff", children: "\u25B8 " }) : /* @__PURE__ */ jsx9(Text10, { children: " " }) }),
3059
- /* @__PURE__ */ jsx9(Box9, { width: 9, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: isSelected ? "#00ffff" : "#ffffff", children: stock.code }) }),
3060
- /* @__PURE__ */ jsx9(Box9, { width: 16, children: /* @__PURE__ */ jsx9(Text10, { color: isSelected ? "#ffffff" : "#cccccc", children: stock.name }) }),
3061
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color, children: formatPrice(stock.price) }) }),
3062
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { color, children: [
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__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { color, children: [
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__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { color: "#cccccc", children: formatPrice(stock.high) }) }),
3072
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsx9(Text10, { color: "#888888", children: formatPrice(stock.low) }) }),
3073
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { color: "#888888", children: formatAmount(stock.amount) }) })
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__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 q \u8FD4\u56DE` }) }),
3077
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ~/.dskcode/settings.json` }) }),
3078
- doubleCtrlC && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
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__ */ jsxs9(Box9, { flexDirection: "column", paddingLeft: 1, children: [
3097
- /* @__PURE__ */ jsxs9(Box9, { marginBottom: 1, justifyContent: "space-between", children: [
3098
- /* @__PURE__ */ jsxs9(Box9, { children: [
3099
- /* @__PURE__ */ jsxs9(Text10, { bold: true, color: "#00ffff", children: [
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__ */ jsx9(Text10, { dimColor: true, children: stock.code }),
3105
- currentTime && /* @__PURE__ */ jsxs9(Text10, { dimColor: true, children: [
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__ */ jsx9(Text10, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
3525
+ /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
3111
3526
  ] }),
3112
- /* @__PURE__ */ jsxs9(Box9, { children: [
3113
- /* @__PURE__ */ jsx9(Box9, { width: 16, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
3114
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { bold: true, color: colorCode, children: [
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__ */ jsxs9(Box9, { children: [
3121
- /* @__PURE__ */ jsx9(Box9, { width: 16, children: /* @__PURE__ */ jsx9(Text10, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
3122
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { color: colorCode, children: [
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__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { color: colorCode, children: line || " " }) }, i)) }),
3132
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
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 jsx10 } from "react/jsx-runtime";
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(` ${chalk3.green("\u2714")} API Key \u5DF2\u4FDD\u5B58\u5230 ${chalk3.dim(savedPath)}
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__ */ jsx10(
3678
+ /* @__PURE__ */ jsx12(
3176
3679
  ChatSession,
3177
3680
  {
3178
- providerCount: ctx?.config.providers.length ?? 1,
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__ */ jsx10(
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__ */ jsx10(
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 = join3(home, ".dskcode", "settings.json");
3784
+ const globalConfigPath = join5(home, ".dskcode", "settings.json");
3280
3785
  let globalConfigHasStock = false;
3281
3786
  try {
3282
- const raw = await readFile3(globalConfigPath, "utf-8");
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(`${chalk3.green("\u2714")} \u5DF2\u751F\u6210\u81EA\u9009\u80A1\u914D\u7F6E: ${chalk3.dim(savedPath)}`);
3296
- console.log(`${chalk3.dim(" \u63D0\u793A: \u53EF\u7F16\u8F91\u4E0A\u8FF0\u6587\u4EF6\u81EA\u5B9A\u4E49\u81EA\u9009\u80A1\u5217\u8868")}
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__ */ jsx10(
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__ */ jsx10(
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: ${chalk3.green(selectedGame.name)}
3855
+ \u542F\u52A8\u6E38\u620F: ${chalk4.green(selectedGame.name)}
3351
3856
  `);
3352
3857
  await selectedGame.play();
3353
3858
  }