oh-skillhub 0.1.17 → 0.1.18
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/package.json +1 -1
- package/src/agents.js +12 -3
- package/src/cli.js +78 -10
package/package.json
CHANGED
package/src/agents.js
CHANGED
|
@@ -13,11 +13,10 @@ function resolveAgentTargets(options = {}) {
|
|
|
13
13
|
if (!["user", "project"].includes(scope)) {
|
|
14
14
|
throw new Error(`Unsupported scope "${scope}". Use user or project.`);
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
const agents = normalizeAgentSelection(agent);
|
|
17
|
+
if (agents.length > 1 && options.target) {
|
|
17
18
|
throw new Error("--agent all cannot be combined with --target");
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
const agents = agent === "all" ? SUPPORTED_AGENTS : [agent];
|
|
21
20
|
for (const item of agents) {
|
|
22
21
|
if (!SUPPORTED_AGENTS.includes(item)) {
|
|
23
22
|
throw new Error(`Unsupported agent "${item}". Use codex, claude, opencode, or all.`);
|
|
@@ -31,6 +30,16 @@ function resolveAgentTargets(options = {}) {
|
|
|
31
30
|
}));
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
function normalizeAgentSelection(agent) {
|
|
34
|
+
if (agent === "all") {
|
|
35
|
+
return SUPPORTED_AGENTS;
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(agent)) {
|
|
38
|
+
return Array.from(new Set(agent));
|
|
39
|
+
}
|
|
40
|
+
return [agent];
|
|
41
|
+
}
|
|
42
|
+
|
|
34
43
|
function defaultDirFor(agent, scope, cwd, homeDir, env) {
|
|
35
44
|
if (scope === "project") {
|
|
36
45
|
if (agent === "codex") return path.join(cwd, ".codex", "skills");
|
package/src/cli.js
CHANGED
|
@@ -38,6 +38,8 @@ const AGENT_CHOICES = [
|
|
|
38
38
|
{ agent: "opencode", label: "OpenCode", hint: "~/.config/opencode/skill" },
|
|
39
39
|
{ agent: "all", label: "All", hint: "Codex + Claude + OpenCode" },
|
|
40
40
|
];
|
|
41
|
+
const INDIVIDUAL_AGENT_INDEXES = [0, 1, 2];
|
|
42
|
+
const ALL_AGENT_INDEX = 3;
|
|
41
43
|
const ACTION_CHOICES = [
|
|
42
44
|
{ action: "install", label: "Install skills", hint: "Choose OpenHarmony skill groups to install" },
|
|
43
45
|
{ action: "clean", label: "Clean installed skills", hint: "Scan an agent target and remove selected skills" },
|
|
@@ -156,7 +158,7 @@ async function runCleanWithAnswers(options, input, output, scriptedAnswers = nul
|
|
|
156
158
|
} else {
|
|
157
159
|
output.write(renderAgentMenu());
|
|
158
160
|
output.write("Select target [1]: \n");
|
|
159
|
-
agent =
|
|
161
|
+
agent = parseAgentSelection(takeAnswer() || "");
|
|
160
162
|
}
|
|
161
163
|
}
|
|
162
164
|
const targets = resolveAgentTargets({
|
|
@@ -379,7 +381,7 @@ async function runInteractiveInstallerFromAnswers(answers, output = process.stdo
|
|
|
379
381
|
const [agentAnswer, groupAnswer] = answers.length > 1 ? [answers[0], answers.slice(1).join(" ")] : ["", answers[0] || ""];
|
|
380
382
|
output.write(renderAgentMenu());
|
|
381
383
|
output.write("Select target [1]: \n");
|
|
382
|
-
const agent =
|
|
384
|
+
const agent = parseAgentSelection(agentAnswer);
|
|
383
385
|
output.write(renderTuiMenu(choices, agent));
|
|
384
386
|
output.write("Select groups [9]: \n");
|
|
385
387
|
const selectedIndexes = parseSelection(groupAnswer, choices.length, 9);
|
|
@@ -392,7 +394,7 @@ async function installInteractiveSelection(manifest, choices, agent, selectedInd
|
|
|
392
394
|
if (!skills.length) {
|
|
393
395
|
throw new Error("No skills matched the selected groups.");
|
|
394
396
|
}
|
|
395
|
-
output.write(`\nInstalling ${selectedChoices.map((choice) => choice.path).join(", ")} for ${agent}:user...\n`);
|
|
397
|
+
output.write(`\nInstalling ${selectedChoices.map((choice) => choice.path).join(", ")} for ${formatAgentSelection(agent)}:user...\n`);
|
|
396
398
|
const sourceRoot = await withSpinner(output, `Preparing skill source from ${manifest.source}#${manifest.ref}`, () =>
|
|
397
399
|
ensureSkillSourceRootAsync(manifest, { env: process.env, skills }),
|
|
398
400
|
);
|
|
@@ -469,7 +471,7 @@ function renderTuiMenu(choices, agent = "codex") {
|
|
|
469
471
|
line,
|
|
470
472
|
"",
|
|
471
473
|
"Target",
|
|
472
|
-
` Agent: ${agent}`,
|
|
474
|
+
` Agent: ${formatAgentSelection(agent)}`,
|
|
473
475
|
" Scope: user",
|
|
474
476
|
"",
|
|
475
477
|
"Choose skill groups",
|
|
@@ -607,7 +609,7 @@ function runRawTuiSelection(input, output, choices, agent = "codex") {
|
|
|
607
609
|
function runRawAgentSelection(input, output) {
|
|
608
610
|
return new Promise((resolve, reject) => {
|
|
609
611
|
let cursor = 0;
|
|
610
|
-
|
|
612
|
+
const selected = new Set([0]);
|
|
611
613
|
const wasRaw = input.isRaw;
|
|
612
614
|
|
|
613
615
|
readline.emitKeypressEvents(input);
|
|
@@ -641,13 +643,13 @@ function runRawAgentSelection(input, output) {
|
|
|
641
643
|
return;
|
|
642
644
|
}
|
|
643
645
|
if (key && key.name === "space") {
|
|
644
|
-
selected
|
|
646
|
+
toggleAgentSelection(selected, cursor);
|
|
645
647
|
render();
|
|
646
648
|
return;
|
|
647
649
|
}
|
|
648
650
|
if (key && key.name === "return") {
|
|
649
651
|
cleanup();
|
|
650
|
-
resolve(
|
|
652
|
+
resolve(agentSelectionFromIndexes(selected, cursor));
|
|
651
653
|
}
|
|
652
654
|
}
|
|
653
655
|
|
|
@@ -733,9 +735,10 @@ function renderRawActionMenu(cursor, selected = cursor) {
|
|
|
733
735
|
return `${lines.join("\n")}\n`;
|
|
734
736
|
}
|
|
735
737
|
|
|
736
|
-
function renderRawAgentMenu(cursor, selected = cursor) {
|
|
738
|
+
function renderRawAgentMenu(cursor, selected = new Set([cursor])) {
|
|
737
739
|
const width = 76;
|
|
738
740
|
const line = `+${"-".repeat(width - 2)}+`;
|
|
741
|
+
const selectedIndexes = normalizeAgentIndexes(selected);
|
|
739
742
|
const lines = [
|
|
740
743
|
line,
|
|
741
744
|
rawHeaderLine("OH SkillHub", width, ANSI.cyan, ANSI.bold),
|
|
@@ -749,7 +752,7 @@ function renderRawAgentMenu(cursor, selected = cursor) {
|
|
|
749
752
|
AGENT_CHOICES.forEach((choice, index) => {
|
|
750
753
|
const pointer = index === cursor ? ">" : " ";
|
|
751
754
|
const highlighted = index === cursor;
|
|
752
|
-
const row = `${pointer} ${rawCheckbox(index
|
|
755
|
+
const row = `${pointer} ${rawCheckbox(isAgentIndexSelected(selectedIndexes, index), highlighted)} ${choice.label.padEnd(10, " ")} ${choice.hint}`;
|
|
753
756
|
lines.push(index === cursor ? colorize(row, ANSI.reverse, ANSI.bold) : row);
|
|
754
757
|
});
|
|
755
758
|
lines.push("");
|
|
@@ -925,6 +928,15 @@ function parseSingleSelection(answer, max, defaultNumber) {
|
|
|
925
928
|
return indexes[0];
|
|
926
929
|
}
|
|
927
930
|
|
|
931
|
+
function parseAgentSelection(answer) {
|
|
932
|
+
const indexes = parseSelection(answer, AGENT_CHOICES.length, 1);
|
|
933
|
+
if (indexes.includes(ALL_AGENT_INDEX)) {
|
|
934
|
+
return "all";
|
|
935
|
+
}
|
|
936
|
+
const agents = indexes.map((index) => AGENT_CHOICES[index].agent);
|
|
937
|
+
return agents.length === 1 ? agents[0] : agents;
|
|
938
|
+
}
|
|
939
|
+
|
|
928
940
|
function isSingleSelection(answer, max) {
|
|
929
941
|
try {
|
|
930
942
|
parseSingleSelection(answer, max, 1);
|
|
@@ -934,6 +946,62 @@ function isSingleSelection(answer, max) {
|
|
|
934
946
|
}
|
|
935
947
|
}
|
|
936
948
|
|
|
949
|
+
function normalizeAgentIndexes(selected) {
|
|
950
|
+
const indexes = selected instanceof Set ? Array.from(selected) : [selected];
|
|
951
|
+
if (indexes.includes(ALL_AGENT_INDEX)) {
|
|
952
|
+
return new Set(INDIVIDUAL_AGENT_INDEXES);
|
|
953
|
+
}
|
|
954
|
+
return new Set(indexes.filter((index) => INDIVIDUAL_AGENT_INDEXES.includes(index)));
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
function isAgentIndexSelected(selected, index) {
|
|
958
|
+
if (index === ALL_AGENT_INDEX) {
|
|
959
|
+
return INDIVIDUAL_AGENT_INDEXES.every((item) => selected.has(item));
|
|
960
|
+
}
|
|
961
|
+
return selected.has(index);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function toggleAgentSelection(selected, cursor) {
|
|
965
|
+
if (cursor === ALL_AGENT_INDEX) {
|
|
966
|
+
if (INDIVIDUAL_AGENT_INDEXES.every((index) => selected.has(index))) {
|
|
967
|
+
selected.clear();
|
|
968
|
+
selected.add(0);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
selected.clear();
|
|
972
|
+
for (const index of INDIVIDUAL_AGENT_INDEXES) {
|
|
973
|
+
selected.add(index);
|
|
974
|
+
}
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (selected.has(cursor) && selected.size > 1) {
|
|
978
|
+
selected.delete(cursor);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
selected.add(cursor);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
function agentSelectionFromIndexes(selected, cursor = 0) {
|
|
985
|
+
const normalized = normalizeAgentIndexes(selected);
|
|
986
|
+
if (!normalized.size) {
|
|
987
|
+
normalized.add(INDIVIDUAL_AGENT_INDEXES.includes(cursor) ? cursor : 0);
|
|
988
|
+
}
|
|
989
|
+
if (INDIVIDUAL_AGENT_INDEXES.every((index) => normalized.has(index))) {
|
|
990
|
+
return "all";
|
|
991
|
+
}
|
|
992
|
+
const agents = Array.from(normalized)
|
|
993
|
+
.sort((left, right) => left - right)
|
|
994
|
+
.map((index) => AGENT_CHOICES[index].agent);
|
|
995
|
+
return agents.length === 1 ? agents[0] : agents;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
function formatAgentSelection(agent) {
|
|
999
|
+
if (Array.isArray(agent)) {
|
|
1000
|
+
return agent.join(", ");
|
|
1001
|
+
}
|
|
1002
|
+
return agent;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
937
1005
|
function selectSkillsForChoices(manifest, choices) {
|
|
938
1006
|
const selected = new Map();
|
|
939
1007
|
for (const choice of choices) {
|
|
@@ -987,7 +1055,7 @@ function renderInteractiveCompletion(skills, targetOptions, output = process.std
|
|
|
987
1055
|
renderStatusLine(
|
|
988
1056
|
"success",
|
|
989
1057
|
"INSTALL SUCCESS",
|
|
990
|
-
`Installed ${skills.length} skill(s) for ${targetOptions.agent}:${targetOptions.scope}.`,
|
|
1058
|
+
`Installed ${skills.length} skill(s) for ${formatAgentSelection(targetOptions.agent)}:${targetOptions.scope}.`,
|
|
991
1059
|
output,
|
|
992
1060
|
),
|
|
993
1061
|
].join("\n");
|