@hiver/skills 1.0.4 → 1.0.5
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/cli.js +117 -34
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -646,8 +646,8 @@ function List() {
|
|
|
646
646
|
// src/commands/Update.jsx
|
|
647
647
|
import React8, { useState as useState4, useEffect as useEffect2 } from "react";
|
|
648
648
|
import { Box as Box7, Text as Text8, useApp as useApp3 } from "ink";
|
|
649
|
-
import
|
|
650
|
-
import
|
|
649
|
+
import path4 from "path";
|
|
650
|
+
import fs4 from "fs-extra";
|
|
651
651
|
|
|
652
652
|
// src/components/Confirm.jsx
|
|
653
653
|
import React6 from "react";
|
|
@@ -692,6 +692,8 @@ function DiffView({ patch }) {
|
|
|
692
692
|
}
|
|
693
693
|
|
|
694
694
|
// src/utils/diffUtil.js
|
|
695
|
+
import path3 from "path";
|
|
696
|
+
import fs3 from "fs-extra";
|
|
695
697
|
import { createTwoFilesPatch } from "diff";
|
|
696
698
|
function computeDiff(filePath, localContent, latestContent) {
|
|
697
699
|
return createTwoFilesPatch(
|
|
@@ -706,6 +708,63 @@ function computeDiff(filePath, localContent, latestContent) {
|
|
|
706
708
|
function hasChanges(localContent, latestContent) {
|
|
707
709
|
return localContent.trim() !== latestContent.trim();
|
|
708
710
|
}
|
|
711
|
+
function walkFiles(dir) {
|
|
712
|
+
const out = [];
|
|
713
|
+
if (!fs3.existsSync(dir)) return out;
|
|
714
|
+
const entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
715
|
+
for (const entry of entries) {
|
|
716
|
+
const full = path3.join(dir, entry.name);
|
|
717
|
+
if (entry.isDirectory()) {
|
|
718
|
+
for (const sub of walkFiles(full)) out.push(path3.join(entry.name, sub));
|
|
719
|
+
} else if (entry.isFile()) {
|
|
720
|
+
out.push(entry.name);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return out;
|
|
724
|
+
}
|
|
725
|
+
function isBinary(buf) {
|
|
726
|
+
const sample = buf.subarray(0, Math.min(buf.length, 8e3));
|
|
727
|
+
for (let i = 0; i < sample.length; i++) {
|
|
728
|
+
if (sample[i] === 0) return true;
|
|
729
|
+
}
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
function hasDirChanges(localDir, latestDir) {
|
|
733
|
+
const localFiles = new Set(walkFiles(localDir));
|
|
734
|
+
const latestFiles = new Set(walkFiles(latestDir));
|
|
735
|
+
if (localFiles.size !== latestFiles.size) return true;
|
|
736
|
+
for (const rel of latestFiles) {
|
|
737
|
+
if (!localFiles.has(rel)) return true;
|
|
738
|
+
const a = fs3.readFileSync(path3.join(localDir, rel));
|
|
739
|
+
const b = fs3.readFileSync(path3.join(latestDir, rel));
|
|
740
|
+
if (!a.equals(b)) return true;
|
|
741
|
+
}
|
|
742
|
+
for (const rel of localFiles) {
|
|
743
|
+
if (!latestFiles.has(rel)) return true;
|
|
744
|
+
}
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
function computeDirDiff(localDir, latestDir) {
|
|
748
|
+
const localFiles = new Set(walkFiles(localDir));
|
|
749
|
+
const latestFiles = new Set(walkFiles(latestDir));
|
|
750
|
+
const allFiles = /* @__PURE__ */ new Set([...localFiles, ...latestFiles]);
|
|
751
|
+
const parts = [];
|
|
752
|
+
for (const rel of [...allFiles].sort()) {
|
|
753
|
+
const localBuf = localFiles.has(rel) ? fs3.readFileSync(path3.join(localDir, rel)) : Buffer.alloc(0);
|
|
754
|
+
const latestBuf = latestFiles.has(rel) ? fs3.readFileSync(path3.join(latestDir, rel)) : Buffer.alloc(0);
|
|
755
|
+
if (localBuf.equals(latestBuf)) continue;
|
|
756
|
+
if (isBinary(localBuf) || isBinary(latestBuf)) {
|
|
757
|
+
const verb = !localFiles.has(rel) ? "added" : !latestFiles.has(rel) ? "removed" : "changed";
|
|
758
|
+
parts.push(`Binary file ${rel} ${verb} (${localBuf.length} \u2192 ${latestBuf.length} bytes)`);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
const localContent = localBuf.toString("utf-8");
|
|
762
|
+
const latestContent = latestBuf.toString("utf-8");
|
|
763
|
+
if (localContent.trim() === latestContent.trim()) continue;
|
|
764
|
+
parts.push(computeDiff(rel, localContent, latestContent));
|
|
765
|
+
}
|
|
766
|
+
return parts.join("\n");
|
|
767
|
+
}
|
|
709
768
|
|
|
710
769
|
// src/commands/Update.jsx
|
|
711
770
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
@@ -718,10 +777,10 @@ var STEPS2 = {
|
|
|
718
777
|
DONE: "done"
|
|
719
778
|
};
|
|
720
779
|
function detectType(name, targetConfig, destRoot) {
|
|
721
|
-
const skillPath =
|
|
722
|
-
if (
|
|
723
|
-
const agentPath =
|
|
724
|
-
if (
|
|
780
|
+
const skillPath = path4.join(destRoot, targetConfig.skillsDir, name, "SKILL.md");
|
|
781
|
+
if (fs4.existsSync(skillPath)) return "skill";
|
|
782
|
+
const agentPath = path4.join(destRoot, targetConfig.agentsDir, `${name}.md`);
|
|
783
|
+
if (fs4.existsSync(agentPath)) return "agent";
|
|
725
784
|
return null;
|
|
726
785
|
}
|
|
727
786
|
function Update({ directSkills }) {
|
|
@@ -737,6 +796,7 @@ function Update({ directSkills }) {
|
|
|
737
796
|
const [installedCount, setInstalledCount] = useState4(0);
|
|
738
797
|
const [missingNames, setMissingNames] = useState4([]);
|
|
739
798
|
const [directInfo, setDirectInfo] = useState4([]);
|
|
799
|
+
const [skipReasons, setSkipReasons] = useState4([]);
|
|
740
800
|
const destRoot = process.cwd();
|
|
741
801
|
function handleTargetSelect(key) {
|
|
742
802
|
setTargetKey(key);
|
|
@@ -832,46 +892,60 @@ function Update({ directSkills }) {
|
|
|
832
892
|
advance();
|
|
833
893
|
return;
|
|
834
894
|
}
|
|
835
|
-
let localFile;
|
|
836
|
-
let latestFile;
|
|
837
895
|
if (item.type === "skill") {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
896
|
+
const localDir = path4.join(destRoot, targetConfig.skillsDir, item.name);
|
|
897
|
+
const latestDir = path4.join(getCollectionsDir(), collection, "skills", item.name);
|
|
898
|
+
if (!fs4.existsSync(localDir) || !fs4.existsSync(latestDir)) {
|
|
899
|
+
recordSkip(item.name, "source or local directory missing");
|
|
900
|
+
advance();
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
if (!hasDirChanges(localDir, latestDir)) {
|
|
904
|
+
recordSkip(item.name, `already up-to-date with ${collection}`);
|
|
905
|
+
advance();
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
setCurrentPatch(computeDirDiff(localDir, latestDir));
|
|
909
|
+
setStep(STEPS2.CONFIRM);
|
|
910
|
+
return;
|
|
843
911
|
}
|
|
844
|
-
|
|
912
|
+
const localFile = path4.join(destRoot, targetConfig.agentsDir, `${item.name}.md`);
|
|
913
|
+
const latestFile = path4.join(getCollectionsDir(), collection, "agents", `${item.name}.md`);
|
|
914
|
+
if (!fs4.existsSync(localFile) || !fs4.existsSync(latestFile)) {
|
|
915
|
+
recordSkip(item.name, "source or local file missing");
|
|
845
916
|
advance();
|
|
846
917
|
return;
|
|
847
918
|
}
|
|
848
|
-
const localContent =
|
|
849
|
-
const latestContent =
|
|
919
|
+
const localContent = fs4.readFileSync(localFile, "utf-8");
|
|
920
|
+
const latestContent = fs4.readFileSync(latestFile, "utf-8");
|
|
850
921
|
if (!hasChanges(localContent, latestContent)) {
|
|
851
|
-
|
|
922
|
+
recordSkip(item.name, `already up-to-date with ${collection}`);
|
|
852
923
|
advance();
|
|
853
924
|
return;
|
|
854
925
|
}
|
|
855
|
-
|
|
856
|
-
setCurrentPatch(computeDiff(filename, localContent, latestContent));
|
|
926
|
+
setCurrentPatch(computeDiff(`${item.name}.md`, localContent, latestContent));
|
|
857
927
|
setStep(STEPS2.CONFIRM);
|
|
858
928
|
}
|
|
929
|
+
function recordSkip(name, reason) {
|
|
930
|
+
setSkippedCount((c) => c + 1);
|
|
931
|
+
setSkipReasons((prev) => [...prev, { name, reason }]);
|
|
932
|
+
}
|
|
859
933
|
function handleConfirm(yes) {
|
|
860
934
|
const item = queue[currentIdx];
|
|
861
935
|
const targetConfig = targets[targetKey];
|
|
862
936
|
if (yes) {
|
|
863
937
|
if (item.type === "skill") {
|
|
864
|
-
const src =
|
|
865
|
-
const dest =
|
|
866
|
-
|
|
938
|
+
const src = path4.join(getCollectionsDir(), selectedCollection, "skills", item.name);
|
|
939
|
+
const dest = path4.join(destRoot, targetConfig.skillsDir, item.name);
|
|
940
|
+
fs4.copySync(src, dest, { overwrite: true });
|
|
867
941
|
} else {
|
|
868
|
-
const src =
|
|
869
|
-
const dest =
|
|
870
|
-
|
|
942
|
+
const src = path4.join(getCollectionsDir(), selectedCollection, "agents", `${item.name}.md`);
|
|
943
|
+
const dest = path4.join(destRoot, targetConfig.agentsDir, `${item.name}.md`);
|
|
944
|
+
fs4.copySync(src, dest, { overwrite: true });
|
|
871
945
|
}
|
|
872
946
|
setUpdatedCount((c) => c + 1);
|
|
873
947
|
} else {
|
|
874
|
-
|
|
948
|
+
recordSkip(item.name, "declined");
|
|
875
949
|
}
|
|
876
950
|
advance();
|
|
877
951
|
}
|
|
@@ -975,17 +1049,26 @@ function Update({ directSkills }) {
|
|
|
975
1049
|
}
|
|
976
1050
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
977
1051
|
missingNames.length > 0 && /* @__PURE__ */ jsxs7(ErrorMsg, { children: [
|
|
978
|
-
"
|
|
1052
|
+
"Not found: ",
|
|
979
1053
|
missingNames.join(", ")
|
|
980
1054
|
] }),
|
|
981
|
-
/* @__PURE__ */ jsxs7(
|
|
1055
|
+
skipReasons.length > 0 && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
1056
|
+
/* @__PURE__ */ jsx7(Info, { children: "Skipped:" }),
|
|
1057
|
+
skipReasons.map((s, i) => /* @__PURE__ */ jsxs7(Text8, { color: "gray", children: [
|
|
1058
|
+
" \u2022 ",
|
|
1059
|
+
s.name,
|
|
1060
|
+
" \u2014 ",
|
|
1061
|
+
s.reason
|
|
1062
|
+
] }, `${s.name}-${i}`))
|
|
1063
|
+
] }),
|
|
1064
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsxs7(Success, { children: [
|
|
982
1065
|
updatedCount,
|
|
983
1066
|
" updated, ",
|
|
984
1067
|
installedCount,
|
|
985
1068
|
" installed, ",
|
|
986
1069
|
skippedCount,
|
|
987
1070
|
" skipped"
|
|
988
|
-
] })
|
|
1071
|
+
] }) })
|
|
989
1072
|
] });
|
|
990
1073
|
}
|
|
991
1074
|
return null;
|
|
@@ -994,8 +1077,8 @@ function Update({ directSkills }) {
|
|
|
994
1077
|
// src/commands/Remove.jsx
|
|
995
1078
|
import React9, { useState as useState5 } from "react";
|
|
996
1079
|
import { Box as Box8, Text as Text9, useApp as useApp4 } from "ink";
|
|
997
|
-
import
|
|
998
|
-
import
|
|
1080
|
+
import path5 from "path";
|
|
1081
|
+
import fs5 from "fs-extra";
|
|
999
1082
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1000
1083
|
var STEPS3 = {
|
|
1001
1084
|
TARGET: "target",
|
|
@@ -1015,9 +1098,9 @@ function Remove({ skillNames }) {
|
|
|
1015
1098
|
const targetConfig = targets[key];
|
|
1016
1099
|
const missing = [];
|
|
1017
1100
|
for (const name of skillNames) {
|
|
1018
|
-
const skillPath =
|
|
1019
|
-
const agentPath =
|
|
1020
|
-
if (!
|
|
1101
|
+
const skillPath = path5.join(destRoot, targetConfig.skillsDir, name);
|
|
1102
|
+
const agentPath = path5.join(destRoot, targetConfig.agentsDir, `${name}.md`);
|
|
1103
|
+
if (!fs5.existsSync(skillPath) && !fs5.existsSync(agentPath)) {
|
|
1021
1104
|
missing.push(name);
|
|
1022
1105
|
}
|
|
1023
1106
|
}
|