@pixelbyte-software/pixcode 1.33.9 → 1.33.11

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 (38) hide show
  1. package/dist/api-docs.html +373 -857
  2. package/dist/assets/{index-DpIcI9Q1.js → index-oLYHJ2X5.js} +154 -166
  3. package/dist/index.html +1 -1
  4. package/dist/openapi.yaml +1311 -0
  5. package/dist-server/server/gemini-cli.js +59 -0
  6. package/dist-server/server/gemini-cli.js.map +1 -1
  7. package/dist-server/server/index.js +6 -1
  8. package/dist-server/server/index.js.map +1 -1
  9. package/dist-server/server/middleware/auth.js +51 -9
  10. package/dist-server/server/middleware/auth.js.map +1 -1
  11. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +54 -15
  12. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
  13. package/dist-server/server/modules/providers/list/qwen/qwen-sessions.provider.js +46 -0
  14. package/dist-server/server/modules/providers/list/qwen/qwen-sessions.provider.js.map +1 -1
  15. package/dist-server/server/modules/providers/provider.routes.js +32 -1
  16. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  17. package/dist-server/server/opencode-cli.js +41 -2
  18. package/dist-server/server/opencode-cli.js.map +1 -1
  19. package/dist-server/server/opencode-response-handler.js +36 -34
  20. package/dist-server/server/opencode-response-handler.js.map +1 -1
  21. package/dist-server/server/routes/agent.js +187 -56
  22. package/dist-server/server/routes/agent.js.map +1 -1
  23. package/dist-server/server/routes/projects.js +134 -8
  24. package/dist-server/server/routes/projects.js.map +1 -1
  25. package/dist-server/server/services/provider-credentials.js +42 -8
  26. package/dist-server/server/services/provider-credentials.js.map +1 -1
  27. package/package.json +1 -1
  28. package/server/gemini-cli.js +60 -0
  29. package/server/index.js +6 -1
  30. package/server/middleware/auth.js +50 -9
  31. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +60 -21
  32. package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +47 -0
  33. package/server/modules/providers/provider.routes.ts +37 -4
  34. package/server/opencode-cli.js +41 -2
  35. package/server/opencode-response-handler.js +36 -29
  36. package/server/routes/agent.js +178 -58
  37. package/server/routes/projects.js +136 -8
  38. package/server/services/provider-credentials.js +42 -8
@@ -1,879 +1,395 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Pixcode - API Documentation</title>
7
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
- <link rel="icon" type="image/png" href="/favicon.png" />
9
-
10
- <!-- Prism.js for syntax highlighting -->
11
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
12
-
13
- <style>
14
- * {
15
- margin: 0;
16
- padding: 0;
17
- box-sizing: border-box;
18
- }
19
-
20
- :root {
21
- --gray-50: #f9fafb;
22
- --gray-100: #f3f4f6;
23
- --gray-200: #e5e7eb;
24
- --gray-600: #4b5563;
25
- --gray-700: #374151;
26
- --gray-800: #1f2937;
27
- --gray-900: #111827;
28
- --primary: #2563eb;
29
- --primary-dark: #1d4ed8;
30
- --green: #10b981;
31
- --red: #ef4444;
32
- }
33
-
34
- body {
35
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
36
- line-height: 1.6;
37
- color: var(--gray-900);
38
- background: var(--gray-50);
39
- margin: 0;
40
- }
41
-
42
- header {
43
- background: white;
44
- border-bottom: 1px solid var(--gray-200);
45
- padding: 1.5rem 0;
46
- position: sticky;
47
- top: 0;
48
- z-index: 100;
49
- }
50
-
51
- .header-content {
52
- display: flex;
53
- align-items: center;
54
- justify-content: space-between;
55
- padding: 0 2rem;
56
- }
57
-
58
- .brand {
59
- display: flex;
60
- align-items: center;
61
- gap: 0.75rem;
62
- }
63
-
64
- .brand-icon {
65
- width: 32px;
66
- height: 32px;
67
- background: var(--primary);
68
- border-radius: 8px;
69
- display: flex;
70
- align-items: center;
71
- justify-content: center;
72
- }
73
-
74
- .brand-icon svg {
75
- width: 16px;
76
- height: 16px;
77
- stroke: white;
78
- }
79
-
80
- .brand-text h1 {
81
- font-size: 1.25rem;
82
- font-weight: 700;
83
- color: var(--gray-900);
84
- }
85
-
86
- .brand-text .subtitle {
87
- font-size: 0.875rem;
88
- color: var(--gray-600);
89
- }
90
-
91
- .back-link {
92
- display: flex;
93
- align-items: center;
94
- gap: 0.5rem;
95
- padding: 0.5rem 1rem;
96
- background: var(--primary);
97
- color: white;
98
- text-decoration: none;
99
- border-radius: 6px;
100
- font-size: 0.875rem;
101
- font-weight: 500;
102
- transition: background 0.2s;
103
- }
104
-
105
- .back-link:hover {
106
- background: var(--primary-dark);
107
- }
108
-
109
- .back-link svg {
110
- width: 16px;
111
- height: 16px;
112
- }
113
-
114
- .main-layout {
115
- display: flex;
116
- }
117
-
118
- .sidebar {
119
- width: 240px;
120
- background: white;
121
- border-right: 1px solid var(--gray-200);
122
- padding: 2rem 0;
123
- position: sticky;
124
- top: 73px;
125
- height: calc(100vh - 73px);
126
- overflow-y: auto;
127
- flex-shrink: 0;
128
- }
129
-
130
- .sidebar-title {
131
- font-size: 0.75rem;
132
- font-weight: 600;
133
- text-transform: uppercase;
134
- color: var(--gray-600);
135
- padding: 0 1.5rem;
136
- margin: 1.5rem 0 0.5rem;
137
- }
138
-
139
- .sidebar a {
140
- display: block;
141
- padding: 0.625rem 1.5rem;
142
- color: var(--gray-700);
143
- text-decoration: none;
144
- font-size: 0.875rem;
145
- transition: all 0.15s;
146
- border-left: 3px solid transparent;
147
- }
148
-
149
- .sidebar a:hover {
150
- background: var(--gray-50);
151
- color: var(--primary);
152
- border-left-color: var(--primary);
153
- }
154
-
155
- .content-wrapper {
156
- flex: 1;
157
- display: flex;
158
- flex-direction: column;
159
- min-height: calc(100vh - 73px);
160
- }
161
-
162
- .section-row {
163
- display: grid;
164
- grid-template-columns: 1fr 600px;
165
- }
166
-
167
- .docs-section {
168
- padding: 3rem 3rem;
169
- background: white;
170
- border-right: 1px solid var(--gray-200);
171
- }
172
-
173
- .examples-section {
174
- padding: 3rem 2rem;
175
- background: #0d1117;
176
- color: #e6edf3;
177
- }
178
-
179
- .examples-section h4 {
180
- color: #e6edf3;
181
- font-size: 0.875rem;
182
- font-weight: 600;
183
- margin-bottom: 1rem;
184
- text-transform: uppercase;
185
- letter-spacing: 0.05em;
186
- }
187
-
188
- h2 {
189
- font-size: 2rem;
190
- font-weight: 700;
191
- margin-bottom: 1rem;
192
- color: var(--gray-900);
193
- }
194
-
195
- h3 {
196
- font-size: 1.375rem;
197
- font-weight: 600;
198
- margin: 2.5rem 0 1rem;
199
- color: var(--gray-900);
200
- }
201
-
202
- h4 {
203
- font-size: 1rem;
204
- font-weight: 600;
205
- margin: 1.5rem 0 0.75rem;
206
- color: var(--gray-700);
207
- }
208
-
209
- p {
210
- margin-bottom: 1rem;
211
- color: var(--gray-600);
212
- }
213
-
214
- .intro {
215
- background: linear-gradient(135deg, rgba(37, 99, 235, 0.08) 0%, rgba(59, 130, 246, 0.08) 100%);
216
- border: 1px solid rgba(37, 99, 235, 0.2);
217
- border-radius: 8px;
218
- padding: 1.5rem;
219
- margin-bottom: 2rem;
220
- }
221
-
222
- .intro p {
223
- color: var(--gray-700);
224
- margin: 0;
225
- }
226
-
227
- .endpoint {
228
- margin: 2rem 0;
229
- padding: 1.5rem;
230
- background: var(--gray-50);
231
- border-radius: 8px;
232
- border: 1px solid var(--gray-200);
233
- }
234
-
235
- .endpoint-header {
236
- display: flex;
237
- align-items: center;
238
- gap: 1rem;
239
- margin-bottom: 1rem;
240
- }
241
-
242
- .method {
243
- padding: 0.375rem 0.875rem;
244
- border-radius: 6px;
245
- font-weight: 700;
246
- font-size: 0.75rem;
247
- text-transform: uppercase;
248
- }
249
-
250
- .method-post {
251
- background: var(--green);
252
- color: white;
253
- }
254
-
255
- .endpoint-path {
256
- font-family: 'Monaco', 'Menlo', monospace;
257
- font-size: 0.9375rem;
258
- font-weight: 600;
259
- }
260
-
261
- table {
262
- width: 100%;
263
- border-collapse: collapse;
264
- margin: 1rem 0;
265
- font-size: 0.875rem;
266
- }
267
-
268
- th {
269
- text-align: left;
270
- padding: 0.875rem;
271
- background: var(--gray-100);
272
- border: 1px solid var(--gray-200);
273
- font-weight: 600;
274
- color: var(--gray-800);
275
- }
276
-
277
- td {
278
- padding: 0.875rem;
279
- border: 1px solid var(--gray-200);
280
- color: var(--gray-700);
281
- }
282
-
283
- code {
284
- background: rgba(37, 99, 235, 0.08);
285
- padding: 0.1875rem 0.5rem;
286
- border-radius: 4px;
287
- font-family: 'Monaco', 'Menlo', monospace;
288
- font-size: 0.875em;
289
- color: var(--primary-dark);
290
- }
291
-
292
- .api-url {
293
- color: #60a5fa;
294
- }
295
-
296
- .badge {
297
- display: inline-block;
298
- padding: 0.1875rem 0.625rem;
299
- border-radius: 12px;
300
- font-size: 0.6875rem;
301
- font-weight: 600;
302
- text-transform: uppercase;
303
- }
304
-
305
- .badge-required {
306
- background: var(--red);
307
- color: white;
308
- }
309
-
310
- .badge-optional {
311
- background: var(--gray-200);
312
- color: var(--gray-700);
313
- }
314
-
315
- .note {
316
- padding: 1.25rem;
317
- background: rgba(37, 99, 235, 0.05);
318
- border-left: 4px solid var(--primary);
319
- border-radius: 8px;
320
- margin: 1rem 0;
321
- font-size: 0.875rem;
322
- }
323
-
324
- /* Code tabs in side panel */
325
- .tab-buttons {
326
- display: flex;
327
- gap: 0.5rem;
328
- margin-bottom: 1rem;
329
- }
330
-
331
- .tab-button {
332
- padding: 0.5rem 1rem;
333
- background: transparent;
334
- border: 1px solid #30363d;
335
- cursor: pointer;
336
- font-size: 0.8125rem;
337
- font-weight: 500;
338
- color: #7d8590;
339
- border-radius: 6px;
340
- transition: all 0.2s;
341
- }
342
-
343
- .tab-button:hover {
344
- color: #e6edf3;
345
- border-color: #58a6ff;
346
- }
347
-
348
- .tab-button.active {
349
- color: #e6edf3;
350
- background: #1f6feb;
351
- border-color: #1f6feb;
352
- }
353
-
354
- .tab-content {
355
- display: none;
356
- }
357
-
358
- .tab-content.active {
359
- display: block;
360
- }
361
-
362
- pre[class*="language-"] {
363
- margin: 0 0 1.5rem 0;
364
- border-radius: 6px;
365
- font-size: 0.8125rem;
366
- }
367
-
368
- .example-block {
369
- margin-bottom: 2rem;
370
- }
371
-
372
- @media (max-width: 1400px) {
373
- .section-row {
374
- grid-template-columns: 1fr 500px;
375
- }
376
- }
377
-
378
- @media (max-width: 1200px) {
379
- .section-row {
380
- grid-template-columns: 1fr;
381
- }
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
+ <title>Pixcode API Documentation</title>
7
+ <meta name="description" content="REST API reference for Pixcode — the multi-CLI web UI for Claude Code, Cursor, Codex, Gemini, Qwen, and OpenCode." />
8
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
9
+ <link rel="icon" type="image/png" href="/favicon.png" />
10
+ <style>
11
+ :root {
12
+ --bg: #0b0d10;
13
+ --bg-soft: #11151b;
14
+ --bg-card: #161b22;
15
+ --border: #232a33;
16
+ --fg: #e6edf3;
17
+ --fg-muted: #8b949e;
18
+ --primary: #2563eb;
19
+ --primary-hover: #1d4ed8;
20
+ --accent: #10b981;
21
+ --warn: #f59e0b;
22
+ }
23
+ @media (prefers-color-scheme: light) {
24
+ :root {
25
+ --bg: #ffffff;
26
+ --bg-soft: #f6f8fa;
27
+ --bg-card: #ffffff;
28
+ --border: #d0d7de;
29
+ --fg: #1f2328;
30
+ --fg-muted: #656d76;
31
+ }
32
+ }
382
33
 
383
- .examples-section {
384
- border-top: 1px solid #30363d;
385
- }
386
- }
34
+ * { box-sizing: border-box; }
35
+ html, body { margin: 0; padding: 0; }
36
+ body {
37
+ background: var(--bg);
38
+ color: var(--fg);
39
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Inter, sans-serif;
40
+ min-height: 100vh;
41
+ }
387
42
 
388
- @media (max-width: 768px) {
389
- .main-layout {
390
- flex-direction: column;
391
- }
392
-
393
- .sidebar {
394
- width: 100%;
395
- position: relative;
396
- height: auto;
397
- border-right: none;
398
- border-bottom: 1px solid var(--gray-200);
399
- }
400
-
401
- .docs-section {
402
- padding: 2rem 1.5rem;
403
- }
43
+ /* ── Top bar ─────────────────────────────────────────────────── */
44
+ .topbar {
45
+ position: sticky; top: 0; z-index: 50;
46
+ display: flex; align-items: center; gap: 12px;
47
+ padding: 10px 16px;
48
+ background: var(--bg-soft);
49
+ border-bottom: 1px solid var(--border);
50
+ backdrop-filter: blur(8px);
51
+ }
52
+ .topbar-brand {
53
+ display: flex; align-items: center; gap: 10px;
54
+ font-weight: 700; font-size: 15px; letter-spacing: -0.01em;
55
+ color: var(--fg); text-decoration: none;
56
+ }
57
+ .topbar-brand img { width: 24px; height: 24px; border-radius: 6px; }
58
+ .topbar-brand .badge {
59
+ font-size: 10px; font-weight: 600;
60
+ padding: 2px 6px; border-radius: 4px;
61
+ background: var(--primary); color: white;
62
+ letter-spacing: 0.04em; text-transform: uppercase;
63
+ }
64
+ .topbar-spacer { flex: 1; }
65
+ .topbar-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
66
+ .topbar select, .topbar a.btn, .topbar button.btn {
67
+ height: 32px;
68
+ padding: 0 12px;
69
+ border-radius: 6px;
70
+ border: 1px solid var(--border);
71
+ background: var(--bg-card);
72
+ color: var(--fg);
73
+ font-size: 13px;
74
+ cursor: pointer;
75
+ text-decoration: none;
76
+ display: inline-flex; align-items: center; gap: 6px;
77
+ }
78
+ .topbar a.btn:hover, .topbar button.btn:hover { border-color: var(--primary); }
79
+ .topbar a.btn.primary, .topbar button.btn.primary {
80
+ background: var(--primary); border-color: var(--primary); color: white;
81
+ }
82
+ .topbar a.btn.primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
83
+
84
+ /* ── API key bar ──────────────────────────────────────────────── */
85
+ .apikey-bar {
86
+ display: flex; align-items: center; gap: 10px;
87
+ padding: 10px 16px;
88
+ background: var(--bg-card);
89
+ border-bottom: 1px solid var(--border);
90
+ flex-wrap: wrap;
91
+ }
92
+ .apikey-bar label {
93
+ font-size: 12px; font-weight: 600; color: var(--fg-muted);
94
+ letter-spacing: 0.02em; text-transform: uppercase;
95
+ }
96
+ .apikey-bar input {
97
+ flex: 1; min-width: 220px;
98
+ height: 34px; padding: 0 12px;
99
+ background: var(--bg-soft);
100
+ border: 1px solid var(--border);
101
+ border-radius: 6px;
102
+ color: var(--fg);
103
+ font-family: 'SF Mono', ui-monospace, monospace;
104
+ font-size: 13px;
105
+ }
106
+ .apikey-bar input:focus { outline: none; border-color: var(--primary); }
107
+ .apikey-bar .hint { font-size: 12px; color: var(--fg-muted); }
108
+ .apikey-bar .status {
109
+ font-size: 11px; padding: 3px 8px; border-radius: 999px;
110
+ background: var(--bg-soft); color: var(--fg-muted);
111
+ border: 1px solid var(--border);
112
+ }
113
+ .apikey-bar .status.ok { color: var(--accent); border-color: var(--accent); }
114
+
115
+ /* ── Scalar host ──────────────────────────────────────────────── */
116
+ #scalar-host { min-height: calc(100vh - 130px); }
117
+
118
+ /* ── Mobile tweaks ────────────────────────────────────────────── */
119
+ @media (max-width: 640px) {
120
+ .topbar { padding: 8px 10px; gap: 8px; }
121
+ .topbar-brand .subtitle { display: none; }
122
+ .topbar-actions a.btn span:not(.icon) { display: none; }
123
+ .apikey-bar { padding: 8px 10px; }
124
+ .apikey-bar .hint { display: none; }
125
+ }
404
126
 
405
- .examples-section {
406
- padding: 2rem 1.5rem;
407
- }
408
- }
409
- </style>
127
+ /* ── Loading state ────────────────────────────────────────────── */
128
+ .loader {
129
+ display: flex; align-items: center; justify-content: center;
130
+ height: calc(100vh - 130px);
131
+ color: var(--fg-muted);
132
+ font-size: 14px;
133
+ gap: 10px;
134
+ }
135
+ .loader .spinner {
136
+ width: 18px; height: 18px;
137
+ border: 2px solid var(--border);
138
+ border-top-color: var(--primary);
139
+ border-radius: 50%;
140
+ animation: spin 0.8s linear infinite;
141
+ }
142
+ @keyframes spin { to { transform: rotate(360deg); } }
143
+ </style>
410
144
  </head>
411
145
  <body>
412
- <header>
413
- <div class="header-content">
414
- <div class="brand">
415
- <div class="brand-icon">
416
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
417
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"/>
418
- </svg>
419
- </div>
420
- <div class="brand-text">
421
- <h1>Pixcode</h1>
422
- <div class="subtitle">API Documentation</div>
423
- </div>
424
- </div>
425
- <a href="/" class="back-link">
426
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
427
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
428
- </svg>
429
- Back to App
430
- </a>
431
- </div>
432
- </header>
433
-
434
- <div class="main-layout">
435
- <nav class="sidebar">
436
- <div class="sidebar-title">Getting Started</div>
437
- <a href="#authentication">Authentication</a>
438
- <a href="#credentials">GitHub Credentials</a>
439
-
440
- <div class="sidebar-title">API Reference</div>
441
- <a href="#agent">Agent</a>
442
-
443
- <div class="sidebar-title">Examples</div>
444
- <a href="#usage-examples">Usage Patterns</a>
445
- </nav>
446
-
447
- <div class="content-wrapper">
448
- <!-- Intro Section -->
449
- <div class="section-row">
450
- <div class="docs-section">
451
- <div class="intro">
452
- <p><strong>Programmatically trigger AI agents to work on projects.</strong> Clone GitHub repositories or use existing project paths. Perfect for CI/CD pipelines, automated code reviews, and bulk processing.</p>
453
- </div>
454
-
455
- <section id="authentication">
456
- <h2>Authentication</h2>
457
- <p>All API requests require authentication using an API key in the <code>X-API-Key</code> header.</p>
458
-
459
- <p>Generate API keys in Settings → API & Tokens.</p>
460
- </section>
461
-
462
- <section id="credentials">
463
- <h3>GitHub Credentials</h3>
464
- <p>For private repositories, store a GitHub token in settings or pass it with each request.</p>
465
-
466
- <div class="note">
467
- <strong>Note:</strong> GitHub tokens in the request override stored tokens.
468
- </div>
469
- </section>
470
- </div>
471
-
472
- <div class="examples-section">
473
- <div class="example-block">
474
- <h4>Authentication Header</h4>
475
- <pre><code class="language-http">X-API-Key: ck_your_api_key_here</code></pre>
476
- </div>
477
- </div>
478
- </div>
479
-
480
- <!-- Agent API Section -->
481
- <div class="section-row">
482
- <div class="docs-section">
483
- <section id="agent">
484
- <h2>Agent</h2>
485
146
 
486
- <div class="endpoint">
487
- <div class="endpoint-header">
488
- <span class="method method-post">POST</span>
489
- <span class="endpoint-path"><span class="api-url">http://localhost:3001</span>/api/agent</span>
490
- </div>
491
-
492
- <p>Trigger an AI agent (Claude, Cursor, or Codex) to work on a project.</p>
493
-
494
- <h4>Request Body Parameters</h4>
495
- <table>
496
- <thead>
497
- <tr>
498
- <th>Parameter</th>
499
- <th>Type</th>
500
- <th>Required</th>
501
- <th>Description</th>
502
- </tr>
503
- </thead>
504
- <tbody>
505
- <tr>
506
- <td><code>githubUrl</code></td>
507
- <td>string</td>
508
- <td><span class="badge badge-optional">Conditional</span></td>
509
- <td>GitHub repository URL to clone. If path exists with same repo, reuses it. If path exists with different repo, returns error.</td>
510
- </tr>
511
- <tr>
512
- <td><code>projectPath</code></td>
513
- <td>string</td>
514
- <td><span class="badge badge-optional">Conditional</span></td>
515
- <td>Path to existing project OR destination for cloning. If omitted with <code>githubUrl</code>, auto-generates path. If used alone, must point to existing project directory.</td>
516
- </tr>
517
- <tr>
518
- <td><code>message</code></td>
519
- <td>string</td>
520
- <td><span class="badge badge-required">Required</span></td>
521
- <td>Task for the AI agent</td>
522
- </tr>
523
- <tr>
524
- <td><code>provider</code></td>
525
- <td>string</td>
526
- <td><span class="badge badge-optional">Optional</span></td>
527
- <td><code>claude</code>, <code>cursor</code>, or <code>codex</code> (default: <code>claude</code>)</td>
528
- </tr>
529
- <tr>
530
- <td><code>stream</code></td>
531
- <td>boolean</td>
532
- <td><span class="badge badge-optional">Optional</span></td>
533
- <td>Enable streaming (default: <code>true</code>)</td>
534
- </tr>
535
- <tr>
536
- <td><code>model</code></td>
537
- <td>string</td>
538
- <td><span class="badge badge-optional">Optional</span></td>
539
- <td id="model-options-cell">
540
- Model identifier for the AI provider (loading from constants...)
541
- </td>
542
- </tr>
543
- <tr>
544
- <td><code>cleanup</code></td>
545
- <td>boolean</td>
546
- <td><span class="badge badge-optional">Optional</span></td>
547
- <td>Auto-cleanup after completion (default: <code>true</code>). Only applies when cloning via <code>githubUrl</code>. Existing projects specified via <code>projectPath</code> are never cleaned up.</td>
548
- </tr>
549
- <tr>
550
- <td><code>githubToken</code></td>
551
- <td>string</td>
552
- <td><span class="badge badge-optional">Optional</span></td>
553
- <td>GitHub token for private repos</td>
554
- </tr>
555
- <tr>
556
- <td><code>branchName</code></td>
557
- <td>string</td>
558
- <td><span class="badge badge-optional">Optional</span></td>
559
- <td>Custom branch name to use. If provided, <code>createBranch</code> is automatically enabled. Branch names are validated against Git naming rules. Works with <code>githubUrl</code> or <code>projectPath</code> (if it has a GitHub remote).</td>
560
- </tr>
561
- <tr>
562
- <td><code>createBranch</code></td>
563
- <td>boolean</td>
564
- <td><span class="badge badge-optional">Optional</span></td>
565
- <td>Create a new branch after successful completion (default: <code>false</code>). Automatically set to <code>true</code> if <code>branchName</code> is provided. Works with <code>githubUrl</code> or <code>projectPath</code> (if it has a GitHub remote).</td>
566
- </tr>
567
- <tr>
568
- <td><code>createPR</code></td>
569
- <td>boolean</td>
570
- <td><span class="badge badge-optional">Optional</span></td>
571
- <td>Create a pull request after successful completion (default: <code>false</code>). PR title and description auto-generated from commit messages. Works with <code>githubUrl</code> or <code>projectPath</code> (if it has a GitHub remote).</td>
572
- </tr>
573
- </tbody>
574
- </table>
575
-
576
- <div class="note">
577
- <strong>Path Handling Behavior:</strong><br><br>
578
- <strong>Scenario 1:</strong> Only <code>githubUrl</code> → Clones to auto-generated temporary path<br>
579
- <strong>Scenario 2:</strong> Only <code>projectPath</code> → Uses existing project at specified path<br>
580
- <strong>Scenario 3:</strong> Both provided → Clones <code>githubUrl</code> to <code>projectPath</code><br><br>
581
- <strong>Validation:</strong> If <code>projectPath</code> exists and contains a git repository, the remote URL is compared with <code>githubUrl</code>. If URLs match, the existing repo is reused. If URLs differ, an error is returned.
582
- </div>
583
-
584
- <h4>Response (Streaming)</h4>
585
- <p>Server-sent events (SSE) format with real-time updates. Content-Type: <code>text/event-stream</code></p>
586
-
587
- <h4>Response (Non-Streaming)</h4>
588
- <p>JSON object containing session details, assistant messages only (filtered), and token usage summary. Content-Type: <code>application/json</code></p>
589
-
590
- <h4>Error Response</h4>
591
- <p>Returns error details with appropriate HTTP status code.</p>
592
- </div>
593
- </section>
594
- </div>
595
-
596
- <div class="examples-section">
597
- <div class="example-block">
598
- <h4>Basic Request</h4>
599
- <div class="tab-buttons">
600
- <button class="tab-button active" onclick="showTab('curl-basic')">cURL</button>
601
- <button class="tab-button" onclick="showTab('js-basic')">JavaScript</button>
602
- <button class="tab-button" onclick="showTab('python-basic')">Python</button>
603
- </div>
604
-
605
- <div class="tab-content active" id="curl-basic">
606
- <pre><code class="language-bash">curl -X POST <span class="api-url">http://localhost:3001</span>/api/agent \
607
- -H "Content-Type: application/json" \
608
- -H "X-API-Key: ck_..." \
609
- -d '{
610
- "githubUrl": "https://github.com/user/repo",
611
- "message": "Add error handling to main.js"
612
- }'</code></pre>
613
- </div>
614
-
615
- <div class="tab-content" id="js-basic">
616
- <pre><code class="language-javascript">const response = await fetch('<span class="api-url">http://localhost:3001</span>/api/agent', {
617
- method: 'POST',
618
- headers: {
619
- 'Content-Type': 'application/json',
620
- 'X-API-Key': process.env.CLAUDE_API_KEY
621
- },
622
- body: JSON.stringify({
623
- githubUrl: 'https://github.com/user/repo',
624
- message: 'Add error handling',
625
- stream: false
626
- })
627
- });
628
-
629
- const result = await response.json();</code></pre>
630
- </div>
631
-
632
- <div class="tab-content" id="python-basic">
633
- <pre><code class="language-python">import requests
634
- import os
635
-
636
- response = requests.post(
637
- '<span class="api-url">http://localhost:3001</span>/api/agent',
638
- headers={
639
- 'Content-Type': 'application/json',
640
- 'X-API-Key': os.environ['CLAUDE_API_KEY']
147
+ <header class="topbar">
148
+ <a href="/" class="topbar-brand">
149
+ <img src="/logo.svg" alt="Pixcode" />
150
+ <span data-i18n="title">Pixcode API</span>
151
+ <span class="badge" data-i18n="badge">v1.33</span>
152
+ </a>
153
+ <div class="topbar-spacer"></div>
154
+ <div class="topbar-actions">
155
+ <select id="lang-select" aria-label="Language" title="Language">
156
+ <option value="en">English</option>
157
+ <option value="tr">Türkçe</option>
158
+ <option value="de">Deutsch</option>
159
+ <option value="it">Italiano</option>
160
+ <option value="ja">日本語</option>
161
+ <option value="ko">한국어</option>
162
+ <option value="ru">Русский</option>
163
+ <option value="zh-CN">中文</option>
164
+ </select>
165
+ <a href="/openapi.yaml" class="btn" download>
166
+ <span class="icon" aria-hidden="true">⬇</span><span data-i18n="downloadSpec">Download spec</span>
167
+ </a>
168
+ <a href="/" class="btn primary">
169
+ <span class="icon" aria-hidden="true">←</span><span data-i18n="backToApp">Back to app</span>
170
+ </a>
171
+ </div>
172
+ </header>
173
+
174
+ <div class="apikey-bar">
175
+ <label for="api-key-input" data-i18n="apiKey.label">API key</label>
176
+ <input
177
+ id="api-key-input"
178
+ type="password"
179
+ placeholder="ck_..."
180
+ autocomplete="off"
181
+ spellcheck="false"
182
+ />
183
+ <span id="api-key-status" class="status" data-i18n="apiKey.notSet">Not set</span>
184
+ <span class="hint" data-i18n="apiKey.hint">Generate one under Settings → API. Stored locally only.</span>
185
+ </div>
186
+
187
+ <div id="scalar-host">
188
+ <div class="loader">
189
+ <div class="spinner"></div>
190
+ <span data-i18n="loading">Loading API reference…</span>
191
+ </div>
192
+ </div>
193
+
194
+ <script>
195
+ // ── i18n: UI chrome only (the OpenAPI spec itself stays in English) ──
196
+ // OpenAPI specs are conventionally English (industry standard). The UI
197
+ // labels above DO change with the language picker — endpoint descriptions
198
+ // do not. Future work: x-translations extension on each operation.
199
+ const I18N = {
200
+ en: {
201
+ title: 'Pixcode API',
202
+ badge: 'v1.33',
203
+ downloadSpec: 'Download spec',
204
+ backToApp: 'Back to app',
205
+ 'apiKey.label': 'API key',
206
+ 'apiKey.notSet': 'Not set',
207
+ 'apiKey.set': 'Saved',
208
+ 'apiKey.hint': 'Generate one under Settings API. Stored locally only.',
209
+ loading: 'Loading API reference…',
641
210
  },
642
- json={
643
- 'githubUrl': 'https://github.com/user/repo',
644
- 'message': 'Add error handling',
645
- 'stream': False
646
- }
647
- )
648
-
649
- print(response.json())</code></pre>
650
- </div>
651
- </div>
652
-
653
- <div class="example-block">
654
- <h4>Streaming Response</h4>
655
- <pre><code class="language-javascript">data: {"type":"status","message":"Repository cloned"}
656
- data: {"type":"thinking","content":"Analyzing..."}
657
- data: {"type":"tool_use","tool":"read_file"}
658
- data: {"type":"content","content":"Done!"}
659
- data: {"type":"done"}</code></pre>
660
- </div>
661
-
662
- <div class="example-block">
663
- <h4>Non-Streaming Response</h4>
664
- <pre><code class="language-json">{
665
- "success": true,
666
- "sessionId": "abc123",
667
- "messages": [
668
- {
669
- "type": "assistant",
670
- "message": {
671
- "role": "assistant",
672
- "content": [
673
- {
674
- "type": "text",
675
- "text": "I've completed the task..."
676
- }
677
- ],
678
- "usage": {
679
- "input_tokens": 150,
680
- "output_tokens": 50
681
- }
682
- }
683
- }
684
- ],
685
- "tokens": {
686
- "inputTokens": 150,
687
- "outputTokens": 50,
688
- "cacheReadTokens": 0,
689
- "cacheCreationTokens": 0,
690
- "totalTokens": 200
691
- },
692
- "projectPath": "/path/to/project",
693
- "branch": {
694
- "name": "fix-authentication-bug-abc123",
695
- "url": "https://github.com/user/repo/tree/fix-authentication-bug-abc123"
696
- },
697
- "pullRequest": {
698
- "number": 42,
699
- "url": "https://github.com/user/repo/pull/42"
211
+ tr: {
212
+ title: 'Pixcode API',
213
+ badge: 'v1.33',
214
+ downloadSpec: 'Spec\'i indir',
215
+ backToApp: 'Uygulamaya dön',
216
+ 'apiKey.label': 'API anahtarı',
217
+ 'apiKey.notSet': 'Boş',
218
+ 'apiKey.set': 'Kaydedildi',
219
+ 'apiKey.hint': 'Ayarlar → API\'den oluşturun. Sadece bu cihazda saklanır.',
220
+ loading: 'API referansı yükleniyor…',
221
+ },
222
+ de: {
223
+ title: 'Pixcode API',
224
+ badge: 'v1.33',
225
+ downloadSpec: 'Spezifikation laden',
226
+ backToApp: 'Zurück zur App',
227
+ 'apiKey.label': 'API-Schlüssel',
228
+ 'apiKey.notSet': 'Nicht gesetzt',
229
+ 'apiKey.set': 'Gespeichert',
230
+ 'apiKey.hint': 'Unter Einstellungen → API erstellen. Nur lokal gespeichert.',
231
+ loading: 'API-Referenz wird geladen…',
232
+ },
233
+ it: {
234
+ title: 'Pixcode API',
235
+ badge: 'v1.33',
236
+ downloadSpec: 'Scarica specifica',
237
+ backToApp: "Torna all'app",
238
+ 'apiKey.label': 'Chiave API',
239
+ 'apiKey.notSet': 'Non impostata',
240
+ 'apiKey.set': 'Salvata',
241
+ 'apiKey.hint': 'Generala in Impostazioni → API. Memorizzata solo localmente.',
242
+ loading: 'Caricamento riferimento API…',
243
+ },
244
+ ja: {
245
+ title: 'Pixcode API',
246
+ badge: 'v1.33',
247
+ downloadSpec: '仕様をダウンロード',
248
+ backToApp: 'アプリに戻る',
249
+ 'apiKey.label': 'API キー',
250
+ 'apiKey.notSet': '未設定',
251
+ 'apiKey.set': '保存済み',
252
+ 'apiKey.hint': '設定 → API で生成してください。このデバイスのみに保存されます。',
253
+ loading: 'API リファレンスを読み込み中…',
254
+ },
255
+ ko: {
256
+ title: 'Pixcode API',
257
+ badge: 'v1.33',
258
+ downloadSpec: '스펙 다운로드',
259
+ backToApp: '앱으로 돌아가기',
260
+ 'apiKey.label': 'API 키',
261
+ 'apiKey.notSet': '미설정',
262
+ 'apiKey.set': '저장됨',
263
+ 'apiKey.hint': '설정 → API에서 생성하세요. 이 기기에만 저장됩니다.',
264
+ loading: 'API 참조 로드 중…',
265
+ },
266
+ ru: {
267
+ title: 'Pixcode API',
268
+ badge: 'v1.33',
269
+ downloadSpec: 'Скачать спецификацию',
270
+ backToApp: 'Вернуться в приложение',
271
+ 'apiKey.label': 'API-ключ',
272
+ 'apiKey.notSet': 'Не задан',
273
+ 'apiKey.set': 'Сохранён',
274
+ 'apiKey.hint': 'Создайте в Настройки → API. Хранится только локально.',
275
+ loading: 'Загрузка справочника API…',
276
+ },
277
+ 'zh-CN': {
278
+ title: 'Pixcode API',
279
+ badge: 'v1.33',
280
+ downloadSpec: '下载规范',
281
+ backToApp: '返回应用',
282
+ 'apiKey.label': 'API 密钥',
283
+ 'apiKey.notSet': '未设置',
284
+ 'apiKey.set': '已保存',
285
+ 'apiKey.hint': '在 设置 → API 生成。仅本地存储。',
286
+ loading: '正在加载 API 参考…',
287
+ },
288
+ };
289
+
290
+ function detectLang() {
291
+ const stored = localStorage.getItem('pixcode-api-docs-lang');
292
+ if (stored && I18N[stored]) return stored;
293
+ const navLang = (navigator.language || 'en').toLowerCase();
294
+ if (navLang.startsWith('zh')) return 'zh-CN';
295
+ const short = navLang.split('-')[0];
296
+ return I18N[short] ? short : 'en';
700
297
  }
701
- }</code></pre>
702
- </div>
703
-
704
- <div class="example-block">
705
- <h4>Error Response</h4>
706
- <pre><code class="language-json">{
707
- "success": false,
708
- "error": "Directory exists with different repo"
709
- }</code></pre>
710
- </div>
711
- </div>
712
- </div>
713
-
714
- <!-- Usage Patterns Section -->
715
- <div class="section-row">
716
- <div class="docs-section">
717
- <section id="usage-examples">
718
- <h2>Usage Patterns</h2>
719
-
720
- <h3>Clone and Process Repository</h3>
721
- <p>Clone a repository to an auto-generated temporary path and process it.</p>
722
-
723
- <h3>Use Existing Project</h3>
724
- <p>Work with an existing project at a specific path.</p>
725
298
 
726
- <h3>Clone to Specific Path</h3>
727
- <p>Clone a repository to a custom location for later reuse.</p>
728
-
729
- <h3>CI/CD Integration</h3>
730
- <p>Integrate with GitHub Actions or other CI/CD pipelines.</p>
731
-
732
- <h3>Create Branch and Pull Request</h3>
733
- <p>Automatically create a new branch and pull request after the agent completes its work. Branch names are auto-generated from the message, and PR title/description are auto-generated from commit messages.</p>
734
- </section>
735
- </div>
736
-
737
- <div class="examples-section">
738
- <div class="example-block">
739
- <h4>Use Existing Project</h4>
740
- <pre><code class="language-bash">curl -X POST <span class="api-url">http://localhost:3001</span>/api/agent \
741
- -H "Content-Type: application/json" \
742
- -H "X-API-Key: ck_..." \
743
- -d '{
744
- "projectPath": "/home/user/my-project",
745
- "message": "Refactor database queries"
746
- }'</code></pre>
747
- </div>
748
-
749
- <div class="example-block">
750
- <h4>Clone to Custom Path</h4>
751
- <pre><code class="language-bash">curl -X POST <span class="api-url">http://localhost:3001</span>/api/agent \
752
- -H "Content-Type: application/json" \
753
- -H "X-API-Key: ck_..." \
754
- -d '{
755
- "githubUrl": "https://github.com/user/repo",
756
- "projectPath": "/tmp/my-location",
757
- "message": "Review security",
758
- "cleanup": false
759
- }'</code></pre>
760
- </div>
761
-
762
- <div class="example-block">
763
- <h4>CI/CD (GitHub Actions)</h4>
764
- <pre><code class="language-yaml">- name: Trigger Agent
765
- run: |
766
- curl -X POST ${{ secrets.API_URL }}/api/agent \
767
- -H "X-API-Key: ${{ secrets.API_KEY }}" \
768
- -H "Content-Type: application/json" \
769
- -d '{
770
- "githubUrl": "${{ github.repository }}",
771
- "message": "Review for security",
772
- "githubToken": "${{ secrets.GITHUB_TOKEN }}"
773
- }'</code></pre>
774
- </div>
775
-
776
- <div class="example-block">
777
- <h4>Create Branch and PR</h4>
778
- <pre><code class="language-bash">curl -X POST <span class="api-url">http://localhost:3001</span>/api/agent \
779
- -H "Content-Type: application/json" \
780
- -H "X-API-Key: ck_..." \
781
- -d '{
782
- "githubUrl": "https://github.com/user/repo",
783
- "message": "Fix authentication bug",
784
- "createBranch": true,
785
- "createPR": true,
786
- "stream": false
787
- }'</code></pre>
788
- </div>
789
-
790
- <div class="example-block">
791
- <h4>Custom Branch Name</h4>
792
- <pre><code class="language-bash">curl -X POST <span class="api-url">http://localhost:3001</span>/api/agent \
793
- -H "Content-Type: application/json" \
794
- -H "X-API-Key: ck_..." \
795
- -d '{
796
- "githubUrl": "https://github.com/user/repo",
797
- "message": "Add user authentication",
798
- "branchName": "feature/user-auth",
799
- "createPR": true,
800
- "stream": false
801
- }'</code></pre>
802
- </div>
803
-
804
- <div class="example-block">
805
- <h4>Branch & PR Response</h4>
806
- <pre><code class="language-json">{
807
- "success": true,
808
- "branch": {
809
- "name": "feature/user-auth",
810
- "url": "https://github.com/user/repo/tree/feature/user-auth"
811
- },
812
- "pullRequest": {
813
- "number": 42,
814
- "url": "https://github.com/user/repo/pull/42"
299
+ function applyI18n(lang) {
300
+ const dict = I18N[lang] || I18N.en;
301
+ document.documentElement.lang = lang;
302
+ document.querySelectorAll('[data-i18n]').forEach((el) => {
303
+ const key = el.getAttribute('data-i18n');
304
+ if (dict[key]) el.textContent = dict[key];
305
+ });
815
306
  }
816
- }</code></pre>
817
- </div>
818
- </div>
819
- </div>
820
- </div>
821
- </div>
822
307
 
823
- <script type="module">
824
- // Import model constants
825
- import { CLAUDE_MODELS, CURSOR_MODELS, CODEX_MODELS } from '/shared/modelConstants.js';
308
+ // ── API key persistence + Scalar prefill ──────────────────────────
309
+ const apiKeyInput = document.getElementById('api-key-input');
310
+ const apiKeyStatus = document.getElementById('api-key-status');
311
+ const STORAGE_KEY = 'pixcode-api-docs-key';
826
312
 
827
- // Dynamic URL replacement
828
- const apiUrl = window.location.origin;
829
- document.querySelectorAll('.api-url').forEach(el => {
830
- el.textContent = apiUrl;
831
- });
832
-
833
- // Dynamically populate model documentation
834
- window.addEventListener('DOMContentLoaded', () => {
835
- const modelCell = document.getElementById('model-options-cell');
836
- if (modelCell) {
837
- const claudeModels = CLAUDE_MODELS.OPTIONS.map(m => `<code>${m.value}</code>`).join(', ');
838
- const cursorModels = CURSOR_MODELS.OPTIONS.slice(0, 8).map(m => `<code>${m.value}</code>`).join(', ');
839
- const codexModels = CODEX_MODELS.OPTIONS.map(m => `<code>${m.value}</code>`).join(', ');
313
+ function setStatus(set) {
314
+ const lang = document.documentElement.lang || 'en';
315
+ const dict = I18N[lang] || I18N.en;
316
+ apiKeyStatus.textContent = set ? dict['apiKey.set'] : dict['apiKey.notSet'];
317
+ apiKeyStatus.classList.toggle('ok', set);
318
+ }
840
319
 
841
- modelCell.innerHTML = `
842
- Model identifier for the AI provider:<br><br>
843
- <strong>Claude:</strong> ${claudeModels} (default: <code>${CLAUDE_MODELS.DEFAULT}</code>)<br><br>
844
- <strong>Cursor:</strong> ${cursorModels}, and more (default: <code>${CURSOR_MODELS.DEFAULT}</code>)<br><br>
845
- <strong>Codex:</strong> ${codexModels} (default: <code>${CODEX_MODELS.DEFAULT}</code>)
846
- `;
847
- }
848
- });
320
+ // Restore on load.
321
+ const savedKey = localStorage.getItem(STORAGE_KEY) || '';
322
+ if (savedKey) {
323
+ apiKeyInput.value = savedKey;
324
+ setStatus(true);
325
+ } else {
326
+ setStatus(false);
327
+ }
849
328
 
850
- // Tab switching
851
- window.showTab = function(tabName) {
852
- const parentBlock = event.target.closest('.example-block');
853
- if (!parentBlock) return;
329
+ apiKeyInput.addEventListener('input', () => {
330
+ const v = apiKeyInput.value.trim();
331
+ if (v) {
332
+ localStorage.setItem(STORAGE_KEY, v);
333
+ setStatus(true);
334
+ } else {
335
+ localStorage.removeItem(STORAGE_KEY);
336
+ setStatus(false);
337
+ }
338
+ // Re-render Scalar so the new key is prefilled in "Try it" panels.
339
+ renderScalar();
340
+ });
341
+
342
+ // ── Language picker ───────────────────────────────────────────────
343
+ const langSelect = document.getElementById('lang-select');
344
+ langSelect.value = detectLang();
345
+ applyI18n(langSelect.value);
346
+ langSelect.addEventListener('change', () => {
347
+ localStorage.setItem('pixcode-api-docs-lang', langSelect.value);
348
+ applyI18n(langSelect.value);
349
+ setStatus(Boolean(localStorage.getItem(STORAGE_KEY)));
350
+ });
351
+
352
+ // ── Scalar mount ──────────────────────────────────────────────────
353
+ // Scalar API Reference: lightweight, modern, mobile-friendly, built-in
354
+ // try-it panel with auth header support. Loaded from CDN as a single
355
+ // global; no build step required.
356
+ function getCurrentApiKey() {
357
+ return apiKeyInput.value.trim();
358
+ }
854
359
 
855
- parentBlock.querySelectorAll('.tab-content').forEach(tab => {
856
- tab.classList.remove('active');
857
- });
858
- parentBlock.querySelectorAll('.tab-button').forEach(btn => {
859
- btn.classList.remove('active');
860
- });
360
+ function renderScalar() {
361
+ if (!window.Scalar || typeof window.Scalar.createApiReference !== 'function') return;
362
+ const host = document.getElementById('scalar-host');
363
+ host.innerHTML = '';
364
+ window.Scalar.createApiReference(host, {
365
+ url: '/openapi.yaml',
366
+ theme: 'default',
367
+ darkMode: window.matchMedia('(prefers-color-scheme: dark)').matches,
368
+ hideClientButton: true,
369
+ hideDarkModeToggle: false,
370
+ authentication: getCurrentApiKey()
371
+ ? {
372
+ preferredSecurityScheme: 'bearerAuth',
373
+ http: { bearer: { token: getCurrentApiKey() } },
374
+ }
375
+ : undefined,
376
+ defaultHttpClient: { targetKey: 'shell', clientKey: 'curl' },
377
+ // Pixcode's app shell uses absolute /api paths against the same host;
378
+ // Scalar's "Try it" sends to the OpenAPI `servers[0]`. We override to
379
+ // the document origin so the user doesn't need to pick a server.
380
+ servers: [{ url: window.location.origin }],
381
+ });
382
+ }
861
383
 
862
- const targetTab = parentBlock.querySelector('#' + tabName);
863
- if (targetTab) {
864
- targetTab.classList.add('active');
865
- event.target.classList.add('active');
866
- }
867
- };
868
- </script>
384
+ const scalarScript = document.createElement('script');
385
+ scalarScript.src = 'https://cdn.jsdelivr.net/npm/@scalar/api-reference@1';
386
+ scalarScript.onload = renderScalar;
387
+ scalarScript.onerror = () => {
388
+ document.getElementById('scalar-host').innerHTML =
389
+ '<div class="loader"><span>⚠ Scalar CDN unreachable. <a href="/openapi.yaml" style="color:var(--primary)">Download the OpenAPI spec</a> and load it in your own viewer.</span></div>';
390
+ };
391
+ document.head.appendChild(scalarScript);
392
+ </script>
869
393
 
870
- <!-- Prism.js -->
871
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
872
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-bash.min.js"></script>
873
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-javascript.min.js"></script>
874
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
875
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js"></script>
876
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-yaml.min.js"></script>
877
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-http.min.js"></script>
878
394
  </body>
879
395
  </html>