@hiver/skills 1.0.3 → 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 +371 -113
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -239,6 +239,15 @@ function getAgentMeta(collectionName, agentName) {
|
|
|
239
239
|
dependencies: Array.isArray(fm.dependencies) ? fm.dependencies : []
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
|
+
function findCollectionsContaining(name, type) {
|
|
243
|
+
const matches = [];
|
|
244
|
+
for (const col of listCollections()) {
|
|
245
|
+
const { skills, agents } = scanCollection(col);
|
|
246
|
+
if (type === "skill" && skills.includes(name)) matches.push(col);
|
|
247
|
+
if (type === "agent" && agents.includes(name)) matches.push(col);
|
|
248
|
+
}
|
|
249
|
+
return matches;
|
|
250
|
+
}
|
|
242
251
|
function resolveDependencies(selected, selectedCollections) {
|
|
243
252
|
const installedNames = /* @__PURE__ */ new Set([
|
|
244
253
|
...selected.skills.map((s) => s.name),
|
|
@@ -341,34 +350,8 @@ function Add({ directSkills }) {
|
|
|
341
350
|
const [selectedType, setSelectedType] = useState3(null);
|
|
342
351
|
const [toInstall, setToInstall] = useState3({ skills: [], agents: [] });
|
|
343
352
|
const [results, setResults] = useState3({ skills: 0, agents: 0, deps: [] });
|
|
353
|
+
const [directMissing, setDirectMissing] = useState3([]);
|
|
344
354
|
const destRoot = process.cwd();
|
|
345
|
-
useEffect(() => {
|
|
346
|
-
if (directSkills && directSkills.length > 0 && targetKey) {
|
|
347
|
-
installByName(directSkills, targets[targetKey], destRoot).then((res) => {
|
|
348
|
-
setResults(res);
|
|
349
|
-
setStep(STEPS.DONE);
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
}, [targetKey]);
|
|
353
|
-
async function installByName(names, targetConfig, dest) {
|
|
354
|
-
const collections = listCollections();
|
|
355
|
-
let skillCount = 0;
|
|
356
|
-
let agentCount = 0;
|
|
357
|
-
for (const name of names) {
|
|
358
|
-
for (const col of collections) {
|
|
359
|
-
const { skills, agents } = scanCollection(col);
|
|
360
|
-
if (skills.includes(name)) {
|
|
361
|
-
if (await installSkill(col, name, targetConfig, dest)) skillCount++;
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
if (agents.includes(name)) {
|
|
365
|
-
if (await installAgent(col, name, targetConfig, dest)) agentCount++;
|
|
366
|
-
break;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return { skills: skillCount, agents: agentCount, deps: [] };
|
|
371
|
-
}
|
|
372
355
|
function getAvailableTypes(col) {
|
|
373
356
|
const { skills, agents } = scanCollection(col);
|
|
374
357
|
const types = [];
|
|
@@ -378,11 +361,29 @@ function Add({ directSkills }) {
|
|
|
378
361
|
}
|
|
379
362
|
function handleTargetSelect(key) {
|
|
380
363
|
setTargetKey(key);
|
|
381
|
-
if (directSkills && directSkills.length > 0) return;
|
|
382
364
|
setStep(STEPS.COLLECTIONS);
|
|
383
365
|
}
|
|
384
366
|
function handleCollectionSelect(col) {
|
|
385
367
|
setSelectedCollection(col);
|
|
368
|
+
if (directSkills && directSkills.length > 0) {
|
|
369
|
+
const { skills, agents } = scanCollection(col);
|
|
370
|
+
const skillItems = [];
|
|
371
|
+
const agentItems = [];
|
|
372
|
+
const missing = [];
|
|
373
|
+
for (const name of directSkills) {
|
|
374
|
+
if (skills.includes(name)) skillItems.push({ collection: col, name });
|
|
375
|
+
else if (agents.includes(name)) agentItems.push({ collection: col, name });
|
|
376
|
+
else missing.push(`${name} (not in ${col})`);
|
|
377
|
+
}
|
|
378
|
+
setDirectMissing(missing);
|
|
379
|
+
setToInstall({ skills: skillItems, agents: agentItems });
|
|
380
|
+
if (skillItems.length === 0 && agentItems.length === 0) {
|
|
381
|
+
setStep(STEPS.DONE);
|
|
382
|
+
} else {
|
|
383
|
+
setStep(STEPS.INSTALLING);
|
|
384
|
+
}
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
386
387
|
setToInstall({ skills: [], agents: [] });
|
|
387
388
|
const types = getAvailableTypes(col);
|
|
388
389
|
if (types.length === 1) {
|
|
@@ -466,8 +467,24 @@ function Add({ directSkills }) {
|
|
|
466
467
|
);
|
|
467
468
|
}
|
|
468
469
|
if (step === STEPS.COLLECTIONS) {
|
|
469
|
-
|
|
470
|
+
let collections = listCollections();
|
|
471
|
+
if (directSkills && directSkills.length > 0) {
|
|
472
|
+
const union = /* @__PURE__ */ new Set();
|
|
473
|
+
for (const name of directSkills) {
|
|
474
|
+
for (const c of findCollectionsContaining(name, "skill")) union.add(c);
|
|
475
|
+
for (const c of findCollectionsContaining(name, "agent")) union.add(c);
|
|
476
|
+
}
|
|
477
|
+
collections = collections.filter((c) => union.has(c));
|
|
478
|
+
}
|
|
470
479
|
const items = collections.map((c) => ({ label: c, value: c }));
|
|
480
|
+
if (items.length === 0) {
|
|
481
|
+
setTimeout(() => exit(), 100);
|
|
482
|
+
return /* @__PURE__ */ jsxs4(ErrorMsg, { children: [
|
|
483
|
+
"None of: ",
|
|
484
|
+
directSkills.join(", "),
|
|
485
|
+
" found in any collection."
|
|
486
|
+
] });
|
|
487
|
+
}
|
|
471
488
|
return /* @__PURE__ */ jsx3(
|
|
472
489
|
Select,
|
|
473
490
|
{
|
|
@@ -530,6 +547,10 @@ function Add({ directSkills }) {
|
|
|
530
547
|
if (step === STEPS.DONE) {
|
|
531
548
|
setTimeout(() => exit(), 100);
|
|
532
549
|
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
550
|
+
directMissing.length > 0 && /* @__PURE__ */ jsx3(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsxs4(ErrorMsg, { children: [
|
|
551
|
+
"Not found in any collection: ",
|
|
552
|
+
directMissing.join(", ")
|
|
553
|
+
] }) }),
|
|
533
554
|
results.deps.length > 0 && /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", marginBottom: 1, children: [
|
|
534
555
|
/* @__PURE__ */ jsx3(Info, { children: "Auto-installed dependencies:" }),
|
|
535
556
|
results.deps.map((d) => /* @__PURE__ */ jsxs4(Text4, { color: "cyan", children: [
|
|
@@ -625,8 +646,8 @@ function List() {
|
|
|
625
646
|
// src/commands/Update.jsx
|
|
626
647
|
import React8, { useState as useState4, useEffect as useEffect2 } from "react";
|
|
627
648
|
import { Box as Box7, Text as Text8, useApp as useApp3 } from "ink";
|
|
628
|
-
import
|
|
629
|
-
import
|
|
649
|
+
import path4 from "path";
|
|
650
|
+
import fs4 from "fs-extra";
|
|
630
651
|
|
|
631
652
|
// src/components/Confirm.jsx
|
|
632
653
|
import React6 from "react";
|
|
@@ -671,6 +692,8 @@ function DiffView({ patch }) {
|
|
|
671
692
|
}
|
|
672
693
|
|
|
673
694
|
// src/utils/diffUtil.js
|
|
695
|
+
import path3 from "path";
|
|
696
|
+
import fs3 from "fs-extra";
|
|
674
697
|
import { createTwoFilesPatch } from "diff";
|
|
675
698
|
function computeDiff(filePath, localContent, latestContent) {
|
|
676
699
|
return createTwoFilesPatch(
|
|
@@ -685,133 +708,367 @@ function computeDiff(filePath, localContent, latestContent) {
|
|
|
685
708
|
function hasChanges(localContent, latestContent) {
|
|
686
709
|
return localContent.trim() !== latestContent.trim();
|
|
687
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
|
+
}
|
|
688
768
|
|
|
689
769
|
// src/commands/Update.jsx
|
|
690
770
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
691
771
|
var STEPS2 = {
|
|
692
772
|
TARGET: "target",
|
|
693
|
-
|
|
773
|
+
COLLECTION: "collection",
|
|
774
|
+
ITEMS: "items",
|
|
775
|
+
RESOLVE: "resolve",
|
|
694
776
|
CONFIRM: "confirm",
|
|
695
777
|
DONE: "done"
|
|
696
778
|
};
|
|
697
|
-
function
|
|
779
|
+
function detectType(name, targetConfig, destRoot) {
|
|
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";
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
function Update({ directSkills }) {
|
|
698
787
|
const { exit } = useApp3();
|
|
699
788
|
const [step, setStep] = useState4(STEPS2.TARGET);
|
|
700
789
|
const [targetKey, setTargetKey] = useState4(null);
|
|
701
|
-
const [
|
|
790
|
+
const [selectedCollection, setSelectedCollection] = useState4(null);
|
|
791
|
+
const [queue, setQueue] = useState4([]);
|
|
702
792
|
const [currentIdx, setCurrentIdx] = useState4(0);
|
|
793
|
+
const [currentPatch, setCurrentPatch] = useState4(null);
|
|
703
794
|
const [updatedCount, setUpdatedCount] = useState4(0);
|
|
704
795
|
const [skippedCount, setSkippedCount] = useState4(0);
|
|
796
|
+
const [installedCount, setInstalledCount] = useState4(0);
|
|
797
|
+
const [missingNames, setMissingNames] = useState4([]);
|
|
798
|
+
const [directInfo, setDirectInfo] = useState4([]);
|
|
799
|
+
const [skipReasons, setSkipReasons] = useState4([]);
|
|
705
800
|
const destRoot = process.cwd();
|
|
706
|
-
function
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
801
|
+
function handleTargetSelect(key) {
|
|
802
|
+
setTargetKey(key);
|
|
803
|
+
if (directSkills && directSkills.length > 0) {
|
|
804
|
+
const targetConfig = targets[key];
|
|
805
|
+
const info = [];
|
|
806
|
+
const missing = [];
|
|
807
|
+
for (const name of directSkills) {
|
|
808
|
+
let type = detectType(name, targetConfig, destRoot);
|
|
809
|
+
let installed = type !== null;
|
|
810
|
+
if (!type) {
|
|
811
|
+
if (findCollectionsContaining(name, "skill").length > 0) type = "skill";
|
|
812
|
+
else if (findCollectionsContaining(name, "agent").length > 0) type = "agent";
|
|
813
|
+
}
|
|
814
|
+
if (!type) {
|
|
815
|
+
missing.push(name);
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
const cols = findCollectionsContaining(name, type);
|
|
819
|
+
if (cols.length === 0) {
|
|
820
|
+
missing.push(name);
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
info.push({ name, type, installed, collections: cols });
|
|
824
|
+
}
|
|
825
|
+
setMissingNames(missing);
|
|
826
|
+
setDirectInfo(info);
|
|
827
|
+
if (info.length === 0) {
|
|
828
|
+
setStep(STEPS2.DONE);
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
711
831
|
}
|
|
712
|
-
|
|
832
|
+
setStep(STEPS2.COLLECTION);
|
|
713
833
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const localContent = fs3.readFileSync(localFile, "utf-8");
|
|
726
|
-
const latestContent = fs3.readFileSync(latestFile, "utf-8");
|
|
727
|
-
if (hasChanges(localContent, latestContent)) {
|
|
728
|
-
changed.push({
|
|
729
|
-
name: skillName,
|
|
730
|
-
type: "skill",
|
|
731
|
-
collection: source.collection,
|
|
732
|
-
patch: computeDiff("SKILL.md", localContent, latestContent)
|
|
733
|
-
});
|
|
834
|
+
function handleCollectionSelect(collection) {
|
|
835
|
+
setSelectedCollection(collection);
|
|
836
|
+
if (directSkills && directSkills.length > 0) {
|
|
837
|
+
const items = [];
|
|
838
|
+
const skipped = [];
|
|
839
|
+
for (const entry of directInfo) {
|
|
840
|
+
if (entry.collections.includes(collection)) {
|
|
841
|
+
items.push({ name: entry.name, type: entry.type, installed: entry.installed });
|
|
842
|
+
} else {
|
|
843
|
+
skipped.push(`${entry.name} (not in ${collection})`);
|
|
844
|
+
}
|
|
734
845
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
if (hasChanges(localContent, latestContent)) {
|
|
745
|
-
changed.push({
|
|
746
|
-
name: agentName,
|
|
747
|
-
type: "agent",
|
|
748
|
-
collection: source.collection,
|
|
749
|
-
patch: computeDiff(`${agentName}.md`, localContent, latestContent)
|
|
750
|
-
});
|
|
846
|
+
if (skipped.length > 0) {
|
|
847
|
+
setMissingNames((prev) => [...prev, ...skipped]);
|
|
848
|
+
}
|
|
849
|
+
setQueue(items);
|
|
850
|
+
setCurrentIdx(0);
|
|
851
|
+
if (items.length === 0) {
|
|
852
|
+
setStep(STEPS2.DONE);
|
|
853
|
+
} else {
|
|
854
|
+
setStep(STEPS2.RESOLVE);
|
|
751
855
|
}
|
|
856
|
+
} else {
|
|
857
|
+
setStep(STEPS2.ITEMS);
|
|
752
858
|
}
|
|
753
|
-
|
|
754
|
-
|
|
859
|
+
}
|
|
860
|
+
function handleItemsSubmit(values) {
|
|
861
|
+
const items = values.map((v) => {
|
|
862
|
+
const [type, name] = v.split(":");
|
|
863
|
+
return { name, type, installed: true };
|
|
864
|
+
});
|
|
865
|
+
setQueue(items);
|
|
866
|
+
setCurrentIdx(0);
|
|
867
|
+
if (items.length === 0) {
|
|
755
868
|
setStep(STEPS2.DONE);
|
|
756
869
|
} else {
|
|
757
|
-
|
|
870
|
+
setStep(STEPS2.RESOLVE);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
useEffect2(() => {
|
|
874
|
+
if (step !== STEPS2.RESOLVE) return;
|
|
875
|
+
const item = queue[currentIdx];
|
|
876
|
+
if (!item) {
|
|
877
|
+
setStep(STEPS2.DONE);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
processItem(item);
|
|
881
|
+
}, [step, currentIdx]);
|
|
882
|
+
async function processItem(item) {
|
|
883
|
+
const targetConfig = targets[targetKey];
|
|
884
|
+
const collection = selectedCollection;
|
|
885
|
+
if (!item.installed) {
|
|
886
|
+
if (item.type === "skill") {
|
|
887
|
+
await installSkill(collection, item.name, targetConfig, destRoot);
|
|
888
|
+
} else {
|
|
889
|
+
await installAgent(collection, item.name, targetConfig, destRoot);
|
|
890
|
+
}
|
|
891
|
+
setInstalledCount((c) => c + 1);
|
|
892
|
+
advance();
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (item.type === "skill") {
|
|
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));
|
|
758
909
|
setStep(STEPS2.CONFIRM);
|
|
910
|
+
return;
|
|
759
911
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
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");
|
|
916
|
+
advance();
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
const localContent = fs4.readFileSync(localFile, "utf-8");
|
|
920
|
+
const latestContent = fs4.readFileSync(latestFile, "utf-8");
|
|
921
|
+
if (!hasChanges(localContent, latestContent)) {
|
|
922
|
+
recordSkip(item.name, `already up-to-date with ${collection}`);
|
|
923
|
+
advance();
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
setCurrentPatch(computeDiff(`${item.name}.md`, localContent, latestContent));
|
|
927
|
+
setStep(STEPS2.CONFIRM);
|
|
928
|
+
}
|
|
929
|
+
function recordSkip(name, reason) {
|
|
930
|
+
setSkippedCount((c) => c + 1);
|
|
931
|
+
setSkipReasons((prev) => [...prev, { name, reason }]);
|
|
764
932
|
}
|
|
765
933
|
function handleConfirm(yes) {
|
|
766
|
-
const item =
|
|
934
|
+
const item = queue[currentIdx];
|
|
767
935
|
const targetConfig = targets[targetKey];
|
|
768
936
|
if (yes) {
|
|
769
937
|
if (item.type === "skill") {
|
|
770
|
-
const src =
|
|
771
|
-
const dest =
|
|
772
|
-
|
|
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 });
|
|
773
941
|
} else {
|
|
774
|
-
const src =
|
|
775
|
-
const dest =
|
|
776
|
-
|
|
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 });
|
|
777
945
|
}
|
|
778
946
|
setUpdatedCount((c) => c + 1);
|
|
779
947
|
} else {
|
|
780
|
-
|
|
948
|
+
recordSkip(item.name, "declined");
|
|
781
949
|
}
|
|
782
|
-
|
|
950
|
+
advance();
|
|
951
|
+
}
|
|
952
|
+
function advance() {
|
|
953
|
+
setCurrentPatch(null);
|
|
954
|
+
if (currentIdx + 1 < queue.length) {
|
|
783
955
|
setCurrentIdx((i) => i + 1);
|
|
956
|
+
setStep(STEPS2.RESOLVE);
|
|
784
957
|
} else {
|
|
785
958
|
setStep(STEPS2.DONE);
|
|
786
959
|
}
|
|
787
960
|
}
|
|
788
961
|
if (step === STEPS2.TARGET) {
|
|
789
|
-
return /* @__PURE__ */ jsx7(
|
|
962
|
+
return /* @__PURE__ */ jsx7(
|
|
963
|
+
Select,
|
|
964
|
+
{
|
|
965
|
+
items: targetList,
|
|
966
|
+
onSelect: handleTargetSelect,
|
|
967
|
+
onBack: () => exit(),
|
|
968
|
+
message: "Which target to update?"
|
|
969
|
+
}
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
if (step === STEPS2.COLLECTION) {
|
|
973
|
+
let collectionNames;
|
|
974
|
+
if (directSkills && directSkills.length > 0) {
|
|
975
|
+
const union = /* @__PURE__ */ new Set();
|
|
976
|
+
for (const entry of directInfo) {
|
|
977
|
+
for (const c of entry.collections) union.add(c);
|
|
978
|
+
}
|
|
979
|
+
collectionNames = listCollections().filter((c) => union.has(c));
|
|
980
|
+
} else {
|
|
981
|
+
collectionNames = listCollections();
|
|
982
|
+
}
|
|
983
|
+
const items = collectionNames.map((c) => ({ label: c, value: c }));
|
|
984
|
+
return /* @__PURE__ */ jsx7(
|
|
985
|
+
Select,
|
|
986
|
+
{
|
|
987
|
+
items,
|
|
988
|
+
onSelect: handleCollectionSelect,
|
|
989
|
+
onBack: () => setStep(STEPS2.TARGET),
|
|
990
|
+
message: "Pick collection to update from:"
|
|
991
|
+
}
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
if (step === STEPS2.ITEMS) {
|
|
995
|
+
const targetConfig = targets[targetKey];
|
|
996
|
+
const installed = listInstalled(targetConfig, destRoot);
|
|
997
|
+
const { skills, agents } = scanCollection(selectedCollection);
|
|
998
|
+
const items = [
|
|
999
|
+
...installed.skills.filter((name) => skills.includes(name)).map((name) => ({
|
|
1000
|
+
label: `${name} (skill)`,
|
|
1001
|
+
value: `skill:${name}`,
|
|
1002
|
+
checked: false
|
|
1003
|
+
})),
|
|
1004
|
+
...installed.agents.filter((name) => agents.includes(name)).map((name) => ({
|
|
1005
|
+
label: `${name} (agent)`,
|
|
1006
|
+
value: `agent:${name}`,
|
|
1007
|
+
checked: false
|
|
1008
|
+
}))
|
|
1009
|
+
];
|
|
1010
|
+
if (items.length === 0) {
|
|
1011
|
+
setTimeout(() => exit(), 100);
|
|
1012
|
+
return /* @__PURE__ */ jsxs7(Info, { children: [
|
|
1013
|
+
'No installed skills/agents from "',
|
|
1014
|
+
selectedCollection,
|
|
1015
|
+
'" under ',
|
|
1016
|
+
targetConfig.skillsDir,
|
|
1017
|
+
"/."
|
|
1018
|
+
] });
|
|
1019
|
+
}
|
|
1020
|
+
return /* @__PURE__ */ jsx7(
|
|
1021
|
+
MultiSelect,
|
|
1022
|
+
{
|
|
1023
|
+
items,
|
|
1024
|
+
onSubmit: handleItemsSubmit,
|
|
1025
|
+
onBack: () => setStep(STEPS2.COLLECTION),
|
|
1026
|
+
message: `Select skills/agents from "${selectedCollection}" to update:`
|
|
1027
|
+
}
|
|
1028
|
+
);
|
|
790
1029
|
}
|
|
791
|
-
if (step === STEPS2.
|
|
792
|
-
return /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: "Checking
|
|
1030
|
+
if (step === STEPS2.RESOLVE) {
|
|
1031
|
+
return /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: "Checking..." });
|
|
793
1032
|
}
|
|
794
1033
|
if (step === STEPS2.CONFIRM) {
|
|
795
|
-
const item =
|
|
1034
|
+
const item = queue[currentIdx];
|
|
796
1035
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
797
1036
|
/* @__PURE__ */ jsxs7(Warning, { children: [
|
|
798
1037
|
item.name,
|
|
799
|
-
": local differs from
|
|
1038
|
+
": local differs from ",
|
|
1039
|
+
selectedCollection
|
|
800
1040
|
] }),
|
|
801
|
-
/* @__PURE__ */ jsx7(DiffView, { patch:
|
|
1041
|
+
/* @__PURE__ */ jsx7(DiffView, { patch: currentPatch }),
|
|
802
1042
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Confirm, { message: `Update ${item.name}?`, onConfirm: handleConfirm }) })
|
|
803
1043
|
] });
|
|
804
1044
|
}
|
|
805
1045
|
if (step === STEPS2.DONE) {
|
|
806
1046
|
setTimeout(() => exit(), 100);
|
|
807
|
-
if (
|
|
808
|
-
return /* @__PURE__ */ jsx7(Success, { children: "
|
|
809
|
-
}
|
|
810
|
-
return /* @__PURE__ */ jsxs7(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1047
|
+
if (queue.length === 0 && missingNames.length === 0) {
|
|
1048
|
+
return /* @__PURE__ */ jsx7(Success, { children: "Nothing to update." });
|
|
1049
|
+
}
|
|
1050
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
1051
|
+
missingNames.length > 0 && /* @__PURE__ */ jsxs7(ErrorMsg, { children: [
|
|
1052
|
+
"Not found: ",
|
|
1053
|
+
missingNames.join(", ")
|
|
1054
|
+
] }),
|
|
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: [
|
|
1065
|
+
updatedCount,
|
|
1066
|
+
" updated, ",
|
|
1067
|
+
installedCount,
|
|
1068
|
+
" installed, ",
|
|
1069
|
+
skippedCount,
|
|
1070
|
+
" skipped"
|
|
1071
|
+
] }) })
|
|
815
1072
|
] });
|
|
816
1073
|
}
|
|
817
1074
|
return null;
|
|
@@ -820,8 +1077,8 @@ function Update() {
|
|
|
820
1077
|
// src/commands/Remove.jsx
|
|
821
1078
|
import React9, { useState as useState5 } from "react";
|
|
822
1079
|
import { Box as Box8, Text as Text9, useApp as useApp4 } from "ink";
|
|
823
|
-
import
|
|
824
|
-
import
|
|
1080
|
+
import path5 from "path";
|
|
1081
|
+
import fs5 from "fs-extra";
|
|
825
1082
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
826
1083
|
var STEPS3 = {
|
|
827
1084
|
TARGET: "target",
|
|
@@ -841,9 +1098,9 @@ function Remove({ skillNames }) {
|
|
|
841
1098
|
const targetConfig = targets[key];
|
|
842
1099
|
const missing = [];
|
|
843
1100
|
for (const name of skillNames) {
|
|
844
|
-
const skillPath =
|
|
845
|
-
const agentPath =
|
|
846
|
-
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)) {
|
|
847
1104
|
missing.push(name);
|
|
848
1105
|
}
|
|
849
1106
|
}
|
|
@@ -914,7 +1171,7 @@ function Help() {
|
|
|
914
1171
|
const commands = [
|
|
915
1172
|
{ name: "add [skills...]", desc: "Install skills/agents (interactive if no args)" },
|
|
916
1173
|
{ name: "list", desc: "List all available skills and agents" },
|
|
917
|
-
{ name: "update", desc: "Update installed skills
|
|
1174
|
+
{ name: "update [skills...]", desc: "Update installed skills (interactive if no args)" },
|
|
918
1175
|
{ name: "remove <skills>", desc: "Remove installed skills/agents" },
|
|
919
1176
|
{ name: "help", desc: "Show this help message" }
|
|
920
1177
|
];
|
|
@@ -923,6 +1180,7 @@ function Help() {
|
|
|
923
1180
|
"npx @hiver/skills add discuss-problem create-prd",
|
|
924
1181
|
"npx @hiver/skills list",
|
|
925
1182
|
"npx @hiver/skills update",
|
|
1183
|
+
"npx @hiver/skills update build-component",
|
|
926
1184
|
"npx @hiver/skills remove discuss-problem"
|
|
927
1185
|
];
|
|
928
1186
|
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [
|
|
@@ -959,7 +1217,7 @@ function App() {
|
|
|
959
1217
|
case "list":
|
|
960
1218
|
return /* @__PURE__ */ jsx9(List, {});
|
|
961
1219
|
case "update":
|
|
962
|
-
return /* @__PURE__ */ jsx9(Update, {});
|
|
1220
|
+
return /* @__PURE__ */ jsx9(Update, { directSkills: restArgs.length > 0 ? restArgs : null });
|
|
963
1221
|
case "remove":
|
|
964
1222
|
if (restArgs.length === 0) {
|
|
965
1223
|
return /* @__PURE__ */ jsxs9(Text10, { color: "red", children: [
|