ape-claw 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/.cursor/skills/ape-claw/SKILL.md +322 -0
  2. package/LICENSE +21 -0
  3. package/README.md +826 -0
  4. package/allowlists/opensea-slug-overrides.json +13 -0
  5. package/allowlists/recommended.apechain.json +322 -0
  6. package/config/clawbots.example.json +3 -0
  7. package/config/policy.example.json +27 -0
  8. package/data/starter-pack-bundle.json +1 -0
  9. package/data/starter-pack.json +495 -0
  10. package/docs/ACP_BOUNTIES.md +108 -0
  11. package/docs/APECLAW_V2_ALPHA.md +206 -0
  12. package/docs/AUTONOMY_AND_SUBSTRATE.md +69 -0
  13. package/docs/CLAWBOTS_AND_INVITES.md +102 -0
  14. package/docs/CLI_GUIDE.md +124 -0
  15. package/docs/CONTRIBUTING.md +130 -0
  16. package/docs/DASHBOARD_GUIDE.md +108 -0
  17. package/docs/GLOBAL_BACKEND.md +145 -0
  18. package/docs/ONCHAIN_V2_GUIDE.md +140 -0
  19. package/docs/PRODUCT_OVERVIEW.md +127 -0
  20. package/docs/README.md +40 -0
  21. package/docs/SKILLCARDS_AND_IMPORTER.md +147 -0
  22. package/docs/STARTER_PACK.md +297 -0
  23. package/docs/SUPPORTED_NETWORKS.md +58 -0
  24. package/docs/TELEMETRY_AND_EVENTS.md +103 -0
  25. package/docs/THE_POD_RUNNER.md +198 -0
  26. package/docs/V1_WORKFLOWS.md +108 -0
  27. package/docs/V2_ONCHAIN_SKILLS.md +157 -0
  28. package/docs/WEB4_PLAN_STATUS.md +95 -0
  29. package/docs/WEB4_SWARM_MODEL.md +104 -0
  30. package/docs/archive/AUTONOMY_AND_SUBSTRATE.md +66 -0
  31. package/docs/archive/WEB4_PLAN_STATUS.md +93 -0
  32. package/docs/archive/WEB4_SWARM_MODEL.md +98 -0
  33. package/docs/developer/01-architecture.md +345 -0
  34. package/docs/developer/02-contracts.md +1034 -0
  35. package/docs/developer/03-writing-modules.md +513 -0
  36. package/docs/developer/04-skillcard-spec.md +336 -0
  37. package/docs/developer/05-backend-api.md +1079 -0
  38. package/docs/developer/06-telemetry.md +798 -0
  39. package/docs/developer/07-testing.md +546 -0
  40. package/docs/developer/08-contributing.md +211 -0
  41. package/docs/operator/01-quickstart.md +49 -0
  42. package/docs/operator/02-dashboard.md +174 -0
  43. package/docs/operator/03-cli-reference.md +818 -0
  44. package/docs/operator/04-skills-library.md +169 -0
  45. package/docs/operator/05-pod-operations.md +314 -0
  46. package/docs/operator/06-deployment.md +299 -0
  47. package/docs/operator/07-safety-and-policy.md +311 -0
  48. package/docs/operator/08-troubleshooting.md +457 -0
  49. package/docs/operator/09-env-reference.md +238 -0
  50. package/docs/social/STARTER_PACK_THREAD.md +209 -0
  51. package/package.json +77 -0
  52. package/skillcards/import-sources.json +93 -0
  53. package/skillcards/seed/acp-bounty-poll.v1.json +38 -0
  54. package/skillcards/seed/acp-bounty-post.v1.json +55 -0
  55. package/skillcards/seed/acp-browse.v1.json +41 -0
  56. package/skillcards/seed/acp-fulfill-and-route.v1.json +56 -0
  57. package/skillcards/seed/apeclaw-bridge-relay.v1.json +46 -0
  58. package/skillcards/seed/apeclaw-nft-autobuy.v1.json +60 -0
  59. package/skillcards/seed/apeclaw-receipt-recorder.v1.json +64 -0
  60. package/skillcards/seed/humanizer.v1.json +74 -0
  61. package/skillcards/seed/otherside-navigator.v1.json +116 -0
  62. package/skillcards/seed/stonkbrokers-launcher.v1.json +280 -0
  63. package/skillcards/seed/walkie-p2p.v1.json +66 -0
  64. package/src/cli/index.mjs +8 -0
  65. package/src/cli.mjs +1929 -0
  66. package/src/lib/bridge-relay.mjs +294 -0
  67. package/src/lib/clawbots.mjs +94 -0
  68. package/src/lib/io.mjs +36 -0
  69. package/src/lib/market.mjs +233 -0
  70. package/src/lib/nft-opensea.mjs +159 -0
  71. package/src/lib/paths.mjs +17 -0
  72. package/src/lib/pod-init.mjs +40 -0
  73. package/src/lib/policy.mjs +112 -0
  74. package/src/lib/rpc.mjs +49 -0
  75. package/src/lib/telemetry.mjs +92 -0
  76. package/src/lib/v2-onchain-abi.mjs +294 -0
  77. package/src/lib/v2-skillcard.mjs +27 -0
  78. package/src/server/index.mjs +169 -0
  79. package/src/server/logger.mjs +21 -0
  80. package/src/server/middleware/auth.mjs +90 -0
  81. package/src/server/middleware/body-limit.mjs +35 -0
  82. package/src/server/middleware/cors.mjs +33 -0
  83. package/src/server/middleware/rate-limit.mjs +44 -0
  84. package/src/server/routes/chat.mjs +178 -0
  85. package/src/server/routes/clawbots.mjs +182 -0
  86. package/src/server/routes/events.mjs +95 -0
  87. package/src/server/routes/health.mjs +72 -0
  88. package/src/server/routes/pod.mjs +64 -0
  89. package/src/server/routes/quotes.mjs +161 -0
  90. package/src/server/routes/skills.mjs +239 -0
  91. package/src/server/routes/static.mjs +161 -0
  92. package/src/server/routes/v2.mjs +48 -0
  93. package/src/server/sse.mjs +73 -0
  94. package/src/server/storage/file-backend.mjs +295 -0
  95. package/src/server/storage/index.mjs +37 -0
  96. package/src/server/storage/sqlite-backend.mjs +380 -0
  97. package/src/telemetry-server.mjs +1604 -0
  98. package/ui/css/dashboard.css +792 -0
  99. package/ui/css/skills.css +689 -0
  100. package/ui/docs.html +840 -0
  101. package/ui/favicon-180.png +0 -0
  102. package/ui/favicon-192.png +0 -0
  103. package/ui/favicon-32.png +0 -0
  104. package/ui/favicon-lobster.png +0 -0
  105. package/ui/favicon.svg +10 -0
  106. package/ui/index.html +2957 -0
  107. package/ui/js/dashboard.js +1766 -0
  108. package/ui/js/skills.js +1621 -0
  109. package/ui/pod.html +909 -0
  110. package/ui/shared/motion.css +286 -0
  111. package/ui/shared/motion.js +170 -0
  112. package/ui/shared/sidebar-nav.css +379 -0
  113. package/ui/shared/sidebar-nav.js +137 -0
  114. package/ui/skills.html +2879 -0
@@ -0,0 +1,379 @@
1
+ :root{
2
+ --sb-z-menu:60;
3
+ --sb-z-backdrop:49;
4
+ --sb-side-w:240px;
5
+ --sb-side-collapsed:56px;
6
+ --sb-side-bg: rgba(9,13,18,0.94);
7
+ --sb-side-border: var(--panel-border, rgba(99,215,255,.25));
8
+ --sb-side-fg: #d4e6fa;
9
+ --sb-side-muted: var(--muted, rgba(212,230,250,.65));
10
+ --sb-accent: var(--amber, rgba(207,255,4,1));
11
+ --sb-accent2: var(--cyan, rgba(99,215,255,.9));
12
+ }
13
+
14
+ /* ── Hamburger (mobile) ───────────────────────────────────────────── */
15
+ .sb-menu-btn{
16
+ position:fixed;
17
+ top:12px;
18
+ left:12px;
19
+ z-index:var(--sb-z-menu);
20
+ width:38px;
21
+ height:38px;
22
+ display:flex;
23
+ align-items:center;
24
+ justify-content:center;
25
+ border-radius:2px;
26
+ background: rgba(9,13,18,0.65);
27
+ border:1px solid var(--sb-side-border);
28
+ color:var(--sb-side-fg);
29
+ box-shadow: 0 10px 30px rgba(0,0,0,0.35), inset 0 0 0 1px rgba(15,29,44,0.9);
30
+ cursor:pointer;
31
+ transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease;
32
+ }
33
+ .sb-menu-btn:hover{ transform: translateY(-1px); border-color: var(--sb-accent2); box-shadow: 0 12px 36px rgba(0,0,0,0.45), 0 0 0 2px rgba(99,215,255,.10); }
34
+ .sb-menu-btn:active{ transform: translateY(0px) scale(0.98); }
35
+ .sb-menu-btn svg{ display:block }
36
+
37
+ /* ── Backdrop (mobile) ────────────────────────────────────────────── */
38
+ .sb-backdrop{
39
+ position:fixed;
40
+ inset:0;
41
+ z-index:var(--sb-z-backdrop);
42
+ background: rgba(0,0,0,0);
43
+ opacity:0;
44
+ pointer-events:none;
45
+ transition: opacity .25s ease, background .25s ease;
46
+ }
47
+ .sb-backdrop[data-open="1"]{
48
+ opacity:1;
49
+ pointer-events:auto;
50
+ background: rgba(0,0,0,0.70);
51
+ backdrop-filter: blur(6px);
52
+ }
53
+
54
+ /* ── Sidebar shell ────────────────────────────────────────────────── */
55
+ .sb-sidebar{
56
+ position:fixed;
57
+ top:0;
58
+ left:0;
59
+ bottom:0;
60
+ z-index:calc(var(--sb-z-menu) - 5);
61
+ width:var(--sb-side-w);
62
+ transform: translateX(-102%);
63
+ transition: transform .30s cubic-bezier(.4,0,.2,1), width .25s ease;
64
+ background: var(--sb-side-bg);
65
+ border-right:1px solid var(--sb-side-border);
66
+ overflow:hidden;
67
+ }
68
+ .sb-sidebar[data-open="1"]{ transform: translateX(0); }
69
+
70
+ .sb-inner{
71
+ height:100%;
72
+ display:flex;
73
+ flex-direction:column;
74
+ }
75
+
76
+ .sb-brand{
77
+ display:flex;
78
+ align-items:center;
79
+ gap:10px;
80
+ padding:14px 14px 12px;
81
+ border-bottom:1px dashed rgba(99,215,255,.22);
82
+ animation: sb-breathe 4s ease-in-out infinite;
83
+ }
84
+ @keyframes sb-breathe {
85
+ 0%, 100% { filter: brightness(1); }
86
+ 50% { filter: brightness(1.15) drop-shadow(0 0 6px rgba(207,255,4,0.15)); }
87
+ }
88
+ .sb-mark{
89
+ width:30px;height:30px;
90
+ flex-shrink:0;
91
+ display:flex;align-items:center;justify-content:center;
92
+ border:1px solid rgba(207,255,4,.3);
93
+ background: rgba(9,13,18,0.6);
94
+ border-radius:4px;
95
+ position:relative;
96
+ box-shadow: 0 0 12px rgba(207,255,4,.08), inset 0 0 0 1px rgba(15,29,44,0.9);
97
+ transition: border-color .3s, box-shadow .3s, width .25s ease, height .25s ease;
98
+ }
99
+ .sb-mark:hover{
100
+ border-color:rgba(207,255,4,.5);
101
+ box-shadow: 0 0 20px rgba(207,255,4,.15), inset 0 0 0 1px rgba(15,29,44,0.9);
102
+ }
103
+ .sb-mark svg{
104
+ width:18px;height:18px;
105
+ color:var(--sb-accent);
106
+ filter:drop-shadow(0 0 4px rgba(207,255,4,.3));
107
+ transition: width .25s ease, height .25s ease;
108
+ }
109
+ .sb-brand strong{
110
+ font-size:12px;
111
+ letter-spacing:.10em;
112
+ text-transform:uppercase;
113
+ color: var(--sb-accent);
114
+ }
115
+ .sb-brand span{
116
+ display:block;
117
+ margin-top:2px;
118
+ font-size:11px;
119
+ color: var(--sb-side-muted);
120
+ }
121
+
122
+ .sb-nav{
123
+ padding:10px;
124
+ display:flex;
125
+ flex-direction:column;
126
+ gap:6px;
127
+ flex:1;
128
+ }
129
+ .sb-link{
130
+ display:flex;
131
+ align-items:center;
132
+ gap:10px;
133
+ padding:10px 10px;
134
+ border-radius:2px;
135
+ color: var(--sb-side-fg);
136
+ text-decoration:none;
137
+ border:1px solid rgba(99,215,255,.14);
138
+ background: rgba(11,22,34,0.35);
139
+ transition: border-color .2s ease, background .2s ease, transform .2s ease, box-shadow .2s ease;
140
+ position: relative;
141
+ overflow: hidden;
142
+ }
143
+ .sb-link::after {
144
+ content: '';
145
+ position: absolute;
146
+ inset: 0;
147
+ background: linear-gradient(90deg, rgba(207,255,4,0.04), transparent);
148
+ opacity: 0;
149
+ transition: opacity 0.25s;
150
+ pointer-events: none;
151
+ }
152
+ .sb-link:hover::after {
153
+ opacity: 1;
154
+ }
155
+ .sb-link:hover{
156
+ transform: translateX(2px);
157
+ border-color: rgba(99,215,255,.32);
158
+ background: rgba(11,22,34,0.60);
159
+ box-shadow: 0 2px 12px rgba(0,0,0,0.2);
160
+ }
161
+ .sb-link:active {
162
+ transform: translateX(2px) scale(0.98);
163
+ }
164
+ .sb-link[aria-current="page"]{
165
+ border-color: rgba(207,255,4,.32);
166
+ box-shadow: 0 0 0 2px rgba(207,255,4,.07);
167
+ background: rgba(207,255,4,0.04);
168
+ }
169
+ .sb-link[aria-current="page"]::before {
170
+ content: '';
171
+ position: absolute;
172
+ left: 10px;
173
+ top: 50%;
174
+ transform: translateY(-50%);
175
+ width: 6px;
176
+ height: 6px;
177
+ border-radius: 50%;
178
+ background: var(--accent, #cff004);
179
+ animation: sb-pulse 2s ease-in-out infinite;
180
+ }
181
+ @keyframes sb-pulse {
182
+ 0%, 100% { opacity: 1; box-shadow: 0 0 4px var(--accent, #cff004); }
183
+ 50% { opacity: 0.4; box-shadow: 0 0 8px var(--accent, #cff004); }
184
+ }
185
+ .sb-ico{
186
+ width:18px;height:18px;
187
+ flex-shrink:0;
188
+ color: rgba(212,230,250,.88);
189
+ transition: color .2s;
190
+ }
191
+ .sb-link:hover .sb-ico{ color:#fff; }
192
+ .sb-link[aria-current="page"] .sb-ico{ color: var(--sb-accent); }
193
+ .sb-text{
194
+ font-weight:800;
195
+ font-size:12px;
196
+ letter-spacing:.06em;
197
+ text-transform:uppercase;
198
+ }
199
+ .sb-sub{
200
+ margin-left:auto;
201
+ font-size:11px;
202
+ color: var(--sb-side-muted);
203
+ }
204
+
205
+ .sb-footer{
206
+ margin-top:auto;
207
+ padding:12px 12px 14px;
208
+ border-top:1px dashed rgba(99,215,255,.22);
209
+ color: var(--sb-side-muted);
210
+ font-size:11px;
211
+ line-height:1.35;
212
+ }
213
+ .sb-footer a{ color: rgba(99,215,255,.9); text-decoration:none; }
214
+ .sb-footer a:hover{ text-decoration:underline; }
215
+
216
+ .sb-powered{
217
+ display:flex;
218
+ align-items:center;
219
+ gap:6px;
220
+ margin-bottom:8px;
221
+ }
222
+ .sb-powered-label{
223
+ font-size:9px;
224
+ text-transform:uppercase;
225
+ letter-spacing:.1em;
226
+ color: rgba(212,230,250,.4);
227
+ }
228
+ .sb-powered-link{
229
+ display:inline-flex;
230
+ align-items:center;
231
+ gap:5px;
232
+ font-weight:700;
233
+ font-size:11px;
234
+ letter-spacing:.04em;
235
+ color: var(--sb-accent) !important;
236
+ transition: text-shadow .2s;
237
+ }
238
+ .sb-powered-link:hover{
239
+ text-decoration:none !important;
240
+ text-shadow: 0 0 8px rgba(207,255,4,.4);
241
+ }
242
+ .sb-powered-logo{
243
+ width:16px;
244
+ height:16px;
245
+ color: var(--sb-accent);
246
+ filter: drop-shadow(0 0 4px rgba(207,255,4,.25));
247
+ }
248
+ .sb-footer-links{
249
+ display:flex;
250
+ gap:12px;
251
+ flex-wrap:wrap;
252
+ }
253
+ .sb-footer-links a{
254
+ display:inline-flex;
255
+ align-items:center;
256
+ gap:4px;
257
+ font-size:10px;
258
+ color: var(--sb-side-muted) !important;
259
+ transition: color .2s;
260
+ }
261
+ .sb-footer-links a:hover{
262
+ color: var(--sb-accent2) !important;
263
+ text-decoration:none !important;
264
+ }
265
+ .sb-footer-links svg{
266
+ opacity:.7;
267
+ transition: opacity .2s;
268
+ }
269
+ .sb-footer-links a:hover svg{
270
+ opacity:1;
271
+ }
272
+
273
+ /* Desktop: always show a slim rail that expands on hover (stonkbrokers-style). */
274
+ @media (min-width: 980px){
275
+ .sb-menu-btn{ display:none; }
276
+ .sb-backdrop{ display:none; }
277
+ .sb-sidebar{
278
+ transform: translateX(0);
279
+ width: var(--sb-side-collapsed);
280
+ transition: width .28s cubic-bezier(.4,0,.2,1);
281
+ }
282
+ .sb-sidebar:hover{ width: var(--sb-side-w); }
283
+ .sb-inner{ overflow-y:auto; overflow-x:hidden; }
284
+
285
+ /* Collapsed: center icons, hide everything else */
286
+ .sb-nav{ padding:8px 4px; }
287
+ .sb-link{
288
+ justify-content:center;
289
+ gap:0;
290
+ padding:12px 0;
291
+ border-color:transparent;
292
+ background:transparent;
293
+ overflow:hidden;
294
+ border-radius:6px;
295
+ }
296
+ .sb-link:hover{ background:rgba(207,255,4,.06); border-color:rgba(207,255,4,.12); }
297
+ .sb-link[aria-current="page"]{ border-color:rgba(207,255,4,.22); background:rgba(207,255,4,.08); }
298
+ .sb-link[aria-current="page"]::before{ left:50%; transform:translate(-50%,-50%); top:4px; width:4px; height:4px; }
299
+ .sb-ico{ width:20px; height:20px; }
300
+ .sb-text, .sb-sub{
301
+ display:none;
302
+ }
303
+ .sb-brand{ justify-content:center; padding:12px 4px 10px; gap:0; }
304
+ .sb-brand .sb-brand-text{
305
+ display:none;
306
+ }
307
+ .sb-mark{ width:36px; height:36px; }
308
+ .sb-mark svg{ width:20px; height:20px; }
309
+ .sb-footer, .sb-powered, .sb-footer-links{
310
+ opacity:0; overflow:hidden; max-height:0; padding:0;
311
+ transition: opacity .2s ease, max-height .25s ease, padding .25s ease;
312
+ }
313
+
314
+ /* Expanded (hover): restore everything */
315
+ .sb-sidebar:hover .sb-nav{ padding:10px; }
316
+ .sb-sidebar:hover .sb-link{
317
+ justify-content:flex-start;
318
+ gap:10px;
319
+ padding:10px 10px;
320
+ border-color:rgba(99,215,255,.14);
321
+ background:rgba(11,22,34,0.35);
322
+ border-radius:2px;
323
+ }
324
+ .sb-sidebar:hover .sb-link:hover{
325
+ border-color:rgba(99,215,255,.32);
326
+ background:rgba(11,22,34,0.60);
327
+ }
328
+ .sb-sidebar:hover .sb-link[aria-current="page"]{
329
+ border-color:rgba(207,255,4,.32);
330
+ }
331
+ .sb-sidebar:hover .sb-link[aria-current="page"]::before{
332
+ left:10px; transform:translateY(-50%); top:50%; width:6px; height:6px;
333
+ }
334
+ .sb-sidebar:hover .sb-ico{ width:18px; height:18px; }
335
+ .sb-sidebar:hover .sb-text,
336
+ .sb-sidebar:hover .sb-sub{ display:inline; }
337
+ .sb-sidebar:hover .sb-brand{ justify-content:flex-start; gap:10px; padding:14px 14px 12px; }
338
+ .sb-sidebar:hover .sb-brand .sb-brand-text{ display:block; }
339
+ .sb-sidebar:hover .sb-mark{ width:30px; height:30px; }
340
+ .sb-sidebar:hover .sb-footer{ opacity:1; max-height:120px; padding:12px 12px 14px; }
341
+ .sb-sidebar:hover .sb-powered{ opacity:1; max-height:60px; }
342
+ .sb-sidebar:hover .sb-footer-links{ opacity:1; max-height:60px; }
343
+ }
344
+
345
+ /* Desktop collapsed: show tooltip on icon hover */
346
+ @media (min-width: 980px){
347
+ .sb-sidebar:not(:hover) .sb-link{
348
+ position:relative;
349
+ }
350
+ .sb-sidebar:not(:hover) .sb-link:hover::after{
351
+ content:attr(data-tip);
352
+ position:absolute;
353
+ left:calc(100% + 8px);
354
+ top:50%;
355
+ transform:translateY(-50%);
356
+ padding:5px 10px;
357
+ background:rgba(9,13,18,.95);
358
+ border:1px solid rgba(207,255,4,.2);
359
+ border-radius:4px;
360
+ color:#e6e6e6;
361
+ font-size:11px;
362
+ font-weight:700;
363
+ letter-spacing:.04em;
364
+ text-transform:uppercase;
365
+ white-space:nowrap;
366
+ z-index:100;
367
+ pointer-events:none;
368
+ box-shadow:0 4px 16px rgba(0,0,0,.4);
369
+ }
370
+ }
371
+
372
+ /* Page content spacing when sidebar is present on desktop.
373
+ Applied to body so .wrap { margin:0 auto } centering is preserved. */
374
+ @media (min-width: 980px){
375
+ body[data-has-sidebar="1"]{
376
+ margin-left: var(--sb-side-collapsed);
377
+ }
378
+ }
379
+
@@ -0,0 +1,137 @@
1
+ /* Minimal stonk-style sidebar for static pages (no framework). */
2
+ (function () {
3
+ function el(id) { return document.getElementById(id); }
4
+ function q(sel) { return document.querySelector(sel); }
5
+
6
+ var mount = el("sbNavMount");
7
+ if (!mount) return;
8
+
9
+ var links = [
10
+ { href: "/", label: "Home", icon: "home" },
11
+ { href: "/ui", label: "Dashboard", icon: "grid" },
12
+ { href: "/pod", label: "THE POD", icon: "pod" },
13
+ { href: "/skills", label: "Skills", icon: "skills" },
14
+ { href: "/docs", label: "Docs", icon: "docs" },
15
+ { href: "https://x.com/ClutchMarkets", label: "ClutchMarkets", icon: "x", external: true },
16
+ { href: "https://github.com/simplefarmer69/ape-claw", label: "GitHub", icon: "github", external: true },
17
+ { href: "https://openclaw.ai", label: "OpenClaw", icon: "claw", external: true },
18
+ ];
19
+
20
+ function iconSvg(kind) {
21
+ var s = '<svg class="sb-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">';
22
+ if (kind === "home") return s + '<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>';
23
+ if (kind === "grid") return s + '<rect x="3" y="3" width="8" height="8" rx="1"/><rect x="13" y="3" width="8" height="8" rx="1"/><rect x="3" y="13" width="8" height="8" rx="1"/><rect x="13" y="13" width="8" height="8" rx="1"/></svg>';
24
+ if (kind === "pod") return s + '<circle cx="12" cy="12" r="3"/><path d="M12 1v4"/><path d="M12 19v4"/><path d="M4.22 4.22l2.83 2.83"/><path d="M16.95 16.95l2.83 2.83"/><path d="M1 12h4"/><path d="M19 12h4"/><path d="M4.22 19.78l2.83-2.83"/><path d="M16.95 7.05l2.83-2.83"/></svg>';
25
+ if (kind === "skills") return s + '<path d="M12 2l9 5-9 5-9-5 9-5z"/><path d="M3 12l9 5 9-5"/><path d="M3 17l9 5 9-5"/></svg>';
26
+ if (kind === "docs") return s + '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>';
27
+ if (kind === "x") return '<svg class="sb-ico" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>';
28
+ if (kind === "github") return '<svg class="sb-ico" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z"/></svg>';
29
+ if (kind === "claw") return s + '<path d="M7.5 4.27l-.89 2.22a2 2 0 0 1-1.17 1.17L3.22 8.55a.5.5 0 0 0 0 .9l2.22.89a2 2 0 0 1 1.17 1.17l.89 2.22a.5.5 0 0 0 .9 0l.89-2.22a2 2 0 0 1 1.17-1.17l2.22-.89a.5.5 0 0 0 0-.9l-2.22-.89a2 2 0 0 1-1.17-1.17L8.4 4.27a.5.5 0 0 0-.9 0z"/><path d="M15.5 12.27l-.89 2.22a2 2 0 0 1-1.17 1.17l-2.22.89a.5.5 0 0 0 0 .9l2.22.89a2 2 0 0 1 1.17 1.17l.89 2.22a.5.5 0 0 0 .9 0l.89-2.22a2 2 0 0 1 1.17-1.17l2.22-.89a.5.5 0 0 0 0-.9l-2.22-.89a2 2 0 0 1-1.17-1.17l-.89-2.22a.5.5 0 0 0-.9 0z"/></svg>';
30
+ return s + '<path d="M10 13a5 5 0 0 0 7.07 0l1.41-1.41a5 5 0 0 0 0-7.07 5 5 0 0 0-7.07 0L10 5"/><path d="M14 11a5 5 0 0 0-7.07 0L5.52 12.41a5 5 0 0 0 0 7.07 5 5 0 0 0 7.07 0L14 19"/></svg>';
31
+ }
32
+
33
+ function normalizePath(p) {
34
+ var s = String(p || "");
35
+ if (!s) return "/";
36
+ // treat /docs?doc=... as /docs for nav active purposes
37
+ return s.split("?")[0].replace(/\/+$/, "") || "/";
38
+ }
39
+
40
+ function isActive(href, curPath) {
41
+ var h = normalizePath(href);
42
+ var c = normalizePath(curPath);
43
+ if (h === "/") return c === "/";
44
+ return c === h || (c.startsWith(h + "/"));
45
+ }
46
+
47
+ var cur = normalizePath(window.location.pathname || "/");
48
+ var navHtml = "";
49
+ for (var i = 0; i < links.length; i++) {
50
+ var l = links[i];
51
+ var active = !l.external && isActive(l.href, cur);
52
+ var attrs = active ? ' aria-current="page"' : "";
53
+ if (l.external) attrs += ' target="_blank" rel="noopener"';
54
+ navHtml +=
55
+ '<a class="sb-link" href="' + String(l.href) + '" data-tip="' + String(l.label) + '"' + attrs + ">" +
56
+ iconSvg(l.icon) +
57
+ '<span class="sb-text">' + String(l.label) + "</span>" +
58
+ (l.external ? '<span class="sb-sub">EXT</span>' : '<span class="sb-sub"></span>') +
59
+ "</a>";
60
+ }
61
+
62
+ mount.innerHTML =
63
+ '<button class="sb-menu-btn" id="sbMenuBtn" type="button" aria-label="Toggle menu" aria-expanded="false">' +
64
+ '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2">' +
65
+ '<line x1="3" y1="6" x2="21" y2="6"></line>' +
66
+ '<line x1="3" y1="12" x2="21" y2="12"></line>' +
67
+ '<line x1="3" y1="18" x2="21" y2="18"></line>' +
68
+ "</svg>" +
69
+ "</button>" +
70
+ '<div class="sb-backdrop" id="sbBackdrop" aria-hidden="true"></div>' +
71
+ '<aside class="sb-sidebar" id="sbSidebar" data-open="0" aria-label="Menu">' +
72
+ '<div class="sb-inner">' +
73
+ '<div class="sb-brand">' +
74
+ '<div class="sb-mark" aria-hidden="true">' +
75
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">' +
76
+ '<path d="M6.5 3C4.5 5 4 7 4 9c0 2.5 1.5 4 3 5"/>' +
77
+ '<path d="M17.5 3c2 2 2.5 4 2.5 6 0 2.5-1.5 4-3 5"/>' +
78
+ '<path d="M7 14c-1 1-2 3-2 5 0 1 .5 2 2 2s2.5-1 3-2"/>' +
79
+ '<path d="M17 14c1 1 2 3 2 5 0 1-.5 2-2 2s-2.5-1-3-2"/>' +
80
+ '<circle cx="12" cy="12" r="3"/>' +
81
+ '</svg>' +
82
+ '</div>' +
83
+ '<div class="sb-brand-text">' +
84
+ "<strong>APECLAW</strong>" +
85
+ '<span>terminal library • pod swarm</span>' +
86
+ "</div>" +
87
+ "</div>" +
88
+ '<nav class="sb-nav" aria-label="Primary navigation">' + navHtml + "</nav>" +
89
+ '<div class="sb-footer">' +
90
+ '<div class="sb-powered">' +
91
+ '<span class="sb-powered-label">Powered by</span>' +
92
+ '<a href="https://x.com/ClutchMarkets" target="_blank" rel="noopener" class="sb-powered-link">' +
93
+ '<svg class="sb-powered-logo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M8 12l3 3 5-6"/></svg>' +
94
+ 'Clutch Labs' +
95
+ '</a>' +
96
+ '</div>' +
97
+ '<div class="sb-footer-links">' +
98
+ '<a href="https://x.com/ClutchMarkets" target="_blank" rel="noopener">' +
99
+ '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>' +
100
+ ' ClutchMarkets' +
101
+ '</a>' +
102
+ '</div>' +
103
+ '</div>' +
104
+ "</div>" +
105
+ "</aside>";
106
+
107
+ var btn = el("sbMenuBtn");
108
+ var bd = el("sbBackdrop");
109
+ var side = el("sbSidebar");
110
+ if (!btn || !bd || !side) return;
111
+
112
+ function setOpen(v) {
113
+ var open = !!v;
114
+ side.setAttribute("data-open", open ? "1" : "0");
115
+ bd.setAttribute("data-open", open ? "1" : "0");
116
+ btn.setAttribute("aria-expanded", open ? "true" : "false");
117
+ // Swap icon to close when open (cheap innerHTML replace).
118
+ btn.innerHTML = open
119
+ ? '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>'
120
+ : '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>';
121
+ }
122
+
123
+ btn.addEventListener("click", function () {
124
+ var open = side.getAttribute("data-open") === "1";
125
+ setOpen(!open);
126
+ });
127
+ bd.addEventListener("click", function () { setOpen(false); });
128
+ window.addEventListener("keydown", function (e) {
129
+ if (e && e.key === "Escape") setOpen(false);
130
+ });
131
+
132
+ // Layout hint for desktop rail.
133
+ try {
134
+ document.body.setAttribute("data-has-sidebar", "1");
135
+ } catch {}
136
+ })();
137
+