itismyskillmarket 1.3.41 → 1.3.43
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/README.md +9 -3
- package/dist/{chunk-XQ653HCI.js → chunk-76RGF4GX.js} +108 -56
- package/dist/electron-entry.js +1 -1
- package/dist/index.js +3 -3
- package/gui/app.js +39 -0
- package/gui/index.html +1 -0
- package/gui/style.css +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SkillMarket
|
|
2
2
|
|
|
3
|
-
> **v1.3.
|
|
3
|
+
> **v1.3.42** — Cross-platform skill manager for AI coding tools (Cursor, VSCode, Codex CLI, OpenCode, Claude Code, Antigravity, OpenClaw, Hermes Agent, Saitec TUI).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -253,6 +253,10 @@ SkillMarket can install skills directly to your AI coding tool's skill directory
|
|
|
253
253
|
| OpenCode | `~/.config/opencode/skills/` | ✅ Detected |
|
|
254
254
|
| Claude Code | `~/.claude/skills/` | ✅ Available |
|
|
255
255
|
| VSCode | `~/.copilot/skills/` | ✅ Available |
|
|
256
|
+
| Codex CLI | `~/.codex/skills/` | ✅ Available |
|
|
257
|
+
| OpenClaw | `~/.openclaw/skills/` | ✅ Available |
|
|
258
|
+
| Hermes Agent | `~/.hermes/skills/` | ✅ Available |
|
|
259
|
+
| Saitec TUI | `~/.saitec_tui/skills/` | ✅ Available |
|
|
256
260
|
|
|
257
261
|
### Installation Behavior
|
|
258
262
|
|
|
@@ -270,7 +274,7 @@ Use `--platform` to target specific platforms:
|
|
|
270
274
|
skm install my-skill --platform opencode
|
|
271
275
|
|
|
272
276
|
# Multiple platforms
|
|
273
|
-
skm install my-skill --platform opencode,claude,vscode
|
|
277
|
+
skm install my-skill --platform opencode,claude,vscode,codex
|
|
274
278
|
```
|
|
275
279
|
|
|
276
280
|
Use `skm platforms` to see which platforms are available on your system:
|
|
@@ -283,6 +287,7 @@ $ skm platforms
|
|
|
283
287
|
OpenCode ✅ Available (2 skills installed)
|
|
284
288
|
Claude Code ✅ Available (1 skills installed)
|
|
285
289
|
VSCode ✅ Available (0 skills installed)
|
|
290
|
+
Codex CLI ✅ Available (0 skills installed)
|
|
286
291
|
OpenClaw ✅ Available (0 skills installed)
|
|
287
292
|
Hermes Agent ✅ Available (0 skills installed)
|
|
288
293
|
Saitec TUI ✅ Available (0 skills installed)
|
|
@@ -327,13 +332,14 @@ Skills are installed to `~/.skillmarket/` with the following structure:
|
|
|
327
332
|
~/.config/opencode/skills/<skill-name>/SKILL.md
|
|
328
333
|
~/.claude/skills/<skill-name>/SKILL.md
|
|
329
334
|
~/.copilot/skills/<skill-name>/SKILL.md
|
|
335
|
+
~/.codex/skills/<skill-name>/SKILL.md
|
|
330
336
|
```
|
|
331
337
|
|
|
332
338
|
## Supported Platforms
|
|
333
339
|
|
|
334
340
|
- Cursor
|
|
335
341
|
- VSCode
|
|
336
|
-
- Codex
|
|
342
|
+
- Codex CLI
|
|
337
343
|
- OpenCode
|
|
338
344
|
- Claude Code
|
|
339
345
|
- Antigravity
|
|
@@ -581,6 +581,56 @@ var SaitecAdapter = class extends BaseAdapter {
|
|
|
581
581
|
}
|
|
582
582
|
};
|
|
583
583
|
|
|
584
|
+
// src/adapters/codex.ts
|
|
585
|
+
import path9 from "path";
|
|
586
|
+
import os9 from "os";
|
|
587
|
+
import fs10 from "fs-extra";
|
|
588
|
+
var CodexAdapter = class extends BaseAdapter {
|
|
589
|
+
id = "codex";
|
|
590
|
+
name = "Codex CLI";
|
|
591
|
+
skillDir = path9.join(os9.homedir(), ".codex", "skills");
|
|
592
|
+
async isAvailable() {
|
|
593
|
+
if (process.env.CODEX_CLI) return true;
|
|
594
|
+
try {
|
|
595
|
+
return await fs10.pathExists(path9.join(os9.homedir(), ".codex"));
|
|
596
|
+
} catch {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
async isInstalled(skillId) {
|
|
601
|
+
try {
|
|
602
|
+
return await fs10.pathExists(path9.join(this.skillDir, skillId));
|
|
603
|
+
} catch {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
async install(skillId, sourceDir) {
|
|
608
|
+
await fs10.ensureDir(this.skillDir);
|
|
609
|
+
const targetDir = path9.join(this.skillDir, skillId);
|
|
610
|
+
if (await fs10.pathExists(targetDir)) {
|
|
611
|
+
await fs10.remove(targetDir);
|
|
612
|
+
}
|
|
613
|
+
await fs10.copy(sourceDir, targetDir, { recursive: true });
|
|
614
|
+
}
|
|
615
|
+
async uninstall(skillId) {
|
|
616
|
+
const targetDir = path9.join(this.skillDir, skillId);
|
|
617
|
+
if (await fs10.pathExists(targetDir)) {
|
|
618
|
+
await fs10.remove(targetDir);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
async listInstalled() {
|
|
622
|
+
try {
|
|
623
|
+
if (!await fs10.pathExists(this.skillDir)) {
|
|
624
|
+
return [];
|
|
625
|
+
}
|
|
626
|
+
const entries = await fs10.readdir(this.skillDir, { withFileTypes: true });
|
|
627
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
628
|
+
} catch {
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
|
|
584
634
|
// src/adapters/registry.ts
|
|
585
635
|
var adapters = /* @__PURE__ */ new Map();
|
|
586
636
|
function registerAdapters() {
|
|
@@ -590,12 +640,14 @@ function registerAdapters() {
|
|
|
590
640
|
const openclaw = new OpenClawAdapter();
|
|
591
641
|
const hermes = new HermesAdapter();
|
|
592
642
|
const saitec = new SaitecAdapter();
|
|
643
|
+
const codex = new CodexAdapter();
|
|
593
644
|
adapters.set(opencode.id, opencode);
|
|
594
645
|
adapters.set(claude.id, claude);
|
|
595
646
|
adapters.set(vscode.id, vscode);
|
|
596
647
|
adapters.set(openclaw.id, openclaw);
|
|
597
648
|
adapters.set(hermes.id, hermes);
|
|
598
649
|
adapters.set(saitec.id, saitec);
|
|
650
|
+
adapters.set(codex.id, codex);
|
|
599
651
|
}
|
|
600
652
|
registerAdapters();
|
|
601
653
|
async function detectPlatforms() {
|
|
@@ -617,8 +669,8 @@ function getAdapterByPlatform(platform) {
|
|
|
617
669
|
vscode: "vscode",
|
|
618
670
|
cursor: "opencode",
|
|
619
671
|
// Cursor uses OpenCode-compatible structure
|
|
620
|
-
codex: "
|
|
621
|
-
// Codex
|
|
672
|
+
codex: "codex",
|
|
673
|
+
// Codex has its own adapter
|
|
622
674
|
antigravity: "opencode",
|
|
623
675
|
// Antigravity uses OpenCode-compatible structure
|
|
624
676
|
openclaw: "openclaw",
|
|
@@ -629,8 +681,8 @@ function getAdapterByPlatform(platform) {
|
|
|
629
681
|
}
|
|
630
682
|
|
|
631
683
|
// src/commands/install.ts
|
|
632
|
-
import
|
|
633
|
-
import
|
|
684
|
+
import fs11 from "fs-extra";
|
|
685
|
+
import path10 from "path";
|
|
634
686
|
import { exec } from "child_process";
|
|
635
687
|
import { promisify } from "util";
|
|
636
688
|
import * as tar from "tar";
|
|
@@ -642,11 +694,11 @@ async function installSkill(skillId, version, options) {
|
|
|
642
694
|
if (options?.sourceDir) {
|
|
643
695
|
console.log(`Installing ${skillId} from local source...`);
|
|
644
696
|
pkgRoot = options.sourceDir;
|
|
645
|
-
const pkgJsonPath =
|
|
697
|
+
const pkgJsonPath = path10.join(pkgRoot, "package.json");
|
|
646
698
|
targetVersion = version || "0.0.0";
|
|
647
|
-
if (await
|
|
699
|
+
if (await fs11.pathExists(pkgJsonPath)) {
|
|
648
700
|
try {
|
|
649
|
-
const pkg = JSON.parse(await
|
|
701
|
+
const pkg = JSON.parse(await fs11.readFile(pkgJsonPath, "utf-8"));
|
|
650
702
|
if (pkg.version) targetVersion = pkg.version;
|
|
651
703
|
} catch {
|
|
652
704
|
}
|
|
@@ -663,20 +715,20 @@ async function installSkill(skillId, version, options) {
|
|
|
663
715
|
throw new Error(`No version found for ${packageName}`);
|
|
664
716
|
}
|
|
665
717
|
const cacheDir = getCacheDir();
|
|
666
|
-
const targetDir =
|
|
667
|
-
if (!await
|
|
718
|
+
const targetDir = path10.join(cacheDir, `${packageName}@${targetVersion}`);
|
|
719
|
+
if (!await fs11.pathExists(targetDir)) {
|
|
668
720
|
console.log("Downloading package...");
|
|
669
|
-
await
|
|
721
|
+
await fs11.ensureDir(cacheDir);
|
|
670
722
|
try {
|
|
671
723
|
const { stdout } = await execAsync(
|
|
672
724
|
`npm pack ${packageName}@${targetVersion} --pack-destination "${cacheDir}"`
|
|
673
725
|
);
|
|
674
726
|
const tarballName = stdout.trim();
|
|
675
|
-
const tarballPath =
|
|
676
|
-
if (await
|
|
727
|
+
const tarballPath = path10.join(cacheDir, tarballName);
|
|
728
|
+
if (await fs11.pathExists(tarballPath)) {
|
|
677
729
|
await tar.extract({ file: tarballPath, cwd: cacheDir });
|
|
678
|
-
await
|
|
679
|
-
await
|
|
730
|
+
await fs11.remove(tarballPath);
|
|
731
|
+
await fs11.move(path10.join(cacheDir, "package"), targetDir, { overwrite: true });
|
|
680
732
|
}
|
|
681
733
|
} catch (err) {
|
|
682
734
|
throw new Error(`Failed to download package: ${err}`);
|
|
@@ -685,29 +737,29 @@ async function installSkill(skillId, version, options) {
|
|
|
685
737
|
pkgRoot = targetDir;
|
|
686
738
|
}
|
|
687
739
|
const skillsDir = getSkillsDir();
|
|
688
|
-
const skillVersionDir =
|
|
740
|
+
const skillVersionDir = path10.join(skillsDir, `${skillId}@${targetVersion}`);
|
|
689
741
|
console.log("Setting up skill...");
|
|
690
|
-
await
|
|
691
|
-
if (await
|
|
692
|
-
await
|
|
693
|
-
|
|
694
|
-
|
|
742
|
+
await fs11.ensureDir(skillVersionDir);
|
|
743
|
+
if (await fs11.pathExists(path10.join(pkgRoot, "SKILL.md"))) {
|
|
744
|
+
await fs11.copy(
|
|
745
|
+
path10.join(pkgRoot, "SKILL.md"),
|
|
746
|
+
path10.join(skillVersionDir, "SKILL.md")
|
|
695
747
|
);
|
|
696
748
|
}
|
|
697
|
-
if (await
|
|
698
|
-
await
|
|
699
|
-
|
|
700
|
-
|
|
749
|
+
if (await fs11.pathExists(path10.join(pkgRoot, "metadata.json"))) {
|
|
750
|
+
await fs11.copy(
|
|
751
|
+
path10.join(pkgRoot, "metadata.json"),
|
|
752
|
+
path10.join(skillVersionDir, "metadata.json")
|
|
701
753
|
);
|
|
702
754
|
}
|
|
703
|
-
const skillDir =
|
|
704
|
-
await
|
|
705
|
-
const latestLink =
|
|
755
|
+
const skillDir = path10.join(skillsDir, skillId);
|
|
756
|
+
await fs11.ensureDir(skillDir);
|
|
757
|
+
const latestLink = path10.join(skillDir, LATEST_LINK);
|
|
706
758
|
try {
|
|
707
|
-
await
|
|
708
|
-
await
|
|
759
|
+
await fs11.remove(latestLink);
|
|
760
|
+
await fs11.symlink(skillVersionDir, latestLink, "junction");
|
|
709
761
|
} catch {
|
|
710
|
-
await
|
|
762
|
+
await fs11.copy(skillVersionDir, path10.join(skillDir, LATEST_LINK), { overwrite: true });
|
|
711
763
|
}
|
|
712
764
|
let targetAdapters = [];
|
|
713
765
|
if (options?.platforms && options.platforms.length > 0) {
|
|
@@ -768,8 +820,8 @@ Installing to ${targetAdapters.length} platform(s)...
|
|
|
768
820
|
}
|
|
769
821
|
|
|
770
822
|
// src/commands/uninstall.ts
|
|
771
|
-
import
|
|
772
|
-
import
|
|
823
|
+
import fs12 from "fs-extra";
|
|
824
|
+
import path11 from "path";
|
|
773
825
|
import readline from "readline";
|
|
774
826
|
async function askConfirmation(message) {
|
|
775
827
|
const rl = readline.createInterface({
|
|
@@ -794,12 +846,12 @@ async function getUninstallPreview(skillId, options) {
|
|
|
794
846
|
platformNames = adapters2.map((a) => a.name);
|
|
795
847
|
}
|
|
796
848
|
const skillsDir = getSkillsDir();
|
|
797
|
-
const localPath =
|
|
849
|
+
const localPath = path11.join(skillsDir, skillId);
|
|
798
850
|
const platformLinksDir = getPlatformLinksDir();
|
|
799
851
|
const platformLinks = [];
|
|
800
852
|
for (const platform of PLATFORMS) {
|
|
801
|
-
const linkPath =
|
|
802
|
-
if (await
|
|
853
|
+
const linkPath = path11.join(platformLinksDir, platform, "skills", skillId);
|
|
854
|
+
if (await fs12.pathExists(linkPath)) {
|
|
803
855
|
platformLinks.push(linkPath);
|
|
804
856
|
}
|
|
805
857
|
}
|
|
@@ -878,17 +930,17 @@ Uninstalling from ${validAdapters.length} platform(s)...
|
|
|
878
930
|
}
|
|
879
931
|
}
|
|
880
932
|
const skillsDir = getSkillsDir();
|
|
881
|
-
const skillDir =
|
|
882
|
-
if (await
|
|
883
|
-
await
|
|
933
|
+
const skillDir = path11.join(skillsDir, skillId);
|
|
934
|
+
if (await fs12.pathExists(skillDir)) {
|
|
935
|
+
await fs12.remove(skillDir);
|
|
884
936
|
console.log(`\u2705 Removed local files: ${skillDir}`);
|
|
885
937
|
}
|
|
886
938
|
const platformLinksDir = getPlatformLinksDir();
|
|
887
939
|
let removedLinks = 0;
|
|
888
940
|
for (const platform of PLATFORMS) {
|
|
889
|
-
const linkPath =
|
|
890
|
-
if (await
|
|
891
|
-
await
|
|
941
|
+
const linkPath = path11.join(platformLinksDir, platform, "skills", skillId);
|
|
942
|
+
if (await fs12.pathExists(linkPath)) {
|
|
943
|
+
await fs12.remove(linkPath);
|
|
892
944
|
removedLinks++;
|
|
893
945
|
}
|
|
894
946
|
}
|
|
@@ -1597,9 +1649,9 @@ async function adminAccess(skillId, level) {
|
|
|
1597
1649
|
}
|
|
1598
1650
|
|
|
1599
1651
|
// src/commands/config.ts
|
|
1600
|
-
import
|
|
1601
|
-
import
|
|
1602
|
-
import
|
|
1652
|
+
import path12 from "path";
|
|
1653
|
+
import fs13 from "fs-extra";
|
|
1654
|
+
import os10 from "os";
|
|
1603
1655
|
var CONFIG_DEFINITIONS = [
|
|
1604
1656
|
{
|
|
1605
1657
|
key: "npmScope",
|
|
@@ -1633,13 +1685,13 @@ var CONFIG_DEFINITIONS = [
|
|
|
1633
1685
|
}
|
|
1634
1686
|
];
|
|
1635
1687
|
function getConfigPath() {
|
|
1636
|
-
return
|
|
1688
|
+
return path12.join(os10.homedir(), ".skillmarket", "config.json");
|
|
1637
1689
|
}
|
|
1638
1690
|
async function readConfigFile() {
|
|
1639
1691
|
try {
|
|
1640
1692
|
const configPath = getConfigPath();
|
|
1641
|
-
if (await
|
|
1642
|
-
const data = await
|
|
1693
|
+
if (await fs13.pathExists(configPath)) {
|
|
1694
|
+
const data = await fs13.readJson(configPath);
|
|
1643
1695
|
const valid = {};
|
|
1644
1696
|
for (const def of CONFIG_DEFINITIONS) {
|
|
1645
1697
|
if (data[def.key] !== void 0) {
|
|
@@ -1654,11 +1706,11 @@ async function readConfigFile() {
|
|
|
1654
1706
|
}
|
|
1655
1707
|
async function writeConfigFile(updates) {
|
|
1656
1708
|
const configPath = getConfigPath();
|
|
1657
|
-
await
|
|
1709
|
+
await fs13.ensureDir(path12.dirname(configPath));
|
|
1658
1710
|
let existing = {};
|
|
1659
1711
|
try {
|
|
1660
|
-
if (await
|
|
1661
|
-
existing = await
|
|
1712
|
+
if (await fs13.pathExists(configPath)) {
|
|
1713
|
+
existing = await fs13.readJson(configPath);
|
|
1662
1714
|
}
|
|
1663
1715
|
} catch {
|
|
1664
1716
|
}
|
|
@@ -1668,25 +1720,25 @@ async function writeConfigFile(updates) {
|
|
|
1668
1720
|
delete merged[key];
|
|
1669
1721
|
}
|
|
1670
1722
|
}
|
|
1671
|
-
await
|
|
1723
|
+
await fs13.writeJson(configPath, merged, { spaces: 2 });
|
|
1672
1724
|
return merged;
|
|
1673
1725
|
}
|
|
1674
1726
|
async function removeConfigKeys(keys) {
|
|
1675
1727
|
const configPath = getConfigPath();
|
|
1676
|
-
if (!await
|
|
1728
|
+
if (!await fs13.pathExists(configPath)) return;
|
|
1677
1729
|
try {
|
|
1678
|
-
const existing = await
|
|
1730
|
+
const existing = await fs13.readJson(configPath);
|
|
1679
1731
|
for (const key of keys) {
|
|
1680
1732
|
delete existing[key];
|
|
1681
1733
|
}
|
|
1682
|
-
await
|
|
1734
|
+
await fs13.writeJson(configPath, existing, { spaces: 2 });
|
|
1683
1735
|
} catch {
|
|
1684
1736
|
}
|
|
1685
1737
|
}
|
|
1686
1738
|
async function removeConfigFile() {
|
|
1687
1739
|
const configPath = getConfigPath();
|
|
1688
|
-
if (await
|
|
1689
|
-
await
|
|
1740
|
+
if (await fs13.pathExists(configPath)) {
|
|
1741
|
+
await fs13.remove(configPath);
|
|
1690
1742
|
}
|
|
1691
1743
|
}
|
|
1692
1744
|
async function getAllConfig() {
|
package/dist/electron-entry.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
uninstallAll,
|
|
39
39
|
uninstallSkill,
|
|
40
40
|
updateSkill
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-76RGF4GX.js";
|
|
42
42
|
|
|
43
43
|
// src/cli.ts
|
|
44
44
|
import { Command } from "commander";
|
|
@@ -671,7 +671,7 @@ Commands:
|
|
|
671
671
|
info <skill> Display skill information
|
|
672
672
|
install <skill> Install a skill from npm or GitHub
|
|
673
673
|
@<version> Install specific version
|
|
674
|
-
--platform Target platforms (opencode,claude,...)
|
|
674
|
+
--platform Target platforms (opencode,claude,vscode,codex,...)
|
|
675
675
|
--force Overwrite if already installed
|
|
676
676
|
-b, --branch GitHub branch to install from
|
|
677
677
|
-c, --commit GitHub commit to install from
|
|
@@ -716,7 +716,7 @@ Examples:
|
|
|
716
716
|
skm install brainstorming Install to all detected platforms
|
|
717
717
|
skm install brainstorming@1.0.0 Install specific version
|
|
718
718
|
skm install owner/repo Install from GitHub
|
|
719
|
-
skm install brainstorming --platform opencode Install to specific
|
|
719
|
+
skm install brainstorming --platform opencode,codex Install to specific platforms
|
|
720
720
|
skm uninstall brainstorming Uninstall skill
|
|
721
721
|
skm uninstall --all Uninstall all skills
|
|
722
722
|
skm uninstall --all --yes Force uninstall all without confirmation
|
package/gui/app.js
CHANGED
|
@@ -241,6 +241,7 @@ const translations = {
|
|
|
241
241
|
'upload.installSuccess': '{skillName} installed locally!',
|
|
242
242
|
'upload.bothSuccess': '{skillName} published & installed!',
|
|
243
243
|
'upload.discarded': 'Upload discarded',
|
|
244
|
+
'upload.fileSelected': 'Selected: {name} ({size})',
|
|
244
245
|
'upload.errorInvalidZip': 'Invalid or empty zip file',
|
|
245
246
|
'upload.errorNoFile': 'Please select a zip file first',
|
|
246
247
|
'upload.uploadError': 'Upload failed: {error}',
|
|
@@ -487,6 +488,7 @@ const translations = {
|
|
|
487
488
|
'upload.installSuccess': '{skillName} 已安装到本地!',
|
|
488
489
|
'upload.bothSuccess': '{skillName} 已发布并安装!',
|
|
489
490
|
'upload.discarded': '上传已丢弃',
|
|
491
|
+
'upload.fileSelected': '已选择: {name} ({size})',
|
|
490
492
|
'upload.errorInvalidZip': '无效或空的 zip 文件',
|
|
491
493
|
'upload.errorNoFile': '请先选择一个 zip 文件',
|
|
492
494
|
'upload.uploadError': '上传失败:{error}',
|
|
@@ -2094,6 +2096,40 @@ const uploadState = {
|
|
|
2094
2096
|
/** 上传文件大小限制:50 MB */
|
|
2095
2097
|
const MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
|
|
2096
2098
|
|
|
2099
|
+
/** 格式化文件大小 */
|
|
2100
|
+
function formatFileSize(bytes) {
|
|
2101
|
+
if (bytes < 1024) return bytes + ' B';
|
|
2102
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
2103
|
+
return (bytes / 1024 / 1024).toFixed(1) + ' MB';
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
/** 更新 dropzone 显示已选文件信息 */
|
|
2107
|
+
function showUploadFileInfo(file) {
|
|
2108
|
+
const info = document.getElementById('upload-file-info');
|
|
2109
|
+
const dropzone = document.getElementById('upload-dropzone');
|
|
2110
|
+
if (!info || !dropzone) return;
|
|
2111
|
+
|
|
2112
|
+
const sizeStr = formatFileSize(file.size);
|
|
2113
|
+
const fileName = file.name;
|
|
2114
|
+
|
|
2115
|
+
info.textContent = t('upload.fileSelected', { name: fileName, size: sizeStr });
|
|
2116
|
+
info.classList.remove('hidden');
|
|
2117
|
+
dropzone.classList.add('selected');
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
/** 清除 dropzone 已选文件信息 */
|
|
2121
|
+
function clearUploadFileInfo() {
|
|
2122
|
+
const info = document.getElementById('upload-file-info');
|
|
2123
|
+
const dropzone = document.getElementById('upload-dropzone');
|
|
2124
|
+
if (info) {
|
|
2125
|
+
info.classList.add('hidden');
|
|
2126
|
+
info.textContent = '';
|
|
2127
|
+
}
|
|
2128
|
+
if (dropzone) {
|
|
2129
|
+
dropzone.classList.remove('selected');
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2097
2133
|
/** 初始化 Upload 控件 */
|
|
2098
2134
|
function initializeUploadControls() {
|
|
2099
2135
|
const dropzone = document.getElementById('upload-dropzone');
|
|
@@ -2120,6 +2156,7 @@ function initializeUploadControls() {
|
|
|
2120
2156
|
}
|
|
2121
2157
|
uploadState.file = file;
|
|
2122
2158
|
submitBtn.disabled = false;
|
|
2159
|
+
showUploadFileInfo(file);
|
|
2123
2160
|
}
|
|
2124
2161
|
});
|
|
2125
2162
|
|
|
@@ -2151,6 +2188,7 @@ function initializeUploadControls() {
|
|
|
2151
2188
|
}
|
|
2152
2189
|
uploadState.file = file;
|
|
2153
2190
|
submitBtn.disabled = false;
|
|
2191
|
+
showUploadFileInfo(file);
|
|
2154
2192
|
}
|
|
2155
2193
|
});
|
|
2156
2194
|
|
|
@@ -2199,6 +2237,7 @@ function resetUploadView() {
|
|
|
2199
2237
|
document.getElementById('upload-progress').classList.add('hidden');
|
|
2200
2238
|
document.getElementById('upload-file-input').value = '';
|
|
2201
2239
|
document.getElementById('upload-skill-name').value = '';
|
|
2240
|
+
clearUploadFileInfo();
|
|
2202
2241
|
}
|
|
2203
2242
|
|
|
2204
2243
|
/** 上传 zip 到后端 */
|
package/gui/index.html
CHANGED
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
<div class="upload-dropzone-icon">📦</div>
|
|
122
122
|
<p class="upload-dropzone-text" id="upload-dropzone-text">Drop a skill .zip file here, or click to select</p>
|
|
123
123
|
<p class="upload-dropzone-hint" id="upload-dropzone-hint">The zip should contain SKILL.md and optionally package.json</p>
|
|
124
|
+
<div id="upload-file-info" class="upload-file-info hidden"></div>
|
|
124
125
|
<input type="file" id="upload-file-input" accept=".zip" style="display:none">
|
|
125
126
|
<button id="upload-select-btn" class="btn btn-primary" style="margin-top:12px;">Choose File</button>
|
|
126
127
|
</div>
|
package/gui/style.css
CHANGED
|
@@ -938,6 +938,27 @@ body {
|
|
|
938
938
|
background: var(--bg-secondary);
|
|
939
939
|
}
|
|
940
940
|
|
|
941
|
+
.upload-dropzone.selected {
|
|
942
|
+
border-color: var(--success);
|
|
943
|
+
background: rgba(76, 175, 80, 0.08);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.upload-file-info {
|
|
947
|
+
margin-top: 12px;
|
|
948
|
+
padding: 6px 14px;
|
|
949
|
+
background: rgba(76, 175, 80, 0.12);
|
|
950
|
+
border: 1px solid var(--success);
|
|
951
|
+
border-radius: 6px;
|
|
952
|
+
color: var(--success);
|
|
953
|
+
font-size: 0.85rem;
|
|
954
|
+
display: inline-block;
|
|
955
|
+
transition: all 0.2s;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.upload-file-info.hidden {
|
|
959
|
+
display: none;
|
|
960
|
+
}
|
|
961
|
+
|
|
941
962
|
.upload-dropzone:hover,
|
|
942
963
|
.upload-dropzone.drag-over {
|
|
943
964
|
border-color: var(--accent);
|