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 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
@@ -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
+ }
@@ -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
- ' note: the solid-2 skill\'s development loop drives the dev server\'s /__solid/diagnostics endpoint; add "@solidjs/diagnostics" to devDependencies so @solidjs/vite-plugin serves it (auto-on when declared). Without it the fallback is an isDev-guarded attribution.enable({ log: false }).',
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 { name, id, solid1, fix } of SOLID2_LINE_PACKAGES) {
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 === 'string' && solid1.test(range)) {
1289
- report(id, `package.json pins ${name} "${range}" — the Solid 1.x line; this kit teaches Solid 2.x. ${fix}`);
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 line once resolved.
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
- if (installed && solid1.test(installed)) {
1296
- report(
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`, the Vite plugin's
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.17.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",