@chrysb/alphaclaw 0.2.3 → 0.3.1
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.
- package/LICENSE +21 -0
- package/README.md +179 -0
- package/bin/alphaclaw.js +79 -0
- package/lib/public/css/shell.css +57 -2
- package/lib/public/css/theme.css +231 -0
- package/lib/public/js/app.js +330 -89
- package/lib/public/js/components/action-button.js +92 -0
- package/lib/public/js/components/channels.js +16 -7
- package/lib/public/js/components/confirm-dialog.js +25 -19
- package/lib/public/js/components/credentials-modal.js +32 -23
- package/lib/public/js/components/device-pairings.js +15 -2
- package/lib/public/js/components/envars.js +22 -65
- package/lib/public/js/components/features.js +1 -1
- package/lib/public/js/components/gateway.js +139 -32
- package/lib/public/js/components/global-restart-banner.js +31 -0
- package/lib/public/js/components/google.js +9 -9
- package/lib/public/js/components/icons.js +19 -0
- package/lib/public/js/components/info-tooltip.js +18 -0
- package/lib/public/js/components/loading-spinner.js +32 -0
- package/lib/public/js/components/modal-shell.js +42 -0
- package/lib/public/js/components/models.js +34 -29
- package/lib/public/js/components/onboarding/welcome-form-step.js +45 -32
- package/lib/public/js/components/onboarding/welcome-pairing-step.js +2 -2
- package/lib/public/js/components/onboarding/welcome-setup-step.js +7 -24
- package/lib/public/js/components/page-header.js +13 -0
- package/lib/public/js/components/pairings.js +15 -2
- package/lib/public/js/components/providers.js +216 -142
- package/lib/public/js/components/scope-picker.js +1 -1
- package/lib/public/js/components/secret-input.js +1 -0
- package/lib/public/js/components/telegram-workspace.js +37 -49
- package/lib/public/js/components/toast.js +34 -5
- package/lib/public/js/components/toggle-switch.js +25 -0
- package/lib/public/js/components/update-action-button.js +13 -53
- package/lib/public/js/components/watchdog-tab.js +312 -0
- package/lib/public/js/components/webhooks.js +1010 -0
- package/lib/public/js/components/welcome.js +2 -1
- package/lib/public/js/lib/api.js +102 -1
- package/lib/public/js/lib/model-config.js +0 -5
- package/lib/server/alphaclaw-version.js +5 -3
- package/lib/server/constants.js +35 -0
- package/lib/server/discord-api.js +48 -0
- package/lib/server/gateway.js +64 -4
- package/lib/server/log-writer.js +102 -0
- package/lib/server/onboarding/github.js +21 -1
- package/lib/server/openclaw-version.js +2 -6
- package/lib/server/restart-required-state.js +86 -0
- package/lib/server/routes/auth.js +9 -4
- package/lib/server/routes/proxy.js +12 -14
- package/lib/server/routes/system.js +61 -15
- package/lib/server/routes/telegram.js +17 -48
- package/lib/server/routes/watchdog.js +68 -0
- package/lib/server/routes/webhooks.js +214 -0
- package/lib/server/telegram-api.js +11 -0
- package/lib/server/watchdog-db.js +148 -0
- package/lib/server/watchdog-notify.js +93 -0
- package/lib/server/watchdog.js +585 -0
- package/lib/server/webhook-middleware.js +195 -0
- package/lib/server/webhooks-db.js +265 -0
- package/lib/server/webhooks.js +238 -0
- package/lib/server.js +119 -4
- package/lib/setup/core-prompts/AGENTS.md +84 -0
- package/lib/setup/core-prompts/TOOLS.md +13 -0
- package/lib/setup/core-prompts/UI-DRY-OPPORTUNITIES.md +50 -0
- package/lib/setup/gitignore +2 -0
- package/package.json +11 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 chrysb
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img width="771" height="339" alt="image" src="https://github.com/user-attachments/assets/99e194dd-902b-46db-ad0c-aaf723592271" />
|
|
3
|
+
</p>
|
|
4
|
+
<h1 align="center">AlphaClaw</h1>
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>The ops layer for OpenClaw. Deploy in minutes. Stay running for months.</strong><br>
|
|
7
|
+
<strong>Observability. Reliability. Agent discipline. Zero SSH rescue missions.</strong>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://github.com/chrysb/alphaclaw/actions/workflows/ci.yml"><img src="https://github.com/chrysb/alphaclaw/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/@chrysb/alphaclaw"><img src="https://img.shields.io/npm/v/@chrysb/alphaclaw" alt="npm version" /></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" /></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">AlphaClaw wraps <a href="https://github.com/openclaw/openclaw">OpenClaw</a> with a convenient setup wizard, self-healing watchdog, Git-backed rollback, and full browser-based observability. Ships with anti-drift prompt hardening to keep your agent disciplined, and simplifies integrations (e.g. Google Workspace, Telegram Topics) so you can manage everything from one UI instead of config files.</p>
|
|
17
|
+
|
|
18
|
+
<p align="center"><em>First deploy to first message in under five minutes.</em></p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="https://railway.com/deploy/openclaw-fast-start?referralCode=jcFhp_&utm_medium=integration&utm_source=template&utm_campaign=generic"><img src="https://railway.com/button.svg" alt="Deploy on Railway" /></a>
|
|
22
|
+
<a href="https://render.com/deploy?repo=https://github.com/chrysb/openclaw-render-template"><img src="https://render.com/images/deploy-to-render-button.svg" alt="Deploy to Render" /></a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
> **Platform:** AlphaClaw currently targets Docker/Linux deployments. macOS local development is not yet supported.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- **Setup UI:** Password-protected web dashboard for onboarding, configuration, and day-to-day management.
|
|
30
|
+
- **Guided Onboarding:** Step-by-step setup wizard — model selection, provider credentials, GitHub repo, channel pairing.
|
|
31
|
+
- **Gateway Manager:** Spawns, monitors, restarts, and proxies the OpenClaw gateway as a managed child process.
|
|
32
|
+
- **Watchdog:** Crash detection, crash-loop recovery, auto-repair (`openclaw doctor --fix`), and Telegram/Discord notifications.
|
|
33
|
+
- **Channel Orchestration:** Telegram and Discord bot pairing, credential sync, and a guided wizard for splitting Telegram into multi-threaded topic groups as your usage grows.
|
|
34
|
+
- **Webhooks:** Named webhook endpoints with per-hook transform modules, request logging, and payload inspection.
|
|
35
|
+
- **Google Workspace:** OAuth integration for Gmail, Calendar, Drive, Docs, Sheets, Tasks, Contacts, and Meet.
|
|
36
|
+
- **Prompt Hardening:** Ships anti-drift bootstrap prompts (`AGENTS.md`, `TOOLS.md`) injected into your agent's system prompt on every message — enforcing safe practices, commit discipline, and change summaries out of the box.
|
|
37
|
+
- **Git Sync:** Automatic hourly commits of your OpenClaw workspace to GitHub with configurable cron schedule. Combined with prompt hardening, every agent action is version-controlled and auditable.
|
|
38
|
+
- **Version Management:** In-place updates for both AlphaClaw and OpenClaw with changelog review and one-click apply.
|
|
39
|
+
- **Codex OAuth:** Built-in PKCE flow for OpenAI Codex CLI model access.
|
|
40
|
+
|
|
41
|
+
## Why AlphaClaw
|
|
42
|
+
|
|
43
|
+
- **Zero to production in one deploy:** Railway/Render templates ship a complete stack — no manual gateway setup.
|
|
44
|
+
- **Self-healing:** Watchdog detects crashes, enters repair mode, relaunches the gateway, and notifies you.
|
|
45
|
+
- **Everything in the browser:** No SSH, no config files to hand-edit, no CLI required after first deploy.
|
|
46
|
+
- **Stays out of the way:** AlphaClaw manages infrastructure; OpenClaw handles the AI.
|
|
47
|
+
|
|
48
|
+
## No Lock-in. Eject Anytime.
|
|
49
|
+
|
|
50
|
+
AlphaClaw writes standard OpenClaw config (`openclaw.json`, `.env`). Remove AlphaClaw and your agent keeps running — nothing proprietary, nothing to migrate.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
### Deploy (recommended)
|
|
57
|
+
|
|
58
|
+
[](https://railway.com/deploy/openclaw-fast-start?referralCode=jcFhp_&utm_medium=integration&utm_source=template&utm_campaign=generic)
|
|
59
|
+
[](https://render.com/deploy?repo=https://github.com/chrysb/openclaw-render-template)
|
|
60
|
+
|
|
61
|
+
Set `SETUP_PASSWORD` at deploy time and visit your deployment URL. The welcome wizard handles the rest.
|
|
62
|
+
|
|
63
|
+
### Local / Docker
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install @chrysb/alphaclaw
|
|
67
|
+
npx alphaclaw start
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or with Docker:
|
|
71
|
+
|
|
72
|
+
```dockerfile
|
|
73
|
+
FROM node:22-slim
|
|
74
|
+
RUN apt-get update && apt-get install -y git curl procps cron && rm -rf /var/lib/apt/lists/*
|
|
75
|
+
WORKDIR /app
|
|
76
|
+
COPY package.json ./
|
|
77
|
+
RUN npm install --omit=dev
|
|
78
|
+
ENV PATH="/app/node_modules/.bin:$PATH"
|
|
79
|
+
ENV ALPHACLAW_ROOT_DIR=/data
|
|
80
|
+
EXPOSE 3000
|
|
81
|
+
CMD ["alphaclaw", "start"]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Setup UI
|
|
85
|
+
|
|
86
|
+
| Tab | What it manages |
|
|
87
|
+
| ------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
88
|
+
| **General** | Gateway status, channel health, pending pairings, Google Workspace, repo sync schedule, OpenClaw dashboard |
|
|
89
|
+
| **Watchdog** | Health monitoring, crash-loop status, auto-repair toggle, notifications toggle, event log, live log tail |
|
|
90
|
+
| **Providers** | AI provider credentials (Anthropic, OpenAI, Gemini, Mistral, Voyage, Groq, Deepgram) and model selection |
|
|
91
|
+
| **Envars** | Environment variables — view, edit, add — with gateway restart prompts |
|
|
92
|
+
| **Webhooks** | Webhook endpoints, transform modules, request history, payload inspection |
|
|
93
|
+
|
|
94
|
+
## CLI
|
|
95
|
+
|
|
96
|
+
| Command | Description |
|
|
97
|
+
| ---------------------------------------------------------- | --------------------------------------------- |
|
|
98
|
+
| `alphaclaw start` | Start the server (Setup UI + gateway manager) |
|
|
99
|
+
| `alphaclaw git-sync -m "message"` | Commit and push the OpenClaw workspace |
|
|
100
|
+
| `alphaclaw telegram topic add --thread <id> --name <text>` | Register a Telegram topic mapping |
|
|
101
|
+
| `alphaclaw version` | Print version |
|
|
102
|
+
| `alphaclaw help` | Show help |
|
|
103
|
+
|
|
104
|
+
## Architecture
|
|
105
|
+
|
|
106
|
+
```mermaid
|
|
107
|
+
graph TD
|
|
108
|
+
subgraph AlphaClaw
|
|
109
|
+
UI["Setup UI<br/><small>Preact + htm + Wouter</small>"]
|
|
110
|
+
WD["Watchdog<br/><small>Crash recovery · Notifications</small>"]
|
|
111
|
+
WH["Webhooks<br/><small>Transforms · Request logging</small>"]
|
|
112
|
+
UI --> API
|
|
113
|
+
WD --> API
|
|
114
|
+
WH --> API
|
|
115
|
+
API["Express Server<br/><small>JSON APIs · Auth · Proxy</small>"]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
API -- "proxy" --> GW["OpenClaw Gateway<br/><small>Child process · 127.0.0.1:18789</small>"]
|
|
119
|
+
GW --> DATA["ALPHACLAW_ROOT_DIR<br/><small>.openclaw/ · .env · logs · SQLite</small>"]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Watchdog
|
|
123
|
+
|
|
124
|
+
The built-in watchdog monitors gateway health and recovers from failures automatically.
|
|
125
|
+
|
|
126
|
+
| Capability | Details |
|
|
127
|
+
| --------------------------- | -------------------------------------------------------------- |
|
|
128
|
+
| **Health checks** | Periodic `openclaw health` with configurable interval |
|
|
129
|
+
| **Crash detection** | Listens for gateway exit events |
|
|
130
|
+
| **Crash-loop detection** | Threshold-based (default: 3 crashes in 300s) |
|
|
131
|
+
| **Auto-repair** | Runs `openclaw doctor --fix --yes`, relaunches gateway |
|
|
132
|
+
| **Notifications** | Telegram and Discord alerts for crashes, repairs, and recovery |
|
|
133
|
+
| **Event log** | SQLite-backed incident history with API and UI access |
|
|
134
|
+
|
|
135
|
+
## Environment Variables
|
|
136
|
+
|
|
137
|
+
| Variable | Required | Description |
|
|
138
|
+
| --------------------------------- | -------- | -------------------------------------------------- |
|
|
139
|
+
| `SETUP_PASSWORD` | Yes | Password for the Setup UI |
|
|
140
|
+
| `OPENCLAW_GATEWAY_TOKEN` | Auto | Gateway auth token (auto-generated if unset) |
|
|
141
|
+
| `GITHUB_TOKEN` | Yes | GitHub PAT for workspace repo |
|
|
142
|
+
| `GITHUB_WORKSPACE_REPO` | Yes | GitHub repo for workspace sync (e.g. `owner/repo`) |
|
|
143
|
+
| `TELEGRAM_BOT_TOKEN` | Optional | Telegram bot token |
|
|
144
|
+
| `DISCORD_BOT_TOKEN` | Optional | Discord bot token |
|
|
145
|
+
| `WATCHDOG_AUTO_REPAIR` | Optional | Enable auto-repair on crash (`true`/`false`) |
|
|
146
|
+
| `WATCHDOG_NOTIFICATIONS_DISABLED` | Optional | Disable watchdog notifications (`true`/`false`) |
|
|
147
|
+
| `PORT` | Optional | Server port (default `3000`) |
|
|
148
|
+
| `ALPHACLAW_ROOT_DIR` | Optional | Data directory (default `/data`) |
|
|
149
|
+
| `TRUST_PROXY_HOPS` | Optional | Trust proxy hop count for correct client IP |
|
|
150
|
+
|
|
151
|
+
## Security Notes
|
|
152
|
+
|
|
153
|
+
AlphaClaw is a convenience wrapper — it intentionally trades some of OpenClaw's default hardening for ease of setup. You should understand what's different:
|
|
154
|
+
|
|
155
|
+
| Area | What AlphaClaw does | Trade-off |
|
|
156
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
157
|
+
| **Setup password** | All gateway access is gated behind a single `SETUP_PASSWORD`. Brute-force protection is built in (exponential backoff lockout). | Simpler than OpenClaw's pairing code flow, but the password must be strong. |
|
|
158
|
+
| **One-click pairing** | Channel pairings (Telegram/Discord) can be approved from the Setup UI instead of the CLI. | No terminal access required, but anyone with the setup password can approve pairings. |
|
|
159
|
+
| **Auto CLI approval** | The first CLI device pairing is auto-approved so you can connect without a second screen. Subsequent requests appear in the UI. | Removes the manual pairing step for the initial CLI connection. |
|
|
160
|
+
| **Query-string tokens** | Webhook URLs support `?token=<WEBHOOK_TOKEN>` for providers that don't support `Authorization` headers. Warnings are shown in the UI. | Tokens may appear in server logs and referrer headers. Use header auth when your provider supports it. |
|
|
161
|
+
| **Gateway token** | `OPENCLAW_GATEWAY_TOKEN` is auto-generated and injected into the environment so the proxy can authenticate with the gateway. | The token lives in the `.env` file on the server — standard for managed deployments but worth noting. |
|
|
162
|
+
|
|
163
|
+
If you need OpenClaw's full security posture (manual pairing codes, no query-string tokens, no auto-approval), use OpenClaw directly without AlphaClaw.
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npm install
|
|
169
|
+
npm test # Full suite (90 tests)
|
|
170
|
+
npm run test:watchdog # Watchdog-focused suite (14 tests)
|
|
171
|
+
npm run test:watch # Watch mode
|
|
172
|
+
npm run test:coverage # Coverage report
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Requirements:** Node.js ≥ 22.12.0
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT
|
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 {
|
package/lib/public/css/shell.css
CHANGED
|
@@ -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 {
|
|
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
|
|
package/lib/public/css/theme.css
CHANGED
|
@@ -48,6 +48,53 @@ body::before {
|
|
|
48
48
|
color: var(--text-muted);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/* Shared collapsible history rows (incidents, webhook requests). */
|
|
52
|
+
.ac-history-list {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
gap: 8px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.ac-history-item {
|
|
59
|
+
border: 1px solid var(--panel-border-contrast);
|
|
60
|
+
border-radius: 10px;
|
|
61
|
+
background: rgba(0, 0, 0, 0.12);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ac-history-summary {
|
|
65
|
+
cursor: pointer;
|
|
66
|
+
list-style: none;
|
|
67
|
+
padding: 8px 10px;
|
|
68
|
+
color: #d1d5db;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ac-history-summary::-webkit-details-marker {
|
|
72
|
+
display: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ac-history-summary-row {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: space-between;
|
|
79
|
+
gap: 8px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.ac-history-toggle {
|
|
83
|
+
color: var(--text-muted);
|
|
84
|
+
transition: transform 0.15s ease, color 0.15s ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ac-history-item[open] .ac-history-toggle {
|
|
88
|
+
transform: rotate(90deg);
|
|
89
|
+
color: #d1d5db;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.ac-history-body {
|
|
93
|
+
margin: 4px 10px 10px;
|
|
94
|
+
padding-top: 8px;
|
|
95
|
+
border-top: 1px solid var(--panel-border-contrast);
|
|
96
|
+
}
|
|
97
|
+
|
|
51
98
|
/* Unified panel treatment across tabs/pages. */
|
|
52
99
|
.bg-surface {
|
|
53
100
|
background: var(--panel-bg-contrast) !important;
|
|
@@ -86,6 +133,15 @@ textarea:focus {
|
|
|
86
133
|
::-webkit-scrollbar-track { background: transparent; }
|
|
87
134
|
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.08); border-radius: 3px; }
|
|
88
135
|
|
|
136
|
+
.scrollbar-hidden {
|
|
137
|
+
-ms-overflow-style: none;
|
|
138
|
+
scrollbar-width: none;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.scrollbar-hidden::-webkit-scrollbar {
|
|
142
|
+
display: none;
|
|
143
|
+
}
|
|
144
|
+
|
|
89
145
|
/* Google scope picker toggle buttons */
|
|
90
146
|
.scope-btn { background: rgba(255,255,255,0.03); color: var(--text-muted); border: 1px solid var(--border); transition: all 0.15s; }
|
|
91
147
|
.scope-btn:hover { border-color: var(--text-dim); color: var(--text); }
|
|
@@ -182,6 +238,159 @@ textarea:focus {
|
|
|
182
238
|
cursor: not-allowed;
|
|
183
239
|
}
|
|
184
240
|
|
|
241
|
+
.ac-btn-ghost {
|
|
242
|
+
border: none;
|
|
243
|
+
color: var(--text-muted);
|
|
244
|
+
background: transparent;
|
|
245
|
+
transition: color 0.15s ease;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.ac-btn-ghost:hover:not(:disabled) {
|
|
249
|
+
color: #f3f4f6;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.ac-btn-ghost:disabled {
|
|
253
|
+
opacity: 0.5;
|
|
254
|
+
cursor: not-allowed;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.ac-btn-danger {
|
|
258
|
+
border: 1px solid rgba(239, 68, 68, 0.45);
|
|
259
|
+
background: rgba(239, 68, 68, 0.08);
|
|
260
|
+
color: #fca5a5;
|
|
261
|
+
transition:
|
|
262
|
+
border-color 0.15s ease,
|
|
263
|
+
color 0.15s ease,
|
|
264
|
+
background 0.15s ease,
|
|
265
|
+
transform 0.15s ease;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.ac-btn-danger:hover:not(:disabled) {
|
|
269
|
+
border-color: rgba(239, 68, 68, 0.7);
|
|
270
|
+
background: rgba(239, 68, 68, 0.14);
|
|
271
|
+
color: #fecaca;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.ac-btn-danger:active:not(:disabled) {
|
|
275
|
+
transform: translateY(1px);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.ac-btn-danger:disabled {
|
|
279
|
+
opacity: 0.5;
|
|
280
|
+
cursor: not-allowed;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.ac-toggle {
|
|
284
|
+
display: inline-flex;
|
|
285
|
+
align-items: center;
|
|
286
|
+
gap: 8px;
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
user-select: none;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.ac-toggle-input {
|
|
292
|
+
position: absolute;
|
|
293
|
+
width: 1px;
|
|
294
|
+
height: 1px;
|
|
295
|
+
opacity: 0;
|
|
296
|
+
pointer-events: none;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.ac-toggle-track {
|
|
300
|
+
position: relative;
|
|
301
|
+
width: 34px;
|
|
302
|
+
height: 20px;
|
|
303
|
+
border-radius: 999px;
|
|
304
|
+
border: 1px solid var(--panel-border-contrast);
|
|
305
|
+
background: rgba(0, 0, 0, 0.35);
|
|
306
|
+
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02);
|
|
307
|
+
transition:
|
|
308
|
+
border-color 0.18s ease,
|
|
309
|
+
background-color 0.18s ease,
|
|
310
|
+
box-shadow 0.18s ease;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.ac-toggle-thumb {
|
|
314
|
+
position: absolute;
|
|
315
|
+
top: 2px;
|
|
316
|
+
left: 2px;
|
|
317
|
+
width: 14px;
|
|
318
|
+
height: 14px;
|
|
319
|
+
border-radius: 999px;
|
|
320
|
+
background: #94a3b8;
|
|
321
|
+
box-shadow: 0 0 0 1px rgba(15, 21, 33, 0.3);
|
|
322
|
+
transition:
|
|
323
|
+
transform 0.18s ease,
|
|
324
|
+
background-color 0.18s ease,
|
|
325
|
+
box-shadow 0.18s ease;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.ac-toggle-label {
|
|
329
|
+
font-size: 12px;
|
|
330
|
+
color: #d1d5db;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.ac-toggle-input:checked + .ac-toggle-track {
|
|
334
|
+
border-color: rgba(99, 235, 255, 0.8);
|
|
335
|
+
background: rgba(99, 235, 255, 0.16);
|
|
336
|
+
box-shadow:
|
|
337
|
+
inset 0 0 0 1px rgba(99, 235, 255, 0.2),
|
|
338
|
+
0 0 10px rgba(99, 235, 255, 0.2);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.ac-toggle-input:checked + .ac-toggle-track .ac-toggle-thumb {
|
|
342
|
+
transform: translateX(14px);
|
|
343
|
+
background: #b6f6ff;
|
|
344
|
+
box-shadow:
|
|
345
|
+
0 0 0 1px rgba(15, 21, 33, 0.25),
|
|
346
|
+
0 0 10px rgba(99, 235, 255, 0.45);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.ac-toggle-input:focus-visible + .ac-toggle-track {
|
|
350
|
+
outline: 2px solid rgba(99, 235, 255, 0.55);
|
|
351
|
+
outline-offset: 2px;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.ac-toggle-input:disabled + .ac-toggle-track {
|
|
355
|
+
opacity: 0.55;
|
|
356
|
+
box-shadow: none;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.ac-toggle-input:disabled + .ac-toggle-track + .ac-toggle-label {
|
|
360
|
+
opacity: 0.6;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@keyframes acStatusDotPulse {
|
|
364
|
+
0%,
|
|
365
|
+
100% {
|
|
366
|
+
transform: scale(1);
|
|
367
|
+
box-shadow:
|
|
368
|
+
0 0 0 0 rgba(34, 197, 94, 0.14),
|
|
369
|
+
0 0 5px rgba(34, 197, 94, 0.18);
|
|
370
|
+
}
|
|
371
|
+
50% {
|
|
372
|
+
transform: scale(1.08);
|
|
373
|
+
box-shadow:
|
|
374
|
+
0 0 0 3px rgba(34, 197, 94, 0.08),
|
|
375
|
+
0 0 9px rgba(34, 197, 94, 0.32);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.ac-status-dot {
|
|
380
|
+
width: 8px;
|
|
381
|
+
height: 8px;
|
|
382
|
+
border-radius: 999px;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.ac-status-dot--healthy {
|
|
386
|
+
background: #22c55e;
|
|
387
|
+
animation: acStatusDotPulse 2.6s ease-in-out infinite;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.ac-status-dot--healthy-offset {
|
|
391
|
+
animation-delay: 0.95s;
|
|
392
|
+
}
|
|
393
|
+
|
|
185
394
|
.ac-btn-green {
|
|
186
395
|
border: 1px solid rgba(34, 197, 94, 0.45);
|
|
187
396
|
background: linear-gradient(
|
|
@@ -215,3 +424,25 @@ textarea:focus {
|
|
|
215
424
|
.ac-btn-green:active:not(:disabled) {
|
|
216
425
|
transform: translateY(1px);
|
|
217
426
|
}
|
|
427
|
+
|
|
428
|
+
@keyframes acSpinnerOrbit {
|
|
429
|
+
0% {
|
|
430
|
+
transform: rotate(0deg);
|
|
431
|
+
}
|
|
432
|
+
100% {
|
|
433
|
+
transform: rotate(360deg);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.ac-spinner {
|
|
438
|
+
animation: acSpinnerOrbit 1s cubic-bezier(0.3, 0.2, 0.7, 0.8) infinite;
|
|
439
|
+
transform-origin: center;
|
|
440
|
+
will-change: transform;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
@media (prefers-reduced-motion: reduce) {
|
|
444
|
+
.ac-spinner {
|
|
445
|
+
animation-duration: 1.8s;
|
|
446
|
+
animation-timing-function: linear;
|
|
447
|
+
}
|
|
448
|
+
}
|