dskcode 0.1.14 → 0.1.15
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 +225 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -487,9 +487,210 @@ 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 } 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
|
+
|
|
490
691
|
// src/cli/index.tsx
|
|
491
692
|
import { readFile as readFile3 } from "fs/promises";
|
|
492
|
-
import { join as
|
|
693
|
+
import { join as join4 } from "path";
|
|
493
694
|
|
|
494
695
|
// src/ui/RenderScope.tsx
|
|
495
696
|
import { render } from "ink";
|
|
@@ -567,8 +768,8 @@ function useDoubleCtrlC(onExit) {
|
|
|
567
768
|
import { Box as Box4, Text as Text5 } from "ink";
|
|
568
769
|
|
|
569
770
|
// src/provider/cost-tracker.ts
|
|
570
|
-
import { mkdir as
|
|
571
|
-
import { join as
|
|
771
|
+
import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
772
|
+
import { join as join3 } from "path";
|
|
572
773
|
var CostTracker = class {
|
|
573
774
|
#costDir;
|
|
574
775
|
#budgetLimit;
|
|
@@ -586,7 +787,7 @@ var CostTracker = class {
|
|
|
586
787
|
#flushInProgress = false;
|
|
587
788
|
constructor(options = {}) {
|
|
588
789
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
589
|
-
this.#costDir = options.costDir ??
|
|
790
|
+
this.#costDir = options.costDir ?? join3(home, ".dskcode", "costs");
|
|
590
791
|
this.#budgetLimit = options.budgetLimit ?? 0;
|
|
591
792
|
this.#tokenBudgetLimit = options.tokenBudgetLimit ?? 0;
|
|
592
793
|
this.#onBudgetExceeded = options.onBudgetExceeded;
|
|
@@ -800,7 +1001,7 @@ var CostTracker = class {
|
|
|
800
1001
|
}
|
|
801
1002
|
/** 从磁盘加载成本存储 */
|
|
802
1003
|
async #loadStore() {
|
|
803
|
-
const filePath =
|
|
1004
|
+
const filePath = join3(this.#costDir, "history.json");
|
|
804
1005
|
try {
|
|
805
1006
|
const raw = await readFile2(filePath, "utf-8");
|
|
806
1007
|
return JSON.parse(raw);
|
|
@@ -819,8 +1020,8 @@ var CostTracker = class {
|
|
|
819
1020
|
for (const date of datesToRemove) {
|
|
820
1021
|
delete store.daily[date];
|
|
821
1022
|
}
|
|
822
|
-
await
|
|
823
|
-
const filePath =
|
|
1023
|
+
await mkdir3(this.#costDir, { recursive: true });
|
|
1024
|
+
const filePath = join3(this.#costDir, "history.json");
|
|
824
1025
|
await writeFile2(filePath, JSON.stringify(store, null, 2), "utf-8");
|
|
825
1026
|
}
|
|
826
1027
|
};
|
|
@@ -1435,7 +1636,7 @@ function pickRandom(arr) {
|
|
|
1435
1636
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
1436
1637
|
}
|
|
1437
1638
|
function ChatSession({
|
|
1438
|
-
|
|
1639
|
+
skillCount,
|
|
1439
1640
|
toolCount,
|
|
1440
1641
|
verbose,
|
|
1441
1642
|
apiKey,
|
|
@@ -1822,8 +2023,8 @@ function ChatSession({
|
|
|
1822
2023
|
/* @__PURE__ */ jsxs5(Text6, { color: "#00ff41", children: [
|
|
1823
2024
|
" \u2714 ",
|
|
1824
2025
|
"\u5DF2\u52A0\u8F7D ",
|
|
1825
|
-
|
|
1826
|
-
" \u4E2A
|
|
2026
|
+
skillCount,
|
|
2027
|
+
" \u4E2A Skill"
|
|
1827
2028
|
] }),
|
|
1828
2029
|
/* @__PURE__ */ jsxs5(Text6, { color: "#00ffff", children: [
|
|
1829
2030
|
" \u2139 ",
|
|
@@ -2822,7 +3023,7 @@ function initGames() {
|
|
|
2822
3023
|
|
|
2823
3024
|
// src/cli/index.tsx
|
|
2824
3025
|
import { render as render4 } from "ink";
|
|
2825
|
-
import
|
|
3026
|
+
import chalk4 from "chalk";
|
|
2826
3027
|
|
|
2827
3028
|
// src/stock/StockList.tsx
|
|
2828
3029
|
import { Box as Box9, Text as Text10, useInput as useInput5 } from "ink";
|
|
@@ -3155,18 +3356,24 @@ function createCli() {
|
|
|
3155
3356
|
const key = await promptForApiKey();
|
|
3156
3357
|
if (!key) process.exit(1);
|
|
3157
3358
|
const savedPath = await saveApiKey(key);
|
|
3158
|
-
console.log(` ${
|
|
3359
|
+
console.log(` ${chalk4.green("\u2714")} API Key \u5DF2\u4FDD\u5B58\u5230 ${chalk4.dim(savedPath)}
|
|
3159
3360
|
`);
|
|
3160
3361
|
const result = await loadAndValidate();
|
|
3161
3362
|
ctx = { ...ctx, config: result.config };
|
|
3162
3363
|
}
|
|
3364
|
+
await promptImportClaudeSkills(process.cwd());
|
|
3163
3365
|
const costTracker = new CostTracker({
|
|
3164
3366
|
budgetLimit: ctx?.config.budgetLimit ?? 0,
|
|
3165
3367
|
tokenBudgetLimit: ctx?.config.tokenBudgetLimit ?? 0
|
|
3166
3368
|
});
|
|
3167
3369
|
startChat(ctx, costTracker);
|
|
3168
3370
|
});
|
|
3169
|
-
function startChat(ctx, costTracker) {
|
|
3371
|
+
async function startChat(ctx, costTracker) {
|
|
3372
|
+
const [globalSkillCount, localSkillCount] = await Promise.all([
|
|
3373
|
+
countDskcodeSkills(),
|
|
3374
|
+
countProjectLocalSkills(process.cwd())
|
|
3375
|
+
]);
|
|
3376
|
+
const skillCount = globalSkillCount + localSkillCount;
|
|
3170
3377
|
const defaultProvider = ctx?.config.providers.find(
|
|
3171
3378
|
(p) => p.name === (ctx?.config.defaultProvider ?? "deepseek")
|
|
3172
3379
|
);
|
|
@@ -3175,7 +3382,7 @@ function createCli() {
|
|
|
3175
3382
|
/* @__PURE__ */ jsx10(
|
|
3176
3383
|
ChatSession,
|
|
3177
3384
|
{
|
|
3178
|
-
|
|
3385
|
+
skillCount,
|
|
3179
3386
|
toolCount: ctx?.config.tools.length ?? 0,
|
|
3180
3387
|
verbose: ctx?.verbose ?? false,
|
|
3181
3388
|
apiKey: defaultProvider?.apiKey,
|
|
@@ -3276,7 +3483,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
3276
3483
|
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
3484
|
const ctx = this.dskcodeCtx;
|
|
3278
3485
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
3279
|
-
const globalConfigPath =
|
|
3486
|
+
const globalConfigPath = join4(home, ".dskcode", "settings.json");
|
|
3280
3487
|
let globalConfigHasStock = false;
|
|
3281
3488
|
try {
|
|
3282
3489
|
const raw = await readFile3(globalConfigPath, "utf-8");
|
|
@@ -3292,8 +3499,8 @@ compdef _dskcode_completion dskcode`);
|
|
|
3292
3499
|
{ code: "sh601899" }
|
|
3293
3500
|
];
|
|
3294
3501
|
const savedPath = await saveStockConfig(defaultSymbols);
|
|
3295
|
-
console.log(`${
|
|
3296
|
-
console.log(`${
|
|
3502
|
+
console.log(`${chalk4.green("\u2714")} \u5DF2\u751F\u6210\u81EA\u9009\u80A1\u914D\u7F6E: ${chalk4.dim(savedPath)}`);
|
|
3503
|
+
console.log(`${chalk4.dim(" \u63D0\u793A: \u53EF\u7F16\u8F91\u4E0A\u8FF0\u6587\u4EF6\u81EA\u5B9A\u4E49\u81EA\u9009\u80A1\u5217\u8868")}
|
|
3297
3504
|
`);
|
|
3298
3505
|
}
|
|
3299
3506
|
const freshResult = await loadAndValidate();
|
|
@@ -3347,7 +3554,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
3347
3554
|
});
|
|
3348
3555
|
if (selectedGame) {
|
|
3349
3556
|
console.log(`
|
|
3350
|
-
\u542F\u52A8\u6E38\u620F: ${
|
|
3557
|
+
\u542F\u52A8\u6E38\u620F: ${chalk4.green(selectedGame.name)}
|
|
3351
3558
|
`);
|
|
3352
3559
|
await selectedGame.play();
|
|
3353
3560
|
}
|