sygnal 6.1.0 → 6.1.1
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 +35 -0
- package/dist/astro/index.cjs.js +60 -14
- package/dist/astro/index.cjs.js.map +1 -1
- package/dist/astro/index.mjs +60 -14
- package/dist/astro/index.mjs.map +1 -1
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/agent.md +10 -2
- package/dist/index.d.ts +45 -1
- package/dist/vike/config/package.json +1 -1
- package/dist/vite/plugin.cjs.js +60 -14
- package/dist/vite/plugin.cjs.js.map +1 -1
- package/dist/vite/plugin.mjs +60 -14
- package/dist/vite/plugin.mjs.map +1 -1
- package/package.json +1 -1
- package/src/extra/diagnostics/checks/index.ts +1 -1
- package/src/extra/diagnostics/checks/public.d.ts +44 -0
- package/src/index.d.ts +3 -0
- package/src/vite/plugin.d.ts +16 -3
- package/src/vite/plugin.ts +66 -18
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Sygnal are listed here. Versions follow [semantic versioning](https://semver.org). Releases before 5.4.0 are described in the [GitHub releases](https://github.com/tpresley/sygnal/releases) and tags.
|
|
4
4
|
|
|
5
|
+
## 6.1.1 — 2026-10-10
|
|
6
|
+
|
|
7
|
+
Editor tooling (PLAN-7). A language server, `sygnal-check lsp`, shows the checker's findings in the editor while you type: an intent selector that matches nothing, an action with no model entry, an EVENTS type nobody listens to, and the other wiring bugs that fail silently at runtime and that TypeScript can't see. It runs in VS Code (a new extension), Claude Code (a new plugin), Neovim, Helix, JetBrains IDEs (LSP4IJ) and any other LSP editor, all from the one server in `sygnal-check`, so the editor, the CLI, the Vite overlay and CI report the same findings from the same config file.
|
|
8
|
+
|
|
9
|
+
`sygnal` itself only changes in `sygnal/vite` (the `check` option reads the config file) and in the static diagnostic types: the core doesn't change (the size gate measures 42,690 B, as in 6.1.0).
|
|
10
|
+
|
|
11
|
+
**Measured impact.** On a generated 20,000-line project (`dev-plans/research/p7-spikes/0-A`, Apple M3 Max): a cold check takes about 230 ms (was about 400 ms) and a re-check after a one-file edit about 80 ms with the parse cache; in the editor an edit shows its findings about 260 ms later (150 ms of it the typing pause), and a hover answers in under 1 ms while a check runs. The server reports exactly what the CLI reports on every example app and fixture set (40 parity cases). Verified clients: VS Code 1.138, Claude Code 2.1.287, Neovim 0.12, Helix 25.07 and IntelliJ IDEA Community 2025.2 with LSP4IJ 0.21. Size: the kanban gate is unchanged, (a) 42,690 B with `nativeGlobalThis: false` (budget 42,700 B) and (b) 38,679 B by default. Whether in-editor findings help coding agents is measured after the release (PLAN-7 E-1).
|
|
12
|
+
|
|
13
|
+
**Companion packages.**
|
|
14
|
+
- **`sygnal-check` 0.4.0:** the language server (`sygnal-check lsp`), the config file, ranges, `related` locations and fixes on every finding, `sources` and a parse cache in the API, and a faster checker.
|
|
15
|
+
- **`create-sygnal-app` 2.2.0:** every template depends on `sygnal` ^6.1.1 and `sygnal-check` ^0.4.0, recommends the VS Code extension and carries `sygnal-check.config.json` (`strict: true`).
|
|
16
|
+
- **VS Code extension 0.1.0** (`sygnal.sygnal`, VS Code Marketplace and Open VSX) and **Claude Code plugin 0.1.0** (`/plugin marketplace add tpresley/sygnal`): new; see the [editor setup guide](https://sygnal.js.org/integration/editors/).
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`sygnal-check lsp`: a language server.** Stdio, part of `sygnal-check` (no new dependency). Findings for the whole project while you type, including unsaved buffers, with exact ranges and related locations; a hover with each code's explanation; quick fixes ("did you mean", the strict rewrites, "add a model entry"), "fix all" (what `--fix` does, on the unsaved text) and "suppress on this line". Checks run in a worker thread: on a 20,000-line project an edit shows its findings in about 260 ms (150 ms of it the typing pause) and a hover answers in under 1 ms during a check. Diagnostics are pushed, never pulled. Settings (`sygnal.strict`, `a11y`, `ignore`, `paths`, `verbose`, `trace.server`) override the config file per folder.
|
|
21
|
+
- **VS Code extension** (`editors/vscode/`, id `sygnal.sygnal`): runs the project's `sygnal-check` when it has the language server, else a bundled copy (always the bundled one in an untrusted workspace); commands Restart Server, Show Output, Explain Code…, Fix All in File; per-folder settings; snippets for a canonical component, an `EFFECT` entry and an `EVENTS` entry (JS and TS).
|
|
22
|
+
- **Claude Code plugin** (`editors/claude-code/`, marketplace `.claude-plugin/marketplace.json`: `/plugin marketplace add tpresley/sygnal`, `/plugin install sygnal@sygnal`): the `sygnal-dev` skill in one install, and the language server, so the agent sees findings after its edits. Without a capable `sygnal-check` in the project the server stays quiet.
|
|
23
|
+
- **Templates** (`create-sygnal-app`, all 10): `.vscode/extensions.json` recommends the extension, and `sygnal-check.config.json` sets `strict: true` (the Vike templates also `paths: ["pages"]`), so `npx sygnal-check`, the dev overlay and the editor check the same files the same way.
|
|
24
|
+
- **`sygnal-check` config file.** `sygnal-check.config.json`, or a `"sygnal-check"` key in `package.json`: `strict`, `a11y`, `ignore`, `paths`, `includeTests`. JSON only. It is found from the working directory up to the nearest project root. The CLI (`--config <file>`, `--no-config`), the MCP server, `check()` / `graph()` and the Vite plugin read it, so the editor, the dev overlay and CI agree. Flags and explicit options win over it; problems in it are SYG900 findings on the file, never a crash.
|
|
25
|
+
- **`sygnal/vite`: the `check` option defaults to the config file.** Explicit `check.*` options win, then the config file, then the `diagnostics.strict` / `diagnostics.ignore` defaults. Editing the config file re-checks. An older `sygnal-check` without config support gets exactly the options it got before. `plugin.d.ts` now also types `check.a11y`.
|
|
26
|
+
- **Ranges on findings.** Every `sygnal-check` diagnostic has `endLine` / `endColumn` (exclusive, UTF-16 columns, as editors count). Findings on multi-line elements underline the tag name; `sygnal-ignore` comments keep matching where they did. Pair and cross-file findings carry `related` locations (SYG104: the child element that renders the class; SYG105, SYG128, SYG129, SYG440, SYG609, SYG643).
|
|
27
|
+
- **Fixes as edits.** Diagnostics carry `fixes: [{ title, kind, preferred?, fixAll?, edits }]`: every unambiguous "did you mean" (SYG110, SYG112, SYG127, SYG140–142, SYG150, SYG151, SYG223, SYG226, SYG641, SYG707; SYG105 as a non-preferred rename), the `--fix` rewrites (SYG504, SYG505, SYG506, SYG612) with their import edits, "add a model entry" for SYG101 and "remove the unreachable entry" for SYG102. `--fix` applies the same `fixAll` edits an editor gets. `controlFixes()` returns the `--controls` conversions one selector at a time.
|
|
28
|
+
- **In-memory sources and a parse cache** for editors and watchers. `check()`, `checkFiles()`, `graph()`, `graphFiles()` and `buildProject()` take `sources` (unsaved buffers; new files resolve as imports) and `cache` (`createParseCache()`: unchanged files aren't parsed again). `fixFiles()` with `sources` fixes in memory and returns the texts and edits. The MCP server keeps a cache.
|
|
29
|
+
- **Types:** `InspectDiagnostic` gains the optional `endLine`, `endColumn`, `related` and `fixes` (`InspectRelatedLocation`, `InspectFix`, `InspectTextEdit`).
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- SYG900's explanation also covers config-file findings.
|
|
34
|
+
- `sygnal-check` performance: walks over a whole file use a flat node list built once per parse. A 20,000-line project checks in about 230 ms cold (was about 400 ms) and re-checks after a one-file edit in about 80 ms with a cache (was about 350 ms without one).
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- `sygnal-check`: three module-level caches keyed by AST nodes (behavior definitions, widgets, a11y `describe()`) could serve one build's data to the next when ASTs are reused; now keyed per project.
|
|
39
|
+
|
|
5
40
|
## 6.1.0 — 2026-10-10
|
|
6
41
|
|
|
7
42
|
A new subpath, `sygnal/ai`, covers the two AI jobs Sygnal apps now meet: calling language models from the app, and letting agents operate it. A chat request is a driver request, like HTTP: the reply streams into a `delta` action and arrives whole as `ok`, through the same reply actions as `makeFetchDriver`, with transports for local models (Ollama through `openResponses()`), an AI SDK route on your server (`uiMessageStream()`), Anthropic, OpenAI-compatible APIs, AG-UI and Chrome's built-in model. `decide()` asks a decision model typed questions through the fetch driver. One declaration per component, the `agent` static, says what an LLM may read and do in the app; the same declaration becomes the tools of an in-app assistant (the `chat` behavior), a command bar (`commandBar`), browser agents through WebMCP (`experimentalExposeWebMcp`), an MCP Apps host (`makeMcpAppDriver`), and coding agents through the dev server (`sygnal({ mcp: true })`). Tests answer chat requests and call agent tools without a model.
|
package/dist/astro/index.cjs.js
CHANGED
|
@@ -666,10 +666,19 @@ if (import.meta.hot) installMcpBridge(import.meta.hot, { agentTools, confirm: ${
|
|
|
666
666
|
* `diagnostics: { mode, ignore }` unless the call sets `diagnostics`
|
|
667
667
|
* itself. With the default ('warn', no ignore list) there is no wrapper.
|
|
668
668
|
* 5. `check` option: runs sygnal-check (an optional dependency, loaded
|
|
669
|
-
* lazily from the project
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
669
|
+
* lazily from the project) over `include` when the dev server starts and
|
|
670
|
+
* again after every source file change. Settings, highest first: the
|
|
671
|
+
* explicit `check.*` options; the project's sygnal-check config file
|
|
672
|
+
* (sygnal-check.config.json or the package.json "sygnal-check" key, read
|
|
673
|
+
* by sygnal-check itself, PLAN-7 C-5 / D299; JSON only, so the editor and
|
|
674
|
+
* the CLI see the same settings without evaluating vite.config); then
|
|
675
|
+
* `strict` from `diagnostics.strict`, `ignore` from `diagnostics.ignore`,
|
|
676
|
+
* and `include` from the existing ones of src/, pages/ and renderer/,
|
|
677
|
+
* else the project root (with a notice). An older sygnal-check without
|
|
678
|
+
* config support (no `loadConfig` export) gets exactly the options it got
|
|
679
|
+
* before: the explicit ones over the `diagnostics` defaults. With config
|
|
680
|
+
* support a change to the config file also re-checks (`include` is fixed
|
|
681
|
+
* when the server starts). Results go to
|
|
673
682
|
* the terminal in sygnal-check's format, and to the browser as a
|
|
674
683
|
* 'sygnal:check' HMR event that the dev client ('virtual:sygnal/dev')
|
|
675
684
|
* logs with console.warn (non-disruptive). The dev client asks for the
|
|
@@ -1309,6 +1318,8 @@ async function loadSygnalCheck(root) {
|
|
|
1309
1318
|
}
|
|
1310
1319
|
}
|
|
1311
1320
|
const SOURCE_RE = /\.[cm]?[jt]sx?$/;
|
|
1321
|
+
// sygnal-check's config sources (PLAN-7 C-5): a change re-checks
|
|
1322
|
+
const CONFIG_FILES = ['sygnal-check.config.json', 'package.json'];
|
|
1312
1323
|
/** sygnal-check's one-line format: `file:line:col CODE [severity] Component: message (fix)` */
|
|
1313
1324
|
function formatLine(d) {
|
|
1314
1325
|
const where = d.file ? `${d.file}:${d.line}:${d.column}` : '<sygnal-check>';
|
|
@@ -1325,11 +1336,11 @@ const DEFAULT_INCLUDE = ['src', 'pages', 'renderer'];
|
|
|
1325
1336
|
* directory, or when none of the given paths exists, so an empty check is
|
|
1326
1337
|
* never a silent all-clear.
|
|
1327
1338
|
*/
|
|
1328
|
-
function checkInclude(root, include, notice) {
|
|
1339
|
+
function checkInclude(root, include, notice, label = 'check.include') {
|
|
1329
1340
|
const exists = (p) => /[*?[{]/.test(p) || fs.existsSync(path.resolve(root, p));
|
|
1330
1341
|
if (include && include.length) {
|
|
1331
1342
|
if (!include.some(exists))
|
|
1332
|
-
notice(`[sygnal] sygnal-check: none of
|
|
1343
|
+
notice(`[sygnal] sygnal-check: none of ${label} (${include.map(p => path.isAbsolute(p) ? path.relative(root, p) || '.' : p).join(', ')}) exists under ${root}, so nothing is checked`);
|
|
1333
1344
|
return include;
|
|
1334
1345
|
}
|
|
1335
1346
|
const dirs = DEFAULT_INCLUDE.filter(exists);
|
|
@@ -1347,11 +1358,43 @@ async function startChecker(server, root, opts, defaults, explicit) {
|
|
|
1347
1358
|
logger.info('[sygnal] sygnal-check is not installed, so static checks are off (npm i -D sygnal-check)');
|
|
1348
1359
|
return;
|
|
1349
1360
|
}
|
|
1350
|
-
const
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
//
|
|
1354
|
-
const
|
|
1361
|
+
const notice = (m) => logger.info(m);
|
|
1362
|
+
// PLAN-7 C-5 (D299): a sygnal-check with config support resolves the settings itself:
|
|
1363
|
+
// explicit check.* options > its config file > the `diagnostics` defaults passed as `defaults`.
|
|
1364
|
+
// An older one gets exactly what it got before.
|
|
1365
|
+
const configAware = typeof mod.loadConfig === 'function';
|
|
1366
|
+
let include;
|
|
1367
|
+
let checkOptions;
|
|
1368
|
+
if (configAware) {
|
|
1369
|
+
let configPaths;
|
|
1370
|
+
if (!(opts.include && opts.include.length)) {
|
|
1371
|
+
try {
|
|
1372
|
+
configPaths = mod.loadConfig(root)?.config?.paths;
|
|
1373
|
+
}
|
|
1374
|
+
catch (_) { }
|
|
1375
|
+
}
|
|
1376
|
+
include = configPaths && configPaths.length
|
|
1377
|
+
? checkInclude(root, configPaths, notice, "the config file's paths")
|
|
1378
|
+
: checkInclude(root, opts.include, notice);
|
|
1379
|
+
checkOptions = {
|
|
1380
|
+
cwd: root,
|
|
1381
|
+
strict: opts.strict === undefined ? undefined : !!opts.strict,
|
|
1382
|
+
ignore: opts.ignore,
|
|
1383
|
+
a11y: opts.a11y === 'error' || opts.a11y === 'warn' ? opts.a11y : undefined,
|
|
1384
|
+
defaults: { strict: defaults.strict, ignore: defaults.ignore },
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
else {
|
|
1388
|
+
include = checkInclude(root, opts.include, notice);
|
|
1389
|
+
// D144: the a11y lane is a warning unless asked for as an error, under strict too
|
|
1390
|
+
checkOptions = {
|
|
1391
|
+
cwd: root,
|
|
1392
|
+
strict: opts.strict === undefined ? defaults.strict : !!opts.strict,
|
|
1393
|
+
ignore: opts.ignore || defaults.ignore,
|
|
1394
|
+
a11y: opts.a11y === 'error' ? 'error' : 'warn',
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
const a11y = checkOptions.a11y;
|
|
1355
1398
|
// Only error-severity findings open Vite's overlay: while an overlay is open
|
|
1356
1399
|
// Vite's client reloads the page on the first HMR update, so warnings stay
|
|
1357
1400
|
// in the terminal and the browser console. overlay: 'warn' is treated as
|
|
@@ -1382,14 +1425,15 @@ async function startChecker(server, root, opts, defaults, explicit) {
|
|
|
1382
1425
|
const run = (initial = false) => {
|
|
1383
1426
|
let diags;
|
|
1384
1427
|
try {
|
|
1385
|
-
diags = mod.check(include,
|
|
1428
|
+
diags = mod.check(include, checkOptions);
|
|
1386
1429
|
}
|
|
1387
1430
|
catch (err) {
|
|
1388
1431
|
logger.warn(`[sygnal] sygnal-check failed: ${err?.message || err}`, { timestamp: true });
|
|
1389
1432
|
return;
|
|
1390
1433
|
}
|
|
1391
1434
|
// A sygnal-check from before D144 reports SYG7xx as errors under strict: keep them warnings
|
|
1392
|
-
|
|
1435
|
+
// (one with config support postdates D144 and resolves a11y itself)
|
|
1436
|
+
if (!configAware && a11y !== 'error') {
|
|
1393
1437
|
diags = diags.map(d => d && d.severity === 'error' && /^SYG7\d\d$/.test(d.code) ? { ...d, severity: 'warn' } : d);
|
|
1394
1438
|
}
|
|
1395
1439
|
const shown = diags.filter(d => d.severity !== 'info');
|
|
@@ -1443,7 +1487,9 @@ async function startChecker(server, root, opts, defaults, explicit) {
|
|
|
1443
1487
|
catch (_) { }
|
|
1444
1488
|
let timer;
|
|
1445
1489
|
const onChange = (file) => {
|
|
1446
|
-
if (
|
|
1490
|
+
if (file.split(/[\\/]/).includes('node_modules'))
|
|
1491
|
+
return;
|
|
1492
|
+
if (!SOURCE_RE.test(file) && !(configAware && CONFIG_FILES.includes(path.basename(file))))
|
|
1447
1493
|
return;
|
|
1448
1494
|
clearTimeout(timer);
|
|
1449
1495
|
timer = setTimeout(run, 100);
|