@przeprogramowani/10x-cli 1.28.0 → 1.29.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.
Files changed (3) hide show
  1. package/README.md +10 -5
  2. package/dist/index.mjs +101 -46
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -309,13 +309,18 @@ releases and suggests running `10x sync`.
309
309
  10x changelog --since 2026-10-01 --limit 50
310
310
  ```
311
311
 
312
- Releases are listed newest first as `vX.Y.Z — <date>` followed by their notes, or
313
- `No toolkit changes since <baseline>.` Exit code is `0` whether or not there are
314
- new releases; an invalid `--since`/`--limit` exits `2`, a missing login `3`. Against
312
+ The output starts with where the project stands (for example `This project is on
313
+ toolkit v2.59.2 (recorded by 10x sync on 2026-10-05) — 2 newer releases:`), then
314
+ lists releases newest first: `vX.Y.Z — <date>`, the release highlights as bullets,
315
+ and the changed skills, prompts, rules and config templates with a status mark
316
+ (`+` new, `~` changed, `-` removed, `>` renamed) and a one-line summary. Colours are
317
+ used only on an interactive terminal and respect `NO_COLOR`. Exit code is `0`
318
+ whether or not there are new releases; an invalid `--since`/`--limit` exits `2`, a
319
+ missing login `3`, and an account without course access `4`. Against
315
320
  a backend that does not serve the changelog yet the command fails with
316
321
  `changelog_unsupported` (exit `1`); `get` and `sync` keep working. JSON output
317
- (`--json` or piped) is `{ baseline: { source, version?, date? }, newEntries,
318
- entries }`, where `source` is `flag`, `sync`, `applied` or `none`.
322
+ (`--json` or piped) is `{ baseline: { source, version?, date?, recordedAt? },
323
+ newEntries, entries }`, where `source` is `flag`, `sync`, `applied` or `none`.
319
324
 
320
325
  ### `10x bench`
321
326
 
package/dist/index.mjs CHANGED
@@ -3183,7 +3183,7 @@ var cac = (name = "") => new CAC(name);
3183
3183
  // package.json
3184
3184
  var package_default = {
3185
3185
  name: "@przeprogramowani/10x-cli",
3186
- version: "1.28.0",
3186
+ version: "1.29.0",
3187
3187
  description: "Open-source CLI for 10xDevs course content",
3188
3188
  repository: {
3189
3189
  type: "git",
@@ -4567,6 +4567,38 @@ function formatReleaseAt(iso, now = new Date) {
4567
4567
  return `${absolute} (tomorrow)`;
4568
4568
  return `${absolute} (in ${days} days)`;
4569
4569
  }
4570
+ function colorsEnabled() {
4571
+ return process.env["NO_COLOR"] === undefined && process.stderr.isTTY === true;
4572
+ }
4573
+ var STYLE = {
4574
+ bold: "1",
4575
+ dim: "2",
4576
+ red: "31",
4577
+ green: "32",
4578
+ yellow: "33",
4579
+ cyan: "36"
4580
+ };
4581
+ function paint(style, text) {
4582
+ if (!colorsEnabled())
4583
+ return text;
4584
+ return `\x1B[${style}m${text}\x1B[0m`;
4585
+ }
4586
+ function wrapText(text, width, prefix, indent = " ".repeat(prefix.length)) {
4587
+ const lines = [];
4588
+ let line = prefix;
4589
+ let empty = true;
4590
+ for (const word of text.split(/\s+/).filter(Boolean)) {
4591
+ if (!empty && line.length + 1 + word.length > width) {
4592
+ lines.push(line);
4593
+ line = indent + word;
4594
+ } else {
4595
+ line += (empty ? "" : " ") + word;
4596
+ }
4597
+ empty = false;
4598
+ }
4599
+ lines.push(line);
4600
+ return lines;
4601
+ }
4570
4602
 
4571
4603
  // src/commands/bench.ts
4572
4604
  function registerBenchCommand(cli) {
@@ -4606,22 +4638,6 @@ function handleBenchError(ctx, status, code, error) {
4606
4638
  }
4607
4639
  outputError(ctx, code || "bench_failed", "Failed to load the leaderboard.", ExitCodes.ERROR, error ? `Server said: ${error}` : undefined);
4608
4640
  }
4609
- function colorsEnabled() {
4610
- return process.env["NO_COLOR"] === undefined && process.stderr.isTTY === true;
4611
- }
4612
- var STYLE = {
4613
- bold: "1",
4614
- dim: "2",
4615
- red: "31",
4616
- green: "32",
4617
- yellow: "33",
4618
- cyan: "36"
4619
- };
4620
- function paint(style, text) {
4621
- if (!colorsEnabled())
4622
- return text;
4623
- return `\x1B[${style}m${text}\x1B[0m`;
4624
- }
4625
4641
  function scoreStyle(percentage) {
4626
4642
  if (percentage >= 90)
4627
4643
  return STYLE.green;
@@ -5832,7 +5848,7 @@ function resolveManifestBaseline(ctx, projectRoot) {
5832
5848
  const { profile, manifest } = found;
5833
5849
  verbose(ctx, `using manifest in ${profile.manifestDir}/`);
5834
5850
  if (manifest.toolkit)
5835
- return { source: "sync", version: manifest.toolkit.version };
5851
+ return { source: "sync", version: manifest.toolkit.version, recordedAt: manifest.toolkit.recordedAt };
5836
5852
  const applied = newestAppliedAt(manifest);
5837
5853
  if (applied)
5838
5854
  return { source: "applied", date: applied };
@@ -5867,48 +5883,87 @@ function handleChangelogError(ctx, status, code, error) {
5867
5883
  }
5868
5884
  outputError(ctx, code || "changelog_failed", error || "Failed to load the toolkit changelog.", ExitCodes.ERROR);
5869
5885
  }
5870
- function describeBaseline(baseline) {
5871
- return baseline.version ?? baseline.date ?? "";
5872
- }
5873
- function describeSource(baseline) {
5886
+ var day = (iso) => (iso ?? "").slice(0, 10);
5887
+ var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
5888
+ function header(baseline, count) {
5889
+ const v3 = paint(STYLE.bold, baseline.version ?? "");
5874
5890
  switch (baseline.source) {
5891
+ case "sync":
5892
+ return `This project is on toolkit ${v3} ${paint(STYLE.dim, `(recorded by 10x sync on ${day(baseline.recordedAt)})`)}${count ? ` — ${plural(count, "newer release")}:` : ""}`;
5875
5893
  case "flag":
5876
- return "from --since";
5894
+ return baseline.version ? `Toolkit changes since ${v3}:` : `Toolkit changes since ${paint(STYLE.bold, day(baseline.date))}:`;
5895
+ case "applied":
5896
+ return `No toolkit version recorded in this project — showing changes since your last lesson apply (${day(baseline.date)}):`;
5897
+ case "none":
5898
+ return `No toolkit version recorded in this project — showing the latest ${plural(count, "release")}:`;
5899
+ }
5900
+ }
5901
+ function emptyMessage(baseline) {
5902
+ switch (baseline.source) {
5877
5903
  case "sync":
5878
- return "recorded by your last 10x sync";
5904
+ return "You're up to date — no toolkit changes since then.";
5905
+ case "flag":
5906
+ return `No toolkit changes since ${baseline.version ?? day(baseline.date)}.`;
5879
5907
  case "applied":
5880
- return "last lesson applied in this project";
5908
+ return `No toolkit changes since ${day(baseline.date)}.`;
5881
5909
  case "none":
5882
- return "no baseline recorded";
5910
+ return "No toolkit changes published yet.";
5883
5911
  }
5884
5912
  }
5913
+ var MAX_WIDTH = 100;
5914
+ var CATEGORIES = [
5915
+ ["skills", "Skills"],
5916
+ ["prompts", "Prompts"],
5917
+ ["rules", "Rules"],
5918
+ ["configTemplates", "Config templates"]
5919
+ ];
5920
+ var STATUS = {
5921
+ added: { mark: "+", style: STYLE.green, label: "new" },
5922
+ modified: { mark: "~", style: STYLE.yellow },
5923
+ removed: { mark: "-", style: STYLE.red, label: "removed" },
5924
+ renamed: { mark: ">", style: STYLE.cyan, label: "renamed" }
5925
+ };
5926
+ function renderEntry(entry, width) {
5927
+ const lines = [`${paint(STYLE.bold, paint(STYLE.cyan, entry.version))} ${paint(STYLE.dim, `— ${entry.releasedAt.slice(0, 10)}`)}`];
5928
+ for (const highlight of entry.highlights)
5929
+ lines.push(...wrapText(sanitize(highlight), width, " • "));
5930
+ for (const [category, label] of CATEGORIES) {
5931
+ const items = entry.artifacts[category];
5932
+ if (items.length === 0)
5933
+ continue;
5934
+ lines.push("", ` ${paint(STYLE.bold, label)}`);
5935
+ for (const item of items) {
5936
+ const status = STATUS[item.status];
5937
+ const suffix = status.label ? ` ${paint(STYLE.dim, `(${status.label})`)}` : "";
5938
+ lines.push(` ${paint(status.style, status.mark)} ${paint(STYLE.bold, sanitize(item.name))}${suffix}`);
5939
+ if (item.summary)
5940
+ lines.push(...wrapText(sanitize(item.summary), width, " "));
5941
+ }
5942
+ }
5943
+ return lines;
5944
+ }
5945
+ function pushSyncHint(lines, baseline) {
5946
+ if (baseline.source !== "none" && baseline.source !== "applied")
5947
+ return;
5948
+ lines.push("", paint(STYLE.dim, "Run 10x sync to record this project's toolkit version; 10x changelog will then show only what changed since."));
5949
+ }
5885
5950
  function render(ctx, baseline, entries) {
5886
5951
  if (ctx.json) {
5887
5952
  output(ctx, "", { baseline, newEntries: entries.length, entries });
5888
5953
  return;
5889
5954
  }
5890
- const lines = [];
5891
- if (baseline.source === "none") {
5892
- lines.push(`Latest toolkit changes (${describeSource(baseline)})`);
5893
- } else {
5894
- lines.push(`Toolkit changes since ${describeBaseline(baseline)} (${describeSource(baseline)})`);
5895
- }
5896
- lines.push("");
5897
5955
  if (entries.length === 0) {
5898
- lines.push(baseline.source === "none" ? "No toolkit changes published yet." : `No toolkit changes since ${describeBaseline(baseline)}.`);
5899
- } else {
5900
- entries.forEach((entry, index) => {
5901
- if (index > 0)
5902
- lines.push("");
5903
- lines.push(`${entry.version} — ${entry.releasedAt.slice(0, 10)}`);
5904
- lines.push("");
5905
- lines.push(entry.markdown.trimEnd());
5906
- });
5907
- }
5908
- if (baseline.source === "none") {
5909
- lines.push("");
5910
- lines.push("Run 10x sync to record your baseline.");
5956
+ const lines2 = baseline.source === "sync" ? [header(baseline, 0), emptyMessage(baseline)] : [emptyMessage(baseline)];
5957
+ pushSyncHint(lines2, baseline);
5958
+ output(ctx, lines2.join(`
5959
+ `), undefined);
5960
+ return;
5911
5961
  }
5962
+ const width = Math.min(process.stderr.columns || 80, MAX_WIDTH);
5963
+ const lines = [header(baseline, entries.length)];
5964
+ for (const entry of entries)
5965
+ lines.push("", ...renderEntry(entry, width));
5966
+ pushSyncHint(lines, baseline);
5912
5967
  output(ctx, lines.join(`
5913
5968
  `), undefined);
5914
5969
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@przeprogramowani/10x-cli",
3
- "version": "1.28.0",
3
+ "version": "1.29.0",
4
4
  "description": "Open-source CLI for 10xDevs course content",
5
5
  "repository": {
6
6
  "type": "git",