@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 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 [40 more](#available-agents).
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 | Global Path |
242
- | ------------------------------------- | ---------------------------------------- | ---------------------- | ------------------------------- |
243
- | Amp, Kimi Code CLI, Replit, Universal | `amp`, `kimi-cli`, `replit`, `universal` | `.agents/skills/` | `~/.config/agents/skills/` |
244
- | Antigravity | `antigravity` | `.agents/skills/` | `~/.gemini/antigravity/skills/` |
245
- | Augment | `augment` | `.augment/skills/` | `~/.augment/skills/` |
246
- | Claude Code | `claude-code` | `.claude/skills/` | `~/.claude/skills/` |
247
- | OpenClaw | `openclaw` | `skills/` | `~/.openclaw/skills/` |
248
- | Cline, Warp | `cline`, `warp` | `.agents/skills/` | `~/.agents/skills/` |
249
- | CodeBuddy | `codebuddy` | `.codebuddy/skills/` | `~/.codebuddy/skills/` |
250
- | Codex | `codex` | `.agents/skills/` | `~/.codex/skills/` |
251
- | Command Code | `command-code` | `.commandcode/skills/` | `~/.commandcode/skills/` |
252
- | Continue | `continue` | `.continue/skills/` | `~/.continue/skills/` |
253
- | Cortex Code | `cortex` | `.cortex/skills/` | `~/.snowflake/cortex/skills/` |
254
- | Crush | `crush` | `.crush/skills/` | `~/.config/crush/skills/` |
255
- | Cursor | `cursor` | `.agents/skills/` | `~/.cursor/skills/` |
256
- | Deep Agents | `deepagents` | `.agents/skills/` | `~/.deepagents/agent/skills/` |
257
- | Droid | `droid` | `.factory/skills/` | `~/.factory/skills/` |
258
- | Firebender | `firebender` | `.agents/skills/` | `~/.firebender/skills/` |
259
- | Gemini CLI | `gemini-cli` | `.agents/skills/` | `~/.gemini/skills/` |
260
- | GitHub Copilot | `github-copilot` | `.agents/skills/` | `~/.copilot/skills/` |
261
- | Goose | `goose` | `.goose/skills/` | `~/.config/goose/skills/` |
262
- | Junie | `junie` | `.junie/skills/` | `~/.junie/skills/` |
263
- | iFlow CLI | `iflow-cli` | `.iflow/skills/` | `~/.iflow/skills/` |
264
- | Kilo Code | `kilo` | `.kilocode/skills/` | `~/.kilocode/skills/` |
265
- | Kiro CLI | `kiro-cli` | `.kiro/skills/` | `~/.kiro/skills/` |
266
- | Kode | `kode` | `.kode/skills/` | `~/.kode/skills/` |
267
- | MCPJam | `mcpjam` | `.mcpjam/skills/` | `~/.mcpjam/skills/` |
268
- | Mistral Vibe | `mistral-vibe` | `.vibe/skills/` | `~/.vibe/skills/` |
269
- | Mux | `mux` | `.mux/skills/` | `~/.mux/skills/` |
270
- | OpenCode | `opencode` | `.agents/skills/` | `~/.config/opencode/skills/` |
271
- | OpenHands | `openhands` | `.openhands/skills/` | `~/.openhands/skills/` |
272
- | Pi | `pi` | `.pi/skills/` | `~/.pi/agent/skills/` |
273
- | Qoder | `qoder` | `.qoder/skills/` | `~/.qoder/skills/` |
274
- | Qwen Code | `qwen-code` | `.qwen/skills/` | `~/.qwen/skills/` |
275
- | Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
276
- | Trae | `trae` | `.trae/skills/` | `~/.trae/skills/` |
277
- | Trae CN | `trae-cn` | `.trae/skills/` | `~/.trae-cn/skills/` |
278
- | Windsurf | `windsurf` | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
279
- | Zencoder | `zencoder` | `.zencoder/skills/` | `~/.zencoder/skills/` |
280
- | Neovate | `neovate` | `.neovate/skills/` | `~/.neovate/skills/` |
281
- | Pochi | `pochi` | `.pochi/skills/` | `~/.pochi/skills/` |
282
- | AdaL | `adal` | `.adal/skills/` | `~/.adal/skills/` |
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
- function normalizeRegion(region) {
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
- const configuredRegion = normalizeRegion(process.env.SAFESKILL_REGION);
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
- if (entry.isDirectory) {
621
- zipfile.readEntry();
622
- return;
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 response = await fetch(buildApiUrl(baseUrl, "/resolve"), {
725
- method: "POST",
726
- headers: getHeaders({ "content-type": "application/json" }),
727
- body: JSON.stringify({
728
- source,
729
- ...agent ? { agent } : {}
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
- return readEnvelope(response);
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.0";
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
- if (spawnSync(process.execPath, [
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 args = process.argv.slice(2);
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.0",
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",