sygnal 6.1.1 → 6.3.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/CHANGELOG.md +100 -0
- package/README.md +3 -1
- package/dist/ai.cjs.js +36 -0
- package/dist/ai.cjs.js.map +1 -1
- package/dist/ai.esm.js +1 -1
- package/dist/astro/server.cjs.js +3 -3
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs +3 -3
- package/dist/astro/server.mjs.map +1 -1
- package/dist/diagnostics.cjs.js +174 -6
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +174 -6
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/adapters.md +2 -1
- package/dist/guide/agent.md +119 -7
- package/dist/guide/ai-cards.md +319 -0
- package/dist/guide/ai-chat.md +64 -16
- package/dist/guide/ai-compose.md +881 -0
- package/dist/guide/ai-decisions.md +17 -1
- package/dist/guide/behaviors.md +1 -1
- package/dist/guide/error-boundaries.md +2 -1
- package/dist/guide/forms.md +1 -1
- package/dist/guide/http.md +5 -4
- package/dist/guide/mcp-apps.md +4 -2
- package/dist/guide/persistence.md +1 -1
- package/dist/guide/recipes/ai-form-fill.md +1 -1
- package/dist/guide/recipes/ai-summarize.md +1 -1
- package/dist/guide/recipes/ai-support-inbox.md +1 -1
- package/dist/guide/resources.md +11 -10
- package/dist/guide/ui/combobox.md +1 -1
- package/dist/guide/undo.md +1 -1
- package/dist/guide/web-components.md +1 -0
- package/dist/guide/webmcp.md +1 -2
- package/dist/index.cjs.js +5842 -370
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +679 -13
- package/dist/index.esm.js +5832 -370
- package/dist/index.esm.js.map +1 -1
- package/dist/sygnal.min.js +1 -1
- package/dist/sygnal.min.js.map +1 -1
- package/dist/vike/config/package.json +1 -1
- package/dist/vike/onRenderClient.cjs.js +3 -2
- package/dist/vike/onRenderClient.cjs.js.map +1 -1
- package/dist/vike/onRenderClient.mjs +3 -2
- package/dist/vike/onRenderClient.mjs.map +1 -1
- package/llms.txt +8 -6
- package/package.json +2 -1
- package/src/ai.d.ts +683 -12
- package/src/ai.ts +6 -0
- package/src/collection.ts +2 -1
- package/src/core/instance.ts +6 -3
- package/src/core/markers/lazy.ts +7 -3
- package/src/core/markers/portal.ts +5 -2
- package/src/core/markers/suspense.ts +3 -2
- package/src/core/markers/transition.ts +6 -3
- package/src/core/registry.ts +9 -5
- package/src/cycle/dom/IsolateModule.ts +25 -22
- package/src/extra/ai/agent/index.ts +111 -26
- package/src/extra/ai/chat/behavior.ts +368 -87
- package/src/extra/ai/chat/driver.ts +7 -4
- package/src/extra/ai/compose/agent.ts +55 -0
- package/src/extra/ai/compose/ask.ts +147 -0
- package/src/extra/ai/compose/behavior.ts +183 -0
- package/src/extra/ai/compose/catalog.ts +211 -0
- package/src/extra/ai/compose/composed.ts +61 -0
- package/src/extra/ai/compose/decisions.ts +1649 -0
- package/src/extra/ai/compose/diag.ts +33 -0
- package/src/extra/ai/compose/index.ts +23 -0
- package/src/extra/ai/compose/layout.ts +441 -0
- package/src/extra/ai/compose/llm.ts +1120 -0
- package/src/extra/ai/compose/render.ts +159 -0
- package/src/extra/ai/compose/testing.ts +71 -0
- package/src/extra/ai/compose/types.ts +159 -0
- package/src/extra/ai/decide.ts +97 -1
- package/src/extra/ai/index.ts +6 -1
- package/src/extra/ai/webmcp.ts +5 -3
- package/src/extra/diagnostics/checks/next.ts +86 -2
- package/src/extra/diagnostics/codes.ts +64 -3
- package/src/extra/fetchDriver.ts +58 -27
- package/src/extra/lens.ts +15 -0
- package/src/extra/ssr.ts +3 -3
- package/src/extra/testing.ts +2 -0
- package/src/extra/widget.ts +3 -3
- package/src/index.d.ts +42 -1
- package/src/index.ts +8 -0
- package/src/lazy.ts +3 -2
- package/src/portal.ts +5 -2
- package/src/pragma/index.ts +2 -1
- package/src/suspense.ts +5 -2
- package/src/switchable.ts +2 -1
- package/src/transition.ts +5 -2
- package/src/vike/onRenderClient.ts +3 -2
package/dist/diagnostics.esm.js
CHANGED
|
@@ -210,9 +210,13 @@ const CODE_TITLES = {
|
|
|
210
210
|
// PLAN-5 2-R (G-393; checks/state.ts; dev entry)
|
|
211
211
|
SYG238: 'Root component with a model but no initial state',
|
|
212
212
|
// PLAN-6 A-1 (sygnal/ai agent layer, src/extra/ai/agent; runtime, while an agent layer runs)
|
|
213
|
-
SYG240: 'Agent action input has no JSON Schema form',
|
|
214
|
-
SYG241: 'Agent read, when or label threw',
|
|
215
|
-
SYG243: 'Agent action input schema converted with losses',
|
|
213
|
+
SYG240: 'Agent action or query input has no JSON Schema form',
|
|
214
|
+
SYG241: 'Agent read, query, when, until or label threw',
|
|
215
|
+
SYG243: 'Agent action or query input schema converted with losses',
|
|
216
|
+
// agent queries (src/extra/ai/agent; runtime and sygnal-check)
|
|
217
|
+
SYG246: 'Agent query is not a synchronous function',
|
|
218
|
+
SYG247: 'Agent query has the tool name of an action',
|
|
219
|
+
SYG248: 'Agent action until names no resource',
|
|
216
220
|
// PLAN-6 A-2 (src/extra/ai/webmcp.ts; reported with the severity passed, dev)
|
|
217
221
|
SYG242: 'WebMCP tool over a size budget',
|
|
218
222
|
SYG244: 'Agent read returns strings, untrusted not declared',
|
|
@@ -243,6 +247,10 @@ const CODE_TITLES = {
|
|
|
243
247
|
SYG423: 'Context change skipped a view whose output it changes',
|
|
244
248
|
SYG424: 'Duplicate Collection item id',
|
|
245
249
|
SYG425: 'isolatedState slice lacks initialState keys',
|
|
250
|
+
// PLAN-9 (D471): checks/next.ts; dev entry and sygnal-check
|
|
251
|
+
SYG426: 'Deprecated lowercase marker tag',
|
|
252
|
+
// PLAN-9 (D470): checks/next.ts; dev entry
|
|
253
|
+
SYG453: 'Two children with the same identity share one instance',
|
|
246
254
|
SYG601: "Retired in 6.0: Missing or invalid sources",
|
|
247
255
|
SYG602: 'Intent is not a function',
|
|
248
256
|
SYG603: 'Intent returned an invalid value',
|
|
@@ -306,6 +314,29 @@ const CODE_TITLES = {
|
|
|
306
314
|
// PLAN-6 A-2: experimentalExposeWebMcp (src/extra/ai/webmcp.ts; dev)
|
|
307
315
|
SYG674: 'WebMCP not available',
|
|
308
316
|
SYG676: 'WebMCP registerTool rejected',
|
|
317
|
+
// ---- PLAN-9 compose (A: src/extra/ai/compose/; dev, reported with the severity passed) ----
|
|
318
|
+
SYG161: 'Catalog container render is a component with a model',
|
|
319
|
+
SYG162: 'Catalog part with neither component nor render',
|
|
320
|
+
SYG250: 'Layout names an unknown part or slot',
|
|
321
|
+
SYG251: 'Invalid param value in a layout',
|
|
322
|
+
SYG252: 'Record param from() does not return an array of { value }',
|
|
323
|
+
SYG450: 'Catalog in names an unknown container or slot',
|
|
324
|
+
SYG451: 'Composed has no catalog or from is not a composition',
|
|
325
|
+
SYG452: 'Layout lists a node key twice',
|
|
326
|
+
SYG681: 'Compose backend option problem',
|
|
327
|
+
// PLAN-9 B-1/B-2: compose.decisions() (src/extra/ai/compose/decisions.ts; explicit severities)
|
|
328
|
+
SYG680: 'Part is LLM-only under a decision backend',
|
|
329
|
+
SYG682: 'Decision model answered outside the criteria',
|
|
330
|
+
// PLAN-9 B-3: compose.llm() (src/extra/ai/compose/llm.ts; the compose status becomes 'error')
|
|
331
|
+
SYG683: 'LLM layout invalid after repair',
|
|
332
|
+
// PLAN-9 X-2: static only (sygnal-check rules/syg253-catalog.js)
|
|
333
|
+
SYG253: 'Misspelled catalog declaration key',
|
|
334
|
+
SYG254: 'Catalog descriptions or options overlap',
|
|
335
|
+
// PLAN-9 H: chat client tools and ask (src/extra/ai/chat/behavior.ts, compose/ask.ts, compose/render.ts)
|
|
336
|
+
SYG160: 'Result part rendered outside a card',
|
|
337
|
+
SYG684: 'Client tool shadows an agent tool',
|
|
338
|
+
SYG685: 'Answer for a tool call that is not open',
|
|
339
|
+
SYG686: 'Ask catalog without a result part',
|
|
309
340
|
// PLAN-4 GS-3: a11y lane (static only, sygnal-check)
|
|
310
341
|
SYG701: 'Click listener on a non-interactive element',
|
|
311
342
|
SYG702: 'Form field without an accessible label',
|
|
@@ -383,6 +414,9 @@ const DEV_CODE_SEVERITY = {
|
|
|
383
414
|
SYG240: 'error',
|
|
384
415
|
SYG241: 'error',
|
|
385
416
|
SYG243: 'warn',
|
|
417
|
+
SYG246: 'error',
|
|
418
|
+
SYG247: 'warn',
|
|
419
|
+
SYG248: 'warn',
|
|
386
420
|
// PLAN-6 A-2 (WebMCP, reported with the severity passed)
|
|
387
421
|
SYG242: 'warn',
|
|
388
422
|
SYG244: 'warn',
|
|
@@ -419,6 +453,10 @@ const DEV_CODE_SEVERITY = {
|
|
|
419
453
|
SYG423: 'warn',
|
|
420
454
|
SYG424: 'warn',
|
|
421
455
|
SYG425: 'warn',
|
|
456
|
+
// PLAN-9 (checks/next.ts): D471 a lowercase <collection> / <switchable> tag (deprecated in 6.3.0)
|
|
457
|
+
SYG426: 'warn',
|
|
458
|
+
// PLAN-9 (checks/next.ts): D470 key identity, two children with one identity
|
|
459
|
+
SYG453: 'warn',
|
|
422
460
|
SYG612: 'error',
|
|
423
461
|
// PLAN-4 D131 (element.ts, through the core bridge; a console warning in dev with diagnostics off)
|
|
424
462
|
SYG644: 'warn',
|
|
@@ -459,6 +497,16 @@ const DEV_CODE_SEVERITY = {
|
|
|
459
497
|
// PLAN-6 A-2 (experimentalExposeWebMcp reports them with an explicit severity)
|
|
460
498
|
SYG674: 'info',
|
|
461
499
|
SYG676: 'warn',
|
|
500
|
+
// PLAN-9 B-1/B-2 (compose.decisions() reports them with an explicit severity)
|
|
501
|
+
SYG680: 'info',
|
|
502
|
+
SYG682: 'warn',
|
|
503
|
+
// PLAN-9 B-3 (compose.llm)
|
|
504
|
+
SYG683: 'error',
|
|
505
|
+
// PLAN-9 H (chat client tools and ask; reported with the severity passed)
|
|
506
|
+
SYG160: 'warn',
|
|
507
|
+
SYG684: 'warn',
|
|
508
|
+
SYG685: 'warn',
|
|
509
|
+
SYG686: 'warn',
|
|
462
510
|
// PLAN-5 V-1: VirtualCollection (checks/virtual.ts, through the core bridge)
|
|
463
511
|
SYG430: 'warn',
|
|
464
512
|
SYG431: 'warn',
|
|
@@ -490,6 +538,19 @@ const DEV_CODE_SEVERITY = {
|
|
|
490
538
|
SYG153: 'warn',
|
|
491
539
|
SYG730: 'warn',
|
|
492
540
|
SYG731: 'warn',
|
|
541
|
+
// ---- PLAN-9 compose (A: src/extra/ai/compose/, reported with the severity passed, dev) ----
|
|
542
|
+
SYG161: 'error',
|
|
543
|
+
SYG162: 'error',
|
|
544
|
+
SYG250: 'warn',
|
|
545
|
+
SYG251: 'warn',
|
|
546
|
+
SYG252: 'warn',
|
|
547
|
+
SYG450: 'warn',
|
|
548
|
+
SYG451: 'warn',
|
|
549
|
+
SYG452: 'warn',
|
|
550
|
+
SYG681: 'error',
|
|
551
|
+
// PLAN-9 X-2: static only (sygnal-check); listed so the entry knows their titles
|
|
552
|
+
SYG253: 'warn',
|
|
553
|
+
SYG254: 'info',
|
|
493
554
|
};
|
|
494
555
|
function getCodeInfo(code) {
|
|
495
556
|
const severity = CODE_SEVERITY[code];
|
|
@@ -3598,7 +3659,8 @@ function installInspect() {
|
|
|
3598
3659
|
* a Collection's viewTransitionName that isn't an identifier, the same name twice on the
|
|
3599
3660
|
* page after a patch, G-460: on rendered elements), SYG612 (D173: a form
|
|
3600
3661
|
* 6.0 removed, met at runtime; once per form and component, with a link to the migration
|
|
3601
|
-
* guide)
|
|
3662
|
+
* guide), SYG453 (PLAN-9, D470: two children with one identity share one instance), SYG426
|
|
3663
|
+
* (PLAN-9, D471: a lowercase <collection> / <switchable> tag, deprecated in 6.3.0).
|
|
3602
3664
|
*
|
|
3603
3665
|
* Only while diagnostics are on (the checks' own rule); production builds never load this.
|
|
3604
3666
|
*/
|
|
@@ -3671,6 +3733,101 @@ function removedTags(f, v, depth = 0) {
|
|
|
3671
3733
|
for (const k of kids)
|
|
3672
3734
|
removedTags(f, k, depth + 1);
|
|
3673
3735
|
}
|
|
3736
|
+
/**
|
|
3737
|
+
* PLAN-9 SYG453 (D470): two children of one view with the same identity (the same component and
|
|
3738
|
+
* `key`, else `id`; `sel::key` in the core) are one instance, rendered in both places. The core
|
|
3739
|
+
* doesn't look (0 production bytes): in the owner's injected vnode that instance's output, a
|
|
3740
|
+
* scoped root (`data.isolate` in the real DOM driver, a `___<scope>` class in the mock DOM), is
|
|
3741
|
+
* the same object twice. Its name and key come from the child whose DOM source has that scope.
|
|
3742
|
+
*/
|
|
3743
|
+
const scopeOfVnode = (n) => {
|
|
3744
|
+
const iso = n.data?.isolate;
|
|
3745
|
+
if (Array.isArray(iso))
|
|
3746
|
+
return iso.length ? iso[iso.length - 1]?.scope : undefined;
|
|
3747
|
+
const m = typeof n.sel == 'string' && /\.___([^.]+)/.exec(n.sel);
|
|
3748
|
+
return m ? m[1] : undefined;
|
|
3749
|
+
};
|
|
3750
|
+
const scopeOfSource = (dom) => {
|
|
3751
|
+
const ns = dom?.namespace;
|
|
3752
|
+
if (Array.isArray(ns))
|
|
3753
|
+
return ns[ns.length - 1]?.scope;
|
|
3754
|
+
const p = dom?._path;
|
|
3755
|
+
const m = Array.isArray(p) && /^\.___(.+)$/.exec(String(p[p.length - 1]));
|
|
3756
|
+
return m ? m[1] : undefined;
|
|
3757
|
+
};
|
|
3758
|
+
function sharedIdentity(iv, v) {
|
|
3759
|
+
const seen = new Set(), dup = new Set();
|
|
3760
|
+
const walk = (n, d) => {
|
|
3761
|
+
if (!n || typeof n != 'object' || d > 300)
|
|
3762
|
+
return;
|
|
3763
|
+
const sc = scopeOfVnode(n);
|
|
3764
|
+
if (sc !== undefined) {
|
|
3765
|
+
if (seen.has(n)) {
|
|
3766
|
+
dup.add(sc);
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
seen.add(n);
|
|
3770
|
+
}
|
|
3771
|
+
const kids = n.children;
|
|
3772
|
+
if (Array.isArray(kids))
|
|
3773
|
+
for (const k of kids)
|
|
3774
|
+
walk(k, d + 1);
|
|
3775
|
+
};
|
|
3776
|
+
walk(v, 0);
|
|
3777
|
+
if (!dup.size)
|
|
3778
|
+
return;
|
|
3779
|
+
const owner = iv.name;
|
|
3780
|
+
for (const sc of dup) {
|
|
3781
|
+
let child;
|
|
3782
|
+
try {
|
|
3783
|
+
child = iv.children().find((c) => scopeOfSource(c.sources?.DOM) === sc);
|
|
3784
|
+
}
|
|
3785
|
+
catch (_) { /* ignore */ }
|
|
3786
|
+
const name = child ? child.name : 'a child component';
|
|
3787
|
+
// the identity's own part of the child's uid (the owner's uid + '-' + its key, id or path)
|
|
3788
|
+
const key = child && typeof child.uid == 'string' && child.uid.startsWith(iv.uid + '-') ? child.uid.slice(iv.uid.length + 1) : undefined;
|
|
3789
|
+
if (!once(`SYG453:${owner}:${name}:${key ?? sc}`))
|
|
3790
|
+
continue;
|
|
3791
|
+
devReport('SYG453', {
|
|
3792
|
+
component: owner,
|
|
3793
|
+
message: `${owner} renders ${child ? `<${name}>` : name} in two places with the same identity${key !== undefined ? ` (key or id ${JSON.stringify(key)})` : ''}, so both places show one instance: it has one state, and the second tag's props replace the first's`,
|
|
3794
|
+
fix: `Give each <${child ? name : 'Child'}> a different key (or id) among its parent's children, e.g. key={item.id}; a key on a component is its identity`,
|
|
3795
|
+
data: { child: child ? name : undefined, key },
|
|
3796
|
+
});
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
/**
|
|
3800
|
+
* PLAN-9 SYG426 (D471): the lowercase host tags, `<collection>` / `<switchable>` (JSX string tags,
|
|
3801
|
+
* or `h('collection')`), deprecated in 6.3.0; the next major removes them (and registers the hosts
|
|
3802
|
+
* on first use, as Portal). The core doesn't look (0 production bytes): the instance's template
|
|
3803
|
+
* keeps a host marker after reconcile (only `pres` markers are rewritten), and the imported
|
|
3804
|
+
* components' markers carry their function in `data.m`, a string tag's don't. The template is
|
|
3805
|
+
* the raw instance's (`iv.i`: the InstanceView's own field, a dev entry of the same build reads it;
|
|
3806
|
+
* the vnode onRender gets has the hosts' output injected in their place). Once per tag.
|
|
3807
|
+
*/
|
|
3808
|
+
const HOST_TAGS = { collection: 'Collection', switchable: 'Switchable' };
|
|
3809
|
+
function lowercaseTags(iv) {
|
|
3810
|
+
const raw = iv.i;
|
|
3811
|
+
if (!raw?.kids?.size || !raw.tmpl)
|
|
3812
|
+
return;
|
|
3813
|
+
const walk = (n, d) => {
|
|
3814
|
+
if (!n || typeof n != 'object' || n.$p || d > 300)
|
|
3815
|
+
return;
|
|
3816
|
+
const name = typeof n.sel == 'string' && !n.data?.m && HOST_TAGS[n.sel];
|
|
3817
|
+
if (name && once(`SYG426:${n.sel}`))
|
|
3818
|
+
devReport('SYG426', {
|
|
3819
|
+
component: iv.name,
|
|
3820
|
+
message: `${iv.name} renders the lowercase <${n.sel}> tag, which is deprecated since Sygnal 6.3.0 and will be removed in the next major (it will then render an unknown <${n.sel}> element)`,
|
|
3821
|
+
fix: `import { ${name} } from 'sygnal' and write <${name} …> (sygnal-check --fix does it)`,
|
|
3822
|
+
data: { tag: n.sel, component: name },
|
|
3823
|
+
});
|
|
3824
|
+
const kids = n.children;
|
|
3825
|
+
if (Array.isArray(kids))
|
|
3826
|
+
for (const k of kids)
|
|
3827
|
+
walk(k, d + 1);
|
|
3828
|
+
};
|
|
3829
|
+
walk(raw.tmpl, 0);
|
|
3830
|
+
}
|
|
3674
3831
|
/** the instance fields the checks read from today's Component instances */
|
|
3675
3832
|
class Facade {
|
|
3676
3833
|
constructor(__next) {
|
|
@@ -3931,8 +4088,19 @@ function nextHooks(_api) {
|
|
|
3931
4088
|
onRender(iv, vnode) {
|
|
3932
4089
|
const f = fac(iv);
|
|
3933
4090
|
H.onRender(f, vnode);
|
|
3934
|
-
if (on())
|
|
3935
|
-
|
|
4091
|
+
if (!on())
|
|
4092
|
+
return;
|
|
4093
|
+
removedTags(f, vnode);
|
|
4094
|
+
try {
|
|
4095
|
+
lowercaseTags(iv);
|
|
4096
|
+
}
|
|
4097
|
+
catch (_) { /* a check never breaks the app */ }
|
|
4098
|
+
// SYG453: only a view with children can render one twice
|
|
4099
|
+
if (iv.children().length)
|
|
4100
|
+
try {
|
|
4101
|
+
sharedIdentity(iv, vnode);
|
|
4102
|
+
}
|
|
4103
|
+
catch (_) { /* a check never breaks the app */ }
|
|
3936
4104
|
},
|
|
3937
4105
|
onReducer(iv, type, prev, next) {
|
|
3938
4106
|
H.onReducer(fac(iv), type, prev, next, 'STATE');
|