@safeskill/cli 0.2.0 → 0.2.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/CHANGELOG.md +10 -0
- package/README.md +56 -43
- package/dist/cli.mjs +136 -27
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.2
|
|
4
|
+
|
|
5
|
+
- Added cross-region hub resolve fallback when the selected SafeSkill hub returns a server error.
|
|
6
|
+
|
|
7
|
+
## 0.2.1
|
|
8
|
+
|
|
9
|
+
- Added Flocks agent support with `.flocks/plugins/skills` install paths.
|
|
10
|
+
- Added hub resolve fallback for new or unsupported agent-specific resolve requests.
|
|
11
|
+
- Fixed zip artifact extraction when packages contain explicit directory entries.
|
|
12
|
+
|
|
3
13
|
## 0.0.1
|
|
4
14
|
|
|
5
15
|
- Renamed the published package and CLI command from `skills` to `safeskill`.
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ The SafeSkill CLI for the open agent skills ecosystem.
|
|
|
6
6
|
|
|
7
7
|
<!-- agent-list:start -->
|
|
8
8
|
|
|
9
|
-
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [
|
|
9
|
+
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [41 more](#available-agents).
|
|
10
10
|
|
|
11
11
|
<!-- agent-list:end -->
|
|
12
12
|
|
|
@@ -76,9 +76,18 @@ npx @safeskill/cli add safeskill://official/acme/code-review@1.2.0
|
|
|
76
76
|
| `-y, --yes` | Skip all confirmation prompts |
|
|
77
77
|
| `--all` | Install all skills to all agents without prompts |
|
|
78
78
|
|
|
79
|
+
### Global Options
|
|
80
|
+
|
|
81
|
+
| Option | Description |
|
|
82
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
83
|
+
| `--region <cn|global>` | Use a specific SafeSkill service region for this run. Overrides `SAFESKILL_REGION`; otherwise auto-detected. |
|
|
84
|
+
|
|
79
85
|
### Examples
|
|
80
86
|
|
|
81
87
|
```bash
|
|
88
|
+
# Force the China service region for this run
|
|
89
|
+
npx @safeskill/cli --region cn add safeskill://official/acme/code-review
|
|
90
|
+
|
|
82
91
|
# List skills in a repository
|
|
83
92
|
npx @safeskill/cli add example-org/agent-skills --list
|
|
84
93
|
|
|
@@ -238,48 +247,49 @@ Skills can be installed to any of these agents:
|
|
|
238
247
|
|
|
239
248
|
<!-- supported-agents:start -->
|
|
240
249
|
|
|
241
|
-
| Agent | `--agent` | Project Path
|
|
242
|
-
| ------------------------------------- | ---------------------------------------- |
|
|
243
|
-
| Amp, Kimi Code CLI, Replit, Universal | `amp`, `kimi-cli`, `replit`, `universal` | `.agents/skills/`
|
|
244
|
-
| Antigravity | `antigravity` | `.agents/skills/`
|
|
245
|
-
| Augment | `augment` | `.augment/skills/`
|
|
246
|
-
| Claude Code | `claude-code` | `.claude/skills/`
|
|
247
|
-
| OpenClaw | `openclaw` | `skills/`
|
|
248
|
-
| Cline, Warp | `cline`, `warp` | `.agents/skills/`
|
|
249
|
-
| CodeBuddy | `codebuddy` | `.codebuddy/skills/`
|
|
250
|
-
| Codex | `codex` | `.agents/skills/`
|
|
251
|
-
| Command Code | `command-code` | `.commandcode/skills/`
|
|
252
|
-
| Continue | `continue` | `.continue/skills/`
|
|
253
|
-
| Cortex Code | `cortex` | `.cortex/skills/`
|
|
254
|
-
| Crush | `crush` | `.crush/skills/`
|
|
255
|
-
| Cursor | `cursor` | `.agents/skills/`
|
|
256
|
-
| Deep Agents | `deepagents` | `.agents/skills/`
|
|
257
|
-
| Droid | `droid` | `.factory/skills/`
|
|
258
|
-
| Firebender | `firebender` | `.agents/skills/`
|
|
259
|
-
|
|
|
260
|
-
|
|
|
261
|
-
|
|
|
262
|
-
|
|
|
263
|
-
|
|
|
264
|
-
|
|
|
265
|
-
|
|
|
266
|
-
|
|
|
267
|
-
|
|
|
268
|
-
|
|
|
269
|
-
|
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
|
|
|
273
|
-
|
|
|
274
|
-
|
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
| Trae
|
|
278
|
-
|
|
|
279
|
-
|
|
|
280
|
-
|
|
|
281
|
-
|
|
|
282
|
-
|
|
|
250
|
+
| Agent | `--agent` | Project Path | Global Path |
|
|
251
|
+
| ------------------------------------- | ---------------------------------------- | ------------------------- | ---------------------------------- |
|
|
252
|
+
| Amp, Kimi Code CLI, Replit, Universal | `amp`, `kimi-cli`, `replit`, `universal` | `.agents/skills/` | `~/.config/agents/skills/` |
|
|
253
|
+
| Antigravity | `antigravity` | `.agents/skills/` | `~/.gemini/antigravity/skills/` |
|
|
254
|
+
| Augment | `augment` | `.augment/skills/` | `~/.augment/skills/` |
|
|
255
|
+
| Claude Code | `claude-code` | `.claude/skills/` | `~/.claude/skills/` |
|
|
256
|
+
| OpenClaw | `openclaw` | `skills/` | `~/.openclaw/skills/` |
|
|
257
|
+
| Cline, Warp | `cline`, `warp` | `.agents/skills/` | `~/.agents/skills/` |
|
|
258
|
+
| CodeBuddy | `codebuddy` | `.codebuddy/skills/` | `~/.codebuddy/skills/` |
|
|
259
|
+
| Codex | `codex` | `.agents/skills/` | `~/.codex/skills/` |
|
|
260
|
+
| Command Code | `command-code` | `.commandcode/skills/` | `~/.commandcode/skills/` |
|
|
261
|
+
| Continue | `continue` | `.continue/skills/` | `~/.continue/skills/` |
|
|
262
|
+
| Cortex Code | `cortex` | `.cortex/skills/` | `~/.snowflake/cortex/skills/` |
|
|
263
|
+
| Crush | `crush` | `.crush/skills/` | `~/.config/crush/skills/` |
|
|
264
|
+
| Cursor | `cursor` | `.agents/skills/` | `~/.cursor/skills/` |
|
|
265
|
+
| Deep Agents | `deepagents` | `.agents/skills/` | `~/.deepagents/agent/skills/` |
|
|
266
|
+
| Droid | `droid` | `.factory/skills/` | `~/.factory/skills/` |
|
|
267
|
+
| Firebender | `firebender` | `.agents/skills/` | `~/.firebender/skills/` |
|
|
268
|
+
| Flocks | `flocks` | `.flocks/plugins/skills/` | `~/.flocks/plugins/skills/` |
|
|
269
|
+
| Gemini CLI | `gemini-cli` | `.agents/skills/` | `~/.gemini/skills/` |
|
|
270
|
+
| GitHub Copilot | `github-copilot` | `.agents/skills/` | `~/.copilot/skills/` |
|
|
271
|
+
| Goose | `goose` | `.goose/skills/` | `~/.config/goose/skills/` |
|
|
272
|
+
| Junie | `junie` | `.junie/skills/` | `~/.junie/skills/` |
|
|
273
|
+
| iFlow CLI | `iflow-cli` | `.iflow/skills/` | `~/.iflow/skills/` |
|
|
274
|
+
| Kilo Code | `kilo` | `.kilocode/skills/` | `~/.kilocode/skills/` |
|
|
275
|
+
| Kiro CLI | `kiro-cli` | `.kiro/skills/` | `~/.kiro/skills/` |
|
|
276
|
+
| Kode | `kode` | `.kode/skills/` | `~/.kode/skills/` |
|
|
277
|
+
| MCPJam | `mcpjam` | `.mcpjam/skills/` | `~/.mcpjam/skills/` |
|
|
278
|
+
| Mistral Vibe | `mistral-vibe` | `.vibe/skills/` | `~/.vibe/skills/` |
|
|
279
|
+
| Mux | `mux` | `.mux/skills/` | `~/.mux/skills/` |
|
|
280
|
+
| OpenCode | `opencode` | `.agents/skills/` | `~/.config/opencode/skills/` |
|
|
281
|
+
| OpenHands | `openhands` | `.openhands/skills/` | `~/.openhands/skills/` |
|
|
282
|
+
| Pi | `pi` | `.pi/skills/` | `~/.pi/agent/skills/` |
|
|
283
|
+
| Qoder | `qoder` | `.qoder/skills/` | `~/.qoder/skills/` |
|
|
284
|
+
| Qwen Code | `qwen-code` | `.qwen/skills/` | `~/.qwen/skills/` |
|
|
285
|
+
| Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
|
|
286
|
+
| Trae | `trae` | `.trae/skills/` | `~/.trae/skills/` |
|
|
287
|
+
| Trae CN | `trae-cn` | `.trae/skills/` | `~/.trae-cn/skills/` |
|
|
288
|
+
| Windsurf | `windsurf` | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
|
|
289
|
+
| Zencoder | `zencoder` | `.zencoder/skills/` | `~/.zencoder/skills/` |
|
|
290
|
+
| Neovate | `neovate` | `.neovate/skills/` | `~/.neovate/skills/` |
|
|
291
|
+
| Pochi | `pochi` | `.pochi/skills/` | `~/.pochi/skills/` |
|
|
292
|
+
| AdaL | `adal` | `.adal/skills/` | `~/.adal/skills/` |
|
|
283
293
|
|
|
284
294
|
<!-- supported-agents:end -->
|
|
285
295
|
|
|
@@ -361,6 +371,7 @@ The CLI searches for skills in these locations within a repository:
|
|
|
361
371
|
- `.cortex/skills/`
|
|
362
372
|
- `.crush/skills/`
|
|
363
373
|
- `.factory/skills/`
|
|
374
|
+
- `.flocks/plugins/skills/`
|
|
364
375
|
- `.goose/skills/`
|
|
365
376
|
- `.junie/skills/`
|
|
366
377
|
- `.iflow/skills/`
|
|
@@ -381,6 +392,7 @@ The CLI searches for skills in these locations within a repository:
|
|
|
381
392
|
- `.neovate/skills/`
|
|
382
393
|
- `.pochi/skills/`
|
|
383
394
|
- `.adal/skills/`
|
|
395
|
+
|
|
384
396
|
<!-- skill-discovery:end -->
|
|
385
397
|
|
|
386
398
|
### Plugin Manifest Discovery
|
|
@@ -438,6 +450,7 @@ Ensure you have write access to the target directory.
|
|
|
438
450
|
| Variable | Description |
|
|
439
451
|
| ------------------------- | -------------------------------------------------------------------------- |
|
|
440
452
|
| `INSTALL_INTERNAL_SKILLS` | Set to `1` or `true` to show and install skills marked as `internal: true` |
|
|
453
|
+
| `SAFESKILL_REGION` | Optional fallback service region (`cn` or `global`) when `--region` is not specified |
|
|
441
454
|
| `DISABLE_TELEMETRY` | Set to disable anonymous usage telemetry |
|
|
442
455
|
| `DO_NOT_TRACK` | Alternative way to disable telemetry |
|
|
443
456
|
|
package/dist/cli.mjs
CHANGED
|
@@ -408,13 +408,18 @@ const STATUS_TIMEOUT_MS = 2500;
|
|
|
408
408
|
const DETECT_TIMEOUT_MS = 1500;
|
|
409
409
|
let resolvedRegionPromise = null;
|
|
410
410
|
let regionAvailabilityCache = /* @__PURE__ */ new Map();
|
|
411
|
-
|
|
411
|
+
let safeSkillRegionOverride = null;
|
|
412
|
+
function normalizeSafeSkillRegion(region) {
|
|
412
413
|
const value = region?.trim().toLowerCase();
|
|
413
414
|
if (!value) return null;
|
|
414
415
|
if (value === "cn" || value === "china") return "cn";
|
|
415
416
|
if (value === "global" || value === "io" || value === "intl" || value === "international") return "global";
|
|
416
417
|
return null;
|
|
417
418
|
}
|
|
419
|
+
function setSafeSkillRegionOverride(region) {
|
|
420
|
+
safeSkillRegionOverride = region;
|
|
421
|
+
resolvedRegionPromise = null;
|
|
422
|
+
}
|
|
418
423
|
function withTimeout(timeoutMs) {
|
|
419
424
|
return AbortSignal.timeout(timeoutMs);
|
|
420
425
|
}
|
|
@@ -496,7 +501,8 @@ async function ensureRegionAvailable(region, hubBaseUrl) {
|
|
|
496
501
|
async function resolveSafeSkillRegion() {
|
|
497
502
|
if (resolvedRegionPromise) return resolvedRegionPromise;
|
|
498
503
|
resolvedRegionPromise = (async () => {
|
|
499
|
-
|
|
504
|
+
if (safeSkillRegionOverride) return safeSkillRegionOverride;
|
|
505
|
+
const configuredRegion = normalizeSafeSkillRegion(process.env.SAFESKILL_REGION);
|
|
500
506
|
if (configuredRegion) return configuredRegion;
|
|
501
507
|
return detectRegionByPublicIP();
|
|
502
508
|
})();
|
|
@@ -530,6 +536,19 @@ function normalizeApiBase(baseUrl) {
|
|
|
530
536
|
function buildApiUrl(baseUrl, path) {
|
|
531
537
|
return `${normalizeApiBase(baseUrl)}${path.startsWith("/") ? path : `/${path}`}`;
|
|
532
538
|
}
|
|
539
|
+
function getAlternateHubBaseUrl(baseUrl) {
|
|
540
|
+
if (process.env.SAFESKILL_HUB_URL) return null;
|
|
541
|
+
const parsed = new URL(baseUrl);
|
|
542
|
+
if (parsed.hostname === "hubapi.safeskill.io") {
|
|
543
|
+
parsed.hostname = "hubapi.safeskill.cn";
|
|
544
|
+
return parsed.toString().replace(/\/$/, "");
|
|
545
|
+
}
|
|
546
|
+
if (parsed.hostname === "hubapi.safeskill.cn") {
|
|
547
|
+
parsed.hostname = "hubapi.safeskill.io";
|
|
548
|
+
return parsed.toString().replace(/\/$/, "");
|
|
549
|
+
}
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
533
552
|
async function readEnvelope(response) {
|
|
534
553
|
const payload = await response.json();
|
|
535
554
|
if (payload && typeof payload === "object" && "data" in payload) return payload.data;
|
|
@@ -607,9 +626,7 @@ async function extractDownloadedArtifact(destination, fileName, bytes) {
|
|
|
607
626
|
import_yauzl.open(tempZipPath, {
|
|
608
627
|
lazyEntries: true,
|
|
609
628
|
strictFileNames: false,
|
|
610
|
-
decodeStrings: true
|
|
611
|
-
encoding,
|
|
612
|
-
validateEntryNames: false
|
|
629
|
+
decodeStrings: true
|
|
613
630
|
}, (err, zipfile) => {
|
|
614
631
|
if (err) {
|
|
615
632
|
reject(err);
|
|
@@ -617,16 +634,22 @@ async function extractDownloadedArtifact(destination, fileName, bytes) {
|
|
|
617
634
|
}
|
|
618
635
|
const processedFiles = /* @__PURE__ */ new Set();
|
|
619
636
|
zipfile.on("entry", (entry) => {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}
|
|
624
|
-
let fileName = entry.fileName;
|
|
625
|
-
fileName = fileName.replace(/[^\w\-._/\\]/g, (char) => {
|
|
637
|
+
let fileName = entry.fileName.replace(/\\/g, "/");
|
|
638
|
+
const isDirectoryEntry = fileName.endsWith("/");
|
|
639
|
+
fileName = fileName.replace(/[^\w\-._/]/g, (char) => {
|
|
626
640
|
const code = char.charCodeAt(0);
|
|
627
641
|
if (code < 32 || code > 126) return "_";
|
|
628
642
|
return char;
|
|
629
643
|
});
|
|
644
|
+
if (isDirectoryEntry) {
|
|
645
|
+
const directoryName = fileName.replace(/\/+$/, "");
|
|
646
|
+
if (!directoryName) {
|
|
647
|
+
zipfile.readEntry();
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
mkdir(join(destination, directoryName), { recursive: true }).then(() => zipfile.readEntry()).catch(reject);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
630
653
|
if (processedFiles.has(fileName)) {
|
|
631
654
|
zipfile.readEntry();
|
|
632
655
|
return;
|
|
@@ -721,20 +744,40 @@ async function searchSkillsCatalog(query, limit = 10) {
|
|
|
721
744
|
}
|
|
722
745
|
async function resolveHubSkill(source, agent) {
|
|
723
746
|
const baseUrl = await getSafeSkillHubBaseUrl();
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
747
|
+
const resolveFromBaseUrl = async (hubBaseUrl) => {
|
|
748
|
+
const resolveUrl = buildApiUrl(hubBaseUrl, "/resolve");
|
|
749
|
+
const resolveWithAgent = agent ? await fetch(resolveUrl, {
|
|
750
|
+
method: "POST",
|
|
751
|
+
headers: getHeaders({ "content-type": "application/json" }),
|
|
752
|
+
body: JSON.stringify({
|
|
753
|
+
source,
|
|
754
|
+
agent
|
|
755
|
+
})
|
|
756
|
+
}) : null;
|
|
757
|
+
return resolveWithAgent && resolveWithAgent.ok ? resolveWithAgent : fetch(resolveUrl, {
|
|
758
|
+
method: "POST",
|
|
759
|
+
headers: getHeaders({ "content-type": "application/json" }),
|
|
760
|
+
body: JSON.stringify({ source })
|
|
761
|
+
});
|
|
762
|
+
};
|
|
763
|
+
let resolvedBaseUrl = baseUrl;
|
|
764
|
+
let response = await resolveFromBaseUrl(baseUrl);
|
|
765
|
+
const alternateBaseUrl = response.status >= 500 ? getAlternateHubBaseUrl(baseUrl) : null;
|
|
766
|
+
if (alternateBaseUrl) {
|
|
767
|
+
const alternateResponse = await resolveFromBaseUrl(alternateBaseUrl);
|
|
768
|
+
if (alternateResponse.ok || !response.ok) {
|
|
769
|
+
response = alternateResponse;
|
|
770
|
+
resolvedBaseUrl = alternateBaseUrl;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
732
773
|
if (!response.ok) throw new Error(`hub resolve failed: ${response.status}`);
|
|
733
|
-
|
|
774
|
+
const resolved = await readEnvelope(response);
|
|
775
|
+
resolved.hubBaseUrl = resolvedBaseUrl;
|
|
776
|
+
return resolved;
|
|
734
777
|
}
|
|
735
778
|
async function downloadHubSource(source, agent) {
|
|
736
|
-
const baseUrl = await getSafeSkillHubBaseUrl();
|
|
737
779
|
const resolved = await resolveHubSkill(source, agent);
|
|
780
|
+
const baseUrl = resolved.hubBaseUrl || await getSafeSkillHubBaseUrl();
|
|
738
781
|
const downloadUrl = resolved.download_uri || (resolved.artifact_digest ? buildApiUrl(baseUrl, `/artifacts/${encodeURIComponent(resolved.artifact_digest)}/download`) : "");
|
|
739
782
|
if (!downloadUrl) throw new Error("hub resolve did not return a downloadable artifact");
|
|
740
783
|
let response;
|
|
@@ -1167,6 +1210,15 @@ const agents = {
|
|
|
1167
1210
|
return existsSync(join(home, ".firebender"));
|
|
1168
1211
|
}
|
|
1169
1212
|
},
|
|
1213
|
+
flocks: {
|
|
1214
|
+
name: "flocks",
|
|
1215
|
+
displayName: "Flocks",
|
|
1216
|
+
skillsDir: ".flocks/plugins/skills",
|
|
1217
|
+
globalSkillsDir: join(home, ".flocks/plugins/skills"),
|
|
1218
|
+
detectInstalled: async () => {
|
|
1219
|
+
return existsSync(join(home, ".flocks"));
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1170
1222
|
"gemini-cli": {
|
|
1171
1223
|
name: "gemini-cli",
|
|
1172
1224
|
displayName: "Gemini CLI",
|
|
@@ -1440,6 +1492,7 @@ const SKILLS_SUBDIR = "skills";
|
|
|
1440
1492
|
function sanitizeName(name) {
|
|
1441
1493
|
const asciiName = name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "");
|
|
1442
1494
|
if (asciiName.length === 0) {
|
|
1495
|
+
if (!/[\p{L}\p{N}]/u.test(name)) return "unnamed-skill";
|
|
1443
1496
|
let hash = 0;
|
|
1444
1497
|
for (let i = 0; i < name.length; i++) {
|
|
1445
1498
|
const char = name.charCodeAt(i);
|
|
@@ -2259,7 +2312,7 @@ function createEmptyLocalLock() {
|
|
|
2259
2312
|
skills: {}
|
|
2260
2313
|
};
|
|
2261
2314
|
}
|
|
2262
|
-
var version$1 = "0.2.
|
|
2315
|
+
var version$1 = "0.2.2";
|
|
2263
2316
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
2264
2317
|
async function isSourcePrivate(source) {
|
|
2265
2318
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -4350,6 +4403,8 @@ ${BOLD}List Options:${RESET}
|
|
|
4350
4403
|
${BOLD}Options:${RESET}
|
|
4351
4404
|
--help, -h Show this help message
|
|
4352
4405
|
--version, -v Show version number
|
|
4406
|
+
--region <cn|global>
|
|
4407
|
+
Use a specific SafeSkill service region for this run
|
|
4353
4408
|
|
|
4354
4409
|
${BOLD}Examples:${RESET}
|
|
4355
4410
|
${DIM}$${RESET} safeskill add example-org/agent-skills
|
|
@@ -4636,7 +4691,7 @@ async function runCheck(args = []) {
|
|
|
4636
4691
|
});
|
|
4637
4692
|
console.log();
|
|
4638
4693
|
}
|
|
4639
|
-
async function runUpdate() {
|
|
4694
|
+
async function runUpdate(region) {
|
|
4640
4695
|
console.log(`${TEXT}Checking for skill updates...${RESET}`);
|
|
4641
4696
|
console.log();
|
|
4642
4697
|
const lock = readSkillLock();
|
|
@@ -4732,13 +4787,22 @@ async function runUpdate() {
|
|
|
4732
4787
|
console.log(` ${DIM}✗ Failed to update ${update.name}: CLI entrypoint not found at ${cliEntry}${RESET}`);
|
|
4733
4788
|
continue;
|
|
4734
4789
|
}
|
|
4735
|
-
|
|
4790
|
+
const addArgs = region ? [
|
|
4791
|
+
cliEntry,
|
|
4792
|
+
"--region",
|
|
4793
|
+
region,
|
|
4794
|
+
"add",
|
|
4795
|
+
installUrl,
|
|
4796
|
+
"-g",
|
|
4797
|
+
"-y"
|
|
4798
|
+
] : [
|
|
4736
4799
|
cliEntry,
|
|
4737
4800
|
"add",
|
|
4738
4801
|
installUrl,
|
|
4739
4802
|
"-g",
|
|
4740
4803
|
"-y"
|
|
4741
|
-
]
|
|
4804
|
+
];
|
|
4805
|
+
if (spawnSync(process.execPath, addArgs, {
|
|
4742
4806
|
stdio: [
|
|
4743
4807
|
"inherit",
|
|
4744
4808
|
"pipe",
|
|
@@ -4765,8 +4829,53 @@ async function runUpdate() {
|
|
|
4765
4829
|
});
|
|
4766
4830
|
console.log();
|
|
4767
4831
|
}
|
|
4832
|
+
function parseGlobalOptions(args) {
|
|
4833
|
+
const parsedArgs = [];
|
|
4834
|
+
let region;
|
|
4835
|
+
for (let i = 0; i < args.length; i++) {
|
|
4836
|
+
const arg = args[i];
|
|
4837
|
+
if (arg === void 0) continue;
|
|
4838
|
+
if (arg === "--region") {
|
|
4839
|
+
const value = args[i + 1];
|
|
4840
|
+
if (typeof value !== "string" || value.startsWith("-")) return {
|
|
4841
|
+
args: parsedArgs,
|
|
4842
|
+
error: "Missing value for --region. Expected one of: cn, global"
|
|
4843
|
+
};
|
|
4844
|
+
const normalized = normalizeSafeSkillRegion(value);
|
|
4845
|
+
if (!normalized) return {
|
|
4846
|
+
args: parsedArgs,
|
|
4847
|
+
error: `Invalid region: ${value}\nExpected one of: cn, global`
|
|
4848
|
+
};
|
|
4849
|
+
region = normalized;
|
|
4850
|
+
i++;
|
|
4851
|
+
continue;
|
|
4852
|
+
}
|
|
4853
|
+
if (arg.startsWith("--region=")) {
|
|
4854
|
+
const value = arg.slice(9);
|
|
4855
|
+
const normalized = normalizeSafeSkillRegion(value);
|
|
4856
|
+
if (!normalized) return {
|
|
4857
|
+
args: parsedArgs,
|
|
4858
|
+
error: `Invalid region: ${value}\nExpected one of: cn, global`
|
|
4859
|
+
};
|
|
4860
|
+
region = normalized;
|
|
4861
|
+
continue;
|
|
4862
|
+
}
|
|
4863
|
+
parsedArgs.push(arg);
|
|
4864
|
+
}
|
|
4865
|
+
return {
|
|
4866
|
+
args: parsedArgs,
|
|
4867
|
+
region
|
|
4868
|
+
};
|
|
4869
|
+
}
|
|
4768
4870
|
async function main() {
|
|
4769
|
-
const
|
|
4871
|
+
const parsedGlobalOptions = parseGlobalOptions(process.argv.slice(2));
|
|
4872
|
+
if (parsedGlobalOptions.error) {
|
|
4873
|
+
console.log(parsedGlobalOptions.error);
|
|
4874
|
+
process.exitCode = 1;
|
|
4875
|
+
return;
|
|
4876
|
+
}
|
|
4877
|
+
if (parsedGlobalOptions.region) setSafeSkillRegionOverride(parsedGlobalOptions.region);
|
|
4878
|
+
const args = parsedGlobalOptions.args;
|
|
4770
4879
|
if (args.length === 0) {
|
|
4771
4880
|
showBanner();
|
|
4772
4881
|
return;
|
|
@@ -4825,7 +4934,7 @@ async function main() {
|
|
|
4825
4934
|
break;
|
|
4826
4935
|
case "update":
|
|
4827
4936
|
case "upgrade":
|
|
4828
|
-
runUpdate();
|
|
4937
|
+
runUpdate(parsedGlobalOptions.region);
|
|
4829
4938
|
break;
|
|
4830
4939
|
case "--help":
|
|
4831
4940
|
case "-h":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@safeskill/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "SafeSkill CLI, for safe your skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"deepagents",
|
|
52
52
|
"droid",
|
|
53
53
|
"firebender",
|
|
54
|
+
"flocks",
|
|
54
55
|
"gemini-cli",
|
|
55
56
|
"github-copilot",
|
|
56
57
|
"goose",
|