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,39 @@
1
+ import { serviceUnavailable } from "../../utils/errors.js";
2
+
3
+ export class HzgProviderClient {
4
+ constructor({
5
+ fetchImpl = globalThis.fetch
6
+ } = {}) {
7
+ this.fetchImpl = fetchImpl;
8
+ }
9
+
10
+ async createSessionCookie(baseUrl, sessionId) {
11
+ const url = `${String(baseUrl || "").replace(/\/$/, "")}/ServerCommand/`;
12
+ if (typeof this.fetchImpl !== "function") {
13
+ throw serviceUnavailable("Fetch is not available for session establishment");
14
+ }
15
+
16
+ const response = await this.fetchImpl(url, {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json"
20
+ },
21
+ body: JSON.stringify({ ManageThreadId: sessionId })
22
+ });
23
+
24
+ const setCookie = response.headers.get("set-cookie");
25
+ if (setCookie) {
26
+ return setCookie;
27
+ }
28
+
29
+ const body = await response.text();
30
+ try {
31
+ const parsed = JSON.parse(body);
32
+ if (parsed.cookie) {
33
+ return parsed.cookie;
34
+ }
35
+ } catch {}
36
+
37
+ throw serviceUnavailable("Failed to establish Huozige session cookie");
38
+ }
39
+ }
@@ -0,0 +1,97 @@
1
+ import { GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
2
+ import { randomUUID } from "node:crypto";
3
+ import { Readable } from "node:stream";
4
+
5
+ import { serviceUnavailable } from "../../utils/errors.js";
6
+
7
+ function sanitizeFileName(fileName) {
8
+ return fileName.replace(/[^A-Za-z0-9._-]+/g, "-");
9
+ }
10
+
11
+ async function bodyToBuffer(body) {
12
+ if (!body) {
13
+ throw serviceUnavailable("S3 object body is empty");
14
+ }
15
+
16
+ if (typeof body === "object" && typeof body.transformToByteArray === "function") {
17
+ return Buffer.from(await body.transformToByteArray());
18
+ }
19
+
20
+ if (body instanceof Readable) {
21
+ const chunks = [];
22
+ for await (const chunk of body) {
23
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
24
+ }
25
+ return Buffer.concat(chunks);
26
+ }
27
+
28
+ if (body instanceof Uint8Array) {
29
+ return Buffer.from(body);
30
+ }
31
+
32
+ throw serviceUnavailable("Unsupported S3 object body type");
33
+ }
34
+
35
+ export class ObjectStorage {
36
+ constructor(env) {
37
+ this.env = env;
38
+ this.client = null;
39
+ }
40
+
41
+ isConfigured() {
42
+ return Boolean(
43
+ this.env.s3.endpoint &&
44
+ this.env.s3.accessKeyId &&
45
+ this.env.s3.secretAccessKey &&
46
+ this.env.s3.adminInboxBucket
47
+ );
48
+ }
49
+
50
+ getClient() {
51
+ if (!this.isConfigured()) {
52
+ throw serviceUnavailable("S3 artifact storage is not configured");
53
+ }
54
+
55
+ if (!this.client) {
56
+ this.client = new S3Client({
57
+ endpoint: this.env.s3.endpoint,
58
+ region: this.env.s3.region,
59
+ forcePathStyle: this.env.s3.forcePathStyle,
60
+ credentials: {
61
+ accessKeyId: this.env.s3.accessKeyId,
62
+ secretAccessKey: this.env.s3.secretAccessKey
63
+ }
64
+ });
65
+ }
66
+
67
+ return this.client;
68
+ }
69
+
70
+ async uploadAdminArtifact({ kind, file }) {
71
+ const objectKey = `${kind}/${new Date().toISOString().slice(0, 10)}/${randomUUID()}-${sanitizeFileName(file.originalname)}`;
72
+ await this.getClient().send(
73
+ new PutObjectCommand({
74
+ Bucket: this.env.s3.adminInboxBucket,
75
+ Key: objectKey,
76
+ Body: file.buffer,
77
+ ContentType: file.mimetype || "application/octet-stream"
78
+ })
79
+ );
80
+
81
+ return {
82
+ bucket: this.env.s3.adminInboxBucket,
83
+ objectKey
84
+ };
85
+ }
86
+
87
+ async downloadObject(bucket, objectKey) {
88
+ const response = await this.getClient().send(
89
+ new GetObjectCommand({
90
+ Bucket: bucket,
91
+ Key: objectKey
92
+ })
93
+ );
94
+
95
+ return await bodyToBuffer(response.Body);
96
+ }
97
+ }
@@ -0,0 +1,54 @@
1
+ export const AGENT_STATUSES = ["normal", "disabled", "overlimit"];
2
+
3
+ const QUOTA_SPECS = [
4
+ { key: "daily", limitKey: "daily_limit", label: "daily" }
5
+ ];
6
+
7
+ export function isAgentStatus(value) {
8
+ return AGENT_STATUSES.includes(value);
9
+ }
10
+
11
+ export function normalizeAgentStatus(value) {
12
+ return value === "disabled" ? "disabled" : "normal";
13
+ }
14
+
15
+ export function normalizeUsage(payload) {
16
+ if (!payload || typeof payload !== "object") {
17
+ return { daily: 0 };
18
+ }
19
+
20
+ const source = payload.usage || payload.tokens || payload;
21
+ return {
22
+ daily: Number(source.daily ?? source.day ?? source.dailyTokens ?? source.today ?? source.totalTokens ?? 0)
23
+ };
24
+ }
25
+
26
+ export function findQuotaViolation(agent, usage) {
27
+ for (const spec of QUOTA_SPECS) {
28
+ const limit = Number(agent?.[spec.limitKey] ?? -1);
29
+ const current = Number(usage?.[spec.key] ?? 0);
30
+ if (limit >= 0 && current >= limit) {
31
+ return {
32
+ period: spec.label,
33
+ limit,
34
+ current,
35
+ limitKey: spec.limitKey,
36
+ usageKey: spec.key
37
+ };
38
+ }
39
+ }
40
+
41
+ return null;
42
+ }
43
+
44
+ export function isOverLimit(agent, usage) {
45
+ return Boolean(findQuotaViolation(agent, usage));
46
+ }
47
+
48
+ export function statusAfterUsageRefresh(agent, usage) {
49
+ if (agent?.status === "disabled") {
50
+ return "disabled";
51
+ }
52
+
53
+ return isOverLimit(agent, usage) ? "overlimit" : "normal";
54
+ }