@starci/eslint-canon-fe 9.13.1 → 9.13.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
|
+
## 9.13.2 - 2026-11-04
|
|
4
|
+
|
|
5
|
+
- Changed: the runtime copies carry `engine/runtime-root.mjs` with the per-user state base of an installed copy (`@starci/hfs` 5.6.0) and the canon pins of release 4 (`@starci/auth` 0.4.0, `@starci/auth-oidc` 0.1.3).
|
|
6
|
+
|
|
3
7
|
## 9.13.1 - 2026-11-04
|
|
4
8
|
|
|
5
9
|
- Changed: the runtime copy of the canon pins names the release-3 versions (`@starci/hfs` 5.5.1, `@starci/jest-preset` 2.7.1, `@starci/eslint-canon-be` 3.15.1, the Grammar family 0.21.18).
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import { parseYaml } from './yaml.mjs';
|
|
@@ -24,17 +25,75 @@ export const LOCAL_ROOT_ENV = 'STARCI_LOCAL_ROOT';
|
|
|
24
25
|
/** The host-data directory of a runtime root. Git-ignored and never packed; the example fixtures under examples/.runtimes are a separate, public exception. */
|
|
25
26
|
export const RUNTIME_STATE_DIR = '.runtime';
|
|
26
27
|
/**
|
|
27
|
-
* <root>/.runtime
|
|
28
|
-
*
|
|
29
|
-
* state), and `starci runtime link` merely points the launcher at a root, so the state follows the code's own location.
|
|
28
|
+
* <root>/.runtime, the state base of a runtime root that is a checkout (the harness repository, or a copy of it placed on the host).
|
|
29
|
+
* An installed or locally sourced copy keeps none (see installedStateBase).
|
|
30
30
|
*/
|
|
31
31
|
export const runtimeStateDir = (root = skillRoot) => path.join(root, RUNTIME_STATE_DIR);
|
|
32
|
+
/** True when `root` is a copy an install or `starci deps source --local` placed below a node_modules folder, not a checkout. */
|
|
33
|
+
export const installedRoot = (root = skillRoot) => path.resolve(root).split(/[\\/]/).includes('node_modules');
|
|
34
|
+
/**
|
|
35
|
+
* The per-user state base of an installed copy: LOCALAPPDATA (Windows), else XDG_STATE_HOME, else ~/.local/state, then
|
|
36
|
+
* starci-harness/state. It lies outside every package and every product repository, so `npm ci` and a package copy never delete a
|
|
37
|
+
* running stack's data, and every installed copy on the host shares one machine.sqlite and one stack/<project>/<env> per environment.
|
|
38
|
+
*/
|
|
39
|
+
export const installedStateBase = (env = process.env) => path.join(env['LOCALAPPDATA'] || env['XDG_STATE_HOME'] || path.join(os.homedir(), '.local', 'state'), 'starci-harness', 'state');
|
|
32
40
|
/**
|
|
33
41
|
* The per-host state base, the one owner of every host-state location: machine.sqlite, projects/<ledger_id>/runtime.sqlite, archive/,
|
|
34
|
-
* artifacts/ (the blob store), guards/, host-lock
|
|
35
|
-
*
|
|
42
|
+
* artifacts/ (the blob store), guards/, host-lock/, stack/<project>/<env>/ and the other process state sit under it. LOCAL_ROOT_ENV
|
|
43
|
+
* replaces it wholesale; else a checkout keeps it in <runtime root>/.runtime and an installed copy in installedStateBase.
|
|
44
|
+
*/
|
|
45
|
+
export const starciLocalRoot = (env = process.env, root = skillRoot) => {
|
|
46
|
+
if (env[LOCAL_ROOT_ENV])
|
|
47
|
+
return path.resolve(env[LOCAL_ROOT_ENV]);
|
|
48
|
+
return installedRoot(root) ? installedStateBase(env) : runtimeStateDir(root);
|
|
49
|
+
};
|
|
50
|
+
/** The refusal of a legacy state base a running process still holds (a stack's bind mounts, an open log). */
|
|
51
|
+
export class LegacyStateHeld extends Error {
|
|
52
|
+
code = 'HFS_STATE_LEGACY_HELD';
|
|
53
|
+
legacy;
|
|
54
|
+
constructor(legacy, cause) {
|
|
55
|
+
super(`${legacy} holds the state of a running stack and cannot move out of the package yet; run \`starci app stack down --env <env>\` for each running environment, then any \`starci app\` verb moves it`, { cause });
|
|
56
|
+
this.legacy = legacy;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const HELD = new Set(['EPERM', 'EBUSY', 'EACCES']);
|
|
60
|
+
const isHeld = (error) => HELD.has(String(error?.code));
|
|
61
|
+
/**
|
|
62
|
+
* Moves the state an installed copy kept inside itself (<copy>/.runtime, before installedStateBase) out to the state base, once: the
|
|
63
|
+
* folder is first renamed to <copy>/.runtime.adopting (a rename a running stack's open files refuse, LegacyStateHeld), then copied
|
|
64
|
+
* entry by entry and removed. An entry the state base already holds is kept beside it under legacy-<stamp>/, never overwritten. An
|
|
65
|
+
* interrupted adoption resumes from .runtime.adopting. Null when there is nothing to adopt: a checkout, LOCAL_ROOT_ENV set, or no
|
|
66
|
+
* legacy folder.
|
|
36
67
|
*/
|
|
37
|
-
export
|
|
68
|
+
export function adoptLegacyState(env = process.env, root = skillRoot, now = () => new Date()) {
|
|
69
|
+
if (env[LOCAL_ROOT_ENV] || !installedRoot(root))
|
|
70
|
+
return null;
|
|
71
|
+
const from = runtimeStateDir(root);
|
|
72
|
+
const parked = `${from}.adopting`;
|
|
73
|
+
if (!fs.existsSync(parked)) {
|
|
74
|
+
if (!fs.existsSync(from))
|
|
75
|
+
return null;
|
|
76
|
+
try {
|
|
77
|
+
fs.renameSync(from, parked);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (isHeld(error))
|
|
81
|
+
throw new LegacyStateHeld(from, error);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const to = installedStateBase(env);
|
|
86
|
+
const aside = path.join(to, `legacy-${now().toISOString().replace(/[^0-9]/g, '').slice(0, 14)}`);
|
|
87
|
+
const moved = [];
|
|
88
|
+
const kept = [];
|
|
89
|
+
for (const name of fs.readdirSync(parked).sort()) {
|
|
90
|
+
const taken = fs.existsSync(path.join(to, name));
|
|
91
|
+
fs.cpSync(path.join(parked, name), path.join(taken ? aside : to, name), { recursive: true, verbatimSymlinks: true, errorOnExist: true, force: false });
|
|
92
|
+
(taken ? kept : moved).push(name);
|
|
93
|
+
}
|
|
94
|
+
fs.rmSync(parked, { recursive: true, force: true });
|
|
95
|
+
return { from, to, moved, kept };
|
|
96
|
+
}
|
|
38
97
|
/**
|
|
39
98
|
* Read a runtime contract document. `parts` are path segments under `skillRoot`
|
|
40
99
|
* (e.g. readModuleJson('modules', 'models', 'kinds.yaml')).
|
|
@@ -38,7 +38,7 @@ pins:
|
|
|
38
38
|
source: packages/next-data/package.json
|
|
39
39
|
why: 'the SWR data helpers of every front end (fe-stack data, owner:next-data-package): pollingRestart, the viewer and tenant key helpers, viewerSwrConfig and the viewer cache; each operation hook stays in the app and the package holds no component.'
|
|
40
40
|
'@starci/grammar':
|
|
41
|
-
version: 0.21.
|
|
41
|
+
version: 0.21.19
|
|
42
42
|
group: starci
|
|
43
43
|
install: registry
|
|
44
44
|
side: fe
|
|
@@ -52,28 +52,28 @@ pins:
|
|
|
52
52
|
source: packages/next-i18n/package.json
|
|
53
53
|
why: 'the next-intl stack of every front end (fe-stack i18n, owner:next-i18n-package): defineI18n over the locales of the app, the locale-negotiating proxy, the locale-aware navigation, the request config that loads the catalogs of the app and the locale read of the [locale] layout; the app keeps its message catalogs and writes none of the stack.'
|
|
54
54
|
'@starci/eslint-canon-be':
|
|
55
|
-
version: 3.15.
|
|
55
|
+
version: 3.15.2
|
|
56
56
|
group: starci
|
|
57
57
|
install: registry
|
|
58
58
|
side: be
|
|
59
59
|
source: packages/eslint-canon-be/package.json
|
|
60
60
|
why: 'the back-end ESLint canon: `loadHfs(import.meta.url)` of be/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the be side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; `starciBeConfig({ hfs: loadHfs(import.meta.url) })` is the typed factory and the BE-CONVENTION laws are its rules.'
|
|
61
61
|
'@starci/eslint-canon-fe':
|
|
62
|
-
version: 9.13.
|
|
62
|
+
version: 9.13.2
|
|
63
63
|
group: starci
|
|
64
64
|
install: registry
|
|
65
65
|
side: fe
|
|
66
66
|
source: packages/eslint-canon-fe/package.json
|
|
67
67
|
why: 'the front-end ESLint canon: `loadHfs(import.meta.url)` of fe/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the fe side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; the front end has no tests (FE_NO_TESTS R97 in hfs) and no-vietnamese-in-source (R91) applies.'
|
|
68
68
|
'@starci/eslint-grammar-core':
|
|
69
|
-
version: 0.21.
|
|
69
|
+
version: 0.21.19
|
|
70
70
|
group: starci
|
|
71
71
|
install: registry
|
|
72
72
|
side: fe
|
|
73
73
|
source: packages/eslint-grammar-core/package.json
|
|
74
74
|
why: 'the StarCi Grammar component API lint, versioned with @starci/grammar; front ends compose this family package with the universal FE canon.'
|
|
75
75
|
'@starci/eslint-grammar-offset-pop':
|
|
76
|
-
version: 0.21.
|
|
76
|
+
version: 0.21.19
|
|
77
77
|
group: starci
|
|
78
78
|
install: registry
|
|
79
79
|
side: fe
|
|
@@ -127,14 +127,14 @@ pins:
|
|
|
127
127
|
source: packages/nest-kit/package.json
|
|
128
128
|
why: 'the module definition of every back-end module: defineConfigurableModule and defineCapabilityModule return the module base class, the options token and the options types with their types stated, so a <x>.module-definition.ts is one call that the lint on stated export types (R368) and the duplicate-code check (R21) both accept; @starci/jest-preset compiles it as an ESM-only dependency.'
|
|
129
129
|
'@starci/auth':
|
|
130
|
-
version: 0.
|
|
130
|
+
version: 0.4.0
|
|
131
131
|
group: starci
|
|
132
132
|
install: registry
|
|
133
133
|
side: both
|
|
134
134
|
source: packages/auth/package.json
|
|
135
135
|
why: 'the lite sign-in: the NestJS module (EdDSA access tokens with a multi-key JWKS, passwords, Google OAuth with state and PKCE, rotating refresh sessions, the sign-in budget, the refresh cookie), the front-end client and its React bindings, the door contracts and test doubles; the one importer of the identity libraries, reached by a back end only through integrations/passport; @starci/jest-preset compiles it as an ESM-only dependency.'
|
|
136
136
|
'@starci/auth-oidc':
|
|
137
|
-
version: 0.1.
|
|
137
|
+
version: 0.1.3
|
|
138
138
|
group: starci
|
|
139
139
|
install: registry
|
|
140
140
|
side: both
|
|
@@ -155,7 +155,7 @@ pins:
|
|
|
155
155
|
source: packages/mail/package.json
|
|
156
156
|
why: 'outgoing mail of a back end: a NestJS module and the Mailer port over SMTP (connect, greeting, socket and total timeouts, STARTTLS required by default, recipient, message and attachment checks, a shared SMTP target policy, coded errors, typed escaping render helpers returning { subject, text, html }), with @starci/mail/testing for its specs; the only importer of nodemailer (R90).'
|
|
157
157
|
'@starci/hfs':
|
|
158
|
-
version: 5.
|
|
158
|
+
version: 5.6.0
|
|
159
159
|
group: starci
|
|
160
160
|
install: registry
|
|
161
161
|
side: both
|