@chrysb/alphaclaw 0.2.3 → 0.3.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 (63) hide show
  1. package/bin/alphaclaw.js +79 -0
  2. package/lib/public/css/shell.css +57 -2
  3. package/lib/public/css/theme.css +184 -0
  4. package/lib/public/js/app.js +330 -89
  5. package/lib/public/js/components/action-button.js +92 -0
  6. package/lib/public/js/components/channels.js +16 -7
  7. package/lib/public/js/components/confirm-dialog.js +25 -19
  8. package/lib/public/js/components/credentials-modal.js +32 -23
  9. package/lib/public/js/components/device-pairings.js +15 -2
  10. package/lib/public/js/components/envars.js +22 -65
  11. package/lib/public/js/components/features.js +1 -1
  12. package/lib/public/js/components/gateway.js +139 -32
  13. package/lib/public/js/components/global-restart-banner.js +31 -0
  14. package/lib/public/js/components/google.js +9 -9
  15. package/lib/public/js/components/icons.js +19 -0
  16. package/lib/public/js/components/info-tooltip.js +18 -0
  17. package/lib/public/js/components/loading-spinner.js +32 -0
  18. package/lib/public/js/components/modal-shell.js +42 -0
  19. package/lib/public/js/components/models.js +34 -29
  20. package/lib/public/js/components/onboarding/welcome-form-step.js +45 -32
  21. package/lib/public/js/components/onboarding/welcome-pairing-step.js +2 -2
  22. package/lib/public/js/components/onboarding/welcome-setup-step.js +7 -24
  23. package/lib/public/js/components/page-header.js +13 -0
  24. package/lib/public/js/components/pairings.js +15 -2
  25. package/lib/public/js/components/providers.js +216 -142
  26. package/lib/public/js/components/scope-picker.js +1 -1
  27. package/lib/public/js/components/secret-input.js +1 -0
  28. package/lib/public/js/components/telegram-workspace.js +37 -49
  29. package/lib/public/js/components/toast.js +34 -5
  30. package/lib/public/js/components/toggle-switch.js +25 -0
  31. package/lib/public/js/components/update-action-button.js +13 -53
  32. package/lib/public/js/components/watchdog-tab.js +312 -0
  33. package/lib/public/js/components/webhooks.js +981 -0
  34. package/lib/public/js/components/welcome.js +2 -1
  35. package/lib/public/js/lib/api.js +102 -1
  36. package/lib/public/js/lib/model-config.js +0 -5
  37. package/lib/server/alphaclaw-version.js +5 -3
  38. package/lib/server/constants.js +33 -0
  39. package/lib/server/discord-api.js +48 -0
  40. package/lib/server/gateway.js +64 -4
  41. package/lib/server/log-writer.js +102 -0
  42. package/lib/server/onboarding/github.js +21 -1
  43. package/lib/server/openclaw-version.js +2 -6
  44. package/lib/server/restart-required-state.js +86 -0
  45. package/lib/server/routes/auth.js +9 -4
  46. package/lib/server/routes/proxy.js +12 -14
  47. package/lib/server/routes/system.js +61 -15
  48. package/lib/server/routes/telegram.js +17 -48
  49. package/lib/server/routes/watchdog.js +68 -0
  50. package/lib/server/routes/webhooks.js +214 -0
  51. package/lib/server/telegram-api.js +11 -0
  52. package/lib/server/watchdog-db.js +148 -0
  53. package/lib/server/watchdog-notify.js +93 -0
  54. package/lib/server/watchdog.js +585 -0
  55. package/lib/server/webhook-middleware.js +195 -0
  56. package/lib/server/webhooks-db.js +265 -0
  57. package/lib/server/webhooks.js +238 -0
  58. package/lib/server.js +119 -4
  59. package/lib/setup/core-prompts/AGENTS.md +84 -0
  60. package/lib/setup/core-prompts/TOOLS.md +13 -0
  61. package/lib/setup/core-prompts/UI-DRY-OPPORTUNITIES.md +50 -0
  62. package/lib/setup/gitignore +2 -0
  63. package/package.json +2 -1
package/bin/alphaclaw.js CHANGED
@@ -660,6 +660,85 @@ if (fs.existsSync(configPath)) {
660
660
  console.log("[alphaclaw] Scrubbed tokenized GitHub remote URL");
661
661
  }
662
662
  } catch {}
663
+
664
+ const bootRestoreConfigFromRemote = () => {
665
+ const branch = (() => {
666
+ try {
667
+ return (
668
+ String(
669
+ execSync("git symbolic-ref --short HEAD", {
670
+ cwd: openclawDir,
671
+ stdio: ["ignore", "pipe", "ignore"],
672
+ encoding: "utf8",
673
+ }),
674
+ ).trim() || "main"
675
+ );
676
+ } catch {
677
+ return "main";
678
+ }
679
+ })();
680
+ const githubToken = String(process.env.GITHUB_TOKEN || "").trim();
681
+ const gitEnv = { ...process.env };
682
+ const askPassPath = path.join(
683
+ os.tmpdir(),
684
+ `alphaclaw-boot-git-askpass-${process.pid}.sh`,
685
+ );
686
+ try {
687
+ if (githubToken) {
688
+ fs.writeFileSync(
689
+ askPassPath,
690
+ [
691
+ "#!/usr/bin/env sh",
692
+ 'case "$1" in',
693
+ ' *Username*) echo "x-access-token" ;;',
694
+ ' *Password*) echo "${GITHUB_TOKEN:-}" ;;',
695
+ ' *) echo "" ;;',
696
+ "esac",
697
+ "",
698
+ ].join("\n"),
699
+ { mode: 0o700 },
700
+ );
701
+ gitEnv.GITHUB_TOKEN = githubToken;
702
+ gitEnv.GIT_TERMINAL_PROMPT = "0";
703
+ gitEnv.GIT_ASKPASS = askPassPath;
704
+ }
705
+ execSync(`git ls-remote --exit-code --heads origin "${branch}"`, {
706
+ cwd: openclawDir,
707
+ stdio: "ignore",
708
+ env: gitEnv,
709
+ });
710
+ execSync(`git fetch --quiet origin "${branch}"`, {
711
+ cwd: openclawDir,
712
+ stdio: "ignore",
713
+ env: gitEnv,
714
+ });
715
+ const remoteConfig = String(
716
+ execSync(`git show "origin/${branch}:openclaw.json"`, {
717
+ cwd: openclawDir,
718
+ stdio: ["ignore", "pipe", "ignore"],
719
+ encoding: "utf8",
720
+ env: gitEnv,
721
+ }),
722
+ );
723
+ if (remoteConfig.trim()) {
724
+ fs.writeFileSync(configPath, remoteConfig);
725
+ console.log(
726
+ `[alphaclaw] Restored openclaw.json from origin/${branch}`,
727
+ );
728
+ }
729
+ } catch (e) {
730
+ console.log(
731
+ `[alphaclaw] Remote config restore skipped: ${String(e.message || "").slice(0, 200)}`,
732
+ );
733
+ } finally {
734
+ if (githubToken) {
735
+ try {
736
+ fs.rmSync(askPassPath, { force: true });
737
+ } catch {}
738
+ }
739
+ }
740
+ };
741
+ bootRestoreConfigFromRemote();
663
742
  }
664
743
 
665
744
  try {
@@ -3,13 +3,46 @@
3
3
  .app-shell {
4
4
  display: grid;
5
5
  grid-template-columns: 220px 1fr;
6
- grid-template-rows: 1fr 24px;
6
+ grid-template-rows: auto 1fr 24px;
7
7
  height: 100vh;
8
8
  position: relative;
9
9
  z-index: 1;
10
10
  }
11
11
 
12
+ .global-restart-banner {
13
+ grid-column: 1 / -1;
14
+ grid-row: 1;
15
+ background: rgba(234, 179, 8, 0.08);
16
+ border-bottom: 1px solid rgba(234, 179, 8, 0.32);
17
+ padding: 10px 32px;
18
+ }
19
+
20
+ .global-restart-banner__content {
21
+ margin: 0 auto;
22
+ max-width: 900px;
23
+ position: relative;
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ gap: 12px;
28
+ min-height: 28px;
29
+ }
30
+
31
+ .global-restart-banner__text {
32
+ font-size: 12px;
33
+ color: #fde68a;
34
+ text-align: center;
35
+ }
36
+
37
+ .global-restart-banner__button {
38
+ position: absolute;
39
+ right: 0;
40
+ top: 50%;
41
+ transform: translateY(-50%);
42
+ }
43
+
12
44
  .app-content {
45
+ grid-row: 2;
13
46
  overflow-y: auto;
14
47
  padding: 24px 32px;
15
48
  position: relative;
@@ -19,6 +52,7 @@
19
52
  /* ── Sidebar ───────────────────────────────────── */
20
53
 
21
54
  .app-sidebar {
55
+ grid-row: 2;
22
56
  background:
23
57
  linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.012) 100%),
24
58
  var(--bg-sidebar);
@@ -159,6 +193,7 @@
159
193
  /* ── Statusbar ─────────────────────────────────── */
160
194
 
161
195
  .app-statusbar {
196
+ grid-row: 3;
162
197
  grid-column: 1 / -1;
163
198
  background: var(--bg-sidebar);
164
199
  border-top: 1px solid var(--border-strong);
@@ -211,8 +246,28 @@
211
246
  /* ── Responsive ────────────────────────────────── */
212
247
 
213
248
  @media (max-width: 768px) {
214
- .app-shell { grid-template-columns: 1fr; }
249
+ .app-shell {
250
+ grid-template-columns: 1fr;
251
+ grid-template-rows: auto 1fr 24px;
252
+ }
253
+ .global-restart-banner {
254
+ padding: 10px 14px;
255
+ }
256
+ .global-restart-banner__content {
257
+ max-width: none;
258
+ align-items: flex-start;
259
+ flex-direction: column;
260
+ min-height: 0;
261
+ }
262
+ .global-restart-banner__text {
263
+ text-align: left;
264
+ }
265
+ .global-restart-banner__button {
266
+ position: static;
267
+ transform: none;
268
+ }
215
269
  .app-content {
270
+ grid-row: 2;
216
271
  padding: 0 14px 12px;
217
272
  }
218
273
 
@@ -86,6 +86,15 @@ textarea:focus {
86
86
  ::-webkit-scrollbar-track { background: transparent; }
87
87
  ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.08); border-radius: 3px; }
88
88
 
89
+ .scrollbar-hidden {
90
+ -ms-overflow-style: none;
91
+ scrollbar-width: none;
92
+ }
93
+
94
+ .scrollbar-hidden::-webkit-scrollbar {
95
+ display: none;
96
+ }
97
+
89
98
  /* Google scope picker toggle buttons */
90
99
  .scope-btn { background: rgba(255,255,255,0.03); color: var(--text-muted); border: 1px solid var(--border); transition: all 0.15s; }
91
100
  .scope-btn:hover { border-color: var(--text-dim); color: var(--text); }
@@ -182,6 +191,159 @@ textarea:focus {
182
191
  cursor: not-allowed;
183
192
  }
184
193
 
194
+ .ac-btn-ghost {
195
+ border: none;
196
+ color: var(--text-muted);
197
+ background: transparent;
198
+ transition: color 0.15s ease;
199
+ }
200
+
201
+ .ac-btn-ghost:hover:not(:disabled) {
202
+ color: #f3f4f6;
203
+ }
204
+
205
+ .ac-btn-ghost:disabled {
206
+ opacity: 0.5;
207
+ cursor: not-allowed;
208
+ }
209
+
210
+ .ac-btn-danger {
211
+ border: 1px solid rgba(239, 68, 68, 0.45);
212
+ background: rgba(239, 68, 68, 0.08);
213
+ color: #fca5a5;
214
+ transition:
215
+ border-color 0.15s ease,
216
+ color 0.15s ease,
217
+ background 0.15s ease,
218
+ transform 0.15s ease;
219
+ }
220
+
221
+ .ac-btn-danger:hover:not(:disabled) {
222
+ border-color: rgba(239, 68, 68, 0.7);
223
+ background: rgba(239, 68, 68, 0.14);
224
+ color: #fecaca;
225
+ }
226
+
227
+ .ac-btn-danger:active:not(:disabled) {
228
+ transform: translateY(1px);
229
+ }
230
+
231
+ .ac-btn-danger:disabled {
232
+ opacity: 0.5;
233
+ cursor: not-allowed;
234
+ }
235
+
236
+ .ac-toggle {
237
+ display: inline-flex;
238
+ align-items: center;
239
+ gap: 8px;
240
+ cursor: pointer;
241
+ user-select: none;
242
+ }
243
+
244
+ .ac-toggle-input {
245
+ position: absolute;
246
+ width: 1px;
247
+ height: 1px;
248
+ opacity: 0;
249
+ pointer-events: none;
250
+ }
251
+
252
+ .ac-toggle-track {
253
+ position: relative;
254
+ width: 34px;
255
+ height: 20px;
256
+ border-radius: 999px;
257
+ border: 1px solid var(--panel-border-contrast);
258
+ background: rgba(0, 0, 0, 0.35);
259
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02);
260
+ transition:
261
+ border-color 0.18s ease,
262
+ background-color 0.18s ease,
263
+ box-shadow 0.18s ease;
264
+ }
265
+
266
+ .ac-toggle-thumb {
267
+ position: absolute;
268
+ top: 2px;
269
+ left: 2px;
270
+ width: 14px;
271
+ height: 14px;
272
+ border-radius: 999px;
273
+ background: #94a3b8;
274
+ box-shadow: 0 0 0 1px rgba(15, 21, 33, 0.3);
275
+ transition:
276
+ transform 0.18s ease,
277
+ background-color 0.18s ease,
278
+ box-shadow 0.18s ease;
279
+ }
280
+
281
+ .ac-toggle-label {
282
+ font-size: 12px;
283
+ color: #d1d5db;
284
+ }
285
+
286
+ .ac-toggle-input:checked + .ac-toggle-track {
287
+ border-color: rgba(99, 235, 255, 0.8);
288
+ background: rgba(99, 235, 255, 0.16);
289
+ box-shadow:
290
+ inset 0 0 0 1px rgba(99, 235, 255, 0.2),
291
+ 0 0 10px rgba(99, 235, 255, 0.2);
292
+ }
293
+
294
+ .ac-toggle-input:checked + .ac-toggle-track .ac-toggle-thumb {
295
+ transform: translateX(14px);
296
+ background: #b6f6ff;
297
+ box-shadow:
298
+ 0 0 0 1px rgba(15, 21, 33, 0.25),
299
+ 0 0 10px rgba(99, 235, 255, 0.45);
300
+ }
301
+
302
+ .ac-toggle-input:focus-visible + .ac-toggle-track {
303
+ outline: 2px solid rgba(99, 235, 255, 0.55);
304
+ outline-offset: 2px;
305
+ }
306
+
307
+ .ac-toggle-input:disabled + .ac-toggle-track {
308
+ opacity: 0.55;
309
+ box-shadow: none;
310
+ }
311
+
312
+ .ac-toggle-input:disabled + .ac-toggle-track + .ac-toggle-label {
313
+ opacity: 0.6;
314
+ }
315
+
316
+ @keyframes acStatusDotPulse {
317
+ 0%,
318
+ 100% {
319
+ transform: scale(1);
320
+ box-shadow:
321
+ 0 0 0 0 rgba(34, 197, 94, 0.14),
322
+ 0 0 5px rgba(34, 197, 94, 0.18);
323
+ }
324
+ 50% {
325
+ transform: scale(1.08);
326
+ box-shadow:
327
+ 0 0 0 3px rgba(34, 197, 94, 0.08),
328
+ 0 0 9px rgba(34, 197, 94, 0.32);
329
+ }
330
+ }
331
+
332
+ .ac-status-dot {
333
+ width: 8px;
334
+ height: 8px;
335
+ border-radius: 999px;
336
+ }
337
+
338
+ .ac-status-dot--healthy {
339
+ background: #22c55e;
340
+ animation: acStatusDotPulse 2.6s ease-in-out infinite;
341
+ }
342
+
343
+ .ac-status-dot--healthy-offset {
344
+ animation-delay: 0.95s;
345
+ }
346
+
185
347
  .ac-btn-green {
186
348
  border: 1px solid rgba(34, 197, 94, 0.45);
187
349
  background: linear-gradient(
@@ -215,3 +377,25 @@ textarea:focus {
215
377
  .ac-btn-green:active:not(:disabled) {
216
378
  transform: translateY(1px);
217
379
  }
380
+
381
+ @keyframes acSpinnerOrbit {
382
+ 0% {
383
+ transform: rotate(0deg);
384
+ }
385
+ 100% {
386
+ transform: rotate(360deg);
387
+ }
388
+ }
389
+
390
+ .ac-spinner {
391
+ animation: acSpinnerOrbit 1s cubic-bezier(0.3, 0.2, 0.7, 0.8) infinite;
392
+ transform-origin: center;
393
+ will-change: transform;
394
+ }
395
+
396
+ @media (prefers-reduced-motion: reduce) {
397
+ .ac-spinner {
398
+ animation-duration: 1.8s;
399
+ animation-timing-function: linear;
400
+ }
401
+ }