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
package/ui/docs.html ADDED
@@ -0,0 +1,840 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Docs — ApeClaw</title>
7
+ <meta name="description" content="ApeClaw documentation: global backend, clawbots, telemetry, v1 workflows, v2-alpha onchain skills, SkillCards, THE POD runner.">
8
+ <link rel="icon" type="image/svg+xml" href="/ui/favicon.svg">
9
+ <link rel="icon" type="image/png" sizes="32x32" href="/ui/favicon-32.png">
10
+ <link rel="apple-touch-icon" sizes="180x180" href="/ui/favicon-180.png">
11
+ <link rel="preconnect" href="https://fonts.googleapis.com">
12
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700;800&family=Outfit:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
14
+ <link rel="stylesheet" href="/ui/shared/sidebar-nav.css">
15
+ <script defer src="/ui/shared/sidebar-nav.js"></script>
16
+ <link rel="stylesheet" href="/ui/shared/motion.css">
17
+ <script defer src="/ui/shared/motion.js"></script>
18
+ <style>
19
+ :root{
20
+ --bg:#0c0c0c;
21
+ --panel:#1a1a1a;
22
+ --panel-2:#212121;
23
+ --panel-hover:#2a2a2a;
24
+ --panel-border:rgba(207,255,4,.75);
25
+ --panel-border-soft:rgba(207,255,4,.35);
26
+ --glow:rgba(207,255,4,.22);
27
+ --muted:#a6a6a6;
28
+ --text:#e6e6e6;
29
+ --amber:#cfff04;
30
+ --amber-soft:rgba(207,255,4,.75);
31
+ --green:#00ff00;
32
+ --cyan:#63d7ff;
33
+ --danger:#ff3333;
34
+ --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
35
+ --font-display:'Outfit','Inter','Segoe UI',sans-serif;
36
+ --terminal-gray:#474546;
37
+ --terminal-lightgray:#9e9e9e;
38
+ --accent:#cfff04;
39
+ --accent-soft:rgba(207,255,4,.75);
40
+ --gray:#474546;
41
+ --lightgray:#aaa;
42
+ }
43
+ *{box-sizing:border-box;margin:0;padding:0}
44
+ html{scroll-behavior:smooth}
45
+ body{
46
+ min-height:100vh;
47
+ margin:0;
48
+ font-family:'Outfit','Inter','Segoe UI',sans-serif;
49
+ background:var(--bg);
50
+ color:var(--text);
51
+ overflow-x:hidden;
52
+ -webkit-font-smoothing:antialiased;
53
+ letter-spacing:.03em;
54
+ }
55
+ body::before{
56
+ content:"";
57
+ position:fixed;
58
+ inset:0;
59
+ pointer-events:none;
60
+ z-index:0;
61
+ background:
62
+ radial-gradient(900px 500px at 20% 10%, rgba(207,255,4,0.10) 0%, transparent 60%),
63
+ radial-gradient(700px 380px at 85% 75%, rgba(0,255,0,0.06) 0%, transparent 55%),
64
+ linear-gradient(180deg, rgba(0,0,0,0.35), rgba(0,0,0,0.85));
65
+ }
66
+ .noise{
67
+ position:fixed;inset:0;pointer-events:none;z-index:2;opacity:0.07;mix-blend-mode:overlay;
68
+ background-image:
69
+ repeating-linear-gradient(0deg, rgba(255,255,255,0.06) 0px, rgba(255,255,255,0.06) 1px, rgba(0,0,0,0) 2px, rgba(0,0,0,0) 4px),
70
+ repeating-linear-gradient(90deg, rgba(255,255,255,0.04) 0px, rgba(255,255,255,0.04) 1px, rgba(0,0,0,0) 2px, rgba(0,0,0,0) 6px);
71
+ }
72
+ .scanlines{overflow:hidden;position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:1}
73
+ .scanlines:before,.scanlines:after{display:block;pointer-events:none;content:"";position:absolute}
74
+ .scanlines:before{width:100%;height:2px;z-index:2147483649;background:rgba(0,0,0,0.3);opacity:0.75;animation:scanline 6s linear infinite}
75
+ .scanlines:after{top:0;right:0;bottom:0;left:0;z-index:2147483648;background:linear-gradient(to bottom, transparent 50%, rgba(0,0,0,0.3) 51%);background-size:100% 4px;animation:scanlines 1s steps(60) infinite}
76
+ @keyframes scanline{0%{transform:translate3d(0,200000%,0)}}
77
+ @keyframes scanlines{0%{background-position:0 200000%}}
78
+ :focus-visible{outline:2px dashed var(--accent);outline-offset:3px}
79
+
80
+ /* Disable the older collage background (previous iteration). */
81
+ .bg-collage, .bg-fade{display:none !important}
82
+ a{color:inherit;text-decoration:none}
83
+ a:hover{text-decoration:underline}
84
+ .bg-fade{
85
+ position:fixed;inset:0;z-index:1;pointer-events:none;
86
+ background:
87
+ radial-gradient(ellipse 90% 50% at 50% 0%, rgba(2,3,5,0.15) 0%, rgba(2,3,5,0.95) 100%),
88
+ linear-gradient(180deg, rgba(2,3,5,0.1) 0%, rgba(2,3,5,0.7) 40%, rgba(2,3,5,1) 100%);
89
+ }
90
+ .bg-collage{
91
+ position:fixed;
92
+ inset:0;
93
+ z-index:0;
94
+ opacity:0.12;
95
+ pointer-events:none;
96
+ display:grid;
97
+ grid-template-columns:repeat(10,1fr);
98
+ gap:5px;
99
+ padding:5px;
100
+ }
101
+ .bg-collage img{
102
+ width:100%;
103
+ aspect-ratio:1/1;
104
+ object-fit:cover;
105
+ border-radius:3px;
106
+ image-rendering:pixelated;
107
+ filter:saturate(0.7) contrast(0.85) brightness(0.9);
108
+ transform:rotate(var(--r));
109
+ }
110
+
111
+ .wrap{position:relative;z-index:3;max-width:1260px;margin:0 auto;padding:20px 20px 28px}
112
+
113
+ .layout{display:grid;grid-template-columns:1fr;gap:12px;margin-top:14px}
114
+ @media(min-width:980px){.layout{grid-template-columns:320px 1fr}}
115
+ .panel{
116
+ background:linear-gradient(180deg,var(--panel-2) 0%,var(--panel) 100%);
117
+ border:1px solid var(--panel-border);
118
+ border-radius:2px;
119
+ box-shadow:inset 0 0 0 1px #0f1d2c;
120
+ }
121
+ .sidebar{padding:14px}
122
+ .main{padding:16px}
123
+ @media(min-width:980px){
124
+ .sidebar{
125
+ position:sticky;
126
+ top:16px;
127
+ align-self:start;
128
+ max-height:calc(100vh - 32px);
129
+ overflow:auto;
130
+ }
131
+ }
132
+
133
+ .eyebrow{font-size:10px;font-weight:800;color:var(--accent);letter-spacing:.2em;text-transform:uppercase;margin-bottom:12px}
134
+ .title{margin:4px 0 10px;font-size:28px;line-height:1.05;font-weight:900;letter-spacing:-.01em;text-transform:uppercase;color:#fff}
135
+ .subtitle{margin:0;color:var(--muted);font-size:14px;line-height:1.65;max-width:92ch}
136
+
137
+ .mini-note{
138
+ margin-top:10px;display:inline-flex;align-items:center;gap:8px;
139
+ padding:7px 10px;border-radius:2px;border:1px solid var(--panel-border);
140
+ background:rgba(9,13,18,0.7);color:var(--muted);font-size:12px;max-width:100%;
141
+ text-transform:uppercase;letter-spacing:.04em;
142
+ }
143
+ .mini-note code{font-family:var(--mono);font-size:11px;color:var(--cyan);text-transform:none;letter-spacing:0}
144
+
145
+ .search{margin-top:12px;display:flex;gap:8px;align-items:center}
146
+ .search input{
147
+ width:100%;
148
+ border:1px solid #2a4056;
149
+ background:#0b1622;
150
+ color:#d4e6fa;
151
+ padding:9px 10px;
152
+ border-radius:2px;
153
+ font-size:13px;
154
+ outline:none;
155
+ }
156
+ .search input:focus{border-color:var(--accent-soft)}
157
+ .mini-btn{
158
+ border:1px solid #2a3d52;background:#0f1b28;color:#f4f7fc;border-radius:2px;
159
+ padding:9px 10px;font-size:13px;cursor:pointer;white-space:nowrap;
160
+ text-transform:uppercase;letter-spacing:.04em;font-weight:700;
161
+ }
162
+ .mini-btn:hover{border-color:var(--accent-soft);background:#132335}
163
+ .tools{margin-top:10px;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
164
+ .tools select{
165
+ border:1px solid #2a4056;
166
+ background:#0b1622;
167
+ color:#d4e6fa;
168
+ padding:9px 10px;
169
+ border-radius:2px;
170
+ font-size:13px;
171
+ outline:none;
172
+ text-transform:uppercase;
173
+ letter-spacing:.04em;
174
+ font-weight:700;
175
+ }
176
+ .tools select:focus{border-color:var(--accent-soft)}
177
+
178
+ .section-h{margin:14px 0 8px;font-size:11px;color:var(--accent);letter-spacing:.15em;text-transform:uppercase;font-weight:800}
179
+ .doclist{display:flex;flex-direction:column;gap:6px}
180
+ .doclink{
181
+ border:1px solid #2a4056;background:#0b1622;border-radius:2px;
182
+ padding:10px 10px;display:flex;align-items:flex-start;justify-content:space-between;gap:10px;
183
+ }
184
+ .doclink:hover{border-color:var(--accent-soft);text-decoration:none}
185
+ .doclink.active{
186
+ border-color:rgba(207,255,4,.55);
187
+ box-shadow:inset 0 0 0 1px rgba(207,255,4,.10);
188
+ background:linear-gradient(180deg,var(--panel-2) 0%,var(--panel) 100%);
189
+ }
190
+ .docname{font-size:13px;color:var(--text);font-weight:800;letter-spacing:.02em;text-transform:uppercase}
191
+ .docdesc{font-size:12px;color:var(--muted);margin-top:4px;line-height:1.45}
192
+ .tag{
193
+ font-size:11px;padding:5px 8px;border-radius:2px;border:1px solid #2a4056;
194
+ background:rgba(9,13,18,0.6);color:#d4e6fa;white-space:nowrap;margin-top:1px;
195
+ text-transform:uppercase;letter-spacing:.04em;
196
+ }
197
+ .sidebar-section{margin-top:16px}
198
+ .sidebar-section:first-child{margin-top:0}
199
+ .sidebar-section h3{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent,#cff004);margin:16px 0 6px;padding:0 12px}
200
+ .sidebar-section .doc-link{
201
+ display:block;padding:8px 12px;color:var(--text);text-decoration:none;font-size:13px;border-radius:2px;margin:2px 0;
202
+ border:1px solid transparent;transition:border-color 0.2s;
203
+ }
204
+ .sidebar-section .doc-link:hover{border-color:var(--accent-soft);text-decoration:none;background:rgba(255,255,255,.02)}
205
+ .sidebar-section .doc-link.active{
206
+ border-color:rgba(207,255,4,.55);
207
+ box-shadow:inset 0 0 0 1px rgba(207,255,4,.10);
208
+ background:linear-gradient(180deg,var(--panel-2) 0%,var(--panel) 100%);
209
+ color:var(--accent);
210
+ }
211
+
212
+ .toolbar{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px}
213
+ .crumbs{color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.04em}
214
+ .toolbar .btns{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
215
+ .btn{
216
+ border:1px solid #2a3d52;background:#0f1b28;color:#f4f7fc;border-radius:2px;
217
+ padding:8px 10px;font-size:12.5px;text-decoration:none;
218
+ text-transform:uppercase;letter-spacing:.04em;font-weight:700;
219
+ }
220
+ .btn:hover{border-color:var(--accent-soft);text-decoration:none;background:#132335}
221
+ .btn.dim{color:var(--muted)}
222
+
223
+ .content{border-top:1px solid rgba(255,255,255,.08);padding-top:12px}
224
+ .loading{
225
+ margin-top:12px;
226
+ padding:12px 12px;
227
+ border-radius:2px;
228
+ border:1px solid #2a4056;
229
+ background:#0b1622;
230
+ font-family:var(--mono);
231
+ font-size:12px;
232
+ color:#d4e6fa;
233
+ line-height:1.55;
234
+ }
235
+ .loading .k{color:var(--cyan)}
236
+
237
+ .md h1,.md h2,.md h3,.md h4{letter-spacing:-.01em;margin:16px 0 10px;font-weight:900;text-transform:uppercase;color:#fff}
238
+ .md h1{font-size:28px;margin-top:0}
239
+ .md h2{font-size:20px}
240
+ .md h3{font-size:16px}
241
+ .md p{margin:10px 0;color:var(--text);line-height:1.75;font-size:14px}
242
+ .md ul,.md ol{margin:10px 0 10px 20px;color:var(--text);line-height:1.7;font-size:14px}
243
+ .md li{margin:5px 0}
244
+ .md code{
245
+ font-family:var(--mono);
246
+ font-size:.92em;
247
+ background:rgba(9,13,18,0.6);
248
+ padding:1px 5px;
249
+ border-radius:2px;
250
+ color:#d4e6fa;
251
+ }
252
+ .md pre{
253
+ margin:12px 0;padding:12px 12px;border-radius:2px;border:1px solid #2a4056;background:#0b1622;overflow:auto;
254
+ }
255
+ .md pre code{background:transparent;padding:0;border-radius:0;color:#d4e6fa;font-size:12.5px;display:block;white-space:pre}
256
+ .md blockquote{
257
+ margin:12px 0;padding:10px 12px;border-radius:2px;border:1px solid rgba(207,255,4,.22);
258
+ background:rgba(207,255,4,.06);color:var(--text);
259
+ }
260
+ .md a{color:var(--cyan)}
261
+
262
+ .toc{
263
+ margin-top:10px;border:1px solid #2a4056;background:#0b1622;border-radius:2px;
264
+ padding:10px 10px;color:var(--muted);font-size:12px;
265
+ }
266
+ .toc strong{color:var(--accent);font-size:12px;letter-spacing:.06em;text-transform:uppercase;font-weight:800}
267
+ .toc a{display:block;padding:6px 6px;border-radius:2px;color:#d4e6fa;text-decoration:none}
268
+ .toc a:hover{background:rgba(255,255,255,.03);text-decoration:none}
269
+
270
+ .sep{height:1px;background:linear-gradient(90deg,transparent,rgba(207,255,4,.3),transparent);transition:all 1s;transform:scaleX(0)}
271
+ .sep.show,.ac-visible .sep{transform:scaleX(1)}
272
+ .foot{padding:16px 20px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--gray);text-transform:uppercase;letter-spacing:.04em}
273
+ </style>
274
+ </head>
275
+ <body>
276
+ <div class="bg-collage" aria-hidden="true" id="bgCollage"></div>
277
+ <div class="bg-fade" aria-hidden="true"></div>
278
+ <div class="scanlines" aria-hidden="true"></div>
279
+ <div class="noise" aria-hidden="true"></div>
280
+ <div id="sbNavMount"></div>
281
+ <div class="wrap sb-content-offset">
282
+ <div class="layout">
283
+ <div class="panel sidebar ac-observe">
284
+ <div class="eyebrow">Documentation</div>
285
+ <div class="title">Everything, in one place.</div>
286
+ <p class="subtitle">
287
+ This page renders the markdown in `docs/*.md` directly. Deep links work via `?doc=...`.
288
+ </p>
289
+ <div class="mini-note" id="backendNote">Backend: <code>auto</code></div>
290
+ <div class="tools" aria-label="Start here shortcuts">
291
+ <a class="btn" href="/docs?doc=developer/08-contributing.md" data-keep-query="1">Contribute</a>
292
+ <a class="btn" href="/skills#your-skills" data-keep-query="1">Add Skill</a>
293
+ <a class="btn" href="/pod" data-keep-query="1">Run Pod</a>
294
+ </div>
295
+
296
+ <div class="search">
297
+ <input id="searchInput" type="search" placeholder="Search docs..." autocomplete="off" spellcheck="false">
298
+ <button class="mini-btn" id="copyLinkBtn" type="button" title="Copy link to this doc">Copy Link</button>
299
+ </div>
300
+ <div class="tools" aria-label="Doc filters">
301
+ <select id="tagFilter" aria-label="Tag filter">
302
+ <option value="all">tag: all</option>
303
+ </select>
304
+ <button class="mini-btn" id="clearBtn" type="button" title="Clear search + filters">Clear</button>
305
+ </div>
306
+ <div class="mini-note" id="statsNote">Docs: <code id="docsCount">0</code> · Showing: <code id="docsShowing">0</code></div>
307
+
308
+ <div id="docNav"></div>
309
+ <div class="foot ac-observe">Tip: press <code>/</code> to focus search.</div>
310
+ </div>
311
+
312
+ <div class="panel main ac-observe">
313
+ <div class="toolbar">
314
+ <div class="crumbs" id="crumbs">Loading…</div>
315
+ <div class="btns">
316
+ <a class="btn dim" id="rawBtn" href="#" target="_blank" rel="noopener">Raw</a>
317
+ <a class="btn dim" id="ghBtn" href="#" target="_blank" rel="noopener">GitHub</a>
318
+ </div>
319
+ </div>
320
+
321
+ <div class="toc" id="toc" style="display:none">
322
+ <strong>On this page</strong>
323
+ <div id="tocLinks"></div>
324
+ </div>
325
+
326
+ <div class="content md" id="content"></div>
327
+ </div>
328
+ </div>
329
+ <div class="foot ac-observe">
330
+ <div>ApeClaw Terminal · ApeChain · Powered by <a href="https://x.com/ClutchMarkets" target="_blank" rel="noopener" style="color:var(--accent);text-decoration:none;font-weight:700">Clutch Labs</a></div>
331
+ <div style="display:flex;align-items:center;gap:14px">
332
+ <a href="https://x.com/ClutchMarkets" target="_blank" rel="noopener" style="display:inline-flex;align-items:center;gap:4px;color:var(--muted);text-decoration:none;font-size:10px;transition:color .2s" onmouseover="this.style.color='var(--accent)'" onmouseout="this.style.color='var(--muted)'"><svg viewBox="0 0 24 24" width="13" height="13" 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> ClutchMarkets</a>
333
+ <div class="online" style="display:inline-flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--gray,#474546);background:rgba(9,13,18,.7);color:var(--muted);font-size:11px"><span class="dot" style="width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 10px rgba(207,255,4,.35)" aria-hidden="true"></span><span>Online</span></div>
334
+ </div>
335
+ </div>
336
+ </div>
337
+
338
+ <script>
339
+ (function () {
340
+ // Lightweight collage background to match the Stonk terminal feel.
341
+ try {
342
+ var c = document.getElementById('bgCollage');
343
+ if (c && !c.hasChildNodes()) {
344
+ var N = 80;
345
+ for (var i = 0; i < N; i++) {
346
+ var img = document.createElement('img');
347
+ img.src = '/ui/favicon-lobster.png';
348
+ img.alt = '';
349
+ img.style.setProperty('--r', (Math.round((Math.random() * 10 - 5) * 10) / 10) + 'deg');
350
+ c.appendChild(img);
351
+ }
352
+ }
353
+ } catch (e) {}
354
+
355
+ var DOCS = [
356
+ { section: "Operator Guide", file: "operator/01-quickstart.md", title: "Quickstart", desc: "Get started with ApeClaw", tag: "operator" },
357
+ { section: "Operator Guide", file: "operator/02-dashboard.md", title: "Dashboard Guide", desc: "How to use the dashboard interface", tag: "operator" },
358
+ { section: "Operator Guide", file: "operator/03-cli-reference.md", title: "CLI Reference", desc: "Command-line interface documentation", tag: "operator" },
359
+ { section: "Operator Guide", file: "operator/04-skills-library.md", title: "Skills Library", desc: "Available skills and how to use them", tag: "operator" },
360
+ { section: "Operator Guide", file: "operator/05-pod-operations.md", title: "Pod Operations", desc: "Running and managing Pods", tag: "operator" },
361
+ { section: "Operator Guide", file: "operator/06-deployment.md", title: "Deployment", desc: "Deployment guides and best practices", tag: "operator" },
362
+ { section: "Operator Guide", file: "operator/07-safety-and-policy.md", title: "Safety & Policy", desc: "Safety measures and policy guidelines", tag: "operator" },
363
+ { section: "Operator Guide", file: "operator/08-troubleshooting.md", title: "Troubleshooting", desc: "Common issues and solutions", tag: "operator" },
364
+ { section: "Operator Guide", file: "operator/09-env-reference.md", title: "Environment Variables", desc: "Configuration via environment variables", tag: "operator" },
365
+ { section: "Developer Guide", file: "developer/01-architecture.md", title: "Architecture", desc: "System architecture and design", tag: "developer" },
366
+ { section: "Developer Guide", file: "developer/02-contracts.md", title: "Smart Contracts", desc: "Smart contract documentation", tag: "developer" },
367
+ { section: "Developer Guide", file: "developer/03-writing-modules.md", title: "Writing Modules", desc: "How to write and extend modules", tag: "developer" },
368
+ { section: "Developer Guide", file: "developer/04-skillcard-spec.md", title: "SkillCard Spec", desc: "SkillCard specification and format", tag: "developer" },
369
+ { section: "Developer Guide", file: "developer/05-backend-api.md", title: "Backend API", desc: "Backend API documentation", tag: "developer" },
370
+ { section: "Developer Guide", file: "developer/06-telemetry.md", title: "Telemetry", desc: "Telemetry system and events", tag: "developer" },
371
+ { section: "Developer Guide", file: "developer/07-testing.md", title: "Testing", desc: "Testing strategies and tools", tag: "developer" },
372
+ { section: "Developer Guide", file: "developer/08-contributing.md", title: "Contributing", desc: "How to contribute to the project", tag: "developer" },
373
+ { section: "Reference", file: "PRODUCT_OVERVIEW.md", title: "Product Overview", desc: "Full product overview and architecture", tag: "reference" },
374
+ { section: "Reference", file: "V1_WORKFLOWS.md", title: "V1 Workflows", desc: "Policy-gated NFT and bridge execution flows", tag: "reference" },
375
+ { section: "Reference", file: "V2_ONCHAIN_SKILLS.md", title: "V2 Onchain Skills", desc: "Onchain skill minting, publishing, and receipts", tag: "reference" },
376
+ { section: "Reference", file: "ONCHAIN_V2_GUIDE.md", title: "Onchain V2 Guide", desc: "End-to-end v2-alpha onchain guide", tag: "reference" },
377
+ { section: "Reference", file: "ACP_BOUNTIES.md", title: "ACP Bounties", desc: "Agent Commerce Protocol bounty integration", tag: "reference" },
378
+ { section: "Reference", file: "THE_POD_RUNNER.md", title: "THE POD Runner", desc: "Pod harness, Otherside navigator, recovery", tag: "reference" },
379
+ { section: "Reference", file: "SKILLCARDS_AND_IMPORTER.md", title: "SkillCards & Importer", desc: "SkillCard format and bulk import pipeline", tag: "reference" },
380
+ { section: "Reference", file: "TELEMETRY_AND_EVENTS.md", title: "Telemetry & Events", desc: "Event schema, SSE streaming, and troubleshooting", tag: "reference" },
381
+ { section: "Reference", file: "CLAWBOTS_AND_INVITES.md", title: "Clawbots & Invites", desc: "Registration, verification, and invite system", tag: "reference" },
382
+ { section: "Reference", file: "GLOBAL_BACKEND.md", title: "Global Backend", desc: "Backend deployment, CORS, persistence", tag: "reference" },
383
+ { section: "Reference", file: "SUPPORTED_NETWORKS.md", title: "Supported Networks", desc: "Network support status and roadmap", tag: "reference" },
384
+ { section: "Reference", file: "DASHBOARD_GUIDE.md", title: "Dashboard Deep Dive", desc: "Legacy dashboard guide with full layout details", tag: "reference" },
385
+ { section: "Reference", file: "CLI_GUIDE.md", title: "CLI Guide (Legacy)", desc: "Original CLI guide with v1+v2 commands", tag: "reference" },
386
+ { section: "Reference", file: "CONTRIBUTING.md", title: "Contributing (Legacy)", desc: "Original contributing guide for users and agents", tag: "reference" },
387
+ { section: "Vision", file: "APECLAW_V2_ALPHA.md", title: "V2-Alpha Overview", desc: "What v2-alpha ships and why it matters", tag: "vision" },
388
+ { section: "Vision", file: "WEB4_SWARM_MODEL.md", title: "Web4 Swarm Model", desc: "Why onchain context enables agent swarms", tag: "vision" },
389
+ { section: "Vision", file: "WEB4_PLAN_STATUS.md", title: "Web4 Plan Status", desc: "What has shipped, what hasn't, and what's next", tag: "vision" },
390
+ { section: "Vision", file: "AUTONOMY_AND_SUBSTRATE.md", title: "Autonomy & Substrate", desc: "Addressing the bounded automation critique", tag: "vision" }
391
+ ];
392
+
393
+ function $(id){ return document.getElementById(id); }
394
+
395
+ function currentSearch(){
396
+ try { return (window.location && window.location.search) ? String(window.location.search) : ""; } catch (e) {}
397
+ return "";
398
+ }
399
+
400
+ function currentApiBase(){
401
+ try {
402
+ var u = new URL(window.location.href);
403
+ var api = (u.searchParams.get("api") || "").trim();
404
+ if (api) return api.replace(/\/+$/, "");
405
+ } catch (e) {}
406
+ return "";
407
+ }
408
+
409
+ function escapeHtml(s){
410
+ return String(s || "")
411
+ .replace(/&/g, "&amp;")
412
+ .replace(/</g, "&lt;")
413
+ .replace(/>/g, "&gt;")
414
+ .replace(/"/g, "&quot;")
415
+ .replace(/'/g, "&#39;");
416
+ }
417
+
418
+ function slugify(s){
419
+ return String(s || "")
420
+ .toLowerCase()
421
+ .trim()
422
+ .replace(/[^a-z0-9]+/g, "-")
423
+ .replace(/^-+|-+$/g, "");
424
+ }
425
+
426
+ function inlineMd(s){
427
+ var out = escapeHtml(s);
428
+ // inline code
429
+ out = out.replace(/`([^`]+)`/g, function(_, c){ return "<code>" + escapeHtml(c) + "</code>"; });
430
+ // links [text](url)
431
+ out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, function(_, t, u){
432
+ var href = escapeHtml(u);
433
+ return "<a href=\"" + href + "\" target=\"_blank\" rel=\"noopener\">" + escapeHtml(t) + "</a>";
434
+ });
435
+ // bold **x**
436
+ out = out.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
437
+ return out;
438
+ }
439
+
440
+ function renderMarkdown(md){
441
+ var lines = String(md || "").replace(/\r/g, "").split("\n");
442
+ var html = [];
443
+ var toc = [];
444
+ var inCode = false;
445
+ var codeFence = "";
446
+ var codeBuf = [];
447
+ var para = [];
448
+ var inUl = false;
449
+ var inOl = false;
450
+ var quoteBuf = [];
451
+
452
+ function flushPara(){
453
+ if (!para.length) return;
454
+ html.push("<p>" + inlineMd(para.join(" ").trim()) + "</p>");
455
+ para = [];
456
+ }
457
+ function closeLists(){
458
+ if (inUl){ html.push("</ul>"); inUl = false; }
459
+ if (inOl){ html.push("</ol>"); inOl = false; }
460
+ }
461
+ function flushQuote(){
462
+ if (!quoteBuf.length) return;
463
+ closeLists();
464
+ flushPara();
465
+ html.push("<blockquote>" + inlineMd(quoteBuf.join("\n")) + "</blockquote>");
466
+ quoteBuf = [];
467
+ }
468
+
469
+ for (var i = 0; i < lines.length; i++){
470
+ var ln = lines[i];
471
+ var t = ln.trim();
472
+
473
+ // fenced code blocks
474
+ var fence = ln.match(/^```(.*)\s*$/);
475
+ if (fence){
476
+ if (!inCode){
477
+ flushQuote();
478
+ closeLists();
479
+ flushPara();
480
+ inCode = true;
481
+ codeFence = String(fence[1] || "").trim();
482
+ codeBuf = [];
483
+ } else {
484
+ inCode = false;
485
+ var code = escapeHtml(codeBuf.join("\n"));
486
+ html.push("<pre><code>" + code + "</code></pre>");
487
+ codeFence = "";
488
+ codeBuf = [];
489
+ }
490
+ continue;
491
+ }
492
+ if (inCode){
493
+ codeBuf.push(ln);
494
+ continue;
495
+ }
496
+
497
+ // blockquote
498
+ if (t.startsWith("> ")){
499
+ flushPara();
500
+ closeLists();
501
+ quoteBuf.push(t.slice(2));
502
+ continue;
503
+ } else {
504
+ flushQuote();
505
+ }
506
+
507
+ // headings
508
+ var h = ln.match(/^(#{1,4})\s+(.*)$/);
509
+ if (h){
510
+ closeLists();
511
+ flushPara();
512
+ var level = h[1].length;
513
+ var text = String(h[2] || "").trim();
514
+ var id = slugify(text);
515
+ html.push("<h" + level + " id=\"" + escapeHtml(id) + "\">" + inlineMd(text) + "</h" + level + ">");
516
+ if (level === 2 || level === 3){
517
+ toc.push({ level: level, id: id, text: text });
518
+ }
519
+ continue;
520
+ }
521
+
522
+ // lists
523
+ var ul = ln.match(/^\s*[-*]\s+(.*)$/);
524
+ var ol = ln.match(/^\s*\d+\.\s+(.*)$/);
525
+ if (ul){
526
+ flushPara();
527
+ if (inOl){ html.push("</ol>"); inOl = false; }
528
+ if (!inUl){ html.push("<ul>"); inUl = true; }
529
+ html.push("<li>" + inlineMd(ul[1]) + "</li>");
530
+ continue;
531
+ }
532
+ if (ol){
533
+ flushPara();
534
+ if (inUl){ html.push("</ul>"); inUl = false; }
535
+ if (!inOl){ html.push("<ol>"); inOl = true; }
536
+ html.push("<li>" + inlineMd(ol[1]) + "</li>");
537
+ continue;
538
+ }
539
+
540
+ // blank line closes blocks
541
+ if (!t){
542
+ closeLists();
543
+ flushPara();
544
+ continue;
545
+ }
546
+
547
+ // paragraph line
548
+ para.push(t);
549
+ }
550
+
551
+ flushQuote();
552
+ closeLists();
553
+ flushPara();
554
+
555
+ return { html: html.join("\n"), toc: toc };
556
+ }
557
+
558
+ function currentDocFromUrl(){
559
+ try {
560
+ var u = new URL(window.location.href);
561
+ var d = (u.searchParams.get("doc") || "").trim();
562
+ if (d) return d;
563
+ } catch (e) {}
564
+ return "operator/01-quickstart.md";
565
+ }
566
+
567
+ function setDocInUrl(doc){
568
+ try {
569
+ var u = new URL(window.location.href);
570
+ u.searchParams.set("doc", doc);
571
+ history.replaceState(null, "", u.toString());
572
+ } catch (e) {}
573
+ }
574
+
575
+ function keepQueryOnLinks(){
576
+ var search = currentSearch();
577
+ if (!search) return;
578
+ try {
579
+ var as = document.querySelectorAll('a[data-keep-query="1"]');
580
+ for (var i = 0; i < as.length; i++) {
581
+ var href = String(as[i].getAttribute("href") || "");
582
+ if (!href || href.indexOf("http") === 0 || href.indexOf("#") === 0) continue;
583
+ if (href.indexOf("?") !== -1) continue;
584
+ as[i].setAttribute("href", href + search);
585
+ }
586
+ } catch (e) {}
587
+ }
588
+
589
+ function highlightActiveDoc(doc){
590
+ var nav = $("docNav");
591
+ if (!nav) return;
592
+ try {
593
+ var links = nav.querySelectorAll("a[data-doc]");
594
+ for (var i = 0; i < links.length; i++){
595
+ var d = String(links[i].getAttribute("data-doc") || "");
596
+ var on = d === doc;
597
+ if (on) {
598
+ links[i].classList.add("active");
599
+ links[i].setAttribute("aria-current", "page");
600
+ } else {
601
+ links[i].classList.remove("active");
602
+ links[i].removeAttribute("aria-current");
603
+ }
604
+ }
605
+ } catch (e) {}
606
+ }
607
+
608
+ function groupDocs(list){
609
+ var out = {};
610
+ for (var i = 0; i < list.length; i++){
611
+ var d = list[i];
612
+ out[d.section] = out[d.section] || [];
613
+ out[d.section].push(d);
614
+ }
615
+ return out;
616
+ }
617
+
618
+ function renderNav(filter, tag){
619
+ var nav = $("docNav");
620
+ if (!nav) return;
621
+ var f = String(filter || "").toLowerCase().trim();
622
+ var tg = String(tag || "all").toLowerCase().trim();
623
+ var filtered = DOCS.filter(function(d){
624
+ if (!f) return true;
625
+ return (d.title + " " + d.desc + " " + d.file + " " + d.section + " " + (d.tag || "")).toLowerCase().indexOf(f) !== -1;
626
+ }).filter(function(d){
627
+ if (!tg || tg === "all") return true;
628
+ return String(d.tag || "").toLowerCase() === tg;
629
+ });
630
+
631
+ // Sidebar stats
632
+ try {
633
+ var dc = $("docsCount");
634
+ var ds = $("docsShowing");
635
+ if (dc) dc.textContent = String(DOCS.length);
636
+ if (ds) ds.textContent = String(filtered.length);
637
+ } catch (e) {}
638
+
639
+ var groups = groupDocs(filtered);
640
+ var sectionOrder = ["Operator Guide", "Developer Guide"];
641
+ var html = [];
642
+ var curDoc = currentDocFromUrl();
643
+ var apiBase = currentApiBase();
644
+
645
+ sectionOrder.forEach(function(section){
646
+ var items = groups[section] || [];
647
+ if (!items.length) return;
648
+ html.push("<div class=\"sidebar-section\">");
649
+ html.push("<h3>" + escapeHtml(section) + "</h3>");
650
+ items.forEach(function(d){
651
+ // Keep current query params (e.g. ?api=...) when deep-linking to docs.
652
+ var href = "/docs?doc=" + encodeURIComponent(d.file) + "&api=" + encodeURIComponent(apiBase);
653
+ var active = (d.file === curDoc) ? " active" : "";
654
+ var currentAttr = (d.file === curDoc) ? " aria-current=\"page\"" : "";
655
+ html.push(
656
+ "<a class=\"doc-link" + active + "\" href=\"" + href + "\" data-doc=\"" + escapeHtml(d.file) + "\"" + currentAttr + ">" +
657
+ escapeHtml(d.title) +
658
+ "</a>"
659
+ );
660
+ });
661
+ html.push("</div>");
662
+ });
663
+
664
+ nav.innerHTML = html.join("\n");
665
+
666
+ // Intercept clicks to avoid full reload.
667
+ try {
668
+ var links = nav.querySelectorAll("a[data-doc]");
669
+ for (var i = 0; i < links.length; i++){
670
+ links[i].addEventListener("click", function(ev){
671
+ ev.preventDefault();
672
+ var doc = this.getAttribute("data-doc") || "operator/01-quickstart.md";
673
+ loadDoc(doc);
674
+ });
675
+ }
676
+ } catch (e) {}
677
+ highlightActiveDoc(curDoc);
678
+ }
679
+
680
+ function updateToc(toc){
681
+ var box = $("toc");
682
+ var list = $("tocLinks");
683
+ if (!box || !list) return;
684
+ if (!toc || !toc.length){
685
+ box.style.display = "none";
686
+ list.innerHTML = "";
687
+ return;
688
+ }
689
+ box.style.display = "block";
690
+ var html = [];
691
+ for (var i = 0; i < toc.length; i++){
692
+ var it = toc[i];
693
+ var pad = it.level === 3 ? " style=\"margin-left:10px\"" : "";
694
+ html.push("<a href=\"#" + escapeHtml(it.id) + "\"" + pad + ">" + escapeHtml(it.text) + "</a>");
695
+ }
696
+ list.innerHTML = html.join("\n");
697
+ }
698
+
699
+ function setToolbar(doc, title){
700
+ var crumbs = $("crumbs");
701
+ var rawBtn = $("rawBtn");
702
+ var ghBtn = $("ghBtn");
703
+ if (crumbs) crumbs.textContent = (title ? title : doc) + " · " + doc;
704
+
705
+ var rawUrl = "/docs/" + encodeURIComponent(doc);
706
+ if (rawBtn) rawBtn.setAttribute("href", rawUrl);
707
+
708
+ var ghUrl = "https://github.com/simplefarmer69/ape-claw/blob/main/docs/" + encodeURIComponent(doc);
709
+ if (ghBtn) ghBtn.setAttribute("href", ghUrl);
710
+ }
711
+
712
+ function loadDoc(doc){
713
+ var content = $("content");
714
+ if (content) content.innerHTML = "<div class=\"loading\">Loading <span class=\"k\">docs/</span>" + escapeHtml(doc) + "…</div>";
715
+ setDocInUrl(doc);
716
+ highlightActiveDoc(doc);
717
+
718
+ var meta = DOCS.find(function(d){ return d.file === doc; }) || null;
719
+ setToolbar(doc, meta ? meta.title : "");
720
+
721
+ var url = "/docs/" + doc.split("/").map(encodeURIComponent).join("/");
722
+ var ghRaw = "https://raw.githubusercontent.com/simplefarmer69/ape-claw/main/docs/" + doc.split("/").map(encodeURIComponent).join("/");
723
+
724
+ function tryFetch(u){
725
+ return fetch(u, { headers: { "accept": "text/plain" } })
726
+ .then(function(r){
727
+ if (!r.ok) throw new Error("fetch failed: " + r.status);
728
+ return r.text();
729
+ });
730
+ }
731
+
732
+ tryFetch(url)
733
+ .catch(function(){
734
+ // Fallback so docs still work even if static `/docs/*.md` isn't served in some deployments.
735
+ try {
736
+ var rawBtn = $("rawBtn");
737
+ if (rawBtn) rawBtn.setAttribute("href", ghRaw);
738
+ } catch (e) {}
739
+ return tryFetch(ghRaw);
740
+ })
741
+ .then(function(md){
742
+ var rendered = renderMarkdown(md);
743
+ if (content) content.innerHTML = rendered.html;
744
+ updateToc(rendered.toc);
745
+ })
746
+ .catch(function(){
747
+ if (content) content.innerHTML = "<blockquote>Failed to load <code>" + escapeHtml(doc) + "</code>. Try <a href=\"" + escapeHtml(ghRaw) + "\" target=\"_blank\" rel=\"noopener\">GitHub raw</a>.</blockquote>";
748
+ updateToc([]);
749
+ });
750
+ }
751
+
752
+ // Init
753
+ keepQueryOnLinks();
754
+ try {
755
+ var n = $("backendNote");
756
+ if (n) n.innerHTML = "Backend: <code>" + escapeHtml(currentApiBase()) + "</code>";
757
+ } catch (e) {}
758
+ // Populate tag filter from DOCS list.
759
+ var tagFilter = $("tagFilter");
760
+ try {
761
+ if (tagFilter) {
762
+ var seen = {};
763
+ var tags = [];
764
+ for (var i = 0; i < DOCS.length; i++){
765
+ var t = String(DOCS[i].tag || "").trim();
766
+ if (!t) continue;
767
+ var k = t.toLowerCase();
768
+ if (seen[k]) continue;
769
+ seen[k] = true;
770
+ tags.push(t);
771
+ }
772
+ tags.sort(function(a, b){ return a.localeCompare(b); });
773
+ for (var j = 0; j < tags.length; j++){
774
+ var opt = document.createElement("option");
775
+ opt.value = String(tags[j]).toLowerCase();
776
+ opt.textContent = "tag: " + tags[j];
777
+ tagFilter.appendChild(opt);
778
+ }
779
+ }
780
+ } catch (e) {}
781
+
782
+ function currentTag(){
783
+ try { return tagFilter ? String(tagFilter.value || "all") : "all"; } catch (e) {}
784
+ return "all";
785
+ }
786
+
787
+ renderNav("", currentTag());
788
+ loadDoc(currentDocFromUrl());
789
+
790
+ var searchInput = $("searchInput");
791
+ if (searchInput){
792
+ searchInput.addEventListener("input", function(){ renderNav(searchInput.value || "", currentTag()); });
793
+ }
794
+ if (tagFilter){
795
+ tagFilter.addEventListener("change", function(){
796
+ renderNav((searchInput && searchInput.value) ? searchInput.value : "", currentTag());
797
+ });
798
+ }
799
+ var clearBtn = $("clearBtn");
800
+ if (clearBtn){
801
+ clearBtn.addEventListener("click", function(){
802
+ try { if (searchInput) searchInput.value = ""; } catch (e) {}
803
+ try { if (tagFilter) tagFilter.value = "all"; } catch (e) {}
804
+ renderNav("", currentTag());
805
+ if (searchInput) searchInput.focus();
806
+ });
807
+ }
808
+ window.addEventListener("keydown", function(e){
809
+ if (!e) return;
810
+ if (e.key === "/" && document.activeElement !== searchInput){
811
+ e.preventDefault();
812
+ if (searchInput) searchInput.focus();
813
+ }
814
+ if (e.key === "Escape"){
815
+ if (document.activeElement === searchInput) searchInput.blur();
816
+ }
817
+ });
818
+
819
+ var copyLinkBtn = $("copyLinkBtn");
820
+ if (copyLinkBtn){
821
+ copyLinkBtn.addEventListener("click", function(){
822
+ try {
823
+ var u = new URL(window.location.href);
824
+ var doc = currentDocFromUrl();
825
+ u.searchParams.set("doc", doc);
826
+ var text = u.toString();
827
+ Promise.resolve(navigator.clipboard && navigator.clipboard.writeText ? navigator.clipboard.writeText(text) : null)
828
+ .catch(function(){})
829
+ .finally(function(){
830
+ copyLinkBtn.textContent = "Copied";
831
+ setTimeout(function(){ copyLinkBtn.textContent = "Copy Link"; }, 900);
832
+ });
833
+ } catch (e) {}
834
+ });
835
+ }
836
+ })();
837
+ </script>
838
+ </body>
839
+ </html>
840
+