@starci/eslint-canon-fe 9.5.23 → 9.6.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 +12 -0
- package/docs/button-intent.md +1 -1
- package/package.json +1 -1
- package/runtime/bundle.json +192 -0
- package/runtime/engine/by-code-unit.mjs +6 -6
- package/runtime/engine/model-config.mjs +98 -76
- package/runtime/engine/orca-config.mjs +22 -17
- package/runtime/engine/release-config.mjs +22 -18
- package/runtime/engine/removed-vocabulary.mjs +21 -20
- package/runtime/engine/resources-config.mjs +42 -35
- package/runtime/engine/runtime-root.mjs +11 -13
- package/runtime/engine/secrets.mjs +170 -102
- package/runtime/engine/sonar-config.mjs +16 -13
- package/runtime/engine/temp-root.mjs +3 -9
- package/runtime/knowledge/hfs/canon-pins.yaml +10 -10
- package/runtime/knowledge/hfs/slots.yaml +2 -2
- package/runtime/knowledge/sonar-gate.yaml +1 -1
- package/runtime/packages/hfs/templates/app/package-scripts/package.json +1 -1
- package/runtime/scripts/api/git/cat-file.mjs +0 -1
- package/runtime/scripts/api/git/config-get.mjs +1 -2
- package/runtime/scripts/api/git/diff.mjs +0 -1
- package/runtime/scripts/api/git/lib.mjs +32 -32
- package/runtime/scripts/api/git/ls-files.mjs +0 -1
- package/runtime/scripts/api/git/ls-tree.mjs +0 -1
- package/runtime/scripts/api/git/merge-base.mjs +2 -3
- package/runtime/scripts/api/git/remote.mjs +0 -1
- package/runtime/scripts/api/git/rev-parse-query.mjs +0 -1
- package/runtime/scripts/api/git/show.mjs +0 -1
- package/runtime/scripts/hfs/allows.mjs +37 -38
- package/runtime/scripts/hfs/architecture/ast-walks.mjs +180 -163
- package/runtime/scripts/hfs/architecture/automatic-gates.mjs +80 -73
- package/runtime/scripts/hfs/architecture/backend-app-files.mjs +88 -77
- package/runtime/scripts/hfs/architecture/backend.mjs +378 -357
- package/runtime/scripts/hfs/architecture/background-unowned.mjs +201 -187
- package/runtime/scripts/hfs/architecture/canon-clones.mjs +260 -209
- package/runtime/scripts/hfs/architecture/canon-jsx-clones.mjs +149 -116
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +72 -68
- package/runtime/scripts/hfs/architecture/clones.mjs +212 -217
- package/runtime/scripts/hfs/architecture/config-unread.mjs +7 -9
- package/runtime/scripts/hfs/architecture/config.mjs +302 -268
- package/runtime/scripts/hfs/architecture/connection-map.mjs +258 -225
- package/runtime/scripts/hfs/architecture/constructor-deps.mjs +80 -71
- package/runtime/scripts/hfs/architecture/context-coupling.mjs +82 -77
- package/runtime/scripts/hfs/architecture/context-map.mjs +267 -234
- package/runtime/scripts/hfs/architecture/context-owner.mjs +73 -61
- package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -43
- package/runtime/scripts/hfs/architecture/context-transaction.mjs +54 -52
- package/runtime/scripts/hfs/architecture/contract-fixture-guard.mjs +113 -104
- package/runtime/scripts/hfs/architecture/contracts-readonly.mjs +288 -270
- package/runtime/scripts/hfs/architecture/contracts.mjs +408 -393
- package/runtime/scripts/hfs/architecture/cross-app-duplicate.mjs +50 -51
- package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +143 -119
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +286 -228
- package/runtime/scripts/hfs/architecture/default-deny.mjs +129 -110
- package/runtime/scripts/hfs/architecture/doc-language.mjs +24 -19
- package/runtime/scripts/hfs/architecture/entity-registry.mjs +20 -22
- package/runtime/scripts/hfs/architecture/entrypoint.mjs +47 -45
- package/runtime/scripts/hfs/architecture/error-codes.mjs +37 -35
- package/runtime/scripts/hfs/architecture/error-masked.mjs +55 -59
- package/runtime/scripts/hfs/architecture/fe-slot-allows.mjs +24 -23
- package/runtime/scripts/hfs/architecture/feature-shape.mjs +40 -38
- package/runtime/scripts/hfs/architecture/framework-pinned.mjs +21 -21
- package/runtime/scripts/hfs/architecture/frontend-block-render.mjs +106 -98
- package/runtime/scripts/hfs/architecture/frontend-grammar.mjs +153 -150
- package/runtime/scripts/hfs/architecture/frontend-routing.mjs +161 -149
- package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +343 -305
- package/runtime/scripts/hfs/architecture/frontend-world.mjs +340 -294
- package/runtime/scripts/hfs/architecture/frontend.mjs +174 -184
- package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +124 -106
- package/runtime/scripts/hfs/architecture/hfs-graph.mjs +52 -48
- package/runtime/scripts/hfs/architecture/hooks-are-hooks.mjs +81 -71
- package/runtime/scripts/hfs/architecture/i18n-keys.mjs +155 -141
- package/runtime/scripts/hfs/architecture/identity.mjs +141 -125
- package/runtime/scripts/hfs/architecture/index.mjs +272 -272
- package/runtime/scripts/hfs/architecture/injection-token-exported.mjs +45 -43
- package/runtime/scripts/hfs/architecture/jwt-ast.mjs +195 -176
- package/runtime/scripts/hfs/architecture/machine-ast.mjs +163 -155
- package/runtime/scripts/hfs/architecture/managed-scripts.mjs +19 -20
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +177 -172
- package/runtime/scripts/hfs/architecture/next-data-contract.mjs +100 -78
- package/runtime/scripts/hfs/architecture/next-data-inference.mjs +170 -154
- package/runtime/scripts/hfs/architecture/next-data-key.mjs +311 -275
- package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +17 -17
- package/runtime/scripts/hfs/architecture/next-data.mjs +351 -334
- package/runtime/scripts/hfs/architecture/operation-contract-roots.mjs +39 -37
- package/runtime/scripts/hfs/architecture/owners.mjs +97 -98
- package/runtime/scripts/hfs/architecture/package-shape.mjs +56 -55
- package/runtime/scripts/hfs/architecture/presentation.mjs +138 -130
- package/runtime/scripts/hfs/architecture/reachability.mjs +258 -241
- package/runtime/scripts/hfs/architecture/register-once.mjs +152 -139
- package/runtime/scripts/hfs/architecture/registration.mjs +301 -267
- package/runtime/scripts/hfs/architecture/required-files.mjs +172 -167
- package/runtime/scripts/hfs/architecture/route-files-thin.mjs +85 -77
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +206 -181
- package/runtime/scripts/hfs/architecture/server-action.mjs +48 -48
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +2 -5
- package/runtime/scripts/hfs/architecture/source-names-shape.mjs +261 -259
- package/runtime/scripts/hfs/architecture/source-names.mjs +304 -278
- package/runtime/scripts/hfs/architecture/sql-keys.mjs +277 -194
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +236 -194
- package/runtime/scripts/hfs/architecture/sql-returning.mjs +46 -45
- package/runtime/scripts/hfs/architecture/sql-token-forms.mjs +86 -74
- package/runtime/scripts/hfs/architecture/sql-tokens.mjs +456 -341
- package/runtime/scripts/hfs/architecture/staged-consumers.mjs +35 -30
- package/runtime/scripts/hfs/architecture/surface.mjs +64 -74
- package/runtime/scripts/hfs/architecture/symbols.mjs +209 -216
- package/runtime/scripts/hfs/architecture/test-world-files.mjs +165 -155
- package/runtime/scripts/hfs/architecture/tiers.mjs +161 -154
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +155 -149
- package/runtime/scripts/hfs/architecture/type-context.mjs +255 -250
- package/runtime/scripts/hfs/architecture/typescript.mjs +358 -318
- package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +110 -92
- package/runtime/scripts/hfs/declaration-shape.mjs +140 -103
- package/runtime/scripts/hfs/declaration-slots.mjs +64 -61
- package/runtime/scripts/hfs/edition-slots.mjs +43 -40
- package/runtime/scripts/hfs/linear-text.mjs +20 -20
- package/runtime/scripts/hfs/param-names.mjs +6 -11
- package/runtime/scripts/hfs/path-findings.mjs +120 -100
- package/runtime/scripts/hfs/repo-identity.mjs +55 -42
- package/runtime/scripts/hfs/rule-catalog.mjs +353 -257
- package/runtime/scripts/hfs/rule-params-shape.mjs +60 -47
- package/runtime/scripts/hfs/rules/database-migrations.mjs +428 -388
- package/runtime/scripts/hfs/rules/fe-no-tests.mjs +37 -36
- package/runtime/scripts/hfs/rules/read.mjs +19 -15
- package/runtime/scripts/hfs/rules/secrets.mjs +1 -1
- package/runtime/scripts/hfs/rules/spec-placement.mjs +12 -13
- package/runtime/scripts/hfs/slot-app-view.mjs +69 -74
- package/runtime/scripts/hfs/slot-classify.mjs +42 -38
- package/runtime/scripts/hfs/slot-errors.mjs +8 -7
- package/runtime/scripts/hfs/slot-imports.mjs +70 -63
- package/runtime/scripts/hfs/slot-manifest-shape.mjs +74 -52
- package/runtime/scripts/hfs/slot-match.mjs +122 -111
- package/runtime/scripts/hfs/slot-path.mjs +0 -2
- package/runtime/scripts/hfs/slot-required.mjs +65 -59
- package/runtime/scripts/hfs/slot-semantic-problems.mjs +138 -112
- package/runtime/scripts/hfs/slot-side-problems.mjs +23 -19
- package/runtime/scripts/hfs/slots.mjs +175 -152
- package/runtime/scripts/hfs/test-world-slot.mjs +0 -1
- package/runtime/scripts/hfs/trailing-slashes.mjs +4 -4
- package/runtime/scripts/hfs/typescript-programs.mjs +66 -69
- package/runtime/scripts/hfs/view.mjs +38 -40
- package/runtime/scripts/lib/dockerfile.mjs +131 -114
- package/runtime/scripts/lib/env.mjs +3 -6
- package/runtime/scripts/lib/event-contract.mjs +73 -78
- package/runtime/scripts/lib/git.mjs +15 -16
- package/runtime/scripts/lib/glob.mjs +23 -14
- package/runtime/scripts/lib/grammar-lint.mjs +33 -37
- package/runtime/scripts/lib/i18n.mjs +32 -35
- package/runtime/scripts/lib/in-order.mjs +57 -38
- package/runtime/scripts/lib/json-clone.mjs +45 -36
- package/runtime/scripts/lib/json.mjs +26 -14
- package/runtime/scripts/lib/language.mjs +133 -129
- package/runtime/scripts/lib/list.mjs +9 -14
- package/runtime/scripts/lib/mutation-fence.mjs +10 -5
- package/runtime/scripts/lib/path-key.mjs +53 -38
- package/runtime/scripts/lib/read-text.mjs +30 -17
- package/runtime/scripts/lib/regex.mjs +1 -2
- package/runtime/scripts/lib/same-text.mjs +0 -1
- package/runtime/scripts/lib/sops-envelope.mjs +148 -120
- package/runtime/scripts/lib/stack-services.mjs +128 -129
- package/runtime/scripts/lib/ts-analysis.mjs +28 -26
- package/runtime/scripts/lib/ts-ast.mjs +36 -42
- package/runtime/scripts/lib/walk.mjs +33 -27
- package/runtime/scripts/lib/yaml-cached.mjs +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 9.6.2 - 2026-10-31
|
|
4
|
+
|
|
5
|
+
- Changed: the bundled canon pins name @starci/grammar 0.16.2 (the horizontal Stepper connector line; SurfaceListCard takes its depth from the surface context).
|
|
6
|
+
|
|
7
|
+
## 9.6.1 - 2026-10-30
|
|
8
|
+
|
|
9
|
+
- Changed: the bundled canon pins name @starci/grammar 0.16.1 (accentCorner, Backdrop, the shell filling the viewport).
|
|
10
|
+
|
|
11
|
+
## 9.6.0 - 2026-10-30
|
|
12
|
+
|
|
13
|
+
- Changed: the bundled runtime copies are now generated from the hfs build (TypeScript emitted as .mjs) per runtime/bundle.json, with a drift check in CI; the copies the package keeps as its own are listed there and stay hand-maintained; the bundled canon pins name hfs 4.12.0, eslint-canon-be 3.9.0, eslint-canon-fe 9.6.0, the Grammar family 0.16.0, jest-preset 2.5.3 and test-world 1.3.3. No rule of this package changed.
|
|
14
|
+
|
|
3
15
|
## 9.5.23 - 2026-10-30
|
|
4
16
|
|
|
5
17
|
- Changed: the bundled canon pins name hfs 4.11.22 (app check and lint pass under 20 findings), eslint-canon-be 3.8.21, eslint-canon-fe 9.5.23 and the Grammar family 0.15.34. No rule changed.
|
package/docs/button-intent.md
CHANGED
|
@@ -19,4 +19,4 @@ App `Button` and `IconButton` commands declare `intent`. Grammar derives their v
|
|
|
19
19
|
</AlertDialog>
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
`starci app codemod button-intent` defaults to a dry run. Use `--
|
|
22
|
+
`starci app codemod button-intent` defaults to a dry run. Use `--execute` to apply deterministic mappings, then resolve every case in its JSON and Markdown report from the command's actual consequence. A destructive-looking label is a review signal rather than authority to choose an intent.
|
package/package.json
CHANGED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generated": [
|
|
3
|
+
"config.example.yaml",
|
|
4
|
+
"engine/by-code-unit.mjs",
|
|
5
|
+
"engine/model-config.mjs",
|
|
6
|
+
"engine/orca-config.mjs",
|
|
7
|
+
"engine/plain-object.mjs",
|
|
8
|
+
"engine/release-config.mjs",
|
|
9
|
+
"engine/removed-vocabulary.mjs",
|
|
10
|
+
"engine/resources-config.mjs",
|
|
11
|
+
"engine/runtime-root.mjs",
|
|
12
|
+
"engine/secrets.mjs",
|
|
13
|
+
"engine/sonar-config.mjs",
|
|
14
|
+
"engine/temp-root.mjs",
|
|
15
|
+
"engine/yaml.mjs",
|
|
16
|
+
"knowledge/grammars/index.yaml",
|
|
17
|
+
"knowledge/hfs/canon-pins.yaml",
|
|
18
|
+
"knowledge/hfs/fe-stack.yaml",
|
|
19
|
+
"knowledge/patterns/fe/folder.yaml",
|
|
20
|
+
"knowledge/sonar-gate.yaml",
|
|
21
|
+
"modules/kernel/removed-vocabulary.yaml",
|
|
22
|
+
"modules/models/registry.yaml",
|
|
23
|
+
"modules/models/runtimes.yaml",
|
|
24
|
+
"modules/models/tiers.yaml",
|
|
25
|
+
"scripts/api/git/cat-file.mjs",
|
|
26
|
+
"scripts/api/git/config-get.mjs",
|
|
27
|
+
"scripts/api/git/diff.mjs",
|
|
28
|
+
"scripts/api/git/lib.mjs",
|
|
29
|
+
"scripts/api/git/ls-files.mjs",
|
|
30
|
+
"scripts/api/git/ls-tree.mjs",
|
|
31
|
+
"scripts/api/git/merge-base.mjs",
|
|
32
|
+
"scripts/api/git/remote.mjs",
|
|
33
|
+
"scripts/api/git/rev-parse-query.mjs",
|
|
34
|
+
"scripts/api/git/show.mjs",
|
|
35
|
+
"scripts/hfs/allows.mjs",
|
|
36
|
+
"scripts/hfs/architecture/ast-walks.mjs",
|
|
37
|
+
"scripts/hfs/architecture/automatic-gates.mjs",
|
|
38
|
+
"scripts/hfs/architecture/backend-app-files.mjs",
|
|
39
|
+
"scripts/hfs/architecture/backend.mjs",
|
|
40
|
+
"scripts/hfs/architecture/background-unowned.mjs",
|
|
41
|
+
"scripts/hfs/architecture/canon-clones.mjs",
|
|
42
|
+
"scripts/hfs/architecture/canon-jsx-clones.mjs",
|
|
43
|
+
"scripts/hfs/architecture/client-reaches-server.mjs",
|
|
44
|
+
"scripts/hfs/architecture/clones.mjs",
|
|
45
|
+
"scripts/hfs/architecture/config-unread.mjs",
|
|
46
|
+
"scripts/hfs/architecture/config.mjs",
|
|
47
|
+
"scripts/hfs/architecture/connection-map.mjs",
|
|
48
|
+
"scripts/hfs/architecture/constructor-deps.mjs",
|
|
49
|
+
"scripts/hfs/architecture/context-coupling.mjs",
|
|
50
|
+
"scripts/hfs/architecture/context-map.mjs",
|
|
51
|
+
"scripts/hfs/architecture/context-owner.mjs",
|
|
52
|
+
"scripts/hfs/architecture/context-platform-tables.mjs",
|
|
53
|
+
"scripts/hfs/architecture/context-transaction.mjs",
|
|
54
|
+
"scripts/hfs/architecture/contract-fixture-guard.mjs",
|
|
55
|
+
"scripts/hfs/architecture/contracts-readonly.mjs",
|
|
56
|
+
"scripts/hfs/architecture/contracts.mjs",
|
|
57
|
+
"scripts/hfs/architecture/cross-app-duplicate.mjs",
|
|
58
|
+
"scripts/hfs/architecture/dead-exports-bindings.mjs",
|
|
59
|
+
"scripts/hfs/architecture/dead-exports.mjs",
|
|
60
|
+
"scripts/hfs/architecture/default-deny.mjs",
|
|
61
|
+
"scripts/hfs/architecture/doc-language.mjs",
|
|
62
|
+
"scripts/hfs/architecture/entity-registry.mjs",
|
|
63
|
+
"scripts/hfs/architecture/entrypoint.mjs",
|
|
64
|
+
"scripts/hfs/architecture/error-codes.mjs",
|
|
65
|
+
"scripts/hfs/architecture/error-masked.mjs",
|
|
66
|
+
"scripts/hfs/architecture/fe-slot-allows.mjs",
|
|
67
|
+
"scripts/hfs/architecture/feature-shape.mjs",
|
|
68
|
+
"scripts/hfs/architecture/framework-pinned.mjs",
|
|
69
|
+
"scripts/hfs/architecture/frontend-block-render.mjs",
|
|
70
|
+
"scripts/hfs/architecture/frontend-grammar.mjs",
|
|
71
|
+
"scripts/hfs/architecture/frontend-routing.mjs",
|
|
72
|
+
"scripts/hfs/architecture/frontend-world-render.mjs",
|
|
73
|
+
"scripts/hfs/architecture/frontend-world.mjs",
|
|
74
|
+
"scripts/hfs/architecture/frontend.mjs",
|
|
75
|
+
"scripts/hfs/architecture/function-spec-providers.mjs",
|
|
76
|
+
"scripts/hfs/architecture/hfs-graph.mjs",
|
|
77
|
+
"scripts/hfs/architecture/hooks-are-hooks.mjs",
|
|
78
|
+
"scripts/hfs/architecture/i18n-keys.mjs",
|
|
79
|
+
"scripts/hfs/architecture/identity.mjs",
|
|
80
|
+
"scripts/hfs/architecture/index.mjs",
|
|
81
|
+
"scripts/hfs/architecture/injection-token-exported.mjs",
|
|
82
|
+
"scripts/hfs/architecture/jwt-ast.mjs",
|
|
83
|
+
"scripts/hfs/architecture/machine-ast.mjs",
|
|
84
|
+
"scripts/hfs/architecture/managed-scripts.mjs",
|
|
85
|
+
"scripts/hfs/architecture/module-per-transport.mjs",
|
|
86
|
+
"scripts/hfs/architecture/next-data-contract.mjs",
|
|
87
|
+
"scripts/hfs/architecture/next-data-inference.mjs",
|
|
88
|
+
"scripts/hfs/architecture/next-data-key.mjs",
|
|
89
|
+
"scripts/hfs/architecture/next-data-symbols.mjs",
|
|
90
|
+
"scripts/hfs/architecture/next-data.mjs",
|
|
91
|
+
"scripts/hfs/architecture/operation-contract-roots.mjs",
|
|
92
|
+
"scripts/hfs/architecture/owners.mjs",
|
|
93
|
+
"scripts/hfs/architecture/package-shape.mjs",
|
|
94
|
+
"scripts/hfs/architecture/presentation.mjs",
|
|
95
|
+
"scripts/hfs/architecture/reachability.mjs",
|
|
96
|
+
"scripts/hfs/architecture/register-once.mjs",
|
|
97
|
+
"scripts/hfs/architecture/registration.mjs",
|
|
98
|
+
"scripts/hfs/architecture/required-files.mjs",
|
|
99
|
+
"scripts/hfs/architecture/route-files-thin.mjs",
|
|
100
|
+
"scripts/hfs/architecture/schema-owner.mjs",
|
|
101
|
+
"scripts/hfs/architecture/server-action.mjs",
|
|
102
|
+
"scripts/hfs/architecture/side-boundary.mjs",
|
|
103
|
+
"scripts/hfs/architecture/source-names-shape.mjs",
|
|
104
|
+
"scripts/hfs/architecture/source-names.mjs",
|
|
105
|
+
"scripts/hfs/architecture/sql-keys.mjs",
|
|
106
|
+
"scripts/hfs/architecture/sql-owner.mjs",
|
|
107
|
+
"scripts/hfs/architecture/sql-returning.mjs",
|
|
108
|
+
"scripts/hfs/architecture/sql-token-forms.mjs",
|
|
109
|
+
"scripts/hfs/architecture/sql-tokens.mjs",
|
|
110
|
+
"scripts/hfs/architecture/staged-consumers.mjs",
|
|
111
|
+
"scripts/hfs/architecture/surface.mjs",
|
|
112
|
+
"scripts/hfs/architecture/symbols.mjs",
|
|
113
|
+
"scripts/hfs/architecture/test-world-files.mjs",
|
|
114
|
+
"scripts/hfs/architecture/tiers.mjs",
|
|
115
|
+
"scripts/hfs/architecture/transport-owner.mjs",
|
|
116
|
+
"scripts/hfs/architecture/type-context.mjs",
|
|
117
|
+
"scripts/hfs/architecture/typescript.mjs",
|
|
118
|
+
"scripts/hfs/architecture/unit-spec-providers.mjs",
|
|
119
|
+
"scripts/hfs/declaration-shape.mjs",
|
|
120
|
+
"scripts/hfs/declaration-slots.mjs",
|
|
121
|
+
"scripts/hfs/edition-slots.mjs",
|
|
122
|
+
"scripts/hfs/linear-text.mjs",
|
|
123
|
+
"scripts/hfs/param-names.mjs",
|
|
124
|
+
"scripts/hfs/path-findings.mjs",
|
|
125
|
+
"scripts/hfs/repo-identity.mjs",
|
|
126
|
+
"scripts/hfs/rule-catalog.mjs",
|
|
127
|
+
"scripts/hfs/rule-params-shape.mjs",
|
|
128
|
+
"scripts/hfs/rules/database-migrations.mjs",
|
|
129
|
+
"scripts/hfs/rules/fe-no-tests.mjs",
|
|
130
|
+
"scripts/hfs/rules/read.mjs",
|
|
131
|
+
"scripts/hfs/rules/spec-placement.mjs",
|
|
132
|
+
"scripts/hfs/slot-app-view.mjs",
|
|
133
|
+
"scripts/hfs/slot-classify.mjs",
|
|
134
|
+
"scripts/hfs/slot-errors.mjs",
|
|
135
|
+
"scripts/hfs/slot-imports.mjs",
|
|
136
|
+
"scripts/hfs/slot-manifest-shape.mjs",
|
|
137
|
+
"scripts/hfs/slot-match.mjs",
|
|
138
|
+
"scripts/hfs/slot-path.mjs",
|
|
139
|
+
"scripts/hfs/slot-required.mjs",
|
|
140
|
+
"scripts/hfs/slot-semantic-problems.mjs",
|
|
141
|
+
"scripts/hfs/slot-side-problems.mjs",
|
|
142
|
+
"scripts/hfs/slots.mjs",
|
|
143
|
+
"scripts/hfs/test-world-slot.mjs",
|
|
144
|
+
"scripts/hfs/trailing-slashes.mjs",
|
|
145
|
+
"scripts/hfs/typescript-programs.mjs",
|
|
146
|
+
"scripts/hfs/view.mjs",
|
|
147
|
+
"scripts/lib/dockerfile.mjs",
|
|
148
|
+
"scripts/lib/env.mjs",
|
|
149
|
+
"scripts/lib/event-contract.mjs",
|
|
150
|
+
"scripts/lib/git.mjs",
|
|
151
|
+
"scripts/lib/glob.mjs",
|
|
152
|
+
"scripts/lib/grammar-lint.mjs",
|
|
153
|
+
"scripts/lib/i18n.mjs",
|
|
154
|
+
"scripts/lib/in-order.mjs",
|
|
155
|
+
"scripts/lib/json-clone.mjs",
|
|
156
|
+
"scripts/lib/json.mjs",
|
|
157
|
+
"scripts/lib/language.mjs",
|
|
158
|
+
"scripts/lib/list.mjs",
|
|
159
|
+
"scripts/lib/mutation-fence.mjs",
|
|
160
|
+
"scripts/lib/path-key.mjs",
|
|
161
|
+
"scripts/lib/read-text.mjs",
|
|
162
|
+
"scripts/lib/regex.mjs",
|
|
163
|
+
"scripts/lib/same-text.mjs",
|
|
164
|
+
"scripts/lib/sops-envelope.mjs",
|
|
165
|
+
"scripts/lib/stack-services.mjs",
|
|
166
|
+
"scripts/lib/ts-analysis.mjs",
|
|
167
|
+
"scripts/lib/ts-ast.mjs",
|
|
168
|
+
"scripts/lib/walk.mjs",
|
|
169
|
+
"scripts/lib/yaml-cached.mjs"
|
|
170
|
+
],
|
|
171
|
+
"own": [
|
|
172
|
+
"engine/config.mjs",
|
|
173
|
+
"engine/invalid-config.mjs",
|
|
174
|
+
"knowledge/hfs/slots.yaml",
|
|
175
|
+
"packages/hfs/templates/app/package-scripts/package.json",
|
|
176
|
+
"scripts/api/git/recorded-lines.mjs",
|
|
177
|
+
"scripts/hfs/architecture/hfs.mjs",
|
|
178
|
+
"scripts/hfs/manifest-shape.mjs",
|
|
179
|
+
"scripts/hfs/project-graph.mjs",
|
|
180
|
+
"scripts/hfs/project-rule.mjs",
|
|
181
|
+
"scripts/hfs/rules/database-constants.mjs",
|
|
182
|
+
"scripts/hfs/rules/secrets.mjs",
|
|
183
|
+
"scripts/lib/git-hooks-dir.mjs",
|
|
184
|
+
"scripts/lib/jsdoc.mjs",
|
|
185
|
+
"scripts/lib/line-count.mjs",
|
|
186
|
+
"scripts/lib/next-contract.mjs",
|
|
187
|
+
"scripts/lib/package-at.mjs",
|
|
188
|
+
"scripts/lib/secret-patterns.mjs",
|
|
189
|
+
"scripts/lib/sonar-syntax-rules.mjs",
|
|
190
|
+
"scripts/lib/sonar-way.mjs"
|
|
191
|
+
]
|
|
192
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// by-code-unit.mjs -
|
|
2
|
-
|
|
1
|
+
// by-code-unit.mjs -the comparator of a bare `Array.prototype.sort()`, owned beside the engine files that digest and canonicalize (scripts/lib/list.mjs re-exports it).
|
|
3
2
|
/**
|
|
4
3
|
* The comparator of a bare `Array.prototype.sort()`: values compared as strings by UTF-16 code unit. Pass it to `sort` and
|
|
5
4
|
* `toSorted` so the order is stated, and stays byte-identical to the default order that digests and canonical output depend on.
|
|
6
5
|
*/
|
|
7
6
|
export const byCodeUnit = (a, b) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const left = String(a);
|
|
8
|
+
const right = String(b);
|
|
9
|
+
if (left < right)
|
|
10
|
+
return -1;
|
|
11
|
+
return left > right ? 1 : 0;
|
|
12
12
|
};
|
|
@@ -1,90 +1,112 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import {fileURLToPath} from 'node:url';
|
|
3
|
-
import {parseYaml} from './yaml.mjs';
|
|
4
|
-
import {isPlainObject as plain} from './plain-object.mjs';
|
|
5
|
-
import {invalid} from './invalid-config.mjs';
|
|
6
|
-
import {byCodeUnit} from './by-code-unit.mjs';
|
|
7
|
-
import {removedOfKind} from './removed-vocabulary.mjs';
|
|
8
|
-
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { parseYaml } from './yaml.mjs';
|
|
4
|
+
import { isPlainObject as plain } from './plain-object.mjs';
|
|
5
|
+
import { invalid } from './invalid-config.mjs';
|
|
6
|
+
import { byCodeUnit } from './by-code-unit.mjs';
|
|
7
|
+
import { removedOfKind } from './removed-vocabulary.mjs';
|
|
9
8
|
/** The effort vocabulary, ordered weakest to strongest — the only list of it. */
|
|
10
|
-
export const EFFORT_LEVELS=new Set(['none','minimal','low','medium','high','xhigh','max','ultra']);
|
|
11
|
-
const DIFFICULTIES=['easy','medium','hard','insane'];
|
|
12
|
-
export const MODELS_KEYS=['tiers','seats','balance','usage'];
|
|
13
|
-
const known=names=>[...names].sort(byCodeUnit).join(', ');
|
|
14
|
-
|
|
15
|
-
const hasPath=(root,dotted)=>dotted.split('.').reduce((node,key)=>(plain(node)&&Object.hasOwn(node,key)?node[key]:undefined),root)!==undefined;
|
|
16
|
-
|
|
9
|
+
export const EFFORT_LEVELS = new Set(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra']);
|
|
10
|
+
const DIFFICULTIES = ['easy', 'medium', 'hard', 'insane'];
|
|
11
|
+
export const MODELS_KEYS = ['tiers', 'seats', 'balance', 'usage'];
|
|
12
|
+
const known = (names) => [...names].sort(byCodeUnit).join(', ');
|
|
13
|
+
const hasPath = (root, dotted) => dotted.split('.').reduce((node, key) => (plain(node) && Object.hasOwn(node, key) ? node[key] : undefined), root) !== undefined;
|
|
17
14
|
/** Refuse an old-shape config (the removed keys of modules/kernel/removed-vocabulary.yaml), naming every removed key and where its meaning lives now. */
|
|
18
|
-
export function refuseRemovedKeys(config){
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
export function refuseRemovedKeys(config) {
|
|
16
|
+
const found = removedOfKind('config-key').filter(({ name }) => hasPath(config, name));
|
|
17
|
+
if (!found.length)
|
|
18
|
+
return;
|
|
19
|
+
const removed = found.map(({ name, use }) => `${name} is removed (${use})`).join('; ');
|
|
20
|
+
throw new Error(`Invalid config.yaml: ${removed}.`);
|
|
23
21
|
}
|
|
24
|
-
|
|
25
|
-
let shippedCache=null;
|
|
22
|
+
let shippedCache = null;
|
|
26
23
|
/** modules/models/tiers.yaml as shipped, parsed once per file version. */
|
|
27
|
-
export function shippedTiers(){
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
export function shippedTiers() {
|
|
25
|
+
const file = fileURLToPath(new URL('../modules/models/tiers.yaml', import.meta.url));
|
|
26
|
+
let stat;
|
|
27
|
+
try {
|
|
28
|
+
stat = fs.statSync(file);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error('Missing modules/models/tiers.yaml');
|
|
32
|
+
}
|
|
33
|
+
const version = `${stat.mtimeMs}:${stat.size}`;
|
|
34
|
+
if (shippedCache?.version !== version)
|
|
35
|
+
shippedCache = { version, doc: parseYaml(fs.readFileSync(file, 'utf8')) };
|
|
36
|
+
return structuredClone(shippedCache.doc);
|
|
33
37
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
function validateMember(bad, where, member, profile) {
|
|
39
|
+
if (!plain(member) || Object.keys(member).some(key => !['agent', 'model', 'effort'].includes(key)) || typeof member.agent !== 'string' || typeof member.model !== 'string')
|
|
40
|
+
return bad(`${where} must be {agent, model, effort?}.`);
|
|
41
|
+
if (profile.models?.[member.model]?.provider !== member.agent)
|
|
42
|
+
bad(`${where}: model ${member.model} is not declared by agent ${member.agent} in modules/models/registry.yaml models.`);
|
|
43
|
+
if (member.effort !== undefined && !(typeof member.effort === 'string' && EFFORT_LEVELS.has(member.effort)))
|
|
44
|
+
bad(`${where}.effort must use the effort vocabulary.`);
|
|
40
45
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
function validateChains(bad, tiers, profile) {
|
|
47
|
+
for (const [name, chain] of Object.entries(tiers)) {
|
|
48
|
+
if (!Array.isArray(chain) || !chain.length)
|
|
49
|
+
return bad(`.${name} must be a non-empty ordered list of {agent, model, effort?}.`);
|
|
50
|
+
chain.forEach((member, index) => validateMember(bad, `.${name}[${index}]`, member, profile));
|
|
51
|
+
// validateMember refused every member that is not a {agent, model, effort?} record above.
|
|
52
|
+
const members = chain;
|
|
53
|
+
if (new Set(members.map(member => `${member.agent}/${member.model}`)).size !== chain.length)
|
|
54
|
+
bad(`.${name} names each member once.`);
|
|
55
|
+
}
|
|
48
56
|
}
|
|
49
|
-
|
|
50
57
|
/** A call tier is taken by a headless call only: no seat, difficulty, kind, order or caller reference may name it, and every call names one. */
|
|
51
|
-
function validateUse(bad,{doc,names,refs}){
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
function validateUse(bad, { doc, names, refs }) {
|
|
59
|
+
const callTiers = new Set(Object.entries(doc.tierUse).filter(([, use]) => use === 'call').map(([tier]) => tier));
|
|
60
|
+
for (const tier of Object.keys(doc.tierUse))
|
|
61
|
+
if (!names.has(tier))
|
|
62
|
+
bad(`: tierUse names tier ${tier} (known: ${known(names)}).`);
|
|
63
|
+
for (const [where, tier] of refs)
|
|
64
|
+
if (callTiers.has(tier))
|
|
65
|
+
bad(`: ${where} names tier ${tier}, a call tier (tierUse): a headless call is made on it, no seat or op is seated on it.`);
|
|
66
|
+
for (const [call, spec] of Object.entries(doc.calls))
|
|
67
|
+
if (!callTiers.has(spec.tier))
|
|
68
|
+
bad(`: calls.${call}.tier ${spec.tier} must be a tier whose tierUse is call.`);
|
|
56
69
|
}
|
|
57
|
-
|
|
58
70
|
/** The tier document the picker reads: the shipped tiers.yaml with config.yaml `models` laid over it. Validated. */
|
|
59
|
-
export function effectiveTiers(config,profile){
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
export function effectiveTiers(config, profile) {
|
|
72
|
+
const doc = shippedTiers(), models = plain(config?.models) ? config.models : {};
|
|
73
|
+
const bad = invalid('models');
|
|
74
|
+
const merged = { ...doc.tiers, ...models.tiers };
|
|
75
|
+
validateChains(bad, merged, profile);
|
|
76
|
+
// validateChains refused every chain that is not a non-empty list of {agent, model, effort?} members.
|
|
77
|
+
const tiers = merged;
|
|
78
|
+
const seats = { ...doc.seats, ...models.seats };
|
|
79
|
+
const balance = { ...doc.balance, ...models.balance };
|
|
80
|
+
const usage = { ...doc.usage, ...models.usage };
|
|
81
|
+
const names = new Set(Object.keys(tiers));
|
|
82
|
+
const refs = [...Object.entries(seats).map(([seat, tier]) => [`.seats.${seat}`, tier]), ...DIFFICULTIES.map(level => [`difficulty.${level}`, doc.difficulty[level]]),
|
|
83
|
+
...Object.entries(doc.kindTiers).map(([kind, tier]) => [`kindTiers.${kind}`, tier]), ...doc.tierOrder.map(tier => ['tierOrder', tier])];
|
|
84
|
+
for (const [where, tier] of refs)
|
|
85
|
+
if (!names.has(tier))
|
|
86
|
+
bad(`: ${where} names tier ${tier} (known: ${known(names)}).`);
|
|
87
|
+
validateUse(bad, { doc, names, refs });
|
|
88
|
+
if (!(Number.isInteger(balance.maxStreak) && balance.maxStreak >= 1))
|
|
89
|
+
bad('.balance.maxStreak must be an integer >= 1.');
|
|
90
|
+
if (!(typeof balance.maxSharePercent === 'number' && balance.maxSharePercent > 0 && balance.maxSharePercent <= 100))
|
|
91
|
+
bad('.balance.maxSharePercent must be a number in (0, 100].');
|
|
92
|
+
const { reservePercent, biasPercent, exhaustedPercent } = usage;
|
|
93
|
+
if (![reservePercent, biasPercent, exhaustedPercent].every(value => typeof value === 'number' && value >= 0 && value <= 100) || !(reservePercent <= biasPercent && biasPercent < exhaustedPercent))
|
|
94
|
+
bad('.usage must hold numbers with reservePercent <= biasPercent < exhaustedPercent, each within 0..100.');
|
|
95
|
+
return { ...doc, tiers, seats, balance, usage };
|
|
78
96
|
}
|
|
79
|
-
|
|
80
97
|
/** config.yaml `models` — {tiers?, seats?, balance?, usage?}; the shipped defaults make every key optional. */
|
|
81
|
-
export function validateModelsBlock(config,profile){
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
export function validateModelsBlock(config, profile) {
|
|
99
|
+
refuseRemovedKeys(config);
|
|
100
|
+
const models = config?.models;
|
|
101
|
+
if (models === undefined || models === null)
|
|
102
|
+
return;
|
|
103
|
+
const bad = invalid('models');
|
|
104
|
+
if (!plain(models) || Object.keys(models).some(key => !MODELS_KEYS.includes(key)))
|
|
105
|
+
return bad(` must be {${MODELS_KEYS.map(key => key + '?').join(', ')}} or null (unknown keys are refused).`);
|
|
106
|
+
if (models.tiers !== undefined && !plain(models.tiers))
|
|
107
|
+
bad('.tiers must map tier names to ordered member lists.');
|
|
108
|
+
for (const key of ['seats', 'balance', 'usage'])
|
|
109
|
+
if (models[key] !== undefined && !plain(models[key]))
|
|
110
|
+
bad(`.${key} must be a mapping.`);
|
|
111
|
+
effectiveTiers(config, profile);
|
|
90
112
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {isPlainObject as plain} from './plain-object.mjs';
|
|
2
|
-
import {invalid} from './invalid-config.mjs';
|
|
3
|
-
|
|
1
|
+
import { isPlainObject as plain } from './plain-object.mjs';
|
|
2
|
+
import { invalid } from './invalid-config.mjs';
|
|
4
3
|
/**
|
|
5
4
|
* config.yaml `orca` — the owner's Orca app settings the runtime must know. maxWorkerDepth is the deepest worker Orca
|
|
6
5
|
* lets start under the owner's chat (chat = depth 0, a Kernel or the [Supervisor] 1, an op or a [Worker] 2, the draw
|
|
@@ -9,21 +8,27 @@ import {invalid} from './invalid-config.mjs';
|
|
|
9
8
|
* deeper than it before worker-start (worker-depth-exceeded), and `start --check` with STARCI_ORCA_LIVE=1 compares it with
|
|
10
9
|
* a measured probe (scripts/agent/depth-probe.mjs).
|
|
11
10
|
*/
|
|
12
|
-
export const ORCA_DEFAULTS=Object.freeze({maxWorkerDepth:4});
|
|
11
|
+
export const ORCA_DEFAULTS = Object.freeze({ maxWorkerDepth: 4 });
|
|
13
12
|
/** The keys of the orca block. */
|
|
14
|
-
export const ORCA_KEYS=Object.freeze(Object.keys(ORCA_DEFAULTS));
|
|
15
|
-
export const MAX_WORKER_DEPTH_CEILING=16;
|
|
16
|
-
export function validateOrca(orca){
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
export const ORCA_KEYS = Object.freeze(Object.keys(ORCA_DEFAULTS));
|
|
14
|
+
export const MAX_WORKER_DEPTH_CEILING = 16;
|
|
15
|
+
export function validateOrca(orca) {
|
|
16
|
+
if (orca === null)
|
|
17
|
+
return;
|
|
18
|
+
const bad = invalid('orca');
|
|
19
|
+
if (!plain(orca))
|
|
20
|
+
return bad(' must be {maxWorkerDepth?} or null.');
|
|
21
|
+
for (const key of Object.keys(orca))
|
|
22
|
+
if (!ORCA_KEYS.includes(key))
|
|
23
|
+
bad(` has unknown key ${key} (allowed: ${ORCA_KEYS.join(', ')}).`);
|
|
24
|
+
const v = orca.maxWorkerDepth;
|
|
25
|
+
if (v !== undefined && v !== null && !(typeof v === 'number' && Number.isInteger(v) && v >= 1 && v <= MAX_WORKER_DEPTH_CEILING))
|
|
26
|
+
bad(`.maxWorkerDepth must be an integer from 1 to ${MAX_WORKER_DEPTH_CEILING} equal to the Orca app's worker depth setting (default ${ORCA_DEFAULTS.maxWorkerDepth}), or null.`);
|
|
23
27
|
}
|
|
24
28
|
/** The owner's Orca settings: {maxWorkerDepth, source: 'orca'|'default'}. An absent or null block or key is the default. */
|
|
25
|
-
export function orcaSettings(config){
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
export function orcaSettings(config) {
|
|
30
|
+
if (config?.orca !== undefined)
|
|
31
|
+
validateOrca(config.orca);
|
|
32
|
+
const value = plain(config?.orca) ? config.orca.maxWorkerDepth : null;
|
|
33
|
+
return typeof value === 'number' && Number.isInteger(value) ? { maxWorkerDepth: value, source: 'orca' } : { maxWorkerDepth: ORCA_DEFAULTS.maxWorkerDepth, source: 'default' };
|
|
29
34
|
}
|
|
@@ -1,28 +1,32 @@
|
|
|
1
|
-
import {isPlainObject as plain} from './plain-object.mjs';
|
|
2
|
-
import {invalid} from './invalid-config.mjs';
|
|
3
|
-
|
|
1
|
+
import { isPlainObject as plain } from './plain-object.mjs';
|
|
2
|
+
import { invalid } from './invalid-config.mjs';
|
|
4
3
|
/** The keys of the release block. */
|
|
5
|
-
export const RELEASE_KEYS=Object.freeze(['suite']);
|
|
4
|
+
export const RELEASE_KEYS = Object.freeze(['suite']);
|
|
6
5
|
/** Where the full test suite of a release is judged: `local` (the release cut also runs the L4 rows before it tags, the shipped default) or `ci` (the GitHub workflows judge EVERY row on each push to main; the cut runs none). */
|
|
7
|
-
export const SUITE_MODES=Object.freeze(['local','ci']);
|
|
8
|
-
const RELEASE_DEFAULTS=Object.freeze({suite:'local'});
|
|
9
|
-
|
|
6
|
+
export const SUITE_MODES = Object.freeze(['local', 'ci']);
|
|
7
|
+
const RELEASE_DEFAULTS = Object.freeze({ suite: 'local' });
|
|
10
8
|
/**
|
|
11
9
|
* config.yaml `release` - {suite?: local | ci}: who judges the full suite of a release (docs/releasing.md "Where the suite runs"). `local` is the shipped default: `starci release cut` also runs the
|
|
12
10
|
* L4 rows on this host before it tags. `ci` is the owner's recorded choice (2026-10-09, widened 2026-10-26 by push-main-after-scoped-check): the full suite runs on GitHub only, on every push
|
|
13
11
|
* to main; the cut runs no row and the verdict is read with `starci release ci-status`. The push of main needs neither mode: it needs a green scoped check.
|
|
14
12
|
* `none` is refused: the suite does not vanish, it moves to CI, and the value says so.
|
|
15
13
|
*/
|
|
16
|
-
export function validateRelease(release){
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
export function validateRelease(release) {
|
|
15
|
+
if (release === null)
|
|
16
|
+
return;
|
|
17
|
+
const bad = invalid('release');
|
|
18
|
+
if (!plain(release))
|
|
19
|
+
return bad(` must be {suite?: ${SUITE_MODES.join(' | ')}} or null.`);
|
|
20
|
+
for (const key of Object.keys(release))
|
|
21
|
+
if (!RELEASE_KEYS.includes(key))
|
|
22
|
+
bad(` has unknown key ${key} (allowed: ${RELEASE_KEYS.join(', ')}).`);
|
|
23
|
+
const value = release.suite;
|
|
24
|
+
if (value === undefined || value === null)
|
|
25
|
+
return;
|
|
26
|
+
if (value === 'none')
|
|
27
|
+
bad('.suite: "none" is not a mode: write "ci" (no local full suite, CI judges) or "local".');
|
|
28
|
+
if (typeof value !== 'string' || !SUITE_MODES.includes(value))
|
|
29
|
+
bad(`.suite must be ${SUITE_MODES.join(' or ')}, or null.`);
|
|
25
30
|
}
|
|
26
|
-
|
|
27
31
|
/** The suite mode a validated owner config names; an absent block or key is the shipped default. */
|
|
28
|
-
export const releaseSuiteMode=config=>config?.release?.suite??RELEASE_DEFAULTS.suite;
|
|
32
|
+
export const releaseSuiteMode = (config) => config?.release?.suite ?? RELEASE_DEFAULTS.suite;
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import {fileURLToPath} from 'node:url';
|
|
3
|
-
import {parseYaml} from './yaml.mjs';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { parseYaml } from './yaml.mjs';
|
|
4
|
+
const FILE = fileURLToPath(new URL('../modules/kernel/removed-vocabulary.yaml', import.meta.url));
|
|
5
|
+
let cache = null;
|
|
6
|
+
function loaded() {
|
|
7
|
+
let stat;
|
|
8
|
+
try {
|
|
9
|
+
stat = fs.statSync(FILE);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new Error('Missing modules/kernel/removed-vocabulary.yaml');
|
|
13
|
+
}
|
|
14
|
+
const version = `${stat.mtimeMs}:${stat.size}`;
|
|
15
|
+
if (cache?.version !== version)
|
|
16
|
+
cache = { version, doc: parseYaml(fs.readFileSync(FILE, 'utf8')) };
|
|
17
|
+
return cache.doc;
|
|
13
18
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
19
|
/** modules/kernel/removed-vocabulary.yaml: the one list of spellings the runtime refuses, each with its replacement and the release that removed it. */
|
|
17
|
-
export const removedVocabulary=()=>loaded().removed;
|
|
18
|
-
|
|
20
|
+
export const removedVocabulary = () => loaded().removed;
|
|
19
21
|
/** The removed spellings of one kind. */
|
|
20
|
-
export const removedOfKind=kind=>removedVocabulary().filter(entry=>entry.kind===kind);
|
|
21
|
-
|
|
22
|
+
export const removedOfKind = (kind) => removedVocabulary().filter(entry => entry.kind === kind);
|
|
22
23
|
/** `<name> is removed (<replacement>)` for a removed spelling of the kind, or undefined when the name is not one. */
|
|
23
|
-
export function removedNotice(kind,name){
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
export function removedNotice(kind, name) {
|
|
25
|
+
const entry = removedOfKind(kind).find(candidate => candidate.name === name);
|
|
26
|
+
return entry ? `${entry.name} is removed (${entry.use})` : undefined;
|
|
26
27
|
}
|