@starci/eslint-canon-fe 8.0.1 → 8.0.3
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 +8 -0
- package/package.json +1 -1
- package/runtime/knowledge/hfs/canon-pins.yaml +13 -13
- package/runtime/knowledge/hfs/slots.yaml +26 -26
- package/runtime/scripts/checks/architecture/connection-map.mjs +5 -2
- package/runtime/scripts/checks/architecture/hfs.mjs +2 -2
- package/runtime/scripts/checks/architecture/test-world-files.mjs +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.0.3 - 2026-10-01
|
|
4
|
+
|
|
5
|
+
- Changed: the bundled canon-pins copy pins @starci/stylelint-canon 2.0.2, @starci/eslint-canon-be 3.0.3 and @starci/hfs 4.0.3. No rule changed.
|
|
6
|
+
|
|
7
|
+
## 8.0.2 - 2026-10-01
|
|
8
|
+
|
|
9
|
+
- Changed: the bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put `.starcistacks` and `.sops.yaml` at the app root (`app.starcistacks`, `app.sops`; a side holding either is refused, `HFS_STACKS_IN_SIDE`) and pin @starci/hfs 4.0.2 and this canon at 8.0.2. No lint rule changed.
|
|
10
|
+
|
|
3
11
|
## 8.0.1 - 2026-10-01
|
|
4
12
|
|
|
5
13
|
- Changed: the bundled runtime copy of knowledge/hfs/canon-pins.yaml pins @starci/hfs 4.0.1 (the scaffold resolves a real lockfile) and this canon at 8.0.1. No rule changed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starci/eslint-canon-fe",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.3",
|
|
4
4
|
"description": "The StarCi front-end lint canon: every rule its laws publish, gathered as one flat-config plugin and attached by one factory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -17,35 +17,35 @@ pins:
|
|
|
17
17
|
# --- @starci packages. Every @starci package is a PUBLISHED npm package (install: registry): a product repository
|
|
18
18
|
# installs the exact pinned version from the npm registry in the root and every workspace package.json, never `file:`.
|
|
19
19
|
'@starci/grammar':
|
|
20
|
-
version: 0.8.
|
|
20
|
+
version: 0.8.1
|
|
21
21
|
group: starci
|
|
22
22
|
install: registry
|
|
23
23
|
side: fe
|
|
24
24
|
source: packages/grammar/package.json
|
|
25
25
|
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.8.0 (the brand layer sets `--font-sans` and `--font-mono`; the grammar reads them; 0.7.2 added the Input tel kind and IconButton disclosure props).
|
|
26
26
|
'@starci/eslint-canon-be':
|
|
27
|
-
version: 3.0.
|
|
27
|
+
version: 3.0.3
|
|
28
28
|
group: starci
|
|
29
29
|
install: registry
|
|
30
30
|
side: be
|
|
31
31
|
source: packages/eslint/be/package.json
|
|
32
|
-
why: '3.0.1: its bundled canon-pins copy pins hfs 4.0.1. 3.0.0: `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; the project graph is built per side. 2.0.0 (C0 release): starciBeConfig({ hfs: loadHfs(import.meta.url) }) typed factory and the BE-CONVENTION laws.'
|
|
32
|
+
why: '3.0.3: its bundled canon-pins copy pins stylelint-canon 2.0.2 and hfs 4.0.3; no rule changed. 3.0.2: its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root (app.starcistacks, app.sops) and pin hfs 4.0.2. 3.0.1: its bundled canon-pins copy pins hfs 4.0.1. 3.0.0: `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; the project graph is built per side. 2.0.0 (C0 release): starciBeConfig({ hfs: loadHfs(import.meta.url) }) typed factory and the BE-CONVENTION laws.'
|
|
33
33
|
'@starci/eslint-canon-fe':
|
|
34
|
-
version: 8.0.
|
|
34
|
+
version: 8.0.3
|
|
35
35
|
group: starci
|
|
36
36
|
install: registry
|
|
37
37
|
side: fe
|
|
38
38
|
source: packages/eslint/fe/package.json
|
|
39
|
-
why: '8.0.1: its bundled canon-pins copy pins hfs 4.0.1. 8.0.0: `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; the project graph is built per side. 7.0.0: the front end has no tests (FE_NO_TESTS R97 in hfs); no-vietnamese-in-source (R91).'
|
|
39
|
+
why: '8.0.3: its bundled canon-pins copy pins stylelint-canon 2.0.2 and hfs 4.0.3; no rule changed. 8.0.2: its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root (app.starcistacks, app.sops) and pin hfs 4.0.2. 8.0.1: its bundled canon-pins copy pins hfs 4.0.1. 8.0.0: `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; the project graph is built per side. 7.0.0: the front end has no tests (FE_NO_TESTS R97 in hfs); no-vietnamese-in-source (R91).'
|
|
40
40
|
'@starci/stylelint-canon':
|
|
41
|
-
version: 2.0.
|
|
41
|
+
version: 2.0.2
|
|
42
42
|
group: starci
|
|
43
43
|
install: registry
|
|
44
44
|
side: fe
|
|
45
45
|
source: packages/stylelint/package.json
|
|
46
|
-
why: '2.0.1 accepts `--font-sans` and `--font-mono` in the brand layer (the vocabulary follows the grammar 0.8.0). 2.0.0 adds status-contrast (HeroUI soft pairs measured per theme), fixes brand-layer-shape on the shared :root,.light,.dark block and the info soft pair, and derives appTokens with loadAppTokens(import.meta.url) for the managed one-line stylelint.config.mjs.'
|
|
46
|
+
why: '2.0.2: no-class-selector refuses a compound class selector (`div.card`), which the 2.0.1 pattern let through. 2.0.1 accepts `--font-sans` and `--font-mono` in the brand layer (the vocabulary follows the grammar 0.8.0). 2.0.0 adds status-contrast (HeroUI soft pairs measured per theme), fixes brand-layer-shape on the shared :root,.light,.dark block and the info soft pair, and derives appTokens with loadAppTokens(import.meta.url) for the managed one-line stylelint.config.mjs.'
|
|
47
47
|
'@starci/tsconfig':
|
|
48
|
-
version: 2.0.
|
|
48
|
+
version: 2.0.1
|
|
49
49
|
group: starci
|
|
50
50
|
install: registry
|
|
51
51
|
side: both
|
|
@@ -57,26 +57,26 @@ pins:
|
|
|
57
57
|
side: both
|
|
58
58
|
source: packages/prettier-config/package.json
|
|
59
59
|
'@starci/jest-preset':
|
|
60
|
-
version: 2.2.
|
|
60
|
+
version: 2.2.1
|
|
61
61
|
group: starci
|
|
62
62
|
install: registry
|
|
63
63
|
side: be
|
|
64
64
|
source: packages/jest-preset/package.json
|
|
65
65
|
why: '2.2.0: the integration, e2e and contract projects run every spec file in a worker process of its own (world-runner.cjs), so a process-global framework registry (@nestjs/graphql type metadata) never leaks between e2e files; 2.1.0: four projects on the test world, the unit kit (mockEntityManager, fakeTransaction, fakeIds, FakeClock, Outcome matchers) and the recordingOutbox claim side.'
|
|
66
66
|
'@starci/test-world':
|
|
67
|
-
version: 1.0.
|
|
67
|
+
version: 1.0.2
|
|
68
68
|
group: starci
|
|
69
69
|
install: registry
|
|
70
70
|
side: be
|
|
71
71
|
source: packages/test-world/package.json
|
|
72
|
-
why: 'the shared e2e library of every back end (R47, R48): the warm stack behind toxiproxy, the network-edge fakes, the Nest boot, the typed useTestWorld handle, useSandbox for contract specs, the outage lock and the starci-test-stack bin behind the managed test:stack script; a devDependency of every back end.'
|
|
72
|
+
why: '1.0.2: every path a declaration names (`stack`, seeds, the realm, Dockerfiles) resolves from the app root (the directory of hfs.json), where .starcistacks lives, never from the be side. The shared e2e library of every back end (R47, R48): the warm stack behind toxiproxy, the network-edge fakes, the Nest boot, the typed useTestWorld handle, useSandbox for contract specs, the outage lock and the starci-test-stack bin behind the managed test:stack script; a devDependency of every back end. 1.0.1: world.keycloak.events/sessions (the user events of the realm and live sessions through the admin API) and world.infra.postgresql.connection(name) (the database of one connection down while the others serve, under the outage lock).'
|
|
73
73
|
'@starci/hfs':
|
|
74
|
-
version: 4.0.
|
|
74
|
+
version: 4.0.3
|
|
75
75
|
group: starci
|
|
76
76
|
install: registry
|
|
77
77
|
side: both
|
|
78
78
|
source: packages/hfs/package.json
|
|
79
|
-
why: '4.0.1: `hfs scaffold app` resolves the real lockfile with npm (`npm install --package-lock-only`) instead of writing a root-only stub that `npm ci` refuses. 4.0.0: the app monorepo standard: one app repository with the root package.json, lockfile and hfs.json of kind app, and the be/ and fe/ sides; `hfs scaffold app <name>` makes it, `hfs lint` at the root lints be/** with the BE canon and fe/** with the FE canon; the standalone be/fe repository kinds and `hfs init` are deleted.'
|
|
79
|
+
why: '4.0.3: its bundled canon-pins copy pins stylelint-canon 2.0.2, eslint-canon-be 3.0.3 and eslint-canon-fe 8.0.3 (what `hfs scaffold app` writes); the package gains its own clean-install test. 4.0.2: .starcistacks and .sops.yaml live at the app root (slots app.starcistacks, app.sops; a side holding either is refused, HFS_STACKS_IN_SIDE), the managed .gitignore block carries the custody rules, the scaffold writes them at the root. 4.0.1: `hfs scaffold app` resolves the real lockfile with npm (`npm install --package-lock-only`) instead of writing a root-only stub that `npm ci` refuses. 4.0.0: the app monorepo standard: one app repository with the root package.json, lockfile and hfs.json of kind app, and the be/ and fe/ sides; `hfs scaffold app <name>` makes it, `hfs lint` at the root lints be/** with the BE canon and fe/** with the FE canon; the standalone be/fe repository kinds and `hfs init` are deleted.'
|
|
80
80
|
# --- tooling
|
|
81
81
|
typescript:
|
|
82
82
|
version: 5.9.3
|
|
@@ -321,6 +321,27 @@ slots:
|
|
|
321
321
|
"features/<feature>/uat/<name>/{seed,cleanup}.sql", "_resources/{identities,environments,fixtures}/<slug>/resource.yaml"]
|
|
322
322
|
forbids: [evidence/, logs/, reports/, captures/, runs/, "kernel-*/", "*.sqlite*", _derived/, "work/node records"]
|
|
323
323
|
rules: [HFS_AGENT_DATA_TRACKED, HFS_WORK_NODE_RETIRED, HFS_IDENTITY_CUSTODY]
|
|
324
|
+
- id: app.starcistacks
|
|
325
|
+
profiles: [app]
|
|
326
|
+
# The stack declarations and the sealed custody of the app, at the app root beside be/, fe/ and .starciwork (never under a side).
|
|
327
|
+
path: ".starcistacks/"
|
|
328
|
+
presence: required
|
|
329
|
+
tracked: tracked
|
|
330
|
+
tier: none
|
|
331
|
+
tests: none
|
|
332
|
+
requires: [application-stacks.yaml]
|
|
333
|
+
allows: [application-stacks.yaml, "<env>/README.md", "<env>/environment.json", "<env>/infra/{compose,k8s,terraform}/**", "<env>/infra/metadata.json",
|
|
334
|
+
"<env>/runtime/{config,env}/**", "<env>/runtime/env/KEYS.md", "<env>/secrets/<slug>.enc", "<env>/seeds/**"]
|
|
335
|
+
forbids: ["<env>/runtime/files/**", "**/*.enc outside <env>/secrets/", DESIGN.md, deployment.json, "k8s/ at root"]
|
|
336
|
+
rules: [HFS_STACKS_SHAPE, HFS_STACKS_IN_SIDE, HFS_PLAINTEXT_SECRET, HFS_IDENTITY_CUSTODY]
|
|
337
|
+
- id: app.sops
|
|
338
|
+
profiles: [app]
|
|
339
|
+
# The sops custody rule of .starcistacks/<env>/secrets/*.enc, at the app root beside the tree it seals.
|
|
340
|
+
path: .sops.yaml
|
|
341
|
+
presence: required
|
|
342
|
+
tracked: tracked
|
|
343
|
+
tier: none
|
|
344
|
+
tests: none
|
|
324
345
|
- id: app.build-output
|
|
325
346
|
profiles: [app]
|
|
326
347
|
path: "{**/node_modules/,coverage/,reports/,test-results/,**/*.tsbuildinfo}"
|
|
@@ -360,18 +381,18 @@ slots:
|
|
|
360
381
|
tracked: external
|
|
361
382
|
tier: none
|
|
362
383
|
tests: none
|
|
363
|
-
goesTo: "
|
|
384
|
+
goesTo: ".starcistacks/<env>/secrets/<slug>.enc (at the app root); decrypted values only in memory or under %LOCALAPPDATA%/StarCi/secrets/<project>/<env>/ via *_FILE"
|
|
364
385
|
rules: [HFS_PLAINTEXT_SECRET]
|
|
365
386
|
|
|
366
387
|
# ----- side root (both sides): what the old standalone repository root held, less the app-root files ----------
|
|
367
388
|
- id: repo.side-root-forbidden
|
|
368
389
|
profiles: [be, fe]
|
|
369
|
-
path: "{package.json,package-lock.json,hfs.json,README.md,.gitignore,.gitattributes,.husky/,.github/,.starciwork
|
|
390
|
+
path: "{package.json,package-lock.json,hfs.json,README.md,.gitignore,.gitattributes,.husky/,.github/,.starciwork/,.starcistacks/,.sops.yaml,sonar-project.properties,.prettierrc,.prettierignore,scripts/}"
|
|
370
391
|
presence: forbidden
|
|
371
392
|
tracked: external
|
|
372
393
|
tier: none
|
|
373
394
|
tests: none
|
|
374
|
-
goesTo: "the app root: one package.json, lockfile, hfs.json, README, git and CI files, hooks, formatter, Sonar configuration, scripts
|
|
395
|
+
goesTo: "the app root: one package.json, lockfile, hfs.json, README, git and CI files, hooks, formatter, Sonar configuration, scripts/, .starciwork, .starcistacks and .sops.yaml per app"
|
|
375
396
|
- id: be.tool-config
|
|
376
397
|
profiles: [be]
|
|
377
398
|
# Managed files (hfs sync renders them, hfs check compares them): the whole tool configuration of a back end. Each is
|
|
@@ -529,7 +550,7 @@ slots:
|
|
|
529
550
|
tracked: external
|
|
530
551
|
tier: none
|
|
531
552
|
tests: none
|
|
532
|
-
goesTo: "
|
|
553
|
+
goesTo: ".starcistacks/<env>/secrets/<slug>.enc (at the app root); decrypted values only in memory or under %LOCALAPPDATA%/StarCi/secrets/<project>/<env>/ via *_FILE"
|
|
533
554
|
rules: [HFS_PLAINTEXT_SECRET]
|
|
534
555
|
- id: be.root-e2e
|
|
535
556
|
profiles: [be]
|
|
@@ -825,7 +846,7 @@ slots:
|
|
|
825
846
|
infrastructure (containers) and runs apps/migrate's exported bootstrap once; use-test-world.ts exports
|
|
826
847
|
useTestWorld({ apps: { <name>: { module, listen? } } } | { modules: [...] }) -> world.apps.<name>.api,
|
|
827
848
|
world.db.<connection> (the shared EntityManager), world.infra.<service> (latency/cut/restore on a REAL service of the repository's
|
|
828
|
-
own stack, `.starcistacks/<env>`, each behind toxiproxy), world.fake.<provider> (a network-edge fake of an external SaaS started by the world, with
|
|
849
|
+
own stack, the app root's `.starcistacks/<env>`, each behind toxiproxy), world.fake.<provider> (a network-edge fake of an external SaaS started by the world, with
|
|
829
850
|
failNext/replayWebhook/delay), world.waitFor; fakes/<provider>/ holds the fake servers and payload fixtures, kit/ the inlined test helpers, and the world root may hold role-suffixed helpers (<name>.client.ts, <name>.contracts.ts, ...). Nothing is
|
|
830
851
|
overridden in the DI container. It is the only test location that may import typeorm's DataSource or testcontainers,
|
|
831
852
|
call migrate/runMigrations/synchronize, or write process.env.
|
|
@@ -905,27 +926,6 @@ slots:
|
|
|
905
926
|
tests: none
|
|
906
927
|
goesTo: "src/tests/world/ (the only test infrastructure location; e2e/<area>/ holds only *.e2e-spec.ts)"
|
|
907
928
|
|
|
908
|
-
# ----- BE: work and stacks -----------------------------------------------------------------------------
|
|
909
|
-
- id: be.starcistacks
|
|
910
|
-
profiles: [be]
|
|
911
|
-
path: ".starcistacks/"
|
|
912
|
-
presence: required
|
|
913
|
-
tracked: tracked
|
|
914
|
-
tier: none
|
|
915
|
-
tests: none
|
|
916
|
-
requires: [application-stacks.yaml]
|
|
917
|
-
allows: [application-stacks.yaml, "<env>/README.md", "<env>/environment.json", "<env>/infra/{compose,k8s,terraform}/**", "<env>/infra/metadata.json",
|
|
918
|
-
"<env>/runtime/{config,env}/**", "<env>/runtime/env/KEYS.md", "<env>/secrets/<slug>.enc", "<env>/seeds/**"]
|
|
919
|
-
forbids: ["<env>/runtime/files/**", "**/*.enc outside <env>/secrets/", DESIGN.md, deployment.json, "k8s/ at root"]
|
|
920
|
-
rules: [HFS_STACKS_SHAPE, HFS_PLAINTEXT_SECRET, HFS_IDENTITY_CUSTODY]
|
|
921
|
-
- id: be.sops
|
|
922
|
-
profiles: [be]
|
|
923
|
-
path: .sops.yaml
|
|
924
|
-
presence: required
|
|
925
|
-
tracked: tracked
|
|
926
|
-
tier: none
|
|
927
|
-
tests: none
|
|
928
|
-
|
|
929
929
|
# ----- FE: apps ----------------------------------------------------------------------------------------
|
|
930
930
|
- id: fe.app.next
|
|
931
931
|
profiles: [fe]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { machineKit, pascal, upperSnake } from './machine-ast.mjs';
|
|
4
|
+
import { locateDeclaration } from '../../lib/hfs-slots.mjs';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* R84 `connection-map` (BE_CONNECTION_DUPLICATE), folding RED01 and RED02. One physical database is one connection, one
|
|
@@ -179,11 +180,13 @@ export function checkConnectionMap(input) {
|
|
|
179
180
|
// 4. Stacks: two connections that resolve to one host, port and database are one database.
|
|
180
181
|
let stacksChecked = 0;
|
|
181
182
|
let stacksSkipped = 0;
|
|
182
|
-
|
|
183
|
+
// .starcistacks sits at the app root: the side folder the machine judges reads its app's tree (locateDeclaration).
|
|
184
|
+
const stacksRoot = path.join(locateDeclaration(config.root).appRoot, '.starcistacks');
|
|
183
185
|
let envs = [];
|
|
184
186
|
try { envs = fs.readdirSync(stacksRoot, { withFileTypes: true }).filter(entry => entry.isDirectory()).map(entry => entry.name).sort(); } catch { envs = []; }
|
|
185
187
|
for (const env of envs) {
|
|
186
|
-
|
|
188
|
+
// Relative to the side folder the machine judges (`../.starcistacks/...` for a side): the app-relative path once the side is prefixed.
|
|
189
|
+
const rel = path.relative(config.root, path.join(stacksRoot, env, 'runtime', 'env')).split(path.sep).join('/');
|
|
187
190
|
const values = readEnvFiles(path.join(stacksRoot, env, 'runtime', 'env'));
|
|
188
191
|
if (!values || values.size === 0) { stacksSkipped += 1; continue; }
|
|
189
192
|
const seen = new Map();
|
|
@@ -36,7 +36,7 @@ export const HFS_RULE_IDS = [
|
|
|
36
36
|
'HFS_ROOT_MARKDOWN_FORBIDDEN',
|
|
37
37
|
'HFS_ROOT_SRC_FORBIDDEN_FE',
|
|
38
38
|
'HFS_SRC_LAYOUT_INVALID',
|
|
39
|
-
'
|
|
39
|
+
'HFS_STACKS_IN_SIDE',
|
|
40
40
|
'HFS_TEST_KIND_RETIRED',
|
|
41
41
|
'HFS_WORK_IN_FE',
|
|
42
42
|
];
|
|
@@ -423,9 +423,9 @@ export function checkHfs(config) {
|
|
|
423
423
|
const allowed = slotRootEntries(resolver, profile);
|
|
424
424
|
for (const entry of [...tree.top].sort()) {
|
|
425
425
|
if (NON_NPM_ENTRIES.has(entry) || /\.md$/iu.test(entry)) continue;
|
|
426
|
+
if (entry === '.starcistacks') { finding('HFS_STACKS_IN_SIDE', entry, `The ${profile} side must not hold .starcistacks; stack declarations and sealed custody live in the app root .starcistacks.`); continue; }
|
|
426
427
|
if (frontend && !backend) {
|
|
427
428
|
if (entry === '.starciwork') { finding('HFS_WORK_IN_FE', entry, 'The fe side must not hold a .starciwork tree; Work records live in the app root .starciwork.'); continue; }
|
|
428
|
-
if (entry === '.starcistacks') { finding('HFS_STACKS_IN_FE', entry, 'The fe side must not hold .starcistacks; stack declarations live in be/.starcistacks.'); continue; }
|
|
429
429
|
if (entry === 'src') { finding('HFS_ROOT_SRC_FORBIDDEN_FE', entry, 'The fe side keeps source only under apps/<app>/src; the fe/src/ tree must move.'); continue; }
|
|
430
430
|
}
|
|
431
431
|
if (frontend && !backend && (isFeTestPath(entry) || isFeTestPath(`${entry}/x`))) continue; // a test entry of a front end is FE_NO_TESTS's, the one finding of that path
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { treeOf } from './required-files.mjs';
|
|
2
2
|
import { allowsFile } from '../../lib/hfs-allows.mjs';
|
|
3
|
+
import { locateDeclaration } from '../../lib/hfs-slots.mjs';
|
|
3
4
|
import { DEFAULT_ENVIRONMENT, STACKS_DIRECTORY, STATEFUL_KINDS, namesOfService, readStack } from '../../lib/stack-services.mjs';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -159,7 +160,8 @@ export function checkTestWorldFiles(input) {
|
|
|
159
160
|
const services = [];
|
|
160
161
|
for (const environment of environments) {
|
|
161
162
|
let stack = null;
|
|
162
|
-
|
|
163
|
+
// The stack is the app root's .starcistacks: the side folder the machine judges reads its app's (locateDeclaration).
|
|
164
|
+
try { stack = readStack({ root: locateDeclaration(config.root).appRoot, environment }); } catch { stack = null; }
|
|
163
165
|
for (const service of stack?.services ?? []) if (service.role !== 'service' && !services.some(known => known.name === service.name)) services.push({ ...service, environment });
|
|
164
166
|
}
|
|
165
167
|
const stackHint = `${STACKS_DIRECTORY}/${environments.join(', ')}`;
|