@slexkit/mcp 0.3.3 → 0.4.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/dist/index.js CHANGED
@@ -236,12 +236,15 @@ function stackLine(error) {
236
236
  const parsed = Number(match[1]);
237
237
  return Number.isFinite(parsed) ? Math.max(1, parsed - 2) : null;
238
238
  }
239
- function scanSource(source) {
239
+ function scanSourceState(source) {
240
240
  const chars = [];
241
+ const stack = [];
242
+ const pairs = { "}": "{", "]": "[", ")": "(" };
241
243
  let quote = "";
242
244
  let escaped = false;
243
245
  let line = 1;
244
246
  let column = 0;
247
+ let mismatchedDelimiter;
245
248
  for (let index = 0;index < source.length; index += 1) {
246
249
  const char = source[index];
247
250
  const next = source[index + 1];
@@ -284,9 +287,28 @@ function scanSource(source) {
284
287
  escaped = false;
285
288
  continue;
286
289
  }
287
- chars.push({ char, index, line, column });
290
+ const located = { char, index, line, column };
291
+ chars.push(located);
292
+ if (char === "{" || char === "[" || char === "(") {
293
+ stack.push(located);
294
+ } else if (char === "}" || char === "]" || char === ")") {
295
+ const expected = pairs[char];
296
+ const opener = stack.pop();
297
+ if (!opener || opener.char !== expected) {
298
+ mismatchedDelimiter = located;
299
+ }
300
+ }
288
301
  }
289
- return chars;
302
+ return {
303
+ chars,
304
+ stack,
305
+ openQuote: quote || undefined,
306
+ escaped,
307
+ mismatchedDelimiter
308
+ };
309
+ }
310
+ function scanSource(source) {
311
+ return scanSourceState(source).chars;
290
312
  }
291
313
  function tokenDiagnostic(source, message) {
292
314
  const chars = scanSource(source);
@@ -322,26 +344,15 @@ function tokenDiagnostic(source, message) {
322
344
  return null;
323
345
  }
324
346
  function delimiterDiagnostic(source) {
325
- const stack = [];
326
- const pairs = { "}": "{", "]": "[", ")": "(" };
327
- for (const item of scanSource(source)) {
328
- if (item.char === "{" || item.char === "[" || item.char === "(") {
329
- stack.push(item);
330
- continue;
331
- }
332
- if (item.char === "}" || item.char === "]" || item.char === ")") {
333
- const expected = pairs[item.char];
334
- const opener2 = stack.pop();
335
- if (!opener2 || opener2.char !== expected) {
336
- return {
337
- line: item.line,
338
- column: item.column,
339
- detail: `Unexpected closing delimiter ${item.char}.`
340
- };
341
- }
342
- }
347
+ const scan = scanSourceState(source);
348
+ if (scan.mismatchedDelimiter) {
349
+ return {
350
+ line: scan.mismatchedDelimiter.line,
351
+ column: scan.mismatchedDelimiter.column,
352
+ detail: `Unexpected closing delimiter ${scan.mismatchedDelimiter.char}.`
353
+ };
343
354
  }
344
- const opener = stack.at(-1);
355
+ const opener = scan.stack.at(-1);
345
356
  if (!opener)
346
357
  return null;
347
358
  const end = lineColumnAt(source, source.length);
@@ -359,6 +370,7 @@ function locateSyntaxError(source, error) {
359
370
  const position = token ?? (delimiter && rawMessage.includes("Expected") ? delimiter : null) ?? (stack ? { line: stack, column: 1 } : null) ?? delimiter ?? { line: 1, column: 1 };
360
371
  const detail = token ? "The parser failed at this token." : delimiter?.detail;
361
372
  return {
373
+ code: "syntax",
362
374
  message: rawMessage,
363
375
  line: position.line,
364
376
  column: position.column,
@@ -499,6 +511,7 @@ ${parseSource}
499
511
  };
500
512
  }
501
513
  }
514
+ var SLEXKIT_VERSION = "0.4.0";
502
515
  var SLEX_PROTOCOL_VERSION = "0.1";
503
516
  var SINCE = "0.1.0";
504
517
  function docs(type) {
@@ -719,12 +732,13 @@ var cardSpec = component({
719
732
  type: "card",
720
733
  category: "Layout",
721
734
  title: "Card",
722
- summary: "Bordered grouping container.",
723
- description: "Use card to group related content on a bounded surface.",
735
+ summary: "Grouping container for related content.",
736
+ description: "Use card to group related content on a framed surface.",
724
737
  props: {
725
738
  title: { type: "string", dynamic: true, description: "Card title." },
726
739
  icon: { type: "string", description: "Icon name shown before the title." },
727
- tone: { type: "string", values: semanticTones, description: "Optional semantic tone for the card surface." }
740
+ tone: { type: "string", values: semanticTones, description: "Optional semantic tone for the card surface." },
741
+ variant: { type: "string", values: ["tool"], description: "Use tool for ToolHost input cards with compact chrome." }
728
742
  },
729
743
  children: childContent,
730
744
  examples: [example("card", {
@@ -1123,8 +1137,10 @@ var radioGroupSpec = component({
1123
1137
  icon: { type: "string", description: "Icon name shown before the group label." },
1124
1138
  options: { type: "array", description: "Options with label, value, and optional icon." },
1125
1139
  "options[].icon": { type: "string", description: "Icon name shown before a single option label." },
1140
+ "options[].description": { type: "string", description: "Secondary text shown below the option label." },
1126
1141
  disabled: { type: "boolean", default: false, dynamic: true, description: "Disable every radio option in the group." },
1127
1142
  orientation: { type: "string", values: ["vertical", "horizontal"], default: "vertical", description: "Radio option layout direction." },
1143
+ variant: { type: "string", values: ["list"], description: "Use list for full-row option surfaces in ToolHost decision cards." },
1128
1144
  haptic: { type: "boolean", default: true, description: "Enable vibration feedback on supported devices." },
1129
1145
  haptics: { type: "boolean", default: true, description: "Alias for haptic." },
1130
1146
  name: { type: "string", description: "Native radio group name shared by options." },
@@ -1163,7 +1179,8 @@ var rowSpec = component({
1163
1179
  props: {
1164
1180
  justify: { type: "string", values: ["start", "center", "end", "space-between", "space-around"], default: "start", description: "Main-axis distribution." },
1165
1181
  align: { type: "string", values: ["start", "center", "end", "baseline", "stretch"], default: "center", description: "Cross-axis alignment." },
1166
- gap: { type: "string", dynamic: true, description: "Spacing between children." }
1182
+ gap: { type: "string", dynamic: true, description: "Spacing between children." },
1183
+ variant: { type: "string", values: ["actions"], description: "Use actions for compact ToolHost action rows." }
1167
1184
  },
1168
1185
  children: childContent,
1169
1186
  examples: [example("row", {
@@ -1328,12 +1345,43 @@ var statSpec = component({
1328
1345
  }
1329
1346
  })]
1330
1347
  });
1348
+ var stepSpec = component({
1349
+ type: "step",
1350
+ category: "Tooling",
1351
+ title: "ToolHost Step",
1352
+ summary: "ToolHost-only step page for multi-part human input.",
1353
+ description: "Use step inside ToolHost templates as the current page in a multi-step function call. It is not a public display component.",
1354
+ props: {
1355
+ title: { type: "string", description: "Step title." },
1356
+ description: { type: "string", description: "Short helper text for the step." },
1357
+ index: { type: "string | number", description: "Visible step number." },
1358
+ total: { type: "string | number", description: "Total step count shown with index." },
1359
+ progress: { type: "string", description: "Explicit progress label, such as 1/2." },
1360
+ state: { type: "string", description: "Optional visual state such as current or completed." }
1361
+ },
1362
+ children: childContent,
1363
+ examples: [example("step", {
1364
+ namespace: "doc_step_toolhost",
1365
+ layout: {
1366
+ "step:strategy": {
1367
+ title: "Release strategy",
1368
+ index: 1,
1369
+ "radio-group:choice": {
1370
+ options: [
1371
+ { label: "Canary", value: "canary" },
1372
+ { label: "Full", value: "full" }
1373
+ ]
1374
+ }
1375
+ }
1376
+ }
1377
+ })]
1378
+ });
1331
1379
  var submitSpec = component({
1332
1380
  type: "submit",
1333
- category: "Action",
1381
+ category: "Tooling",
1334
1382
  title: "Submit",
1335
1383
  summary: "ToolHost submit and ignore controls.",
1336
- description: "Use submit inside tool templates to return selected state fields to the host.",
1384
+ description: "Use submit only inside ToolHost templates to return selected state fields to the host.",
1337
1385
  props: {
1338
1386
  submitLabel: { type: "string", default: "Submit", description: "Submit button text." },
1339
1387
  ignoreLabel: { type: "string", default: "Ignore", description: "Ignore button text." },
@@ -1549,6 +1597,7 @@ var componentSpecs = [
1549
1597
  selectSpec,
1550
1598
  sliderSpec,
1551
1599
  statSpec,
1600
+ stepSpec,
1552
1601
  submitSpec,
1553
1602
  switchSpec,
1554
1603
  tableSpec,
@@ -1556,8 +1605,19 @@ var componentSpecs = [
1556
1605
  textSpec,
1557
1606
  toastSpec
1558
1607
  ];
1559
- var publicComponentTypes = componentSpecs.map((spec) => spec.type);
1608
+ var internalComponentTypes = new Set(["submit", "step"]);
1609
+ var publicComponentSpecs = componentSpecs.filter((spec) => !internalComponentTypes.has(spec.type));
1610
+ var publicComponentTypes = publicComponentSpecs.map((spec) => spec.type);
1560
1611
  var componentSpecByType = new Map(componentSpecs.map((spec) => [spec.type, spec]));
1612
+ var slexkitExpressionContext = [
1613
+ { name: "g", scope: "always", summary: "Reactive state proxy." },
1614
+ { name: "std", scope: "always", summary: "Pure deterministic SlexKit standard library." },
1615
+ { name: "api", scope: "host-injected", summary: "Host or secure runtime capability object." },
1616
+ { name: "$event", scope: "event handlers", summary: "Event payload for on* handlers." },
1617
+ { name: "$item", scope: "$for", summary: "Current array item." },
1618
+ { name: "$index", scope: "$for", summary: "Current item index." },
1619
+ { name: "$key", scope: "$for", summary: "Current item key." }
1620
+ ];
1561
1621
  var slexkitStdlibDocs = [
1562
1622
  {
1563
1623
  name: "math",
@@ -1624,16 +1684,499 @@ var slexkitRuntimeCapabilities = [
1624
1684
  ];
1625
1685
  var slexkitStdlibFunctionNames = slexkitStdlibDocs.flatMap((namespace) => namespace.functions.map((fn) => fn.name));
1626
1686
  var slexkitRuntimeCapabilityNames = slexkitRuntimeCapabilities.map((capability) => capability.name);
1687
+ var SLEX_SCHEMA_VERSION = "2026-06";
1688
+ var SLEX_LOGIC_PROFILE_VERSION = "0.1";
1689
+ var SLEX_STANDARD_ARTIFACTS = [
1690
+ "slex-expression.schema.json",
1691
+ "slex-component-catalog.json",
1692
+ "slex-logic-profile.json",
1693
+ "slex-capabilities.catalog.json",
1694
+ "slex-conformance.json",
1695
+ "slex-standard-manifest.json"
1696
+ ];
1697
+ var slexReservedContextNames = [
1698
+ "g",
1699
+ "std",
1700
+ "api",
1701
+ "$event",
1702
+ "$item",
1703
+ "$index",
1704
+ "$key"
1705
+ ];
1706
+ var slexNativeSecureCapabilities = [
1707
+ "fetch",
1708
+ "XMLHttpRequest",
1709
+ "WebSocket",
1710
+ "setTimeout",
1711
+ "setInterval",
1712
+ "requestAnimationFrame"
1713
+ ];
1714
+ function hashStandardText(source) {
1715
+ let hash = 2166136261;
1716
+ for (let index = 0;index < source.length; index += 1) {
1717
+ hash ^= source.charCodeAt(index);
1718
+ hash = Math.imul(hash, 16777619);
1719
+ }
1720
+ return (hash >>> 0).toString(16).padStart(8, "0");
1721
+ }
1722
+ function stableJson(value) {
1723
+ return `${JSON.stringify(value, null, 2)}
1724
+ `;
1725
+ }
1726
+ function componentHash(value) {
1727
+ return hashStandardText(JSON.stringify(value));
1728
+ }
1729
+ function propJsonSchema(prop) {
1730
+ if (prop.values?.length) {
1731
+ return {
1732
+ enum: [...prop.values],
1733
+ description: prop.description,
1734
+ default: prop.default
1735
+ };
1736
+ }
1737
+ const typeMap = {
1738
+ string: { type: "string" },
1739
+ number: { type: "number" },
1740
+ boolean: { type: "boolean" },
1741
+ array: { type: "array" },
1742
+ "string[]": { type: "array", items: { type: "string" } },
1743
+ "string | number": { type: ["string", "number"] },
1744
+ "string | string[]": {
1745
+ anyOf: [
1746
+ { type: "string" },
1747
+ { type: "array", items: { type: "string" } }
1748
+ ]
1749
+ },
1750
+ "object | string": {
1751
+ anyOf: [
1752
+ { type: "object", additionalProperties: true },
1753
+ { type: "string" }
1754
+ ]
1755
+ },
1756
+ "write-expression": { type: "string", xSlexkitExpressionKind: "write" }
1757
+ };
1758
+ return {
1759
+ ...typeMap[prop.type] ?? { description: `SlexKit prop type '${prop.type}'.` },
1760
+ description: prop.description,
1761
+ default: prop.default
1762
+ };
1763
+ }
1764
+ function componentPropSchema(spec) {
1765
+ const properties = {};
1766
+ const required = [];
1767
+ for (const [name, prop] of Object.entries(spec.props)) {
1768
+ properties[name] = propJsonSchema(prop);
1769
+ if (prop.dynamic) {
1770
+ properties[`$${name}`] = {
1771
+ type: "string",
1772
+ description: `Dynamic expression for '${name}'. Evaluated with the Slex logic profile.`,
1773
+ xSlexkitExpressionKind: "read"
1774
+ };
1775
+ }
1776
+ if (prop.required)
1777
+ required.push(name);
1778
+ }
1779
+ return {
1780
+ type: "object",
1781
+ additionalProperties: true,
1782
+ properties,
1783
+ required,
1784
+ patternProperties: {
1785
+ "^[a-z][a-z0-9-]*:[A-Za-z0-9_$-]*$": { $ref: "#/$defs/componentNode" },
1786
+ "^on[A-Za-z_$][\\w$-]*$": {
1787
+ type: "string",
1788
+ description: "Write-pipe event handler expression.",
1789
+ xSlexkitExpressionKind: "write"
1790
+ }
1791
+ }
1792
+ };
1793
+ }
1794
+ function expressionSchema(packageVersion) {
1795
+ const componentKeyPattern = "^[a-z][a-z0-9-]*:[A-Za-z0-9_$-]*$";
1796
+ return {
1797
+ $schema: "https://json-schema.org/draft/2020-12/schema",
1798
+ $id: "https://slexkit.dev/standard/slex-expression.schema.json",
1799
+ title: "Slex Expression",
1800
+ description: "Structural schema for SlexKit logic-bearing Markdown UI artifacts. JavaScript expression semantics are defined by slex-logic-profile.json.",
1801
+ type: "object",
1802
+ additionalProperties: true,
1803
+ properties: {
1804
+ slex: {
1805
+ type: "string",
1806
+ const: SLEX_PROTOCOL_VERSION,
1807
+ description: "Optional public Slex protocol marker."
1808
+ },
1809
+ namespace: {
1810
+ type: "string",
1811
+ minLength: 1,
1812
+ description: "State namespace. Bare component trees default to namespace 'default'."
1813
+ },
1814
+ g: {
1815
+ $ref: "#/$defs/stateObject"
1816
+ },
1817
+ layout: {
1818
+ $ref: "#/$defs/layoutTree",
1819
+ description: "Component tree keyed by 'type:identifier'."
1820
+ }
1821
+ },
1822
+ patternProperties: {
1823
+ [componentKeyPattern]: {
1824
+ $ref: "#/$defs/componentNode"
1825
+ }
1826
+ },
1827
+ $defs: {
1828
+ componentKey: {
1829
+ type: "string",
1830
+ pattern: componentKeyPattern
1831
+ },
1832
+ directive: {
1833
+ type: "string",
1834
+ description: "$if, $for, and $key directive expressions are JavaScript expression strings."
1835
+ },
1836
+ readPipe: {
1837
+ type: "string",
1838
+ description: "JavaScript expression evaluated against g, std, api, component state, and loop context.",
1839
+ xSlexkitExpressionKind: "read"
1840
+ },
1841
+ writePipe: {
1842
+ type: "string",
1843
+ description: "JavaScript statements executed with $event and the Slex expression context.",
1844
+ xSlexkitExpressionKind: "write"
1845
+ },
1846
+ stateObject: {
1847
+ type: "object",
1848
+ additionalProperties: true,
1849
+ description: "Mutable artifact state and helper functions. Source form may contain JavaScript functions."
1850
+ },
1851
+ layoutTree: {
1852
+ type: "object",
1853
+ propertyNames: { $ref: "#/$defs/componentKey" },
1854
+ additionalProperties: { $ref: "#/$defs/componentNode" }
1855
+ },
1856
+ componentNode: {
1857
+ type: "object",
1858
+ additionalProperties: true,
1859
+ properties: {
1860
+ $if: { $ref: "#/$defs/directive" },
1861
+ $for: { $ref: "#/$defs/directive" },
1862
+ $key: { $ref: "#/$defs/directive" }
1863
+ },
1864
+ patternProperties: {
1865
+ "^\\$[A-Za-z_$][\\w$-]*$": { $ref: "#/$defs/readPipe" },
1866
+ "^on[A-Za-z_$][\\w$-]*$": { $ref: "#/$defs/writePipe" },
1867
+ [componentKeyPattern]: { $ref: "#/$defs/componentNode" }
1868
+ }
1869
+ },
1870
+ components: Object.fromEntries(publicComponentSpecs.map((spec) => [spec.type, componentPropSchema(spec)]))
1871
+ },
1872
+ xSlexkit: {
1873
+ packageVersion,
1874
+ schemaVersion: SLEX_SCHEMA_VERSION,
1875
+ protocolVersion: SLEX_PROTOCOL_VERSION,
1876
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
1877
+ sourceFormat: "JavaScript object literal embedded in explicit Markdown ```slex fences"
1878
+ }
1879
+ };
1880
+ }
1881
+ function componentCatalog(packageVersion) {
1882
+ return {
1883
+ name: "slex-component-catalog",
1884
+ packageName: "slexkit",
1885
+ version: packageVersion,
1886
+ schemaVersion: SLEX_SCHEMA_VERSION,
1887
+ protocolVersion: SLEX_PROTOCOL_VERSION,
1888
+ componentCount: publicComponentTypes.length,
1889
+ components: publicComponentSpecs.map((spec) => ({
1890
+ type: spec.type,
1891
+ category: spec.category,
1892
+ status: spec.status,
1893
+ state: spec.state,
1894
+ since: spec.since,
1895
+ title: spec.title,
1896
+ summary: spec.summary,
1897
+ description: spec.description,
1898
+ props: spec.props,
1899
+ children: spec.children,
1900
+ examples: spec.examples,
1901
+ docs: spec.docs,
1902
+ jsonSchema: componentPropSchema(spec),
1903
+ hash: componentHash(spec)
1904
+ }))
1905
+ };
1906
+ }
1907
+ function logicProfile(packageVersion) {
1908
+ return {
1909
+ name: "slex-logic-profile",
1910
+ packageName: "slexkit",
1911
+ version: packageVersion,
1912
+ profileVersion: SLEX_LOGIC_PROFILE_VERSION,
1913
+ schemaVersion: SLEX_SCHEMA_VERSION,
1914
+ protocolVersion: SLEX_PROTOCOL_VERSION,
1915
+ positioning: "Slex is a Markdown-native logic-bearing UI artifact: component structure is declarative, while local state and interaction logic are expressed through a constrained JavaScript expression profile.",
1916
+ sourceFormat: {
1917
+ fenceLanguage: "slex",
1918
+ acceptedForms: ["Slex expression envelope", "bare component tree shorthand", "state-only envelope"],
1919
+ plainJsonOnly: false
1920
+ },
1921
+ readPipes: {
1922
+ match: "Component prop keys beginning with '$', excluding structural directives.",
1923
+ valueType: "string",
1924
+ semantics: "Evaluated as JavaScript expressions with access to the Slex expression context."
1925
+ },
1926
+ writePipes: {
1927
+ match: "Component prop keys beginning with 'on'.",
1928
+ valueType: "string",
1929
+ semantics: "Executed as JavaScript statements. $event contains the emitted event data."
1930
+ },
1931
+ structuralDirectives: {
1932
+ $if: { valueType: "string", semantics: "Controls component existence." },
1933
+ $for: { valueType: "string", semantics: "Iterates over array-like values." },
1934
+ $key: { valueType: "string", semantics: "Provides the keyed reconciliation strategy for $for." }
1935
+ },
1936
+ expressionContext: slexkitExpressionContext,
1937
+ reservedContextNames: [...slexReservedContextNames],
1938
+ componentState: "Named components expose state according to their component catalog state mode: value, checked, enabled, readable, or none.",
1939
+ secureMode: {
1940
+ nativeCapabilitiesDenied: [...slexNativeSecureCapabilities],
1941
+ policyGatedApi: slexkitRuntimeCapabilityNames,
1942
+ guidance: "Use policy-gated api.* capabilities in secure mode; do not call native browser capabilities directly."
1943
+ },
1944
+ diagnostics: [
1945
+ "unsupported_protocol",
1946
+ "invalid_component_key",
1947
+ "invalid_directive_type",
1948
+ "unknown_component",
1949
+ "unknown_prop",
1950
+ "unknown_std_member",
1951
+ "unknown_api_member",
1952
+ "native_secure_capability",
1953
+ "reserved_context_shadowing"
1954
+ ]
1955
+ };
1956
+ }
1957
+ function capabilitiesCatalog(packageVersion) {
1958
+ return {
1959
+ name: "slex-capabilities-catalog",
1960
+ packageName: "slexkit",
1961
+ version: packageVersion,
1962
+ schemaVersion: SLEX_SCHEMA_VERSION,
1963
+ protocolVersion: SLEX_PROTOCOL_VERSION,
1964
+ expressionContext: slexkitExpressionContext,
1965
+ stdlib: slexkitStdlibDocs,
1966
+ stdlibFunctionNames: slexkitStdlibFunctionNames,
1967
+ apiCapabilities: slexkitRuntimeCapabilities,
1968
+ apiCapabilityNames: slexkitRuntimeCapabilityNames,
1969
+ secureNativeCapabilitiesDenied: [...slexNativeSecureCapabilities]
1970
+ };
1971
+ }
1972
+ function conformance(packageVersion) {
1973
+ return {
1974
+ name: "slex-conformance",
1975
+ packageName: "slexkit",
1976
+ version: packageVersion,
1977
+ schemaVersion: SLEX_SCHEMA_VERSION,
1978
+ protocolVersion: SLEX_PROTOCOL_VERSION,
1979
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
1980
+ fixtures: [
1981
+ {
1982
+ id: "valid-full-envelope",
1983
+ kind: "valid",
1984
+ mode: "trusted",
1985
+ source: '{ slex: "0.1", namespace: "valid_full", g: { count: 0 }, layout: { "button:add": { label: "Add", onclick: "g.count++" }, "text:value": { "$text": "String(g.count)" } } }',
1986
+ expected: { ok: true, warnings: [] }
1987
+ },
1988
+ {
1989
+ id: "valid-dynamic-props",
1990
+ kind: "valid",
1991
+ mode: "trusted",
1992
+ source: `{ slex: "0.1", namespace: "dynamic_props", g: { name: "Slex" }, layout: { "text:greeting": { "$text": "'Hello, ' + g.name" } } }`,
1993
+ expected: { ok: true, warnings: [] }
1994
+ },
1995
+ {
1996
+ id: "valid-event-handler",
1997
+ kind: "valid",
1998
+ mode: "trusted",
1999
+ source: '{ slex: "0.1", namespace: "event_handler", g: { count: 0 }, layout: { "button:add": { label: "Add", onclick: "g.count = g.count + Number($event || 1)" } } }',
2000
+ expected: { ok: true, warnings: [] }
2001
+ },
2002
+ {
2003
+ id: "valid-loop-condition",
2004
+ kind: "valid",
2005
+ mode: "trusted",
2006
+ source: '{ slex: "0.1", namespace: "loop_condition", g: { visible: true, items: [{ id: "a", label: "A" }] }, layout: { "column:list": { "$if": "g.visible", "text:item": { "$for": "g.items", "$key": "$item.id", "$text": "$item.label" } } } }',
2007
+ expected: { ok: true, warnings: [] }
2008
+ },
2009
+ {
2010
+ id: "valid-stdlib",
2011
+ kind: "valid",
2012
+ mode: "trusted",
2013
+ source: '{ slex: "0.1", namespace: "stdlib", g: { done: 3, total: 4 }, layout: { "stat:progress": { label: "Progress", "$value": "std.format.percent(std.math.safeDivide(g.done, g.total), 1)" } } }',
2014
+ expected: { ok: true, warnings: [] }
2015
+ },
2016
+ {
2017
+ id: "valid-secure-api",
2018
+ kind: "valid",
2019
+ mode: "secure",
2020
+ source: '{ slex: "0.1", namespace: "secure_api", g: { status: "idle", async load() { const result = await api.fetch("/status"); this.status = String(result.status); } }, layout: { "button:load": { label: "Load", onclick: "g.load()" }, "text:status": { "$text": "g.status" } } }',
2021
+ expected: { ok: true, warnings: [] }
2022
+ },
2023
+ {
2024
+ id: "valid-bare-tree",
2025
+ kind: "valid",
2026
+ mode: "trusted",
2027
+ source: '{ "text:message": { text: "Bare tree" } }',
2028
+ expected: { ok: true, warnings: [] }
2029
+ },
2030
+ {
2031
+ id: "valid-state-only",
2032
+ kind: "valid",
2033
+ mode: "trusted",
2034
+ source: '{ slex: "0.1", namespace: "state_only", g: { ready: true } }',
2035
+ expected: { ok: true, warnings: [] }
2036
+ },
2037
+ {
2038
+ id: "warning-secure-native-capability",
2039
+ kind: "warning",
2040
+ mode: "secure",
2041
+ source: '{ slex: "0.1", namespace: "native_fetch", g: { load() { fetch("/x"); } }, layout: { "button:load": { label: "Load", onclick: "g.load()" } } }',
2042
+ expected: { ok: true, warnings: [{ code: "native_secure_capability", path: "g.load", value: "fetch" }] }
2043
+ },
2044
+ {
2045
+ id: "warning-secure-native-timer-websocket",
2046
+ kind: "warning",
2047
+ mode: "secure",
2048
+ source: '{ slex: "0.1", namespace: "native_timer_socket", g: { start() { setTimeout(() => {}, 10); const socket = new WebSocket("wss://example.com"); return socket; } }, layout: { "button:start": { label: "Start", onclick: "g.start()" } } }',
2049
+ expected: {
2050
+ ok: true,
2051
+ warnings: [
2052
+ { code: "native_secure_capability", path: "g.start", value: "WebSocket" },
2053
+ { code: "native_secure_capability", path: "g.start", value: "setTimeout" }
2054
+ ]
2055
+ }
2056
+ },
2057
+ {
2058
+ id: "warning-unknown-component-prop",
2059
+ kind: "warning",
2060
+ mode: "trusted",
2061
+ source: '{ namespace: "unknowns", layout: { "madeup:thing": { madeUp: true }, "text:body": { madeUp: true } } }',
2062
+ expected: {
2063
+ ok: true,
2064
+ warnings: [
2065
+ { code: "unknown_component", path: "layout.madeup:thing", value: "madeup" },
2066
+ { code: "unknown_prop", path: "layout.text:body.madeUp", value: "madeUp" }
2067
+ ]
2068
+ }
2069
+ },
2070
+ {
2071
+ id: "warning-invalid-component-key",
2072
+ kind: "warning",
2073
+ mode: "trusted",
2074
+ source: '{ namespace: "bad_key", layout: { "Text Bad:item": { text: "bad" } } }',
2075
+ expected: { ok: true, warnings: [{ code: "invalid_component_key", path: "layout.Text Bad:item", value: "Text Bad:item" }] }
2076
+ },
2077
+ {
2078
+ id: "warning-invalid-directive-type",
2079
+ kind: "warning",
2080
+ mode: "trusted",
2081
+ source: '{ namespace: "bad_directive", layout: { "text:message": { "$if": true, text: "bad" } } }',
2082
+ expected: { ok: true, warnings: [{ code: "invalid_directive_type", path: "layout.text:message.$if", value: "$if" }] }
2083
+ },
2084
+ {
2085
+ id: "warning-unsupported-protocol",
2086
+ kind: "warning",
2087
+ mode: "trusted",
2088
+ source: '{ slex: "9.9", namespace: "future", layout: { "text:message": { text: "future" } } }',
2089
+ expected: { ok: true, warnings: [{ code: "unsupported_protocol", path: "slex", value: "9.9" }] }
2090
+ },
2091
+ {
2092
+ id: "warning-reserved-context-shadowing",
2093
+ kind: "warning",
2094
+ mode: "trusted",
2095
+ source: '{ namespace: "shadow", g: { std: "bad" }, layout: { "text:api": { text: "shadow" } } }',
2096
+ expected: {
2097
+ ok: true,
2098
+ warnings: [
2099
+ { code: "reserved_context_shadowing", path: "g.std", value: "std" },
2100
+ { code: "reserved_context_shadowing", path: "layout.text:api", value: "api" }
2101
+ ]
2102
+ }
2103
+ },
2104
+ {
2105
+ id: "warning-unknown-std-api",
2106
+ kind: "warning",
2107
+ mode: "secure",
2108
+ source: '{ slex: "0.1", namespace: "unknown_logic", g: { load() { api.socket(); } }, layout: { "text:value": { "$text": "std.math.nope(1)" } } }',
2109
+ expected: {
2110
+ ok: true,
2111
+ warnings: [
2112
+ { code: "unknown_api_member", path: "g.load", value: "api.socket" },
2113
+ { code: "unknown_std_member", path: "layout.text:value.$text", value: "std.math.nope" }
2114
+ ]
2115
+ }
2116
+ },
2117
+ {
2118
+ id: "invalid-syntax",
2119
+ kind: "invalid",
2120
+ mode: "trusted",
2121
+ source: '{ namespace: "broken", layout: { "text:message": { text: "missing close" }',
2122
+ expected: { ok: false, diagnostic: "syntax" }
2123
+ }
2124
+ ]
2125
+ };
2126
+ }
2127
+ function createStandardArtifacts(packageVersion, generatedAt = new Date().toISOString()) {
2128
+ const artifacts = {
2129
+ "slex-expression.schema.json": expressionSchema(packageVersion),
2130
+ "slex-component-catalog.json": componentCatalog(packageVersion),
2131
+ "slex-logic-profile.json": logicProfile(packageVersion),
2132
+ "slex-capabilities.catalog.json": capabilitiesCatalog(packageVersion),
2133
+ "slex-conformance.json": conformance(packageVersion)
2134
+ };
2135
+ const artifactMetadata = Object.fromEntries(Object.entries(artifacts).map(([filename, artifact]) => [
2136
+ filename,
2137
+ {
2138
+ path: `/standard/${filename}`,
2139
+ hash: hashStandardText(stableJson(artifact))
2140
+ }
2141
+ ]));
2142
+ const manifest = {
2143
+ name: "slex-standard-manifest",
2144
+ packageName: "slexkit",
2145
+ version: packageVersion,
2146
+ schemaVersion: SLEX_SCHEMA_VERSION,
2147
+ protocolVersion: SLEX_PROTOCOL_VERSION,
2148
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
2149
+ generatedAt,
2150
+ positioning: "Markdown-native logic-bearing UI artifact",
2151
+ compatibility: {
2152
+ keepsJavaScriptExpressionProfile: true,
2153
+ pureJsonUiProtocol: false,
2154
+ a2uiBridgePlanned: true
2155
+ },
2156
+ artifacts: artifactMetadata
2157
+ };
2158
+ const allArtifacts = {
2159
+ ...artifacts,
2160
+ "slex-standard-manifest.json": manifest
2161
+ };
2162
+ return {
2163
+ artifacts: allArtifacts,
2164
+ files: Object.fromEntries(SLEX_STANDARD_ARTIFACTS.map((filename) => [filename, stableJson(allArtifacts[filename])]))
2165
+ };
2166
+ }
1627
2167
  var componentSpecByType2 = new Map(componentSpecs.map((spec) => [spec.type, spec]));
1628
2168
  var stdlibFunctions = new Set(slexkitStdlibFunctionNames);
1629
2169
  var stdlibNamespaces = new Set(slexkitStdlibFunctionNames.map((name) => name.split(".").slice(0, 2).join(".")));
1630
2170
  var apiMembers = new Set(slexkitRuntimeCapabilityNames);
1631
2171
  var directiveProps = new Set(["$if", "$for", "$key"]);
2172
+ var reservedContextNames = new Set(slexReservedContextNames);
2173
+ var componentKeyPattern = /^[a-z][a-z0-9-]*:[A-Za-z0-9_$-]*$/;
1632
2174
  var nativeSecureCapabilities = [
1633
2175
  { value: "fetch", pattern: /(?<!\.)\bfetch\s*\(/ },
1634
2176
  { value: "XMLHttpRequest", pattern: /\bXMLHttpRequest\b/ },
1635
2177
  { value: "WebSocket", pattern: /\bWebSocket\b/ },
1636
2178
  { value: "setTimeout", pattern: /(?<!\.)\bsetTimeout\s*\(/ },
2179
+ { value: "setInterval", pattern: /(?<!\.)\bsetInterval\s*\(/ },
1637
2180
  { value: "requestAnimationFrame", pattern: /(?<!\.)\brequestAnimationFrame\s*\(/ }
1638
2181
  ];
1639
2182
  function collectMemberUsage(source, root) {
@@ -1648,6 +2191,10 @@ function componentKeyType(key) {
1648
2191
  const colon = key.indexOf(":");
1649
2192
  return colon > 0 ? key.slice(0, colon) : null;
1650
2193
  }
2194
+ function componentKeyIdentifier(key) {
2195
+ const colon = key.indexOf(":");
2196
+ return colon >= 0 ? key.slice(colon + 1) : "";
2197
+ }
1651
2198
  function isKnownProp(type, key) {
1652
2199
  if (directiveProps.has(key) || key.startsWith("on"))
1653
2200
  return true;
@@ -1657,16 +2204,55 @@ function isKnownProp(type, key) {
1657
2204
  const propName = key.startsWith("$") ? key.slice(1) : key;
1658
2205
  return propName in spec.props;
1659
2206
  }
2207
+ function isLogicProp(key) {
2208
+ return directiveProps.has(key) || key.startsWith("$") || key.startsWith("on");
2209
+ }
2210
+ function collectLogicSources(value, path = "") {
2211
+ const sources = [];
2212
+ if (!value || typeof value !== "object")
2213
+ return sources;
2214
+ for (const [key, child] of Object.entries(value)) {
2215
+ const childPath = path ? `${path}.${key}` : key;
2216
+ if (typeof child === "function") {
2217
+ sources.push({ path: childPath, source: child.toString() });
2218
+ continue;
2219
+ }
2220
+ if (typeof child === "string" && isLogicProp(key)) {
2221
+ sources.push({ path: childPath, source: child });
2222
+ continue;
2223
+ }
2224
+ sources.push(...collectLogicSources(child, childPath));
2225
+ }
2226
+ return sources;
2227
+ }
1660
2228
  function walkComponents(value, warnings, usage, path = "") {
1661
2229
  if (!value || typeof value !== "object")
1662
2230
  return;
1663
2231
  for (const [key, child] of Object.entries(value)) {
1664
2232
  const childPath = path ? `${path}.${key}` : key;
2233
+ const isInvalidComponentKey = key.includes(":") && !componentKeyPattern.test(key);
2234
+ if (isInvalidComponentKey) {
2235
+ warnings.push({
2236
+ code: "invalid_component_key",
2237
+ message: `Invalid component key '${key}'. Use 'type:identifier' with a kebab-case type.`,
2238
+ path: childPath,
2239
+ value: key
2240
+ });
2241
+ }
1665
2242
  const type = componentKeyType(key);
1666
2243
  if (type) {
1667
2244
  usage.add(type);
2245
+ const identifier = componentKeyIdentifier(key);
2246
+ if (reservedContextNames.has(identifier)) {
2247
+ warnings.push({
2248
+ code: "reserved_context_shadowing",
2249
+ message: `Component identifier '${identifier}' shadows a reserved expression context name.`,
2250
+ path: childPath,
2251
+ value: identifier
2252
+ });
2253
+ }
1668
2254
  const spec = componentSpecByType2.get(type);
1669
- if (!spec) {
2255
+ if (!spec && !isInvalidComponentKey) {
1670
2256
  warnings.push({
1671
2257
  code: "unknown_component",
1672
2258
  message: `Unknown SlexKit component '${type}'.`,
@@ -1675,9 +2261,17 @@ function walkComponents(value, warnings, usage, path = "") {
1675
2261
  });
1676
2262
  }
1677
2263
  if (child && typeof child === "object") {
1678
- for (const propName of Object.keys(child)) {
2264
+ for (const [propName, propValue] of Object.entries(child)) {
1679
2265
  if (componentKeyType(propName))
1680
2266
  continue;
2267
+ if (directiveProps.has(propName) && typeof propValue !== "string") {
2268
+ warnings.push({
2269
+ code: "invalid_directive_type",
2270
+ message: `Directive '${propName}' on component '${type}' must be a JavaScript expression string.`,
2271
+ path: `${childPath}.${propName}`,
2272
+ value: propName
2273
+ });
2274
+ }
1681
2275
  if (!isKnownProp(type, propName)) {
1682
2276
  warnings.push({
1683
2277
  code: "unknown_prop",
@@ -1727,24 +2321,103 @@ function sourceWarnings(source, mode) {
1727
2321
  }
1728
2322
  return { warnings, stdlibUsage, apiUsage };
1729
2323
  }
2324
+ function logicSourceWarnings(sources, mode) {
2325
+ const warnings = [];
2326
+ const stdlibUsage = new Set;
2327
+ const apiUsage = new Set;
2328
+ for (const logic of sources) {
2329
+ for (const name of collectMemberUsage(logic.source, "std")) {
2330
+ stdlibUsage.add(name);
2331
+ if (stdlibFunctions.has(name) || stdlibNamespaces.has(name))
2332
+ continue;
2333
+ warnings.push({
2334
+ code: "unknown_std_member",
2335
+ message: `Unknown SlexKit stdlib member '${name}'.`,
2336
+ path: logic.path,
2337
+ value: name
2338
+ });
2339
+ }
2340
+ for (const name of collectMemberUsage(logic.source, "api")) {
2341
+ apiUsage.add(name);
2342
+ if (apiMembers.has(name))
2343
+ continue;
2344
+ warnings.push({
2345
+ code: "unknown_api_member",
2346
+ message: `Unknown SlexKit runtime API member '${name}'.`,
2347
+ path: logic.path,
2348
+ value: name
2349
+ });
2350
+ }
2351
+ if (mode === "secure") {
2352
+ for (const capability of nativeSecureCapabilities) {
2353
+ if (!capability.pattern.test(logic.source))
2354
+ continue;
2355
+ warnings.push({
2356
+ code: "native_secure_capability",
2357
+ message: `Native '${capability.value}' is not supported in secure mode. Use policy-gated api.* instead.`,
2358
+ path: logic.path,
2359
+ value: capability.value
2360
+ });
2361
+ }
2362
+ }
2363
+ }
2364
+ return {
2365
+ warnings,
2366
+ stdlibUsage: [...stdlibUsage].sort(),
2367
+ apiUsage: [...apiUsage].sort()
2368
+ };
2369
+ }
2370
+ function envelopeWarnings(value, warnings) {
2371
+ if (!value || typeof value !== "object")
2372
+ return;
2373
+ const expression = value;
2374
+ if (expression.slex !== undefined && expression.slex !== SLEX_PROTOCOL_VERSION) {
2375
+ warnings.push({
2376
+ code: "unsupported_protocol",
2377
+ message: `Slex protocol marker '${String(expression.slex)}' does not match supported protocol '${SLEX_PROTOCOL_VERSION}'.`,
2378
+ path: "slex",
2379
+ value: String(expression.slex)
2380
+ });
2381
+ }
2382
+ if (expression.g && typeof expression.g === "object") {
2383
+ for (const key of Object.keys(expression.g)) {
2384
+ if (!reservedContextNames.has(key))
2385
+ continue;
2386
+ warnings.push({
2387
+ code: "reserved_context_shadowing",
2388
+ message: `State key '${key}' shadows a reserved expression context name.`,
2389
+ path: `g.${key}`,
2390
+ value: key
2391
+ });
2392
+ }
2393
+ }
2394
+ }
1730
2395
  function validateSlexSource(source, options = {}) {
1731
2396
  const mode = options.mode ?? "trusted";
1732
2397
  const parsed = parseSlexSource(source);
1733
2398
  const usage = new Set;
1734
- const { warnings, stdlibUsage, apiUsage } = sourceWarnings(source, mode);
1735
2399
  if (!parsed.ok) {
2400
+ const { warnings: warnings2, stdlibUsage: stdlibUsage2, apiUsage: apiUsage2 } = sourceWarnings(source, mode);
1736
2401
  return {
1737
2402
  ok: false,
2403
+ schemaVersion: SLEX_SCHEMA_VERSION,
2404
+ protocolVersion: SLEX_PROTOCOL_VERSION,
2405
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
1738
2406
  diagnostic: parsed.diagnostic,
1739
- warnings,
2407
+ warnings: warnings2,
1740
2408
  componentUsage: [],
1741
- stdlibUsage,
1742
- apiUsage
2409
+ stdlibUsage: stdlibUsage2,
2410
+ apiUsage: apiUsage2
1743
2411
  };
1744
2412
  }
2413
+ const { warnings, stdlibUsage, apiUsage } = logicSourceWarnings(collectLogicSources(parsed.value), mode);
2414
+ envelopeWarnings(parsed.value, warnings);
1745
2415
  walkComponents(parsed.value, warnings, usage);
1746
2416
  return {
1747
2417
  ok: true,
2418
+ schemaVersion: SLEX_SCHEMA_VERSION,
2419
+ protocolVersion: SLEX_PROTOCOL_VERSION,
2420
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
1748
2421
  value: parsed.value,
1749
2422
  warnings,
1750
2423
  componentUsage: [...usage].sort(),
@@ -1752,6 +2425,99 @@ function validateSlexSource(source, options = {}) {
1752
2425
  apiUsage
1753
2426
  };
1754
2427
  }
2428
+ function normalizeExpectedWarning(warning) {
2429
+ return typeof warning === "string" ? { code: warning } : warning;
2430
+ }
2431
+ function warningMatches(actual, expected) {
2432
+ if (actual.code !== expected.code)
2433
+ return false;
2434
+ if (expected.path !== undefined && actual.path !== expected.path)
2435
+ return false;
2436
+ if (expected.value !== undefined && actual.value !== expected.value)
2437
+ return false;
2438
+ return true;
2439
+ }
2440
+ function warningLabel(warning) {
2441
+ return [warning.code, warning.path, warning.value].filter((item) => item !== undefined).join(" ");
2442
+ }
2443
+ function caseResult(fixture) {
2444
+ const result = validateSlexSource(fixture.source, { mode: fixture.mode });
2445
+ const errors = [];
2446
+ if (result.ok !== fixture.expected.ok) {
2447
+ errors.push(`Expected ok=${String(fixture.expected.ok)} but got ok=${String(result.ok)}.`);
2448
+ }
2449
+ const expectedWarnings = fixture.expected.warnings?.map(normalizeExpectedWarning);
2450
+ if (expectedWarnings) {
2451
+ for (const expected of expectedWarnings) {
2452
+ if (!result.warnings.some((warning) => warningMatches(warning, expected))) {
2453
+ errors.push(`Missing warning ${JSON.stringify(expected)}.`);
2454
+ }
2455
+ }
2456
+ for (const actual of result.warnings) {
2457
+ if (!expectedWarnings.some((expected) => warningMatches(actual, expected))) {
2458
+ errors.push(`Unexpected warning ${warningLabel(actual)}.`);
2459
+ }
2460
+ }
2461
+ }
2462
+ if (fixture.expected.diagnostic) {
2463
+ if (result.ok) {
2464
+ errors.push(`Expected diagnostic '${fixture.expected.diagnostic}' but validation succeeded.`);
2465
+ } else if (result.diagnostic.code !== fixture.expected.diagnostic) {
2466
+ errors.push(`Expected diagnostic '${fixture.expected.diagnostic}' but got '${result.diagnostic.code}'.`);
2467
+ }
2468
+ }
2469
+ return {
2470
+ id: fixture.id,
2471
+ kind: fixture.kind,
2472
+ mode: fixture.mode,
2473
+ ok: errors.length === 0,
2474
+ expected: fixture.expected,
2475
+ actual: {
2476
+ ok: result.ok,
2477
+ warnings: result.warnings,
2478
+ diagnostic: result.ok ? undefined : result.diagnostic
2479
+ },
2480
+ errors
2481
+ };
2482
+ }
2483
+ function conformanceFixtures(packageVersion) {
2484
+ const artifact = createStandardArtifacts(packageVersion).artifacts["slex-conformance.json"];
2485
+ return artifact.fixtures;
2486
+ }
2487
+ function runSlexConformance(options = {}) {
2488
+ const packageVersion = options.packageVersion ?? SLEXKIT_VERSION;
2489
+ const fixtures = conformanceFixtures(packageVersion);
2490
+ const selectedFixtures = options.fixtureId ? fixtures.filter((fixture) => fixture.id === options.fixtureId) : fixtures;
2491
+ if (options.fixtureId && selectedFixtures.length === 0) {
2492
+ return {
2493
+ ok: false,
2494
+ packageVersion,
2495
+ schemaVersion: SLEX_SCHEMA_VERSION,
2496
+ protocolVersion: SLEX_PROTOCOL_VERSION,
2497
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
2498
+ total: 0,
2499
+ passed: 0,
2500
+ failed: 0,
2501
+ fixtureId: options.fixtureId,
2502
+ cases: [],
2503
+ error: `Unknown conformance fixture '${options.fixtureId}'.`
2504
+ };
2505
+ }
2506
+ const cases = selectedFixtures.map(caseResult);
2507
+ const failed = cases.filter((item) => !item.ok).length;
2508
+ return {
2509
+ ok: failed === 0,
2510
+ packageVersion,
2511
+ schemaVersion: SLEX_SCHEMA_VERSION,
2512
+ protocolVersion: SLEX_PROTOCOL_VERSION,
2513
+ logicProfileVersion: SLEX_LOGIC_PROFILE_VERSION,
2514
+ total: cases.length,
2515
+ passed: cases.length - failed,
2516
+ failed,
2517
+ fixtureId: options.fixtureId,
2518
+ cases
2519
+ };
2520
+ }
1755
2521
  var defaultRuntimeUrl = typeof document !== "undefined" && typeof document.currentScript === "object" && document.currentScript && "src" in document.currentScript ? String(document.currentScript.src || "") : undefined;
1756
2522
  function setSlexKitRuntimeUrl(url) {
1757
2523
  defaultRuntimeUrl = url || undefined;
@@ -1770,13 +2536,26 @@ var canvasSnapshot = {
1770
2536
  };
1771
2537
  setSlexKitRuntimeUrl(import.meta.url);
1772
2538
  var parseSlexSourceApi = parseSlexSource;
2539
+ var runSlexConformanceApi = runSlexConformance;
1773
2540
  var validateSlexSourceApi = validateSlexSource;
1774
2541
 
1775
2542
  // src/index.ts
1776
2543
  var dataBase = new URL("./data/", import.meta.url);
2544
+ var standardArtifactNames = [
2545
+ "slex-expression.schema.json",
2546
+ "slex-component-catalog.json",
2547
+ "slex-logic-profile.json",
2548
+ "slex-capabilities.catalog.json",
2549
+ "slex-conformance.json",
2550
+ "slex-standard-manifest.json"
2551
+ ];
2552
+ var standardArtifactNameSet = new Set(standardArtifactNames);
1777
2553
  async function readDataFile(name) {
1778
2554
  return readFile(new URL(name, dataBase), "utf-8");
1779
2555
  }
2556
+ async function readStandardArtifact(filename) {
2557
+ return JSON.parse(await readDataFile(`standard/${filename}`));
2558
+ }
1780
2559
  var manifest = JSON.parse(await readDataFile("slexkit-ai-manifest.json"));
1781
2560
  function stringArg(args, key) {
1782
2561
  const value = args[key];
@@ -1937,9 +2716,42 @@ var tools = [
1937
2716
  group: { type: "string", description: "Optional group filter: Guides, Components, Runtime, ToolHost, Security, Packages, Icons." },
1938
2717
  slug: { type: "string", description: "Optional page id or slug to fetch, such as components/card or card." },
1939
2718
  url: { type: "string", description: "Optional href or raw .md URL to fetch." },
1940
- includeCapabilities: { type: "boolean", description: "When true, include expression context, stdlib, and api capability summaries." }
2719
+ includeCapabilities: { type: "boolean", description: "When true, include expression context, stdlib, and api capability summaries." },
2720
+ conformanceReport: {
2721
+ type: "boolean",
2722
+ description: "When true, run SlexKit's bundled standard conformance fixtures and return a structured report."
2723
+ },
2724
+ conformanceFixture: {
2725
+ type: "string",
2726
+ description: "Optional fixture id to run when conformanceReport is true."
2727
+ },
2728
+ standardArtifact: {
2729
+ type: "string",
2730
+ enum: standardArtifactNames,
2731
+ description: "Optional standard artifact JSON to fetch, such as slex-standard-manifest.json, slex-component-catalog.json, or slex-logic-profile.json."
2732
+ }
1941
2733
  }),
1942
- handler(args) {
2734
+ async handler(args) {
2735
+ if (booleanArg(args, "conformanceReport")) {
2736
+ return {
2737
+ version: manifest.version,
2738
+ conformanceReport: runSlexConformanceApi({ fixtureId: optionalStringArg(args, "conformanceFixture") })
2739
+ };
2740
+ }
2741
+ const standardArtifact = optionalStringArg(args, "standardArtifact");
2742
+ if (standardArtifact) {
2743
+ if (!standardArtifactNameSet.has(standardArtifact)) {
2744
+ return { error: "standard_artifact_not_found", standardArtifact, available: standardArtifactNames };
2745
+ }
2746
+ return {
2747
+ version: manifest.version,
2748
+ standardArtifact: {
2749
+ filename: standardArtifact,
2750
+ metadata: manifest.standardArtifacts?.[standardArtifact],
2751
+ content: await readStandardArtifact(standardArtifact)
2752
+ }
2753
+ };
2754
+ }
1943
2755
  const capabilities = booleanArg(args, "includeCapabilities") ? {
1944
2756
  expressionContext: manifest.expressionContext,
1945
2757
  stdlib: manifest.stdlib,
@@ -1947,8 +2759,8 @@ var tools = [
1947
2759
  } : undefined;
1948
2760
  const page = findPage(args);
1949
2761
  if (page)
1950
- return { version: manifest.version, page, capabilities };
1951
- return { version: manifest.version, pages: searchPages(args), capabilities };
2762
+ return { version: manifest.version, page, capabilities, standardArtifacts: manifest.standardArtifacts };
2763
+ return { version: manifest.version, pages: searchPages(args), capabilities, standardArtifacts: manifest.standardArtifacts };
1952
2764
  }
1953
2765
  },
1954
2766
  {
@@ -2060,4 +2872,4 @@ rl.on("line", (line) => {
2060
2872
  })();
2061
2873
  });
2062
2874
 
2063
- //# debugId=47E6ACD49C36F18A64756E2164756E21
2875
+ //# debugId=E327C2B1CABE15F364756E2164756E21