solid2-agent-kit 0.23.0 → 0.24.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/bin/baseline.mjs CHANGED
@@ -19,14 +19,14 @@
19
19
  // pulls them in — so doctor also checks an undeclared install of any package
20
20
  // here, which is where a lockfile holds an older compiler.
21
21
  export const BASELINE = {
22
- 'solid-js': { line: 2, baseline: '2.0.0-rc.17' },
23
- '@solidjs/web': { line: 2, baseline: '2.0.0-rc.17' },
24
- '@solidjs/signals': { line: 2, baseline: '2.0.0-rc.17' },
25
- '@solidjs/diagnostics': { line: 2, baseline: '2.0.0-rc.17' },
26
- '@solidjs/compiler': { line: 2, baseline: '2.0.0-rc.17' },
27
- '@solidjs/babel-plugin': { line: 2, baseline: '2.0.0-rc.17' },
28
- '@solidjs/router': { line: 2, baseline: '2.0.0-next.42' },
29
- '@solidjs/vite-plugin': { line: 3, baseline: '3.0.0-next.51' },
22
+ 'solid-js': { line: 2, baseline: '2.0.0-rc.19' },
23
+ '@solidjs/web': { line: 2, baseline: '2.0.0-rc.19' },
24
+ '@solidjs/signals': { line: 2, baseline: '2.0.0-rc.19' },
25
+ '@solidjs/diagnostics': { line: 2, baseline: '2.0.0-rc.19' },
26
+ '@solidjs/compiler': { line: 2, baseline: '2.0.0-rc.19' },
27
+ '@solidjs/babel-plugin': { line: 2, baseline: '2.0.0-rc.19' },
28
+ '@solidjs/router': { line: 2, baseline: '2.0.0-next.43' },
29
+ '@solidjs/vite-plugin': { line: 3, baseline: '3.0.0-next.52' },
30
30
  '@solidjs/testing-library': { line: 1, baseline: '1.0.0-rc.2' },
31
31
  };
32
32
 
@@ -849,12 +849,13 @@ const CHECKS = [
849
849
  },
850
850
  ];
851
851
 
852
- // Named imports from "@solidjs/router" among `names`, located at the name inside
853
- // the import list. Only the imported name counts: `action as save` is flagged,
854
- // `formAction as action` (the local name) is not.
852
+ // Named imports (and re-exports) from "@solidjs/router" or its `/data` subpath
853
+ // among `names`, located at the name inside the import list. Only the imported
854
+ // name counts: `action as save` is flagged, `formAction as action` (the local
855
+ // name) is not.
855
856
  function routerImportFindings(content, names) {
856
857
  const findings = [];
857
- for (const statement of content.matchAll(/import\s+(?:type\s+)?\{([^}]*)\}\s*from\s*['"]@solidjs\/router['"]/g)) {
858
+ for (const statement of content.matchAll(/(?:import|export)\s*(?:type\s+)?\{([^}]*)\}\s*from\s*['"]@solidjs\/router(?:\/data)?['"]/g)) {
858
859
  const list = statement[1];
859
860
  const offset = statement.index + statement[0].indexOf(list);
860
861
  for (const name of names) {
@@ -5,4 +5,4 @@
5
5
  - After editing TSX, run the `solid2-kit check` mechanical gate — it fails on React/Solid 1.x tokens and props destructuring. Use the project's `lint:solid` script if one exists; otherwise `npx solid2-agent-kit check` (with the kit as a devDependency) or `npx github:lightsound/solid2-agent-kit check`. An edit-time hook may also run this gate automatically after each file edit — treat its findings as errors to fix immediately, not warnings. Do not install `eslint-plugin-solid` (built for Solid 1.x; misreads Solid 2 idioms).
6
6
  - After editing `package.json`, `tsconfig*.json`, or root config files (Vite, ESLint), run `solid2-kit doctor` — it fails on React/Solid 1.x wiring: `react`/`vite-plugin-solid`/`eslint-plugin-solid`/SolidStart dependencies, 1.x `solid-js` ranges, and `jsx`/`jsxImportSource` values other than `preserve`/`@solidjs/web`.
7
7
  - The kit's guidance and gate files (`.cursor/rules/solid-2.mdc`, the `solid-2` skill directories, hook entries, managed blocks in this file and `CLAUDE.md`) are guardrails, not obstacles. Never edit, weaken, bypass, or delete them to make a failure go away — fix the flagged code. If a guardrail seems wrong, stop and tell the user.
8
- - Solid 2.0 shipped recently and breaks with 1.x — never trust pre-2.0 Solid docs, tutorials, or training knowledge. Verify APIs against https://v2-rebuild--solid-docs-v2.netlify.app/llms.txt (markdown mirror of https://v2.solidjs.com/, which blocks non-browser fetchers). If the project has `@solidjs/router`, server functions, or `@solidjs/meta`, use those official pages (see the skill's official-docs index) — not React Router, Next.js, SolidStart 1.x, or Solid Router 0.x/1.x JSX `<Route>`/`<A>`. Core `action` from `solid-js` is a generator transaction; router `formAction`/`query` from `@solidjs/router` are POST forms and a read cache (router `action` is a deprecated alias of `formAction`, and `useAction` is deprecated: call the server function directly — a mounted router applies its revalidation and redirect on any call <!-- upstream:router-action-deprecated -->). React `useDeferredValue` is `createDeferred(fn)`: an async memo that lags but never leads <!-- upstream:create-deferred-export -->. Core `refresh(source)`, router `revalidate(key)`, and server-function `return reload(...)` are three different APIs. Pass the accessor to `isPending(user)`, not `isPending(user())`. Pass async values as values (`user={user()}`) — JSX props are lazy; types stay `User`, not `Promise<User>`. `<Loading>` wraps the read, not the memo. Nested fetches run in parallel (components do not suspend). `isPending` is a per-expression question (`isPending(() => props.story)` / `isPending(selectedId)`), not a global spinner; `latest(selectedId)` is opt-in so highlight and content stay consistent by default. `<Errored>` heals when the source succeeds. Pass a function to `render`/`hydrate`: `render(() => <App />, root)`. Component teardown is `onSettled`, not `onCleanup` — return the cleanup; `onCleanup`, memo/effect creation, and `flush()` throw inside the `onSettled` callback in dev. Creating a memo/effect/root inside an effect's `apply` callback throws in dev too (`[PRIMITIVE_IN_EFFECT_CALLBACK]`) — create it in the body or compute phase. <!-- upstream:primitive-in-effect-callback --> Effect `apply` functions use block bodies (`(t) => { document.title = t; }`): any return value other than a cleanup function halts reactivity. Stores are written only through the setter's draft — writes to the store itself are ignored (dev warns `[STORE_WRITE_OUTSIDE_SETTER]` <!-- upstream:store-write-outside-setter -->), and `Map`/`Set`/`Date` inside a store are not tracked. Shared state, app-wide included, is created in a provider at the root of `App` (`createContext<T>()` + `useX()`), never a module-level signal/store (one instance serves every SSR request). Errors thrown out of an `action` never reach `<Errored>` — catch them in the action or `.catch` the call. One router instance; in-app navigation is `useNavigate` / `<a href>`, not `window.location`. Types: `solid-js` exports no `JSX` namespace — markup types are `JSX.Element` from `@solidjs/web` or `Element` from `solid-js` (alias it `SolidElement` next to DOM code) <!-- upstream:jsx-namespace-absent -->. Reset-a-signal-on-change is a writable derivation (`createSignal(() => { source(); return initial; })`), never an effect calling the setter. Client mode mounts with `render()` into an empty body — no hydration mismatch exists, so never defer initial values to post-mount React-style (that can overwrite persisted state). Client → server is additive (same setters + `action` + server functions): do not rewrite App with loading/error branches, disable optimistic rows until ack, invent tRPC, or refetch in `hydrate`/`onSettled`. The graph continues across the wire (`live()` owns the client connection; `<Reveal>` not a delayed stream). A server bundle uses `handleRequest` / Fetchable `fetch`; client-only start is static `dist/client`. One browser-only value takes `ssrSource: "client"` on the memo/signal/derived store, not a `clientOnly` component split. Router link state is `aria-current`/`data-active` + CSS (`data-pending` is opt-in via `createRouter({ links: pendingLinks })`; `useLinkState`/`useIsRouting` in JSX) <!-- upstream:pending-links-opt-in -->; link preloading is opt-in too (`preloadLinks: intentPreload()` for hover/focus/touch; none by default; opt one link out with the string `preload="false"`) <!-- upstream:preload-links-opt-in -->; search params via `useSearchParams`; router forms validate on the server (`throw respond({issues},{400})`) with inline errors from `useSubmissions`. Confirmations on another channel — fire-and-forget sends, and mutations whose result is read through `live()` — wait with `yield until(predicate, {timeout})`, not `refresh()`. Declare live reads `live(fn)` — it implies `GET` (`live(GET(fn))` is the same) <!-- upstream:live-implies-get -->. Debounce at the handler; inputs feeding a request bind `latest(query)`. Dev diagnostics are errors: `[STRICT_READ_UNTRACKED]` means a read outside a tracking scope, `[ASYNC_STORE_SETTER]` means a store setter callback awaited (the draft is a synchronous transaction — await first, then write) <!-- upstream:async-store-setter-throws -->, a held write needs `isPending`/`latest`/optimistic/`affects` feedback or dev + attribution reports `[SILENT_HOLD]`, and `[UNCOMMITTED_INPUT_OVERWRITTEN]` means a `value`/`checked` binding re-wrote the bound value over text the user typed but never committed (`value={props.name} onChange={commit}` with no draft signal) — bind a draft signal written from `onInput`, or `defaultValue` <!-- upstream:uncommitted-input-overwritten -->. Error monitoring is `configureClientErrors` / `configureServerErrors` (or per root `render(fn, root, undefined, { onError })` — options are the 4th argument), not a side effect inside `<Errored fallback>`; the server hook must return a reference or nothing, never the error itself. `<Dynamic>` is deprecated — use `dynamic()`. <!-- upstream:dynamic-deprecated --> Observability is on by default in development: whenever a change touches stores, lists, async, actions, or effects, keep the dev console free of `[CODE]` findings and run an attribution session (`/__solid/diagnostics` `begin` → interact → `whyDidRun` / `costs` → `end` with `@solidjs/diagnostics` installed, otherwise `isDev`-guarded `attribution.enable({ log: false })` + `why()` / `costs()`) before finishing. `vite dev` is always the dev build; `solid({ observe: true })` is a production opt-in.
8
+ - Solid 2.0 shipped recently and breaks with 1.x — never trust pre-2.0 Solid docs, tutorials, or training knowledge. Verify APIs against https://v2-rebuild--solid-docs-v2.netlify.app/llms.txt (markdown mirror of https://v2.solidjs.com/, which blocks non-browser fetchers). If the project has `@solidjs/router`, server functions, or `@solidjs/meta`, use those official pages (see the skill's official-docs index) — not React Router, Next.js, SolidStart 1.x, or Solid Router 0.x/1.x JSX `<Route>`/`<A>`. Core `action` from `solid-js` is a generator transaction; router `formAction`/`query` from `@solidjs/router` are POST forms and a read cache (router `action` is a deprecated alias of `formAction`, and `useAction` is deprecated: call the server function directly — a mounted router applies its revalidation and redirect on any call <!-- upstream:router-action-deprecated -->). React `useDeferredValue` is `createDeferred(fn)`: an async memo that lags but never leads <!-- upstream:create-deferred-export -->. Core `refresh(source)`, router `revalidate(key)`, and server-function `return reload(...)` are three different APIs. Pass the accessor to `isPending(user)`, not `isPending(user())`. Pass async values as values (`user={user()}`) — JSX props are lazy; types stay `User`, not `Promise<User>`. `<Loading>` wraps the read, not the memo. Nested fetches run in parallel (components do not suspend). `isPending` is a per-expression question (`isPending(() => props.story)` / `isPending(selectedId)`), not a global spinner; `latest(selectedId)` is opt-in so highlight and content stay consistent by default. `<Errored>` heals when the source succeeds. Pass a function to `render`/`hydrate`: `render(() => <App />, root)`. Component teardown is `onSettled`, not `onCleanup` — return the cleanup; `onCleanup`, memo/effect creation, and `flush()` throw inside the `onSettled` callback in dev. Creating a memo/effect/root inside an effect's `apply` callback throws in dev too (`[PRIMITIVE_IN_EFFECT_CALLBACK]`) — create it in the body or compute phase. <!-- upstream:primitive-in-effect-callback --> Effect `apply` functions use block bodies (`(t) => { document.title = t; }`): any return value other than a cleanup function halts reactivity. Stores are written only through the setter's draft — writes to the store itself are ignored (dev warns `[STORE_WRITE_OUTSIDE_SETTER]` <!-- upstream:store-write-outside-setter -->), and `Map`/`Set`/`Date` inside a store are not tracked. Shared state, app-wide included, is created in a provider at the root of `App` (`createContext<T>()` + `useX()`), never a module-level signal/store (one instance serves every SSR request). Errors thrown out of an `action` never reach `<Errored>` — catch them in the action or `.catch` the call. One router instance; in-app navigation is `useNavigate` / `<a href>`, not `window.location`. Types: `solid-js` exports no `JSX` namespace — markup types are `JSX.Element` from `@solidjs/web` or `Element` from `solid-js` (alias it `SolidElement` next to DOM code) <!-- upstream:jsx-namespace-absent -->. Reset-a-signal-on-change is a writable derivation (`createSignal(() => { source(); return initial; })`), never an effect calling the setter. Client mode mounts with `render()` into an empty body — no hydration mismatch exists, so never defer initial values to post-mount React-style (that can overwrite persisted state). Client → server is additive (same setters + `action` + server functions): do not rewrite App with loading/error branches, disable optimistic rows until ack, invent tRPC, or refetch in `hydrate`/`onSettled`. The graph continues across the wire (`live()` owns the client connection; `<Reveal>` not a delayed stream). A server bundle uses `handleRequest` / Fetchable `fetch`; client-only start is static `dist/client`. One browser-only value takes `ssrSource: "client"` on the memo/signal/derived store, not a `clientOnly` component split. Router link state is `aria-current`/`data-active` + CSS (`data-pending` is opt-in via `createRouter({ links: pendingLinks })`; `useLinkState`/`useIsRouting` in JSX) <!-- upstream:pending-links-opt-in -->; link preloading is opt-in too (`preloadLinks: intentPreload()` for hover/focus/touch; none by default; opt one link out with the string `preload="false"`) <!-- upstream:preload-links-opt-in -->; search params via `useSearchParams`; router forms validate on the server (`throw respond({issues},{400})`) with inline errors from `useSubmissions`. Confirmations on another channel — fire-and-forget sends, and mutations whose result is read through `live()` — wait with `yield until(predicate, {timeout})`, not `refresh()`. Declare live reads `live(fn)` — it implies `GET` (`live(GET(fn))` is the same) <!-- upstream:live-implies-get -->. Debounce at the handler; inputs feeding a request bind `latest(query)`. Dev diagnostics are errors: `[STRICT_READ_UNTRACKED]` means a read outside a tracking scope, `[ASYNC_STORE_SETTER]` means a store setter callback awaited (the draft is a synchronous transaction — await first, then write) <!-- upstream:async-store-setter-throws -->, a held write needs `isPending`/`latest`/optimistic/`affects` feedback or dev + attribution reports `[SILENT_HOLD]` (a write that must not join another update's hold goes in `onFlush(...)` <!-- upstream:on-flush -->), and `[UNCOMMITTED_INPUT_OVERWRITTEN]` means a `value`/`checked` binding re-wrote the bound value over text the user typed but never committed (`value={props.name} onChange={commit}` with no draft signal) — bind a draft signal written from `onInput`, or `defaultValue` <!-- upstream:uncommitted-input-overwritten -->. Error monitoring is `configureClientErrors` / `configureServerErrors` (or per root `render(fn, root, undefined, { onError })` — options are the 4th argument), not a side effect inside `<Errored fallback>`; the server hook must return a reference or nothing, never the error itself. `<Dynamic>` is deprecated — use `dynamic()`. <!-- upstream:dynamic-deprecated --> Observability is on by default in development: whenever a change touches stores, lists, async, actions, or effects, keep the dev console free of `[CODE]` findings and run an attribution session (`/__solid/diagnostics` `begin` → interact → `whyDidRun` / `costs` → `end` with `@solidjs/diagnostics` installed, otherwise `isDev`-guarded `attribution.enable({ log: false })` + `why()` / `costs()`) before finishing. `vite dev` is always the dev build; `solid({ observe: true })` is a production opt-in.
@@ -316,7 +316,8 @@ Claude Code) for full patterns, decision tables, and official documentation URLs
316
316
  <!-- upstream:uncommitted-input-overwritten -->. Bind a draft signal written from
317
317
  `onInput` (`createSignal(() => props.name)` resets it when the prop changes), use
318
318
  `defaultValue` for an uncontrolled field, or write the next value back explicitly;
319
- `equals: false` on the signal does not help (the binding, not the signal, re-runs).
319
+ `equals: false` on the bound signal is no way to reject input — a source firing with an
320
+ equal value is one of the causes the warning names, so it only adds re-writes.
320
321
  22. Miscellaneous defaults: SSR-stable element ids come from `createUniqueId()` (never
321
322
  `Math.random()` or hardcoded duplicates); pass store data to `structuredClone` /
322
323
  `postMessage` / logs via `snapshot(store)` (proxies fail or leak reactivity) — a
@@ -563,7 +564,7 @@ directory (default `src/`).
563
564
  | `createDeferred(source, { timeoutMs })` (1.x: a signal that lags by idle time) | `createDeferred(fn)` (2.0: an async memo that may lag its inputs but never leads them; `isPending(deferred)` while it catches up) <!-- upstream:create-deferred-export --> |
564
565
  | `startTransition`, `useTransition` | automatic held updates + `isPending` |
565
566
  | `onError` / `catchError` | `<Errored>` or effect bundle `{ effect, error }` |
566
- | `from(...)` / `observable(...)` (the solid-js helpers) | inbound: async iterable from a memo; outbound: split effect |
567
+ | `from(...)` / `observable(...)` (the solid-js helpers) | inbound: `from(source)` — the same name in 2.0, but it returns an AsyncIterable for a computation (`createMemo(() => from(source))`), not a signal <!-- upstream:from-source-adapts -->; outbound: split effect |
567
568
  | `createDynamic(...)`, `<Dynamic component={...}>` (deprecated in 2.0) <!-- upstream:dynamic-deprecated --> | `dynamic(source)` from `@solidjs/web` — `dynamicComponent(source)` from `solid-js` when the source only answers with a component <!-- upstream:dynamic-component-export --> |
568
569
  | `renderToStringAsync(...)` | `await renderToStream(() => <App />)` (one consumer: `pipe` / `pipeTo` / `readable`) |
569
570
  | `clearDelegatedEvents` | delete — delegated listeners are scoped to each render root |
@@ -44,7 +44,7 @@ Practical consequences:
44
44
  | App-wide state (theme, session, cart, locale) | the same provider, placed at the root of `App` — not a module-level signal/store (under SSR one module instance serves every request) |
45
45
  | Constants (a category list, a formatter, the `createContext` call) | module scope |
46
46
  | Tentative value during a mutation | `createOptimistic` / `createOptimisticStore` + `action` |
47
- | Values pushed by an external subscription (websocket, reactive client) | async iterable returned from a memo (or function-form `createStore` for keyed reconciliation) — never `{ data, error }` signal pairs |
47
+ | Values pushed by an external subscription (websocket, reactive client) | async iterable returned from a memo — `from(source)` adapts a callback subscription, an Observable, or an AsyncIterable <!-- upstream:from-source-adapts --> (or function-form `createStore` for keyed reconciliation) — never `{ data, error }` signal pairs |
48
48
 
49
49
  ### Should this be an effect?
50
50
 
@@ -162,8 +162,9 @@ seed the shape through the `createStore` argument or a derivation.
162
162
  **The store itself is read-only; only the draft writes.** An assignment or mutating
163
163
  call on the store proxy outside a setter is *ignored* — no throw, the value does not
164
164
  change, and TypeScript accepts it (`Store<T>` is `T`). Since 2.0.0-rc.17 dev warns
165
- `[STORE_WRITE_OUTSIDE_SETTER]` once per store object and key (the property and whether
166
- it was a set, define or delete); production stays silent
165
+ `[STORE_WRITE_OUTSIDE_SETTER]` once per store object and key (a later delete of a key
166
+ already reported is not reported again; the operation is only in the event's `data`);
167
+ production stays silent
167
168
  <!-- upstream:store-write-outside-setter -->. This is the
168
169
  MobX / Vue / Solid 1 `createMutable` reflex:
169
170
 
@@ -459,9 +460,20 @@ return <StoryDetail story={story} />;
459
460
  `transition-delay` so fast swaps do not flash. Inputs that feed a request follow
460
461
  the same rule: bind `value={latest(query)}` so a controlled search box reflects
461
462
  keystrokes while its write is held (an uncontrolled input needs nothing).
463
+ When one write in a handler must *not* join the hold — closing a menu before
464
+ `props.onSelect` starts a navigation — defer just that write with
465
+ `onFlush(() => setOpen(false))` (since 2.0.0-rc.19): it runs once right after the
466
+ pending flush as its own update, instead of flushing early
467
+ <!-- upstream:on-flush -->. It belongs in event handlers and effect callbacks; in a
468
+ component body or computation dev warns `ON_FLUSH_IN_OWNED_SCOPE`.
462
469
  - Read every reactive input **before the first `await`** in an async computation. A read
463
470
  after `await` does not subscribe (dev reports `[UNTRACKED_READ_AFTER_AWAIT]` on V8 —
464
471
  Chromium, Node, Deno, Bun); production can sit pending with no retry.
472
+ - An async memo returns **data**, never rendered output. On the server, a memo (or async
473
+ iterable source) landing on JSX, a component result, or a `<Loading>`/`<Errored>`
474
+ boundary cannot serialize for hydration: since 2.0.0-rc.19 the memo rejects with
475
+ `ASYNC_MEMO_ELEMENT` and the nearest `<Errored>` contains it like any render error
476
+ <!-- upstream:async-memo-element -->. Render the JSX from the data the memo returns.
465
477
  - `<Errored>` function fallbacks receive an error **accessor** and a `reset` callback:
466
478
  `fallback={(error, reset) => ...}`. The boundary **heals** when the source succeeds
467
479
  again (refresh, live reconnect, input change) — it is graph status, not a terminal
@@ -557,7 +569,15 @@ errors matter (the rc.8 one-argument form keeps working). <!-- upstream:render-o
557
569
  Push-based sources integrate by returning an **async iterable** from a computation — reads
558
570
  then suspend to `<Loading>` until the first value, later pushes update the settled value,
559
571
  and thrown errors reach `<Errored>`. Integration layers should return a plain accessor, not
560
- `{ data, error }` signals:
572
+ `{ data, error }` signals.
573
+
574
+ For a callback subscription, an Observable, or an existing AsyncIterable, the adapter is
575
+ built in: `from(source)` returns the async iterable a computation consumes —
576
+ `createMemo(() => from(source))` <!-- upstream:from-source-adapts -->. Read the inputs that
577
+ choose the source before calling it, so a change re-runs the memo, closes the old source,
578
+ and opens the new one <!-- upstream:from-source-adapts -->. The hand-rolled form below remains for what `from` does not fit —
579
+ an event stream where every message matters (keep a queue instead of conflating to the
580
+ latest), or a subscribe signature that is not `(next, error, complete) => unsubscribe`:
561
581
 
562
582
  ```tsx
563
583
  import { createMemo, onCleanup } from 'solid-js';
@@ -947,8 +967,9 @@ const [draft, setDraft] = createSignal(() => props.name);
947
967
  // 3. explicit write-back when the field must follow an external value exactly
948
968
  ```
949
969
 
950
- `equals: false` on the committed signal changes nothing — the binding re-runs, not the
951
- signal — and a `createEffect` that copies the prop into the field is rule 4 again.
970
+ `equals: false` on the committed signal makes it worse, not better — a source firing with
971
+ an equal value is one of the three causes the warning names, beside another binding in the
972
+ same template changing and a spread re-running — and a `createEffect` that copies the prop into the field is rule 4 again.
952
973
 
953
974
  ### Context
954
975
 
@@ -1233,7 +1254,7 @@ committed value over uncommitted user input <!-- upstream:uncommitted-input-over
1233
1254
  `[ASYNC_OUTSIDE_LOADING_BOUNDARY]` when a tracked read has no boundary above it, and
1234
1255
  `[LOADING_ON_OUTSIDE_HOLD]` when a `<Loading on>` boundary's data is also read outside it.
1235
1256
  Each entry carries a stable `[CODE]`, what the runtime observed, an owner chain
1236
- (`in <App> › <Cart> › <LineItem>`), and — since rc.17, under `vite dev` — an
1257
+ (`in <App> › <Cart> › <LineItem>`), and — since rc.16, under `vite dev` — an
1237
1258
  `at src/Cart.tsx:12:5` line naming where the scope was created (the compiler's
1238
1259
  `sourceNames.locations`; the same `loc` sits on every artifact event)
1239
1260
  <!-- upstream:source-names-locations -->; never silence a code before understanding it.
@@ -1291,7 +1312,7 @@ anonymous nodes print as `computed` / `effect` / `signal`; component labels
1291
1312
  (`<Checkout>`) are always present under `vite dev` and survive minification only with
1292
1313
  the compiler's `sourceNames` option (components, binding effects, primitives — the Vite
1293
1314
  plugin turns it on under `vite dev` and `observe: true`; `componentNames` was its rc.9 name
1294
- and is rejected now) <!-- upstream:source-names-option -->. Its `locations` kind (rc.17)
1315
+ and is rejected now) <!-- upstream:source-names-option -->. Its `locations` kind (rc.16)
1295
1316
  adds `file:line:col` to every name — `createComponent(Home, props, "Home", "src/App.tsx:12:5")`,
1296
1317
  `{ name, loc }` on primitives — which is what the `at …` line in a diagnostic and
1297
1318
  `event.loc` in an artifact print; the plugin turns it on under `vite dev` only, and an
@@ -2179,7 +2200,7 @@ how to reuse. Prefer the form on the right.
2179
2200
  | `onClick={setCount}` | `onClick={() => setCount((c) => c + 1)}` |
2180
2201
  | `onclick={fn}` / `onmouseover={fn}` (lowercase handlers) | `onClick={fn}` — a lowercase `on*` name is a plain attribute (dev warns `[LOWERCASE_EVENT_ATTRIBUTE]`), not an event <!-- upstream:lowercase-event-attribute --> |
2181
2202
  | `on:click={fn}` / `use:tooltip` / `attr:title` / `classList={{ on: x() }}` on a native element | `onClick`, a ref callback from a directive factory, `title`, `class={["btn", { on: x() }]}` — the 1.x forms are compile errors since rc.17 (`prop:` remains) <!-- upstream:removed-attribute-compile-error --> |
2182
- | `value={props.name} onChange={(e) => props.onCommit(e.currentTarget.value)}` (bound to the committed value, no per-edit write) | a draft signal `createSignal(() => props.name)` written from `onInput`, or `defaultValue={props.name}` — the binding re-applies the committed value over uncommitted typing (`[UNCOMMITTED_INPUT_OVERWRITTEN]`); `equals: false` does not help <!-- upstream:uncommitted-input-overwritten --> |
2203
+ | `value={props.name} onChange={(e) => props.onCommit(e.currentTarget.value)}` (bound to the committed value, no per-edit write) | a draft signal `createSignal(() => props.name)` written from `onInput`, or `defaultValue={props.name}` — the binding re-applies the committed value over uncommitted typing (`[UNCOMMITTED_INPUT_OVERWRITTEN]`); `equals: false` is one of its causes, not a fix <!-- upstream:uncommitted-input-overwritten --> |
2183
2204
  | `useDeferredValue(query())` / `startTransition(() => setQuery(q))` for an expensive derivation | `const rows = createDeferred(() => filter(all(), query()))` — an async memo that lags but never leads its inputs; `isPending(rows)` while it catches up. Unrelated to the 1.x `createDeferred(source, { timeoutMs })` <!-- upstream:create-deferred-export --> |
2184
2205
  | `event.target.value` | `event.currentTarget.value` |
2185
2206
  | `createContext(emptyStore)` for reactive state | `createContext<Todos>()` — dummy defaults silently no-op |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solid2-agent-kit",
3
- "version": "0.23.0",
3
+ "version": "0.24.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",