@fraczak/k 6.7.0 → 6.8.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.
@@ -28,8 +28,8 @@ if (fs.existsSync(coreKPath)) {
28
28
  vfsFiles["core.k"] = fs.readFileSync(coreKPath, "utf8");
29
29
  }
30
30
 
31
- // Add verified k-code files: arithmetics.k, ieee.k
32
- const verifiedExamples = ["arithmetics.k", "ieee.k"];
31
+ // Add verified k-code files: arithmetics.k, ieee.k, poly.k
32
+ const verifiedExamples = ["arithmetics.k", "ieee.k", "poly.k"];
33
33
  const examplesDir = path.join(projectRoot, "Examples");
34
34
  for (const filename of verifiedExamples) {
35
35
  const fullPath = path.join(examplesDir, filename);
@@ -173,21 +173,24 @@ const htmlContent = `<!DOCTYPE html>
173
173
 
174
174
  /* Header */
175
175
  .navbar {
176
- height: 48px;
176
+ min-height: 48px;
177
+ height: auto;
177
178
  background: var(--bg-surface);
178
179
  border-bottom: 1px solid var(--border-color);
179
180
  display: flex;
180
181
  align-items: center;
181
182
  justify-content: space-between;
182
- padding: 0 16px;
183
+ padding: 6px 16px;
183
184
  flex-shrink: 0;
184
- gap: 12px;
185
+ flex-wrap: wrap;
186
+ gap: 8px 12px;
185
187
  }
186
188
 
187
189
  .nav-left {
188
190
  display: flex;
189
191
  align-items: center;
190
192
  gap: 12px;
193
+ flex-shrink: 0;
191
194
  }
192
195
 
193
196
  .brand {
@@ -199,12 +202,6 @@ const htmlContent = `<!DOCTYPE html>
199
202
  user-select: none;
200
203
  }
201
204
 
202
- .brand-lambda {
203
- color: var(--color-prompt);
204
- font-size: 20px;
205
- line-height: 1;
206
- }
207
-
208
205
  .brand-name {
209
206
  letter-spacing: 0.5px;
210
207
  }
@@ -253,8 +250,11 @@ const htmlContent = `<!DOCTYPE html>
253
250
  .nav-right {
254
251
  display: flex;
255
252
  align-items: center;
256
- gap: 8px;
257
- flex-wrap: nowrap;
253
+ gap: 6px 8px;
254
+ flex-wrap: wrap;
255
+ justify-content: flex-end;
256
+ flex: 1 1 auto;
257
+ min-width: 0;
258
258
  }
259
259
 
260
260
  .control-group {
@@ -320,7 +320,8 @@ const htmlContent = `<!DOCTYPE html>
320
320
 
321
321
  /* Terminal */
322
322
  .terminal-main {
323
- flex: 1;
323
+ flex: 1 1 auto;
324
+ min-height: 0;
324
325
  display: flex;
325
326
  flex-direction: column;
326
327
  overflow: hidden;
@@ -758,7 +759,7 @@ const htmlContent = `<!DOCTYPE html>
758
759
 
759
760
  /* Welcome banner */
760
761
  .welcome-banner {
761
- padding: 16px;
762
+ padding: 12px 16px;
762
763
  background: var(--bg-surface);
763
764
  border: 1px solid var(--border-color);
764
765
  border-radius: 8px;
@@ -766,10 +767,10 @@ const htmlContent = `<!DOCTYPE html>
766
767
  }
767
768
 
768
769
  .welcome-title {
769
- font-size: 18px;
770
+ font-size: 16px;
770
771
  font-weight: 700;
771
772
  color: var(--color-prompt);
772
- margin-bottom: 4px;
773
+ margin-bottom: 0;
773
774
  }
774
775
 
775
776
  .welcome-desc {
@@ -990,6 +991,17 @@ const htmlContent = `<!DOCTYPE html>
990
991
  font-size: 13px;
991
992
  }
992
993
 
994
+ .help-table th {
995
+ text-align: left;
996
+ padding: 6px 10px;
997
+ font-size: 11px;
998
+ font-weight: 600;
999
+ color: var(--text-muted);
1000
+ text-transform: uppercase;
1001
+ letter-spacing: 0.5px;
1002
+ border-bottom: 1px solid var(--border-color);
1003
+ }
1004
+
993
1005
  .help-table td {
994
1006
  padding: 6px 10px;
995
1007
  border-bottom: 1px solid rgba(48, 54, 61, 0.4);
@@ -1001,6 +1013,27 @@ const htmlContent = `<!DOCTYPE html>
1001
1013
  color: var(--color-cyan);
1002
1014
  }
1003
1015
 
1016
+ .help-bridge-box {
1017
+ background: rgba(88, 166, 255, 0.08);
1018
+ border: 1px solid rgba(88, 166, 255, 0.25);
1019
+ border-left: 3px solid var(--color-prompt);
1020
+ border-radius: 4px;
1021
+ padding: 10px 14px;
1022
+ margin: 12px 0 16px 0;
1023
+ font-size: 12px;
1024
+ line-height: 1.5;
1025
+ }
1026
+
1027
+ .help-category-title {
1028
+ font-size: 13px;
1029
+ font-weight: 600;
1030
+ color: var(--text-main);
1031
+ margin: 16px 0 6px 0;
1032
+ display: flex;
1033
+ align-items: center;
1034
+ gap: 6px;
1035
+ }
1036
+
1004
1037
  .help-section ul {
1005
1038
  padding-left: 24px;
1006
1039
  font-size: 13px;
@@ -1312,6 +1345,12 @@ const htmlContent = `<!DOCTYPE html>
1312
1345
  border-color: rgba(210, 153, 34, 0.3);
1313
1346
  }
1314
1347
 
1348
+ .badge-type.parameterized {
1349
+ background: rgba(187, 128, 179, 0.15);
1350
+ color: var(--color-purple);
1351
+ border-color: rgba(187, 128, 179, 0.3);
1352
+ }
1353
+
1315
1354
  .codecs-table-container {
1316
1355
  background: var(--bg-base);
1317
1356
  border: 1px solid var(--border-color);
@@ -1600,14 +1639,27 @@ const htmlContent = `<!DOCTYPE html>
1600
1639
  /* Responsive */
1601
1640
  @media (max-width: 768px) {
1602
1641
  .navbar {
1603
- height: auto;
1604
- flex-direction: column;
1605
1642
  padding: 8px 12px;
1606
- align-items: stretch;
1643
+ gap: 8px;
1644
+ }
1645
+ .nav-left {
1646
+ width: 100%;
1647
+ justify-content: space-between;
1607
1648
  }
1608
1649
  .nav-right {
1609
- overflow-x: auto;
1610
- padding-bottom: 4px;
1650
+ width: 100%;
1651
+ justify-content: flex-start;
1652
+ overflow-x: visible;
1653
+ flex-wrap: wrap;
1654
+ gap: 6px;
1655
+ }
1656
+ .control-group {
1657
+ flex: 1 1 180px;
1658
+ }
1659
+ .control-group select {
1660
+ flex: 1 1 auto;
1661
+ max-width: 100%;
1662
+ min-width: 120px;
1611
1663
  }
1612
1664
  .vfs-body {
1613
1665
  flex-direction: column;
@@ -1627,7 +1679,6 @@ const htmlContent = `<!DOCTYPE html>
1627
1679
  <header class="navbar">
1628
1680
  <div class="nav-left">
1629
1681
  <div class="brand">
1630
- <span class="brand-lambda">λ</span>
1631
1682
  <span class="brand-name">k repl</span>
1632
1683
  <span class="engine-badge">wasm-in-process</span>
1633
1684
  </div>
@@ -1646,27 +1697,27 @@ const htmlContent = `<!DOCTYPE html>
1646
1697
  <option value="core.k">core.k</option>
1647
1698
  <option value="arithmetics.k">arithmetics.k</option>
1648
1699
  <option value="ieee.k">ieee.k</option>
1700
+ <option value="poly.k">poly.k</option>
1649
1701
  </optgroup>
1650
1702
  <optgroup label="Quick Expressions">
1651
- <option value="expr:10">10</option>
1652
- <option value="expr:{10 int x, 5 int y} plus">{10 int x, 5 int y} plus</option>
1703
+ <option value="expr:{} | ok">{} | ok</option>
1704
+ <option value="expr:()">()</option>
1705
+ <option value="expr:$ bool = &lt; {} true, {} false &gt;; not = $ bool &lt; / true | false, {} | true &gt; $ bool; {} | true not">not (boolean relation with fallback)</option>
1706
+ <option value="expr:{10 x, 5 y} plus">{10 x, 5 y} plus (bits)</option>
1653
1707
  <option value="expr:1 succ">1 succ</option>
1654
- <option value="expr:() ()">()</option>
1655
- <option value="expr::t plus">:t plus</option>
1656
- <option value="expr::d plus">:d plus</option>
1657
- <option value="expr::codes">:codes</option>
1658
- <option value="expr::rels">:rels</option>
1659
- <option value="expr::val">:val</option>
1708
+ <option value="expr:{10 int x, 5 int y} plus">{10 int x, 5 int y} plus (int)</option>
1709
+ <option value="expr::codes">:codes (list types)</option>
1710
+ <option value="expr::rels">:rels (list relations)</option>
1660
1711
  </optgroup>
1661
- <optgroup label="Codecs &amp; Serializers">
1712
+ <optgroup label="Codecs &amp; Format Adapters">
1662
1713
  <option value="expr::codecs">:codecs</option>
1663
- <option value="expr::input">:input (codec popup)</option>
1714
+ <option value="expr::input">:input (interactive dialog)</option>
1664
1715
  <option value="expr::codec load int">:codec load int</option>
1665
- <option value="expr:10 int">10 int</option>
1666
1716
  <option value="expr::codec load utf8">:codec load utf8</option>
1667
1717
  <option value="expr::codec load json">:codec load json</option>
1668
1718
  <option value="expr::codec load ieee">:codec load ieee</option>
1669
1719
  <option value="expr::codec load unit">:codec load unit</option>
1720
+ <option value="expr::input {float64 x, string n} json">:input {float64 x, string n} json</option>
1670
1721
  </optgroup>
1671
1722
  </select>
1672
1723
  <button id="btn-load-example" class="btn btn-primary">Load</button>
@@ -1690,9 +1741,6 @@ const htmlContent = `<!DOCTYPE html>
1690
1741
  <!-- Clear -->
1691
1742
  <button id="btn-clear" class="btn btn-secondary" title="Clear terminal screen (Ctrl+L)">⌫ Clear</button>
1692
1743
 
1693
- <!-- Reset -->
1694
- <button id="btn-reset" class="btn btn-secondary" title="Reset REPL state (:reset)">↺ Reset</button>
1695
-
1696
1744
  <!-- Export -->
1697
1745
  <button id="btn-export" class="btn btn-secondary" title="Export session to .klib">💾 Save .klib</button>
1698
1746
 
@@ -1757,17 +1805,17 @@ const htmlContent = `<!DOCTYPE html>
1757
1805
  <div class="modal-dialog codecs-dialog">
1758
1806
  <div class="modal-header">
1759
1807
  <div style="display: flex; align-items: center; gap: 10px;">
1760
- <h3>Codecs &amp; Custom Serializers / Deserializers</h3>
1808
+ <h3>Format Codecs &amp; Custom Serializers / Deserializers</h3>
1761
1809
  <span class="engine-badge">:codecs subsystem</span>
1762
1810
  </div>
1763
1811
  <button id="btn-close-codecs" class="btn-close">&times;</button>
1764
1812
  </div>
1765
1813
  <div class="modal-body codecs-body">
1766
- <!-- Section 1: Standard Built-in Codecs -->
1814
+ <!-- Section 1: Available Format Codecs -->
1767
1815
  <div class="codecs-section">
1768
1816
  <div class="codecs-section-header">
1769
- <h4>Standard Built-in Codecs</h4>
1770
- <span class="section-subtitle">Click 'Load' to activate bidirectional serialization in the REPL session</span>
1817
+ <h4>Available Format Codecs</h4>
1818
+ <span class="section-subtitle">External adapters translating between text formats and typed <code>(filter, tree)</code> values. Click 'Load' to activate in current session.</span>
1771
1819
  </div>
1772
1820
  <div class="codec-grid">
1773
1821
  <!-- int card -->
@@ -1778,8 +1826,8 @@ const htmlContent = `<!DOCTYPE html>
1778
1826
  <span class="codec-name">int</span>
1779
1827
  <span id="codec-badge-int" class="codec-status-badge">Inactive</span>
1780
1828
  </div>
1781
- <div class="codec-types">Target: <span class="badge-type">$int</span></div>
1782
- <div class="codec-desc">Arbitrary-precision signed integers serialized to/from sign-magnitude bit sequences.</div>
1829
+ <div class="codec-types">Target: <span class="badge-type">$ int</span></div>
1830
+ <div class="codec-desc">Converts decimal integers to/from <code>$ int = &lt; bits '+', bits '-' &gt;</code>.</div>
1783
1831
  </div>
1784
1832
  <div class="codec-card-footer">
1785
1833
  <div class="codec-caps">
@@ -1798,8 +1846,8 @@ const htmlContent = `<!DOCTYPE html>
1798
1846
  <span class="codec-name">utf8</span>
1799
1847
  <span id="codec-badge-utf8" class="codec-status-badge">Inactive</span>
1800
1848
  </div>
1801
- <div class="codec-types">Target: <span class="badge-type">$list $byte</span></div>
1802
- <div class="codec-desc">UTF-8 strings serialized to/from linked lists of 8-bit bytes ($byte).</div>
1849
+ <div class="codec-types">Target: <span class="badge-type">$ string ($ utf8)</span></div>
1850
+ <div class="codec-desc">Converts text to/from <code>$ string</code>, a list of Unicode scalar values (<code>$ unicode</code>) partitioned by Unicode planes.</div>
1803
1851
  </div>
1804
1852
  <div class="codec-card-footer">
1805
1853
  <div class="codec-caps">
@@ -1818,8 +1866,8 @@ const htmlContent = `<!DOCTYPE html>
1818
1866
  <span class="codec-name">json</span>
1819
1867
  <span id="codec-badge-json" class="codec-status-badge">Inactive</span>
1820
1868
  </div>
1821
- <div class="codec-types">Target: <span class="badge-type universal">Universal (*)</span></div>
1822
- <div class="codec-desc">Arbitrary algebraic products and variants mapped to standard JSON objects and values.</div>
1869
+ <div class="codec-types">Target: <span class="badge-type parameterized">Pattern / Universal</span></div>
1870
+ <div class="codec-desc">Universal / pattern-driven codec. Deserializes JSON text into <i>k</i> values using a pattern expression (e.g. <code>:input ? {float64 x, string n} json</code> or <code>:input json</code>), or serializes <i>k</i> values to JSON.</div>
1823
1871
  </div>
1824
1872
  <div class="codec-card-footer">
1825
1873
  <div class="codec-caps">
@@ -1838,8 +1886,8 @@ const htmlContent = `<!DOCTYPE html>
1838
1886
  <span class="codec-name">ieee</span>
1839
1887
  <span id="codec-badge-ieee" class="codec-status-badge">Inactive</span>
1840
1888
  </div>
1841
- <div class="codec-types">Target: <span class="badge-type">$float</span></div>
1842
- <div class="codec-desc">IEEE 754 floating point numbers serialized to sign, exponent, and mantissa fields.</div>
1889
+ <div class="codec-types">Target: <span class="badge-type">$ float64</span></div>
1890
+ <div class="codec-desc">IEEE 754 floating point numbers serialized to/from sign, exponent, and fraction fields.</div>
1843
1891
  </div>
1844
1892
  <div class="codec-card-footer">
1845
1893
  <div class="codec-caps">
@@ -1880,7 +1928,7 @@ const htmlContent = `<!DOCTYPE html>
1880
1928
  <div class="codecs-section">
1881
1929
  <div class="codecs-section-header">
1882
1930
  <h4>Custom Serializer &amp; Deserializer Studio</h4>
1883
- <span class="section-subtitle">Create and test custom domain formats (e.g. Yes/No booleans, Hex, Currency, Dates)</span>
1931
+ <span class="section-subtitle">Codecs convert external text representations to/from <i>k</i> values defined as pairs <code>(filter, tree)</code>.</span>
1884
1932
  </div>
1885
1933
 
1886
1934
  <div class="codec-studio-box">
@@ -1888,9 +1936,9 @@ const htmlContent = `<!DOCTYPE html>
1888
1936
  <div class="studio-field">
1889
1937
  <label for="codec-preset-select">Preset Template:</label>
1890
1938
  <select id="codec-preset-select">
1891
- <option value="yn">Yes / No ($bool)</option>
1892
- <option value="hex">Hexadecimal 0x... ($int)</option>
1893
- <option value="currency">Currency $XX.YY ($int cents)</option>
1939
+ <option value="yn">Yes / No ($ yes_no)</option>
1940
+ <option value="hex">Hexadecimal 0x... ($ int)</option>
1941
+ <option value="currency">Currency $XX.YY ($ int cents)</option>
1894
1942
  <option value="blank">Blank / Custom</option>
1895
1943
  </select>
1896
1944
  </div>
@@ -1932,7 +1980,7 @@ const htmlContent = `<!DOCTYPE html>
1932
1980
  <input type="text" id="codec-test-input" placeholder="e.g. yes or 0xFF or $42.50" value="yes">
1933
1981
  </div>
1934
1982
  <button id="btn-test-parse" class="btn btn-secondary btn-sm" title="Test parse function against test input">🧪 Test Parse</button>
1935
- <button id="btn-test-print" class="btn btn-secondary btn-sm" title="Test print function against current REPL value (:val)">🖨 Test Print</button>
1983
+ <button id="btn-test-print" class="btn btn-secondary btn-sm" title="Test print function against current REPL value">🖨 Test Print</button>
1936
1984
  <button id="btn-register-codec" class="btn btn-primary btn-sm" title="Register codec in active REPL state">✓ Register in REPL</button>
1937
1985
  <button id="btn-save-codec-vfs" class="btn btn-secondary btn-sm" title="Export as standalone .mjs file to VFS">💾 Save to VFS</button>
1938
1986
  </div>
@@ -1949,28 +1997,28 @@ const htmlContent = `<!DOCTYPE html>
1949
1997
  <div class="modal-dialog input-popup-dialog">
1950
1998
  <div class="modal-header">
1951
1999
  <div style="display: flex; align-items: center; gap: 10px;">
1952
- <h3>📥 Codec Input</h3>
2000
+ <h3>📥 Code Input</h3>
1953
2001
  <span class="engine-badge">:input directive</span>
1954
2002
  </div>
1955
2003
  <button id="btn-close-input-popup" class="btn-close">&times;</button>
1956
2004
  </div>
1957
2005
  <div class="modal-body input-popup-body">
1958
2006
  <div id="input-popup-banner" class="input-popup-banner">
1959
- <span id="input-popup-hint">Enter input string to deserialize into a K algebraic value:</span>
2007
+ <span id="input-popup-hint">Enter input string to deserialize into a K value:</span>
1960
2008
  </div>
1961
2009
 
1962
2010
  <div class="input-popup-form-row">
1963
2011
  <div class="studio-field" style="flex: 1;">
1964
- <label for="input-popup-type">Target Type:</label>
1965
- <select id="input-popup-type">
1966
- <!-- populated dynamically -->
1967
- </select>
2012
+ <label for="input-popup-type">Target Pattern:</label>
2013
+ <input type="text" id="input-popup-type" list="input-popup-type-list" placeholder="e.g. (...) or $ int or ? {float64 x, string n}" autocomplete="off">
2014
+ <datalist id="input-popup-type-list"></datalist>
1968
2015
  </div>
1969
2016
  <div class="studio-field" style="flex: 1;">
1970
2017
  <label for="input-popup-codec">Deserializer Codec:</label>
1971
2018
  <select id="input-popup-codec">
1972
2019
  <!-- populated dynamically -->
1973
2020
  </select>
2021
+ <div id="input-popup-codec-hint" class="input-popup-codec-hint" style="font-size:11px;color:var(--text-muted);margin-top:4px;"></div>
1974
2022
  </div>
1975
2023
  </div>
1976
2024
 
@@ -2005,22 +2053,112 @@ const htmlContent = `<!DOCTYPE html>
2005
2053
  <button id="btn-close-help" class="btn-close">&times;</button>
2006
2054
  </div>
2007
2055
  <div class="modal-body help-body">
2056
+ <div class="help-section">
2057
+ <h4>Language Overview</h4>
2058
+ <p style="margin-bottom: 8px; color: var(--text-muted); line-height: 1.45;">
2059
+ <b>k</b> is a concise language of <b>types</b> and <b>relations</b> (functions) over tree-like (JSON-like) documents. Every expression denotes a relation that transforms an input document into an output document.
2060
+ </p>
2061
+ <p style="margin-bottom: 10px; color: var(--text-muted); line-height: 1.45;">
2062
+ <b>Content-Addressed:</b> Functions and types are identified by their canonical content hash (<code>@...</code>) derived directly from their structure. Local names are just temporary aliases used for recursion and readability.
2063
+ </p>
2064
+
2065
+ <div class="help-category-title">1. Definitions (Local Aliases)</div>
2066
+ <p style="margin-bottom: 6px; color: var(--text-muted); font-size: 12px;">Definitions introduce local aliases for recursion and convenience (terminated by <code>;</code>):</p>
2067
+ <table class="help-table">
2068
+ <thead>
2069
+ <tr><th style="width: 38%;">Syntax</th><th>Description &amp; Example</th></tr>
2070
+ </thead>
2071
+ <tbody>
2072
+ <tr>
2073
+ <td><code>name = relExpr;</code></td>
2074
+ <td><b>Relation Alias:</b> Defines a local alias for a relation expression.<br><i>e.g.</i> <code>swap = { . y x, . x y };</code></td>
2075
+ </tr>
2076
+ <tr>
2077
+ <td><code>$ name = typeExpr;</code></td>
2078
+ <td><b>Type Alias:</b> Defines a local alias for a type schema.<br><i>e.g.</i> <code>$ bool = &lt; {} true, {} false &gt;;</code></td>
2079
+ </tr>
2080
+ </tbody>
2081
+ </table>
2082
+
2083
+ <div class="help-category-title">2. Type Expressions (<code>typeExpr</code>)</div>
2084
+ <p style="margin-bottom: 6px; color: var(--text-muted); font-size: 12px;">Schemas describing tree-like documents:</p>
2085
+ <table class="help-table">
2086
+ <thead>
2087
+ <tr><th style="width: 45%;">Syntax</th><th>Description</th></tr>
2088
+ </thead>
2089
+ <tbody>
2090
+ <tr>
2091
+ <td><code>{ Type_1 label_1, ..., Type_k label_k }</code></td>
2092
+ <td><b>Product Type:</b> Labeled record of arity <i>k</i> (e.g. <code>{float64 x, string n}</code>; special case: <code>{}</code> is the 0-ary product)</td>
2093
+ </tr>
2094
+ <tr>
2095
+ <td><code>&lt; Type_1 tag_1, ..., Type_k tag_k &gt;</code></td>
2096
+ <td><b>Union Type:</b> Tagged sum of <i>k</i> variants (e.g. <code>&lt;int ok, string err&gt;</code>)</td>
2097
+ </tr>
2098
+ <tr>
2099
+ <td><code>name</code> / <code>@hash</code></td>
2100
+ <td><b>Type Reference:</b> References a type by local alias or canonical content hash</td>
2101
+ </tr>
2102
+ </tbody>
2103
+ </table>
2104
+
2105
+ <div class="help-category-title">3. Relation Expressions (<code>relExpr</code>)</div>
2106
+ <p style="margin-bottom: 6px; color: var(--text-muted); font-size: 12px;">Functions transforming an input document to an output document:</p>
2107
+ <table class="help-table">
2108
+ <thead>
2109
+ <tr><th style="width: 45%;">Syntax</th><th>Description</th></tr>
2110
+ </thead>
2111
+ <tbody>
2112
+ <tr>
2113
+ <td><code>{ rel_1 label_1, ..., rel_k label_k }</code></td>
2114
+ <td><b>Product:</b> Evaluates <i>k</i> relations into record fields (special case: <code>{}</code> evaluates 0 relations, producing empty record <code>{}</code>)</td>
2115
+ </tr>
2116
+ <tr>
2117
+ <td><code>&lt; rel_1, ..., rel_k &gt;</code></td>
2118
+ <td><b>Union (Choice):</b> Evaluates relations in order of arity <i>k</i> (tries <code>rel_1</code>; if it fails, tries <code>rel_2</code>, ..., <code>rel_k</code>)</td>
2119
+ </tr>
2120
+ <tr>
2121
+ <td><code>( rel_1 ... rel_k )</code></td>
2122
+ <td><b>Composition:</b> Sequentially composes <i>k</i> relations (special case: <code>()</code> is the 0-ary composition, denoting identity; parentheses may be omitted when non-empty: <code>f g</code>)</td>
2123
+ </tr>
2124
+ <tr>
2125
+ <td><code>. label</code></td>
2126
+ <td><b>Field Projection:</b> Extracts field <code>label</code> from a record</td>
2127
+ </tr>
2128
+ <tr>
2129
+ <td><code>/ tag</code></td>
2130
+ <td><b>Variant Branch:</b> Extracts payload of variant <code>tag</code> (fails if tag differs)</td>
2131
+ </tr>
2132
+ <tr>
2133
+ <td><code>| tag</code></td>
2134
+ <td><b>Variant Constructor:</b> Wraps document into variant <code>tag</code></td>
2135
+ </tr>
2136
+ <tr>
2137
+ <td><code>$ typeExpr</code></td>
2138
+ <td><b>Type Constraint:</b> Asserts input matches <code>typeExpr</code> (compile-time Type Error on mismatch)</td>
2139
+ </tr>
2140
+ <tr>
2141
+ <td><code>name</code> / <code>@hash</code></td>
2142
+ <td><b>Relation Reference:</b> Calls a relation by local alias or canonical content hash</td>
2143
+ </tr>
2144
+ </tbody>
2145
+ </table>
2146
+ </div>
2147
+
2008
2148
  <div class="help-section">
2009
2149
  <h4>REPL Commands</h4>
2010
2150
  <table class="help-table">
2011
2151
  <tr><td><code>:load &lt;file&gt;</code></td><td>Load a <code>.k</code> source or <code>.klib</code> library into current state</td></tr>
2012
2152
  <tr><td><code>:t &lt;name&gt;</code></td><td>Display the derived type of relation <code>&lt;name&gt;</code></td></tr>
2013
2153
  <tr><td><code>:d &lt;name&gt;</code></td><td>Display definition of relation <code>&lt;name&gt;</code></td></tr>
2014
- <tr><td><code>:type &lt;name&gt;</code></td><td>Show or define a type (<code>:type name = &lt;...&gt;</code>)</td></tr>
2015
- <tr><td><code>:rel &lt;name&gt; = expr</code></td><td>Define a relation alias</td></tr>
2016
- <tr><td><code>:codes</code></td><td>List all type aliases</td></tr>
2154
+ <tr><td><code>:type &lt;name&gt;</code></td><td>Display definition of type <code>&lt;name&gt;</code></td></tr>
2155
+ <tr><td><code>:codes</code></td><td>List all type aliases and canonical hashes</td></tr>
2017
2156
  <tr><td><code>:rels</code></td><td>List all relation aliases</td></tr>
2018
- <tr><td><code>:codecs</code></td><td>List all loaded codecs / serializers</td></tr>
2019
- <tr><td><code>:codec load &lt;name|file&gt;</code></td><td>Load a built-in codec (<code>int</code>, <code>utf8</code>, <code>json</code>, <code>ieee</code>) or file</td></tr>
2020
- <tr><td><code>:codec define n t b</code></td><td>Define inline custom codec: <code>name type { parse: ..., print: ... }</code></td></tr>
2157
+ <tr><td><code>:codecs</code></td><td>List all registered format codecs</td></tr>
2158
+ <tr><td><code>:codec load &lt;name|file&gt;</code></td><td>Load a format codec (<code>int</code>, <code>utf8</code>, <code>json</code>, <code>ieee</code>, <code>unit</code>) or file</td></tr>
2021
2159
  <tr><td><code>:codec unload &lt;name&gt;</code></td><td>Unload a registered codec</td></tr>
2022
- <tr><td><code>:input &lt;type&gt; [codec]</code></td><td>Read next input line using specified codec</td></tr>
2023
- <tr><td><code>:val</code></td><td>Print current accumulator value</td></tr>
2160
+ <tr><td><code>:input [&lt;filter=(...)&gt; [codec]]</code></td><td>Read next input line using specified codec (opens dialog in browser)</td></tr>
2161
+ <tr><td><code>:time &lt;expr&gt;</code></td><td>Evaluate <code>&lt;expr&gt;</code> and report execution time</td></tr>
2024
2162
  <tr><td><code>:klib &lt;file&gt;</code></td><td>Export current state as a <code>.klib</code> binary file</td></tr>
2025
2163
  <tr><td><code>:reset</code></td><td>Clear state and reset to initial environment</td></tr>
2026
2164
  <tr><td><code>:help</code></td><td>Show command reference</td></tr>
@@ -2031,10 +2169,13 @@ const htmlContent = `<!DOCTYPE html>
2031
2169
  <h4>Expressions &amp; Snippets</h4>
2032
2170
  <p style="margin-bottom: 8px; color: var(--text-muted);">Any raw K expression entered at the prompt is compiled and evaluated on top of the current state using WebAssembly.</p>
2033
2171
  <ul>
2034
- <li><code>10</code> &mdash; Integer literal (encodes to bit-path via arithmetics)</li>
2035
- <li><code>{10 int x, 5 int y} plus</code> &mdash; Composition / function call</li>
2036
- <li><code>succ = {inv x, _ y} _inc;</code> &mdash; Define a relation (ends with <code>;</code>)</li>
2037
- <li><code>$ bit = &lt; {} 0, {} 1 &gt;;</code> &mdash; Define a type</li>
2172
+ <li><code>{} | ok</code> &mdash; Constant relation producing variant <code>ok</code> with empty document payload <code>{}</code></li>
2173
+ <li><code>not = &lt; / true | false, / false | true &gt;;</code> &mdash; Polymorphic negation via branch projections and ordered choice</li>
2174
+ <li><code>{} | true not</code> &mdash; Compose constant relation <code>{} | true</code> with <code>not</code> (evaluates to <code>{} | false</code>)</li>
2175
+ <li><code>$ bool = &lt; {} true, {} false &gt;;</code> &mdash; Define a boolean union type schema</li>
2176
+ <li><code>not = $ bool &lt; / true | false, {} | true &gt; $ bool;</code> &mdash; Typed boolean negation: guarded by <code>$ bool</code>, defaulting to <code>{} | true</code></li>
2177
+ <li><code>swap = { . y x, . x y };</code> &mdash; Define a product field-swapping relation</li>
2178
+ <li><code>{ {} | ok x, {} | nil y } swap</code> &mdash; Construct a product and pass it through <code>swap</code></li>
2038
2179
  </ul>
2039
2180
  </div>
2040
2181
 
@@ -145,6 +145,7 @@ if (chromiumBin) {
145
145
  "ieee.mjs",
146
146
  "int.mjs",
147
147
  "json.mjs",
148
+ "poly.k",
148
149
  "unit.mjs",
149
150
  "utf8.mjs"
150
151
  ].sort();
@@ -202,14 +203,16 @@ if (chromiumBin) {
202
203
  })()`);
203
204
  assert(formattedVal.includes("int: 10"), `Expected 'int: 10' in output, got: ${formattedVal}`);
204
205
 
205
- // Test defining inline custom codec via :codec define
206
- await evaluateAsync(`window.kRepl.executeCommand(":type bool = <{} true, {} false>")`);
206
+ // Test defining custom codec via Custom Codec Studio UI
207
+ await evaluateAsync(`window.kRepl.executeCommand("$ yes_no = < {} yes, {} no >;");`);
207
208
  const defineCodecOut = await evaluateAsync(`(async () => {
208
- await window.kRepl.executeCommand(":codec define yn bool ({ parse: (t) => Value.variant(t.trim() === 'yes' ? 'true' : 'false', Value.product({})), print: (v) => v.tag === 'true' ? 'YES' : 'NO' })");
209
- const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
210
- return lines[lines.length - 1];
209
+ window.kRepl.openCodecsModal();
210
+ const typeSelect = document.getElementById("codec-custom-type");
211
+ if (typeSelect) typeSelect.value = "yes_no";
212
+ document.getElementById("btn-register-codec").click();
213
+ return document.getElementById("codec-studio-status")?.textContent || "";
211
214
  })()`);
212
- assert(defineCodecOut.includes("defined codec yn"), `Expected defined codec yn, got: ${defineCodecOut}`);
215
+ assert(defineCodecOut.includes("Successfully registered codec yn"), `Expected defined codec yn, got: ${defineCodecOut}`);
213
216
 
214
217
  // Test modal interaction via openCodecsModal
215
218
  const modalIsOpen = await evaluateAsync(`(() => {
@@ -273,6 +276,32 @@ if (chromiumBin) {
273
276
  })()`);
274
277
  assert(jsonResult.includes('json: {"a":"Woj","n":123}'), `Expected json: {"a":"Woj","n":123}, got: ${jsonResult}`);
275
278
 
279
+ // Verify Reset button is removed from navbar
280
+ const hasResetBtn = await evaluateAsync(`Boolean(document.getElementById("btn-reset"))`);
281
+ assert.strictEqual(hasResetBtn, false, "Reset button should be removed from navbar");
282
+
283
+ // Test explicit pattern expression :input ? {string a, float64 n} json
284
+ await evaluateAsync(`(async () => {
285
+ await window.kRepl.executeCommand(":input ? {string a, float64 n} json");
286
+ await window.kRepl.executeCommand('{"a":"Test","n":456}');
287
+ })()`);
288
+ const patternResult = await evaluateAsync(`(() => {
289
+ const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
290
+ return lines[lines.length - 1];
291
+ })()`);
292
+ assert(patternResult.includes('json: {"a":"Test","n":456}'), `Expected json: {"a":"Test","n":456}, got: ${patternResult}`);
293
+
294
+ // Test standalone codec input :input json without pre-declared type
295
+ await evaluateAsync(`(async () => {
296
+ await window.kRepl.executeCommand(":input json");
297
+ await window.kRepl.executeCommand('{"foo":"bar"}');
298
+ })()`);
299
+ const standaloneResult = await evaluateAsync(`(() => {
300
+ const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
301
+ return lines[lines.length - 1];
302
+ })()`);
303
+ assert(standaloneResult.includes('json: {"foo":"bar"}'), `Expected json: {"foo":"bar"}, got: ${standaloneResult}`);
304
+
276
305
  // Verify text selection holds in output element
277
306
  const selectionCheck = await evaluateAsync(`(() => {
278
307
  const output = document.getElementById("terminal-output");
@@ -428,6 +457,55 @@ if (chromiumBin) {
428
457
  assert.strictEqual(variantDepthAndActionsCheck.allOpenAfterExpand, true, "Expand button should expand collapsed nodes");
429
458
  assert.strictEqual(variantDepthAndActionsCheck.v4CollapsedAgain, true, "Collapse button should reset deeper nodes to collapsed");
430
459
 
460
+ // 4. Verify shortened welcome banner
461
+ const bannerCheck = await evaluateAsync(`(() => {
462
+ const banner = document.querySelector(".welcome-banner");
463
+ const title = banner?.querySelector(".welcome-title")?.textContent.trim();
464
+ const desc = banner?.querySelector(".welcome-desc");
465
+ const tips = banner?.querySelector(".welcome-tips");
466
+ return { hasBanner: !!banner, title, hasDesc: !!desc, hasTips: !!tips };
467
+ })()`);
468
+ assert.strictEqual(bannerCheck.hasBanner, true, "Welcome banner should be present");
469
+ assert.strictEqual(bannerCheck.title, "k interactive repl", "Welcome banner title should be 'k interactive repl'");
470
+ assert.strictEqual(bannerCheck.hasDesc, false, "Welcome banner description should be removed");
471
+ assert.strictEqual(bannerCheck.hasTips, false, "Welcome banner tips should be removed");
472
+
473
+ // 5. Test narrow viewport rendering (e.g. 600px width)
474
+ await send("Emulation.setDeviceMetricsOverride", { width: 600, height: 800, deviceScaleFactor: 1, mobile: false });
475
+ const narrowNavbarCheck = await evaluateAsync(`(() => {
476
+ const btnHelp = document.getElementById("btn-help");
477
+ if (!btnHelp) return { found: false };
478
+ const rect = btnHelp.getBoundingClientRect();
479
+ const isVisible = rect.width > 0 && rect.height > 0 && rect.left >= 0 && rect.right <= window.innerWidth;
480
+ btnHelp.click();
481
+ const helpModalOpen = document.getElementById("help-modal")?.classList.contains("open");
482
+ const modalText = document.getElementById("help-modal")?.textContent || "";
483
+ const hasRel = modalText.includes(":rel ");
484
+ const hasVal = modalText.includes(":val");
485
+ const hasTiming = modalText.includes(":timing");
486
+ const hasCodecDefine = modalText.includes(":codec define");
487
+ const hasType = modalText.includes(":type <name>");
488
+ return {
489
+ found: true,
490
+ isVisible,
491
+ rect: { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom },
492
+ helpModalOpen,
493
+ hasRel,
494
+ hasVal,
495
+ hasTiming,
496
+ hasCodecDefine,
497
+ hasType
498
+ };
499
+ })()`);
500
+ assert.strictEqual(narrowNavbarCheck.found, true, "#btn-help should exist");
501
+ assert.strictEqual(narrowNavbarCheck.isVisible, true, "#btn-help should be visible within narrow viewport");
502
+ assert.strictEqual(narrowNavbarCheck.helpModalOpen, true, "Clicking #btn-help in narrow viewport should open help modal");
503
+ assert.strictEqual(narrowNavbarCheck.hasRel, false, "Help modal should not contain :rel");
504
+ assert.strictEqual(narrowNavbarCheck.hasVal, false, "Help modal should not contain :val");
505
+ assert.strictEqual(narrowNavbarCheck.hasTiming, false, "Help modal should not contain :timing");
506
+ assert.strictEqual(narrowNavbarCheck.hasCodecDefine, false, "Help modal should not contain :codec define");
507
+ assert.strictEqual(narrowNavbarCheck.hasType, true, "Help modal should contain :type <name>");
508
+
431
509
  ws.close();
432
510
  console.log(" Browser execution verified successfully!");
433
511
  } finally {