skillstogether 0.1.0 → 0.1.2
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 +0 -13
- package/dist/index.js +370 -381
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -145,19 +145,6 @@ pnpm unlink --global
|
|
|
145
145
|
node packages/cli/dist/index.js --help
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
### Environment Variables
|
|
149
|
-
|
|
150
|
-
| Variable | Default | Description |
|
|
151
|
-
| --------------------- | ----------------------- | -------------------- |
|
|
152
|
-
| `CLI_API_URL` | `http://localhost:3000` | API server URL |
|
|
153
|
-
|
|
154
|
-
Example:
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
# Use a different API URL
|
|
158
|
-
CLI_API_URL=http://localhost:3000 node dist/index.js auth login
|
|
159
|
-
```
|
|
160
|
-
|
|
161
148
|
### Testing the Full Flow
|
|
162
149
|
|
|
163
150
|
1. Start the Next.js dev server:
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command8 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/add.ts
|
|
7
7
|
import * as p2 from "@clack/prompts";
|
|
@@ -49,16 +49,9 @@ function removeToken() {
|
|
|
49
49
|
delete config.token;
|
|
50
50
|
writeConfig(config);
|
|
51
51
|
}
|
|
52
|
+
var API_URL = process.env.NODE_ENV === "production" ? "https://skillstogether.app" : "http://localhost:3000";
|
|
52
53
|
function getApiUrl() {
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
function isInsecureApiUrl() {
|
|
56
|
-
try {
|
|
57
|
-
const parsed = new URL(getApiUrl());
|
|
58
|
-
return parsed.protocol === "http:" && parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1";
|
|
59
|
-
} catch {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
54
|
+
return API_URL;
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
// src/lib/constants.ts
|
|
@@ -174,20 +167,12 @@ async function fetchWithSizeLimit(url, options = {}) {
|
|
|
174
167
|
}
|
|
175
168
|
|
|
176
169
|
// src/lib/api.ts
|
|
177
|
-
var insecureUrlWarned = false;
|
|
178
|
-
function warnInsecureApiUrlOnce() {
|
|
179
|
-
if (!insecureUrlWarned && isInsecureApiUrl()) {
|
|
180
|
-
insecureUrlWarned = true;
|
|
181
|
-
console.warn("Warning: CLI_API_URL is using HTTP. Use HTTPS in production.");
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
170
|
function wrapFetchError(url, cause) {
|
|
185
171
|
const message = cause instanceof Error ? cause.message : "Unknown network error";
|
|
186
172
|
if (message === "fetch failed" || message.includes("ECONNREFUSED") || message.includes("ENOTFOUND") || message.includes("network")) {
|
|
187
|
-
return new Error(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
);
|
|
173
|
+
return new Error(`Cannot reach API at ${url}.`, {
|
|
174
|
+
cause: cause instanceof Error ? cause : void 0
|
|
175
|
+
});
|
|
191
176
|
}
|
|
192
177
|
return cause instanceof Error ? cause : new Error(String(cause));
|
|
193
178
|
}
|
|
@@ -196,7 +181,6 @@ async function apiGet(path, queryParams) {
|
|
|
196
181
|
if (!token) {
|
|
197
182
|
throw new Error("Not authenticated. Run 'auth login' first.");
|
|
198
183
|
}
|
|
199
|
-
warnInsecureApiUrlOnce();
|
|
200
184
|
const apiUrl = getApiUrl();
|
|
201
185
|
const url = new URL(`${apiUrl}/api${path}`);
|
|
202
186
|
if (queryParams) {
|
|
@@ -230,7 +214,6 @@ async function apiPost(path, body) {
|
|
|
230
214
|
if (!token) {
|
|
231
215
|
throw new Error("Not authenticated. Run 'auth login' first.");
|
|
232
216
|
}
|
|
233
|
-
warnInsecureApiUrlOnce();
|
|
234
217
|
const apiUrl = getApiUrl();
|
|
235
218
|
const url = `${apiUrl}/api${path}`;
|
|
236
219
|
let response;
|
|
@@ -517,23 +500,257 @@ import { basename, join as join3 } from "path";
|
|
|
517
500
|
|
|
518
501
|
// src/lib/agents.ts
|
|
519
502
|
var AGENTS = [
|
|
520
|
-
|
|
521
|
-
{
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
{
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
503
|
+
// A
|
|
504
|
+
{
|
|
505
|
+
id: "adal",
|
|
506
|
+
name: "AdaL",
|
|
507
|
+
dir: ".adal/skills",
|
|
508
|
+
globalDir: "~/.adal/skills"
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: "amp",
|
|
512
|
+
name: "Amp",
|
|
513
|
+
dir: ".agents/skills",
|
|
514
|
+
globalDir: "~/.config/agents/skills"
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
id: "antigravity",
|
|
518
|
+
name: "Antigravity",
|
|
519
|
+
dir: ".agent/skills",
|
|
520
|
+
globalDir: "~/.gemini/antigravity/skills"
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
id: "augment",
|
|
524
|
+
name: "Augment",
|
|
525
|
+
dir: ".augment/rules",
|
|
526
|
+
globalDir: "~/.augment/rules"
|
|
527
|
+
},
|
|
528
|
+
// C
|
|
529
|
+
{
|
|
530
|
+
id: "claude-code",
|
|
531
|
+
name: "Claude Code",
|
|
532
|
+
dir: ".claude/skills",
|
|
533
|
+
globalDir: "~/.claude/skills"
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
id: "cline",
|
|
537
|
+
name: "Cline",
|
|
538
|
+
dir: ".cline/skills",
|
|
539
|
+
globalDir: "~/.cline/skills"
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
id: "codebuddy",
|
|
543
|
+
name: "CodeBuddy",
|
|
544
|
+
dir: ".codebuddy/skills",
|
|
545
|
+
globalDir: "~/.codebuddy/skills"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
id: "codex",
|
|
549
|
+
name: "Codex",
|
|
550
|
+
dir: ".codex/skills",
|
|
551
|
+
globalDir: "~/.codex/skills"
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
id: "command-code",
|
|
555
|
+
name: "Command Code",
|
|
556
|
+
dir: ".commandcode/skills",
|
|
557
|
+
globalDir: "~/.commandcode/skills"
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
id: "continue",
|
|
561
|
+
name: "Continue",
|
|
562
|
+
dir: ".continue/skills",
|
|
563
|
+
globalDir: "~/.continue/skills"
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
id: "crush",
|
|
567
|
+
name: "Crush",
|
|
568
|
+
dir: ".crush/skills",
|
|
569
|
+
globalDir: "~/.config/crush/skills"
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
id: "cursor",
|
|
573
|
+
name: "Cursor",
|
|
574
|
+
dir: ".cursor/skills",
|
|
575
|
+
globalDir: "~/.cursor/skills"
|
|
576
|
+
},
|
|
577
|
+
// D
|
|
578
|
+
{
|
|
579
|
+
id: "droid",
|
|
580
|
+
name: "Droid",
|
|
581
|
+
dir: ".factory/skills",
|
|
582
|
+
globalDir: "~/.factory/skills"
|
|
583
|
+
},
|
|
584
|
+
// G
|
|
585
|
+
{
|
|
586
|
+
id: "gemini-cli",
|
|
587
|
+
name: "Gemini CLI",
|
|
588
|
+
dir: ".gemini/skills",
|
|
589
|
+
globalDir: "~/.gemini/skills"
|
|
590
|
+
},
|
|
531
591
|
{
|
|
532
592
|
id: "github-copilot",
|
|
533
593
|
name: "GitHub Copilot",
|
|
534
|
-
dir: ".github/
|
|
594
|
+
dir: ".github/skills",
|
|
595
|
+
globalDir: "~/.copilot/skills"
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
id: "goose",
|
|
599
|
+
name: "Goose",
|
|
600
|
+
dir: ".goose/skills",
|
|
601
|
+
globalDir: "~/.config/goose/skills"
|
|
602
|
+
},
|
|
603
|
+
// I
|
|
604
|
+
{
|
|
605
|
+
id: "iflow-cli",
|
|
606
|
+
name: "iFlow CLI",
|
|
607
|
+
dir: ".iflow/skills",
|
|
608
|
+
globalDir: "~/.iflow/skills"
|
|
609
|
+
},
|
|
610
|
+
// J
|
|
611
|
+
{
|
|
612
|
+
id: "junie",
|
|
613
|
+
name: "Junie",
|
|
614
|
+
dir: ".junie/skills",
|
|
615
|
+
globalDir: "~/.junie/skills"
|
|
616
|
+
},
|
|
617
|
+
// K
|
|
618
|
+
{
|
|
619
|
+
id: "kilo",
|
|
620
|
+
name: "Kilo Code",
|
|
621
|
+
dir: ".kilocode/skills",
|
|
622
|
+
globalDir: "~/.kilocode/skills"
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
id: "kimi-cli",
|
|
626
|
+
name: "Kimi Code CLI",
|
|
627
|
+
dir: ".agents/skills",
|
|
628
|
+
globalDir: "~/.config/agents/skills"
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
id: "kiro-cli",
|
|
632
|
+
name: "Kiro CLI",
|
|
633
|
+
dir: ".kiro/skills",
|
|
634
|
+
globalDir: "~/.kiro/skills"
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
id: "kode",
|
|
638
|
+
name: "Kode",
|
|
639
|
+
dir: ".kode/skills",
|
|
640
|
+
globalDir: "~/.kode/skills"
|
|
641
|
+
},
|
|
642
|
+
// M
|
|
643
|
+
{
|
|
644
|
+
id: "mcpjam",
|
|
645
|
+
name: "MCPJam",
|
|
646
|
+
dir: ".mcpjam/skills",
|
|
647
|
+
globalDir: "~/.mcpjam/skills"
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
id: "mistral-vibe",
|
|
651
|
+
name: "Mistral Vibe",
|
|
652
|
+
dir: ".vibe/skills",
|
|
653
|
+
globalDir: "~/.vibe/skills"
|
|
654
|
+
},
|
|
655
|
+
{ id: "mux", name: "Mux", dir: ".mux/skills", globalDir: "~/.mux/skills" },
|
|
656
|
+
// N
|
|
657
|
+
{
|
|
658
|
+
id: "neovate",
|
|
659
|
+
name: "Neovate",
|
|
660
|
+
dir: ".neovate/skills",
|
|
661
|
+
globalDir: "~/.neovate/skills"
|
|
662
|
+
},
|
|
663
|
+
// O
|
|
664
|
+
{
|
|
665
|
+
id: "openclaw",
|
|
666
|
+
name: "OpenClaw",
|
|
667
|
+
dir: "skills",
|
|
668
|
+
globalDir: "~/.moltbot/skills"
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
id: "opencode",
|
|
672
|
+
name: "OpenCode",
|
|
673
|
+
dir: ".opencode/skills",
|
|
674
|
+
globalDir: "~/.config/opencode/skills"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
id: "openhands",
|
|
678
|
+
name: "OpenHands",
|
|
679
|
+
dir: ".openhands/skills",
|
|
680
|
+
globalDir: "~/.openhands/skills"
|
|
681
|
+
},
|
|
682
|
+
// P
|
|
683
|
+
{ id: "pi", name: "Pi", dir: ".pi/skills", globalDir: "~/.pi/agent/skills" },
|
|
684
|
+
{
|
|
685
|
+
id: "pochi",
|
|
686
|
+
name: "Pochi",
|
|
687
|
+
dir: ".pochi/skills",
|
|
688
|
+
globalDir: "~/.pochi/skills"
|
|
689
|
+
},
|
|
690
|
+
// Q
|
|
691
|
+
{
|
|
692
|
+
id: "qoder",
|
|
693
|
+
name: "Qoder",
|
|
694
|
+
dir: ".qoder/skills",
|
|
695
|
+
globalDir: "~/.qoder/skills"
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
id: "qwen-code",
|
|
699
|
+
name: "Qwen Code",
|
|
700
|
+
dir: ".qwen/skills",
|
|
701
|
+
globalDir: "~/.qwen/skills"
|
|
702
|
+
},
|
|
703
|
+
// R
|
|
704
|
+
{
|
|
705
|
+
id: "replit",
|
|
706
|
+
name: "Replit",
|
|
707
|
+
dir: ".agents/skills",
|
|
708
|
+
globalDir: null
|
|
709
|
+
// project-only
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
id: "roo",
|
|
713
|
+
name: "Roo Code",
|
|
714
|
+
dir: ".roo/skills",
|
|
715
|
+
globalDir: "~/.roo/skills"
|
|
716
|
+
},
|
|
717
|
+
// T
|
|
718
|
+
{
|
|
719
|
+
id: "trae",
|
|
720
|
+
name: "Trae",
|
|
721
|
+
dir: ".trae/skills",
|
|
722
|
+
globalDir: "~/.trae/skills"
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
id: "trae-cn",
|
|
726
|
+
name: "Trae CN",
|
|
727
|
+
dir: ".trae/skills",
|
|
728
|
+
globalDir: "~/.trae-cn/skills"
|
|
729
|
+
},
|
|
730
|
+
// W
|
|
731
|
+
{
|
|
732
|
+
id: "windsurf",
|
|
733
|
+
name: "Windsurf",
|
|
734
|
+
dir: ".windsurf/skills",
|
|
735
|
+
globalDir: "~/.codeium/windsurf/skills"
|
|
736
|
+
},
|
|
737
|
+
// Z
|
|
738
|
+
{
|
|
739
|
+
id: "zencoder",
|
|
740
|
+
name: "Zencoder",
|
|
741
|
+
dir: ".zencoder/skills",
|
|
742
|
+
globalDir: "~/.zencoder/skills"
|
|
535
743
|
}
|
|
536
744
|
];
|
|
745
|
+
function getAgentsByIds(ids) {
|
|
746
|
+
return AGENTS.filter((agent) => ids.includes(agent.id));
|
|
747
|
+
}
|
|
748
|
+
function expandHomePath(path, homeDir) {
|
|
749
|
+
if (path.startsWith("~/")) {
|
|
750
|
+
return path.replace("~", homeDir);
|
|
751
|
+
}
|
|
752
|
+
return path;
|
|
753
|
+
}
|
|
537
754
|
|
|
538
755
|
// src/lib/frontmatter.ts
|
|
539
756
|
function parseFrontmatter(content) {
|
|
@@ -687,7 +904,7 @@ function scanAgentDirectory(agentDir, agent, scope) {
|
|
|
687
904
|
function scanInstalledSkills(options = {}) {
|
|
688
905
|
const skills = [];
|
|
689
906
|
const projectDir = process.cwd();
|
|
690
|
-
const
|
|
907
|
+
const homeDir = homedir2();
|
|
691
908
|
const agentsToScan = options.agents ? AGENTS.filter((a) => options.agents.includes(a.id)) : AGENTS;
|
|
692
909
|
for (const agent of agentsToScan) {
|
|
693
910
|
if (!options.scope || options.scope === "project") {
|
|
@@ -699,8 +916,8 @@ function scanInstalledSkills(options = {}) {
|
|
|
699
916
|
);
|
|
700
917
|
skills.push(...projectSkills);
|
|
701
918
|
}
|
|
702
|
-
if (!options.scope || options.scope === "global") {
|
|
703
|
-
const globalAgentDir =
|
|
919
|
+
if ((!options.scope || options.scope === "global") && agent.globalDir) {
|
|
920
|
+
const globalAgentDir = expandHomePath(agent.globalDir, homeDir);
|
|
704
921
|
const globalSkills = scanAgentDirectory(globalAgentDir, agent, "global");
|
|
705
922
|
skills.push(...globalSkills);
|
|
706
923
|
}
|
|
@@ -832,7 +1049,19 @@ var SCOPE_CONFIGS = {
|
|
|
832
1049
|
getBaseDir: () => homedir4()
|
|
833
1050
|
}
|
|
834
1051
|
};
|
|
835
|
-
async function selectAgents(skipPrompts) {
|
|
1052
|
+
async function selectAgents(skipPrompts, targetAgents) {
|
|
1053
|
+
if (targetAgents) {
|
|
1054
|
+
const agentIds = targetAgents.split(",").map((id) => id.trim());
|
|
1055
|
+
const agents = getAgentsByIds(agentIds);
|
|
1056
|
+
if (agents.length === 0) {
|
|
1057
|
+
p.log.error(
|
|
1058
|
+
`No valid agents found for: ${agentIds.join(", ")}
|
|
1059
|
+
Available agents: ${AGENTS.map((a) => a.id).join(", ")}`
|
|
1060
|
+
);
|
|
1061
|
+
process.exit(1);
|
|
1062
|
+
}
|
|
1063
|
+
return agents;
|
|
1064
|
+
}
|
|
836
1065
|
if (skipPrompts) {
|
|
837
1066
|
return AGENTS.filter((a) => a.id === "cursor");
|
|
838
1067
|
}
|
|
@@ -984,7 +1213,10 @@ function buildDownloadEvents(allResults, skills, scopeLabel) {
|
|
|
984
1213
|
}
|
|
985
1214
|
return events;
|
|
986
1215
|
}
|
|
987
|
-
var addCommand = new Command("add").description("Install skills from an organization").argument("<target>", "Organization slug or organization/skill slug").option("-d, --dir <path>", "Custom installation directory").option("-f, --force", "Overwrite existing skill files", false).option("-y, --yes", "Skip interactive prompts and install all skills", false).option("--skill <slug>", "Install a specific skill by slug").option("--global", "Install globally (in home directory)", false).
|
|
1216
|
+
var addCommand = new Command("add").description("Install skills from an organization").argument("<target>", "Organization slug or organization/skill slug").option("-d, --dir <path>", "Custom installation directory").option("-f, --force", "Overwrite existing skill files", false).option("-y, --yes", "Skip interactive prompts and install all skills", false).option("--skill <slug>", "Install a specific skill by slug").option("--global", "Install globally (in home directory)", false).option(
|
|
1217
|
+
"--target <agents>",
|
|
1218
|
+
"Comma-separated list of agent IDs to install to (e.g., claude-code,cursor)"
|
|
1219
|
+
).action(
|
|
988
1220
|
async (target, options) => {
|
|
989
1221
|
printBanner();
|
|
990
1222
|
p2.intro(pc3.bgCyan(pc3.black(" npx skillstogether ")));
|
|
@@ -1150,7 +1382,7 @@ async function installOrganizationSkills(organizationSlug, options) {
|
|
|
1150
1382
|
);
|
|
1151
1383
|
}
|
|
1152
1384
|
}
|
|
1153
|
-
const selectedAgents = await selectAgents(options.yes);
|
|
1385
|
+
const selectedAgents = await selectAgents(options.yes, options.target);
|
|
1154
1386
|
if (!options.yes) {
|
|
1155
1387
|
p2.log.step(
|
|
1156
1388
|
`Selected ${pc3.green(selectedAgents.length.toString())} agent${selectedAgents.length > 1 ? "s" : ""}: ${selectedAgents.map((a) => a.name).join(", ")}`
|
|
@@ -1242,7 +1474,7 @@ async function installSingleSkill(organizationSlug, skillSlug, options) {
|
|
|
1242
1474
|
if (skill.description) {
|
|
1243
1475
|
p2.log.info(`Description: ${pc3.dim(skill.description)}`);
|
|
1244
1476
|
}
|
|
1245
|
-
const selectedAgents = await selectAgents(options.yes);
|
|
1477
|
+
const selectedAgents = await selectAgents(options.yes, options.target);
|
|
1246
1478
|
if (!options.yes) {
|
|
1247
1479
|
p2.log.step(
|
|
1248
1480
|
`Selected ${pc3.green(selectedAgents.length.toString())} agent${selectedAgents.length > 1 ? "s" : ""}: ${selectedAgents.map((a) => a.name).join(", ")}`
|
|
@@ -1746,19 +1978,21 @@ var doctorCommand = new Command3("doctor").description("Diagnose and fix common
|
|
|
1746
1978
|
message: `Configured: ${apiUrl}`
|
|
1747
1979
|
});
|
|
1748
1980
|
const projectDir = process.cwd();
|
|
1749
|
-
const
|
|
1981
|
+
const homeDir = homedir5();
|
|
1750
1982
|
let agentDirsFound = 0;
|
|
1751
1983
|
const agentDirDetails = [];
|
|
1752
1984
|
for (const agent of AGENTS) {
|
|
1753
1985
|
const projectPath = join6(projectDir, agent.dir);
|
|
1754
|
-
const globalPath = join6(globalDir, agent.dir);
|
|
1755
1986
|
if (existsSync4(projectPath)) {
|
|
1756
1987
|
agentDirsFound++;
|
|
1757
1988
|
agentDirDetails.push(`${agent.name} (project): ${projectPath}`);
|
|
1758
1989
|
}
|
|
1759
|
-
if (
|
|
1760
|
-
|
|
1761
|
-
|
|
1990
|
+
if (agent.globalDir) {
|
|
1991
|
+
const globalPath = expandHomePath(agent.globalDir, homeDir);
|
|
1992
|
+
if (existsSync4(globalPath)) {
|
|
1993
|
+
agentDirsFound++;
|
|
1994
|
+
agentDirDetails.push(`${agent.name} (global): ${globalPath}`);
|
|
1995
|
+
}
|
|
1762
1996
|
}
|
|
1763
1997
|
}
|
|
1764
1998
|
if (agentDirsFound > 0) {
|
|
@@ -1917,7 +2151,7 @@ function displaySkillsByAgent(skills) {
|
|
|
1917
2151
|
}
|
|
1918
2152
|
}
|
|
1919
2153
|
}
|
|
1920
|
-
var listCommand = new Command4("list").description("List installed skills").option("--global", "Show only globally installed skills").option("--project", "Show only project-installed skills").option("--agent <id>", "Show only skills for a specific agent").option("--by-agent", "Group output by agent instead of organization").
|
|
2154
|
+
var listCommand = new Command4("list").description("List installed skills").option("--global", "Show only globally installed skills").option("--project", "Show only project-installed skills").option("--agent <id>", "Show only skills for a specific agent").option("--by-agent", "Group output by agent instead of organization").action(
|
|
1921
2155
|
async (options) => {
|
|
1922
2156
|
printCompactBanner();
|
|
1923
2157
|
p5.intro(pc6.bgCyan(pc6.black(" Installed Skills ")));
|
|
@@ -1947,26 +2181,6 @@ var listCommand = new Command4("list").description("List installed skills").opti
|
|
|
1947
2181
|
p5.outro(pc6.dim("Done"));
|
|
1948
2182
|
return;
|
|
1949
2183
|
}
|
|
1950
|
-
if (options.json) {
|
|
1951
|
-
console.log(
|
|
1952
|
-
JSON.stringify(
|
|
1953
|
-
skills.map((s2) => ({
|
|
1954
|
-
slug: s2.slug,
|
|
1955
|
-
name: s2.name,
|
|
1956
|
-
organization: s2.organization,
|
|
1957
|
-
description: s2.description,
|
|
1958
|
-
installedAt: s2.installedAt,
|
|
1959
|
-
version: s2.version,
|
|
1960
|
-
path: s2.path,
|
|
1961
|
-
agent: s2.agent.id,
|
|
1962
|
-
scope: s2.scope
|
|
1963
|
-
})),
|
|
1964
|
-
null,
|
|
1965
|
-
2
|
|
1966
|
-
)
|
|
1967
|
-
);
|
|
1968
|
-
return;
|
|
1969
|
-
}
|
|
1970
2184
|
if (options.byAgent) {
|
|
1971
2185
|
displaySkillsByAgent(skills);
|
|
1972
2186
|
} else {
|
|
@@ -2016,7 +2230,7 @@ function groupByOrganization(skills) {
|
|
|
2016
2230
|
}
|
|
2017
2231
|
return groups;
|
|
2018
2232
|
}
|
|
2019
|
-
var statusCommand = new Command5("status").description("Check for skill updates").argument("[org-slug]", "Organization to check (optional)").option("--global", "Check only globally installed skills").option("--project", "Check only project-installed skills").
|
|
2233
|
+
var statusCommand = new Command5("status").description("Check for skill updates").argument("[org-slug]", "Organization to check (optional)").option("--global", "Check only globally installed skills").option("--project", "Check only project-installed skills").action(
|
|
2020
2234
|
async (organizationSlug, options) => {
|
|
2021
2235
|
printCompactBanner();
|
|
2022
2236
|
p6.intro(pc7.bgCyan(pc7.black(" Check for Updates ")));
|
|
@@ -2075,20 +2289,6 @@ var statusCommand = new Command5("status").description("Check for skill updates"
|
|
|
2075
2289
|
const upToDateSkills = allUpdates.flatMap(
|
|
2076
2290
|
(o) => o.updates.filter((u) => !u.hasUpdate)
|
|
2077
2291
|
);
|
|
2078
|
-
if (options.json) {
|
|
2079
|
-
console.log(
|
|
2080
|
-
JSON.stringify(
|
|
2081
|
-
{
|
|
2082
|
-
outdated: outdatedSkills,
|
|
2083
|
-
upToDate: upToDateSkills,
|
|
2084
|
-
errors
|
|
2085
|
-
},
|
|
2086
|
-
null,
|
|
2087
|
-
2
|
|
2088
|
-
)
|
|
2089
|
-
);
|
|
2090
|
-
return;
|
|
2091
|
-
}
|
|
2092
2292
|
if (outdatedSkills.length > 0) {
|
|
2093
2293
|
console.log();
|
|
2094
2294
|
p6.log.warn(
|
|
@@ -2136,226 +2336,16 @@ var statusCommand = new Command5("status").description("Check for skill updates"
|
|
|
2136
2336
|
}
|
|
2137
2337
|
);
|
|
2138
2338
|
|
|
2139
|
-
// src/commands/
|
|
2339
|
+
// src/commands/uninstall.ts
|
|
2140
2340
|
import * as p7 from "@clack/prompts";
|
|
2141
2341
|
import { Command as Command6 } from "commander";
|
|
2142
|
-
import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
2143
|
-
import { homedir as homedir6 } from "os";
|
|
2144
|
-
import { dirname as dirname2, join as join7 } from "path";
|
|
2145
|
-
import pc8 from "picocolors";
|
|
2146
|
-
function getDestinationPath(skill, targetAgent, scope) {
|
|
2147
|
-
const baseDir = scope === "global" ? homedir6() : process.cwd();
|
|
2148
|
-
const folderName = SKILL_FOLDER_PATTERN(skill.organization, skill.slug);
|
|
2149
|
-
return join7(baseDir, targetAgent.dir, folderName, SKILL_FILENAME);
|
|
2150
|
-
}
|
|
2151
|
-
function copySkill(sourcePath, destPath) {
|
|
2152
|
-
try {
|
|
2153
|
-
const destDir = dirname2(destPath);
|
|
2154
|
-
if (!existsSync5(destDir)) {
|
|
2155
|
-
mkdirSync3(destDir, { recursive: true });
|
|
2156
|
-
}
|
|
2157
|
-
copyFileSync(sourcePath, destPath);
|
|
2158
|
-
return { success: true };
|
|
2159
|
-
} catch (error) {
|
|
2160
|
-
return {
|
|
2161
|
-
success: false,
|
|
2162
|
-
error: formatErrorMessage(error)
|
|
2163
|
-
};
|
|
2164
|
-
}
|
|
2165
|
-
}
|
|
2166
|
-
var syncCommand = new Command6("sync").description("Sync skills between agents").option("--from <agent>", "Source agent to sync from").option("--to <agent>", "Target agent to sync to (can be repeated)", []).option("--global", "Sync globally installed skills").option("--project", "Sync project-installed skills").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Show what would be synced without making changes").action(
|
|
2167
|
-
async (options) => {
|
|
2168
|
-
printCompactBanner();
|
|
2169
|
-
p7.intro(pc8.bgCyan(pc8.black(" Sync Skills ")));
|
|
2170
|
-
let scope;
|
|
2171
|
-
if (options.global && !options.project) {
|
|
2172
|
-
scope = "global";
|
|
2173
|
-
} else if (options.project && !options.global) {
|
|
2174
|
-
scope = "project";
|
|
2175
|
-
}
|
|
2176
|
-
let sourceAgentId = options.from;
|
|
2177
|
-
if (!sourceAgentId) {
|
|
2178
|
-
const selected = await p7.select({
|
|
2179
|
-
message: "Select source agent to sync from:",
|
|
2180
|
-
options: AGENTS.map((agent) => ({
|
|
2181
|
-
value: agent.id,
|
|
2182
|
-
label: agent.name,
|
|
2183
|
-
hint: agent.dir
|
|
2184
|
-
}))
|
|
2185
|
-
});
|
|
2186
|
-
if (p7.isCancel(selected)) {
|
|
2187
|
-
p7.cancel("Sync cancelled");
|
|
2188
|
-
process.exit(0);
|
|
2189
|
-
}
|
|
2190
|
-
sourceAgentId = selected;
|
|
2191
|
-
}
|
|
2192
|
-
agentSchema.parse(sourceAgentId);
|
|
2193
|
-
const sourceAgent = AGENTS.find((a) => a.id === sourceAgentId);
|
|
2194
|
-
if (!sourceAgent) {
|
|
2195
|
-
p7.log.error(`Unknown agent: ${sourceAgentId}`);
|
|
2196
|
-
p7.log.info(`Available agents: ${AGENTS.map((a) => a.id).join(", ")}`);
|
|
2197
|
-
p7.outro(pc8.red("Invalid agent"));
|
|
2198
|
-
process.exit(1);
|
|
2199
|
-
}
|
|
2200
|
-
let targetAgentIds = options.to || [];
|
|
2201
|
-
if (targetAgentIds.length === 0) {
|
|
2202
|
-
const selected = await p7.multiselect({
|
|
2203
|
-
message: "Select target agents to sync to:",
|
|
2204
|
-
options: AGENTS.filter((a) => a.id !== sourceAgentId).map((agent) => ({
|
|
2205
|
-
value: agent.id,
|
|
2206
|
-
label: agent.name,
|
|
2207
|
-
hint: agent.dir
|
|
2208
|
-
})),
|
|
2209
|
-
required: true
|
|
2210
|
-
});
|
|
2211
|
-
if (p7.isCancel(selected)) {
|
|
2212
|
-
p7.cancel("Sync cancelled");
|
|
2213
|
-
process.exit(0);
|
|
2214
|
-
}
|
|
2215
|
-
targetAgentIds = selected;
|
|
2216
|
-
}
|
|
2217
|
-
const targetAgents = [];
|
|
2218
|
-
for (const id of targetAgentIds) {
|
|
2219
|
-
agentSchema.parse(id);
|
|
2220
|
-
const agent = AGENTS.find((a) => a.id === id);
|
|
2221
|
-
if (!agent) {
|
|
2222
|
-
p7.log.error(`Unknown agent: ${id}`);
|
|
2223
|
-
p7.log.info(`Available agents: ${AGENTS.map((a) => a.id).join(", ")}`);
|
|
2224
|
-
p7.outro(pc8.red("Invalid agent"));
|
|
2225
|
-
process.exit(1);
|
|
2226
|
-
}
|
|
2227
|
-
if (agent.id === sourceAgentId) {
|
|
2228
|
-
p7.log.warn(`Skipping source agent as target: ${id}`);
|
|
2229
|
-
continue;
|
|
2230
|
-
}
|
|
2231
|
-
targetAgents.push(agent);
|
|
2232
|
-
}
|
|
2233
|
-
if (targetAgents.length === 0) {
|
|
2234
|
-
p7.log.error("No valid target agents selected");
|
|
2235
|
-
p7.outro(pc8.red("No targets"));
|
|
2236
|
-
process.exit(1);
|
|
2237
|
-
}
|
|
2238
|
-
const s = p7.spinner();
|
|
2239
|
-
s.start(`Scanning skills from ${pc8.cyan(sourceAgent.name)}...`);
|
|
2240
|
-
const skills = scanInstalledSkills({
|
|
2241
|
-
agents: [sourceAgentId],
|
|
2242
|
-
scope
|
|
2243
|
-
});
|
|
2244
|
-
if (skills.length === 0) {
|
|
2245
|
-
s.stop(`No skills found in ${pc8.cyan(sourceAgent.name)}`);
|
|
2246
|
-
p7.outro(pc8.yellow("Nothing to sync"));
|
|
2247
|
-
return;
|
|
2248
|
-
}
|
|
2249
|
-
s.stop(
|
|
2250
|
-
`Found ${pc8.green(skills.length.toString())} skill${skills.length !== 1 ? "s" : ""} in ${pc8.cyan(sourceAgent.name)}`
|
|
2251
|
-
);
|
|
2252
|
-
const operations = [];
|
|
2253
|
-
for (const skill of skills) {
|
|
2254
|
-
for (const target of targetAgents) {
|
|
2255
|
-
const destPath = getDestinationPath(skill, target, skill.scope);
|
|
2256
|
-
const exists = existsSync5(destPath);
|
|
2257
|
-
operations.push({
|
|
2258
|
-
skill,
|
|
2259
|
-
target,
|
|
2260
|
-
destPath,
|
|
2261
|
-
exists
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
}
|
|
2265
|
-
console.log();
|
|
2266
|
-
p7.log.info(
|
|
2267
|
-
`Will sync ${pc8.green(skills.length.toString())} skill${skills.length !== 1 ? "s" : ""} to ${pc8.cyan(targetAgents.length.toString())} agent${targetAgents.length !== 1 ? "s" : ""}:`
|
|
2268
|
-
);
|
|
2269
|
-
for (const target of targetAgents) {
|
|
2270
|
-
const targetOps = operations.filter((o) => o.target.id === target.id);
|
|
2271
|
-
const targetNew = targetOps.filter((o) => !o.exists).length;
|
|
2272
|
-
const targetUpdate = targetOps.filter((o) => o.exists).length;
|
|
2273
|
-
console.log(` ${pc8.cyan(target.name)}`);
|
|
2274
|
-
if (targetNew > 0) {
|
|
2275
|
-
console.log(` ${pc8.green(`+ ${targetNew} new`)}`);
|
|
2276
|
-
}
|
|
2277
|
-
if (targetUpdate > 0) {
|
|
2278
|
-
console.log(
|
|
2279
|
-
` ${pc8.yellow(`\u2191 ${targetUpdate} existing (will overwrite)`)}`
|
|
2280
|
-
);
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
console.log();
|
|
2284
|
-
if (options.dryRun) {
|
|
2285
|
-
p7.log.info(pc8.dim("Dry run - no changes made"));
|
|
2286
|
-
if (options.yes || await confirmVerbose()) {
|
|
2287
|
-
for (const op of operations) {
|
|
2288
|
-
const icon = op.exists ? pc8.yellow("\u2191") : pc8.green("+");
|
|
2289
|
-
console.log(
|
|
2290
|
-
` ${icon} ${op.skill.organization}/${op.skill.slug} \u2192 ${op.target.name}`
|
|
2291
|
-
);
|
|
2292
|
-
console.log(` ${pc8.dim(shortenPath(op.destPath))}`);
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
p7.outro(pc8.dim("Done"));
|
|
2296
|
-
return;
|
|
2297
|
-
}
|
|
2298
|
-
if (!options.yes) {
|
|
2299
|
-
const confirmed = await p7.confirm({
|
|
2300
|
-
message: `Sync ${skills.length} skill${skills.length !== 1 ? "s" : ""} to ${targetAgents.length} agent${targetAgents.length !== 1 ? "s" : ""}?`,
|
|
2301
|
-
initialValue: true
|
|
2302
|
-
});
|
|
2303
|
-
if (p7.isCancel(confirmed) || !confirmed) {
|
|
2304
|
-
p7.cancel("Sync cancelled");
|
|
2305
|
-
process.exit(0);
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
const syncSpinner = p7.spinner();
|
|
2309
|
-
syncSpinner.start("Syncing skills...");
|
|
2310
|
-
let synced = 0;
|
|
2311
|
-
let failed = 0;
|
|
2312
|
-
const errors = [];
|
|
2313
|
-
for (const op of operations) {
|
|
2314
|
-
const result = copySkill(op.skill.path, op.destPath);
|
|
2315
|
-
if (result.success) {
|
|
2316
|
-
synced++;
|
|
2317
|
-
} else {
|
|
2318
|
-
failed++;
|
|
2319
|
-
errors.push(
|
|
2320
|
-
`${op.skill.organization}/${op.skill.slug} \u2192 ${op.target.name}: ${result.error}`
|
|
2321
|
-
);
|
|
2322
|
-
}
|
|
2323
|
-
}
|
|
2324
|
-
syncSpinner.stop("Sync complete");
|
|
2325
|
-
if (synced > 0) {
|
|
2326
|
-
p7.log.success(
|
|
2327
|
-
`Synced ${pc8.green(synced.toString())} skill${synced !== 1 ? "s" : ""}`
|
|
2328
|
-
);
|
|
2329
|
-
}
|
|
2330
|
-
if (failed > 0) {
|
|
2331
|
-
p7.log.error(
|
|
2332
|
-
`Failed to sync ${pc8.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
|
|
2333
|
-
);
|
|
2334
|
-
for (const error of errors) {
|
|
2335
|
-
console.log(` ${pc8.red("\u2022")} ${error}`);
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
p7.outro(pc8.dim("Done"));
|
|
2339
|
-
}
|
|
2340
|
-
);
|
|
2341
|
-
async function confirmVerbose() {
|
|
2342
|
-
const showDetails = await p7.confirm({
|
|
2343
|
-
message: "Show detailed operations?",
|
|
2344
|
-
initialValue: false
|
|
2345
|
-
});
|
|
2346
|
-
return !p7.isCancel(showDetails) && showDetails;
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
// src/commands/uninstall.ts
|
|
2350
|
-
import * as p8 from "@clack/prompts";
|
|
2351
|
-
import { Command as Command7 } from "commander";
|
|
2352
2342
|
import { readdirSync as readdirSync2, rmSync, rmdirSync } from "fs";
|
|
2353
|
-
import { dirname as
|
|
2354
|
-
import
|
|
2343
|
+
import { dirname as dirname2 } from "path";
|
|
2344
|
+
import pc8 from "picocolors";
|
|
2355
2345
|
function removeSkill(skill) {
|
|
2356
2346
|
try {
|
|
2357
2347
|
rmSync(skill.path);
|
|
2358
|
-
const orgDir =
|
|
2348
|
+
const orgDir = dirname2(skill.path);
|
|
2359
2349
|
try {
|
|
2360
2350
|
const remaining = readdirSync2(orgDir);
|
|
2361
2351
|
if (remaining.length === 0) {
|
|
@@ -2371,10 +2361,10 @@ function removeSkill(skill) {
|
|
|
2371
2361
|
};
|
|
2372
2362
|
}
|
|
2373
2363
|
}
|
|
2374
|
-
var uninstallCommand = new
|
|
2364
|
+
var uninstallCommand = new Command6("uninstall").description("Remove installed skills").argument("<target>", "Organization slug or organization/skill slug").option("--all", "Remove all skills from the organization").option("--global", "Remove from global installation only").option("--project", "Remove from project installation only").option("-y, --yes", "Skip confirmation prompts").action(
|
|
2375
2365
|
async (target, options) => {
|
|
2376
2366
|
printCompactBanner();
|
|
2377
|
-
|
|
2367
|
+
p7.intro(pc8.bgCyan(pc8.black(" Uninstall Skills ")));
|
|
2378
2368
|
let scope;
|
|
2379
2369
|
if (options.global && !options.project) {
|
|
2380
2370
|
scope = "global";
|
|
@@ -2386,19 +2376,19 @@ var uninstallCommand = new Command7("uninstall").description("Remove installed s
|
|
|
2386
2376
|
parsed = parseUninstallTarget(target);
|
|
2387
2377
|
} catch (err) {
|
|
2388
2378
|
const msg = err instanceof Error && "message" in err ? err.message : "Invalid target format";
|
|
2389
|
-
|
|
2390
|
-
|
|
2379
|
+
p7.log.error(msg);
|
|
2380
|
+
p7.outro(pc8.red("Invalid format"));
|
|
2391
2381
|
process.exit(1);
|
|
2392
2382
|
}
|
|
2393
2383
|
if (parsed.skillSlug === void 0) {
|
|
2394
2384
|
if (!options.all) {
|
|
2395
|
-
|
|
2396
|
-
`To uninstall all skills from ${
|
|
2385
|
+
p7.log.error(
|
|
2386
|
+
`To uninstall all skills from ${pc8.cyan(parsed.organizationSlug)}, use the ${pc8.cyan("--all")} flag`
|
|
2397
2387
|
);
|
|
2398
|
-
|
|
2399
|
-
`Or specify a skill: ${
|
|
2388
|
+
p7.log.info(
|
|
2389
|
+
`Or specify a skill: ${pc8.cyan(`npx skillstogether uninstall ${parsed.organizationSlug}/<skill-slug>`)}`
|
|
2400
2390
|
);
|
|
2401
|
-
|
|
2391
|
+
p7.outro(pc8.red("Aborted"));
|
|
2402
2392
|
process.exit(1);
|
|
2403
2393
|
}
|
|
2404
2394
|
await uninstallOrganization(parsed.organizationSlug, scope, options.yes);
|
|
@@ -2413,37 +2403,37 @@ var uninstallCommand = new Command7("uninstall").description("Remove installed s
|
|
|
2413
2403
|
}
|
|
2414
2404
|
);
|
|
2415
2405
|
async function uninstallOrganization(organizationSlug, scope, skipConfirm) {
|
|
2416
|
-
const s =
|
|
2417
|
-
s.start(`Finding skills from ${
|
|
2406
|
+
const s = p7.spinner();
|
|
2407
|
+
s.start(`Finding skills from ${pc8.cyan(organizationSlug)}...`);
|
|
2418
2408
|
const skills = scanInstalledSkills({ organization: organizationSlug, scope });
|
|
2419
2409
|
if (skills.length === 0) {
|
|
2420
|
-
s.stop(`No skills found from ${
|
|
2421
|
-
|
|
2410
|
+
s.stop(`No skills found from ${pc8.cyan(organizationSlug)}`);
|
|
2411
|
+
p7.outro(pc8.yellow("Nothing to uninstall"));
|
|
2422
2412
|
return;
|
|
2423
2413
|
}
|
|
2424
2414
|
s.stop(
|
|
2425
|
-
`Found ${
|
|
2415
|
+
`Found ${pc8.green(skills.length.toString())} skill${skills.length !== 1 ? "s" : ""} from ${pc8.cyan(organizationSlug)}`
|
|
2426
2416
|
);
|
|
2427
2417
|
console.log();
|
|
2428
|
-
|
|
2418
|
+
p7.log.info("Skills to remove:");
|
|
2429
2419
|
for (const skill of skills) {
|
|
2430
|
-
const scopeBadge = skill.scope === "global" ?
|
|
2420
|
+
const scopeBadge = skill.scope === "global" ? pc8.yellow("(global)") : pc8.dim("(project)");
|
|
2431
2421
|
console.log(
|
|
2432
|
-
` ${
|
|
2422
|
+
` ${pc8.red("\u2022")} ${skill.name} ${pc8.dim(`[${skill.agent.name}]`)} ${scopeBadge}`
|
|
2433
2423
|
);
|
|
2434
2424
|
}
|
|
2435
2425
|
console.log();
|
|
2436
2426
|
if (!skipConfirm) {
|
|
2437
|
-
const confirmed = await
|
|
2427
|
+
const confirmed = await p7.confirm({
|
|
2438
2428
|
message: `Remove all ${skills.length} skill${skills.length !== 1 ? "s" : ""} from ${organizationSlug}?`,
|
|
2439
2429
|
initialValue: false
|
|
2440
2430
|
});
|
|
2441
|
-
if (
|
|
2442
|
-
|
|
2431
|
+
if (p7.isCancel(confirmed) || !confirmed) {
|
|
2432
|
+
p7.cancel("Uninstall cancelled");
|
|
2443
2433
|
process.exit(0);
|
|
2444
2434
|
}
|
|
2445
2435
|
}
|
|
2446
|
-
const removeSpinner =
|
|
2436
|
+
const removeSpinner = p7.spinner();
|
|
2447
2437
|
removeSpinner.start("Removing skills...");
|
|
2448
2438
|
let removed = 0;
|
|
2449
2439
|
let failed = 0;
|
|
@@ -2459,53 +2449,53 @@ async function uninstallOrganization(organizationSlug, scope, skipConfirm) {
|
|
|
2459
2449
|
}
|
|
2460
2450
|
removeSpinner.stop("Removal complete");
|
|
2461
2451
|
if (removed > 0) {
|
|
2462
|
-
|
|
2463
|
-
`Removed ${
|
|
2452
|
+
p7.log.success(
|
|
2453
|
+
`Removed ${pc8.green(removed.toString())} skill${removed !== 1 ? "s" : ""}`
|
|
2464
2454
|
);
|
|
2465
2455
|
}
|
|
2466
2456
|
if (failed > 0) {
|
|
2467
|
-
|
|
2468
|
-
`Failed to remove ${
|
|
2457
|
+
p7.log.error(
|
|
2458
|
+
`Failed to remove ${pc8.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
|
|
2469
2459
|
);
|
|
2470
2460
|
for (const error of errors) {
|
|
2471
|
-
|
|
2461
|
+
p7.log.error(pc8.dim(` ${error}`));
|
|
2472
2462
|
}
|
|
2473
2463
|
}
|
|
2474
|
-
|
|
2464
|
+
p7.outro(pc8.dim("Done"));
|
|
2475
2465
|
}
|
|
2476
2466
|
async function uninstallSkill(organizationSlug, skillSlug, scope, skipConfirm) {
|
|
2477
|
-
const s =
|
|
2478
|
-
s.start(`Finding ${
|
|
2467
|
+
const s = p7.spinner();
|
|
2468
|
+
s.start(`Finding ${pc8.cyan(`${organizationSlug}/${skillSlug}`)}...`);
|
|
2479
2469
|
const instances = findSkillInstances(organizationSlug, skillSlug, { scope });
|
|
2480
2470
|
if (instances.length === 0) {
|
|
2481
|
-
s.stop(`Skill ${
|
|
2482
|
-
|
|
2471
|
+
s.stop(`Skill ${pc8.cyan(`${organizationSlug}/${skillSlug}`)} not found`);
|
|
2472
|
+
p7.outro(pc8.yellow("Nothing to uninstall"));
|
|
2483
2473
|
return;
|
|
2484
2474
|
}
|
|
2485
2475
|
s.stop(
|
|
2486
|
-
`Found ${
|
|
2476
|
+
`Found ${pc8.green(instances.length.toString())} instance${instances.length !== 1 ? "s" : ""} of ${pc8.cyan(`${organizationSlug}/${skillSlug}`)}`
|
|
2487
2477
|
);
|
|
2488
2478
|
console.log();
|
|
2489
|
-
|
|
2479
|
+
p7.log.info("Instances to remove:");
|
|
2490
2480
|
for (const skill of instances) {
|
|
2491
|
-
const scopeBadge = skill.scope === "global" ?
|
|
2481
|
+
const scopeBadge = skill.scope === "global" ? pc8.yellow("(global)") : pc8.dim("(project)");
|
|
2492
2482
|
console.log(
|
|
2493
|
-
` ${
|
|
2483
|
+
` ${pc8.red("\u2022")} ${pc8.dim(`[${skill.agent.name}]`)} ${scopeBadge}`
|
|
2494
2484
|
);
|
|
2495
|
-
console.log(` ${
|
|
2485
|
+
console.log(` ${pc8.dim(shortenPath(skill.path))}`);
|
|
2496
2486
|
}
|
|
2497
2487
|
console.log();
|
|
2498
2488
|
if (!skipConfirm) {
|
|
2499
|
-
const confirmed = await
|
|
2489
|
+
const confirmed = await p7.confirm({
|
|
2500
2490
|
message: `Remove ${instances.length} instance${instances.length !== 1 ? "s" : ""} of ${organizationSlug}/${skillSlug}?`,
|
|
2501
2491
|
initialValue: false
|
|
2502
2492
|
});
|
|
2503
|
-
if (
|
|
2504
|
-
|
|
2493
|
+
if (p7.isCancel(confirmed) || !confirmed) {
|
|
2494
|
+
p7.cancel("Uninstall cancelled");
|
|
2505
2495
|
process.exit(0);
|
|
2506
2496
|
}
|
|
2507
2497
|
}
|
|
2508
|
-
const removeSpinner =
|
|
2498
|
+
const removeSpinner = p7.spinner();
|
|
2509
2499
|
removeSpinner.start("Removing skill...");
|
|
2510
2500
|
let removed = 0;
|
|
2511
2501
|
let failed = 0;
|
|
@@ -2521,26 +2511,26 @@ async function uninstallSkill(organizationSlug, skillSlug, scope, skipConfirm) {
|
|
|
2521
2511
|
}
|
|
2522
2512
|
removeSpinner.stop("Removal complete");
|
|
2523
2513
|
if (removed > 0) {
|
|
2524
|
-
|
|
2525
|
-
`Removed ${
|
|
2514
|
+
p7.log.success(
|
|
2515
|
+
`Removed ${pc8.green(removed.toString())} instance${removed !== 1 ? "s" : ""}`
|
|
2526
2516
|
);
|
|
2527
2517
|
}
|
|
2528
2518
|
if (failed > 0) {
|
|
2529
|
-
|
|
2530
|
-
`Failed to remove ${
|
|
2519
|
+
p7.log.error(
|
|
2520
|
+
`Failed to remove ${pc8.red(failed.toString())} instance${failed !== 1 ? "s" : ""}`
|
|
2531
2521
|
);
|
|
2532
2522
|
for (const error of errors) {
|
|
2533
|
-
|
|
2523
|
+
p7.log.error(pc8.dim(` ${error}`));
|
|
2534
2524
|
}
|
|
2535
2525
|
}
|
|
2536
|
-
|
|
2526
|
+
p7.outro(pc8.dim("Done"));
|
|
2537
2527
|
}
|
|
2538
2528
|
|
|
2539
2529
|
// src/commands/update.ts
|
|
2540
|
-
import * as
|
|
2541
|
-
import { Command as
|
|
2530
|
+
import * as p8 from "@clack/prompts";
|
|
2531
|
+
import { Command as Command7 } from "commander";
|
|
2542
2532
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
2543
|
-
import
|
|
2533
|
+
import pc9 from "picocolors";
|
|
2544
2534
|
function generateUpdatedContent(skill, organizationSlug) {
|
|
2545
2535
|
const frontmatter = generateFrontmatter({
|
|
2546
2536
|
name: skill.name,
|
|
@@ -2552,16 +2542,16 @@ function generateUpdatedContent(skill, organizationSlug) {
|
|
|
2552
2542
|
});
|
|
2553
2543
|
return frontmatter + "\n" + (skill.content || "");
|
|
2554
2544
|
}
|
|
2555
|
-
var updateCommand = new
|
|
2545
|
+
var updateCommand = new Command7("update").description("Update installed skills to latest version").argument("[target]", "Organization slug or organization/skill slug").option("--global", "Update only globally installed skills").option("--project", "Update only project-installed skills").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Show what would be updated without making changes").action(
|
|
2556
2546
|
async (target, options) => {
|
|
2557
2547
|
printCompactBanner();
|
|
2558
|
-
|
|
2548
|
+
p8.intro(pc9.bgCyan(pc9.black(" Update Skills ")));
|
|
2559
2549
|
const token = getToken();
|
|
2560
2550
|
if (!token) {
|
|
2561
|
-
|
|
2562
|
-
`Not authenticated. Run ${
|
|
2551
|
+
p8.log.error(
|
|
2552
|
+
`Not authenticated. Run ${pc9.cyan("npx skillstogether auth login")} first.`
|
|
2563
2553
|
);
|
|
2564
|
-
|
|
2554
|
+
p8.outro(pc9.red("Authentication required"));
|
|
2565
2555
|
process.exit(1);
|
|
2566
2556
|
}
|
|
2567
2557
|
let scope;
|
|
@@ -2579,12 +2569,12 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2579
2569
|
skillSlug = parsed.skillSlug;
|
|
2580
2570
|
} catch (err) {
|
|
2581
2571
|
const msg = err instanceof Error && "message" in err ? err.message : "Invalid target format";
|
|
2582
|
-
|
|
2583
|
-
|
|
2572
|
+
p8.log.error(msg);
|
|
2573
|
+
p8.outro(pc9.red("Invalid format"));
|
|
2584
2574
|
process.exit(1);
|
|
2585
2575
|
}
|
|
2586
2576
|
}
|
|
2587
|
-
const s =
|
|
2577
|
+
const s = p8.spinner();
|
|
2588
2578
|
s.start("Scanning installed skills...");
|
|
2589
2579
|
const allInstalledSkills = scanInstalledSkills({
|
|
2590
2580
|
scope,
|
|
@@ -2596,15 +2586,15 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2596
2586
|
}
|
|
2597
2587
|
if (skillsToCheck.length === 0) {
|
|
2598
2588
|
s.stop("No installed skills found");
|
|
2599
|
-
|
|
2600
|
-
|
|
2589
|
+
p8.log.info(
|
|
2590
|
+
pc9.dim("Install skills with: npx skillstogether add <org-slug>")
|
|
2601
2591
|
);
|
|
2602
|
-
|
|
2592
|
+
p8.outro(pc9.dim("Done"));
|
|
2603
2593
|
return;
|
|
2604
2594
|
}
|
|
2605
2595
|
const uniqueSkills = deduplicateSkills(skillsToCheck);
|
|
2606
2596
|
s.stop(
|
|
2607
|
-
`Found ${
|
|
2597
|
+
`Found ${pc9.green(uniqueSkills.length.toString())} installed skill${uniqueSkills.length !== 1 ? "s" : ""}`
|
|
2608
2598
|
);
|
|
2609
2599
|
const byOrg = /* @__PURE__ */ new Map();
|
|
2610
2600
|
for (const skill of uniqueSkills) {
|
|
@@ -2612,7 +2602,7 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2612
2602
|
existing.push(skill);
|
|
2613
2603
|
byOrg.set(skill.organization, existing);
|
|
2614
2604
|
}
|
|
2615
|
-
const checkSpinner =
|
|
2605
|
+
const checkSpinner = p8.spinner();
|
|
2616
2606
|
checkSpinner.start("Checking for updates...");
|
|
2617
2607
|
const skillsToUpdate = [];
|
|
2618
2608
|
const errors = [];
|
|
@@ -2641,17 +2631,17 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2641
2631
|
}
|
|
2642
2632
|
checkSpinner.stop("Update check complete");
|
|
2643
2633
|
if (skillsToUpdate.length === 0) {
|
|
2644
|
-
|
|
2634
|
+
p8.log.success("All skills are up to date!");
|
|
2645
2635
|
if (errors.length > 0) {
|
|
2646
2636
|
console.log();
|
|
2647
|
-
|
|
2637
|
+
p8.log.error(
|
|
2648
2638
|
`Failed to check ${errors.length} organization${errors.length !== 1 ? "s" : ""}:`
|
|
2649
2639
|
);
|
|
2650
2640
|
for (const error of errors) {
|
|
2651
|
-
console.log(` ${
|
|
2641
|
+
console.log(` ${pc9.red("\u2022")} ${error}`);
|
|
2652
2642
|
}
|
|
2653
2643
|
}
|
|
2654
|
-
|
|
2644
|
+
p8.outro(pc9.dim("Done"));
|
|
2655
2645
|
return;
|
|
2656
2646
|
}
|
|
2657
2647
|
const totalInstances = skillsToUpdate.reduce(
|
|
@@ -2659,33 +2649,33 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2659
2649
|
0
|
|
2660
2650
|
);
|
|
2661
2651
|
console.log();
|
|
2662
|
-
const updateMsg = skillsToUpdate.length === totalInstances ? `${
|
|
2663
|
-
|
|
2652
|
+
const updateMsg = skillsToUpdate.length === totalInstances ? `${pc9.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} will be updated:` : `${pc9.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalInstances} installations) will be updated:`;
|
|
2653
|
+
p8.log.info(updateMsg);
|
|
2664
2654
|
for (const { unique, remoteVersion } of skillsToUpdate) {
|
|
2665
2655
|
const agentNames = unique.agents.map((a) => a.name).join(", ");
|
|
2666
|
-
const scopeBadge = unique.scope === "global" ?
|
|
2656
|
+
const scopeBadge = unique.scope === "global" ? pc9.yellow("(global)") : pc9.dim("(project)");
|
|
2667
2657
|
console.log(
|
|
2668
|
-
` ${
|
|
2658
|
+
` ${pc9.yellow("\u2191")} ${pc9.white(`${unique.organization}/${unique.slug}`)} ${pc9.dim(`v${unique.version || "?"}`)} \u2192 ${pc9.green(`v${remoteVersion}`)} ${pc9.dim(`[${agentNames}]`)} ${scopeBadge}`
|
|
2669
2659
|
);
|
|
2670
2660
|
}
|
|
2671
2661
|
console.log();
|
|
2672
2662
|
if (options.dryRun) {
|
|
2673
|
-
|
|
2674
|
-
|
|
2663
|
+
p8.log.info(pc9.dim("Dry run - no changes made"));
|
|
2664
|
+
p8.outro(pc9.dim("Done"));
|
|
2675
2665
|
return;
|
|
2676
2666
|
}
|
|
2677
2667
|
if (!options.yes) {
|
|
2678
2668
|
const confirmMsg = skillsToUpdate.length === totalInstances ? `Update ${skillsToUpdate.length} skill${skillsToUpdate.length !== 1 ? "s" : ""}?` : `Update ${skillsToUpdate.length} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalInstances} installations)?`;
|
|
2679
|
-
const confirmed = await
|
|
2669
|
+
const confirmed = await p8.confirm({
|
|
2680
2670
|
message: confirmMsg,
|
|
2681
2671
|
initialValue: true
|
|
2682
2672
|
});
|
|
2683
|
-
if (
|
|
2684
|
-
|
|
2673
|
+
if (p8.isCancel(confirmed) || !confirmed) {
|
|
2674
|
+
p8.cancel("Update cancelled");
|
|
2685
2675
|
process.exit(0);
|
|
2686
2676
|
}
|
|
2687
2677
|
}
|
|
2688
|
-
const updateSpinner =
|
|
2678
|
+
const updateSpinner = p8.spinner();
|
|
2689
2679
|
updateSpinner.start("Updating skills...");
|
|
2690
2680
|
let updatedSkills = 0;
|
|
2691
2681
|
let updatedInstances = 0;
|
|
@@ -2709,23 +2699,23 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2709
2699
|
}
|
|
2710
2700
|
updateSpinner.stop("Update complete");
|
|
2711
2701
|
if (updatedSkills > 0) {
|
|
2712
|
-
const summaryMsg = updatedSkills === updatedInstances ? `Updated ${
|
|
2713
|
-
|
|
2702
|
+
const summaryMsg = updatedSkills === updatedInstances ? `Updated ${pc9.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""}` : `Updated ${pc9.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""} (${updatedInstances} installations)`;
|
|
2703
|
+
p8.log.success(summaryMsg);
|
|
2714
2704
|
}
|
|
2715
2705
|
if (failed > 0) {
|
|
2716
|
-
|
|
2717
|
-
`Failed to update ${
|
|
2706
|
+
p8.log.error(
|
|
2707
|
+
`Failed to update ${pc9.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
|
|
2718
2708
|
);
|
|
2719
2709
|
for (const error of updateErrors) {
|
|
2720
|
-
console.log(` ${
|
|
2710
|
+
console.log(` ${pc9.red("\u2022")} ${error}`);
|
|
2721
2711
|
}
|
|
2722
2712
|
}
|
|
2723
|
-
|
|
2713
|
+
p8.outro(pc9.dim("Done"));
|
|
2724
2714
|
}
|
|
2725
2715
|
);
|
|
2726
2716
|
|
|
2727
2717
|
// src/index.ts
|
|
2728
|
-
var program = new
|
|
2718
|
+
var program = new Command8();
|
|
2729
2719
|
program.name("skillstogether").description("CLI tool to install organization skills").version("0.1.0").hook("preAction", (thisCommand) => {
|
|
2730
2720
|
const commandName = thisCommand.name();
|
|
2731
2721
|
if (commandName === "skillstogether") {
|
|
@@ -2743,7 +2733,6 @@ program.addCommand(addCommand);
|
|
|
2743
2733
|
program.addCommand(doctorCommand);
|
|
2744
2734
|
program.addCommand(listCommand);
|
|
2745
2735
|
program.addCommand(statusCommand);
|
|
2746
|
-
program.addCommand(syncCommand);
|
|
2747
2736
|
program.addCommand(uninstallCommand);
|
|
2748
2737
|
program.addCommand(updateCommand);
|
|
2749
2738
|
program.parse();
|