bitwrench 2.0.21 → 2.0.23
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/LICENSE.txt +1 -1
- package/README.md +4 -5
- package/bin/bwmcp.js +3 -0
- package/dist/bitwrench-bccl.cjs.js +1 -1
- package/dist/bitwrench-bccl.cjs.min.js +1 -1
- package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
- package/dist/bitwrench-bccl.esm.js +1 -1
- package/dist/bitwrench-bccl.esm.min.js +1 -1
- package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
- package/dist/bitwrench-bccl.umd.js +1 -1
- package/dist/bitwrench-bccl.umd.min.js +1 -1
- package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
- package/dist/bitwrench-code-edit.cjs.js +1 -1
- package/dist/bitwrench-code-edit.cjs.min.js +1 -1
- package/dist/bitwrench-code-edit.es5.js +1 -1
- package/dist/bitwrench-code-edit.es5.min.js +1 -1
- package/dist/bitwrench-code-edit.esm.js +1 -1
- package/dist/bitwrench-code-edit.esm.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
- package/dist/bitwrench-debug.js +1 -1
- package/dist/bitwrench-debug.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +3 -3
- package/dist/bitwrench-lean.cjs.min.js +2 -2
- package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
- package/dist/bitwrench-lean.es5.js +3 -3
- package/dist/bitwrench-lean.es5.min.js +2 -2
- package/dist/bitwrench-lean.es5.min.js.gz +0 -0
- package/dist/bitwrench-lean.esm.js +3 -3
- package/dist/bitwrench-lean.esm.min.js +2 -2
- package/dist/bitwrench-lean.esm.min.js.gz +0 -0
- package/dist/bitwrench-lean.umd.js +3 -3
- package/dist/bitwrench-lean.umd.min.js +2 -2
- package/dist/bitwrench-lean.umd.min.js.gz +0 -0
- package/dist/bitwrench-util-css.cjs.js +1 -1
- package/dist/bitwrench-util-css.cjs.min.js +1 -1
- package/dist/bitwrench-util-css.es5.js +1 -1
- package/dist/bitwrench-util-css.es5.min.js +1 -1
- package/dist/bitwrench-util-css.esm.js +1 -1
- package/dist/bitwrench-util-css.esm.min.js +1 -1
- package/dist/bitwrench-util-css.umd.js +1 -1
- package/dist/bitwrench-util-css.umd.min.js +1 -1
- package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
- package/dist/bitwrench.cjs.js +3 -3
- package/dist/bitwrench.cjs.min.js +2 -2
- package/dist/bitwrench.cjs.min.js.gz +0 -0
- package/dist/bitwrench.css +1 -1
- package/dist/bitwrench.es5.js +3 -3
- package/dist/bitwrench.es5.min.js +2 -2
- package/dist/bitwrench.es5.min.js.gz +0 -0
- package/dist/bitwrench.esm.js +3 -3
- package/dist/bitwrench.esm.min.js +2 -2
- package/dist/bitwrench.esm.min.js.gz +0 -0
- package/dist/bitwrench.umd.js +3 -3
- package/dist/bitwrench.umd.min.js +2 -2
- package/dist/bitwrench.umd.min.js.gz +0 -0
- package/dist/builds.json +61 -61
- package/dist/bwserve.cjs.js +2 -2
- package/dist/bwserve.esm.js +2 -2
- package/dist/sri.json +45 -45
- package/docs/README.md +76 -0
- package/docs/app-patterns.md +264 -0
- package/docs/bitwrench-mcp.md +426 -0
- package/docs/bitwrench_api.md +2232 -0
- package/docs/bw-attach.md +399 -0
- package/docs/bwserve.md +841 -0
- package/docs/cli.md +307 -0
- package/docs/component-cheatsheet.md +144 -0
- package/docs/component-library.md +1099 -0
- package/docs/framework-translation-table.md +33 -0
- package/docs/llm-bitwrench-guide.md +672 -0
- package/docs/routing.md +562 -0
- package/docs/state-management.md +767 -0
- package/docs/taco-format.md +373 -0
- package/docs/theming.md +309 -0
- package/docs/thinking-in-bitwrench.md +1457 -0
- package/docs/tutorial-bwserve.md +297 -0
- package/docs/tutorial-embedded.md +314 -0
- package/docs/tutorial-website.md +255 -0
- package/package.json +11 -3
- package/readme.html +6 -5
- package/src/mcp/knowledge.js +231 -0
- package/src/mcp/live.js +226 -0
- package/src/mcp/server.js +216 -0
- package/src/mcp/tools.js +369 -0
- package/src/mcp/transport.js +55 -0
- package/src/version.js +3 -3
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Tutorial: Building a Website with Bitwrench
|
|
2
|
+
|
|
3
|
+
This tutorial walks through building a complete, styled website using bitwrench — from a blank HTML file to a multi-section landing page with theme, navigation, and responsive layout.
|
|
4
|
+
|
|
5
|
+
## What you'll build
|
|
6
|
+
|
|
7
|
+
A product landing page with:
|
|
8
|
+
- Navigation bar
|
|
9
|
+
- Hero section with call-to-action
|
|
10
|
+
- Feature grid
|
|
11
|
+
- Pricing cards
|
|
12
|
+
- Contact form with handle-based validation
|
|
13
|
+
- Footer
|
|
14
|
+
|
|
15
|
+
Total code: ~120 lines of JavaScript. No build step.
|
|
16
|
+
|
|
17
|
+
## Step 1: Start with a blank page
|
|
18
|
+
|
|
19
|
+
Create `index.html`:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<!DOCTYPE html>
|
|
23
|
+
<html lang="en">
|
|
24
|
+
<head>
|
|
25
|
+
<meta charset="UTF-8">
|
|
26
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
27
|
+
<title>My Product</title>
|
|
28
|
+
<script src="https://cdn.jsdelivr.net/npm/bitwrench/dist/bitwrench.umd.min.js"></script>
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<div id="app"></div>
|
|
32
|
+
<script>
|
|
33
|
+
// We'll build everything here
|
|
34
|
+
bw.loadStyles();
|
|
35
|
+
bw.DOM('#app', { t: 'h1', c: 'Hello bitwrench!' });
|
|
36
|
+
</script>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Open it in a browser. You should see styled "Hello bitwrench!" text.
|
|
42
|
+
|
|
43
|
+
## Step 2: Add a theme
|
|
44
|
+
|
|
45
|
+
Replace the script contents with:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
bw.loadStyles();
|
|
49
|
+
bw.loadStyles({
|
|
50
|
+
primary: '#2563eb',
|
|
51
|
+
secondary: '#7c3aed',
|
|
52
|
+
spacing: 'normal',
|
|
53
|
+
radius: 'md'
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
bw.DOM('#app', { t: 'h1', c: 'Themed heading' });
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Every bitwrench component now uses your brand colors automatically.
|
|
60
|
+
|
|
61
|
+
## Step 3: Build the navigation
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
var nav = bw.makeNavbar({
|
|
65
|
+
brand: 'Acme',
|
|
66
|
+
items: [
|
|
67
|
+
{ text: 'Features', href: '#features' },
|
|
68
|
+
{ text: 'Pricing', href: '#pricing' },
|
|
69
|
+
{ text: 'Contact', href: '#contact' }
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`makeNavbar()` returns a TACO object — plain data, not DOM. Nothing is rendered yet.
|
|
75
|
+
|
|
76
|
+
## Step 4: Build the hero section
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
var hero = bw.makeHero({
|
|
80
|
+
title: 'Ship faster with Acme',
|
|
81
|
+
subtitle: 'The developer toolkit that gets out of your way.',
|
|
82
|
+
actions: [
|
|
83
|
+
bw.makeButton({ text: 'Get Started', variant: 'primary', size: 'lg' }),
|
|
84
|
+
bw.makeButton({ text: 'Learn More', variant: 'secondary', size: 'lg' })
|
|
85
|
+
]
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Step 5: Build the feature grid
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
var features = bw.makeFeatureGrid({
|
|
93
|
+
columns: 3,
|
|
94
|
+
features: [
|
|
95
|
+
{ icon: 'bolt', title: 'Fast', desc: 'No build step, no virtual DOM. Just objects and functions.' },
|
|
96
|
+
{ icon: 'shield', title: 'Reliable', desc: '100% test coverage. Works in IE11 through modern browsers.' },
|
|
97
|
+
{ icon: 'code', title: 'Simple', desc: 'One file, ~40KB gzipped. Zero dependencies. Learn in an afternoon.' }
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Step 6: Add pricing cards
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
var pricing = {
|
|
106
|
+
t: 'section', a: { id: 'pricing', style: 'padding: 3rem 1rem; text-align: center' },
|
|
107
|
+
c: [
|
|
108
|
+
{ t: 'h2', c: 'Pricing' },
|
|
109
|
+
{
|
|
110
|
+
t: 'div', a: { style: 'display: flex; gap: 1.5rem; justify-content: center; flex-wrap: wrap; margin-top: 2rem' },
|
|
111
|
+
c: [
|
|
112
|
+
bw.makeCard({ title: 'Free', content: '$0/mo -- For personal projects', footer: bw.makeButton({ text: 'Start Free', variant: 'secondary' }) }),
|
|
113
|
+
bw.makeCard({ title: 'Pro', content: '$29/mo -- For teams', footer: bw.makeButton({ text: 'Subscribe', variant: 'primary' }) }),
|
|
114
|
+
bw.makeCard({ title: 'Enterprise', content: 'Custom -- Contact us', footer: bw.makeButton({ text: 'Contact Sales', variant: 'secondary' }) })
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This mixes `make*()` components with raw TACO for layout. Both work together — TACO objects nest freely.
|
|
122
|
+
|
|
123
|
+
## Step 7: Add a contact form
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
var contact = {
|
|
127
|
+
t: 'section', a: { id: 'contact', style: 'padding: 3rem 1rem; max-width: 600px; margin: 0 auto' },
|
|
128
|
+
c: [
|
|
129
|
+
{ t: 'h2', c: 'Contact Us' },
|
|
130
|
+
bw.makeForm({
|
|
131
|
+
children: [
|
|
132
|
+
bw.makeFormGroup({ label: 'Name', input: bw.makeInput({ type: 'text', placeholder: 'Jane Smith' }) }),
|
|
133
|
+
bw.makeFormGroup({ label: 'Email', input: bw.makeInput({ type: 'email', placeholder: 'jane@example.com' }) }),
|
|
134
|
+
bw.makeFormGroup({ label: 'Message', input: bw.makeTextarea({ placeholder: 'How can we help?' }) }),
|
|
135
|
+
bw.makeButton({ text: 'Send Message', type: 'submit', variant: 'primary' })
|
|
136
|
+
]
|
|
137
|
+
})
|
|
138
|
+
]
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Step 7b: Add form validation with handles
|
|
143
|
+
|
|
144
|
+
The contact form above works, but there's no feedback when the user submits. Use `o.slots` for a status message and `o.handle` for show/clear methods -- no full re-render needed, so the form inputs keep their values and focus:
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
var contactForm = {
|
|
148
|
+
t: 'section', a: { id: 'contact', style: 'padding: 3rem 1rem; max-width: 600px; margin: 0 auto' },
|
|
149
|
+
c: [
|
|
150
|
+
{ t: 'h2', c: 'Contact Us' },
|
|
151
|
+
{ t: 'div', a: { class: 'status', style: 'display:none' }, c: '' },
|
|
152
|
+
bw.makeForm({
|
|
153
|
+
children: [
|
|
154
|
+
bw.makeFormGroup({ label: 'Name', input: bw.makeInput({ type: 'text', placeholder: 'Jane Smith' }) }),
|
|
155
|
+
bw.makeFormGroup({ label: 'Email', input: bw.makeInput({ type: 'email', placeholder: 'jane@example.com' }) }),
|
|
156
|
+
bw.makeFormGroup({ label: 'Message', input: bw.makeTextarea({ placeholder: 'How can we help?' }) }),
|
|
157
|
+
bw.makeButton({ text: 'Send Message', type: 'submit', variant: 'primary' })
|
|
158
|
+
],
|
|
159
|
+
onsubmit: function(e) {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
// Access el.bw via the mounted element
|
|
162
|
+
var el = e.target.closest('[class*="bw_uuid"]') || e.target.parentElement;
|
|
163
|
+
if (el && el.bw) {
|
|
164
|
+
el.bw.showStatus('Message sent! We will reply within 24 hours.');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
],
|
|
169
|
+
o: {
|
|
170
|
+
slots: { status: '.status' },
|
|
171
|
+
handle: {
|
|
172
|
+
showStatus: function(el, msg) {
|
|
173
|
+
var s = el.querySelector('.status');
|
|
174
|
+
s.style.display = 'block';
|
|
175
|
+
s.textContent = msg;
|
|
176
|
+
s.style.cssText = 'padding:0.75rem;border-radius:8px;background:#d4edda;color:#155724;margin-bottom:1rem';
|
|
177
|
+
},
|
|
178
|
+
clearStatus: function(el) {
|
|
179
|
+
var s = el.querySelector('.status');
|
|
180
|
+
s.style.display = 'none';
|
|
181
|
+
s.textContent = '';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
var formEl = bw.mount('#contact-wrapper', contactForm);
|
|
187
|
+
// Can also call from outside: formEl.bw.showStatus('Saved!');
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The key insight: `o.handle` methods update just the status div. The form inputs -- and any text the user has typed -- are untouched. This is why handles exist: targeted updates without re-render side effects.
|
|
191
|
+
|
|
192
|
+
## Step 8: Compose and render
|
|
193
|
+
|
|
194
|
+
Now combine everything into one `bw.DOM()` call:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
bw.DOM('#app', {
|
|
198
|
+
t: 'div', a: { class: 'brand' }, // theme scope class
|
|
199
|
+
c: [
|
|
200
|
+
nav,
|
|
201
|
+
hero,
|
|
202
|
+
{ t: 'section', a: { id: 'features', style: 'padding: 3rem 1rem' }, c: [
|
|
203
|
+
{ t: 'h2', a: { style: 'text-align: center' }, c: 'Features' },
|
|
204
|
+
features
|
|
205
|
+
]},
|
|
206
|
+
pricing,
|
|
207
|
+
contact,
|
|
208
|
+
{ t: 'footer', a: { style: 'text-align: center; padding: 2rem; color: #666' },
|
|
209
|
+
c: '2026 Acme Inc. Built with bitwrench.' }
|
|
210
|
+
]
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
One function call, one mount point, one render. The entire page is described as a tree of plain objects.
|
|
215
|
+
|
|
216
|
+
## Step 9: Add custom CSS
|
|
217
|
+
|
|
218
|
+
Use `bw.css()` for page-specific styles:
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
bw.injectCSS(bw.css({
|
|
222
|
+
'.brand .bw-hero': {
|
|
223
|
+
'text-align': 'center',
|
|
224
|
+
'background': 'linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)',
|
|
225
|
+
'color': '#fff',
|
|
226
|
+
'padding': '5rem 2rem'
|
|
227
|
+
},
|
|
228
|
+
'.brand footer': {
|
|
229
|
+
'border-top': '1px solid #e5e7eb'
|
|
230
|
+
}
|
|
231
|
+
}));
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## The complete file
|
|
235
|
+
|
|
236
|
+
Putting it all together, the full `index.html` is about 120 lines of JavaScript. No npm, no build tool, no framework CLI. Just one HTML file and one `<script>` tag.
|
|
237
|
+
|
|
238
|
+
## Converting to a static site with bwcli
|
|
239
|
+
|
|
240
|
+
You can also write content in Markdown and convert it:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npm install -g bitwrench
|
|
244
|
+
bwcli README.md --theme ocean --standalone -o index.html
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This produces a self-contained HTML file with the ocean theme baked in — works offline, no CDN needed.
|
|
248
|
+
|
|
249
|
+
## Next steps
|
|
250
|
+
|
|
251
|
+
- [Component Library](component-library.md) -- all 50+ `make*()` functions
|
|
252
|
+
- [Theming](theming.md) -- customize colors, spacing, and radius
|
|
253
|
+
- [State Management](state-management.md) -- add interactivity with `o.state` + `o.render`
|
|
254
|
+
- [Routing](routing.md) -- turn this into a multi-page SPA with `bw.router()`
|
|
255
|
+
- [bwserve](bwserve.md) -- server-driven dynamic pages
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bitwrench",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.23",
|
|
4
4
|
"description": "A library for javascript UI functions.",
|
|
5
5
|
"main": "./dist/bitwrench.umd.js",
|
|
6
6
|
"repository": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"author": "manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)",
|
|
14
14
|
"license": "BSD-2-Clause",
|
|
15
15
|
"bin": {
|
|
16
|
-
"bwcli": "./bin/bwcli.js"
|
|
16
|
+
"bwcli": "./bin/bwcli.js",
|
|
17
|
+
"bwmcp": "./bin/bwmcp.js"
|
|
17
18
|
},
|
|
18
19
|
"type": "module",
|
|
19
20
|
"module": "./dist/bitwrench.esm.js",
|
|
@@ -36,16 +37,21 @@
|
|
|
36
37
|
"./bwserve": {
|
|
37
38
|
"import": "./dist/bwserve.esm.js",
|
|
38
39
|
"require": "./dist/bwserve.cjs.js"
|
|
40
|
+
},
|
|
41
|
+
"./mcp": {
|
|
42
|
+
"import": "./src/mcp/server.js"
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
"types": "./dist/bitwrench.d.ts",
|
|
42
46
|
"files": [
|
|
43
47
|
"dist/*.js",
|
|
48
|
+
"dist/*.js.gz",
|
|
44
49
|
"dist/*.css",
|
|
45
50
|
"dist/*.json",
|
|
46
51
|
"dist/*.d.ts",
|
|
47
52
|
"bin/",
|
|
48
53
|
"src/",
|
|
54
|
+
"docs/",
|
|
49
55
|
"README.md",
|
|
50
56
|
"LICENSE.txt"
|
|
51
57
|
],
|
|
@@ -95,7 +101,7 @@
|
|
|
95
101
|
"update_rm": "echo 'DEPRECATED: use build:index instead'",
|
|
96
102
|
"cleanbuild": "npm run clean && npm run build && npm run build:generated",
|
|
97
103
|
"oldtest": "./node_modules/mocha/bin/mocha test/bitwrench_test.js --reporter spec",
|
|
98
|
-
"test": "c8 --reporter=text mocha ./test/bitwrench_ci.js ./test/bitwrench_test_coverage.js ./test/bitwrench_test_pubsub.js ./test/bitwrench_test_theme.js ./test/bitwrench_test_nodemap.js ./test/bitwrench_test_components.js ./test/bitwrench_test_coverage_gaps.js ./test/bitwrench_test_bwserve.js ./test/bitwrench_test_attach.js ./test/bitwrench_test_serve.js ./test/bitwrench_test_code_edit.js ./test/bitwrench_test_html_page.js ./test/bitwrench_test_util_css.js ./test/bitwrench_test_handle.js ./test/bitwrench_test_debug.js ./test/bitwrench_test_router.js -r jsdom-global/register",
|
|
104
|
+
"test": "c8 --reporter=text mocha ./test/bitwrench_ci.js ./test/bitwrench_test_coverage.js ./test/bitwrench_test_pubsub.js ./test/bitwrench_test_theme.js ./test/bitwrench_test_nodemap.js ./test/bitwrench_test_components.js ./test/bitwrench_test_coverage_gaps.js ./test/bitwrench_test_bwserve.js ./test/bitwrench_test_attach.js ./test/bitwrench_test_serve.js ./test/bitwrench_test_code_edit.js ./test/bitwrench_test_html_page.js ./test/bitwrench_test_util_css.js ./test/bitwrench_test_handle.js ./test/bitwrench_test_debug.js ./test/bitwrench_test_router.js ./test/bitwrench_test_mcp_transport.js ./test/bitwrench_test_mcp_server.js ./test/bitwrench_test_mcp_tools.js ./test/bitwrench_test_mcp_knowledge.js -r jsdom-global/register",
|
|
99
105
|
"test:bwserve": "mocha ./test/bitwrench_test_bwserve.js -r jsdom-global/register",
|
|
100
106
|
"test:attach": "mocha ./test/bitwrench_test_attach.js -r jsdom-global/register",
|
|
101
107
|
"test:serve": "mocha ./test/bitwrench_test_serve.js -r jsdom-global/register --exit",
|
|
@@ -117,6 +123,8 @@
|
|
|
117
123
|
"test:router": "mocha ./test/bitwrench_test_router.js -r jsdom-global/register",
|
|
118
124
|
"test:code-edit": "mocha ./test/bitwrench_test_code_edit.js -r jsdom-global/register",
|
|
119
125
|
"test:html-page": "mocha ./test/bitwrench_test_html_page.js -r jsdom-global/register",
|
|
126
|
+
"test:mcp": "mocha ./test/bitwrench_test_mcp_transport.js ./test/bitwrench_test_mcp_server.js ./test/bitwrench_test_mcp_tools.js ./test/bitwrench_test_mcp_knowledge.js -r jsdom-global/register --exit",
|
|
127
|
+
"test:mcp:e2e": "mocha ./test/bitwrench_test_mcp_e2e.js --exit --timeout 15000",
|
|
120
128
|
"test:e2e": "playwright test",
|
|
121
129
|
"test:e2e:headed": "playwright test --headed",
|
|
122
130
|
"test:e2e:debug": "playwright test --debug",
|
package/readme.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<meta name="generator" content="bitwrench v2.0.
|
|
6
|
+
<meta name="generator" content="bitwrench v2.0.23">
|
|
7
7
|
<title>bitwrench.js - README</title>
|
|
8
8
|
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
|
|
9
9
|
<script src="dist/bitwrench.umd.min.js"></script>
|
|
@@ -83,15 +83,16 @@ var page = {
|
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
bw.DOM('#app', page); // -> live DOM
|
|
86
|
-
bw.html(page); // -> HTML string (Node.js, emails, SSR)</code></pre><p>Each object has four keys: <strong class="quikdown-strong">t</strong> (tag), <strong class="quikdown-strong">a</strong> (attributes), <strong class="quikdown-strong">c</strong> (content), <strong class="quikdown-strong">o</strong> (options for state/lifecycle). Nest them, loop them, compose them -- it's just JavaScript.</p><
|
|
87
|
-
<strong class="quikdown-strong">One file, everywhere.</strong> At ~
|
|
86
|
+
bw.html(page); // -> HTML string (Node.js, emails, SSR)</code></pre><p>Each object has four keys: <strong class="quikdown-strong">t</strong> (tag), <strong class="quikdown-strong">a</strong> (attributes), <strong class="quikdown-strong">c</strong> (content), <strong class="quikdown-strong">o</strong> (options for state/lifecycle). Nest them, loop them, compose them -- it's just JavaScript.</p><h3 class="quikdown-h3">Why bitwrench?</h3>
|
|
87
|
+
<strong class="quikdown-strong">One file, everywhere.</strong> At ~40KB gzipped with zero dependencies, bitwrench runs on anything with a browser -- phones, tablets, Raspberry Pi, even ESP32 microcontrollers. The device serves a single HTML page and pushes data as JSON; bitwrench handles all rendering, styling, and state on the client. No Node.js, no build step, no internet connection required.</p><p>Structure, styling, state, and server rendering are all handled as JavaScript objects:</p><ul class="quikdown-ul">
|
|
88
88
|
<li class="quikdown-li"><strong class="quikdown-strong">No build toolchain</strong> -- works with a <code class="quikdown-code"><script></code> tag</li>
|
|
89
89
|
<li class="quikdown-li"><strong class="quikdown-strong">50+ ready-made components</strong> -- buttons, tables, modals, forms, charts, toasts -- one <code class="quikdown-code">make*()</code> call each, returns a composable TACO</li>
|
|
90
90
|
<li class="quikdown-li"><strong class="quikdown-strong">CSS from JavaScript</strong> -- <code class="quikdown-code">bw.css()</code> generates stylesheets, <code class="quikdown-code">bw.s()</code> composes inline styles, <code class="quikdown-code">bw.loadStyles()</code> derives a complete design system from 2 seed colors</li>
|
|
91
91
|
<li class="quikdown-li"><strong class="quikdown-strong">Reactive state</strong> -- <code class="quikdown-code">o.state</code> + <code class="quikdown-code">o.render</code> + <code class="quikdown-code">bw.update()</code> for stateful components; <code class="quikdown-code">bw.pub()</code>/<code class="quikdown-code">bw.sub()</code> for cross-component messaging</li>
|
|
92
92
|
<li class="quikdown-li"><strong class="quikdown-strong">Dual rendering</strong> -- same object renders to live DOM (<code class="quikdown-code">bw.DOM()</code>) or HTML string (<code class="quikdown-code">bw.html()</code>) for SSR, emails, or static sites</li>
|
|
93
|
-
<li class="quikdown-li"><strong class="quikdown-strong">Server-driven UI</strong> -- push UI updates from any backend (Python, C, Rust, Go) over SSE; <code class="quikdown-code">client.screenshot()</code> captures the page back as PNG/JPEG</li>
|
|
93
|
+
<li class="quikdown-li"><strong class="quikdown-strong">Server-driven UI</strong> -- push UI updates from any backend (Python, C, Rust, Go) over SSE via the biwrench bwserve protocol; <code class="quikdown-code">client.screenshot()</code> captures the page back as PNG/JPEG</li>
|
|
94
94
|
<li class="quikdown-li"><strong class="quikdown-strong">CLI</strong> -- <code class="quikdown-code">bwcli</code> converts Markdown, HTML, and JSON to styled standalone pages</li>
|
|
95
|
+
<li class="quikdown-li"><strong class="quikdown-strong">Debug tools</strong> -- live client and server debugging with remote incremental inspect, screenshots, and state updates</li>
|
|
95
96
|
<li class="quikdown-li"><strong class="quikdown-strong">Utilities</strong> -- color interpolation, random data, lorem ipsum, cookies, URL params, file I/O</li>
|
|
96
97
|
</ul><h3 class="quikdown-h3">Coming from other Frameworks</h3>
|
|
97
98
|
<p>Bitwrench uses JavaScript equivalents for most forms of front-end development. Here is a quick mapping (see the <a class="quikdown-a" href="docs/README.md">docs</a> and <a class="quikdown-a" href="docs/thinking-in-bitwrench.md">Thinking in Bitwrench</a> for more details).</p><table class="quikdown-table">
|
|
@@ -381,7 +382,7 @@ curl -X POST http://localhost:9000 -d '{"type":"patch",&
|
|
|
381
382
|
<li class="quikdown-li"><a class="quikdown-a" href="examples/client-server/">bwserve Counter</a> -- server-driven UI demo</li>
|
|
382
383
|
<li class="quikdown-li"><a class="quikdown-a" href="examples/llm-chat/">LLM Chat</a> -- streaming chat via bwserve + Ollama/OpenAI</li>
|
|
383
384
|
</ul><h2 class="quikdown-h2">FAQ</h2>
|
|
384
|
-
<strong class="quikdown-strong">Is this a framework?</strong> -- No. Bitwrench is a library (~
|
|
385
|
+
<strong class="quikdown-strong">Is this a framework?</strong> -- No. Bitwrench is a library (~40KB gzipped). No lifecycle to learn, no project structure to follow. Import it, call functions, done.</p><p><strong class="quikdown-strong">How does bitwrench compare to React/Vue?</strong> -- They solve different problems at different scales. React and Vue provide a component model, virtual DOM, and ecosystem for large team-built SPAs. Bitwrench provides rendering and state primitives in a single file with no build step, aimed at single-page tools, dashboards, embedded devices, and server-driven UIs. They coexist fine -- use whichever fits the job.</p><p><strong class="quikdown-strong">How does CSS work?</strong> -- Bitwrench doesn't own your CSS. Use any external stylesheet, Tailwind, or CSS file you want -- bitwrench doesn't interfere. On top of that, <code class="quikdown-code">bw.css()</code> generates CSS from JS objects (with <code class="quikdown-code">@media</code>, <code class="quikdown-code">@keyframes</code>, pseudo-classes), <code class="quikdown-code">bw.s()</code> composes inline style objects, and <code class="quikdown-code">bw.loadStyles()</code> derives a complete design system from 2 seed colors. You can use all three together or none at all.</p><p><strong class="quikdown-strong">What's the difference between <code class="quikdown-code">bw.DOM()</code> and <code class="quikdown-code">bw.html()</code>?</strong> -- Same TACO input, two outputs. <code class="quikdown-code">bw.DOM('#app', taco)</code> mounts live DOM elements in a browser. <code class="quikdown-code">bw.html(taco)</code> returns an HTML string -- use it in Node.js scripts, email generators, static site builds, or anywhere you need markup without a browser. One object format, two rendering modes.</p><p><strong class="quikdown-strong">What is bwserve?</strong> -- bwserve lets any server push UI updates to a browser over SSE. The server sends TACO objects as JSON; the browser renders them. It's language-agnostic -- the server can be Python, Go, Rust, C, or a shell script. Anything that can write JSON to an HTTP response can drive a bitwrench UI. See the <a class="quikdown-a" href="docs/bwserve.md">bwserve docs</a>.</p><p><strong class="quikdown-strong">Can I use bitwrench on embedded devices?</strong> -- Yes -- this is a primary use case. An ESP32 or Raspberry Pi serves one HTML page with bitwrench loaded, then pushes sensor data as JSON patches over SSE. The device never generates HTML. See the <a class="quikdown-a" href="docs/tutorial-embedded.md">ESP32 tutorial</a>.</p><p><strong class="quikdown-strong">Can I use it with TypeScript?</strong> -- Yes. Type declarations are included. TACO objects are plain JSON-compatible objects that TypeScript infers naturally.</p><p><strong class="quikdown-strong">What about accessibility?</strong> -- BCCL components emit semantic HTML with ARIA attributes where applicable. You can add any <code class="quikdown-code">aria-*</code> attribute via <code class="quikdown-code">a: { 'aria-label': '...' }</code>.</p><h2 class="quikdown-h2">Development</h2>
|
|
385
386
|
<p><pre class="quikdown-pre"><code class="language-bash">npm install # install dev dependencies
|
|
386
387
|
npm run build # build all dist formats (UMD, ESM, CJS, ES5)
|
|
387
388
|
npm test # run unit tests (1400+ tests, 96% coverage)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP knowledge tools -- serve documentation as tool results.
|
|
3
|
+
*
|
|
4
|
+
* Knowledge tools read .md files from docs/ at call time (no caching,
|
|
5
|
+
* always fresh). Section/component filtering uses simple heading parsing.
|
|
6
|
+
*
|
|
7
|
+
* @module mcp/knowledge
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { resolve, dirname } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
|
|
14
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
var DOCS_DIR = resolve(__dirname, '../../docs');
|
|
16
|
+
|
|
17
|
+
// Section name -> heading prefix mapping for bitwrench_guide
|
|
18
|
+
var GUIDE_SECTIONS = {
|
|
19
|
+
'taco': 'Step 2: Understand TACO',
|
|
20
|
+
'levels': 'Step 3: Three Levels',
|
|
21
|
+
'events': 'Step 4: Events',
|
|
22
|
+
'css': 'Step 5: CSS and Theming',
|
|
23
|
+
'components': 'Step 6: BCCL Components',
|
|
24
|
+
'bwserve': 'Step 8: bwserve',
|
|
25
|
+
'routing': 'Step 9: Client-Side Routing',
|
|
26
|
+
'api-reference': 'Core API Quick Reference',
|
|
27
|
+
'rules': 'Key Rules Summary'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Extract a section from markdown content by ## heading.
|
|
32
|
+
* Returns text from the matching ## heading to the next ## heading (or EOF).
|
|
33
|
+
*/
|
|
34
|
+
function extractSection(content, heading) {
|
|
35
|
+
var lines = content.split('\n');
|
|
36
|
+
var start = -1;
|
|
37
|
+
var end = lines.length;
|
|
38
|
+
for (var i = 0; i < lines.length; i++) {
|
|
39
|
+
var line = lines[i];
|
|
40
|
+
if (start === -1) {
|
|
41
|
+
if (line.startsWith('## ') && line.indexOf(heading) >= 0) {
|
|
42
|
+
start = i;
|
|
43
|
+
}
|
|
44
|
+
} else if (line.startsWith('## ')) {
|
|
45
|
+
end = i;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (start === -1) return null;
|
|
50
|
+
return lines.slice(start, end).join('\n').trim();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Extract a component section from component-library.md by ### heading.
|
|
55
|
+
*/
|
|
56
|
+
function extractComponent(content, name) {
|
|
57
|
+
var lines = content.split('\n');
|
|
58
|
+
var start = -1;
|
|
59
|
+
var end = lines.length;
|
|
60
|
+
for (var i = 0; i < lines.length; i++) {
|
|
61
|
+
var line = lines[i];
|
|
62
|
+
if (start === -1) {
|
|
63
|
+
if (line.startsWith('### ') && line.indexOf(name) >= 0) {
|
|
64
|
+
start = i;
|
|
65
|
+
}
|
|
66
|
+
} else if (line.startsWith('### ') || line.startsWith('## ')) {
|
|
67
|
+
end = i;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (start === -1) return null;
|
|
72
|
+
return lines.slice(start, end).join('\n').trim();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Read a doc file. Returns content string or error message.
|
|
77
|
+
*/
|
|
78
|
+
function readDoc(filename) {
|
|
79
|
+
try {
|
|
80
|
+
return readFileSync(resolve(DOCS_DIR, filename), 'utf8');
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return 'Error: could not read ' + filename + ' (' + e.code + ')';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// -- Tool definitions --
|
|
87
|
+
|
|
88
|
+
export var knowledgeToolDefs = [
|
|
89
|
+
{
|
|
90
|
+
name: 'bitwrench_start_here',
|
|
91
|
+
title: 'Start Here -- Bitwrench Quick Orientation',
|
|
92
|
+
description: 'IMPORTANT: Call this tool FIRST before using any other bitwrench tools. Returns a quick orientation: what bitwrench is, the TACO format, your workflow for building UI, and which other tools to call for deeper knowledge.',
|
|
93
|
+
inputSchema: { type: 'object', properties: {} }
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'bitwrench_guide',
|
|
97
|
+
title: 'Bitwrench Developer Guide',
|
|
98
|
+
description: 'Complete bitwrench developer guide covering TACO format, component composition, layout patterns, theming, and workflow. Call this to learn how to use bitwrench effectively. Read this guide, then use the component and utility tools.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
section: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
description: 'Optional: return only a specific section. Omit for full guide.',
|
|
105
|
+
enum: ['taco', 'levels', 'events', 'css', 'components', 'bwserve', 'routing', 'api-reference', 'rules']
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'bitwrench_components',
|
|
112
|
+
title: 'Component Library Reference',
|
|
113
|
+
description: 'Complete reference for all bitwrench make*() components. Call this when you need to know the exact props, variants, and options for a specific component. Returns the full component catalog with examples.',
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
component: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: "Optional: return docs for a specific component only (e.g. 'makeCard', 'makeTable', 'makeAccordion'). Omit for complete catalog."
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'bitwrench_server_guide',
|
|
126
|
+
title: 'Server-Driven UI Guide',
|
|
127
|
+
description: 'Tutorial for building server-driven UI with bwserve. Covers: SSE streaming, replace/patch/append protocol, data-bw-action buttons, live metrics, screenshots. Call this when building real-time or server-pushed interfaces.',
|
|
128
|
+
inputSchema: { type: 'object', properties: {} }
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'bitwrench_themes',
|
|
132
|
+
title: 'Theme and Color Reference',
|
|
133
|
+
description: 'Reference for bitwrench theming: 12 built-in presets (teal, ocean, sunset, forest, slate, rose, indigo, amber, emerald, nord, coral, midnight), custom palette configuration, color utilities.',
|
|
134
|
+
inputSchema: { type: 'object', properties: {} }
|
|
135
|
+
}
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
// -- Tool handlers --
|
|
139
|
+
|
|
140
|
+
var START_HERE_TEXT = [
|
|
141
|
+
'BITWRENCH QUICK ORIENTATION',
|
|
142
|
+
'============================',
|
|
143
|
+
'',
|
|
144
|
+
'Bitwrench is a zero-dependency JS UI library (~40KB gzipped). You',
|
|
145
|
+
'generate UI by composing TACO objects -- plain JSON:',
|
|
146
|
+
'',
|
|
147
|
+
" {t: 'div', a: {class: 'bw_card'}, c: 'Hello'}",
|
|
148
|
+
' ^tag ^attributes ^content (string, TACO, or array)',
|
|
149
|
+
'',
|
|
150
|
+
'YOUR WORKFLOW:',
|
|
151
|
+
'1. Call bitwrench_guide to learn TACO format, layout, and composition',
|
|
152
|
+
'2. Call bitwrench_components to look up props for specific components',
|
|
153
|
+
'3. Call make_card, make_table, make_hero, etc. to build TACO components',
|
|
154
|
+
'4. Nest TACOs into a layout using the grid: bw_container > bw_row > bw_col',
|
|
155
|
+
'5. Call build_page with a theme to produce a complete standalone .html file',
|
|
156
|
+
'',
|
|
157
|
+
'KEY RULES:',
|
|
158
|
+
'- Every make*() tool returns a TACO object, NOT HTML',
|
|
159
|
+
"- Compose by nesting TACOs in the 'c' field: {t:'div', c: [taco1, taco2]}",
|
|
160
|
+
'- Grid layout:',
|
|
161
|
+
" {t:'div', a:{class:'bw_container'}, c:[",
|
|
162
|
+
" {t:'div', a:{class:'bw_row'}, c:[",
|
|
163
|
+
" {t:'div', a:{class:'bw_col'}, c:[ <your content> ]}",
|
|
164
|
+
' ]}',
|
|
165
|
+
' ]}',
|
|
166
|
+
"- Themes: pass theme:'ocean' to build_page (also: forest, sunset,",
|
|
167
|
+
' midnight, slate, rose, indigo, amber, emerald, nord, coral, teal)',
|
|
168
|
+
'- Call render_taco to convert any TACO to an HTML string',
|
|
169
|
+
'- Call build_page to get a complete standalone .html file (works offline)',
|
|
170
|
+
'',
|
|
171
|
+
'OTHER KNOWLEDGE TOOLS (call as needed):',
|
|
172
|
+
'- bitwrench_guide: Full tutorial (TACO format, 3 levels, events, CSS,',
|
|
173
|
+
' components, bwserve, routing, API reference)',
|
|
174
|
+
'- bitwrench_components: Props reference for all 47+ make*() components',
|
|
175
|
+
'- bitwrench_server_guide: bwserve tutorial (SSE streaming, live UI)',
|
|
176
|
+
'- bitwrench_themes: Theme presets, custom palettes, color utilities'
|
|
177
|
+
].join('\n');
|
|
178
|
+
|
|
179
|
+
export var knowledgeHandlers = {
|
|
180
|
+
bitwrench_start_here: function() {
|
|
181
|
+
return { content: [{ type: 'text', text: START_HERE_TEXT }] };
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
bitwrench_guide: function(args) {
|
|
185
|
+
var content = readDoc('llm-bitwrench-guide.md');
|
|
186
|
+
if (args && args.section) {
|
|
187
|
+
var heading = GUIDE_SECTIONS[args.section];
|
|
188
|
+
if (!heading) {
|
|
189
|
+
return {
|
|
190
|
+
content: [{ type: 'text', text: 'Unknown section: ' + args.section + '. Valid: ' + Object.keys(GUIDE_SECTIONS).join(', ') }],
|
|
191
|
+
isError: true
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
var section = extractSection(content, heading);
|
|
195
|
+
if (!section) {
|
|
196
|
+
return {
|
|
197
|
+
content: [{ type: 'text', text: 'Section not found in guide: ' + heading }],
|
|
198
|
+
isError: true
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
content = section;
|
|
202
|
+
}
|
|
203
|
+
return { content: [{ type: 'text', text: content }] };
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
bitwrench_components: function(args) {
|
|
207
|
+
var content = readDoc('component-library.md');
|
|
208
|
+
if (args && args.component) {
|
|
209
|
+
var section = extractComponent(content, args.component);
|
|
210
|
+
if (!section) {
|
|
211
|
+
return {
|
|
212
|
+
content: [{ type: 'text', text: 'Component not found: ' + args.component }],
|
|
213
|
+
isError: true
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
content = section;
|
|
217
|
+
}
|
|
218
|
+
return { content: [{ type: 'text', text: content }] };
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
bitwrench_server_guide: function() {
|
|
222
|
+
return { content: [{ type: 'text', text: readDoc('tutorial-bwserve.md') }] };
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
bitwrench_themes: function() {
|
|
226
|
+
return { content: [{ type: 'text', text: readDoc('theming.md') }] };
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Exported for testing
|
|
231
|
+
export { extractSection, extractComponent, readDoc, GUIDE_SECTIONS, DOCS_DIR };
|