@flame0510/project-aether 1.1.9

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 (290) hide show
  1. package/README.md +150 -0
  2. package/agent-templates/README.md +37 -0
  3. package/agent-templates/argus/AGENTS.md +52 -0
  4. package/agent-templates/argus/IDENTITY.md +7 -0
  5. package/agent-templates/argus/MEMORY.md +9 -0
  6. package/agent-templates/argus/SOUL.md +24 -0
  7. package/agent-templates/argus/TOOLS.md +8 -0
  8. package/agent-templates/atlas/AGENTS.md +47 -0
  9. package/agent-templates/atlas/HEARTBEAT.md +10 -0
  10. package/agent-templates/atlas/IDENTITY.md +6 -0
  11. package/agent-templates/atlas/MEMORY.md +9 -0
  12. package/agent-templates/atlas/SOUL.md +21 -0
  13. package/agent-templates/atlas/TOOLS.md +4 -0
  14. package/agent-templates/base-image/.trigger +0 -0
  15. package/agent-templates/base-image/Dockerfile +90 -0
  16. package/agent-templates/base-image/entrypoint.sh +37 -0
  17. package/agent-templates/custom/AGENTS.md +29 -0
  18. package/agent-templates/custom/BOOTSTRAP.md +56 -0
  19. package/agent-templates/custom/MEMORY.md +8 -0
  20. package/agent-templates/prometheus/AGENTS.md +37 -0
  21. package/agent-templates/prometheus/IDENTITY.md +6 -0
  22. package/agent-templates/prometheus/MEMORY.md +9 -0
  23. package/agent-templates/prometheus/SOUL.md +21 -0
  24. package/agent-templates/prometheus/TOOLS.md +4 -0
  25. package/app/agents/ChannelManager.tsx +465 -0
  26. package/app/agents/ImageDownloadBanner.tsx +159 -0
  27. package/app/agents/PageClient.tsx +1285 -0
  28. package/app/agents/create/PageClient.tsx +437 -0
  29. package/app/agents/create/page.tsx +126 -0
  30. package/app/agents/loading.tsx +14 -0
  31. package/app/agents/page.tsx +5 -0
  32. package/app/api/agents/[id]/backup/route.ts +169 -0
  33. package/app/api/agents/[id]/channels/pairing/route.ts +69 -0
  34. package/app/api/agents/[id]/channels/route.ts +14 -0
  35. package/app/api/agents/[id]/channels/telegram/route.ts +50 -0
  36. package/app/api/agents/[id]/lifecycle/route.ts +94 -0
  37. package/app/api/agents/[id]/recreate/route.ts +199 -0
  38. package/app/api/agents/[id]/restart/route.ts +33 -0
  39. package/app/api/agents/[id]/restore/route.ts +81 -0
  40. package/app/api/agents/[id]/route.ts +280 -0
  41. package/app/api/agents/channels-summary/route.ts +39 -0
  42. package/app/api/agents/config-json/route.ts +58 -0
  43. package/app/api/agents/create/route.ts +488 -0
  44. package/app/api/agents/download-image/route.ts +32 -0
  45. package/app/api/agents/image-status/route.ts +126 -0
  46. package/app/api/agents/route.ts +213 -0
  47. package/app/api/agents/token/route.ts +94 -0
  48. package/app/api/agents-active/route.ts +190 -0
  49. package/app/api/agents-config/route.ts +629 -0
  50. package/app/api/alerts/smoke/route.ts +26 -0
  51. package/app/api/aliases/add/route.ts +28 -0
  52. package/app/api/aliases/remove/route.ts +27 -0
  53. package/app/api/assistant/route.ts +204 -0
  54. package/app/api/auth/check/route.ts +38 -0
  55. package/app/api/auth/login/route.ts +85 -0
  56. package/app/api/auth/logout/route.ts +7 -0
  57. package/app/api/auth/status/route.ts +33 -0
  58. package/app/api/config/env/route.ts +132 -0
  59. package/app/api/config/restart/route.ts +26 -0
  60. package/app/api/containers/route.ts +75 -0
  61. package/app/api/cost-override/route.ts +46 -0
  62. package/app/api/costs/route.ts +84 -0
  63. package/app/api/credentials/[id]/reveal/route.ts +21 -0
  64. package/app/api/credentials/[id]/route.ts +52 -0
  65. package/app/api/credentials/[id]/sync/route.ts +58 -0
  66. package/app/api/credentials/detect/route.ts +246 -0
  67. package/app/api/credentials/route.ts +33 -0
  68. package/app/api/crons/[id]/route.ts +69 -0
  69. package/app/api/crons/route.ts +12 -0
  70. package/app/api/crons/runs/route.ts +31 -0
  71. package/app/api/debug/route.ts +11 -0
  72. package/app/api/envcheck/route.ts +18 -0
  73. package/app/api/events/route.ts +24 -0
  74. package/app/api/gateway/agent/route.ts +154 -0
  75. package/app/api/gateway/provider/balance/route.ts +38 -0
  76. package/app/api/gateway/provider/keys.ts +38 -0
  77. package/app/api/gateway/provider/oauth/route.ts +304 -0
  78. package/app/api/gateway/provider/route.ts +209 -0
  79. package/app/api/gateway/route.ts +223 -0
  80. package/app/api/gateway/sync.ts +189 -0
  81. package/app/api/lineage/route.ts +54 -0
  82. package/app/api/memory-context/route.ts +15 -0
  83. package/app/api/metrics/route.ts +35 -0
  84. package/app/api/models/route.ts +77 -0
  85. package/app/api/plugins/route.js +37 -0
  86. package/app/api/provider/upstream.ts +142 -0
  87. package/app/api/provider/v1/chat/completions/route.ts +146 -0
  88. package/app/api/provider/v1/models/route.ts +167 -0
  89. package/app/api/provider-usage/route.ts +629 -0
  90. package/app/api/session/route.ts +39 -0
  91. package/app/api/sessions/[id]/route.ts +38 -0
  92. package/app/api/sessions/route.ts +23 -0
  93. package/app/api/setup/agent-image/route.ts +102 -0
  94. package/app/api/setup/password/route.ts +111 -0
  95. package/app/api/setup/restart/route.ts +76 -0
  96. package/app/api/skills/delete/route.js +105 -0
  97. package/app/api/skills/promote/route.js +129 -0
  98. package/app/api/skills/route.js +203 -0
  99. package/app/api/skills/save/route.js +142 -0
  100. package/app/api/stats/route.ts +34 -0
  101. package/app/api/stats-since/route.ts +20 -0
  102. package/app/api/stream/route.ts +70 -0
  103. package/app/api/system-health/route.ts +233 -0
  104. package/app/api/tool-calls/route.ts +24 -0
  105. package/app/api/tools-config/route.ts +163 -0
  106. package/app/api/update-check/route.ts +127 -0
  107. package/app/api/version/route.ts +25 -0
  108. package/app/api/wizard/complete/route.ts +32 -0
  109. package/app/api/wizard/reset/route.ts +28 -0
  110. package/app/api/wizard/status/route.ts +28 -0
  111. package/app/api/workspace/route.ts +392 -0
  112. package/app/api/workspace/stream/route.ts +136 -0
  113. package/app/components/AppShell.tsx +33 -0
  114. package/app/components/AuthGuard.tsx +91 -0
  115. package/app/components/CostBreakdown.tsx +37 -0
  116. package/app/components/DashboardHeader.tsx +73 -0
  117. package/app/components/DashboardLayout.tsx +76 -0
  118. package/app/components/DashboardToolbar.tsx +61 -0
  119. package/app/components/FloatingActions.tsx +33 -0
  120. package/app/components/Icons.tsx +78 -0
  121. package/app/components/LineageGraphPage.tsx +142 -0
  122. package/app/components/LiveFeed.tsx +48 -0
  123. package/app/components/MobileBottomNav.tsx +84 -0
  124. package/app/components/ModelPickerModal.tsx +94 -0
  125. package/app/components/PasswordInput.tsx +86 -0
  126. package/app/components/PulseChat.tsx +362 -0
  127. package/app/components/Rev4aLoader.tsx +48 -0
  128. package/app/components/SessionDrawer.tsx +263 -0
  129. package/app/components/SessionTopology.tsx +289 -0
  130. package/app/components/Sidebar.tsx +294 -0
  131. package/app/components/Skeleton.tsx +133 -0
  132. package/app/components/SystemCockpit.tsx +169 -0
  133. package/app/components/VersionBanner.tsx +105 -0
  134. package/app/components/WizardButton.tsx +30 -0
  135. package/app/components/ui/Badge.tsx +30 -0
  136. package/app/components/ui/Button.tsx +59 -0
  137. package/app/components/ui/ConfirmModal.tsx +46 -0
  138. package/app/components/ui/FilterBar.tsx +33 -0
  139. package/app/components/ui/Input.tsx +25 -0
  140. package/app/components/ui/ItemList.tsx +83 -0
  141. package/app/components/ui/LoadingSpinner.tsx +30 -0
  142. package/app/components/ui/Metric.tsx +22 -0
  143. package/app/components/ui/Modal.tsx +42 -0
  144. package/app/components/ui/Page.tsx +18 -0
  145. package/app/components/ui/Pill.tsx +6 -0
  146. package/app/components/ui/PropertyList.tsx +24 -0
  147. package/app/components/ui/Select.tsx +26 -0
  148. package/app/components/ui/StatusCard.tsx +32 -0
  149. package/app/components/ui/Surface.tsx +14 -0
  150. package/app/components/ui/Tabs.tsx +55 -0
  151. package/app/components/ui/TemplateOption.tsx +59 -0
  152. package/app/components/ui/Toast.tsx +44 -0
  153. package/app/components/ui/index.ts +19 -0
  154. package/app/components/ui/tokens.ts +18 -0
  155. package/app/config/PageClient.tsx +293 -0
  156. package/app/config/loading.tsx +10 -0
  157. package/app/config/page.tsx +7 -0
  158. package/app/containers/ContainersClient.tsx +129 -0
  159. package/app/containers/loading.tsx +21 -0
  160. package/app/containers/page.tsx +5 -0
  161. package/app/containers/terminal/[id]/TerminalClient.tsx +313 -0
  162. package/app/containers/terminal/[id]/page.tsx +6 -0
  163. package/app/credentials/PageClient.tsx +598 -0
  164. package/app/credentials/loading.tsx +10 -0
  165. package/app/credentials/page.tsx +7 -0
  166. package/app/crons/PageClient.tsx +538 -0
  167. package/app/crons/loading.tsx +10 -0
  168. package/app/crons/page.tsx +5 -0
  169. package/app/design-system.ts +57 -0
  170. package/app/gateway/PageClient.tsx +1048 -0
  171. package/app/gateway/loading.tsx +24 -0
  172. package/app/gateway/page.tsx +5 -0
  173. package/app/globals.css +1474 -0
  174. package/app/layout.tsx +45 -0
  175. package/app/lib/models-context.tsx +41 -0
  176. package/app/lineage/loading.tsx +10 -0
  177. package/app/lineage/page.tsx +13 -0
  178. package/app/loading.tsx +16 -0
  179. package/app/login/page.tsx +160 -0
  180. package/app/memory/MemoryContextPageClient.tsx +196 -0
  181. package/app/memory/loading.tsx +10 -0
  182. package/app/memory/page.tsx +8 -0
  183. package/app/page.tsx +31 -0
  184. package/app/plugins/PageClient.tsx +296 -0
  185. package/app/plugins/loading.tsx +10 -0
  186. package/app/plugins/page.tsx +5 -0
  187. package/app/setup/PageClient.tsx +227 -0
  188. package/app/setup/loading.tsx +21 -0
  189. package/app/setup/page.tsx +7 -0
  190. package/app/skills/PageClient.tsx +499 -0
  191. package/app/skills/loading.tsx +10 -0
  192. package/app/skills/page.tsx +5 -0
  193. package/app/tools/ToolsPageClient.tsx +308 -0
  194. package/app/tools/loading.tsx +10 -0
  195. package/app/tools/page.tsx +62 -0
  196. package/app/tools/tools-catalog.ts +141 -0
  197. package/app/wizard/PageClient.tsx +485 -0
  198. package/app/wizard/icons.tsx +89 -0
  199. package/app/wizard/loading.tsx +24 -0
  200. package/app/wizard/page.tsx +7 -0
  201. package/app/wizard/storage.ts +33 -0
  202. package/app/wizard/useWizard.ts +101 -0
  203. package/app/workspace/WorkspaceClient.tsx +633 -0
  204. package/app/workspace/loading.tsx +36 -0
  205. package/app/workspace/page.tsx +8 -0
  206. package/bin/docker-entrypoint.sh +21 -0
  207. package/bin/postinstall.js +20 -0
  208. package/bin/rev4a.js +696 -0
  209. package/daemon.js +783 -0
  210. package/docs/ARCHITECTURE.md +557 -0
  211. package/docs/CONTAINER-TERMINAL.md +280 -0
  212. package/docs/DESIGN-SYSTEM.md +99 -0
  213. package/docs/FRONTEND-ARCHITECTURE.md +119 -0
  214. package/docs/REV4A.md +504 -0
  215. package/docs/dev/API-REFERENCE.md +1835 -0
  216. package/docs/dev/DATABASE.md +224 -0
  217. package/docs/dev/GATEWAY.md +300 -0
  218. package/docs/dev/PROVIDERS.md +229 -0
  219. package/docs/dev/SESSION-MAINTENANCE-PLAN.md +607 -0
  220. package/docs/dev/WORKSPACE.md +199 -0
  221. package/docs/rag/DATA-FRESHNESS.md +109 -0
  222. package/docs/rag/GLOSSARY.md +125 -0
  223. package/docs/rag/REV4A-OVERVIEW.md +135 -0
  224. package/docs/rag/WHAT-I-CAN-ANSWER.md +124 -0
  225. package/lib/agent-setup.ts +130 -0
  226. package/lib/alerts.ts +115 -0
  227. package/lib/apiFetch.ts +7 -0
  228. package/lib/auth.ts +28 -0
  229. package/lib/billing.ts +100 -0
  230. package/lib/buildAgentImage.ts +346 -0
  231. package/lib/channelManager.ts +386 -0
  232. package/lib/container.ts +60 -0
  233. package/lib/credentials/db.ts +86 -0
  234. package/lib/credentials/delivery.ts +448 -0
  235. package/lib/credentials/detect.ts +149 -0
  236. package/lib/credentials/hash.ts +9 -0
  237. package/lib/credentials/providers.ts +110 -0
  238. package/lib/credentials/vault.ts +195 -0
  239. package/lib/db-bootstrap.d.ts +3 -0
  240. package/lib/db-bootstrap.mjs +144 -0
  241. package/lib/db.ts +25 -0
  242. package/lib/docker-utils.ts +60 -0
  243. package/lib/hooks/useDashboard.ts +264 -0
  244. package/lib/hooks/useRev4aTimezone.ts +28 -0
  245. package/lib/hooks/useScreenshot.ts +30 -0
  246. package/lib/memory-context.ts +385 -0
  247. package/lib/model-catalogue.ts +131 -0
  248. package/lib/model-pricing.ts +63 -0
  249. package/lib/openclaw-cron.ts +350 -0
  250. package/lib/patterns/ApiAdapter.ts +73 -0
  251. package/lib/patterns/ApiClient.ts +65 -0
  252. package/lib/patterns/EventBus.ts +113 -0
  253. package/lib/patterns/FilterStrategy.ts +79 -0
  254. package/lib/patterns/SessionFactory.ts +117 -0
  255. package/lib/patterns/sessionPresentation.ts +117 -0
  256. package/lib/provider-balance.ts +163 -0
  257. package/lib/requireAuth.tsx +38 -0
  258. package/lib/rev4a-auth.d.ts +3 -0
  259. package/lib/rev4a-auth.js +36 -0
  260. package/lib/rev4a-paths.ts +145 -0
  261. package/lib/timezone.ts +46 -0
  262. package/lib/types/index.ts +96 -0
  263. package/lib/utils/format.ts +82 -0
  264. package/lineage.js +56 -0
  265. package/model-pricing.json +482 -0
  266. package/models.config.json +844 -0
  267. package/next-env.d.ts +6 -0
  268. package/next.config.mjs +7 -0
  269. package/package.json +82 -0
  270. package/public/apple-touch-icon.png +0 -0
  271. package/public/favicon-64.png +0 -0
  272. package/public/favicon.svg +58 -0
  273. package/public/icon-192-maskable.png +0 -0
  274. package/public/icon-192.png +0 -0
  275. package/public/icon-512-maskable.png +0 -0
  276. package/public/icon-512.png +0 -0
  277. package/public/manifest.json +38 -0
  278. package/public/rev4a-logo.png +0 -0
  279. package/public/rev4a-logo.svg +58 -0
  280. package/rev4a-rules/AGENTS.md +37 -0
  281. package/scripts/add-auth.cjs +185 -0
  282. package/scripts/backup.sh +66 -0
  283. package/scripts/check-providers.mjs +143 -0
  284. package/scripts/docker/traefik/docker-compose.yml +32 -0
  285. package/scripts/docker/traefik/dynamic/.gitkeep +18 -0
  286. package/scripts/docker/traefik/traefik.yml +37 -0
  287. package/scripts/remove-auth-profile.js +56 -0
  288. package/scripts/restore.sh +82 -0
  289. package/terminal-ws-server.js +139 -0
  290. package/tsconfig.json +42 -0
@@ -0,0 +1,143 @@
1
+ import { chromium } from '@playwright/test';
2
+ import http from 'http';
3
+
4
+ /**
5
+ * Playwright check: providers page, Atlas agent, DeepSeek key visibility.
6
+ * Uses existing session cookie from login.
7
+ */
8
+
9
+ const BASE = 'http://127.0.0.1:3740';
10
+ const PASSWORD = process.env.REV4A_PASSWORD || '';
11
+
12
+ function postLogin() {
13
+ return new Promise((resolve, reject) => {
14
+ const data = JSON.stringify({ password: PASSWORD });
15
+ const req = http.request(`${BASE}/api/auth/login`, {
16
+ method: 'POST',
17
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
18
+ }, (res) => {
19
+ let body = '';
20
+ res.on('data', (c) => body += c);
21
+ res.on('end', () => {
22
+ const cookies = (res.headers['set-cookie'] || []).join('; ');
23
+ const token = cookies.match(/rev4a_token=([^;]+)/)?.[1];
24
+ resolve(token ? { token, cookie: cookies } : null);
25
+ });
26
+ });
27
+ req.on('error', reject);
28
+ req.write(data);
29
+ req.end();
30
+ });
31
+ }
32
+
33
+ async function getAgentProviders(cookie) {
34
+ return new Promise((resolve, reject) => {
35
+ http.get(`${BASE}/api/agent-providers`, { headers: { Cookie: cookie } }, (res) => {
36
+ let body = '';
37
+ res.on('data', (c) => body += c);
38
+ res.on('end', () => {
39
+ try { resolve(JSON.parse(body)); } catch { resolve(null); }
40
+ });
41
+ }).on('error', reject);
42
+ });
43
+ }
44
+
45
+ (async () => {
46
+ console.log('=== Provider check script ===\n');
47
+
48
+ // 1. Login and get session cookie
49
+ const login = await postLogin();
50
+ if (!login) {
51
+ console.log('FAIL: could not login');
52
+ process.exit(1);
53
+ }
54
+ console.log('OK: logged in');
55
+
56
+ // 2. Check API agent-providers returns Atlas with deepseek
57
+ const agents = await getAgentProviders(login.cookie);
58
+ if (!agents) {
59
+ console.log('FAIL: /api/agent-providers returned null');
60
+ process.exit(1);
61
+ }
62
+ console.log(`Found ${agents.length} agent(s):`);
63
+ let atlasDeepseekCount = 0;
64
+ for (const a of agents) {
65
+ const providerNames = (a.providers || []).map(p => p.provider).join(', ');
66
+ console.log(` ${a.agentId}: ${providerNames || '(none)'}`);
67
+ if (a.agentId === 'openclaw-atlas') {
68
+ for (const p of (a.providers || [])) {
69
+ if (p.provider === 'deepseek') atlasDeepseekCount++;
70
+ }
71
+ }
72
+ }
73
+
74
+ if (atlasDeepseekCount === 0) {
75
+ console.log('\nWARN: deepseek NOT found in Atlas via API. UI will show it inactive.\n');
76
+ } else {
77
+ console.log(`\nOK: deepseek found in Atlas (${atlasDeepseekCount} entry)\n`);
78
+ }
79
+
80
+ // 3. Playwright: headless browser visit providers page with cookie
81
+ const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
82
+ const context = await browser.newContext();
83
+ // Set the rev4a_token cookie manually for the domain
84
+ await context.addCookies([{
85
+ name: 'rev4a_token',
86
+ value: login.token,
87
+ domain: '127.0.0.1',
88
+ path: '/',
89
+ httpOnly: true,
90
+ sameSite: 'Lax',
91
+ }]);
92
+ const page = await context.newPage();
93
+
94
+ console.log('Navigating to providers page...');
95
+ await page.goto(`${BASE}/providers`, { waitUntil: 'networkidle' });
96
+ // Wait a moment for agent loading
97
+ await page.waitForTimeout(2000);
98
+
99
+ // 4. Check page has agent selector
100
+ const selectors = await page.locator('select').count();
101
+ console.log(`Select dropdowns found: ${selectors}`);
102
+
103
+ // Try to select Atlas from dropdown
104
+ const selects = page.locator('select');
105
+ const selectCount = await selects.count();
106
+ if (selectCount > 0) {
107
+ // First select is usually the agent selector
108
+ const firstSelect = selects.first();
109
+ const options = await firstSelect.locator('option').allTextContents();
110
+ console.log(`Agent options: ${options.join(', ')}`);
111
+
112
+ if (options.some(o => o.includes('atlas'))) {
113
+ console.log('OK: Atlas option found in selector');
114
+ await firstSelect.selectOption(options.find(o => o.includes('atlas')) || options[1]);
115
+ await page.waitForTimeout(2000);
116
+
117
+ // Check for deepseek in visible text
118
+ const bodyText = await page.locator('body').innerText();
119
+ const hasDeepseek = bodyText.toLowerCase().includes('deepseek');
120
+ console.log(`Deepseek visible on page after selecting Atlas: ${hasDeepseek ? 'YES' : 'NO'}`);
121
+
122
+ // Look for active indicators
123
+ const activeElements = page.locator('text=ACTIVE');
124
+ const activeCount = await activeElements.count();
125
+ console.log(`"ACTIVE" text occurrences: ${activeCount}`);
126
+ } else {
127
+ console.log('WARN: Atlas option NOT found in agent selector');
128
+ }
129
+ } else {
130
+ console.log('WARN: no selector found on page');
131
+ }
132
+
133
+ // 5. Screenshot for visual inspection
134
+ await page.screenshot({ path: '/tmp/providers-atlas-check.png', fullPage: false });
135
+ console.log('Screenshot saved to /tmp/providers-atlas-check.png');
136
+
137
+ await browser.close();
138
+ console.log('\n=== Check complete ===');
139
+
140
+ // Exit with status: 0 if deepseek visible, 1 if not
141
+ const finalBody = await page.locator('body').innerText().catch(() => '');
142
+ process.exit(finalBody.toLowerCase().includes('deepseek') && atlasDeepseekCount > 0 ? 0 : 1);
143
+ })();
@@ -0,0 +1,32 @@
1
+ # Rev4a Traefik — dedicated reverse proxy
2
+ #
3
+ # This Traefik instance is isolated from any other Traefik running on the host.
4
+ # It uses its own Docker network (rev4a-traefik) and config directory.
5
+ #
6
+ # Ports:
7
+ # 80 → HTTP (entrypoint: web)
8
+ # 443 → HTTPS (entrypoint: websecure)
9
+ # 8080 → Dashboard (internal only, not exposed)
10
+
11
+ services:
12
+ traefik:
13
+ image: traefik:latest
14
+ container_name: traefik-'rev4a'
15
+ restart: unless-stopped
16
+ ports:
17
+ - "80:80"
18
+ - "443:443"
19
+ networks:
20
+ - rev4a-traefik
21
+ volumes:
22
+ - /var/run/docker.sock:/var/run/docker.sock:ro
23
+ - ./traefik.yml:/etc/traefik/traefik.yml:ro
24
+ - ./dynamic:/etc/traefik/dynamic:ro
25
+ - ./certs:/etc/traefik/certs
26
+ labels:
27
+ - "traefik.enable=false"
28
+
29
+ networks:
30
+ rev4a-traefik:
31
+ name: rev4a-traefik
32
+ external: true # created by setup.sh before this Compose stack starts
@@ -0,0 +1,18 @@
1
+ # Add dynamic Traefik routes here.
2
+ # Files in this directory are watched and applied automatically.
3
+ #
4
+ # Example: route rev4a.yourdomain.com to the Rev4a dashboard:
5
+ #
6
+ # http:
7
+ # routers:
8
+ # rev4a-dashboard:
9
+ # entryPoints: [websecure]
10
+ # rule: "Host(`rev4a.yourdomain.com`)"
11
+ # service: rev4a
12
+ # tls:
13
+ # certResolver: letsencrypt
14
+ # services:
15
+ # rev4a:
16
+ # loadBalancer:
17
+ # servers:
18
+ # - url: "http://127.0.0.1:3740"
@@ -0,0 +1,37 @@
1
+ # Traefik static configuration
2
+ # See: https://doc.traefik.io/traefik/reference/static-configuration/file/
3
+
4
+ global:
5
+ checkNewVersion: false
6
+ sendAnonymousUsage: false
7
+
8
+ log:
9
+ level: WARN
10
+
11
+ api:
12
+ dashboard: true
13
+ insecure: false
14
+
15
+ entryPoints:
16
+ web:
17
+ address: ":80"
18
+ websecure:
19
+ address: ":443"
20
+
21
+ providers:
22
+ docker:
23
+ endpoint: "unix:///var/run/docker.sock"
24
+ exposedByDefault: false
25
+ network: rev4a-traefik
26
+
27
+ file:
28
+ directory: /etc/traefik/dynamic
29
+ watch: true
30
+
31
+ certificatesResolvers:
32
+ letsencrypt:
33
+ acme:
34
+ email: "admin@example.com" # CHANGE THIS to your real email before enabling HTTPS
35
+ storage: /etc/traefik/certs/acme.json
36
+ httpChallenge:
37
+ entryPoint: web
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Remove an auth profile from the OpenClaw SQLite database.
3
+ * Usage: node remove-auth-profile.js <db-path> <provider-name>
4
+ *
5
+ * Reads the store_json from auth_profile_store, removes any profiles
6
+ * matching the provider, and writes back.
7
+ */
8
+ const { execSync: run } = require('child_process');
9
+
10
+ const db = process.argv[2];
11
+ const provider = process.argv[3];
12
+
13
+ if (!db || !provider) {
14
+ process.stderr.write('Usage: node remove-auth-profile.js <db-path> <provider>\n');
15
+ process.exit(1);
16
+ }
17
+
18
+ try {
19
+ const row = run(
20
+ 'sqlite3 ' + JSON.stringify(db) + ' "SELECT store_json FROM auth_profile_store WHERE store_key=\'primary\'"',
21
+ { encoding: 'utf8', timeout: 5000 }
22
+ ).trim();
23
+
24
+ if (!row) process.exit(0);
25
+
26
+ const data = JSON.parse(row);
27
+ if (!data.profiles) process.exit(0);
28
+
29
+ let changed = false;
30
+ for (const pid of Object.keys(data.profiles)) {
31
+ const p = data.profiles[pid];
32
+ if (p.provider === provider || pid.startsWith(provider + ':')) {
33
+ delete data.profiles[pid];
34
+ changed = true;
35
+ process.stderr.write('Removed profile: ' + pid + '\n');
36
+ }
37
+ }
38
+
39
+ if (!changed) process.exit(0);
40
+
41
+ const newJson = JSON.stringify(data);
42
+ // Escape single quotes for SQLite shell
43
+ const escaped = newJson.replace(/'/g, "''");
44
+ const updateCmd =
45
+ 'sqlite3 ' + JSON.stringify(db) +
46
+ ' "UPDATE auth_profile_store SET store_json=\'' + escaped +
47
+ '\', updated_at=' + Date.now() +
48
+ ' WHERE store_key=\'primary\'"';
49
+
50
+ run(updateCmd, { timeout: 5000 });
51
+ process.stderr.write('Updated auth_profile_store\n');
52
+ console.log('ok');
53
+ } catch (e) {
54
+ process.stderr.write('Error: ' + e.message + '\n');
55
+ process.exit(1);
56
+ }
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env bash
2
+ # restore.sh — Restore Rev4a data from a backup archive
3
+ #
4
+ # Usage:
5
+ # sudo bash scripts/restore.sh backups/rev4a-backup-20260724-120000.tar.gz
6
+ #
7
+ # The script restores:
8
+ # - data/*.db
9
+ # - data/provider-keys.json
10
+ # - data/agents-token.json
11
+ # - models.config.json
12
+ # - .env
13
+ #
14
+ # Existing files are backed up to a .pre-restore directory before overwriting.
15
+ set -euo pipefail
16
+
17
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ REV4A_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
19
+
20
+ ARCHIVE="${1:-}"
21
+
22
+ if [[ -z "$ARCHIVE" ]]; then
23
+ echo "Usage: sudo bash scripts/restore.sh <backup-archive.tar.gz>"
24
+ echo ""
25
+ echo "Available backups:"
26
+ if [[ -d "${REV4A_ROOT}/backups" ]]; then
27
+ ls -lh "${REV4A_ROOT}/backups/"*.tar.gz 2>/dev/null || echo " (none)"
28
+ else
29
+ echo " (no backups directory)"
30
+ fi
31
+ exit 1
32
+ fi
33
+
34
+ if [[ ! -f "$ARCHIVE" ]]; then
35
+ echo "Error: Archive not found: $ARCHIVE"
36
+ exit 1
37
+ fi
38
+
39
+ echo "Restoring Rev4a from: $ARCHIVE"
40
+ echo ""
41
+
42
+ # Create pre-restore backup of current state
43
+ PRE_DIR="${REV4A_ROOT}/backups/.pre-restore-$(date -u +%Y%m%d-%H%M%S)"
44
+ mkdir -p "$PRE_DIR"
45
+
46
+ echo "Saving current state to: $PRE_DIR"
47
+ cd "$REV4A_ROOT"
48
+ for f in data/*.db data/*.db-shm data/*.db-wal data/provider-keys.json data/agents-token.json models.config.json .env; do
49
+ if [[ -f "$f" ]]; then
50
+ cp --parents "$f" "$PRE_DIR/" 2>/dev/null || true
51
+ fi
52
+ done
53
+
54
+ # Stop Rev4a services before restore
55
+ if systemctl is-active --quiet rev4a.service 2>/dev/null; then
56
+ echo "Stopping Rev4a services..."
57
+ sudo systemctl stop rev4a.service
58
+ echo "Services stopped."
59
+ fi
60
+
61
+ # Extract the archive
62
+ echo "Extracting backup..."
63
+ tar -xzf "$ARCHIVE" -C "$REV4A_ROOT"
64
+
65
+ # Fix permissions
66
+ chmod 600 "${REV4A_ROOT}/.env" 2>/dev/null || true
67
+ chmod 600 "${REV4A_ROOT}/data/provider-keys.json" 2>/dev/null || true
68
+ chmod 600 "${REV4A_ROOT}/data/agents-token.json" 2>/dev/null || true
69
+
70
+ echo ""
71
+ echo "=============================================="
72
+ echo " Restore complete!"
73
+ echo "=============================================="
74
+ echo ""
75
+ echo " Previous state saved to: ${PRE_DIR}"
76
+ echo ""
77
+ echo " To restart Rev4a:"
78
+ echo " sudo systemctl start rev4a.service"
79
+ echo ""
80
+ echo " If something went wrong, restore previous state from:"
81
+ echo " ${PRE_DIR}"
82
+ echo "=============================================="
@@ -0,0 +1,139 @@
1
+ // Terminal WebSocket Server — standalone
2
+ // Uses node-pty for real PTY with docker exec - fully interactive
3
+ const { WebSocketServer } = require('ws');
4
+ const http = require('http');
5
+ const path = require('path');
6
+
7
+ const pty = require(path.resolve(__dirname, 'node_modules/node-pty'));
8
+
9
+ const PORT = parseInt(process.env.TERMINAL_WS_PORT || '3741', 10);
10
+ const SESSION_TIMEOUT_MS = 30 * 60 * 1000;
11
+ const IDLE_RESET_TIMEOUT_MS = 60 * 1000;
12
+
13
+ const server = http.createServer((_req, res) => {
14
+ res.writeHead(426, { 'Content-Type': 'text/plain' });
15
+ res.end('Use WebSocket');
16
+ });
17
+
18
+ const wss = new WebSocketServer({ server });
19
+
20
+ wss.on('connection', (ws, req) => {
21
+ const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
22
+ const containerId = url.searchParams.get('id');
23
+
24
+ if (!containerId) {
25
+ ws.send(`\r\n[Error: Missing container id]\r\n`);
26
+ ws.close();
27
+ return;
28
+ }
29
+
30
+ let term = null;
31
+ let idleTimer = setTimeout(() => {
32
+ ws.send('\r\n[Session timeout: 30 minutes]\r\n');
33
+ try { ws.close(); } catch {}
34
+ }, SESSION_TIMEOUT_MS);
35
+
36
+ function resetIdleTimer() {
37
+ clearTimeout(idleTimer);
38
+ idleTimer = setTimeout(() => {
39
+ ws.send('\r\n[Session timeout: 30 minutes]\r\n');
40
+ try { ws.close(); } catch {}
41
+ }, SESSION_TIMEOUT_MS);
42
+ }
43
+
44
+ try {
45
+ term = pty.spawn('docker', ['exec', '-it', containerId, 'env', 'TERM=xterm-256color', 'bash'], {
46
+ name: 'xterm-256color',
47
+ cols: 80,
48
+ rows: 30,
49
+ });
50
+ } catch (err) {
51
+ ws.send(`\r\n[Error: ${err.message}]\r\n`);
52
+ ws.close();
53
+ clearTimeout(idleTimer);
54
+ return;
55
+ }
56
+
57
+ // PTY output → WebSocket.
58
+ // Use a queue + micro-delay to avoid flooding xterm.js with one giant chunk.
59
+ let outputBuf = '';
60
+ let outputTimer = null;
61
+
62
+ function flushOutput() {
63
+ outputTimer = null;
64
+ if (!outputBuf) return;
65
+ if (ws.readyState !== ws.OPEN) { outputBuf = ''; return; }
66
+ ws.send(outputBuf);
67
+ outputBuf = '';
68
+ }
69
+
70
+ term.onData((data) => {
71
+ if (!data) return;
72
+ outputBuf += data;
73
+ // Flush every 10ms max (roughly 30-40 chunks/sec — safe for DOM renderer)
74
+ if (!outputTimer) {
75
+ outputTimer = setTimeout(flushOutput, 10);
76
+ }
77
+ // If buffer grows huge, flush immediately in chunks
78
+ if (outputBuf.length > 4000) {
79
+ // Split into 2k chunks
80
+ while (outputBuf.length > 2000) {
81
+ const chunk = outputBuf.slice(0, 2000);
82
+ outputBuf = outputBuf.slice(2000);
83
+ if (ws.readyState === ws.OPEN) ws.send(chunk);
84
+ }
85
+ }
86
+ });
87
+
88
+ // WebSocket input → PTY
89
+ ws.on('message', (data) => {
90
+ resetIdleTimer();
91
+ if (!term) return;
92
+
93
+ const msg = data.toString();
94
+
95
+ // Handle resize message from client
96
+ if (msg.startsWith('{"type":"resize"}') || msg.startsWith('{"type":"resize"') && msg.includes('"cols"')) {
97
+ try {
98
+ const parsed = JSON.parse(msg);
99
+ if (parsed.type === 'resize' && parsed.cols && parsed.rows) {
100
+ term.resize(parsed.cols, parsed.rows);
101
+ }
102
+ } catch {}
103
+ return;
104
+ }
105
+
106
+ term.write(msg);
107
+ });
108
+
109
+ term.onExit(({ exitCode, signal }) => {
110
+ clearTimeout(idleTimer);
111
+ if (ws.readyState === ws.OPEN) {
112
+ ws.send(`\r\n[Process exited with code ${exitCode}]\r\n`);
113
+ ws.close();
114
+ }
115
+ });
116
+
117
+ ws.on('close', () => {
118
+ clearTimeout(idleTimer);
119
+ if (term) term.kill('SIGTERM');
120
+ });
121
+
122
+ ws.on('error', () => {
123
+ clearTimeout(idleTimer);
124
+ if (term) term.kill('SIGTERM');
125
+ });
126
+
127
+ term.write('\n');
128
+ ws.send(`\r\n[Connected to container: ${containerId}]\r\n`);
129
+ });
130
+
131
+ server.listen(PORT, '127.0.0.1', () => {
132
+ console.log(`[TerminalWS] Server listening on ws://127.0.0.1:${PORT}`);
133
+ });
134
+
135
+ process.on('SIGTERM', () => {
136
+ console.log('[TerminalWS] Shutting down...');
137
+ wss.close();
138
+ server.close(() => process.exit(0));
139
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": [
5
+ "dom",
6
+ "dom.iterable",
7
+ "esnext"
8
+ ],
9
+ "allowJs": true,
10
+ "skipLibCheck": true,
11
+ "strict": true,
12
+ "noEmit": true,
13
+ "esModuleInterop": true,
14
+ "module": "esnext",
15
+ "moduleResolution": "bundler",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "jsx": "react-jsx",
19
+ "incremental": true,
20
+ "plugins": [
21
+ {
22
+ "name": "next"
23
+ }
24
+ ],
25
+ "paths": {
26
+ "@/*": [
27
+ "./*"
28
+ ]
29
+ }
30
+ },
31
+ "include": [
32
+ "next-env.d.ts",
33
+ "**/*.ts",
34
+ "**/*.tsx",
35
+ ".next/types/**/*.ts",
36
+ ".next/dev/types/**/*.ts",
37
+ ".next/dev/dev/types/**/*.ts"
38
+ ],
39
+ "exclude": [
40
+ "node_modules"
41
+ ]
42
+ }