@codyswann/lisa 3.47.4 → 3.47.6
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/all/copy-overwrite/scripts/lib/gate-failure-diagnosis.mjs +270 -0
- package/all/copy-overwrite/scripts/lisa-gates.mjs +30 -0
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +294 -34
- package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +126 -32
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +83 -26
- package/dist/configs/eslint/expo.d.ts +50 -1
- package/dist/configs/eslint/expo.d.ts.map +1 -1
- package/dist/configs/eslint/expo.js +86 -5
- package/dist/configs/eslint/expo.js.map +1 -1
- package/dist/core/downstream-names.d.ts +83 -0
- package/dist/core/downstream-names.d.ts.map +1 -0
- package/dist/core/downstream-names.js +289 -0
- package/dist/core/downstream-names.js.map +1 -0
- package/dist/core/downstream-references.d.ts +21 -6
- package/dist/core/downstream-references.d.ts.map +1 -1
- package/dist/core/downstream-references.js +19 -16
- package/dist/core/downstream-references.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +16 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +23 -10
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/migrations/ensure-tsconfig-local-includes.d.ts +1 -1
- package/dist/migrations/ensure-tsconfig-local-includes.js +1 -1
- package/expo/copy-overwrite/eslint.config.ts +9 -0
- package/expo/copy-overwrite/eslint.expo.ts +92 -4
- package/package.json +5 -2
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/rules/reference/design-value-binding.md +4 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/rules/reference/design-value-binding.md +4 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/design-value-binding-reference.mdc +4 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/rules/reference/design-value-binding.md +4 -0
- package/scripts/lisa-mutation.mjs +13 -0
- package/typescript/copy-contents/.husky/pre-push +7 -1
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +496 -122
- package/typescript/package-lisa/package.lisa.json +1 -0
|
@@ -9,7 +9,7 @@ import type { Migration, MigrationContext, MigrationResult } from "./migration.i
|
|
|
9
9
|
*
|
|
10
10
|
* Additionally, this migration preserves a project's narrower include/exclude from
|
|
11
11
|
* the pre-strategy tsconfig.json when the stack template's include/exclude would
|
|
12
|
-
* widen tsc scope. Evidence:
|
|
12
|
+
* widen tsc scope. Evidence: acmeorgd-backend's tsconfig.json pinned `include: ["src/**\/*"]`
|
|
13
13
|
* but after Lisa overwrote tsconfig.json the stack template's include was used,
|
|
14
14
|
* pulling `vitest.*.ts` into typecheck scope.
|
|
15
15
|
*/
|
|
@@ -61,7 +61,7 @@ async function loadTemplateDefaults(lisaDir, type) {
|
|
|
61
61
|
*
|
|
62
62
|
* Additionally, this migration preserves a project's narrower include/exclude from
|
|
63
63
|
* the pre-strategy tsconfig.json when the stack template's include/exclude would
|
|
64
|
-
* widen tsc scope. Evidence:
|
|
64
|
+
* widen tsc scope. Evidence: acmeorgd-backend's tsconfig.json pinned `include: ["src/**\/*"]`
|
|
65
65
|
* but after Lisa overwrote tsconfig.json the stack template's include was used,
|
|
66
66
|
* pulling `vitest.*.ts` into typecheck scope.
|
|
67
67
|
*/
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
defaultIgnores,
|
|
25
25
|
defaultThresholds,
|
|
26
26
|
getExpoConfig,
|
|
27
|
+
readTypedAxes,
|
|
27
28
|
} from "@codyswann/lisa/eslint/expo";
|
|
28
29
|
|
|
29
30
|
import ignoreConfig from "./eslint.ignore.config.json" with { type: "json" };
|
|
@@ -47,6 +48,13 @@ const localIgnores: string[] = existsSync(
|
|
|
47
48
|
? (require("./eslint.ignore.config.local.json").ignores ?? [])
|
|
48
49
|
: [];
|
|
49
50
|
|
|
51
|
+
// Arm ui-standards/no-unbound-design-value from `design.tokens.axes` in
|
|
52
|
+
// .lisa.config.json. Declaring an axis is what arms the rule; declaring none
|
|
53
|
+
// leaves it silent. Read here, at config load, exactly like
|
|
54
|
+
// eslint.thresholds.json and eslint.ignore.config.json above — so there is no
|
|
55
|
+
// generation step and nothing that can go stale against the config (#2807).
|
|
56
|
+
const typedAxes = readTypedAxes(__dirname);
|
|
57
|
+
|
|
50
58
|
// Type only the managed factory result, then trust project-owned additions at
|
|
51
59
|
// their spread boundary. The double assertion is intentional: one custom-plugin
|
|
52
60
|
// entry can be structurally different enough for a direct cast to raise TS2352,
|
|
@@ -66,6 +74,7 @@ const config: ReturnType<typeof getExpoConfig> = [
|
|
|
66
74
|
],
|
|
67
75
|
thresholds: { ...defaultThresholds, ...thresholdsConfig },
|
|
68
76
|
sourceRoot,
|
|
77
|
+
typedAxes,
|
|
69
78
|
}),
|
|
70
79
|
...(localConfig as unknown as ReturnType<typeof getExpoConfig>),
|
|
71
80
|
];
|
|
@@ -24,7 +24,9 @@ import reactCompiler from "eslint-plugin-react-compiler";
|
|
|
24
24
|
// @ts-expect-error -- eslint-plugin-react-perf lacks type declarations
|
|
25
25
|
import reactPerf from "eslint-plugin-react-perf";
|
|
26
26
|
import tailwind from "eslint-plugin-tailwindcss";
|
|
27
|
+
import { readFileSync } from "fs";
|
|
27
28
|
import { createRequire } from "module";
|
|
29
|
+
import path from "path";
|
|
28
30
|
|
|
29
31
|
// Import TypeScript config and utilities from the Lisa package
|
|
30
32
|
// (eslint.typescript.ts is no longer deployed to downstream projects)
|
|
@@ -57,22 +59,105 @@ const componentStructure = require("@codyswann/eslint-plugin-component-structure
|
|
|
57
59
|
const uiStandards = require("@codyswann/eslint-plugin-ui-standards");
|
|
58
60
|
const expoConfig = require("eslint-config-expo/flat");
|
|
59
61
|
|
|
62
|
+
/**
|
|
63
|
+
* A project's `.lisa.config.json`, when it has one.
|
|
64
|
+
*
|
|
65
|
+
* Absence is not an error: a project that has never run `lisa apply` has no
|
|
66
|
+
* such file and declares no axes.
|
|
67
|
+
* @param file - Absolute path to the candidate `.lisa.config.json`.
|
|
68
|
+
* @returns Its text, or undefined when the project has no such file.
|
|
69
|
+
*/
|
|
70
|
+
function readConfigText(file: string): string | undefined {
|
|
71
|
+
try {
|
|
72
|
+
return readFileSync(file, "utf8");
|
|
73
|
+
} catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Axes a project declares typed, read from its own `.lisa.config.json`.
|
|
80
|
+
*
|
|
81
|
+
* #2807: the design-value rule shipped installed, severity `"off"`, and arming
|
|
82
|
+
* it needed a severity AND a `typedAxes` option hand-written into
|
|
83
|
+
* `eslint.config.local.ts`. Nothing carried `design.tokens.axes` from
|
|
84
|
+
* `.lisa.config.json` to the rule, so a project could declare every axis,
|
|
85
|
+
* install the policy, pass every test, and enforce nothing.
|
|
86
|
+
*
|
|
87
|
+
* It is read HERE, at ESLint **config** load, rather than inside the rule at
|
|
88
|
+
* **rule** load. That distinction is what makes it unremarkable: the managed
|
|
89
|
+
* `eslint.config.ts` already reads `eslint.thresholds.json` and
|
|
90
|
+
* `eslint.ignore.config.json` from disk at exactly this moment, so this adds no
|
|
91
|
+
* new class of behaviour and gives ESLint's config cache nothing to fight. A
|
|
92
|
+
* rule reading project files on every `create()` would do both.
|
|
93
|
+
*
|
|
94
|
+
* It also needs no generation step, which is what the alternative — emitting
|
|
95
|
+
* rule options into a generated file during `lisa apply` — would have cost. A
|
|
96
|
+
* generated file can go stale against the config it was generated from; a value
|
|
97
|
+
* read at load cannot.
|
|
98
|
+
* @param projectRoot - Directory holding the project's `.lisa.config.json`.
|
|
99
|
+
* @returns The declared axes, or an empty list when none are declared.
|
|
100
|
+
* @throws {TypeError} When `design.tokens.axes` is present but is not a list of strings.
|
|
101
|
+
*/
|
|
102
|
+
export function readTypedAxes(projectRoot: string): string[] {
|
|
103
|
+
const file = path.join(projectRoot, ".lisa.config.json");
|
|
104
|
+
const raw = readConfigText(file);
|
|
105
|
+
if (raw === undefined) return [];
|
|
106
|
+
const axes = (JSON.parse(raw) as { design?: { tokens?: { axes?: unknown } } })
|
|
107
|
+
.design?.tokens?.axes;
|
|
108
|
+
if (axes === undefined) return [];
|
|
109
|
+
if (!Array.isArray(axes) || axes.some(axis => typeof axis !== "string")) {
|
|
110
|
+
// Coercing a malformed declaration to "no axes" would disarm the rule
|
|
111
|
+
// silently — #2807 reproduced one layer down. Refuse loudly instead.
|
|
112
|
+
throw new TypeError(
|
|
113
|
+
`${file}: design.tokens.axes must be an array of axis names, e.g. ["color"].`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return axes as string[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The `ui-standards/no-unbound-design-value` entry for a set of typed axes.
|
|
121
|
+
*
|
|
122
|
+
* Silence-by-default is deliberate and unchanged: an axis with no published
|
|
123
|
+
* variable collection behind it has no token to bind to, and a rule that fires
|
|
124
|
+
* on every project is a rule that gets switched off. What changes is that
|
|
125
|
+
* declaring an axis is now SUFFICIENT to arm it. Previously nothing was.
|
|
126
|
+
*
|
|
127
|
+
* An axis name outside the rule's fixed vocabulary is passed through rather
|
|
128
|
+
* than filtered out, so ESLint's own schema validation rejects it by name. A
|
|
129
|
+
* filter would turn a typo into silent non-enforcement, which is the defect
|
|
130
|
+
* this function exists to remove.
|
|
131
|
+
* @param typedAxes - Axes the project declares typed.
|
|
132
|
+
* @returns `"off"` when none are declared, an armed error entry otherwise.
|
|
133
|
+
*/
|
|
134
|
+
export function getDesignValueBindingRule(
|
|
135
|
+
typedAxes: readonly string[]
|
|
136
|
+
): import("eslint").Linter.RuleEntry {
|
|
137
|
+
return typedAxes.length > 0
|
|
138
|
+
? ["error", { typedAxes: [...typedAxes] }]
|
|
139
|
+
: "off";
|
|
140
|
+
}
|
|
141
|
+
|
|
60
142
|
/**
|
|
61
143
|
* Creates the Expo ESLint configuration.
|
|
62
144
|
* @param {object} options - Configuration options
|
|
63
145
|
* @param {string} options.tsconfigRootDir - Root directory for tsconfig.json
|
|
64
146
|
* @param {string[]} [options.ignorePatterns] - Patterns to ignore
|
|
65
147
|
* @param {object} [options.thresholds] - Threshold overrides
|
|
148
|
+
* @param {string[]} [options.typedAxes] - Axes the project declares typed, mirroring `design.tokens.axes`. Empty leaves the design-value rule off.
|
|
66
149
|
* @returns {Array} ESLint flat config array
|
|
67
150
|
*/
|
|
68
151
|
export function getExpoConfig({
|
|
69
152
|
tsconfigRootDir,
|
|
70
153
|
ignorePatterns = defaultIgnores,
|
|
71
154
|
thresholds = defaultThresholds,
|
|
155
|
+
typedAxes = [],
|
|
72
156
|
}: {
|
|
73
157
|
tsconfigRootDir: string;
|
|
74
158
|
ignorePatterns?: string[];
|
|
75
159
|
thresholds?: typeof defaultThresholds;
|
|
160
|
+
typedAxes?: readonly string[];
|
|
76
161
|
}) {
|
|
77
162
|
return [
|
|
78
163
|
// Global ignores
|
|
@@ -125,10 +210,13 @@ export function getExpoConfig({
|
|
|
125
210
|
"ui-standards/no-classname-outside-ui": "off",
|
|
126
211
|
"ui-standards/no-direct-rn-imports": "off",
|
|
127
212
|
// Regime-aware by declaration: silent until the project names the axes
|
|
128
|
-
// it publishes design variables for.
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
|
|
213
|
+
// it publishes design variables for. Declaring `design.tokens.axes` in
|
|
214
|
+
// .lisa.config.json is what arms it — the managed eslint.config.ts
|
|
215
|
+
// reads that key and hands it here (#2807). Declaring nothing leaves
|
|
216
|
+
// the rule off, which is the correct default and was previously the
|
|
217
|
+
// ONLY reachable state.
|
|
218
|
+
"ui-standards/no-unbound-design-value":
|
|
219
|
+
getDesignValueBindingRule(typedAxes),
|
|
132
220
|
|
|
133
221
|
// Tailwind
|
|
134
222
|
"tailwindcss/classnames-order": [
|
package/package.json
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
"build": "bun run build:dist && bun run build:plugins",
|
|
4
4
|
"build:dist": "node scripts/clean-dist.mjs && tsc && node scripts/copy-codex-scripts.mjs && node scripts/copy-opencode-plugin-templates.mjs",
|
|
5
5
|
"test:integration": "vitest run tests/integration",
|
|
6
|
+
"test:integration:push": "vitest run tests/integration --exclude='**/mutation-gate-bite.test.ts' --exclude='**/mutation-gate-diff-bite.test.ts'",
|
|
6
7
|
"postinstall": "bash ./scripts/install-claude-plugins.sh || true; [ -d dist/configs ] || tsc || true",
|
|
7
8
|
"pretest": "[ -d dist/configs ] || bun run build",
|
|
8
9
|
"test": "vitest run",
|
|
9
10
|
"test:unit": "vitest run --exclude='**/integration/**'",
|
|
10
11
|
"test:cov": "vitest run --coverage",
|
|
12
|
+
"test:cov:unit": "vitest run --coverage --exclude='**/integration/**'",
|
|
11
13
|
"pretest:mutation": "[ -d dist/configs ] || bun run build",
|
|
12
|
-
"test:mutation": "
|
|
14
|
+
"test:mutation": "node scripts/lisa-mutation.mjs",
|
|
15
|
+
"test:mutation:full": "stryker run",
|
|
13
16
|
"lint": "oxlint --disable-nested-config && eslint . --quiet",
|
|
14
17
|
"lint:fix": "oxlint --fix --disable-nested-config && eslint . --fix",
|
|
15
18
|
"lint:slow": "eslint . --config eslint.slow.config.ts --quiet",
|
|
@@ -138,7 +141,7 @@
|
|
|
138
141
|
"zod-validation-error": "^4.0.0"
|
|
139
142
|
},
|
|
140
143
|
"name": "@codyswann/lisa",
|
|
141
|
-
"version": "3.47.
|
|
144
|
+
"version": "3.47.6",
|
|
142
145
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
143
146
|
"main": "dist/index.js",
|
|
144
147
|
"exports": {
|
|
@@ -69,6 +69,10 @@ A frame-level read counts the chrome behind a modal and over-reports. One measur
|
|
|
69
69
|
|
|
70
70
|
ESLint runs on source text with no network and no design-tool session, so `ui-standards/no-unbound-design-value` cannot read the map at all. It takes the typed axes as its `typedAxes` option, which mirrors `design.tokens.axes`, and reports nothing when that list is empty.
|
|
71
71
|
|
|
72
|
+
**How the option is armed (#2807).** The managed `eslint.config.ts` reads `design.tokens.axes` out of `.lisa.config.json` at ESLint **config** load — alongside `eslint.thresholds.json` and `eslint.ignore.config.json`, which it has always read there — and hands the list to the config factory, which emits `["error", { typedAxes }]` for a non-empty list and `"off"` for an empty one. **Declaring an axis is therefore sufficient to arm the rule; nothing has to be written into `eslint.config.local.ts`.** Before this the rule shipped severity `"off"` with no path from configuration to activation at all, so a project could declare every axis, install the policy, pass every test, and enforce nothing — a control installed, adopted, green and inert.
|
|
73
|
+
|
|
74
|
+
An axis name outside the six is passed straight through to ESLint's own schema validation, which rejects it by name. Filtering it out instead would turn a typo into silent non-enforcement, which is the same failure one layer down.
|
|
75
|
+
|
|
72
76
|
The intake probe's regime is **observed**; the lint rule's is **declared**, and the declared list can go stale relative to the map. It is still the correct division — an over-firing lint rule is a disabled lint rule, and a rule that silently skipped an axis it could not verify would be worse than one that skips an axis nobody declared. Intake is the arm that sees the truth; lint is the arm that catches the same defect at authoring time on the axes the project has already committed to.
|
|
73
77
|
|
|
74
78
|
## A design source is optional
|
|
@@ -69,6 +69,10 @@ A frame-level read counts the chrome behind a modal and over-reports. One measur
|
|
|
69
69
|
|
|
70
70
|
ESLint runs on source text with no network and no design-tool session, so `ui-standards/no-unbound-design-value` cannot read the map at all. It takes the typed axes as its `typedAxes` option, which mirrors `design.tokens.axes`, and reports nothing when that list is empty.
|
|
71
71
|
|
|
72
|
+
**How the option is armed (#2807).** The managed `eslint.config.ts` reads `design.tokens.axes` out of `.lisa.config.json` at ESLint **config** load — alongside `eslint.thresholds.json` and `eslint.ignore.config.json`, which it has always read there — and hands the list to the config factory, which emits `["error", { typedAxes }]` for a non-empty list and `"off"` for an empty one. **Declaring an axis is therefore sufficient to arm the rule; nothing has to be written into `eslint.config.local.ts`.** Before this the rule shipped severity `"off"` with no path from configuration to activation at all, so a project could declare every axis, install the policy, pass every test, and enforce nothing — a control installed, adopted, green and inert.
|
|
73
|
+
|
|
74
|
+
An axis name outside the six is passed straight through to ESLint's own schema validation, which rejects it by name. Filtering it out instead would turn a typo into silent non-enforcement, which is the same failure one layer down.
|
|
75
|
+
|
|
72
76
|
The intake probe's regime is **observed**; the lint rule's is **declared**, and the declared list can go stale relative to the map. It is still the correct division — an over-firing lint rule is a disabled lint rule, and a rule that silently skipped an axis it could not verify would be worse than one that skips an axis nobody declared. Intake is the arm that sees the truth; lint is the arm that catches the same defect at authoring time on the axes the project has already committed to.
|
|
73
77
|
|
|
74
78
|
## A design source is optional
|
|
@@ -74,6 +74,10 @@ A frame-level read counts the chrome behind a modal and over-reports. One measur
|
|
|
74
74
|
|
|
75
75
|
ESLint runs on source text with no network and no design-tool session, so `ui-standards/no-unbound-design-value` cannot read the map at all. It takes the typed axes as its `typedAxes` option, which mirrors `design.tokens.axes`, and reports nothing when that list is empty.
|
|
76
76
|
|
|
77
|
+
**How the option is armed (#2807).** The managed `eslint.config.ts` reads `design.tokens.axes` out of `.lisa.config.json` at ESLint **config** load — alongside `eslint.thresholds.json` and `eslint.ignore.config.json`, which it has always read there — and hands the list to the config factory, which emits `["error", { typedAxes }]` for a non-empty list and `"off"` for an empty one. **Declaring an axis is therefore sufficient to arm the rule; nothing has to be written into `eslint.config.local.ts`.** Before this the rule shipped severity `"off"` with no path from configuration to activation at all, so a project could declare every axis, install the policy, pass every test, and enforce nothing — a control installed, adopted, green and inert.
|
|
78
|
+
|
|
79
|
+
An axis name outside the six is passed straight through to ESLint's own schema validation, which rejects it by name. Filtering it out instead would turn a typo into silent non-enforcement, which is the same failure one layer down.
|
|
80
|
+
|
|
77
81
|
The intake probe's regime is **observed**; the lint rule's is **declared**, and the declared list can go stale relative to the map. It is still the correct division — an over-firing lint rule is a disabled lint rule, and a rule that silently skipped an axis it could not verify would be worse than one that skips an axis nobody declared. Intake is the arm that sees the truth; lint is the arm that catches the same defect at authoring time on the axes the project has already committed to.
|
|
78
82
|
|
|
79
83
|
## A design source is optional
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "3.47.
|
|
3
|
+
"version": "3.47.6",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "3.47.
|
|
3
|
+
"version": "3.47.6",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "3.47.
|
|
3
|
+
"version": "3.47.6",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "3.47.
|
|
3
|
+
"version": "3.47.6",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "3.47.
|
|
3
|
+
"version": "3.47.6",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|