@starci/hfs 2.0.0 → 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 +9 -0
- package/bin/hfs.mjs +4 -1
- package/package.json +1 -1
- package/runtime/knowledge/hfs/canon-pins.yaml +2 -2
- package/runtime/scripts/checks/architecture.mjs +2 -1
- package/runtime/scripts/checks/common.mjs +8 -1
- package/sync/index.mjs +8 -1
- package/templates/be/package-scripts/package.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
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
|
+
|
|
7
|
+
## 2.0.1 - 2026-10-01
|
|
8
|
+
|
|
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.
|
|
10
|
+
- Changed: the back-end managed scripts carry `test:stack` (`starci-test-stack`); repo-specific devDependencies stay the repository's (sync owns only the `scripts` block and the canon pins).
|
|
11
|
+
|
|
3
12
|
## 2.0.0 - 2026-09-30
|
|
4
13
|
|
|
5
14
|
- Added (lane PORT): the repository scripts of the product repos are gone, so their laws live here. `repo.scripts` owns `scripts/{.gitkeep,*.mjs,*.cjs,*.ps1,*.sh}` (operational scripts, or an empty folder with `.gitkeep`, which `hfs sync --init` writes from `templates/{be,fe}/skeleton/scripts/.gitkeep`). New checks: `BE_SPEC_PLACEMENT` (R102, a spec outside the four test layers, `scripts/` and `tools/` included), `HFS_REPO_LOCAL_CHECK` (R103, a `check-*` file, `eslint-local-rules*`, a local plugin, a script that runs one), `HFS_LINT_SUPPRESSION_FILE` (R104, an eslint suppressions file, script or flag), `HFS_PROOF_COMMAND_FILE_MISSING` (R105, a `.starciwork` proof command that runs a file the repository does not hold; only records of this repository are judged) and, in the architecture machine, `FE_I18N_KEYS` (R106, a key the source reads that a locale lacks, a catalog key nothing reads). `HFS_DEP_VERSION_SKEW` (R14) also refuses a dependency declared at another version than the root `overrides` pin.
|
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
|
-
|
|
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.
|
|
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",
|
|
@@ -17,7 +17,7 @@ pins:
|
|
|
17
17
|
source: packages/grammar/package.json
|
|
18
18
|
why: nivo-fe pins 0.4.11 and 0.5.0 in one workspace, starci-next-fe 0.5.1, miamia-fe 0.5.0; the runtime source is 0.7.2 (Input tel kind and IconButton disclosure props).
|
|
19
19
|
'@starci/eslint-canon-be':
|
|
20
|
-
version: 2.0.
|
|
20
|
+
version: 2.0.1
|
|
21
21
|
group: starci
|
|
22
22
|
install: registry
|
|
23
23
|
side: be
|
|
@@ -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.
|
|
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 (
|
|
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
|
-
|
|
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
|
package/sync/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import { createRequire } from 'node:module';
|
|
|
15
15
|
import fs from 'node:fs';
|
|
16
16
|
import path from 'node:path';
|
|
17
17
|
import { braceVariants } from '../runtime/scripts/lib/glob.mjs';
|
|
18
|
-
import { loadSlotManifest } from '../runtime/scripts/lib/hfs-slots.mjs';
|
|
18
|
+
import { loadSlotManifest, resolveRepoDeclaration } from '../runtime/scripts/lib/hfs-slots.mjs';
|
|
19
19
|
import { readDeclaredSonarKey } from './sonar-key.mjs';
|
|
20
20
|
|
|
21
21
|
export const TEMPLATES_DIR = path.join(import.meta.dirname, '..', 'templates');
|
|
@@ -87,6 +87,13 @@ export function validateHfs(hfs, manifest = loadSlotManifest()) {
|
|
|
87
87
|
if (hfs.profile === 'be' && !manifest.appKinds.be.includes(app.kind)) bad(`app ${app.name} needs a kind, one of ${manifest.appKinds.be.join(', ')}`);
|
|
88
88
|
seen.add(app.name);
|
|
89
89
|
}
|
|
90
|
+
// The whole declaration must be valid for the manifest it pins (connections, optional slots, ...): sync never renders
|
|
91
|
+
// configs for a declaration the eslint canons and hfs check would refuse, so a pin bump cannot leave lint unable to start.
|
|
92
|
+
try {
|
|
93
|
+
resolveRepoDeclaration(manifest, hfs);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
bad(`hfs.json is not a valid declaration for manifest ${manifest.version}: ${error.message}`);
|
|
96
|
+
}
|
|
90
97
|
return hfs;
|
|
91
98
|
}
|
|
92
99
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"test:integration": "npm run typecheck:tests && jest --selectProjects integration",
|
|
15
15
|
"test:e2e": "npm run typecheck:tests && jest --selectProjects e2e",
|
|
16
16
|
"test:contract": "npm run typecheck:tests && jest --selectProjects contract",
|
|
17
|
+
"test:stack": "starci-test-stack",
|
|
17
18
|
"contract:emit": "hfs emit-contracts",
|
|
18
19
|
"hfs:check": "hfs check",
|
|
19
20
|
"hfs:report": "hfs check --sonar reports/hfs.sonar.json"
|