@alphafox/cli 0.2.0 → 0.3.3

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 (73) hide show
  1. package/README.md +42 -4
  2. package/dist/auth/loopback-callback.js +6 -6
  3. package/dist/catalog/command-tree.d.ts +1 -0
  4. package/dist/catalog/command-tree.js +5 -3
  5. package/dist/catalog/validate-body.d.ts +22 -0
  6. package/dist/catalog/validate-body.js +98 -0
  7. package/dist/commands/request-body.d.ts +21 -0
  8. package/dist/commands/request-body.js +92 -0
  9. package/dist/commands/run.js +113 -10
  10. package/dist/engine-backtest/errors.d.ts +18 -0
  11. package/dist/engine-backtest/errors.js +26 -0
  12. package/dist/engine-backtest/fetch-runtime.d.ts +38 -0
  13. package/dist/engine-backtest/fetch-runtime.js +170 -0
  14. package/dist/engine-backtest/native-import.d.ts +1 -0
  15. package/dist/engine-backtest/native-import.js +10 -0
  16. package/dist/engine-backtest/parse-args.d.ts +6 -0
  17. package/dist/engine-backtest/parse-args.js +281 -0
  18. package/dist/engine-backtest/persist.d.ts +32 -0
  19. package/dist/engine-backtest/persist.js +94 -0
  20. package/dist/engine-backtest/replay-timeframe.d.ts +16 -0
  21. package/dist/engine-backtest/replay-timeframe.js +48 -0
  22. package/dist/engine-backtest/resolve-packages.d.ts +27 -0
  23. package/dist/engine-backtest/resolve-packages.js +288 -0
  24. package/dist/engine-backtest/run-command.d.ts +38 -0
  25. package/dist/engine-backtest/run-command.js +540 -0
  26. package/dist/engine-backtest/types.d.ts +249 -0
  27. package/dist/engine-backtest/types.js +2 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.js +16 -1
  30. package/dist/install/exec.d.ts +13 -0
  31. package/dist/install/exec.js +77 -0
  32. package/dist/install/package-root.d.ts +4 -0
  33. package/dist/install/package-root.js +59 -0
  34. package/dist/install/types.d.ts +69 -0
  35. package/dist/install/types.js +26 -0
  36. package/dist/install/wizard.d.ts +21 -0
  37. package/dist/install/wizard.js +330 -0
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/docs/.nojekyll +0 -0
  41. package/docs/alphafox-cli-installation-guide.md +105 -0
  42. package/docs/favicon.svg +4 -0
  43. package/docs/index.html +748 -0
  44. package/docs/logo/alphafox-mark.svg +4 -0
  45. package/docs/logo/alphafox-wordmark-black-en.svg +17 -0
  46. package/docs/logo/alphafox-wordmark-white-en.svg +16 -0
  47. package/docs/release-supply-chain.md +10 -2
  48. package/package.json +7 -2
  49. package/skills/account/SKILL.md +2 -2
  50. package/skills/admin/SKILL.md +2 -2
  51. package/skills/alphafox-shared/SKILL.md +22 -1
  52. package/skills/auth/SKILL.md +1 -1
  53. package/skills/engine-backtest/SKILL.md +71 -0
  54. package/skills/exchange/SKILL.md +2 -2
  55. package/skills/market/SKILL.md +1 -1
  56. package/skills/notification/SKILL.md +2 -2
  57. package/skills/strategy/SKILL.md +10 -2
  58. package/skills/trading/SKILL.md +6 -3
  59. package/vendor/backtest-runner/NOTICE.md +1 -0
  60. package/vendor/backtest-runner/README.md +97 -0
  61. package/vendor/backtest-runner/index.d.ts +423 -0
  62. package/vendor/backtest-runner/index.mjs +59 -0
  63. package/vendor/backtest-runner/lib/abortable.mjs +23 -0
  64. package/vendor/backtest-runner/lib/cache.mjs +159 -0
  65. package/vendor/backtest-runner/lib/coverage.mjs +238 -0
  66. package/vendor/backtest-runner/lib/encode.mjs +28 -0
  67. package/vendor/backtest-runner/lib/exchanges.mjs +143 -0
  68. package/vendor/backtest-runner/lib/proxy.mjs +78 -0
  69. package/vendor/backtest-runner/lib/scenario.mjs +66 -0
  70. package/vendor/backtest-runner/lib/series.mjs +370 -0
  71. package/vendor/backtest-runner/lib/tape-loader.mjs +614 -0
  72. package/vendor/backtest-runner/lib/timeframes.mjs +55 -0
  73. package/vendor/backtest-runner/package.json +13 -0
@@ -0,0 +1,748 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Alphafox CLI</title>
7
+ <meta
8
+ name="description"
9
+ content="仅需一行指令,在任意 Agent 操作 Alphafox。安装 CLI 与 Skills,用 Public Application API 做回测、策略与交易。"
10
+ />
11
+ <meta name="theme-color" content="#FF991F" />
12
+ <link rel="icon" href="favicon.svg" type="image/svg+xml" />
13
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
14
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
15
+ <link
16
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
17
+ rel="stylesheet"
18
+ />
19
+ <script>
20
+ (() => {
21
+ const stored = window.localStorage.getItem("alphafox-cli.theme");
22
+ const theme =
23
+ stored === "light" || stored === "dark"
24
+ ? stored
25
+ : window.matchMedia("(prefers-color-scheme: dark)").matches
26
+ ? "dark"
27
+ : "light";
28
+ document.documentElement.classList.toggle("dark", theme === "dark");
29
+ document.documentElement.style.colorScheme = theme;
30
+ })();
31
+ </script>
32
+ <style>
33
+ :root {
34
+ --background: #eef4fa;
35
+ --foreground: #111111;
36
+ --card: #ffffff;
37
+ --muted: #f2f5f7;
38
+ --muted-foreground: rgb(17 17 17 / 0.64);
39
+ --foreground-soft: rgb(17 17 17 / 0.72);
40
+ --border: rgb(17 17 17 / 0.1);
41
+ --primary: #ff991f;
42
+ --primary-foreground: #ffffff;
43
+ --primary-hover: #f0aa29;
44
+ --brand-cyan: #83e6ff;
45
+ --aurora-mint: #0be5c7;
46
+ --profit: #2fbd85;
47
+ --header-surface: rgb(255 255 255 / 0.72);
48
+ --surface-tint: rgb(17 17 17 / 0.04);
49
+ --radius: 1rem;
50
+ --radius-sm: 0.75rem;
51
+ --sans: Inter, "HarmonyOS Sans SC", "PingFang SC", "Hiragino Sans GB",
52
+ "Microsoft YaHei", "Noto Sans SC", system-ui, sans-serif;
53
+ --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco,
54
+ Consolas, monospace;
55
+ }
56
+
57
+ html.dark {
58
+ --background: #0c0b0a;
59
+ --foreground: #f7f5f2;
60
+ --card: #141210;
61
+ --muted: #1b1815;
62
+ --muted-foreground: rgb(247 245 242 / 0.68);
63
+ --foreground-soft: rgb(247 245 242 / 0.78);
64
+ --border: rgb(255 255 255 / 0.1);
65
+ --header-surface: rgb(12 11 10 / 0.72);
66
+ --surface-tint: rgb(255 255 255 / 0.05);
67
+ }
68
+
69
+ * {
70
+ box-sizing: border-box;
71
+ }
72
+
73
+ html,
74
+ body {
75
+ margin: 0;
76
+ min-height: 100%;
77
+ background: var(--background);
78
+ color: var(--foreground);
79
+ font-family: var(--sans);
80
+ }
81
+
82
+ body {
83
+ min-height: 100vh;
84
+ background:
85
+ radial-gradient(
86
+ 36rem 16rem at 8% -12%,
87
+ color-mix(in oklab, var(--primary) 16%, transparent),
88
+ transparent 68%
89
+ ),
90
+ radial-gradient(
91
+ 28rem 14rem at 100% -8%,
92
+ color-mix(in oklab, var(--brand-cyan) 14%, transparent),
93
+ transparent 64%
94
+ ),
95
+ var(--background);
96
+ }
97
+
98
+ a {
99
+ color: inherit;
100
+ }
101
+
102
+ button,
103
+ a.btn {
104
+ font: inherit;
105
+ }
106
+
107
+ .site-header {
108
+ position: sticky;
109
+ top: 0;
110
+ z-index: 20;
111
+ height: 64px;
112
+ border-bottom: 1px solid var(--border);
113
+ background: var(--header-surface);
114
+ backdrop-filter: blur(20px);
115
+ }
116
+
117
+ .site-header-inner,
118
+ .wrap {
119
+ width: min(52rem, calc(100% - 2rem));
120
+ margin: 0 auto;
121
+ }
122
+
123
+ .site-header-inner {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: space-between;
127
+ height: 100%;
128
+ width: min(76rem, calc(100% - 2rem));
129
+ }
130
+
131
+ .brand {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ gap: 10px;
135
+ min-width: 0;
136
+ color: inherit;
137
+ text-decoration: none;
138
+ }
139
+
140
+ .brand:hover {
141
+ opacity: 0.8;
142
+ }
143
+
144
+ .mark {
145
+ width: 36px;
146
+ height: 36px;
147
+ flex: 0 0 auto;
148
+ object-fit: contain;
149
+ }
150
+
151
+ .wordmark {
152
+ width: 7.6rem;
153
+ height: auto;
154
+ flex: 0 0 auto;
155
+ }
156
+
157
+ .wordmark-dark {
158
+ display: none;
159
+ }
160
+
161
+ html.dark .wordmark-light {
162
+ display: none;
163
+ }
164
+
165
+ html.dark .wordmark-dark {
166
+ display: block;
167
+ }
168
+
169
+ .product {
170
+ display: inline-flex;
171
+ align-items: center;
172
+ height: 22px;
173
+ padding: 0 8px;
174
+ border: 1px solid var(--border);
175
+ border-radius: 999px;
176
+ background: var(--card);
177
+ color: var(--muted-foreground);
178
+ font-size: 11px;
179
+ font-weight: 600;
180
+ letter-spacing: 0.08em;
181
+ }
182
+
183
+ .header-actions {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 6px;
187
+ }
188
+
189
+ .icon-btn {
190
+ display: inline-flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ width: 36px;
194
+ height: 36px;
195
+ padding: 0;
196
+ border: 0;
197
+ border-radius: 999px;
198
+ background: transparent;
199
+ color: var(--muted-foreground);
200
+ cursor: pointer;
201
+ }
202
+
203
+ .icon-btn:hover {
204
+ background: var(--surface-tint);
205
+ color: var(--foreground);
206
+ }
207
+
208
+ .icon-btn svg {
209
+ width: 16px;
210
+ height: 16px;
211
+ }
212
+
213
+ .locale-btn {
214
+ font-family: var(--mono);
215
+ font-size: 11.5px;
216
+ font-weight: 600;
217
+ letter-spacing: 0.08em;
218
+ }
219
+
220
+ .open-app {
221
+ display: inline-flex;
222
+ align-items: center;
223
+ gap: 6px;
224
+ height: 36px;
225
+ padding: 0 16px;
226
+ border: 0;
227
+ border-radius: 999px;
228
+ background: var(--primary);
229
+ color: var(--primary-foreground);
230
+ font-size: 15px;
231
+ font-weight: 600;
232
+ text-decoration: none;
233
+ }
234
+
235
+ .open-app:hover {
236
+ background: var(--primary-hover);
237
+ }
238
+
239
+ .theme-icon-dark,
240
+ html.dark .theme-icon-light {
241
+ display: none;
242
+ }
243
+
244
+ html.dark .theme-icon-dark {
245
+ display: block;
246
+ }
247
+
248
+ .wrap {
249
+ padding: 40px 0 72px;
250
+ }
251
+
252
+ .hero {
253
+ overflow: hidden;
254
+ border: 1px solid var(--border);
255
+ border-radius: calc(var(--radius) + 0.25rem);
256
+ background:
257
+ radial-gradient(
258
+ 36rem 14rem at 6% -20%,
259
+ color-mix(in oklab, var(--primary) 12%, transparent),
260
+ transparent 68%
261
+ ),
262
+ radial-gradient(
263
+ 28rem 12rem at 100% 120%,
264
+ color-mix(in oklab, var(--brand-cyan) 10%, transparent),
265
+ transparent 64%
266
+ ),
267
+ var(--card);
268
+ padding: clamp(1.5rem, 3.2vw, 2.4rem) clamp(1.25rem, 2.8vw, 2.2rem);
269
+ }
270
+
271
+ .kicker {
272
+ margin: 0;
273
+ color: var(--primary);
274
+ font-size: 12px;
275
+ font-weight: 600;
276
+ letter-spacing: 0.04em;
277
+ }
278
+
279
+ .headline {
280
+ margin: 0.4rem 0 0;
281
+ color: var(--foreground);
282
+ font-size: clamp(1.7rem, 4vw, 2.25rem);
283
+ font-weight: 600;
284
+ letter-spacing: -0.02em;
285
+ line-height: 1.18;
286
+ text-wrap: balance;
287
+ }
288
+
289
+ .lede {
290
+ max-width: 40rem;
291
+ margin: 0.75rem 0 0;
292
+ color: var(--muted-foreground);
293
+ font-size: 0.98rem;
294
+ line-height: 1.7;
295
+ text-wrap: pretty;
296
+ }
297
+
298
+ .tabs {
299
+ display: flex;
300
+ flex-wrap: wrap;
301
+ gap: 4px;
302
+ width: fit-content;
303
+ margin: 1.35rem 0 0;
304
+ padding: 4px;
305
+ border: 1px solid var(--border);
306
+ border-radius: 999px;
307
+ background: var(--card);
308
+ }
309
+
310
+ .tab {
311
+ appearance: none;
312
+ border: 0;
313
+ border-radius: 999px;
314
+ background: transparent;
315
+ color: var(--muted-foreground);
316
+ cursor: pointer;
317
+ font-size: 14px;
318
+ font-weight: 600;
319
+ padding: 8px 14px;
320
+ }
321
+
322
+ .tab:hover {
323
+ color: var(--foreground);
324
+ }
325
+
326
+ .tab[aria-selected="true"] {
327
+ background: var(--muted);
328
+ color: var(--foreground);
329
+ }
330
+
331
+ .panel {
332
+ display: none;
333
+ margin-top: 1.1rem;
334
+ }
335
+
336
+ .panel.active {
337
+ display: block;
338
+ }
339
+
340
+ .hint {
341
+ margin: 0 0 12px;
342
+ color: var(--muted-foreground);
343
+ font-size: 14px;
344
+ line-height: 1.6;
345
+ }
346
+
347
+ .cmd {
348
+ display: flex;
349
+ align-items: center;
350
+ gap: 12px;
351
+ padding: 14px 14px 14px 16px;
352
+ border: 1px solid var(--border);
353
+ border-radius: var(--radius);
354
+ background: var(--muted);
355
+ }
356
+
357
+ .cmd code {
358
+ flex: 1;
359
+ color: var(--foreground);
360
+ font-family: var(--mono);
361
+ font-size: 13.5px;
362
+ line-height: 1.55;
363
+ word-break: break-all;
364
+ white-space: pre-wrap;
365
+ }
366
+
367
+ .copy {
368
+ flex: 0 0 auto;
369
+ display: inline-flex;
370
+ align-items: center;
371
+ gap: 6px;
372
+ height: 36px;
373
+ padding: 0 14px;
374
+ border: 0;
375
+ border-radius: 999px;
376
+ background: var(--primary);
377
+ color: var(--primary-foreground);
378
+ cursor: pointer;
379
+ font-size: 13px;
380
+ font-weight: 600;
381
+ }
382
+
383
+ .copy:hover {
384
+ background: var(--primary-hover);
385
+ }
386
+
387
+ .copy.copied {
388
+ background: color-mix(in oklab, var(--profit) 88%, #0b3d28);
389
+ }
390
+
391
+ .copy svg {
392
+ width: 14px;
393
+ height: 14px;
394
+ }
395
+
396
+ .status {
397
+ display: flex;
398
+ align-items: center;
399
+ gap: 8px;
400
+ margin: 18px 0 0;
401
+ color: var(--foreground-soft);
402
+ font-size: 14px;
403
+ }
404
+
405
+ .status svg {
406
+ width: 16px;
407
+ height: 16px;
408
+ color: var(--profit);
409
+ flex: 0 0 auto;
410
+ }
411
+
412
+ .links {
413
+ display: flex;
414
+ flex-wrap: wrap;
415
+ gap: 8px;
416
+ margin-top: 18px;
417
+ }
418
+
419
+ .links a {
420
+ display: inline-flex;
421
+ align-items: center;
422
+ padding: 8px 14px;
423
+ border: 1px solid var(--border);
424
+ border-radius: 999px;
425
+ background: var(--card);
426
+ color: var(--foreground);
427
+ font-size: 14px;
428
+ font-weight: 600;
429
+ text-decoration: none;
430
+ }
431
+
432
+ .links a:hover {
433
+ border-color: color-mix(in oklab, var(--primary) 32%, var(--border));
434
+ background: color-mix(in oklab, var(--primary) 8%, var(--card));
435
+ }
436
+
437
+ .links a.is-primary {
438
+ border-color: transparent;
439
+ background: var(--primary);
440
+ color: var(--primary-foreground);
441
+ }
442
+
443
+ .links a.is-primary:hover {
444
+ background: var(--primary-hover);
445
+ }
446
+
447
+ .site-footer {
448
+ width: min(52rem, calc(100% - 2rem));
449
+ margin: 0 auto;
450
+ padding: 0 0 32px;
451
+ color: var(--muted-foreground);
452
+ font-size: 13px;
453
+ }
454
+
455
+ .site-footer a {
456
+ color: var(--foreground-soft);
457
+ text-decoration: none;
458
+ }
459
+
460
+ .site-footer a:hover {
461
+ color: var(--primary);
462
+ }
463
+
464
+ @media (min-width: 640px) {
465
+ .mark {
466
+ width: 40px;
467
+ height: 40px;
468
+ }
469
+
470
+ .wordmark {
471
+ width: 10.3rem;
472
+ }
473
+ }
474
+
475
+ @media (max-width: 720px) {
476
+ .product {
477
+ display: none;
478
+ }
479
+
480
+ .cmd {
481
+ flex-direction: column;
482
+ align-items: stretch;
483
+ }
484
+
485
+ .copy {
486
+ justify-content: center;
487
+ }
488
+ }
489
+ </style>
490
+ </head>
491
+ <body>
492
+ <header class="site-header">
493
+ <div class="site-header-inner">
494
+ <a class="brand" href="./" aria-label="Alphafox CLI">
495
+ <img class="mark" src="logo/alphafox-mark.svg" alt="" width="36" height="36" />
496
+ <img
497
+ class="wordmark wordmark-light"
498
+ src="logo/alphafox-wordmark-black-en.svg"
499
+ alt=""
500
+ width="210"
501
+ height="40"
502
+ />
503
+ <img
504
+ class="wordmark wordmark-dark"
505
+ src="logo/alphafox-wordmark-white-en.svg"
506
+ alt=""
507
+ width="210"
508
+ height="40"
509
+ />
510
+ <span class="product">CLI</span>
511
+ </a>
512
+ <div class="header-actions">
513
+ <button type="button" class="icon-btn" id="theme-toggle" aria-label="Toggle theme">
514
+ <svg class="theme-icon-light" viewBox="0 0 24 24" fill="none" aria-hidden="true">
515
+ <path
516
+ d="M12 3v2M12 19v2M5 12H3M21 12h-2M6.2 6.2 4.8 4.8M19.2 19.2l-1.4-1.4M17.8 6.2l1.4-1.4M4.8 19.2l1.4-1.4"
517
+ stroke="currentColor"
518
+ stroke-width="1.7"
519
+ stroke-linecap="round"
520
+ />
521
+ <circle cx="12" cy="12" r="3.4" stroke="currentColor" stroke-width="1.7" />
522
+ </svg>
523
+ <svg class="theme-icon-dark" viewBox="0 0 24 24" fill="none" aria-hidden="true">
524
+ <path
525
+ d="M15.4 13.2A6.2 6.2 0 0 1 10.8 4.4 7 7 0 1 0 19.6 13.2a6.2 6.2 0 0 1-4.2 0Z"
526
+ stroke="currentColor"
527
+ stroke-width="1.7"
528
+ stroke-linejoin="round"
529
+ />
530
+ </svg>
531
+ </button>
532
+ <button type="button" class="icon-btn locale-btn" id="lang-toggle" aria-label="Switch language">
533
+ EN
534
+ </button>
535
+ <a class="open-app" href="https://www.alphafox.app" data-i18n="openApp">
536
+ <span class="open-app-label">打开 App</span>
537
+ <svg class="open-app-icon" viewBox="0 0 16 16" width="14" height="14" fill="none" aria-hidden="true">
538
+ <path d="M4.5 11.5 11.5 4.5M6 4.5h5.5V10" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />
539
+ </svg>
540
+ </a>
541
+ </div>
542
+ </div>
543
+ </header>
544
+
545
+ <main class="wrap">
546
+ <section class="hero">
547
+ <p class="kicker">Alphafox CLI</p>
548
+ <h1 class="headline" data-i18n="headline">仅需一行指令,在任意 Agent 操作 Alphafox</h1>
549
+ <p class="lede" data-i18n="lede">
550
+ 安装 CLI 与 Skills,用 Public Application API 做回测、策略与交易。
551
+ </p>
552
+
553
+ <div class="tabs" role="tablist">
554
+ <button class="tab" id="tab-manual" role="tab" aria-selected="true" aria-controls="panel-manual" data-i18n="tabManual">
555
+ 手动安装
556
+ </button>
557
+ <button class="tab" id="tab-agent" role="tab" aria-selected="false" aria-controls="panel-agent" data-i18n="tabAgent">
558
+ 通过 AI Agent 安装
559
+ </button>
560
+ </div>
561
+
562
+ <section class="panel active" id="panel-manual" role="tabpanel" aria-labelledby="tab-manual">
563
+ <p class="hint" data-i18n="manualHint">复制以下命令到终端运行即可完成安装:</p>
564
+ <div class="cmd">
565
+ <code id="manual-cmd">npx @alphafox/cli@latest install</code>
566
+ <button class="copy" type="button" data-copy="manual-cmd">
567
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
568
+ <rect x="5.5" y="5.5" width="8" height="8" rx="1.5" stroke="currentColor" />
569
+ <path d="M10.5 5.5V4A1.5 1.5 0 0 0 9 2.5H4A1.5 1.5 0 0 0 2.5 4v5A1.5 1.5 0 0 0 4 10.5h1.5" stroke="currentColor" />
570
+ </svg>
571
+ <span data-i18n="copy">复制</span>
572
+ </button>
573
+ </div>
574
+ </section>
575
+
576
+ <section class="panel" id="panel-agent" role="tabpanel" aria-labelledby="tab-agent" hidden>
577
+ <p class="hint" data-i18n="agentHint">把下面这段话发给任意 AI Agent,它会按安装指南完成配置:</p>
578
+ <div class="cmd">
579
+ <code id="agent-cmd">帮我安装 Alphafox CLI:https://github.com/alphafoxai/alphafox-cli/blob/main/docs/alphafox-cli-installation-guide.md</code>
580
+ <button class="copy" type="button" data-copy="agent-cmd">
581
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
582
+ <rect x="5.5" y="5.5" width="8" height="8" rx="1.5" stroke="currentColor" />
583
+ <path d="M10.5 5.5V4A1.5 1.5 0 0 0 9 2.5H4A1.5 1.5 0 0 0 2.5 4v5A1.5 1.5 0 0 0 4 10.5h1.5" stroke="currentColor" />
584
+ </svg>
585
+ <span data-i18n="copy">复制</span>
586
+ </button>
587
+ </div>
588
+ </section>
589
+
590
+ <p class="status">
591
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
592
+ <circle cx="8" cy="8" r="6.25" stroke="currentColor" stroke-width="1.4" />
593
+ <path d="M5.2 8.15 7.1 10l3.7-4.2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
594
+ </svg>
595
+ <span data-i18n="status">配置完成后,重启你的 AI Agent 即可开始使用</span>
596
+ </p>
597
+
598
+ <nav class="links">
599
+ <a class="is-primary" href="https://github.com/alphafoxai/alphafox-cli/blob/main/docs/alphafox-cli-installation-guide.md" data-i18n="guide">使用指南</a>
600
+ <a href="https://github.com/alphafoxai/alphafox-cli" data-i18n="source">开源地址</a>
601
+ <a href="https://github.com/alphafoxai/alphafox-cli/releases" data-i18n="changelog">更新日志</a>
602
+ </nav>
603
+ </section>
604
+ </main>
605
+
606
+ <footer class="site-footer">
607
+ <span>© 2026 Alphafox</span>
608
+ ·
609
+ <a href="https://www.alphafox.app">alphafox.app</a>
610
+ </footer>
611
+
612
+ <script>
613
+ const copyLabels = { zh: { idle: "复制", done: "已复制" }, en: { idle: "Copy", done: "Copied" } };
614
+ const i18n = {
615
+ zh: {
616
+ headline: "仅需一行指令,在任意 Agent 操作 Alphafox",
617
+ lede: "安装 CLI 与 Skills,用 Public Application API 做回测、策略与交易。",
618
+ tabManual: "手动安装",
619
+ tabAgent: "通过 AI Agent 安装",
620
+ manualHint: "复制以下命令到终端运行即可完成安装:",
621
+ agentHint: "把下面这段话发给任意 AI Agent,它会按安装指南完成配置:",
622
+ copy: "复制",
623
+ status: "配置完成后,重启你的 AI Agent 即可开始使用",
624
+ guide: "使用指南",
625
+ source: "开源地址",
626
+ changelog: "更新日志",
627
+ openApp: "打开 App",
628
+ themeAria: "切换到深色模式",
629
+ themeAriaDark: "切换到浅色模式",
630
+ langAria: "切换语言",
631
+ agentCmd:
632
+ "帮我安装 Alphafox CLI:https://github.com/alphafoxai/alphafox-cli/blob/main/docs/alphafox-cli-installation-guide.md",
633
+ },
634
+ en: {
635
+ headline: "One command to operate Alphafox from any Agent",
636
+ lede: "Install the CLI and Skills, then run backtests, strategies, and trades through the Public Application API.",
637
+ tabManual: "Manual install",
638
+ tabAgent: "Install via AI Agent",
639
+ manualHint: "Copy this command into your terminal to finish install:",
640
+ agentHint: "Paste this prompt into any AI Agent. It will follow the install guide:",
641
+ copy: "Copy",
642
+ status: "After setup, restart your AI Agent and start using it",
643
+ guide: "Usage guide",
644
+ source: "Source",
645
+ changelog: "Changelog",
646
+ openApp: "Open App",
647
+ themeAria: "Switch to dark mode",
648
+ themeAriaDark: "Switch to light mode",
649
+ langAria: "Switch language",
650
+ agentCmd:
651
+ "Install Alphafox CLI for me: https://github.com/alphafoxai/alphafox-cli/blob/main/docs/alphafox-cli-installation-guide.md",
652
+ },
653
+ };
654
+
655
+ let lang = "zh";
656
+
657
+ function currentTheme() {
658
+ return document.documentElement.classList.contains("dark") ? "dark" : "light";
659
+ }
660
+
661
+ function applyTheme(theme) {
662
+ document.documentElement.classList.toggle("dark", theme === "dark");
663
+ document.documentElement.style.colorScheme = theme;
664
+ window.localStorage.setItem("alphafox-cli.theme", theme);
665
+ syncChrome();
666
+ }
667
+
668
+ function applyLang(next) {
669
+ lang = next;
670
+ document.documentElement.lang = next === "zh" ? "zh-CN" : "en";
671
+ document.querySelectorAll("[data-i18n]").forEach((el) => {
672
+ const key = el.getAttribute("data-i18n");
673
+ if (key === "openApp") {
674
+ const label = el.querySelector(".open-app-label");
675
+ if (label) label.textContent = i18n[next][key];
676
+ return;
677
+ }
678
+ if (i18n[next][key]) el.textContent = i18n[next][key];
679
+ });
680
+ document.getElementById("agent-cmd").textContent = i18n[next].agentCmd;
681
+ document.querySelectorAll(".copy span").forEach((span) => {
682
+ span.textContent = copyLabels[next].idle;
683
+ });
684
+ syncChrome();
685
+ }
686
+
687
+ function syncChrome() {
688
+ const themeBtn = document.getElementById("theme-toggle");
689
+ const langBtn = document.getElementById("lang-toggle");
690
+ themeBtn.setAttribute(
691
+ "aria-label",
692
+ currentTheme() === "dark" ? i18n[lang].themeAriaDark : i18n[lang].themeAria
693
+ );
694
+ langBtn.setAttribute("aria-label", i18n[lang].langAria);
695
+ langBtn.textContent = lang === "zh" ? "EN" : "CH";
696
+ }
697
+
698
+ document.getElementById("theme-toggle").addEventListener("click", () => {
699
+ applyTheme(currentTheme() === "dark" ? "light" : "dark");
700
+ });
701
+ document.getElementById("lang-toggle").addEventListener("click", () => {
702
+ applyLang(lang === "zh" ? "en" : "zh");
703
+ });
704
+
705
+ const tabs = [
706
+ { btn: document.getElementById("tab-manual"), panel: document.getElementById("panel-manual") },
707
+ { btn: document.getElementById("tab-agent"), panel: document.getElementById("panel-agent") },
708
+ ];
709
+
710
+ function selectTab(target) {
711
+ tabs.forEach(({ btn, panel }) => {
712
+ const on = btn === target;
713
+ btn.setAttribute("aria-selected", String(on));
714
+ panel.classList.toggle("active", on);
715
+ panel.hidden = !on;
716
+ });
717
+ }
718
+
719
+ tabs.forEach(({ btn }) => btn.addEventListener("click", () => selectTab(btn)));
720
+
721
+ document.querySelectorAll("[data-copy]").forEach((button) => {
722
+ button.addEventListener("click", async () => {
723
+ const id = button.getAttribute("data-copy");
724
+ const text = document.getElementById(id).textContent;
725
+ try {
726
+ await navigator.clipboard.writeText(text);
727
+ } catch {
728
+ const area = document.createElement("textarea");
729
+ area.value = text;
730
+ document.body.appendChild(area);
731
+ area.select();
732
+ document.execCommand("copy");
733
+ area.remove();
734
+ }
735
+ button.classList.add("copied");
736
+ const label = button.querySelector("span");
737
+ label.textContent = copyLabels[lang].done;
738
+ setTimeout(() => {
739
+ button.classList.remove("copied");
740
+ label.textContent = copyLabels[lang].idle;
741
+ }, 1600);
742
+ });
743
+ });
744
+
745
+ syncChrome();
746
+ </script>
747
+ </body>
748
+ </html>