bitwrench 2.0.15 → 2.0.17

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.
Files changed (53) hide show
  1. package/README.md +57 -21
  2. package/dist/bitwrench-bccl.cjs.js +3750 -0
  3. package/dist/bitwrench-bccl.cjs.min.js +40 -0
  4. package/dist/bitwrench-bccl.esm.js +3745 -0
  5. package/dist/bitwrench-bccl.esm.min.js +40 -0
  6. package/dist/bitwrench-bccl.umd.js +3756 -0
  7. package/dist/bitwrench-bccl.umd.min.js +40 -0
  8. package/dist/bitwrench-code-edit.cjs.js +57 -7
  9. package/dist/bitwrench-code-edit.cjs.min.js +9 -2
  10. package/dist/bitwrench-code-edit.es5.js +74 -11
  11. package/dist/bitwrench-code-edit.es5.min.js +9 -2
  12. package/dist/bitwrench-code-edit.esm.js +57 -7
  13. package/dist/bitwrench-code-edit.esm.min.js +9 -2
  14. package/dist/bitwrench-code-edit.umd.js +57 -7
  15. package/dist/bitwrench-code-edit.umd.min.js +9 -2
  16. package/dist/bitwrench-lean.cjs.js +905 -157
  17. package/dist/bitwrench-lean.cjs.min.js +7 -7
  18. package/dist/bitwrench-lean.es5.js +931 -157
  19. package/dist/bitwrench-lean.es5.min.js +5 -5
  20. package/dist/bitwrench-lean.esm.js +904 -157
  21. package/dist/bitwrench-lean.esm.min.js +7 -7
  22. package/dist/bitwrench-lean.umd.js +905 -157
  23. package/dist/bitwrench-lean.umd.min.js +7 -7
  24. package/dist/bitwrench.cjs.js +910 -158
  25. package/dist/bitwrench.cjs.min.js +8 -8
  26. package/dist/bitwrench.css +60 -17
  27. package/dist/bitwrench.es5.js +939 -158
  28. package/dist/bitwrench.es5.min.js +6 -6
  29. package/dist/bitwrench.esm.js +909 -158
  30. package/dist/bitwrench.esm.min.js +8 -8
  31. package/dist/bitwrench.min.css +1 -1
  32. package/dist/bitwrench.umd.js +910 -158
  33. package/dist/bitwrench.umd.min.js +8 -8
  34. package/dist/builds.json +168 -80
  35. package/dist/bwserve.cjs.js +660 -0
  36. package/dist/bwserve.esm.js +652 -0
  37. package/dist/sri.json +36 -28
  38. package/package.json +20 -3
  39. package/readme.html +62 -23
  40. package/src/bitwrench-bccl-entry.js +72 -0
  41. package/src/bitwrench-bccl.js +5 -1
  42. package/src/bitwrench-code-edit.js +56 -6
  43. package/src/bitwrench-color-utils.js +5 -6
  44. package/src/bitwrench-styles.js +20 -8
  45. package/src/bitwrench.js +876 -140
  46. package/src/bwserve/client.js +182 -0
  47. package/src/bwserve/index.js +363 -0
  48. package/src/bwserve/shell.js +106 -0
  49. package/src/cli/index.js +36 -15
  50. package/src/cli/layout-default.js +47 -32
  51. package/src/cli/serve.js +325 -0
  52. package/src/version.js +3 -3
  53. /package/bin/{bitwrench.js → bwcli.js} +0 -0
package/src/cli/index.js CHANGED
@@ -1,21 +1,27 @@
1
1
  /**
2
- * Bitwrench CLI - Main entry point
2
+ * bwcli Main entry point for the bitwrench command-line tool
3
3
  * Arg parsing with util.parseArgs(), help, version, dispatch
4
+ *
5
+ * Subcommands:
6
+ * bwcli <file> [options] Convert a file to styled HTML
7
+ * bwcli serve [dir] [options] Start bwserve dev server
4
8
  */
5
9
 
6
10
  import { parseArgs } from 'node:util';
7
11
  import { VERSION } from '../version.js';
8
12
  import { convertFile } from './convert.js';
13
+ import { runServe } from './serve.js';
9
14
 
10
15
  const USAGE = `
11
- bitwrench v${VERSION} — Document converter & static site generator
16
+ bwcli v${VERSION} — bitwrench command-line tool
12
17
 
13
18
  Usage:
14
- bitwrench <file> [options] Convert a file to styled HTML
15
- bitwrench --version Print version
16
- bitwrench --help Print this help
19
+ bwcli <file> [options] Convert a file to styled HTML
20
+ bwcli serve [dir] [options] Start bwserve development server
21
+ bwcli --version Print version
22
+ bwcli --help Print this help
17
23
 
18
- Options:
24
+ Convert options:
19
25
  -o, --output <file> Output file path (default: input with .html extension)
20
26
  -c, --css <file> Include external CSS file
21
27
  -t, --theme <name> Theme preset (ocean, sunset, forest, slate) or hex colors ("#pri,#sec")
@@ -26,16 +32,26 @@ Options:
26
32
  -f, --favicon <path> Favicon path or URL
27
33
  --highlight Include highlight.js for syntax highlighting
28
34
  -v, --verbose Verbose output
35
+
36
+ Serve options:
37
+ -p, --port <number> Port to listen on (default: 7902)
38
+ -t, --theme <name> Theme preset or hex colors
39
+ --open Open browser on start
40
+ -v, --verbose Verbose output
41
+
42
+ General:
29
43
  -h, --help Print this help
30
44
  --version Print version
31
45
 
32
46
  Examples:
33
- bitwrench README.md Convert README.md to README.html
34
- bitwrench README.md -o index.html Specify output file
35
- bitwrench README.md -o out.html --theme ocean Apply ocean theme
36
- bitwrench README.md -o out.html --standalone Self-contained offline HTML
37
- bitwrench README.md -o out.html --highlight With syntax highlighting
38
- bitwrench doc.md --theme "#336699,#cc6633" Custom theme colors
47
+ bwcli README.md Convert README.md to README.html
48
+ bwcli README.md -o index.html Specify output file
49
+ bwcli README.md -o out.html --theme ocean Apply ocean theme
50
+ bwcli README.md -o out.html --standalone Self-contained offline HTML
51
+ bwcli README.md -o out.html --highlight With syntax highlighting
52
+ bwcli doc.md --theme "#336699,#cc6633" Custom theme colors
53
+ bwcli serve Serve current directory on port 7902
54
+ bwcli serve ./site --port 8080 Serve ./site on port 8080
39
55
  `.trim();
40
56
 
41
57
  /**
@@ -43,6 +59,11 @@ Examples:
43
59
  * @param {string[]} argv - process.argv.slice(2)
44
60
  */
45
61
  export function run(argv) {
62
+ // Check for subcommand before parseArgs (subcommands have different options)
63
+ if (argv.length > 0 && argv[0] === 'serve') {
64
+ return runServe(argv.slice(1));
65
+ }
66
+
46
67
  let values, positionals;
47
68
 
48
69
  try {
@@ -69,13 +90,13 @@ export function run(argv) {
69
90
  positionals = result.positionals;
70
91
  } catch (err) {
71
92
  console.error(`Error: ${err.message}`);
72
- console.error('Run "bitwrench --help" for usage.');
93
+ console.error('Run "bwcli --help" for usage.');
73
94
  process.exit(1);
74
95
  }
75
96
 
76
97
  // --version
77
98
  if (values.version) {
78
- console.log(`bitwrench v${VERSION}`);
99
+ console.log(`bwcli v${VERSION}`);
79
100
  return;
80
101
  }
81
102
 
@@ -88,7 +109,7 @@ export function run(argv) {
88
109
  // No positional args → error
89
110
  if (positionals.length === 0) {
90
111
  console.error('Error: No input file specified.');
91
- console.error('Run "bitwrench --help" for usage.');
112
+ console.error('Run "bwcli --help" for usage.');
92
113
  process.exit(1);
93
114
  }
94
115
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Bitwrench CLI - Default page layout
3
- * Wraps converted content in a complete HTML document
3
+ * Wraps converted content in a complete HTML document.
4
+ * Delegates to bw.htmlPage() for document structure.
4
5
  */
5
6
 
6
7
  import bw from '../bitwrench.js';
@@ -77,7 +78,11 @@ const BASE_PAGE_CSS = `
77
78
  `;
78
79
 
79
80
  /**
80
- * Build a complete HTML page from content and options
81
+ * Build a complete HTML page from content and options.
82
+ * Delegates to bw.htmlPage() for document structure, adding CLI-specific
83
+ * concerns: .bw_cli_page wrapper, generator meta tag, highlight.js, and
84
+ * pre-resolved injection strings from inject.js.
85
+ *
81
86
  * @param {Object} opts
82
87
  * @param {string} opts.title - Page title
83
88
  * @param {string} opts.bodyHTML - Rendered HTML content for the body
@@ -99,44 +104,54 @@ export function makePageLayout(opts) {
99
104
  highlight = false
100
105
  } = opts;
101
106
 
102
- const safeTitle = bw.escapeHTML(title);
103
- const version = bw.version;
107
+ const version = bw.getVersion().version;
104
108
 
105
- let faviconTag = '';
106
- if (favicon) {
107
- // Only escape quotes and angle brackets for attribute safety, not slashes
108
- const safeFavicon = favicon.replace(/[&<>"']/g, c => ({
109
- '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
110
- })[c]);
111
- faviconTag = `<link rel="icon" href="${safeFavicon}">`;
109
+ // Build extra <head> elements: generator meta, injection script, highlight.js CSS
110
+ const headElements = [];
111
+
112
+ // Generator meta tag (CLI-specific)
113
+ headElements.push({
114
+ t: 'meta', a: { name: 'generator', content: 'bitwrench v' + version }
115
+ });
116
+
117
+ // Injection script from inject.js (already pre-built HTML string)
118
+ if (headInjection) {
119
+ headElements.push(bw.raw(headInjection));
112
120
  }
113
121
 
114
- let highlightHead = '';
115
- let highlightBodyEnd = '';
122
+ // Highlight.js CSS
116
123
  if (highlight) {
117
- highlightHead = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github.min.css">';
118
- highlightBodyEnd = '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"></script>\n<script>hljs.highlightAll();</script>';
124
+ headElements.push({
125
+ t: 'link', a: {
126
+ rel: 'stylesheet',
127
+ href: 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github.min.css'
128
+ }
129
+ });
119
130
  }
120
131
 
132
+ // Wrap body content in .bw_cli_page div (CLI-specific)
133
+ const wrappedBody = '<div class="bw_cli_page">\n' + bodyHTML + '\n</div>';
134
+
135
+ // Build body-end injection (highlight.js init)
136
+ let fullBodyEnd = bodyEndInjection || '';
137
+ if (highlight) {
138
+ fullBodyEnd += '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"></script>\n<script>hljs.highlightAll();</script>';
139
+ }
140
+
141
+ // Combine all CSS
121
142
  const allCSS = BASE_PAGE_CSS + (css ? '\n' + css : '');
122
143
 
123
- return `<!DOCTYPE html>
124
- <html lang="en">
125
- <head>
126
- <meta charset="UTF-8">
127
- <meta name="viewport" content="width=device-width, initial-scale=1">
128
- <meta name="generator" content="bitwrench v${version}">
129
- <title>${safeTitle}</title>
130
- ${faviconTag}${headInjection}${highlightHead}
131
- <style>${allCSS}</style>
132
- </head>
133
- <body>
134
- <div class="bw_cli_page">
135
- ${bodyHTML}
136
- </div>
137
- ${bodyEndInjection}${highlightBodyEnd}
138
- </body>
139
- </html>`;
144
+ // Use bw.htmlPage() with runtime:'none' since CLI handles injection itself
145
+ var page = bw.htmlPage({
146
+ title: title,
147
+ body: wrappedBody + (fullBodyEnd ? '\n' + fullBodyEnd : ''),
148
+ css: allCSS,
149
+ head: headElements,
150
+ favicon: favicon,
151
+ runtime: 'none'
152
+ });
153
+
154
+ return page;
140
155
  }
141
156
 
142
157
  export { BASE_PAGE_CSS };
@@ -0,0 +1,325 @@
1
+ /**
2
+ * bwcli serve — CLI subcommand for bwserve pipe server.
3
+ *
4
+ * Serves a directory of bitwrench pages and accepts protocol messages
5
+ * via an input HTTP port or stdin. Broadcasts messages to all connected
6
+ * browser tabs.
7
+ *
8
+ * Usage:
9
+ * bwcli serve [dir] [--port N] [--listen N] [--stdin] [--theme name]
10
+ */
11
+
12
+ import { parseArgs } from 'node:util';
13
+ import { createServer } from 'node:http';
14
+ import { createReadStream } from 'node:fs';
15
+ import { VERSION } from '../version.js';
16
+
17
+ var SERVE_USAGE = `
18
+ bwcli serve v${VERSION} — Pipe server for browser UI
19
+
20
+ Usage:
21
+ bwcli serve [dir] [options]
22
+
23
+ Arguments:
24
+ dir Directory to serve static files from (default: .)
25
+
26
+ Options:
27
+ -p, --port <number> Browser-facing web port (default: 8080)
28
+ -l, --listen <number> Input port for protocol messages (default: 9000)
29
+ --stdin Read protocol messages from stdin (newline-delimited JSON)
30
+ -t, --theme <name> Theme preset or hex colors ("#pri,#sec")
31
+ --title <string> Page title (default: "bwcli serve")
32
+ --open Open browser on start
33
+ -v, --verbose Verbose output
34
+ -h, --help Print this help
35
+
36
+ Examples:
37
+ bwcli serve Serve . on :8080, listen on :9000
38
+ bwcli serve ./public --port 3000 Serve ./public on :3000
39
+ bwcli serve --stdin Read from pipe instead of input port
40
+ sensor-reader | bwcli serve --stdin Pipe sensor data to browser
41
+ curl -X POST :9000 -d '{"type":"replace","target":"#app","node":{"t":"h1","c":"Hi"}}'
42
+ `.trim();
43
+
44
+ /**
45
+ * Parse a message string — supports both strict JSON and r-prefixed relaxed JSON.
46
+ * @param {string} str
47
+ * @returns {Object|null} parsed message or null on error
48
+ */
49
+ function parseMessage(str) {
50
+ str = str.trim();
51
+ if (!str) return null;
52
+ try {
53
+ if (str.charAt(0) === 'r') {
54
+ return parseRelaxedJSON(str.slice(1));
55
+ }
56
+ return JSON.parse(str);
57
+ } catch (e) {
58
+ return null;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Parse relaxed JSON (single-quoted strings, trailing commas).
64
+ * State machine — walks char by char.
65
+ */
66
+ function parseRelaxedJSON(str) {
67
+ var out = [];
68
+ var i = 0;
69
+ var len = str.length;
70
+
71
+ while (i < len) {
72
+ var ch = str[i];
73
+
74
+ if (ch === "'") {
75
+ out.push('"');
76
+ i++;
77
+ while (i < len) {
78
+ var c = str[i];
79
+ if (c === '\\' && i + 1 < len) {
80
+ var next = str[i + 1];
81
+ if (next === "'") {
82
+ out.push("'");
83
+ } else {
84
+ out.push('\\');
85
+ out.push(next);
86
+ }
87
+ i += 2;
88
+ } else if (c === '"') {
89
+ out.push('\\"');
90
+ i++;
91
+ } else if (c === "'") {
92
+ break;
93
+ } else {
94
+ out.push(c);
95
+ i++;
96
+ }
97
+ }
98
+ out.push('"');
99
+ i++;
100
+ } else if (ch === '"') {
101
+ out.push(ch);
102
+ i++;
103
+ while (i < len) {
104
+ var c2 = str[i];
105
+ if (c2 === '\\' && i + 1 < len) {
106
+ out.push(c2);
107
+ out.push(str[i + 1]);
108
+ i += 2;
109
+ } else {
110
+ out.push(c2);
111
+ i++;
112
+ if (c2 === '"') break;
113
+ }
114
+ }
115
+ } else if (ch === ',') {
116
+ var j = i + 1;
117
+ while (j < len && (str[j] === ' ' || str[j] === '\t' || str[j] === '\n' || str[j] === '\r')) j++;
118
+ if (j < len && (str[j] === '}' || str[j] === ']')) {
119
+ i++;
120
+ } else {
121
+ out.push(ch);
122
+ i++;
123
+ }
124
+ } else {
125
+ out.push(ch);
126
+ i++;
127
+ }
128
+ }
129
+
130
+ return JSON.parse(out.join(''));
131
+ }
132
+
133
+ /**
134
+ * Run the serve subcommand.
135
+ * @param {string[]} argv - arguments after "serve"
136
+ */
137
+ export function runServe(argv) {
138
+ var values, positionals;
139
+
140
+ try {
141
+ var result = parseArgs({
142
+ args: argv,
143
+ strict: true,
144
+ allowPositionals: true,
145
+ options: {
146
+ port: { type: 'string', short: 'p' },
147
+ listen: { type: 'string', short: 'l' },
148
+ stdin: { type: 'boolean' },
149
+ theme: { type: 'string', short: 't' },
150
+ title: { type: 'string' },
151
+ open: { type: 'boolean' },
152
+ verbose: { type: 'boolean', short: 'v' },
153
+ help: { type: 'boolean', short: 'h' }
154
+ }
155
+ });
156
+ values = result.values;
157
+ positionals = result.positionals;
158
+ } catch (err) {
159
+ console.error('Error: ' + err.message);
160
+ console.error('Run "bwcli serve --help" for usage.');
161
+ process.exit(1);
162
+ }
163
+
164
+ if (values.help) {
165
+ console.log(SERVE_USAGE);
166
+ return;
167
+ }
168
+
169
+ var dir = positionals[0] || '.';
170
+ var webPort = values.port ? parseInt(values.port, 10) : 8080;
171
+ var listenPort = values.listen ? parseInt(values.listen, 10) : 9000;
172
+ var useStdin = !!values.stdin;
173
+ var theme = values.theme || null;
174
+ var title = values.title || 'bwcli serve';
175
+ var verbose = !!values.verbose;
176
+
177
+ if (isNaN(webPort) || webPort < 1 || webPort > 65535) {
178
+ console.error('Error: --port must be a number between 1 and 65535.');
179
+ process.exit(1);
180
+ }
181
+ if (!useStdin && (isNaN(listenPort) || listenPort < 1 || listenPort > 65535)) {
182
+ console.error('Error: --listen must be a number between 1 and 65535.');
183
+ process.exit(1);
184
+ }
185
+
186
+ // Dynamic import of bwserve to avoid loading it at parse time
187
+ import('../../src/bwserve/index.js').then(function(bwserve) {
188
+ startServer(bwserve, {
189
+ dir: dir,
190
+ webPort: webPort,
191
+ listenPort: listenPort,
192
+ useStdin: useStdin,
193
+ theme: theme,
194
+ title: title,
195
+ verbose: verbose,
196
+ open: !!values.open
197
+ });
198
+ }).catch(function(err) {
199
+ console.error('Failed to load bwserve: ' + err.message);
200
+ process.exit(1);
201
+ });
202
+ }
203
+
204
+ /**
205
+ * Start the bwserve pipe server.
206
+ */
207
+ function startServer(bwserve, opts) {
208
+ var app = bwserve.create({
209
+ port: opts.webPort,
210
+ title: opts.title,
211
+ static: opts.dir,
212
+ theme: opts.theme
213
+ });
214
+
215
+ // Register a passthrough page handler — just keeps clients alive
216
+ app.page('/', function(client) {
217
+ if (opts.verbose) {
218
+ console.error('[bwcli serve] Client connected: ' + client.id);
219
+ }
220
+ client.on('_disconnect', function() {
221
+ if (opts.verbose) {
222
+ console.error('[bwcli serve] Client disconnected: ' + client.id);
223
+ }
224
+ });
225
+ });
226
+
227
+ // Start web server
228
+ app.listen(function() {
229
+ console.error('bwcli serve v' + VERSION);
230
+ console.error(' Web server: http://localhost:' + opts.webPort);
231
+ console.error(' Static dir: ' + opts.dir);
232
+ if (opts.theme) console.error(' Theme: ' + opts.theme);
233
+
234
+ if (opts.useStdin) {
235
+ console.error(' Input: stdin (newline-delimited JSON)');
236
+ startStdinReader(app, opts.verbose);
237
+ } else {
238
+ console.error(' Input port: http://localhost:' + opts.listenPort);
239
+ startInputServer(app, opts.listenPort, opts.verbose);
240
+ }
241
+
242
+ console.error('');
243
+ console.error('Ready. Send protocol messages to push UI to browsers.');
244
+
245
+ if (opts.open) {
246
+ import('node:child_process').then(function(cp) {
247
+ var url = 'http://localhost:' + opts.webPort;
248
+ var cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
249
+ cp.exec(cmd + ' ' + url);
250
+ });
251
+ }
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Start the input HTTP server for receiving protocol messages.
257
+ */
258
+ function startInputServer(app, listenPort, verbose) {
259
+ var inputServer = createServer(function(req, res) {
260
+ if (req.method !== 'POST') {
261
+ res.writeHead(405, { 'Content-Type': 'application/json' });
262
+ res.end(JSON.stringify({ error: 'Use POST' }));
263
+ return;
264
+ }
265
+
266
+ var body = '';
267
+ req.on('data', function(chunk) { body += chunk; });
268
+ req.on('end', function() {
269
+ var msg = parseMessage(body);
270
+ if (!msg) {
271
+ res.writeHead(400, { 'Content-Type': 'application/json' });
272
+ res.end(JSON.stringify({ error: 'Invalid message' }));
273
+ return;
274
+ }
275
+
276
+ var count = app.broadcast(msg);
277
+ if (verbose) {
278
+ console.error('[input] ' + msg.type + ' -> ' + count + ' client(s)');
279
+ }
280
+ res.writeHead(200, { 'Content-Type': 'application/json' });
281
+ res.end(JSON.stringify({ ok: true, clients: count }));
282
+ });
283
+ });
284
+
285
+ inputServer.listen(listenPort);
286
+ }
287
+
288
+ /**
289
+ * Read protocol messages from stdin (newline-delimited).
290
+ */
291
+ function startStdinReader(app, verbose) {
292
+ var buffer = '';
293
+
294
+ process.stdin.setEncoding('utf8');
295
+ process.stdin.on('data', function(chunk) {
296
+ buffer += chunk;
297
+ var lines = buffer.split('\n');
298
+ buffer = lines.pop() || '';
299
+
300
+ for (var i = 0; i < lines.length; i++) {
301
+ var line = lines[i].trim();
302
+ if (!line) continue;
303
+
304
+ var msg = parseMessage(line);
305
+ if (!msg) {
306
+ if (verbose) console.error('[stdin] Parse error: ' + line.slice(0, 80));
307
+ continue;
308
+ }
309
+
310
+ var count = app.broadcast(msg);
311
+ if (verbose) {
312
+ console.error('[stdin] ' + msg.type + ' -> ' + count + ' client(s)');
313
+ }
314
+ }
315
+ });
316
+
317
+ process.stdin.on('end', function() {
318
+ // Flush remaining buffer
319
+ if (buffer.trim()) {
320
+ var msg = parseMessage(buffer.trim());
321
+ if (msg) app.broadcast(msg);
322
+ }
323
+ if (verbose) console.error('[stdin] Input stream closed. Server stays running.');
324
+ });
325
+ }
package/src/version.js CHANGED
@@ -3,14 +3,14 @@
3
3
  * DO NOT EDIT DIRECTLY - Use npm run generate-version
4
4
  */
5
5
 
6
- export const VERSION = '2.0.15';
6
+ export const VERSION = '2.0.17';
7
7
  export const VERSION_INFO = {
8
- version: '2.0.15',
8
+ version: '2.0.17',
9
9
  name: 'bitwrench',
10
10
  description: 'A library for javascript UI functions.',
11
11
  license: 'BSD-2-Clause',
12
12
  homepage: 'https://deftio.github.com/bitwrench/pages',
13
13
  repository: 'git+https://github.com/deftio/bitwrench.git',
14
14
  author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
15
- buildDate: '2026-03-10T09:08:17.015Z'
15
+ buildDate: '2026-03-13T23:15:10.823Z'
16
16
  };
File without changes