clew-code 0.2.27 → 0.2.28

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/docs/js/main.js CHANGED
@@ -1,437 +1,438 @@
1
- // Clew Docs — Mobile Nav, Header, Sidebar, TOC, Code Copy
2
- (function () {
3
- 'use strict';
4
-
5
- // ── Root Prefix (for script location detection) ──
6
- var rootPrefix = '';
7
- var scripts = document.getElementsByTagName('script');
8
- for (var i = 0; i < scripts.length; i++) {
9
- var src = scripts[i].getAttribute('src');
10
- if (src && src.indexOf('js/main.js') !== -1) {
11
- rootPrefix = src.replace('js/main.js', '');
12
- break;
13
- }
14
- }
15
-
16
- // ── Header Injection ──
17
- function injectHeader() {
18
- var header = document.querySelector('.header');
19
- if (!header) return;
20
-
21
- var path = window.location.pathname;
22
- var isThai = /\.th\.html$/.test(path);
23
- var isIndex = /\/index(\.th)?\.html$/.test(path) || path === '/' || path.endsWith('/docs/');
24
- var currentPage = path.split('/').pop() || 'index.html';
25
-
26
- var logoHref = isThai ? 'index.th.html' : 'index.html';
27
- var docsHref = isThai ? 'quick-start.th.html' : 'quick-start.html';
28
- var ariaLabel = isThai ? '\u0E40\u0E1B\u0E34\u0E14/\u0E1B\u0E34\u0E14\u0E40\u0E21\u0E19\u0E39' : 'Toggle navigation';
29
-
30
- // Language toggle
31
- var langTarget = isThai
32
- ? currentPage.replace(/\.th\.html$/, '.html')
33
- : currentPage.replace(/\.html$/, '.th.html');
34
- var langLabel = isThai ? 'EN' : '\u0E44\u0E17\u0E22';
35
- // If no .html page exists for the target, just use README
36
- if (isIndex) langTarget = isThai ? 'index.html' : 'index.th.html';
37
-
38
- // Build breadcrumbs from path
39
- var crumbs = [];
40
- var parts = path.replace(/\/$/, '').split('/').filter(Boolean);
41
- if (parts[0] === 'docs') parts.shift(); // remove leading "docs"
42
- if (parts.length > 0) {
43
- var crumbPath = '';
44
- for (var i = 0; i < parts.length; i++) {
45
- crumbPath += (i === 0 ? '' : '/') + parts[i];
46
- var isLast = i === parts.length - 1;
47
- var label = parts[i].replace(/\.th\.html$/, '').replace(/\.html$/, '').replace(/-/g, ' ');
48
- if (isLast) {
49
- crumbs.push('<span class="current">' + label + '</span>');
50
- } else {
51
- crumbs.push('<a href="' + crumbPath + '">' + label + '</a>');
52
- crumbs.push('<span class="sep">/</span>');
53
- }
54
- }
55
- }
56
- var breadcrumbsHtml = crumbs.length > 0
57
- ? '<nav class="header-breadcrumbs">' + crumbs.join('') + '</nav>'
58
- : '';
59
-
60
- header.innerHTML =
61
- '<div class="header-inner">' +
62
- ' <a href="' + logoHref + '" class="logo">Clew</a>' +
63
- breadcrumbsHtml +
64
- ' <div class="header-search">' +
65
- ' <input type="text" id="headerSearchInput" placeholder="' + (isThai ? '\u0E04\u0E49\u0E19\u0E2B\u0E32\u0E40\u0E2D\u0E01\u0E2A\u0E32\u0E23...' : 'Search docs...') + '" autocomplete="off">' +
66
- ' <span class="search-icon">\u2315</span>' +
67
- ' <div class="search-results" id="headerSearchResults"></div>' +
68
- ' </div>' +
69
- ' <nav class="header-nav">' +
70
- ' <a href="' + logoHref + '">' + (isThai ? '\u0E2B\u0E19\u0E49\u0E32\u0E41\u0E23\u0E01' : 'Home') + '</a>' +
71
- ' <a href="' + docsHref + '">' + (isThai ? '\u0E40\u0E2D\u0E01\u0E2A\u0E32\u0E23' : 'Docs') + '</a>' +
72
- ' <a href="https://github.com/JonusNattapong/ClewCode" target="_blank">GitHub</a>' +
73
- ' </nav>' +
74
- ' <button class="lang-toggle" id="langToggle" aria-label="Switch language">' + langLabel + '</button>' +
75
- ' <button class="menu-btn" id="menuToggle" aria-label="' + ariaLabel + '"><span></span><span></span><span></span></button>' +
76
- '</div>';
77
-
78
- // Language toggle
79
- var langToggle = document.getElementById('langToggle');
80
- if (langToggle) {
81
- langToggle.addEventListener('click', function () {
82
- window.location.href = langTarget;
83
- });
84
- }
85
-
86
- // Active nav link
87
- var navLinks = header.querySelectorAll('.header-nav a');
88
- navLinks.forEach(function (link) {
89
- var href = link.getAttribute('href');
90
- if (!href) return;
91
- var hrefPage = href.split('/').pop().split('#')[0] || 'index.html';
92
- if (hrefPage === currentPage) link.classList.add('active');
93
- });
94
- if (!isIndex) {
95
- var docsLink = header.querySelector('.header-nav a[href*="quick-start"]');
96
- if (docsLink) docsLink.classList.add('active');
97
- }
98
-
99
- // Search functionality
100
- initHeaderSearch();
101
- }
102
-
103
- function initHeaderSearch() {
104
- var input = document.getElementById('headerSearchInput');
105
- var results = document.getElementById('headerSearchResults');
106
- if (!input || !results) return;
107
-
108
- // Build search index from sidebar links + TOC headings
109
- var searchIndex = [];
110
- document.querySelectorAll('.sidebar-link').forEach(function (link) {
111
- searchIndex.push({ text: link.textContent.trim(), href: link.getAttribute('href'), type: 'page' });
112
- });
113
- document.querySelectorAll('.content h2, .content h3').forEach(function (h) {
114
- searchIndex.push({ text: h.textContent.trim(), href: '#' + h.id, type: 'section' });
115
- });
116
-
117
- input.addEventListener('input', function () {
118
- var query = this.value.trim().toLowerCase();
119
- results.innerHTML = '';
120
- results.classList.remove('open');
121
- if (query.length < 1) return;
122
-
123
- var matches = [];
124
- for (var i = 0; i < searchIndex.length; i++) {
125
- var item = searchIndex[i];
126
- if (item.text.toLowerCase().indexOf(query) !== -1) {
127
- matches.push(item);
128
- }
129
- }
130
-
131
- if (matches.length === 0) {
132
- results.innerHTML = '<div class="search-empty">No results found</div>';
133
- results.classList.add('open');
134
- return;
135
- }
136
-
137
- for (var j = 0; j < Math.min(matches.length, 8); j++) {
138
- var m = matches[j];
139
- var highlighted = m.text.replace(
140
- new RegExp('(' + query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')', 'gi'),
141
- '<mark>$1</mark>'
142
- );
143
- results.innerHTML +=
144
- '<a href="' + m.href + '" class="search-result">' +
145
- '<span class="search-type">' + (m.type === 'page' ? '\u{1F4C4}' : '#') + '</span> ' +
146
- highlighted +
147
- '</a>';
148
- }
149
- results.classList.add('open');
150
- });
151
-
152
- // Close on click outside
153
- document.addEventListener('click', function (e) {
154
- if (!input.contains(e.target) && !results.contains(e.target)) {
155
- results.classList.remove('open');
156
- }
157
- });
158
-
159
- // Close on Escape
160
- input.addEventListener('keydown', function (e) {
161
- if (e.key === 'Escape') {
162
- results.classList.remove('open');
163
- input.blur();
164
- }
165
- });
166
- }
167
-
168
- injectHeader();
169
-
170
- // ── Sidebar Injection ──
171
- var sidebar = document.getElementById('sidebar');
172
- if (sidebar) {
173
- sidebar.innerHTML =
174
- '<div class="sidebar-section">' +
175
- ' <div class="sidebar-label">Getting Started</div>' +
176
- ' <nav>' +
177
- ' <a href="' + rootPrefix + 'index.html" class="sidebar-link"><span class="link-icon"></span>Overview</a>' +
178
- ' <a href="' + rootPrefix + 'quick-start.html" class="sidebar-link"><span class="link-icon"></span>Quick Start</a>' +
179
- ' <a href="' + rootPrefix + 'installation.html" class="sidebar-link"><span class="link-icon"></span>Installation</a>' +
180
- ' <a href="' + rootPrefix + 'configuration.html" class="sidebar-link"><span class="link-icon"></span>Configuration</a>' +
181
- ' <a href="' + rootPrefix + 'cli-reference.html" class="sidebar-link"><span class="link-icon"></span>CLI Reference</a>' +
182
- ' <a href="' + rootPrefix + 'troubleshooting.html" class="sidebar-link"><span class="link-icon"></span>Troubleshooting</a>' +
183
- ' </nav>' +
184
- '</div>' +
185
- '<div class="sidebar-section">' +
186
- ' <div class="sidebar-label">Core Concepts</div>' +
187
- ' <nav>' +
188
- ' <a href="' + rootPrefix + 'providers.html" class="sidebar-link"><span class="link-icon"></span>Providers</a>' +
189
- ' <a href="' + rootPrefix + 'models.html" class="sidebar-link"><span class="link-icon"></span>Models</a>' +
190
- ' <a href="' + rootPrefix + 'commands.html" class="sidebar-link"><span class="link-icon"></span>Commands</a>' +
191
- ' <a href="' + rootPrefix + 'tools.html" class="sidebar-link"><span class="link-icon"></span>Tools</a>' +
192
- ' <a href="' + rootPrefix + 'permission-model.html" class="sidebar-link"><span class="link-icon"></span>Permission Model</a>' +
193
- ' </nav>' +
194
- '</div>' +
195
- '<div class="sidebar-section">' +
196
- ' <div class="sidebar-label">Extending</div>' +
197
- ' <nav>' +
198
- ' <a href="' + rootPrefix + 'plugins.html" class="sidebar-link"><span class="link-icon"></span>Plugins</a>' +
199
- ' <a href="' + rootPrefix + 'skills.html" class="sidebar-link"><span class="link-icon"></span>Skills</a>' +
200
- ' <a href="' + rootPrefix + 'architecture.html" class="sidebar-link"><span class="link-icon"></span>Architecture</a>' +
201
- ' <a href="' + rootPrefix + 'mcp.html" class="sidebar-link"><span class="link-icon"></span>MCP</a>' +
202
- ' </nav>' +
203
- '</div>' +
204
- '<div class="sidebar-section">' +
205
- ' <div class="sidebar-label">Autonomous</div>' +
206
- ' <nav>' +
207
- ' <a href="' + rootPrefix + 'daemon.html" class="sidebar-link"><span class="link-icon"></span>Daemon Mode</a>' +
208
- ' </nav>' +
209
- '</div>' +
210
- '<div class="sidebar-section">' +
211
- ' <div class="sidebar-label">Features</div>' +
212
- ' <nav>' +
213
- ' <a href="' + rootPrefix + 'research-memory.html" class="sidebar-link"><span class="link-icon"></span>Research & Memory</a>' +
214
- ' <a href="' + rootPrefix + 'features/searxng-search.html" class="sidebar-link"><span class="link-icon"></span>SearXNG Search</a>' +
215
- ' <a href="' + rootPrefix + 'features/bridge-mode.html" class="sidebar-link"><span class="link-icon"></span>Bridge Mode</a>' +
216
- ' <a href="' + rootPrefix + 'features/evals.html" class="sidebar-link"><span class="link-icon"></span>Evaluation Harness</a>' +
217
- ' <a href="' + rootPrefix + 'features/sentry-setup.html" class="sidebar-link"><span class="link-icon"></span>Sentry Setup</a>' +
218
- ' <a href="' + rootPrefix + 'voice-mode.html" class="sidebar-link"><span class="link-icon"></span>Voice Mode</a>' +
219
- ' <a href="' + rootPrefix + 'swarm.html" class="sidebar-link"><span class="link-icon"></span>Swarm System</a>' +
220
- ' <a href="' + rootPrefix + 'loop.html" class="sidebar-link"><span class="link-icon"></span>Agent Loop</a>' +
221
- ' </nav>' +
222
- '</div>' +
223
- '<div class="sidebar-section">' +
224
- ' <div class="sidebar-label">Internals</div>' +
225
- ' <nav>' +
226
- ' <a href="' + rootPrefix + 'internals/hidden-features.html" class="sidebar-link"><span class="link-icon"></span>Hidden Features</a>' +
227
- ' <a href="' + rootPrefix + 'internals/growthbook-ab-testing.html" class="sidebar-link"><span class="link-icon"></span>A/B Testing</a>' +
228
- ' </nav>' +
229
- '</div>' +
230
- '<div class="sidebar-section">' +
231
- ' <div class="sidebar-label">Community</div>' +
232
- ' <nav>' +
233
- ' <a href="' + rootPrefix + 'changelog.html" class="sidebar-link"><span class="link-icon"></span>Changelog</a>' +
234
- ' <a href="' + rootPrefix + 'security.html" class="sidebar-link"><span class="link-icon"></span>Security</a>' +
235
- ' <a href="' + rootPrefix + 'contributing.html" class="sidebar-link"><span class="link-icon"></span>Contributing</a>' +
236
- ' </nav>' +
237
- '</div>';
238
- }
239
-
240
- // ── Mobile Nav ──
241
- var menuBtn = document.getElementById('menuToggle');
242
- var overlay = document.getElementById('sidebarOverlay');
243
-
244
- function openSidebar() {
245
- sidebar && sidebar.classList.add('open');
246
- menuBtn && menuBtn.setAttribute('aria-expanded', 'true');
247
- overlay && overlay.classList.add('open');
248
- document.body.style.overflow = 'hidden';
249
- }
250
-
251
- function closeSidebar() {
252
- sidebar && sidebar.classList.remove('open');
253
- menuBtn && menuBtn.setAttribute('aria-expanded', 'false');
254
- overlay && overlay.classList.remove('open');
255
- document.body.style.overflow = '';
256
- }
257
-
258
- if (menuBtn) menuBtn.addEventListener('click', function (e) {
259
- e.stopPropagation();
260
- sidebar && sidebar.classList.contains('open') ? closeSidebar() : openSidebar();
261
- });
262
-
263
- if (overlay) overlay.addEventListener('click', closeSidebar);
264
-
265
- document.addEventListener('keydown', function (e) {
266
- if (e.key === 'Escape' && sidebar && sidebar.classList.contains('open')) closeSidebar();
267
- });
268
-
269
- if (sidebar) {
270
- sidebar.querySelectorAll('.sidebar-link').forEach(function (link) {
271
- link.addEventListener('click', closeSidebar);
272
- });
273
- }
274
-
275
- // ── Active Sidebar Link ──
276
- var currentPath = window.location.pathname;
277
- var currentPage = currentPath.split('/').pop() || 'index.html';
278
- if (currentPage === '') currentPage = 'index.html';
279
-
280
- document.querySelectorAll('.sidebar-link').forEach(function (link) {
281
- var href = link.getAttribute('href');
282
- if (!href) return;
283
- var hrefPage = href.split('/').pop().split('#')[0];
284
- if (hrefPage === currentPage) link.classList.add('active');
285
- });
286
-
287
- // ── Code Copy Buttons ──
288
- function addCopyButtons() {
289
- document.querySelectorAll('.content pre').forEach(function (pre) {
290
- if (pre.parentElement && pre.parentElement.classList.contains('code-block-wrap')) return;
291
-
292
- var wrap = document.createElement('div');
293
- wrap.className = 'code-block-wrap';
294
-
295
- var header = document.createElement('div');
296
- header.className = 'code-block-header';
297
-
298
- var lang = document.createElement('span');
299
- var code = pre.querySelector('code');
300
- var langName = '';
301
- if (code) {
302
- var cls = code.className || '';
303
- var match = cls.match(/language-(\w+)/);
304
- if (match) langName = match[1];
305
- }
306
- lang.textContent = langName || '';
307
- lang.style.textTransform = 'lowercase';
308
-
309
- var btn = document.createElement('button');
310
- btn.className = 'copy-btn';
311
- btn.textContent = 'Copy';
312
- btn.setAttribute('aria-label', 'Copy code to clipboard');
313
-
314
- btn.addEventListener('click', function () {
315
- var text = pre.textContent || '';
316
- text = text.replace(/^\n+|\n+$/g, '');
317
- navigator.clipboard.writeText(text).then(function () {
318
- btn.textContent = 'Copied!';
319
- btn.classList.add('copied');
320
- setTimeout(function () {
321
- btn.textContent = 'Copy';
322
- btn.classList.remove('copied');
323
- }, 2000);
324
- }).catch(function () {
325
- btn.textContent = 'Failed';
326
- setTimeout(function () {
327
- btn.textContent = 'Copy';
328
- }, 2000);
329
- });
330
- });
331
-
332
- header.appendChild(lang);
333
- header.appendChild(btn);
334
-
335
- pre.parentNode.insertBefore(wrap, pre);
336
- wrap.appendChild(header);
337
- wrap.appendChild(pre);
338
- });
339
- }
340
-
341
- addCopyButtons();
342
-
343
- // ── Table Wrapping ──
344
- document.querySelectorAll('.content table').forEach(function (table) {
345
- if (table.parentElement && table.parentElement.classList.contains('table-wrap')) return;
346
- var wrapper = document.createElement('div');
347
- wrapper.className = 'table-wrap';
348
- table.parentNode.insertBefore(wrapper, table);
349
- wrapper.appendChild(table);
350
- });
351
-
352
- // ── TOC Generation ──
353
- function buildTOC() {
354
- var toc = document.querySelector('.toc-sidebar');
355
- if (!toc) return;
356
-
357
- var content = document.querySelector('.content');
358
- if (!content) return;
359
-
360
- var headings = content.querySelectorAll('h2, h3');
361
- if (headings.length < 2) {
362
- toc.style.display = 'none';
363
- return;
364
- }
365
-
366
- var label = document.createElement('div');
367
- label.className = 'toc-label';
368
- label.textContent = 'On this page';
369
- toc.appendChild(label);
370
-
371
- var list = document.createElement('nav');
372
- list.className = 'toc-list';
373
-
374
- var items = [];
375
- headings.forEach(function (h) {
376
- if (!h.id) {
377
- var text = (h.textContent || '')
378
- .toLowerCase()
379
- .replace(/[^a-z0-9\u0E00-\u0E7F]+/g, '-')
380
- .replace(/^-|-$/g, '');
381
- h.id = text || 'section-' + Math.random().toString(36).slice(2, 6);
382
- }
383
-
384
- var link = document.createElement('a');
385
- link.href = '#' + h.id;
386
- link.className = 'toc-link';
387
- if (h.tagName === 'H3') link.classList.add('toc-h3');
388
- link.textContent = h.textContent;
389
-
390
- list.appendChild(link);
391
- items.push({ el: link, id: h.id });
392
- });
393
-
394
- toc.appendChild(list);
395
-
396
- if (typeof IntersectionObserver !== 'undefined' && items.length > 0) {
397
- var observeTargets = [];
398
- headings.forEach(function (h) { observeTargets.push(h); });
399
-
400
- var observer = new IntersectionObserver(function (entries) {
401
- entries.forEach(function (entry) {
402
- if (entry.isIntersecting) {
403
- items.forEach(function (item) {
404
- item.el.classList.toggle('active', item.id === entry.target.id);
405
- });
406
- }
407
- });
408
- }, {
409
- rootMargin: '-64px 0px -60% 0px',
410
- threshold: 0
411
- });
412
-
413
- observeTargets.forEach(function (h) { observer.observe(h); });
414
- }
415
- }
416
-
417
- buildTOC();
418
-
419
- // ── Footer Injection ──
420
- function injectFooter() {
421
- var content = document.querySelector('.content');
422
- if (!content || content.querySelector('.footer')) return;
423
-
424
- var footer = document.createElement('div');
425
- footer.className = 'footer';
426
- footer.innerHTML =
427
- '<span>Clew Code \u2014 GPL-3.0</span>' +
428
- '<div class="footer-links">' +
429
- ' <a href="https://github.com/ClewCode/ClewCode">GitHub</a>' +
430
- ' <a href="https://github.com/ClewCode/ClewCode/issues">Issues</a>' +
431
- ' <a href="https://www.npmjs.com/package/clew-code">npm</a>' +
432
- '</div>';
433
- content.appendChild(footer);
434
- }
435
-
436
- injectFooter();
437
- })();
1
+ // Clew Docs — Mobile Nav, Header, Sidebar, TOC, Code Copy
2
+ (function () {
3
+ 'use strict';
4
+
5
+ // ── Root Prefix (for script location detection) ──
6
+ var rootPrefix = '';
7
+ var scripts = document.getElementsByTagName('script');
8
+ for (var i = 0; i < scripts.length; i++) {
9
+ var src = scripts[i].getAttribute('src');
10
+ if (src && src.indexOf('js/main.js') !== -1) {
11
+ rootPrefix = src.replace('js/main.js', '');
12
+ break;
13
+ }
14
+ }
15
+
16
+ // ── Header Injection ──
17
+ function injectHeader() {
18
+ var header = document.querySelector('.header');
19
+ if (!header) return;
20
+
21
+ var path = window.location.pathname;
22
+ var isThai = /\.th\.html$/.test(path);
23
+ var isIndex = /\/index(\.th)?\.html$/.test(path) || path === '/' || path.endsWith('/docs/');
24
+ var currentPage = path.split('/').pop() || 'index.html';
25
+
26
+ var logoHref = isThai ? 'index.th.html' : 'index.html';
27
+ var docsHref = isThai ? 'quick-start.th.html' : 'quick-start.html';
28
+ var ariaLabel = isThai ? '\u0E40\u0E1B\u0E34\u0E14/\u0E1B\u0E34\u0E14\u0E40\u0E21\u0E19\u0E39' : 'Toggle navigation';
29
+
30
+ // Language toggle
31
+ var langTarget = isThai
32
+ ? currentPage.replace(/\.th\.html$/, '.html')
33
+ : currentPage.replace(/\.html$/, '.th.html');
34
+ var langLabel = isThai ? 'EN' : '\u0E44\u0E17\u0E22';
35
+ // If no .html page exists for the target, just use README
36
+ if (isIndex) langTarget = isThai ? 'index.html' : 'index.th.html';
37
+
38
+ // Build breadcrumbs from path
39
+ var crumbs = [];
40
+ var parts = path.replace(/\/$/, '').split('/').filter(Boolean);
41
+ if (parts[0] === 'docs') parts.shift(); // remove leading "docs"
42
+ if (parts.length > 0) {
43
+ var crumbPath = '';
44
+ for (var i = 0; i < parts.length; i++) {
45
+ crumbPath += (i === 0 ? '' : '/') + parts[i];
46
+ var isLast = i === parts.length - 1;
47
+ var label = parts[i].replace(/\.th\.html$/, '').replace(/\.html$/, '').replace(/-/g, ' ');
48
+ if (isLast) {
49
+ crumbs.push('<span class="current">' + label + '</span>');
50
+ } else {
51
+ crumbs.push('<a href="' + crumbPath + '">' + label + '</a>');
52
+ crumbs.push('<span class="sep">/</span>');
53
+ }
54
+ }
55
+ }
56
+ var breadcrumbsHtml = crumbs.length > 0
57
+ ? '<nav class="header-breadcrumbs">' + crumbs.join('') + '</nav>'
58
+ : '';
59
+
60
+ header.innerHTML =
61
+ '<div class="header-inner">' +
62
+ ' <a href="' + logoHref + '" class="logo">Clew</a>' +
63
+ breadcrumbsHtml +
64
+ ' <div class="header-search">' +
65
+ ' <input type="text" id="headerSearchInput" placeholder="' + (isThai ? '\u0E04\u0E49\u0E19\u0E2B\u0E32\u0E40\u0E2D\u0E01\u0E2A\u0E32\u0E23...' : 'Search docs...') + '" autocomplete="off">' +
66
+ ' <span class="search-icon">\u2315</span>' +
67
+ ' <div class="search-results" id="headerSearchResults"></div>' +
68
+ ' </div>' +
69
+ ' <nav class="header-nav">' +
70
+ ' <a href="' + logoHref + '">' + (isThai ? '\u0E2B\u0E19\u0E49\u0E32\u0E41\u0E23\u0E01' : 'Home') + '</a>' +
71
+ ' <a href="' + docsHref + '">' + (isThai ? '\u0E40\u0E2D\u0E01\u0E2A\u0E32\u0E23' : 'Docs') + '</a>' +
72
+ ' <a href="https://github.com/JonusNattapong/ClewCode" target="_blank">GitHub</a>' +
73
+ ' </nav>' +
74
+ ' <button class="lang-toggle" id="langToggle" aria-label="Switch language">' + langLabel + '</button>' +
75
+ ' <button class="menu-btn" id="menuToggle" aria-label="' + ariaLabel + '"><span></span><span></span><span></span></button>' +
76
+ '</div>';
77
+
78
+ // Language toggle
79
+ var langToggle = document.getElementById('langToggle');
80
+ if (langToggle) {
81
+ langToggle.addEventListener('click', function () {
82
+ window.location.href = langTarget;
83
+ });
84
+ }
85
+
86
+ // Active nav link
87
+ var navLinks = header.querySelectorAll('.header-nav a');
88
+ navLinks.forEach(function (link) {
89
+ var href = link.getAttribute('href');
90
+ if (!href) return;
91
+ var hrefPage = href.split('/').pop().split('#')[0] || 'index.html';
92
+ if (hrefPage === currentPage) link.classList.add('active');
93
+ });
94
+ if (!isIndex) {
95
+ var docsLink = header.querySelector('.header-nav a[href*="quick-start"]');
96
+ if (docsLink) docsLink.classList.add('active');
97
+ }
98
+
99
+ // Search functionality
100
+ initHeaderSearch();
101
+ }
102
+
103
+ function initHeaderSearch() {
104
+ var input = document.getElementById('headerSearchInput');
105
+ var results = document.getElementById('headerSearchResults');
106
+ if (!input || !results) return;
107
+
108
+ // Build search index from sidebar links + TOC headings
109
+ var searchIndex = [];
110
+ document.querySelectorAll('.sidebar-link').forEach(function (link) {
111
+ searchIndex.push({ text: link.textContent.trim(), href: link.getAttribute('href'), type: 'page' });
112
+ });
113
+ document.querySelectorAll('.content h2, .content h3').forEach(function (h) {
114
+ searchIndex.push({ text: h.textContent.trim(), href: '#' + h.id, type: 'section' });
115
+ });
116
+
117
+ input.addEventListener('input', function () {
118
+ var query = this.value.trim().toLowerCase();
119
+ results.innerHTML = '';
120
+ results.classList.remove('open');
121
+ if (query.length < 1) return;
122
+
123
+ var matches = [];
124
+ for (var i = 0; i < searchIndex.length; i++) {
125
+ var item = searchIndex[i];
126
+ if (item.text.toLowerCase().indexOf(query) !== -1) {
127
+ matches.push(item);
128
+ }
129
+ }
130
+
131
+ if (matches.length === 0) {
132
+ results.innerHTML = '<div class="search-empty">No results found</div>';
133
+ results.classList.add('open');
134
+ return;
135
+ }
136
+
137
+ for (var j = 0; j < Math.min(matches.length, 8); j++) {
138
+ var m = matches[j];
139
+ var highlighted = m.text.replace(
140
+ new RegExp('(' + query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')', 'gi'),
141
+ '<mark>$1</mark>'
142
+ );
143
+ results.innerHTML +=
144
+ '<a href="' + m.href + '" class="search-result">' +
145
+ '<span class="search-type">' + (m.type === 'page' ? '\u{1F4C4}' : '#') + '</span> ' +
146
+ highlighted +
147
+ '</a>';
148
+ }
149
+ results.classList.add('open');
150
+ });
151
+
152
+ // Close on click outside
153
+ document.addEventListener('click', function (e) {
154
+ if (!input.contains(e.target) && !results.contains(e.target)) {
155
+ results.classList.remove('open');
156
+ }
157
+ });
158
+
159
+ // Close on Escape
160
+ input.addEventListener('keydown', function (e) {
161
+ if (e.key === 'Escape') {
162
+ results.classList.remove('open');
163
+ input.blur();
164
+ }
165
+ });
166
+ }
167
+
168
+ injectHeader();
169
+
170
+ // ── Sidebar Injection ──
171
+ var sidebar = document.getElementById('sidebar');
172
+ if (sidebar) {
173
+ sidebar.innerHTML =
174
+ '<div class="sidebar-section">' +
175
+ ' <div class="sidebar-label">Getting Started</div>' +
176
+ ' <nav>' +
177
+ ' <a href="' + rootPrefix + 'index.html" class="sidebar-link"><span class="link-icon"></span>Overview</a>' +
178
+ ' <a href="' + rootPrefix + 'quick-start.html" class="sidebar-link"><span class="link-icon"></span>Quick Start</a>' +
179
+ ' <a href="' + rootPrefix + 'installation.html" class="sidebar-link"><span class="link-icon"></span>Installation</a>' +
180
+ ' <a href="' + rootPrefix + 'configuration.html" class="sidebar-link"><span class="link-icon"></span>Configuration</a>' +
181
+ ' <a href="' + rootPrefix + 'cli-reference.html" class="sidebar-link"><span class="link-icon"></span>CLI Reference</a>' +
182
+ ' <a href="' + rootPrefix + 'troubleshooting.html" class="sidebar-link"><span class="link-icon"></span>Troubleshooting</a>' +
183
+ ' </nav>' +
184
+ '</div>' +
185
+ '<div class="sidebar-section">' +
186
+ ' <div class="sidebar-label">Core Concepts</div>' +
187
+ ' <nav>' +
188
+ ' <a href="' + rootPrefix + 'providers.html" class="sidebar-link"><span class="link-icon"></span>Providers</a>' +
189
+ ' <a href="' + rootPrefix + 'models.html" class="sidebar-link"><span class="link-icon"></span>Models</a>' +
190
+ ' <a href="' + rootPrefix + 'commands.html" class="sidebar-link"><span class="link-icon"></span>Commands</a>' +
191
+ ' <a href="' + rootPrefix + 'tools.html" class="sidebar-link"><span class="link-icon"></span>Tools</a>' +
192
+ ' <a href="' + rootPrefix + 'permission-model.html" class="sidebar-link"><span class="link-icon"></span>Permission Model</a>' +
193
+ ' <a href="' + rootPrefix + 'personal-profile.html" class="sidebar-link"><span class="link-icon"></span>Personal Profile</a>' +
194
+ ' </nav>' +
195
+ '</div>' +
196
+ '<div class="sidebar-section">' +
197
+ ' <div class="sidebar-label">Extending</div>' +
198
+ ' <nav>' +
199
+ ' <a href="' + rootPrefix + 'plugins.html" class="sidebar-link"><span class="link-icon"></span>Plugins</a>' +
200
+ ' <a href="' + rootPrefix + 'skills.html" class="sidebar-link"><span class="link-icon"></span>Skills</a>' +
201
+ ' <a href="' + rootPrefix + 'architecture.html" class="sidebar-link"><span class="link-icon"></span>Architecture</a>' +
202
+ ' <a href="' + rootPrefix + 'mcp.html" class="sidebar-link"><span class="link-icon"></span>MCP</a>' +
203
+ ' </nav>' +
204
+ '</div>' +
205
+ '<div class="sidebar-section">' +
206
+ ' <div class="sidebar-label">Autonomous</div>' +
207
+ ' <nav>' +
208
+ ' <a href="' + rootPrefix + 'daemon.html" class="sidebar-link"><span class="link-icon"></span>Daemon Mode</a>' +
209
+ ' </nav>' +
210
+ '</div>' +
211
+ '<div class="sidebar-section">' +
212
+ ' <div class="sidebar-label">Features</div>' +
213
+ ' <nav>' +
214
+ ' <a href="' + rootPrefix + 'research-memory.html" class="sidebar-link"><span class="link-icon"></span>Research & Memory</a>' +
215
+ ' <a href="' + rootPrefix + 'features/searxng-search.html" class="sidebar-link"><span class="link-icon"></span>SearXNG Search</a>' +
216
+ ' <a href="' + rootPrefix + 'features/bridge-mode.html" class="sidebar-link"><span class="link-icon"></span>Bridge Mode</a>' +
217
+ ' <a href="' + rootPrefix + 'features/evals.html" class="sidebar-link"><span class="link-icon"></span>Evaluation Harness</a>' +
218
+ ' <a href="' + rootPrefix + 'features/sentry-setup.html" class="sidebar-link"><span class="link-icon"></span>Sentry Setup</a>' +
219
+ ' <a href="' + rootPrefix + 'voice-mode.html" class="sidebar-link"><span class="link-icon"></span>Voice Mode</a>' +
220
+ ' <a href="' + rootPrefix + 'swarm.html" class="sidebar-link"><span class="link-icon"></span>Swarm System</a>' +
221
+ ' <a href="' + rootPrefix + 'loop.html" class="sidebar-link"><span class="link-icon"></span>Agent Loop</a>' +
222
+ ' </nav>' +
223
+ '</div>' +
224
+ '<div class="sidebar-section">' +
225
+ ' <div class="sidebar-label">Internals</div>' +
226
+ ' <nav>' +
227
+ ' <a href="' + rootPrefix + 'internals/hidden-features.html" class="sidebar-link"><span class="link-icon"></span>Hidden Features</a>' +
228
+ ' <a href="' + rootPrefix + 'internals/growthbook-ab-testing.html" class="sidebar-link"><span class="link-icon"></span>A/B Testing</a>' +
229
+ ' </nav>' +
230
+ '</div>' +
231
+ '<div class="sidebar-section">' +
232
+ ' <div class="sidebar-label">Community</div>' +
233
+ ' <nav>' +
234
+ ' <a href="' + rootPrefix + 'changelog.html" class="sidebar-link"><span class="link-icon"></span>Changelog</a>' +
235
+ ' <a href="' + rootPrefix + 'security.html" class="sidebar-link"><span class="link-icon"></span>Security</a>' +
236
+ ' <a href="' + rootPrefix + 'contributing.html" class="sidebar-link"><span class="link-icon"></span>Contributing</a>' +
237
+ ' </nav>' +
238
+ '</div>';
239
+ }
240
+
241
+ // ── Mobile Nav ──
242
+ var menuBtn = document.getElementById('menuToggle');
243
+ var overlay = document.getElementById('sidebarOverlay');
244
+
245
+ function openSidebar() {
246
+ sidebar && sidebar.classList.add('open');
247
+ menuBtn && menuBtn.setAttribute('aria-expanded', 'true');
248
+ overlay && overlay.classList.add('open');
249
+ document.body.style.overflow = 'hidden';
250
+ }
251
+
252
+ function closeSidebar() {
253
+ sidebar && sidebar.classList.remove('open');
254
+ menuBtn && menuBtn.setAttribute('aria-expanded', 'false');
255
+ overlay && overlay.classList.remove('open');
256
+ document.body.style.overflow = '';
257
+ }
258
+
259
+ if (menuBtn) menuBtn.addEventListener('click', function (e) {
260
+ e.stopPropagation();
261
+ sidebar && sidebar.classList.contains('open') ? closeSidebar() : openSidebar();
262
+ });
263
+
264
+ if (overlay) overlay.addEventListener('click', closeSidebar);
265
+
266
+ document.addEventListener('keydown', function (e) {
267
+ if (e.key === 'Escape' && sidebar && sidebar.classList.contains('open')) closeSidebar();
268
+ });
269
+
270
+ if (sidebar) {
271
+ sidebar.querySelectorAll('.sidebar-link').forEach(function (link) {
272
+ link.addEventListener('click', closeSidebar);
273
+ });
274
+ }
275
+
276
+ // ── Active Sidebar Link ──
277
+ var currentPath = window.location.pathname;
278
+ var currentPage = currentPath.split('/').pop() || 'index.html';
279
+ if (currentPage === '') currentPage = 'index.html';
280
+
281
+ document.querySelectorAll('.sidebar-link').forEach(function (link) {
282
+ var href = link.getAttribute('href');
283
+ if (!href) return;
284
+ var hrefPage = href.split('/').pop().split('#')[0];
285
+ if (hrefPage === currentPage) link.classList.add('active');
286
+ });
287
+
288
+ // ── Code Copy Buttons ──
289
+ function addCopyButtons() {
290
+ document.querySelectorAll('.content pre').forEach(function (pre) {
291
+ if (pre.parentElement && pre.parentElement.classList.contains('code-block-wrap')) return;
292
+
293
+ var wrap = document.createElement('div');
294
+ wrap.className = 'code-block-wrap';
295
+
296
+ var header = document.createElement('div');
297
+ header.className = 'code-block-header';
298
+
299
+ var lang = document.createElement('span');
300
+ var code = pre.querySelector('code');
301
+ var langName = '';
302
+ if (code) {
303
+ var cls = code.className || '';
304
+ var match = cls.match(/language-(\w+)/);
305
+ if (match) langName = match[1];
306
+ }
307
+ lang.textContent = langName || '';
308
+ lang.style.textTransform = 'lowercase';
309
+
310
+ var btn = document.createElement('button');
311
+ btn.className = 'copy-btn';
312
+ btn.textContent = 'Copy';
313
+ btn.setAttribute('aria-label', 'Copy code to clipboard');
314
+
315
+ btn.addEventListener('click', function () {
316
+ var text = pre.textContent || '';
317
+ text = text.replace(/^\n+|\n+$/g, '');
318
+ navigator.clipboard.writeText(text).then(function () {
319
+ btn.textContent = 'Copied!';
320
+ btn.classList.add('copied');
321
+ setTimeout(function () {
322
+ btn.textContent = 'Copy';
323
+ btn.classList.remove('copied');
324
+ }, 2000);
325
+ }).catch(function () {
326
+ btn.textContent = 'Failed';
327
+ setTimeout(function () {
328
+ btn.textContent = 'Copy';
329
+ }, 2000);
330
+ });
331
+ });
332
+
333
+ header.appendChild(lang);
334
+ header.appendChild(btn);
335
+
336
+ pre.parentNode.insertBefore(wrap, pre);
337
+ wrap.appendChild(header);
338
+ wrap.appendChild(pre);
339
+ });
340
+ }
341
+
342
+ addCopyButtons();
343
+
344
+ // ── Table Wrapping ──
345
+ document.querySelectorAll('.content table').forEach(function (table) {
346
+ if (table.parentElement && table.parentElement.classList.contains('table-wrap')) return;
347
+ var wrapper = document.createElement('div');
348
+ wrapper.className = 'table-wrap';
349
+ table.parentNode.insertBefore(wrapper, table);
350
+ wrapper.appendChild(table);
351
+ });
352
+
353
+ // ── TOC Generation ──
354
+ function buildTOC() {
355
+ var toc = document.querySelector('.toc-sidebar');
356
+ if (!toc) return;
357
+
358
+ var content = document.querySelector('.content');
359
+ if (!content) return;
360
+
361
+ var headings = content.querySelectorAll('h2, h3');
362
+ if (headings.length < 2) {
363
+ toc.style.display = 'none';
364
+ return;
365
+ }
366
+
367
+ var label = document.createElement('div');
368
+ label.className = 'toc-label';
369
+ label.textContent = 'On this page';
370
+ toc.appendChild(label);
371
+
372
+ var list = document.createElement('nav');
373
+ list.className = 'toc-list';
374
+
375
+ var items = [];
376
+ headings.forEach(function (h) {
377
+ if (!h.id) {
378
+ var text = (h.textContent || '')
379
+ .toLowerCase()
380
+ .replace(/[^a-z0-9\u0E00-\u0E7F]+/g, '-')
381
+ .replace(/^-|-$/g, '');
382
+ h.id = text || 'section-' + Math.random().toString(36).slice(2, 6);
383
+ }
384
+
385
+ var link = document.createElement('a');
386
+ link.href = '#' + h.id;
387
+ link.className = 'toc-link';
388
+ if (h.tagName === 'H3') link.classList.add('toc-h3');
389
+ link.textContent = h.textContent;
390
+
391
+ list.appendChild(link);
392
+ items.push({ el: link, id: h.id });
393
+ });
394
+
395
+ toc.appendChild(list);
396
+
397
+ if (typeof IntersectionObserver !== 'undefined' && items.length > 0) {
398
+ var observeTargets = [];
399
+ headings.forEach(function (h) { observeTargets.push(h); });
400
+
401
+ var observer = new IntersectionObserver(function (entries) {
402
+ entries.forEach(function (entry) {
403
+ if (entry.isIntersecting) {
404
+ items.forEach(function (item) {
405
+ item.el.classList.toggle('active', item.id === entry.target.id);
406
+ });
407
+ }
408
+ });
409
+ }, {
410
+ rootMargin: '-64px 0px -60% 0px',
411
+ threshold: 0
412
+ });
413
+
414
+ observeTargets.forEach(function (h) { observer.observe(h); });
415
+ }
416
+ }
417
+
418
+ buildTOC();
419
+
420
+ // ── Footer Injection ──
421
+ function injectFooter() {
422
+ var content = document.querySelector('.content');
423
+ if (!content || content.querySelector('.footer')) return;
424
+
425
+ var footer = document.createElement('div');
426
+ footer.className = 'footer';
427
+ footer.innerHTML =
428
+ '<span>Clew Code \u2014 GPL-3.0</span>' +
429
+ '<div class="footer-links">' +
430
+ ' <a href="https://github.com/ClewCode/ClewCode">GitHub</a>' +
431
+ ' <a href="https://github.com/ClewCode/ClewCode/issues">Issues</a>' +
432
+ ' <a href="https://www.npmjs.com/package/clew-code">npm</a>' +
433
+ '</div>';
434
+ content.appendChild(footer);
435
+ }
436
+
437
+ injectFooter();
438
+ })();