@starci/hfs 2.0.1 → 2.0.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,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.2 - 2026-10-01
4
+
5
+ - Fixed: `hfs` printed nothing and checked nothing when started through a node_modules junction or symlink (every lane worktree, some npx shims): the entry-point test compared `argv[1]` with the resolved module path. It now compares real paths (`isMain` of `scripts/checks/common.mjs`, shared by the bin and the architecture entry). Spec: `tests/hfs-cli-worktree.spec.mjs` runs `hfs check` inside a `git worktree add` checkout with a junctioned node_modules and requires a report or a loud refusal.
6
+
3
7
  ## 2.0.1 - 2026-10-01
4
8
 
5
9
  - Fixed: `hfs sync` validates the whole hfs.json declaration against the manifest before rendering (a pre-2.0 `connections` list of names is refused), so a pin bump can never leave eslint unable to start.
package/bin/hfs.mjs CHANGED
@@ -35,6 +35,7 @@
35
35
  import fs from 'node:fs';
36
36
  import path from 'node:path';
37
37
  import { fileURLToPath } from 'node:url';
38
+ import { isMain } from '../runtime/scripts/checks/common.mjs';
38
39
  import { checkRepository, explainPath, initRepo, trackedFiles } from '../runtime/scripts/lib/hfs-check.mjs';
39
40
  import { HfsSlotsError } from '../runtime/scripts/lib/hfs-slots.mjs';
40
41
  import { formatFindings } from '../sync/format.mjs';
@@ -201,4 +202,6 @@ export async function main(argv, { stdout = (s) => process.stdout.write(s), stde
201
202
  }
202
203
  }
203
204
 
204
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) process.exitCode = await main(process.argv.slice(2));
205
+ // Run when this file is the entry point, compared by real path: through a node_modules junction or an npx shim argv[1] is
206
+ // the junction path while import.meta.url is the resolved one, and a plain comparison silently skipped main (hfs printed nothing).
207
+ if (isMain(import.meta.url)) process.exitCode = await main(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starci/hfs",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "The HFS command line of a StarCi product repository: hfs check, init, explain, sync and work-hygiene. Self-contained: it carries the runtime files it reads.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -57,7 +57,7 @@ pins:
57
57
  source: packages/jest-preset/package.json
58
58
  why: '2.1.0: four projects on the test world, the unit kit (mockEntityManager, fakeTransaction, fakeIds, FakeClock, Outcome matchers) and the recordingOutbox claim side.'
59
59
  '@starci/hfs':
60
- version: 2.0.1
60
+ version: 2.0.2
61
61
  group: starci
62
62
  install: registry
63
63
  side: both
@@ -7,6 +7,7 @@
7
7
  import path from 'node:path';
8
8
  import {fileURLToPath} from 'node:url';
9
9
  import {checkArchitecture} from './architecture/index.mjs';
10
+ import { isMain } from './common.mjs';
10
11
 
11
12
  export {checkArchitecture};
12
13
 
@@ -38,4 +39,4 @@ export function architectureMain(argv, {check = checkArchitecture, write = (text
38
39
  return report?.ok === true ? 0 : 1;
39
40
  }
40
41
 
41
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) process.exitCode = architectureMain(process.argv.slice(2));
42
+ if (isMain(import.meta.url)) process.exitCode = architectureMain(process.argv.slice(2));
@@ -9,7 +9,14 @@ export function isInside(root, target) {
9
9
  }
10
10
 
11
11
  /** True when this module is the process entry point (`node file.mjs`, not an import). */
12
- export const isMain = (metaUrl, argv = process.argv) => Boolean(argv[1]) && path.resolve(argv[1]) === fileURLToPath(metaUrl);
12
+ /** The real path of a file, or its resolved path when it cannot be read (a missing file is never the entry module). */
13
+ const realPathOf = (file) => { try { return fs.realpathSync.native(path.resolve(file)); } catch { return path.resolve(file); } };
14
+ /**
15
+ * True when the module at `metaUrl` is the process entry point. Both sides are compared as REAL paths: Node gives a module
16
+ * its symlink-resolved URL, while argv[1] keeps the path it was started with, so an entry reached through a node_modules
17
+ * junction or symlink (a lane worktree, an npx shim) would otherwise look like an import and silently do nothing.
18
+ */
19
+ export const isMain = (metaUrl, argv = process.argv) => Boolean(argv[1]) && realPathOf(argv[1]) === realPathOf(fileURLToPath(metaUrl));
13
20
 
14
21
  /**
15
22
  * Every entry under `dir` that is not a directory, depth-first; `filter` sees the entry name and full