aios-management-web 0.1.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 (91) hide show
  1. package/.env.json +21 -0
  2. package/README.md +257 -0
  3. package/data/management-console.db +0 -0
  4. package/data/management-console.db-shm +0 -0
  5. package/data/management-console.db-wal +0 -0
  6. package/dist/assets/index-CV_wjCAG.js +464 -0
  7. package/dist/assets/index-DfMPB0eV.css +1 -0
  8. package/dist/index.html +13 -0
  9. package/docs/spec.md +199 -0
  10. package/index.html +12 -0
  11. package/package.json +37 -0
  12. package/scripts/reset-kernel.js +59 -0
  13. package/scripts/reset-password.js +22 -0
  14. package/server/fakes.js +57 -0
  15. package/server/index.js +21 -0
  16. package/server/src/api/middleware/auth.js +29 -0
  17. package/server/src/api/middleware/internal.js +44 -0
  18. package/server/src/api/routes/index.js +677 -0
  19. package/server/src/app.js +90 -0
  20. package/server/src/background/index.js +106 -0
  21. package/server/src/background/protocol.js +15 -0
  22. package/server/src/config/env.js +90 -0
  23. package/server/src/db/index.js +501 -0
  24. package/server/src/infra/mqtt/management-rpc-client.js +213 -0
  25. package/server/src/infra/providers/hzg-provider-client.js +39 -0
  26. package/server/src/infra/s3/object-storage.js +97 -0
  27. package/server/src/services/agent-quota.js +54 -0
  28. package/server/src/services/agent-service.js +696 -0
  29. package/server/src/services/agent-status-sync-service.js +132 -0
  30. package/server/src/services/audit-log-service.js +39 -0
  31. package/server/src/services/auth-service.js +153 -0
  32. package/server/src/services/catalog-sync-service.js +712 -0
  33. package/server/src/services/external-service.js +308 -0
  34. package/server/src/services/kernel-reset-service.js +86 -0
  35. package/server/src/services/portal-service.js +555 -0
  36. package/server/src/services/system-service.js +580 -0
  37. package/server/src/services/topic-ping-service.js +282 -0
  38. package/server/src/utils/errors.js +36 -0
  39. package/server/src/utils/security.js +22 -0
  40. package/server/test/agent-service-alignment.test.js +316 -0
  41. package/server/test/agent-service-create.test.js +662 -0
  42. package/server/test/agent-status-sync-service.test.js +167 -0
  43. package/server/test/agent-update-audit.test.js +63 -0
  44. package/server/test/auth-middleware.test.js +71 -0
  45. package/server/test/background-services.test.js +160 -0
  46. package/server/test/catalog-sync-service.test.js +920 -0
  47. package/server/test/db-reset-migration.test.js +123 -0
  48. package/server/test/env-config.test.js +68 -0
  49. package/server/test/external-service.test.js +380 -0
  50. package/server/test/hzg-provider-client.test.js +50 -0
  51. package/server/test/internal-auth-middleware.test.js +66 -0
  52. package/server/test/kernel-reset-service.test.js +112 -0
  53. package/server/test/management-rpc-client.test.js +105 -0
  54. package/server/test/portal-service-access-tokens.test.js +121 -0
  55. package/server/test/portal-service-alignment.test.js +318 -0
  56. package/server/test/portal-service-management-logs.test.js +114 -0
  57. package/server/test/reset-kernel-cli.test.js +23 -0
  58. package/server/test/service-api-auth-middleware.test.js +59 -0
  59. package/server/test/system-service-alignment.test.js +265 -0
  60. package/server/test/topic-ping-service.test.js +182 -0
  61. package/server/test/usage-refresh-audit-route.test.js +82 -0
  62. package/src/App.jsx +1 -0
  63. package/src/api.js +1 -0
  64. package/src/app/App.jsx +346 -0
  65. package/src/app/api-client.js +112 -0
  66. package/src/components/AppShell.jsx +117 -0
  67. package/src/components/CardTitleWithReload.jsx +20 -0
  68. package/src/components/DeleteActionButton.jsx +31 -0
  69. package/src/main.jsx +14 -0
  70. package/src/pages/AgentsPage.jsx +647 -0
  71. package/src/pages/AiosUsersPage.jsx +151 -0
  72. package/src/pages/DashboardPage.jsx +72 -0
  73. package/src/pages/LoginPage.jsx +41 -0
  74. package/src/pages/SettingsPage.jsx +431 -0
  75. package/src/pages/SkillsPage.jsx +175 -0
  76. package/src/pages/SystemLogsPage.jsx +349 -0
  77. package/src/pages/SystemsPage.jsx +498 -0
  78. package/src/pages/TemplatesPage.jsx +207 -0
  79. package/src/pages/UserManagementPage.jsx +25 -0
  80. package/src/pages/UsersPage.jsx +192 -0
  81. package/src/pages/system-logs/SystemLogsTabs.jsx +362 -0
  82. package/src/styles.css +222 -0
  83. package/src/utils/format.js +63 -0
  84. package/test/.reports/fast-2026-05-25T08-32-39-420Z.json +299 -0
  85. package/test/integration/common.js +208 -0
  86. package/test/integration/fast.js +135 -0
  87. package/test/integration/full.js +306 -0
  88. package/test/run-browser-e2e.js +212 -0
  89. package/test/run-jasmine.js +21 -0
  90. package/test/setup.js +1 -0
  91. package/vite.config.js +12 -0
@@ -0,0 +1,212 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ import { chromium } from "playwright-core";
6
+ import { createServer } from "vite";
7
+
8
+ function findChromeExecutable() {
9
+ const candidates = [
10
+ process.env.PLAYWRIGHT_CHROME_PATH,
11
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
12
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
13
+ "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
14
+ "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
15
+ ].filter(Boolean);
16
+
17
+ for (const candidate of candidates) {
18
+ if (fs.existsSync(candidate)) {
19
+ return candidate;
20
+ }
21
+ }
22
+
23
+ throw new Error("No Chrome/Edge executable found");
24
+ }
25
+
26
+ function jsonBody(payload) {
27
+ return {
28
+ status: 200,
29
+ contentType: "application/json",
30
+ body: JSON.stringify(payload)
31
+ };
32
+ }
33
+
34
+ async function main() {
35
+ const vite = await createServer({
36
+ configFile: path.resolve("vite.config.js"),
37
+ logLevel: "error",
38
+ server: {
39
+ host: "127.0.0.1",
40
+ port: 4173,
41
+ strictPort: true
42
+ }
43
+ });
44
+ await vite.listen();
45
+
46
+ const chromePath = findChromeExecutable();
47
+ const browser = await chromium.launch({
48
+ executablePath: chromePath,
49
+ headless: true
50
+ });
51
+
52
+ const context = await browser.newContext({
53
+ viewport: { width: 1440, height: 1024 }
54
+ });
55
+ const page = await context.newPage();
56
+
57
+ const agents = [];
58
+ let createPayload = null;
59
+
60
+ await context.route("**/api/**", async (route) => {
61
+ const request = route.request();
62
+ const url = new URL(request.url());
63
+ const { pathname, search } = url;
64
+ const method = request.method();
65
+
66
+ if (pathname === "/api/auth/login" && method === "POST") {
67
+ await route.fulfill(jsonBody({
68
+ token: "e2e-token",
69
+ user: {
70
+ id: 1,
71
+ role: "aios-admin",
72
+ username: "aios",
73
+ display_name: "AIOS Admin",
74
+ status: "active",
75
+ is_builtin: true,
76
+ must_change_password: false,
77
+ tags: ["builtin", "ops"]
78
+ }
79
+ }));
80
+ return;
81
+ }
82
+
83
+ if (pathname === "/api/bootstrap" && method === "GET") {
84
+ await route.fulfill(jsonBody({
85
+ current_user: {
86
+ id: 1,
87
+ role: "aios-admin",
88
+ username: "aios",
89
+ display_name: "AIOS Admin",
90
+ status: "active",
91
+ is_builtin: true,
92
+ must_change_password: false,
93
+ tags: ["builtin", "ops"]
94
+ },
95
+ settings: {
96
+ id: 1,
97
+ portal_name: "AIOS Console",
98
+ brand_subtitle: "E2E",
99
+ theme_color: "#07c160"
100
+ },
101
+ agent_sync: { status: "idle", summary: {} },
102
+ skill_sync: { status: "idle", summary: {} },
103
+ template_sync: { status: "idle", summary: {} },
104
+ system_sync: { status: "idle", summary: {} },
105
+ usage_refresh: { status: "idle", summary: {} }
106
+ }));
107
+ return;
108
+ }
109
+
110
+ if (pathname === "/api/dashboard" && method === "GET") {
111
+ await route.fulfill(jsonBody({
112
+ stats: {
113
+ users: 1,
114
+ agents: 0,
115
+ templates: 2,
116
+ skills: 0,
117
+ systems: 0,
118
+ threads: 0
119
+ },
120
+ recentInvocations: []
121
+ }));
122
+ return;
123
+ }
124
+
125
+ if (pathname === "/api/aios-users" && method === "GET") {
126
+ await route.fulfill(jsonBody({
127
+ items: [],
128
+ total: 0,
129
+ page: 1,
130
+ pageSize: 50
131
+ }));
132
+ return;
133
+ }
134
+
135
+ if (pathname === "/api/agents" && method === "GET") {
136
+ await route.fulfill(jsonBody(agents));
137
+ return;
138
+ }
139
+
140
+ if (pathname === "/api/agents" && method === "POST") {
141
+ createPayload = JSON.parse(request.postData() || "{}");
142
+ const created = {
143
+ id: agents.length + 1,
144
+ slug: createPayload.id,
145
+ agent_name: createPayload.agent_name || createPayload.id,
146
+ description: "",
147
+ template_name: "default",
148
+ status: "normal",
149
+ daily_limit: createPayload.daily_limit,
150
+ permissions: [],
151
+ usage: { daily: 0 },
152
+ health: "normal",
153
+ skills: []
154
+ };
155
+ agents.unshift(created);
156
+ await route.fulfill({
157
+ status: 201,
158
+ contentType: "application/json",
159
+ body: JSON.stringify(created)
160
+ });
161
+ return;
162
+ }
163
+
164
+ throw new Error(`Unexpected API call: ${method} ${pathname}${search}`);
165
+ });
166
+
167
+ try {
168
+ await page.goto("http://127.0.0.1:4173", { waitUntil: "networkidle" });
169
+
170
+ await page.locator('input[type="text"]').first().fill("aios");
171
+ await page.locator('input[type="password"]').fill("123456");
172
+ await page.locator('button[type="submit"]').click();
173
+ await page.locator(".ant-layout-sider").waitFor({ state: "visible" });
174
+
175
+ await page.locator(".ant-layout-sider").getByText("数字员工", { exact: true }).click();
176
+ await page.locator(".page-card .ant-card-extra .ant-btn-primary").waitFor({ state: "visible" });
177
+ await page.locator(".page-card .ant-card-extra .ant-btn-primary").click();
178
+
179
+ const modal = page.locator(".ant-modal-content").filter({ hasText: "新增数字员工" });
180
+ await modal.waitFor({ state: "visible" });
181
+
182
+ await modal.locator('input[type="text"]').nth(0).fill("Bad_Id");
183
+ await modal.locator('input[type="text"]').nth(1).fill("E2E Agent");
184
+ await modal.locator('input[role="spinbutton"]').fill("-1");
185
+ await modal.locator("button.ant-btn-primary").click();
186
+ await modal.locator(".ant-form-item-explain-error").first().waitFor({ state: "visible" });
187
+
188
+ await modal.locator('input[type="text"]').nth(0).fill("finance-agent");
189
+ await modal.locator("button.ant-btn-primary").click();
190
+
191
+ await page.getByRole("cell", { name: "finance-agent" }).waitFor({ state: "visible" });
192
+ await page.getByRole("cell", { name: "E2E Agent" }).waitFor({ state: "visible" });
193
+ await page.getByRole("cell", { name: "正常" }).waitFor({ state: "visible" });
194
+
195
+ assert.deepEqual(createPayload, {
196
+ id: "finance-agent",
197
+ agent_name: "E2E Agent",
198
+ daily_limit: -1
199
+ });
200
+
201
+ console.log("browser e2e passed");
202
+ } finally {
203
+ await context.close();
204
+ await browser.close();
205
+ await vite.close();
206
+ }
207
+ }
208
+
209
+ main().catch((error) => {
210
+ console.error(error);
211
+ process.exit(1);
212
+ });
@@ -0,0 +1,21 @@
1
+ import Jasmine from "jasmine";
2
+
3
+ async function main() {
4
+ const runner = new Jasmine();
5
+ runner.exitOnCompletion = false;
6
+ runner.loadConfig({
7
+ spec_dir: ".",
8
+ spec_files: ["server/test/**/*.test.js"],
9
+ helpers: ["test/setup.js"],
10
+ random: false,
11
+ stopSpecOnExpectationFailure: false
12
+ });
13
+
14
+ const result = await runner.execute();
15
+ process.exit(result.overallStatus === "passed" ? 0 : 1);
16
+ }
17
+
18
+ void main().catch((error) => {
19
+ console.error(error);
20
+ process.exit(1);
21
+ });
package/test/setup.js ADDED
@@ -0,0 +1 @@
1
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = Number(process.env.AIOS_TEST_TIMEOUT_MS || "300000");
package/vite.config.js ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ server: {
7
+ port: 5173,
8
+ proxy: {
9
+ "/api": "http://localhost:3030"
10
+ }
11
+ }
12
+ });