solid2-agent-kit 0.17.0 → 0.18.0
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/README.md +2 -1
- package/bin/baseline.mjs +41 -0
- package/bin/solid2-kit.mjs +36 -12
- package/files/skills/solid-2/SKILL.md +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Supported agents: **Cursor** and **Claude Code**.
|
|
|
20
20
|
| Edit-time hook | `postToolUse` entry in `.cursor/hooks.json` | `PostToolUse` entry in `.claude/settings.json` (matcher includes `Bash`) | Runs the mechanical gate automatically on **every agent file edit — including edits made through shell commands** (sed, heredocs, codemods; source paths mentioned in the command are checked after it ran) — and feeds findings straight back into the conversation (Cursor: `additional_context`; Claude Code: stderr + exit 2), so enforcement does not depend on the agent remembering to run `check`. Wired only when the kit is a local devDependency; opt out with `--no-hooks` |
|
|
21
21
|
| Turn-end gate | — | `Stop` entry in `.claude/settings.json` | Whole-project `check` + `doctor` when the agent tries to end its turn: with findings in place the stop is blocked (exit 2) and the findings are fed back, so a turn cannot finish with React/Solid 1.x patterns left behind. Loop-safe via `stop_hook_active` (one forced continuation, never an infinite loop) |
|
|
22
22
|
| Pre-execution guard | `preToolUse` + `beforeShellExecution` entries in `.cursor/hooks.json` | `PreToolUse` entry in `.claude/settings.json` | Denies actions **before they run**: edits/deletes of kit-owned guardrail files (an agent blocked by a gate will try to remove the gate), edits that would strip the kit's hook entries or managed blocks, uninspectable shell rewrites of those files, and `npm/pnpm/yarn/bun install` of banned dependencies (`react`, `vite-plugin-solid`, `eslint-plugin-solid`, SolidStart, ...) — caught proactively instead of post-hoc by `doctor` |
|
|
23
|
-
| Project-wiring gate | `solid2-kit doctor` | same | Config drift the source gate cannot see: React / `vite-plugin-solid` / `eslint-plugin-solid` / SolidStart deps in `package.json`, a Solid 1.x line of `solid-js` / `@solidjs/router` / `@solidjs/meta` / `@solidjs/testing-library` / `@tanstack/solid-router` / `@tanstack/solid-query` (declared, or installed from the `latest` tag — Solid 2 releases are on `next`; TanStack Router's and Query's on `rc`), `jsx` ≠ `preserve` or `jsxImportSource` ≠ `@solidjs/web` in tsconfig, Solid 1.x wiring in root config files, and stale installed guidance (kit updated but `sync` not re-run) |
|
|
23
|
+
| Project-wiring gate | `solid2-kit doctor` | same | Config drift the source gate cannot see: React / `vite-plugin-solid` / `eslint-plugin-solid` / SolidStart deps in `package.json`, a Solid 1.x line of `solid-js` / `@solidjs/router` / `@solidjs/meta` / `@solidjs/testing-library` / `@tanstack/solid-router` / `@tanstack/solid-query` (declared, or installed from the `latest` tag — Solid 2 releases are on `next`; TanStack Router's and Query's on `rc`), a Solid 2 prerelease older than the kit's baseline in `bin/baseline.mjs` (`@solidjs/web` / `@solidjs/signals` / `@solidjs/diagnostics` `latest` is an older rc than `next`), `jsx` ≠ `preserve` or `jsxImportSource` ≠ `@solidjs/web` in tsconfig, Solid 1.x wiring in root config files, and stale installed guidance (kit updated but `sync` not re-run) |
|
|
24
24
|
| Review command | `.cursor/commands/solid2-review.md` | `.claude/commands/solid2-review.md` | `/solid2-review` — on-demand deep review: runs both gates, then walks the diff against the skill checklist targeting the semantic failure classes regexes cannot see (post-`await` reads, effect misuse, unkeyed server rows, boundary placement, context snapshots) |
|
|
25
25
|
|
|
26
26
|
Managed blocks are delimited with `<!-- solid2-agent-kit:*:start/end -->` markers; everything
|
|
@@ -169,6 +169,7 @@ markdown with an `.md` suffix).
|
|
|
169
169
|
|
|
170
170
|
```
|
|
171
171
|
bin/solid2-kit.mjs CLI: init / sync / check / doctor / hook
|
|
172
|
+
bin/baseline.mjs Solid 2 versions the kit is verified against (doctor + check:upstream)
|
|
172
173
|
files/shared/rules-body.md hard rules (rendered into .mdc and CLAUDE.md)
|
|
173
174
|
files/shared/agents-section.md AGENTS.md managed-block content
|
|
174
175
|
files/skills/solid-2/ SKILL.md + references/official-docs.md
|
package/bin/baseline.mjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// The Solid 2 releases the kit's guidance is verified against, shared by
|
|
2
|
+
// `solid2-kit doctor` (a project on an older release is flagged) and
|
|
3
|
+
// check:upstream (scripts/upstream-probes/registry.mjs: a newer release is
|
|
4
|
+
// flagged). `line` is the major the kit targets: check:upstream installs the
|
|
5
|
+
// newest dist-tagged version on it. `baseline` is the version every upstream
|
|
6
|
+
// probe was verified against — bump it (and fix any marked claim that changed)
|
|
7
|
+
// after re-verifying.
|
|
8
|
+
//
|
|
9
|
+
// npm dist-tags lag each other on these prereleases (@solidjs/web, @solidjs/signals
|
|
10
|
+
// and @solidjs/diagnostics `latest` is an older 2.0 rc than `next`;
|
|
11
|
+
// @solidjs/vite-plugin's `next` is behind `latest`), so a bare install can
|
|
12
|
+
// resolve a release older than the baseline.
|
|
13
|
+
export const BASELINE = {
|
|
14
|
+
'solid-js': { line: 2, baseline: '2.0.0-rc.9' },
|
|
15
|
+
'@solidjs/web': { line: 2, baseline: '2.0.0-rc.9' },
|
|
16
|
+
'@solidjs/signals': { line: 2, baseline: '2.0.0-rc.9' },
|
|
17
|
+
'@solidjs/diagnostics': { line: 2, baseline: '2.0.0-rc.9' },
|
|
18
|
+
'@solidjs/router': { line: 2, baseline: '2.0.0-next.27' },
|
|
19
|
+
'@solidjs/vite-plugin': { line: 3, baseline: '3.0.0-next.44' },
|
|
20
|
+
'@solidjs/testing-library': { line: 1, baseline: '1.0.0-beta.3' },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function parseVersion(version) {
|
|
24
|
+
const [core, pre] = version.split('+')[0].split(/-(.*)/s);
|
|
25
|
+
return { core: core.split('.').map(Number), pre: pre ? pre.split('.') : [] };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Semver precedence, prerelease-aware (2.0.0-rc.10 > 2.0.0-rc.9 < 2.0.0).
|
|
29
|
+
export function compareVersions(a, b) {
|
|
30
|
+
const x = parseVersion(a);
|
|
31
|
+
const y = parseVersion(b);
|
|
32
|
+
for (let i = 0; i < 3; i++) if (x.core[i] !== y.core[i]) return x.core[i] - y.core[i];
|
|
33
|
+
if (!x.pre.length || !y.pre.length) return y.pre.length - x.pre.length;
|
|
34
|
+
for (let i = 0; i < Math.max(x.pre.length, y.pre.length); i++) {
|
|
35
|
+
const [p, q] = [x.pre[i], y.pre[i]];
|
|
36
|
+
if (p === undefined || q === undefined) return p === undefined ? -1 : 1;
|
|
37
|
+
const numeric = /^\d+$/.test(p) && /^\d+$/.test(q);
|
|
38
|
+
if (p !== q) return numeric ? Number(p) - Number(q) : /^\d+$/.test(p) ? -1 : /^\d+$/.test(q) ? 1 : p < q ? -1 : 1;
|
|
39
|
+
}
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
package/bin/solid2-kit.mjs
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from 'node:fs';
|
|
25
25
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
26
26
|
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import { BASELINE, compareVersions } from './baseline.mjs';
|
|
27
28
|
|
|
28
29
|
const KIT_ROOT = fileURLToPath(new URL('..', import.meta.url));
|
|
29
30
|
const VERSION = JSON.parse(readFileSync(join(KIT_ROOT, 'package.json'), 'utf8')).version;
|
|
@@ -273,7 +274,7 @@ function init() {
|
|
|
273
274
|
if (hooksNote) console.log(` note: ${hooksNote}`);
|
|
274
275
|
if (!hasDiagnosticsDependency(target)) {
|
|
275
276
|
console.log(
|
|
276
|
-
|
|
277
|
+
` note: the solid-2 skill's development loop drives the dev server's /__solid/diagnostics endpoint; add "@solidjs/diagnostics" to devDependencies (install @solidjs/diagnostics@^${BASELINE['@solidjs/diagnostics'].baseline} — npm \`latest\` can be an older rc) so @solidjs/vite-plugin serves it (auto-on when declared). Without it the fallback is an isDev-guarded attribution.enable({ log: false }).`,
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
280
|
}
|
|
@@ -1259,6 +1260,31 @@ const SOLID2_LINE_PACKAGES = [
|
|
|
1259
1260
|
},
|
|
1260
1261
|
];
|
|
1261
1262
|
|
|
1263
|
+
// Packages doctor checks the version of: the Solid 1.x lines above, then any
|
|
1264
|
+
// release older than the kit's baseline (bin/baseline.mjs) — a bare
|
|
1265
|
+
// `npm i @solidjs/web` installs `latest`, 2.0.0-rc.0, which the current
|
|
1266
|
+
// @solidjs/vite-plugin's `@solidjs/web ^2.0.0-rc.9` peer rejects.
|
|
1267
|
+
const VERSION_CHECKED = [...new Set([...SOLID2_LINE_PACKAGES.map((p) => p.name), ...Object.keys(BASELINE)])];
|
|
1268
|
+
|
|
1269
|
+
// The lower bound of a single-comparator range ("^2.0.0-rc.0", "~2.0.0-rc.8",
|
|
1270
|
+
// ">=2.0.0-rc.0", "2.0.0-rc.0") or an installed version. Dist-tags, "*",
|
|
1271
|
+
// unions and protocol specs have no bound to read; their install is checked.
|
|
1272
|
+
const LOWER_BOUND = /^\s*(?:[\^~]|>=|=)?\s*v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\s*$/;
|
|
1273
|
+
|
|
1274
|
+
// `declared` ranges are judged by their floor: npm installs the `latest` tag
|
|
1275
|
+
// whenever it satisfies the range, so "^2.0.0-rc.0" resolves to rc.0 today.
|
|
1276
|
+
function versionProblem(name, version, declared) {
|
|
1277
|
+
const line = SOLID2_LINE_PACKAGES.find((p) => p.name === name);
|
|
1278
|
+
if (line?.solid1.test(version)) return `the Solid 1.x line; this kit teaches Solid 2.x. ${line.fix}`;
|
|
1279
|
+
const baseline = BASELINE[name]?.baseline;
|
|
1280
|
+
const lowest = version.match(LOWER_BOUND)?.[1];
|
|
1281
|
+
if (baseline && lowest && compareVersions(lowest, baseline) < 0) {
|
|
1282
|
+
const older = declared ? 'allows releases older than' : 'older than';
|
|
1283
|
+
return `${older} ${baseline}, the release this kit's guidance is verified against (npm dist-tags lag on the Solid 2 prereleases, so a bare install can resolve an older one). Install ${name}@^${baseline}.`;
|
|
1284
|
+
}
|
|
1285
|
+
return null;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1262
1288
|
function installedVersion(target, name) {
|
|
1263
1289
|
try {
|
|
1264
1290
|
return JSON.parse(readFileSync(join(target, 'node_modules', name, 'package.json'), 'utf8')).version;
|
|
@@ -1283,21 +1309,19 @@ function doctorFindings(target) {
|
|
|
1283
1309
|
for (const [name, message] of Object.entries(BANNED_DEPS)) {
|
|
1284
1310
|
if (name in deps) report(`dep-${name.replace(/[@/]/g, '')}`, `package.json depends on "${name}". ${message}`);
|
|
1285
1311
|
}
|
|
1286
|
-
for (const
|
|
1312
|
+
for (const name of VERSION_CHECKED) {
|
|
1313
|
+
const id = SOLID2_LINE_PACKAGES.find((p) => p.name === name)?.id ?? `${name.replace('@solidjs/', '')}-version`;
|
|
1287
1314
|
const range = deps[name];
|
|
1288
|
-
if (typeof range
|
|
1289
|
-
|
|
1315
|
+
if (typeof range !== 'string') continue;
|
|
1316
|
+
const declared = versionProblem(name, range, true);
|
|
1317
|
+
if (declared) {
|
|
1318
|
+
report(id, `package.json pins ${name} "${range}" — ${declared}`);
|
|
1290
1319
|
continue;
|
|
1291
1320
|
}
|
|
1292
|
-
// A range such as "latest" or "*" only shows its
|
|
1293
|
-
if (range === undefined) continue;
|
|
1321
|
+
// A range such as "latest" or "*" only shows its version once resolved.
|
|
1294
1322
|
const installed = installedVersion(target, name);
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
id,
|
|
1298
|
-
`node_modules has ${name} ${installed} (package.json: "${range}") — the Solid 1.x line; this kit teaches Solid 2.x. ${fix}`,
|
|
1299
|
-
);
|
|
1300
|
-
}
|
|
1323
|
+
const resolved = installed && versionProblem(name, installed, false);
|
|
1324
|
+
if (resolved) report(id, `node_modules has ${name} ${installed} (package.json: "${range}") — ${resolved}`);
|
|
1301
1325
|
}
|
|
1302
1326
|
|
|
1303
1327
|
for (const entry of readdirSync(target, { withFileTypes: true })) {
|
|
@@ -1179,7 +1179,8 @@ effects** — a pure markup or styling change does not need it.
|
|
|
1179
1179
|
2. **Name the scopes you changed** (`createMemo(fn, { name: "total" })`,
|
|
1180
1180
|
`createStore(v, { name: "cart" })`) so chains and tables refer to them by name.
|
|
1181
1181
|
3. **Record the interaction and ask.** First choice — no app code — is the diagnostics
|
|
1182
|
-
endpoint: with `@solidjs/diagnostics` in `devDependencies
|
|
1182
|
+
endpoint: with `@solidjs/diagnostics` in `devDependencies` at the same version as
|
|
1183
|
+
`solid-js` (npm `latest` can lag; `solid2-kit doctor` flags an older one), the Vite plugin's
|
|
1183
1184
|
`diagnostics` option (auto-on when the package is declared; dev server only, never
|
|
1184
1185
|
under vitest, `vite build`, or preview) injects the capture bridge and serves
|
|
1185
1186
|
`/__solid/diagnostics`. `begin` enables attribution with `log: false` for the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid2-agent-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Teach AI coding agents (Cursor, Claude Code) to write correct Solid 2.0 instead of React or Solid 1.x — always-applied rules, an agent skill, and a mechanical pattern gate.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|