@przeprogramowani/10x-cli 1.4.0 → 1.6.0

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 CHANGED
@@ -63,7 +63,7 @@ Once installed, just tell your agent to **set up 10x-cli** and it will pick up t
63
63
 
64
64
  | Flag | Description |
65
65
  |------|-------------|
66
- | `--tool <tool>` | AI coding tool: `claude-code`, `cursor`, `copilot`, `codex`, `generic` |
66
+ | `--tool <tool>` | AI coding tool: `claude-code`, `cursor`, `copilot`, `codex`, `windsurf`, `gemini`, `generic` |
67
67
  | `--print` | Output artifact content to stdout instead of writing files |
68
68
  | `--type <type>` | Filter by artifact type: `skills`, `prompts`, `rules`, `configs` |
69
69
  | `--name <name>` | Filter by artifact name (requires `--type`) |
@@ -114,6 +114,8 @@ On first run, the CLI prompts you to choose your AI coding tool. Artifacts are w
114
114
  | Cursor | `.cursor/` | `.cursor/rules/10x-course.mdc` |
115
115
  | GitHub Copilot | `.github/` | `.github/copilot-instructions.md` |
116
116
  | Codex CLI | `.agents/` | `AGENTS.md` |
117
+ | Windsurf | `.windsurf/` | `.windsurfrules` |
118
+ | Gemini CLI | `.gemini/` | `GEMINI.md` |
117
119
  | Generic | `.ai/` | `AGENTS.md` |
118
120
 
119
121
  Override anytime with `--tool <name>`. Your choice is saved in `~/.config/10x-cli/config.json`.
package/dist/index.mjs CHANGED
@@ -2271,7 +2271,7 @@ var cac = (name = "") => new CAC(name);
2271
2271
  // package.json
2272
2272
  var package_default = {
2273
2273
  name: "@przeprogramowani/10x-cli",
2274
- version: "1.4.0",
2274
+ version: "1.6.0",
2275
2275
  description: "Open-source CLI for 10xDevs course content",
2276
2276
  repository: {
2277
2277
  type: "git",
@@ -3807,6 +3807,18 @@ var PROFILES = {
3807
3807
  sentinelBegin: SENTINEL_BEGIN,
3808
3808
  sentinelEnd: SENTINEL_END
3809
3809
  },
3810
+ gemini: {
3811
+ toolId: "gemini",
3812
+ displayName: "Gemini CLI",
3813
+ skillPath: (n) => `.gemini/skills/${n}/SKILL.md`,
3814
+ skillDir: (n) => `.gemini/skills/${n}`,
3815
+ promptPath: (n) => `.gemini/prompts/${n}.md`,
3816
+ configPath: (n) => `.gemini/config-templates/${n}`,
3817
+ rulesFile: "GEMINI.md",
3818
+ manifestDir: ".gemini",
3819
+ sentinelBegin: SENTINEL_BEGIN,
3820
+ sentinelEnd: SENTINEL_END
3821
+ },
3810
3822
  generic: {
3811
3823
  toolId: "generic",
3812
3824
  displayName: "Other / Generic",
@@ -3822,6 +3834,68 @@ var PROFILES = {
3822
3834
  };
3823
3835
  var DEFAULT_TOOL = "claude-code";
3824
3836
 
3837
+ // src/lib/update-check.ts
3838
+ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@przeprogramowani/10x-cli/latest";
3839
+ async function fetchLatestVersion(options = {}) {
3840
+ const timeoutMs = options.timeoutMs ?? 2000;
3841
+ const url = options.url ?? NPM_REGISTRY_URL;
3842
+ const controller = new AbortController;
3843
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
3844
+ try {
3845
+ const res = await fetch(url, {
3846
+ signal: controller.signal,
3847
+ headers: { Accept: "application/json", "User-Agent": "10x-cli" }
3848
+ });
3849
+ if (!res.ok) {
3850
+ return {
3851
+ ok: false,
3852
+ code: "http_error",
3853
+ error: `registry returned HTTP ${res.status}`
3854
+ };
3855
+ }
3856
+ const body = await res.json();
3857
+ if (typeof body.version !== "string" || body.version.length === 0) {
3858
+ return {
3859
+ ok: false,
3860
+ code: "parse_error",
3861
+ error: "registry payload missing 'version' field"
3862
+ };
3863
+ }
3864
+ return { ok: true, version: body.version };
3865
+ } catch (err) {
3866
+ const aborted = controller.signal.aborted;
3867
+ return {
3868
+ ok: false,
3869
+ code: aborted ? "timeout" : "network_error",
3870
+ error: err instanceof Error ? err.message : String(err)
3871
+ };
3872
+ } finally {
3873
+ clearTimeout(timer);
3874
+ }
3875
+ }
3876
+ function compareSemver(a2, b2) {
3877
+ const parse = (v2) => {
3878
+ const core = v2.split(/[-+]/)[0] ?? v2;
3879
+ const parts = core.split(".").map((p2) => {
3880
+ const n = Number.parseInt(p2, 10);
3881
+ return Number.isFinite(n) ? n : 0;
3882
+ });
3883
+ return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
3884
+ };
3885
+ const [a1, a22, a3] = parse(a2);
3886
+ const [b1, b22, b3] = parse(b2);
3887
+ if (a1 !== b1)
3888
+ return a1 < b1 ? -1 : 1;
3889
+ if (a22 !== b22)
3890
+ return a22 < b22 ? -1 : 1;
3891
+ if (a3 !== b3)
3892
+ return a3 < b3 ? -1 : 1;
3893
+ return 0;
3894
+ }
3895
+ function upgradeCommand() {
3896
+ return "npm install -g @przeprogramowani/10x-cli";
3897
+ }
3898
+
3825
3899
  // src/commands/doctor.ts
3826
3900
  var EX_CONFIG = 78;
3827
3901
  function registerDoctorCommand(cli) {
@@ -3836,7 +3910,7 @@ async function runDoctor(ctx) {
3836
3910
  checks.push(checkAuth());
3837
3911
  checks.push(await checkApiConnectivity());
3838
3912
  checks.push(checkConfigDirectory());
3839
- checks.push(checkCliVersion());
3913
+ checks.push(await checkCliVersion());
3840
3914
  checks.push(checkToolDirectory());
3841
3915
  const failed = checks.filter((c2) => c2.status === "fail").length;
3842
3916
  const passed = checks.filter((c2) => c2.status === "pass").length;
@@ -3985,13 +4059,35 @@ function checkConfigDirectory() {
3985
4059
  };
3986
4060
  }
3987
4061
  }
3988
- function checkCliVersion() {
4062
+ async function checkCliVersion() {
4063
+ const current = package_default.version;
4064
+ const latest = await fetchLatestVersion({ timeoutMs: 2000 });
4065
+ if (!latest.ok) {
4066
+ return {
4067
+ name: "version",
4068
+ label: "Version",
4069
+ status: "pass",
4070
+ message: `10x-cli ${current} (update check skipped).`,
4071
+ details: { version: current, lookup: { ok: false, code: latest.code } }
4072
+ };
4073
+ }
4074
+ const cmp = compareSemver(current, latest.version);
4075
+ if (cmp < 0) {
4076
+ return {
4077
+ name: "version",
4078
+ label: "Version",
4079
+ status: "warn",
4080
+ message: `10x-cli ${current} is behind latest ${latest.version}.`,
4081
+ hint: `Upgrade with '${upgradeCommand()}'.`,
4082
+ details: { version: current, latest: latest.version, outdated: true }
4083
+ };
4084
+ }
3989
4085
  return {
3990
4086
  name: "version",
3991
4087
  label: "Version",
3992
4088
  status: "pass",
3993
- message: `10x-cli ${package_default.version}.`,
3994
- details: { version: package_default.version }
4089
+ message: `10x-cli ${current} — up to date.`,
4090
+ details: { version: current, latest: latest.version, outdated: false }
3995
4091
  };
3996
4092
  }
3997
4093
  function checkToolDirectory() {
@@ -4210,6 +4306,17 @@ function detectTools(projectRoot) {
4210
4306
  } else if (hit(".windsurf")) {
4211
4307
  signals.push({ profileId: "windsurf", confidence: "medium", reason: ".windsurf/ directory" });
4212
4308
  }
4309
+ if (hit(".gemini/" + MANIFEST_FILENAME)) {
4310
+ signals.push({
4311
+ profileId: "gemini",
4312
+ confidence: "strong",
4313
+ reason: ".gemini/.10x-cli-manifest.json"
4314
+ });
4315
+ } else if (hit("GEMINI.md")) {
4316
+ signals.push({ profileId: "gemini", confidence: "strong", reason: "GEMINI.md" });
4317
+ } else if (hit(".gemini")) {
4318
+ signals.push({ profileId: "gemini", confidence: "medium", reason: ".gemini/ directory" });
4319
+ }
4213
4320
  if (hit(".ai/" + MANIFEST_FILENAME)) {
4214
4321
  signals.push({
4215
4322
  profileId: "generic",
@@ -4224,7 +4331,7 @@ function detectTools(projectRoot) {
4224
4331
  return rankSignals(signals);
4225
4332
  }
4226
4333
  var CONFIDENCE_ORDER = { strong: 3, medium: 2, weak: 1 };
4227
- var PROFILE_ORDER = ["claude-code", "cursor", "copilot", "codex", "windsurf", "generic"];
4334
+ var PROFILE_ORDER = ["claude-code", "cursor", "copilot", "codex", "windsurf", "gemini", "generic"];
4228
4335
  function rankSignals(signals) {
4229
4336
  return [...signals].sort((a2, b2) => {
4230
4337
  const c2 = CONFIDENCE_ORDER[b2.confidence] - CONFIDENCE_ORDER[a2.confidence];
@@ -4949,7 +5056,7 @@ function isArtifactType(s) {
4949
5056
  }
4950
5057
  var DEFAULT_COURSE2 = "10xdevs3";
4951
5058
  function registerGetCommand(cli) {
4952
- cli.command("get <ref>", "Fetch and apply a lesson pack").option("--dry-run", "Show what would be written without touching the filesystem").option("--course <course>", "Override the course slug (default: 10xdevs3)").option("--tool <tool>", "AI coding tool (claude-code, cursor, copilot, codex, generic)").option("--print", "Print artifact content to stdout instead of writing to files").option("--type <type>", "Artifact type filter: skills, prompts, rules, configs").option("--name <name>", "Artifact name filter (requires --type)").option("--lang <lang>", "Content language: en (default) or pl").action(async (ref, options) => {
5059
+ cli.command("get <ref>", "Fetch and apply a lesson pack").option("--dry-run", "Show what would be written without touching the filesystem").option("--course <course>", "Override the course slug (default: 10xdevs3)").option("--tool <tool>", "AI coding tool (claude-code, cursor, copilot, codex, windsurf, gemini, generic)").option("--print", "Print artifact content to stdout instead of writing to files").option("--type <type>", "Artifact type filter: skills, prompts, rules, configs").option("--name <name>", "Artifact name filter (requires --type)").option("--lang <lang>", "Content language: en (default) or pl").action(async (ref, options) => {
4953
5060
  const ctx = resolveContext(options);
4954
5061
  await runGet(ctx, ref, options);
4955
5062
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@przeprogramowani/10x-cli",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Open-source CLI for 10xDevs course content",
5
5
  "repository": {
6
6
  "type": "git",