@elizaos/autonomous 2.0.0-alpha.10
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/package.json +270 -0
- package/src/actions/emote.ts +101 -0
- package/src/actions/restart.ts +101 -0
- package/src/actions/send-message.ts +168 -0
- package/src/actions/stream-control.ts +439 -0
- package/src/actions/switch-stream-source.ts +126 -0
- package/src/actions/terminal.ts +186 -0
- package/src/api/agent-admin-routes.ts +178 -0
- package/src/api/agent-lifecycle-routes.ts +129 -0
- package/src/api/agent-model.ts +143 -0
- package/src/api/agent-transfer-routes.ts +211 -0
- package/src/api/apps-routes.ts +210 -0
- package/src/api/auth-routes.ts +90 -0
- package/src/api/bsc-trade.ts +736 -0
- package/src/api/bug-report-routes.ts +161 -0
- package/src/api/character-routes.ts +421 -0
- package/src/api/cloud-billing-routes.ts +598 -0
- package/src/api/cloud-compat-routes.ts +192 -0
- package/src/api/cloud-routes.ts +529 -0
- package/src/api/cloud-status-routes.ts +234 -0
- package/src/api/compat-utils.ts +154 -0
- package/src/api/connector-health.ts +135 -0
- package/src/api/coordinator-wiring.ts +179 -0
- package/src/api/credit-detection.ts +47 -0
- package/src/api/database.ts +1357 -0
- package/src/api/diagnostics-routes.ts +389 -0
- package/src/api/drop-service.ts +205 -0
- package/src/api/early-logs.ts +111 -0
- package/src/api/http-helpers.ts +252 -0
- package/src/api/index.ts +85 -0
- package/src/api/knowledge-routes.ts +1189 -0
- package/src/api/knowledge-service-loader.ts +92 -0
- package/src/api/memory-bounds.ts +121 -0
- package/src/api/memory-routes.ts +349 -0
- package/src/api/merkle-tree.ts +239 -0
- package/src/api/models-routes.ts +72 -0
- package/src/api/nfa-routes.ts +169 -0
- package/src/api/nft-verify.ts +188 -0
- package/src/api/og-tracker.ts +72 -0
- package/src/api/parse-action-block.ts +145 -0
- package/src/api/permissions-routes.ts +222 -0
- package/src/api/plugin-validation.ts +355 -0
- package/src/api/provider-switch-config.ts +455 -0
- package/src/api/registry-routes.ts +165 -0
- package/src/api/registry-service.ts +292 -0
- package/src/api/route-helpers.ts +21 -0
- package/src/api/sandbox-routes.ts +1480 -0
- package/src/api/server.ts +17674 -0
- package/src/api/signal-routes.ts +265 -0
- package/src/api/stream-persistence.ts +297 -0
- package/src/api/stream-route-state.ts +48 -0
- package/src/api/stream-routes.ts +1046 -0
- package/src/api/stream-voice-routes.ts +208 -0
- package/src/api/streaming-text.ts +129 -0
- package/src/api/streaming-types.ts +23 -0
- package/src/api/subscription-routes.ts +283 -0
- package/src/api/terminal-run-limits.ts +31 -0
- package/src/api/training-backend-check.ts +40 -0
- package/src/api/training-routes.ts +314 -0
- package/src/api/training-service-like.ts +46 -0
- package/src/api/trajectory-routes.ts +714 -0
- package/src/api/trigger-routes.ts +438 -0
- package/src/api/twitter-verify.ts +226 -0
- package/src/api/tx-service.ts +193 -0
- package/src/api/wallet-dex-prices.ts +206 -0
- package/src/api/wallet-evm-balance.ts +989 -0
- package/src/api/wallet-routes.ts +505 -0
- package/src/api/wallet-rpc.ts +523 -0
- package/src/api/wallet-trading-profile.ts +694 -0
- package/src/api/wallet.ts +745 -0
- package/src/api/whatsapp-routes.ts +282 -0
- package/src/api/zip-utils.ts +130 -0
- package/src/auth/anthropic.ts +63 -0
- package/src/auth/apply-stealth.ts +38 -0
- package/src/auth/claude-code-stealth.ts +141 -0
- package/src/auth/credentials.ts +226 -0
- package/src/auth/index.ts +18 -0
- package/src/auth/openai-codex.ts +94 -0
- package/src/auth/types.ts +24 -0
- package/src/awareness/registry.ts +220 -0
- package/src/bin.ts +10 -0
- package/src/cli/index.ts +36 -0
- package/src/cli/parse-duration.ts +43 -0
- package/src/cloud/auth.test.ts +370 -0
- package/src/cloud/auth.ts +176 -0
- package/src/cloud/backup.test.ts +150 -0
- package/src/cloud/backup.ts +50 -0
- package/src/cloud/base-url.ts +45 -0
- package/src/cloud/bridge-client.test.ts +481 -0
- package/src/cloud/bridge-client.ts +307 -0
- package/src/cloud/cloud-manager.test.ts +223 -0
- package/src/cloud/cloud-manager.ts +151 -0
- package/src/cloud/cloud-proxy.test.ts +122 -0
- package/src/cloud/cloud-proxy.ts +52 -0
- package/src/cloud/index.ts +23 -0
- package/src/cloud/reconnect.test.ts +178 -0
- package/src/cloud/reconnect.ts +108 -0
- package/src/cloud/validate-url.test.ts +147 -0
- package/src/cloud/validate-url.ts +176 -0
- package/src/config/character-schema.ts +44 -0
- package/src/config/config.ts +149 -0
- package/src/config/env-vars.ts +86 -0
- package/src/config/includes.ts +196 -0
- package/src/config/index.ts +15 -0
- package/src/config/object-utils.ts +10 -0
- package/src/config/paths.ts +92 -0
- package/src/config/plugin-auto-enable.ts +520 -0
- package/src/config/schema.ts +1342 -0
- package/src/config/telegram-custom-commands.ts +99 -0
- package/src/config/types.agent-defaults.ts +342 -0
- package/src/config/types.agents.ts +112 -0
- package/src/config/types.gateway.ts +243 -0
- package/src/config/types.hooks.ts +124 -0
- package/src/config/types.messages.ts +201 -0
- package/src/config/types.milady.ts +791 -0
- package/src/config/types.tools.ts +416 -0
- package/src/config/types.ts +7 -0
- package/src/config/zod-schema.agent-runtime.ts +777 -0
- package/src/config/zod-schema.core.ts +778 -0
- package/src/config/zod-schema.hooks.ts +139 -0
- package/src/config/zod-schema.providers-core.ts +1126 -0
- package/src/config/zod-schema.session.ts +98 -0
- package/src/config/zod-schema.ts +865 -0
- package/src/contracts/apps.ts +46 -0
- package/src/contracts/awareness.ts +56 -0
- package/src/contracts/config.ts +172 -0
- package/src/contracts/drop.ts +21 -0
- package/src/contracts/index.ts +8 -0
- package/src/contracts/onboarding.ts +592 -0
- package/src/contracts/permissions.ts +52 -0
- package/src/contracts/verification.ts +9 -0
- package/src/contracts/wallet.ts +503 -0
- package/src/diagnostics/integration-observability.ts +132 -0
- package/src/emotes/catalog.ts +655 -0
- package/src/external-modules.d.ts +7 -0
- package/src/hooks/discovery.test.ts +357 -0
- package/src/hooks/discovery.ts +231 -0
- package/src/hooks/eligibility.ts +146 -0
- package/src/hooks/hooks.test.ts +320 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/loader.test.ts +418 -0
- package/src/hooks/loader.ts +256 -0
- package/src/hooks/registry.test.ts +168 -0
- package/src/hooks/registry.ts +74 -0
- package/src/hooks/types.ts +121 -0
- package/src/index.ts +19 -0
- package/src/onboarding-presets.ts +828 -0
- package/src/plugins/custom-rtmp/index.ts +40 -0
- package/src/providers/admin-trust.ts +76 -0
- package/src/providers/session-bridge.ts +143 -0
- package/src/providers/session-utils.ts +42 -0
- package/src/providers/simple-mode.ts +113 -0
- package/src/providers/ui-catalog.ts +135 -0
- package/src/providers/workspace-provider.ts +213 -0
- package/src/providers/workspace.ts +497 -0
- package/src/runtime/agent-event-service.ts +57 -0
- package/src/runtime/cloud-onboarding.test.ts +489 -0
- package/src/runtime/cloud-onboarding.ts +408 -0
- package/src/runtime/core-plugins.ts +53 -0
- package/src/runtime/custom-actions.ts +605 -0
- package/src/runtime/eliza.ts +4941 -0
- package/src/runtime/embedding-presets.ts +73 -0
- package/src/runtime/index.ts +8 -0
- package/src/runtime/milady-plugin.ts +180 -0
- package/src/runtime/onboarding-names.ts +76 -0
- package/src/runtime/release-plugin-policy.ts +119 -0
- package/src/runtime/restart.ts +59 -0
- package/src/runtime/trajectory-persistence.ts +2584 -0
- package/src/runtime/version.ts +6 -0
- package/src/security/audit-log.ts +222 -0
- package/src/security/network-policy.ts +91 -0
- package/src/server/index.ts +6 -0
- package/src/services/agent-export.ts +976 -0
- package/src/services/app-manager.ts +755 -0
- package/src/services/browser-capture.ts +215 -0
- package/src/services/coding-agent-context.ts +355 -0
- package/src/services/fallback-training-service.ts +196 -0
- package/src/services/index.ts +17 -0
- package/src/services/mcp-marketplace.ts +327 -0
- package/src/services/plugin-manager-types.ts +185 -0
- package/src/services/privy-wallets.ts +352 -0
- package/src/services/registry-client-app-meta.ts +201 -0
- package/src/services/registry-client-endpoints.ts +253 -0
- package/src/services/registry-client-local.ts +485 -0
- package/src/services/registry-client-network.ts +173 -0
- package/src/services/registry-client-queries.ts +176 -0
- package/src/services/registry-client-types.ts +104 -0
- package/src/services/registry-client.ts +366 -0
- package/src/services/remote-signing-service.ts +261 -0
- package/src/services/sandbox-engine.ts +753 -0
- package/src/services/sandbox-manager.ts +503 -0
- package/src/services/self-updater.ts +213 -0
- package/src/services/signal-pairing.ts +189 -0
- package/src/services/signing-policy.ts +230 -0
- package/src/services/skill-catalog-client.ts +195 -0
- package/src/services/skill-marketplace.ts +909 -0
- package/src/services/stream-manager.ts +707 -0
- package/src/services/tts-stream-bridge.ts +465 -0
- package/src/services/update-checker.ts +163 -0
- package/src/services/version-compat.ts +367 -0
- package/src/services/whatsapp-pairing.ts +279 -0
- package/src/shared/ui-catalog-prompt.ts +1158 -0
- package/src/test-support/process-helpers.ts +35 -0
- package/src/test-support/route-test-helpers.ts +113 -0
- package/src/test-support/test-helpers.ts +304 -0
- package/src/testing/index.ts +3 -0
- package/src/triggers/action.ts +342 -0
- package/src/triggers/runtime.ts +432 -0
- package/src/triggers/scheduling.ts +472 -0
- package/src/triggers/types.ts +133 -0
- package/src/types/app-hyperscape-routes-shim.d.ts +29 -0
- package/src/types/external-modules.d.ts +7 -0
- package/src/utils/exec-safety.ts +23 -0
- package/src/utils/number-parsing.ts +112 -0
- package/src/utils/spoken-text.ts +65 -0
- package/src/version-resolver.ts +60 -0
- package/test/api/agent-admin-routes.test.ts +160 -0
- package/test/api/agent-lifecycle-routes.test.ts +164 -0
- package/test/api/agent-transfer-routes.test.ts +136 -0
- package/test/api/apps-routes.test.ts +140 -0
- package/test/api/auth-routes.test.ts +160 -0
- package/test/api/bug-report-routes.test.ts +88 -0
- package/test/api/knowledge-routes.test.ts +73 -0
- package/test/api/lifecycle.test.ts +342 -0
- package/test/api/memory-routes.test.ts +74 -0
- package/test/api/models-routes.test.ts +112 -0
- package/test/api/nfa-routes.test.ts +78 -0
- package/test/api/permissions-routes.test.ts +185 -0
- package/test/api/registry-routes.test.ts +157 -0
- package/test/api/signal-routes.test.ts +113 -0
- package/test/api/subscription-routes.test.ts +90 -0
- package/test/api/trigger-routes.test.ts +87 -0
- package/test/api/wallet-routes.observability.test.ts +191 -0
- package/test/api/wallet-routes.test.ts +502 -0
- package/test/diagnostics/integration-observability.test.ts +135 -0
- package/test/security/audit-log.test.ts +229 -0
- package/test/security/network-policy.test.ts +143 -0
- package/test/services/version-compat.test.ts +127 -0
- package/tsconfig.build.json +21 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createMockIncomingMessage,
|
|
4
|
+
createMockHttpResponse,
|
|
5
|
+
} from "../../src/test-support/test-helpers";
|
|
6
|
+
import { handlePermissionRoutes } from "../../src/api/permissions-routes";
|
|
7
|
+
import type { PermissionRouteContext } from "../../src/api/permissions-routes";
|
|
8
|
+
|
|
9
|
+
function buildCtx(
|
|
10
|
+
method: string,
|
|
11
|
+
pathname: string,
|
|
12
|
+
overrides?: Partial<PermissionRouteContext>,
|
|
13
|
+
): PermissionRouteContext {
|
|
14
|
+
const { res } = createMockHttpResponse();
|
|
15
|
+
return {
|
|
16
|
+
req: createMockIncomingMessage({ method, url: pathname }),
|
|
17
|
+
res,
|
|
18
|
+
method,
|
|
19
|
+
pathname,
|
|
20
|
+
json: vi.fn((r, data, status = 200) => {
|
|
21
|
+
r.writeHead(status);
|
|
22
|
+
r.end(JSON.stringify(data));
|
|
23
|
+
}),
|
|
24
|
+
error: vi.fn((r, msg, status = 500) => {
|
|
25
|
+
r.writeHead(status);
|
|
26
|
+
r.end(JSON.stringify({ error: msg }));
|
|
27
|
+
}),
|
|
28
|
+
readJsonBody: vi.fn(async () => ({})),
|
|
29
|
+
state: {
|
|
30
|
+
runtime: null,
|
|
31
|
+
config: { features: { shellEnabled: false } },
|
|
32
|
+
permissionStates: {},
|
|
33
|
+
shellEnabled: false,
|
|
34
|
+
},
|
|
35
|
+
saveConfig: vi.fn(),
|
|
36
|
+
scheduleRuntimeRestart: vi.fn(),
|
|
37
|
+
...overrides,
|
|
38
|
+
} as PermissionRouteContext;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("permissions-routes", () => {
|
|
42
|
+
describe("GET /api/permissions", () => {
|
|
43
|
+
test("returns permission states with platform", async () => {
|
|
44
|
+
const ctx = buildCtx("GET", "/api/permissions");
|
|
45
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
46
|
+
expect(handled).toBe(true);
|
|
47
|
+
expect(ctx.json).toHaveBeenCalledOnce();
|
|
48
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
49
|
+
expect(payload).toHaveProperty("_platform");
|
|
50
|
+
expect(payload).toHaveProperty("_shellEnabled");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("GET /api/permissions/shell", () => {
|
|
55
|
+
test("returns shell permission state", async () => {
|
|
56
|
+
const ctx = buildCtx("GET", "/api/permissions/shell");
|
|
57
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
58
|
+
expect(handled).toBe(true);
|
|
59
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
60
|
+
expect(payload).toHaveProperty("enabled");
|
|
61
|
+
expect(payload).toHaveProperty("permission");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("GET /api/permissions/:id", () => {
|
|
66
|
+
test("returns not-applicable for unknown permission", async () => {
|
|
67
|
+
const ctx = buildCtx("GET", "/api/permissions/camera");
|
|
68
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
69
|
+
expect(handled).toBe(true);
|
|
70
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
71
|
+
expect(payload.status).toBe("not-applicable");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("returns stored state for known permission", async () => {
|
|
75
|
+
const ctx = buildCtx("GET", "/api/permissions/camera", {
|
|
76
|
+
state: {
|
|
77
|
+
runtime: null,
|
|
78
|
+
config: {},
|
|
79
|
+
permissionStates: {
|
|
80
|
+
camera: {
|
|
81
|
+
id: "camera",
|
|
82
|
+
status: "granted",
|
|
83
|
+
lastChecked: Date.now(),
|
|
84
|
+
canRequest: false,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
90
|
+
expect(handled).toBe(true);
|
|
91
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
92
|
+
expect(payload.status).toBe("granted");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("PUT /api/permissions/shell", () => {
|
|
97
|
+
test("enables shell and saves config", async () => {
|
|
98
|
+
const ctx = buildCtx("PUT", "/api/permissions/shell", {
|
|
99
|
+
readJsonBody: vi.fn(async () => ({ enabled: true })),
|
|
100
|
+
});
|
|
101
|
+
await handlePermissionRoutes(ctx);
|
|
102
|
+
expect(ctx.saveConfig).toHaveBeenCalled();
|
|
103
|
+
expect(ctx.state.shellEnabled).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("schedules restart when runtime exists", async () => {
|
|
107
|
+
const ctx = buildCtx("PUT", "/api/permissions/shell", {
|
|
108
|
+
readJsonBody: vi.fn(async () => ({ enabled: true })),
|
|
109
|
+
state: {
|
|
110
|
+
runtime: {} as any,
|
|
111
|
+
config: { features: {} },
|
|
112
|
+
shellEnabled: false,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
await handlePermissionRoutes(ctx);
|
|
116
|
+
expect(ctx.scheduleRuntimeRestart).toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("does not schedule restart when no runtime", async () => {
|
|
120
|
+
const ctx = buildCtx("PUT", "/api/permissions/shell", {
|
|
121
|
+
readJsonBody: vi.fn(async () => ({ enabled: true })),
|
|
122
|
+
});
|
|
123
|
+
await handlePermissionRoutes(ctx);
|
|
124
|
+
expect(ctx.scheduleRuntimeRestart).not.toHaveBeenCalled();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("POST /api/permissions/refresh", () => {
|
|
129
|
+
test("returns refresh message", async () => {
|
|
130
|
+
const ctx = buildCtx("POST", "/api/permissions/refresh");
|
|
131
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
132
|
+
expect(handled).toBe(true);
|
|
133
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
134
|
+
expect(payload.action).toBe("ipc:permissions:refresh");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("POST /api/permissions/:id/request", () => {
|
|
139
|
+
test("returns request action", async () => {
|
|
140
|
+
const ctx = buildCtx("POST", "/api/permissions/camera/request");
|
|
141
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
142
|
+
expect(handled).toBe(true);
|
|
143
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
144
|
+
expect(payload.action).toBe("ipc:permissions:request:camera");
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe("POST /api/permissions/:id/open-settings", () => {
|
|
149
|
+
test("returns open-settings action", async () => {
|
|
150
|
+
const ctx = buildCtx("POST", "/api/permissions/microphone/open-settings");
|
|
151
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
152
|
+
expect(handled).toBe(true);
|
|
153
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
154
|
+
expect(payload.action).toBe("ipc:permissions:openSettings:microphone");
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("PUT /api/permissions/state", () => {
|
|
159
|
+
test("updates permission states", async () => {
|
|
160
|
+
const ctx = buildCtx("PUT", "/api/permissions/state", {
|
|
161
|
+
readJsonBody: vi.fn(async () => ({
|
|
162
|
+
permissions: {
|
|
163
|
+
camera: {
|
|
164
|
+
id: "camera",
|
|
165
|
+
status: "granted",
|
|
166
|
+
lastChecked: Date.now(),
|
|
167
|
+
canRequest: false,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
})),
|
|
171
|
+
});
|
|
172
|
+
const handled = await handlePermissionRoutes(ctx);
|
|
173
|
+
expect(handled).toBe(true);
|
|
174
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
175
|
+
expect(payload.updated).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("routing", () => {
|
|
180
|
+
test("unrelated path returns false", async () => {
|
|
181
|
+
const ctx = buildCtx("GET", "/api/other");
|
|
182
|
+
expect(await handlePermissionRoutes(ctx)).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createMockIncomingMessage,
|
|
4
|
+
createMockHttpResponse,
|
|
5
|
+
} from "../../src/test-support/test-helpers";
|
|
6
|
+
import { handleRegistryRoutes } from "../../src/api/registry-routes";
|
|
7
|
+
import type { RegistryRouteContext } from "../../src/api/registry-routes";
|
|
8
|
+
|
|
9
|
+
function buildCtx(
|
|
10
|
+
method: string,
|
|
11
|
+
pathname: string,
|
|
12
|
+
overrides?: Partial<RegistryRouteContext>,
|
|
13
|
+
): RegistryRouteContext & { getStatus: () => number; getJson: () => unknown } {
|
|
14
|
+
const { res, getStatus, getJson } = createMockHttpResponse();
|
|
15
|
+
const urlString = `http://localhost:2138${pathname}`;
|
|
16
|
+
const req = createMockIncomingMessage({ method, url: pathname });
|
|
17
|
+
const ctx = {
|
|
18
|
+
req,
|
|
19
|
+
res,
|
|
20
|
+
method,
|
|
21
|
+
pathname,
|
|
22
|
+
url: new URL(urlString),
|
|
23
|
+
json: vi.fn((r, data, status = 200) => {
|
|
24
|
+
r.writeHead(status);
|
|
25
|
+
r.end(JSON.stringify(data));
|
|
26
|
+
}),
|
|
27
|
+
error: vi.fn((r, msg, status = 500) => {
|
|
28
|
+
r.writeHead(status);
|
|
29
|
+
r.end(JSON.stringify({ error: msg }));
|
|
30
|
+
}),
|
|
31
|
+
getPluginManager: () => ({
|
|
32
|
+
refreshRegistry: vi.fn(async () => new Map()),
|
|
33
|
+
listInstalledPlugins: vi.fn(async () => []),
|
|
34
|
+
getRegistryPlugin: vi.fn(async () => null),
|
|
35
|
+
searchRegistry: vi.fn(async () => []),
|
|
36
|
+
}),
|
|
37
|
+
getLoadedPluginNames: () => [],
|
|
38
|
+
getBundledPluginIds: () => new Set<string>(),
|
|
39
|
+
classifyRegistryPluginRelease: () => "compatible",
|
|
40
|
+
...overrides,
|
|
41
|
+
} as RegistryRouteContext & {
|
|
42
|
+
getStatus: () => number;
|
|
43
|
+
getJson: () => unknown;
|
|
44
|
+
};
|
|
45
|
+
(ctx as any).getStatus = getStatus;
|
|
46
|
+
(ctx as any).getJson = getJson;
|
|
47
|
+
return ctx;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("registry-routes", () => {
|
|
51
|
+
describe("GET /api/registry/plugins", () => {
|
|
52
|
+
test("returns empty plugin list from empty registry", async () => {
|
|
53
|
+
const ctx = buildCtx("GET", "/api/registry/plugins");
|
|
54
|
+
const handled = await handleRegistryRoutes(ctx);
|
|
55
|
+
expect(handled).toBe(true);
|
|
56
|
+
expect(ctx.json).toHaveBeenCalledOnce();
|
|
57
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
58
|
+
expect(payload.count).toBe(0);
|
|
59
|
+
expect(payload.plugins).toEqual([]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("returns plugins with installed/loaded/bundled flags", async () => {
|
|
63
|
+
const registry = new Map([
|
|
64
|
+
[
|
|
65
|
+
"@elizaos/plugin-foo",
|
|
66
|
+
{ name: "@elizaos/plugin-foo", kind: "plugin" },
|
|
67
|
+
],
|
|
68
|
+
]);
|
|
69
|
+
const pluginManager = {
|
|
70
|
+
refreshRegistry: vi.fn(async () => registry),
|
|
71
|
+
listInstalledPlugins: vi.fn(async () => [
|
|
72
|
+
{ name: "@elizaos/plugin-foo", version: "1.0.0" },
|
|
73
|
+
]),
|
|
74
|
+
getRegistryPlugin: vi.fn(async () => null),
|
|
75
|
+
searchRegistry: vi.fn(async () => []),
|
|
76
|
+
};
|
|
77
|
+
const ctx = buildCtx("GET", "/api/registry/plugins", {
|
|
78
|
+
getPluginManager: () => pluginManager,
|
|
79
|
+
getLoadedPluginNames: () => ["@elizaos/plugin-foo"],
|
|
80
|
+
getBundledPluginIds: () => new Set(["foo"]),
|
|
81
|
+
});
|
|
82
|
+
const handled = await handleRegistryRoutes(ctx);
|
|
83
|
+
expect(handled).toBe(true);
|
|
84
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
85
|
+
expect(payload.count).toBe(1);
|
|
86
|
+
expect(payload.plugins[0].installed).toBe(true);
|
|
87
|
+
expect(payload.plugins[0].loaded).toBe(true);
|
|
88
|
+
expect(payload.plugins[0].bundled).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("returns 502 when registry refresh throws", async () => {
|
|
92
|
+
const pluginManager = {
|
|
93
|
+
refreshRegistry: vi.fn(async () => {
|
|
94
|
+
throw new Error("network error");
|
|
95
|
+
}),
|
|
96
|
+
listInstalledPlugins: vi.fn(async () => []),
|
|
97
|
+
getRegistryPlugin: vi.fn(async () => null),
|
|
98
|
+
searchRegistry: vi.fn(async () => []),
|
|
99
|
+
};
|
|
100
|
+
const ctx = buildCtx("GET", "/api/registry/plugins", {
|
|
101
|
+
getPluginManager: () => pluginManager,
|
|
102
|
+
});
|
|
103
|
+
const handled = await handleRegistryRoutes(ctx);
|
|
104
|
+
expect(handled).toBe(true);
|
|
105
|
+
expect(ctx.error).toHaveBeenCalledOnce();
|
|
106
|
+
const args = (ctx.error as ReturnType<typeof vi.fn>).mock.calls[0];
|
|
107
|
+
expect(args[2]).toBe(502);
|
|
108
|
+
expect(args[1]).toContain("network error");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("GET /api/registry/search", () => {
|
|
113
|
+
test("returns 400 when query parameter is empty", async () => {
|
|
114
|
+
const ctx = buildCtx("GET", "/api/registry/search");
|
|
115
|
+
const handled = await handleRegistryRoutes(ctx);
|
|
116
|
+
expect(handled).toBe(true);
|
|
117
|
+
expect(ctx.error).toHaveBeenCalledOnce();
|
|
118
|
+
const args = (ctx.error as ReturnType<typeof vi.fn>).mock.calls[0];
|
|
119
|
+
expect(args[2]).toBe(400);
|
|
120
|
+
expect(args[1]).toContain("'q' is required");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("returns results when query is provided", async () => {
|
|
124
|
+
const searchResults = [{ name: "@elizaos/plugin-foo" }];
|
|
125
|
+
const pluginManager = {
|
|
126
|
+
refreshRegistry: vi.fn(async () => new Map()),
|
|
127
|
+
listInstalledPlugins: vi.fn(async () => []),
|
|
128
|
+
getRegistryPlugin: vi.fn(async () => null),
|
|
129
|
+
searchRegistry: vi.fn(async () => searchResults),
|
|
130
|
+
};
|
|
131
|
+
const ctx = buildCtx("GET", "/api/registry/search?q=foo", {
|
|
132
|
+
getPluginManager: () => pluginManager,
|
|
133
|
+
url: new URL("http://localhost:2138/api/registry/search?q=foo"),
|
|
134
|
+
});
|
|
135
|
+
ctx.pathname = "/api/registry/search";
|
|
136
|
+
const handled = await handleRegistryRoutes(ctx);
|
|
137
|
+
expect(handled).toBe(true);
|
|
138
|
+
expect(ctx.json).toHaveBeenCalledOnce();
|
|
139
|
+
const payload = (ctx.json as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
140
|
+
expect(payload.query).toBe("foo");
|
|
141
|
+
expect(payload.count).toBe(1);
|
|
142
|
+
expect(payload.results).toEqual(searchResults);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("routing", () => {
|
|
147
|
+
test("unrelated path returns false", async () => {
|
|
148
|
+
const ctx = buildCtx("GET", "/api/other");
|
|
149
|
+
expect(await handleRegistryRoutes(ctx)).toBe(false);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("POST to /api/registry/plugins returns false (wrong method)", async () => {
|
|
153
|
+
const ctx = buildCtx("POST", "/api/registry/plugins");
|
|
154
|
+
expect(await handleRegistryRoutes(ctx)).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createMockIncomingMessage,
|
|
4
|
+
createMockHttpResponse,
|
|
5
|
+
} from "../../src/test-support/test-helpers";
|
|
6
|
+
import type {
|
|
7
|
+
SignalRouteState,
|
|
8
|
+
SignalRouteDeps,
|
|
9
|
+
} from "../../src/api/signal-routes";
|
|
10
|
+
import { handleSignalRoute } from "../../src/api/signal-routes";
|
|
11
|
+
|
|
12
|
+
function buildState(
|
|
13
|
+
overrides: Partial<SignalRouteState> = {},
|
|
14
|
+
): SignalRouteState {
|
|
15
|
+
return {
|
|
16
|
+
signalPairingSessions: new Map(),
|
|
17
|
+
broadcastWs: vi.fn(),
|
|
18
|
+
config: {},
|
|
19
|
+
runtime: undefined,
|
|
20
|
+
saveConfig: vi.fn(),
|
|
21
|
+
workspaceDir: "/tmp/test-workspace",
|
|
22
|
+
...overrides,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function buildDeps(overrides: Partial<SignalRouteDeps> = {}): SignalRouteDeps {
|
|
27
|
+
return {
|
|
28
|
+
sanitizeAccountId: vi.fn((id: string) => id),
|
|
29
|
+
signalAuthExists: vi.fn(() => false),
|
|
30
|
+
signalLogout: vi.fn(),
|
|
31
|
+
createSignalPairingSession: vi.fn(() => ({
|
|
32
|
+
start: vi.fn(async () => {}),
|
|
33
|
+
stop: vi.fn(),
|
|
34
|
+
getStatus: vi.fn(() => "pairing"),
|
|
35
|
+
})),
|
|
36
|
+
...overrides,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("handleSignalRoute", () => {
|
|
41
|
+
test("returns false for unrelated path", async () => {
|
|
42
|
+
const req = createMockIncomingMessage({ method: "GET", url: "/api/other" });
|
|
43
|
+
const { res } = createMockHttpResponse();
|
|
44
|
+
const state = buildState();
|
|
45
|
+
const deps = buildDeps();
|
|
46
|
+
|
|
47
|
+
const handled = await handleSignalRoute(
|
|
48
|
+
req,
|
|
49
|
+
res,
|
|
50
|
+
"/api/other",
|
|
51
|
+
"GET",
|
|
52
|
+
state,
|
|
53
|
+
deps,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(handled).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("POST /api/signal/pair creates a pairing session", async () => {
|
|
60
|
+
const req = createMockIncomingMessage({
|
|
61
|
+
method: "POST",
|
|
62
|
+
url: "/api/signal/pair",
|
|
63
|
+
body: JSON.stringify({ accountId: "test-account" }),
|
|
64
|
+
headers: { host: "localhost:2138", "content-type": "application/json" },
|
|
65
|
+
});
|
|
66
|
+
const { res, getStatus, getJson } = createMockHttpResponse();
|
|
67
|
+
const state = buildState();
|
|
68
|
+
const deps = buildDeps();
|
|
69
|
+
|
|
70
|
+
const handled = await handleSignalRoute(
|
|
71
|
+
req,
|
|
72
|
+
res,
|
|
73
|
+
"/api/signal/pair",
|
|
74
|
+
"POST",
|
|
75
|
+
state,
|
|
76
|
+
deps,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(handled).toBe(true);
|
|
80
|
+
expect(getStatus()).toBe(200);
|
|
81
|
+
const json = getJson<{ ok: boolean; accountId: string }>();
|
|
82
|
+
expect(json.ok).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("POST /api/signal/pair returns 400 when sanitizeAccountId throws", async () => {
|
|
86
|
+
const req = createMockIncomingMessage({
|
|
87
|
+
method: "POST",
|
|
88
|
+
url: "/api/signal/pair",
|
|
89
|
+
body: JSON.stringify({ accountId: "" }),
|
|
90
|
+
headers: { host: "localhost:2138", "content-type": "application/json" },
|
|
91
|
+
});
|
|
92
|
+
const { res, getStatus, getJson } = createMockHttpResponse();
|
|
93
|
+
const state = buildState();
|
|
94
|
+
const deps = buildDeps({
|
|
95
|
+
sanitizeAccountId: vi.fn(() => {
|
|
96
|
+
throw new Error("Invalid account ID");
|
|
97
|
+
}),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const handled = await handleSignalRoute(
|
|
101
|
+
req,
|
|
102
|
+
res,
|
|
103
|
+
"/api/signal/pair",
|
|
104
|
+
"POST",
|
|
105
|
+
state,
|
|
106
|
+
deps,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
expect(handled).toBe(true);
|
|
110
|
+
expect(getStatus()).toBe(400);
|
|
111
|
+
expect(getJson<{ error: string }>().error).toBe("Invalid account ID");
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createMockIncomingMessage,
|
|
4
|
+
createMockHttpResponse,
|
|
5
|
+
} from "../../src/test-support/test-helpers";
|
|
6
|
+
import type { SubscriptionRouteContext } from "../../src/api/subscription-routes";
|
|
7
|
+
import { handleSubscriptionRoutes } from "../../src/api/subscription-routes";
|
|
8
|
+
|
|
9
|
+
function buildCtx(
|
|
10
|
+
overrides: Partial<SubscriptionRouteContext> = {},
|
|
11
|
+
): SubscriptionRouteContext {
|
|
12
|
+
const { res } = createMockHttpResponse();
|
|
13
|
+
return {
|
|
14
|
+
req: createMockIncomingMessage({ method: "GET", url: "/" }),
|
|
15
|
+
res,
|
|
16
|
+
method: "GET",
|
|
17
|
+
pathname: "/",
|
|
18
|
+
json: vi.fn((r, data, status = 200) => {
|
|
19
|
+
r.writeHead(status);
|
|
20
|
+
r.end(JSON.stringify(data));
|
|
21
|
+
}),
|
|
22
|
+
error: vi.fn((r, message, status = 500) => {
|
|
23
|
+
r.writeHead(status);
|
|
24
|
+
r.end(JSON.stringify({ error: message }));
|
|
25
|
+
}),
|
|
26
|
+
readJsonBody: vi.fn(async () => null),
|
|
27
|
+
state: {
|
|
28
|
+
config: {},
|
|
29
|
+
},
|
|
30
|
+
saveConfig: vi.fn(),
|
|
31
|
+
loadSubscriptionAuth: vi.fn(async () => ({
|
|
32
|
+
getSubscriptionStatus: vi.fn(() => ({ anthropic: "active" })),
|
|
33
|
+
startAnthropicLogin: vi.fn(),
|
|
34
|
+
startCodexLogin: vi.fn(),
|
|
35
|
+
saveCredentials: vi.fn(),
|
|
36
|
+
applySubscriptionCredentials: vi.fn(),
|
|
37
|
+
deleteCredentials: vi.fn(),
|
|
38
|
+
})),
|
|
39
|
+
...overrides,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("handleSubscriptionRoutes", () => {
|
|
44
|
+
test("returns false for unrelated path", async () => {
|
|
45
|
+
const ctx = buildCtx({ pathname: "/api/other" });
|
|
46
|
+
const handled = await handleSubscriptionRoutes(ctx);
|
|
47
|
+
expect(handled).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("GET /api/subscription/status returns provider status", async () => {
|
|
51
|
+
const { res, getStatus, getJson } = createMockHttpResponse();
|
|
52
|
+
const providerStatuses = { anthropic: "active", openai: "inactive" };
|
|
53
|
+
const ctx = buildCtx({
|
|
54
|
+
method: "GET",
|
|
55
|
+
pathname: "/api/subscription/status",
|
|
56
|
+
res,
|
|
57
|
+
loadSubscriptionAuth: vi.fn(async () => ({
|
|
58
|
+
getSubscriptionStatus: vi.fn(() => providerStatuses),
|
|
59
|
+
startAnthropicLogin: vi.fn(),
|
|
60
|
+
startCodexLogin: vi.fn(),
|
|
61
|
+
saveCredentials: vi.fn(),
|
|
62
|
+
applySubscriptionCredentials: vi.fn(),
|
|
63
|
+
deleteCredentials: vi.fn(),
|
|
64
|
+
})),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const handled = await handleSubscriptionRoutes(ctx);
|
|
68
|
+
|
|
69
|
+
expect(handled).toBe(true);
|
|
70
|
+
expect(getStatus()).toBe(200);
|
|
71
|
+
expect(getJson()).toEqual({ providers: providerStatuses });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("GET /api/subscription/status returns 500 when loadSubscriptionAuth throws", async () => {
|
|
75
|
+
const { res, getStatus } = createMockHttpResponse();
|
|
76
|
+
const ctx = buildCtx({
|
|
77
|
+
method: "GET",
|
|
78
|
+
pathname: "/api/subscription/status",
|
|
79
|
+
res,
|
|
80
|
+
loadSubscriptionAuth: vi.fn(async () => {
|
|
81
|
+
throw new Error("auth module unavailable");
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const handled = await handleSubscriptionRoutes(ctx);
|
|
86
|
+
|
|
87
|
+
expect(handled).toBe(true);
|
|
88
|
+
expect(getStatus()).toBe(500);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createMockIncomingMessage,
|
|
4
|
+
createMockHttpResponse,
|
|
5
|
+
} from "../../src/test-support/test-helpers";
|
|
6
|
+
import type { TriggerRouteContext } from "../../src/api/trigger-routes";
|
|
7
|
+
import { handleTriggerRoutes } from "../../src/api/trigger-routes";
|
|
8
|
+
|
|
9
|
+
function buildCtx(
|
|
10
|
+
overrides: Partial<TriggerRouteContext> = {},
|
|
11
|
+
): TriggerRouteContext {
|
|
12
|
+
const { res } = createMockHttpResponse();
|
|
13
|
+
return {
|
|
14
|
+
req: createMockIncomingMessage({ method: "GET", url: "/" }),
|
|
15
|
+
res,
|
|
16
|
+
method: "GET",
|
|
17
|
+
pathname: "/",
|
|
18
|
+
json: vi.fn((r, data, status = 200) => {
|
|
19
|
+
r.writeHead(status);
|
|
20
|
+
r.end(JSON.stringify(data));
|
|
21
|
+
}),
|
|
22
|
+
error: vi.fn((r, message, status = 500) => {
|
|
23
|
+
r.writeHead(status);
|
|
24
|
+
r.end(JSON.stringify({ error: message }));
|
|
25
|
+
}),
|
|
26
|
+
readJsonBody: vi.fn(async () => null),
|
|
27
|
+
runtime: null,
|
|
28
|
+
executeTriggerTask: vi.fn(),
|
|
29
|
+
getTriggerHealthSnapshot: vi.fn(async () => ({ healthy: true })),
|
|
30
|
+
getTriggerLimit: vi.fn(() => 10),
|
|
31
|
+
listTriggerTasks: vi.fn(async () => []),
|
|
32
|
+
readTriggerConfig: vi.fn(() => null),
|
|
33
|
+
readTriggerRuns: vi.fn(() => []),
|
|
34
|
+
taskToTriggerSummary: vi.fn(() => null),
|
|
35
|
+
triggersFeatureEnabled: vi.fn(() => true),
|
|
36
|
+
buildTriggerConfig: vi.fn(),
|
|
37
|
+
buildTriggerMetadata: vi.fn(() => null),
|
|
38
|
+
normalizeTriggerDraft: vi.fn(() => ({ draft: undefined, error: "noop" })),
|
|
39
|
+
DISABLED_TRIGGER_INTERVAL_MS: 86_400_000,
|
|
40
|
+
TRIGGER_TASK_NAME: "trigger",
|
|
41
|
+
TRIGGER_TASK_TAGS: ["trigger"],
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("handleTriggerRoutes", () => {
|
|
47
|
+
test("returns false for unrelated path", async () => {
|
|
48
|
+
const ctx = buildCtx({ pathname: "/api/other" });
|
|
49
|
+
const handled = await handleTriggerRoutes(ctx);
|
|
50
|
+
expect(handled).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("returns 503 when runtime is null", async () => {
|
|
54
|
+
const { res, getStatus, getJson } = createMockHttpResponse();
|
|
55
|
+
const ctx = buildCtx({
|
|
56
|
+
method: "GET",
|
|
57
|
+
pathname: "/api/triggers",
|
|
58
|
+
res,
|
|
59
|
+
runtime: null,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const handled = await handleTriggerRoutes(ctx);
|
|
63
|
+
|
|
64
|
+
expect(handled).toBe(true);
|
|
65
|
+
expect(getStatus()).toBe(503);
|
|
66
|
+
expect(getJson()).toEqual({ error: "Agent is not running" });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("GET /api/triggers/health returns snapshot even without runtime features enabled", async () => {
|
|
70
|
+
const { res, getStatus, getJson } = createMockHttpResponse();
|
|
71
|
+
const snapshot = { healthy: true, triggers: 0 };
|
|
72
|
+
const ctx = buildCtx({
|
|
73
|
+
method: "GET",
|
|
74
|
+
pathname: "/api/triggers/health",
|
|
75
|
+
res,
|
|
76
|
+
runtime: {} as TriggerRouteContext["runtime"],
|
|
77
|
+
triggersFeatureEnabled: vi.fn(() => false),
|
|
78
|
+
getTriggerHealthSnapshot: vi.fn(async () => snapshot),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const handled = await handleTriggerRoutes(ctx);
|
|
82
|
+
|
|
83
|
+
expect(handled).toBe(true);
|
|
84
|
+
expect(getStatus()).toBe(200);
|
|
85
|
+
expect(getJson()).toEqual(snapshot);
|
|
86
|
+
});
|
|
87
|
+
});
|