@natjswenson/devlog 0.5.0 → 0.5.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/bin/devlog.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn, spawnSync, execSync } from 'node:child_process';
3
- import { existsSync, mkdirSync, readFileSync, copyFileSync } from 'node:fs';
3
+ import { existsSync, mkdirSync, readFileSync, copyFileSync, realpathSync } from 'node:fs';
4
4
  import { dirname, join, resolve, basename } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { createRequire } from 'node:module';
@@ -725,7 +725,17 @@ Issues: https://github.com/natejswenson/devlog/issues
725
725
  // ─── dispatch ────────────────────────────────────────────────────────────────
726
726
  // Only run the CLI dispatch when this file is executed directly, not when it is
727
727
  // imported (e.g. by the test suite). Importing the module must have no side effects.
728
- const isMain = process.argv[1] === fileURLToPath(import.meta.url);
728
+ // Both sides are realpath'd: under npm/npx, argv[1] is the node_modules/.bin/devlog
729
+ // SYMLINK while import.meta.url is the resolved file — a naive === never matches
730
+ // and every npx invocation becomes a silent no-op.
731
+ const isMain = (() => {
732
+ if (!process.argv[1]) return false;
733
+ try {
734
+ return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
735
+ } catch {
736
+ return false;
737
+ }
738
+ })();
729
739
  if (isMain) {
730
740
  const arg = process.argv[2];
731
741
  const rest = process.argv.slice(3);
@@ -7,12 +7,30 @@ import { join } from 'node:path';
7
7
  import { RE_PROJECT_KEY, RE_FINAL_RELEASE, atomicWriteJSON } from './core.mjs';
8
8
  import { parseFrontmatter } from './lint_post.mjs';
9
9
 
10
- // Newest-first by date; ties keep insertion order (Array.prototype.sort is
11
- // stable). Date order is normally also version order, but a backported tag
12
- // (v1.9.1 tagged after v2.0.0) can diverge sorting by date matches how the
13
- // feed renders.
10
+ // Newest-first by date; same-date ties break by version, highest first.
11
+ // Without the tiebreak, several releases cut on one day render oldest-on-top
12
+ // in the feed (stable sort keeps insertion order), burying the newest post
13
+ // under its predecessors. Date still wins overall because a backported tag
14
+ // (v1.9.1 tagged after v2.0.0) must sort by when it was released.
15
+ function versionNums(entry) {
16
+ const m = /^v(\d+(?:\.\d+)*)$/.exec(entry.version || '');
17
+ return m ? m[1].split('.').map(Number) : null;
18
+ }
19
+
20
+ function compareVersionsDesc(a, b) {
21
+ const va = versionNums(a);
22
+ const vb = versionNums(b);
23
+ if (!va || !vb) return 0; // legacy rows without a version keep their order
24
+ for (let i = 0; i < Math.max(va.length, vb.length); i++) {
25
+ const d = (vb[i] ?? 0) - (va[i] ?? 0);
26
+ if (d !== 0) return d;
27
+ }
28
+ return 0;
29
+ }
30
+
14
31
  function sortEntries(entries) {
15
- return entries.slice().sort((a, b) => String(b.date).localeCompare(String(a.date)));
32
+ return entries.slice().sort((a, b) =>
33
+ String(b.date).localeCompare(String(a.date)) || compareVersionsDesc(a, b));
16
34
  }
17
35
 
18
36
  export function publishEntry({ cloneDir, project, version, entryPath }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@natjswenson/devlog",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Release dev log generator \u2014 Claude Code skill + preview app for publishing version-release dev logs, written in your voice, to your site",
5
5
  "license": "MIT",
6
6
  "author": "Nate Swenson",