miladyai 2.0.0-alpha.27
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/dist/_virtual/_rolldown/runtime.js +7 -0
- package/dist/actions/emote.js +64 -0
- package/dist/actions/restart.js +81 -0
- package/dist/actions/send-message.js +152 -0
- package/dist/agent-admin-routes.js +82 -0
- package/dist/agent-lifecycle-routes.js +79 -0
- package/dist/agent-transfer-routes.js +102 -0
- package/dist/api/agent-admin-routes.js +82 -0
- package/dist/api/agent-lifecycle-routes.js +79 -0
- package/dist/api/agent-transfer-routes.js +102 -0
- package/dist/api/apps-hyperscape-routes.js +58 -0
- package/dist/api/apps-routes.js +114 -0
- package/dist/api/auth-routes.js +56 -0
- package/dist/api/autonomy-routes.js +44 -0
- package/dist/api/bug-report-routes.js +111 -0
- package/dist/api/character-routes.js +195 -0
- package/dist/api/cloud-routes.js +330 -0
- package/dist/api/cloud-status-routes.js +155 -0
- package/dist/api/compat-utils.js +111 -0
- package/dist/api/database.js +735 -0
- package/dist/api/diagnostics-routes.js +205 -0
- package/dist/api/drop-service.js +134 -0
- package/dist/api/early-logs.js +86 -0
- package/dist/api/http-helpers.js +131 -0
- package/dist/api/knowledge-routes.js +534 -0
- package/dist/api/memory-bounds.js +71 -0
- package/dist/api/models-routes.js +28 -0
- package/dist/api/og-tracker.js +36 -0
- package/dist/api/permissions-routes.js +109 -0
- package/dist/api/plugin-validation.js +198 -0
- package/dist/api/provider-switch-config.js +41 -0
- package/dist/api/registry-routes.js +86 -0
- package/dist/api/registry-service.js +164 -0
- package/dist/api/sandbox-routes.js +1112 -0
- package/dist/api/server.js +7949 -0
- package/dist/api/subscription-routes.js +172 -0
- package/dist/api/terminal-run-limits.js +24 -0
- package/dist/api/training-routes.js +158 -0
- package/dist/api/trajectory-routes.js +300 -0
- package/dist/api/trigger-routes.js +246 -0
- package/dist/api/twitter-verify.js +134 -0
- package/dist/api/tx-service.js +108 -0
- package/dist/api/wallet-routes.js +266 -0
- package/dist/api/wallet.js +568 -0
- package/dist/api/whatsapp-routes.js +182 -0
- package/dist/api/zip-utils.js +109 -0
- package/dist/apps-hyperscape-routes.js +58 -0
- package/dist/apps-routes.js +114 -0
- package/dist/ascii.js +20 -0
- package/dist/auth/anthropic.js +44 -0
- package/dist/auth/apply-stealth.js +41 -0
- package/dist/auth/claude-code-stealth.js +78 -0
- package/dist/auth/credentials.js +156 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/openai-codex.js +66 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth-routes.js +56 -0
- package/dist/autonomy-routes.js +44 -0
- package/dist/bug-report-routes.js +111 -0
- package/dist/build-info.json +6 -0
- package/dist/character-routes.js +195 -0
- package/dist/cli/argv.js +63 -0
- package/dist/cli/banner.js +34 -0
- package/dist/cli/cli-name.js +21 -0
- package/dist/cli/cli-utils.js +16 -0
- package/dist/cli/git-commit.js +78 -0
- package/dist/cli/parse-duration.js +15 -0
- package/dist/cli/plugins-cli.js +590 -0
- package/dist/cli/profile-utils.js +9 -0
- package/dist/cli/profile.js +95 -0
- package/dist/cli/program/build-program.js +17 -0
- package/dist/cli/program/command-registry.js +23 -0
- package/dist/cli/program/help.js +47 -0
- package/dist/cli/program/preaction.js +33 -0
- package/dist/cli/program/register.config.js +106 -0
- package/dist/cli/program/register.configure.js +20 -0
- package/dist/cli/program/register.dashboard.js +124 -0
- package/dist/cli/program/register.models.js +23 -0
- package/dist/cli/program/register.setup.js +36 -0
- package/dist/cli/program/register.start.js +22 -0
- package/dist/cli/program/register.subclis.js +70 -0
- package/dist/cli/program/register.tui.js +163 -0
- package/dist/cli/program/register.update.js +154 -0
- package/dist/cli/program.js +3 -0
- package/dist/cli/run-main.js +37 -0
- package/dist/cli/version.js +7 -0
- package/dist/cloud/validate-url.js +93 -0
- package/dist/cloud-routes.js +330 -0
- package/dist/cloud-status-routes.js +155 -0
- package/dist/compat-utils.js +111 -0
- package/dist/config/config.js +69 -0
- package/dist/config/env-vars.js +19 -0
- package/dist/config/includes.js +121 -0
- package/dist/config/object-utils.js +7 -0
- package/dist/config/paths.js +38 -0
- package/dist/config/plugin-auto-enable.js +231 -0
- package/dist/config/schema.js +864 -0
- package/dist/config/telegram-custom-commands.js +76 -0
- package/dist/config/zod-schema.agent-runtime.js +519 -0
- package/dist/config/zod-schema.core.js +538 -0
- package/dist/config/zod-schema.hooks.js +103 -0
- package/dist/config/zod-schema.js +488 -0
- package/dist/config/zod-schema.providers-core.js +785 -0
- package/dist/config/zod-schema.session.js +73 -0
- package/dist/core-plugins.js +37 -0
- package/dist/custom-actions.js +250 -0
- package/dist/database.js +735 -0
- package/dist/diagnostics/integration-observability.js +57 -0
- package/dist/diagnostics-routes.js +205 -0
- package/dist/drop-service.js +134 -0
- package/dist/early-logs.js +24 -0
- package/dist/eliza.js +2061 -0
- package/dist/emotes/catalog.js +271 -0
- package/dist/entry.js +40 -0
- package/dist/hooks/discovery.js +167 -0
- package/dist/hooks/eligibility.js +64 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/loader.js +147 -0
- package/dist/hooks/registry.js +55 -0
- package/dist/http-helpers.js +131 -0
- package/dist/index.js +49 -0
- package/dist/knowledge-routes.js +534 -0
- package/dist/memory-bounds.js +71 -0
- package/dist/milady-plugin.js +90 -0
- package/dist/models-routes.js +28 -0
- package/dist/onboarding-names.js +78 -0
- package/dist/onboarding-presets.js +922 -0
- package/dist/package.json +1 -0
- package/dist/permissions-routes.js +109 -0
- package/dist/plugin-validation.js +107 -0
- package/dist/plugins/whatsapp/actions.js +91 -0
- package/dist/plugins/whatsapp/index.js +16 -0
- package/dist/plugins/whatsapp/service.js +270 -0
- package/dist/provider-switch-config.js +41 -0
- package/dist/providers/admin-trust.js +46 -0
- package/dist/providers/autonomous-state.js +101 -0
- package/dist/providers/session-bridge.js +86 -0
- package/dist/providers/session-utils.js +36 -0
- package/dist/providers/simple-mode.js +50 -0
- package/dist/providers/ui-catalog.js +15 -0
- package/dist/providers/workspace-provider.js +93 -0
- package/dist/providers/workspace.js +348 -0
- package/dist/registry-routes.js +86 -0
- package/dist/registry-service.js +164 -0
- package/dist/restart.js +40 -0
- package/dist/runtime/core-plugins.js +37 -0
- package/dist/runtime/custom-actions.js +250 -0
- package/dist/runtime/eliza.js +2061 -0
- package/dist/runtime/embedding-manager-support.js +185 -0
- package/dist/runtime/embedding-manager.js +193 -0
- package/dist/runtime/embedding-presets.js +54 -0
- package/dist/runtime/embedding-state.js +8 -0
- package/dist/runtime/milady-plugin.js +90 -0
- package/dist/runtime/onboarding-names.js +78 -0
- package/dist/runtime/restart.js +40 -0
- package/dist/runtime/version.js +7 -0
- package/dist/sandbox-routes.js +1112 -0
- package/dist/security/audit-log.js +149 -0
- package/dist/security/network-policy.js +70 -0
- package/dist/server.js +7949 -0
- package/dist/services/agent-export.js +559 -0
- package/dist/services/app-manager.js +389 -0
- package/dist/services/browser-capture.js +86 -0
- package/dist/services/fallback-training-service.js +128 -0
- package/dist/services/mcp-marketplace.js +134 -0
- package/dist/services/plugin-installer.js +396 -0
- package/dist/services/plugin-manager-types.js +15 -0
- package/dist/services/registry-client-app-meta.js +144 -0
- package/dist/services/registry-client-endpoints.js +166 -0
- package/dist/services/registry-client-local.js +271 -0
- package/dist/services/registry-client-network.js +93 -0
- package/dist/services/registry-client-queries.js +70 -0
- package/dist/services/registry-client.js +157 -0
- package/dist/services/sandbox-engine.js +511 -0
- package/dist/services/sandbox-manager.js +297 -0
- package/dist/services/self-updater.js +175 -0
- package/dist/services/skill-catalog-client.js +119 -0
- package/dist/services/skill-marketplace.js +521 -0
- package/dist/services/stream-manager.js +236 -0
- package/dist/services/update-checker.js +121 -0
- package/dist/services/update-notifier.js +29 -0
- package/dist/services/version-compat.js +78 -0
- package/dist/services/whatsapp-pairing.js +196 -0
- package/dist/shared/ui-catalog-prompt.js +728 -0
- package/dist/subscription-routes.js +172 -0
- package/dist/terminal/links.js +19 -0
- package/dist/terminal/palette.js +14 -0
- package/dist/terminal/theme.js +25 -0
- package/dist/terminal-run-limits.js +24 -0
- package/dist/training-routes.js +158 -0
- package/dist/trajectory-routes.js +300 -0
- package/dist/trigger-routes.js +246 -0
- package/dist/triggers/action.js +218 -0
- package/dist/triggers/runtime.js +281 -0
- package/dist/triggers/scheduling.js +295 -0
- package/dist/triggers/types.js +5 -0
- package/dist/tui/components/assistant-message.js +76 -0
- package/dist/tui/components/chat-editor.js +34 -0
- package/dist/tui/components/embeddings-overlay.js +46 -0
- package/dist/tui/components/footer.js +60 -0
- package/dist/tui/components/index.js +15 -0
- package/dist/tui/components/modal-frame.js +45 -0
- package/dist/tui/components/modal-style.js +15 -0
- package/dist/tui/components/model-selector.js +70 -0
- package/dist/tui/components/pinned-chat-layout.js +46 -0
- package/dist/tui/components/plugins-endpoints-tab.js +196 -0
- package/dist/tui/components/plugins-installed-tab-view.js +69 -0
- package/dist/tui/components/plugins-installed-tab.js +319 -0
- package/dist/tui/components/plugins-overlay-catalog.js +81 -0
- package/dist/tui/components/plugins-overlay-data-api.js +21 -0
- package/dist/tui/components/plugins-overlay-data-shared.js +20 -0
- package/dist/tui/components/plugins-overlay-data.js +323 -0
- package/dist/tui/components/plugins-overlay.js +117 -0
- package/dist/tui/components/plugins-store-tab.js +148 -0
- package/dist/tui/components/settings-overlay.js +61 -0
- package/dist/tui/components/status-bar.js +64 -0
- package/dist/tui/components/tool-execution.js +68 -0
- package/dist/tui/components/user-message.js +22 -0
- package/dist/tui/eliza-tui-bridge.js +606 -0
- package/dist/tui/index.js +370 -0
- package/dist/tui/modal-presets.js +33 -0
- package/dist/tui/model-spec.js +46 -0
- package/dist/tui/sse-parser.js +78 -0
- package/dist/tui/theme.js +110 -0
- package/dist/tui/titlebar-spinner.js +62 -0
- package/dist/tui/tui-app.js +311 -0
- package/dist/tui/ws-client.js +215 -0
- package/dist/twitter-verify.js +134 -0
- package/dist/tx-service.js +108 -0
- package/dist/utils/exec-safety.js +17 -0
- package/dist/utils/globals.js +20 -0
- package/dist/utils/milady-root.js +61 -0
- package/dist/utils/number-parsing.js +37 -0
- package/dist/version-resolver.js +37 -0
- package/dist/version.js +7 -0
- package/dist/wallet-routes.js +266 -0
- package/dist/wallet.js +568 -0
- package/dist/whatsapp-routes.js +182 -0
- package/dist/zip-utils.js +109 -0
- package/milady.mjs +14 -0
- package/package.json +111 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { getAutonomySvc } from "./autonomy-routes.js";
|
|
2
|
+
|
|
3
|
+
//#region src/api/agent-lifecycle-routes.ts
|
|
4
|
+
function detectModel(runtime) {
|
|
5
|
+
if (!runtime) return "unknown";
|
|
6
|
+
return runtime.plugins.find((plugin) => plugin.name.includes("anthropic") || plugin.name.includes("openai") || plugin.name.includes("groq"))?.name ?? "unknown";
|
|
7
|
+
}
|
|
8
|
+
async function handleAgentLifecycleRoutes(ctx) {
|
|
9
|
+
const { res, method, pathname, state, json } = ctx;
|
|
10
|
+
if (method === "POST" && pathname === "/api/agent/start") {
|
|
11
|
+
state.agentState = "running";
|
|
12
|
+
state.startedAt = Date.now();
|
|
13
|
+
state.model = detectModel(state.runtime);
|
|
14
|
+
const svc = getAutonomySvc(state.runtime);
|
|
15
|
+
if (svc) await svc.enableAutonomy();
|
|
16
|
+
json(res, {
|
|
17
|
+
ok: true,
|
|
18
|
+
status: {
|
|
19
|
+
state: state.agentState,
|
|
20
|
+
agentName: state.agentName,
|
|
21
|
+
model: state.model,
|
|
22
|
+
uptime: 0,
|
|
23
|
+
startedAt: state.startedAt
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (method === "POST" && pathname === "/api/agent/stop") {
|
|
29
|
+
const svc = getAutonomySvc(state.runtime);
|
|
30
|
+
if (svc) await svc.disableAutonomy();
|
|
31
|
+
state.agentState = "stopped";
|
|
32
|
+
state.startedAt = void 0;
|
|
33
|
+
state.model = void 0;
|
|
34
|
+
json(res, {
|
|
35
|
+
ok: true,
|
|
36
|
+
status: {
|
|
37
|
+
state: state.agentState,
|
|
38
|
+
agentName: state.agentName
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (method === "POST" && pathname === "/api/agent/pause") {
|
|
44
|
+
const svc = getAutonomySvc(state.runtime);
|
|
45
|
+
if (svc) await svc.disableAutonomy();
|
|
46
|
+
state.agentState = "paused";
|
|
47
|
+
json(res, {
|
|
48
|
+
ok: true,
|
|
49
|
+
status: {
|
|
50
|
+
state: state.agentState,
|
|
51
|
+
agentName: state.agentName,
|
|
52
|
+
model: state.model,
|
|
53
|
+
uptime: state.startedAt ? Date.now() - state.startedAt : void 0,
|
|
54
|
+
startedAt: state.startedAt
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (method === "POST" && pathname === "/api/agent/resume") {
|
|
60
|
+
const svc = getAutonomySvc(state.runtime);
|
|
61
|
+
if (svc) await svc.enableAutonomy();
|
|
62
|
+
state.agentState = "running";
|
|
63
|
+
json(res, {
|
|
64
|
+
ok: true,
|
|
65
|
+
status: {
|
|
66
|
+
state: state.agentState,
|
|
67
|
+
agentName: state.agentName,
|
|
68
|
+
model: state.model,
|
|
69
|
+
uptime: state.startedAt ? Date.now() - state.startedAt : void 0,
|
|
70
|
+
startedAt: state.startedAt
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { handleAgentLifecycleRoutes };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { AgentExportError, estimateExportSize, exportAgent, importAgent } from "../services/agent-export.js";
|
|
2
|
+
import { readRequestBodyBuffer } from "./http-helpers.js";
|
|
3
|
+
|
|
4
|
+
//#region src/api/agent-transfer-routes.ts
|
|
5
|
+
const MAX_IMPORT_BYTES = 512 * 1048576;
|
|
6
|
+
const AGENT_TRANSFER_MIN_PASSWORD_LENGTH = 4;
|
|
7
|
+
const AGENT_TRANSFER_MAX_PASSWORD_LENGTH = 1024;
|
|
8
|
+
function readRawBody(req, maxBytes) {
|
|
9
|
+
return readRequestBodyBuffer(req, { maxBytes }).then((body) => {
|
|
10
|
+
if (body === null) throw new Error(`Request body exceeds maximum size (${maxBytes} bytes)`);
|
|
11
|
+
return body;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async function handleAgentTransferRoutes(ctx) {
|
|
15
|
+
const { req, res, method, pathname, state, readJsonBody, json, error } = ctx;
|
|
16
|
+
if (method === "POST" && pathname === "/api/agent/export") {
|
|
17
|
+
if (!state.runtime) {
|
|
18
|
+
error(res, "Agent is not running — start it before exporting.", 503);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
const body = await readJsonBody(req, res);
|
|
22
|
+
if (!body) return true;
|
|
23
|
+
if (!body.password || typeof body.password !== "string") {
|
|
24
|
+
error(res, `A password of at least ${AGENT_TRANSFER_MIN_PASSWORD_LENGTH} characters is required.`, 400);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (body.password.length < AGENT_TRANSFER_MIN_PASSWORD_LENGTH) {
|
|
28
|
+
error(res, `A password of at least ${AGENT_TRANSFER_MIN_PASSWORD_LENGTH} characters is required.`, 400);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const fileBuffer = await exportAgent(state.runtime, body.password, { includeLogs: body.includeLogs === true });
|
|
33
|
+
const filename = `${(state.runtime.character.name ?? "agent").replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase()}-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.eliza-agent`;
|
|
34
|
+
res.statusCode = 200;
|
|
35
|
+
res.setHeader("Content-Type", "application/octet-stream");
|
|
36
|
+
res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
|
|
37
|
+
res.setHeader("Content-Length", fileBuffer.length);
|
|
38
|
+
res.end(fileBuffer);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
if (err instanceof AgentExportError) error(res, message, 400);
|
|
42
|
+
else error(res, `Export failed: ${message}`, 500);
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (method === "GET" && pathname === "/api/agent/export/estimate") {
|
|
47
|
+
if (!state.runtime) {
|
|
48
|
+
error(res, "Agent is not running.", 503);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
json(res, await estimateExportSize(state.runtime));
|
|
53
|
+
} catch (err) {
|
|
54
|
+
error(res, `Estimate failed: ${err instanceof Error ? err.message : String(err)}`, 500);
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (method === "POST" && pathname === "/api/agent/import") {
|
|
59
|
+
if (!state.runtime) {
|
|
60
|
+
error(res, "Agent is not running — start it before importing.", 503);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
let rawBody;
|
|
64
|
+
try {
|
|
65
|
+
rawBody = await readRawBody(req, MAX_IMPORT_BYTES);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
error(res, err instanceof Error ? err.message : String(err), 413);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
if (rawBody.length < 5) {
|
|
71
|
+
error(res, "Request body is too small — expected password + file data.", 400);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const passwordLength = rawBody.readUInt32BE(0);
|
|
75
|
+
if (passwordLength < AGENT_TRANSFER_MIN_PASSWORD_LENGTH) {
|
|
76
|
+
error(res, `Password must be at least ${AGENT_TRANSFER_MIN_PASSWORD_LENGTH} characters.`, 400);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (passwordLength > AGENT_TRANSFER_MAX_PASSWORD_LENGTH) {
|
|
80
|
+
error(res, `Password is too long (max ${AGENT_TRANSFER_MAX_PASSWORD_LENGTH} bytes).`, 400);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (rawBody.length < 4 + passwordLength + 1) {
|
|
84
|
+
error(res, "Request body is incomplete — missing file data after password.", 400);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
const password = rawBody.subarray(4, 4 + passwordLength).toString("utf-8");
|
|
88
|
+
const fileBuffer = rawBody.subarray(4 + passwordLength);
|
|
89
|
+
try {
|
|
90
|
+
json(res, await importAgent(state.runtime, fileBuffer, password));
|
|
91
|
+
} catch (err) {
|
|
92
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
93
|
+
if (err instanceof AgentExportError) error(res, message, 400);
|
|
94
|
+
else error(res, `Import failed: ${message}`, 500);
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
export { handleAgentTransferRoutes };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/api/apps-hyperscape-routes.ts
|
|
2
|
+
async function handleAppsHyperscapeRoutes(ctx) {
|
|
3
|
+
const { req, res, method, pathname, relayHyperscapeApi, readJsonBody, error } = ctx;
|
|
4
|
+
if (method === "GET" && pathname === "/api/apps/hyperscape/embedded-agents") {
|
|
5
|
+
await relayHyperscapeApi("GET", "/api/embedded-agents");
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
if (method === "POST" && pathname === "/api/apps/hyperscape/embedded-agents") {
|
|
9
|
+
await relayHyperscapeApi("POST", "/api/embedded-agents");
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (method === "POST") {
|
|
13
|
+
const embeddedActionMatch = pathname.match(/^\/api\/apps\/hyperscape\/embedded-agents\/([^/]+)\/(start|stop|pause|resume|command)$/);
|
|
14
|
+
if (embeddedActionMatch) {
|
|
15
|
+
const characterId = decodeURIComponent(embeddedActionMatch[1]);
|
|
16
|
+
const action = embeddedActionMatch[2];
|
|
17
|
+
await relayHyperscapeApi("POST", `/api/embedded-agents/${encodeURIComponent(characterId)}/${action}`);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
const messageMatch = pathname.match(/^\/api\/apps\/hyperscape\/agents\/([^/]+)\/message$/);
|
|
21
|
+
if (messageMatch) {
|
|
22
|
+
const agentId = decodeURIComponent(messageMatch[1]);
|
|
23
|
+
const body = await readJsonBody(req, res);
|
|
24
|
+
if (!body) return true;
|
|
25
|
+
const content = body.content?.trim();
|
|
26
|
+
if (!content) {
|
|
27
|
+
error(res, "content is required");
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
await relayHyperscapeApi("POST", `/api/embedded-agents/${encodeURIComponent(agentId)}/command`, {
|
|
31
|
+
rawBodyOverride: JSON.stringify({
|
|
32
|
+
command: "chat",
|
|
33
|
+
data: { message: content }
|
|
34
|
+
}),
|
|
35
|
+
contentTypeOverride: "application/json"
|
|
36
|
+
});
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (method === "GET") {
|
|
41
|
+
const goalMatch = pathname.match(/^\/api\/apps\/hyperscape\/agents\/([^/]+)\/goal$/);
|
|
42
|
+
if (goalMatch) {
|
|
43
|
+
const agentId = decodeURIComponent(goalMatch[1]);
|
|
44
|
+
await relayHyperscapeApi("GET", `/api/agents/${encodeURIComponent(agentId)}/goal`);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
const quickActionsMatch = pathname.match(/^\/api\/apps\/hyperscape\/agents\/([^/]+)\/quick-actions$/);
|
|
48
|
+
if (quickActionsMatch) {
|
|
49
|
+
const agentId = decodeURIComponent(quickActionsMatch[1]);
|
|
50
|
+
await relayHyperscapeApi("GET", `/api/agents/${encodeURIComponent(agentId)}/quick-actions`);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { handleAppsHyperscapeRoutes };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
//#region src/api/apps-routes.ts
|
|
2
|
+
function isNonAppRegistryPlugin(plugin) {
|
|
3
|
+
if (plugin.kind === "app") return false;
|
|
4
|
+
const name = plugin.name.toLowerCase();
|
|
5
|
+
const npmPackage = plugin.npm.package.toLowerCase();
|
|
6
|
+
return !name.includes("/app-") && !npmPackage.includes("/app-");
|
|
7
|
+
}
|
|
8
|
+
function isNonAppSearchResult(plugin) {
|
|
9
|
+
const name = plugin.name.toLowerCase();
|
|
10
|
+
const npmPackage = plugin.npmPackage.toLowerCase();
|
|
11
|
+
return !name.includes("/app-") && !npmPackage.includes("/app-");
|
|
12
|
+
}
|
|
13
|
+
async function handleAppsRoutes(ctx) {
|
|
14
|
+
const { req, res, method, pathname, url, appManager, getPluginManager, parseBoundedLimit, readJsonBody, json, error, runtime } = ctx;
|
|
15
|
+
if (method === "GET" && pathname === "/api/apps") {
|
|
16
|
+
const pluginManager = getPluginManager();
|
|
17
|
+
json(res, await appManager.listAvailable(pluginManager));
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (method === "GET" && pathname === "/api/apps/search") {
|
|
21
|
+
const query = url.searchParams.get("q") ?? "";
|
|
22
|
+
if (!query.trim()) {
|
|
23
|
+
json(res, []);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
const limit = parseBoundedLimit(url.searchParams.get("limit"));
|
|
27
|
+
const pluginManager = getPluginManager();
|
|
28
|
+
json(res, await appManager.search(pluginManager, query, limit));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (method === "GET" && pathname === "/api/apps/installed") {
|
|
32
|
+
const pluginManager = getPluginManager();
|
|
33
|
+
json(res, await appManager.listInstalled(pluginManager));
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
if (method === "POST" && pathname === "/api/apps/launch") {
|
|
37
|
+
const body = await readJsonBody(req, res);
|
|
38
|
+
if (!body) return true;
|
|
39
|
+
if (!body.name?.trim()) {
|
|
40
|
+
error(res, "name is required");
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
const pluginManager = getPluginManager();
|
|
44
|
+
json(res, await appManager.launch(pluginManager, body.name.trim(), (_progress) => {}, runtime));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (method === "POST" && pathname === "/api/apps/stop") {
|
|
48
|
+
const body = await readJsonBody(req, res);
|
|
49
|
+
if (!body) return true;
|
|
50
|
+
if (!body.name?.trim()) {
|
|
51
|
+
error(res, "name is required");
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
const appName = body.name.trim();
|
|
55
|
+
const pluginManager = getPluginManager();
|
|
56
|
+
json(res, await appManager.stop(pluginManager, appName));
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (method === "GET" && pathname.startsWith("/api/apps/info/")) {
|
|
60
|
+
const appName = decodeURIComponent(pathname.slice(15));
|
|
61
|
+
if (!appName) {
|
|
62
|
+
error(res, "app name is required");
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
const pluginManager = getPluginManager();
|
|
66
|
+
const info = await appManager.getInfo(pluginManager, appName);
|
|
67
|
+
if (!info) {
|
|
68
|
+
error(res, `App "${appName}" not found in registry`, 404);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
json(res, info);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
if (method === "GET" && pathname === "/api/apps/plugins") {
|
|
75
|
+
try {
|
|
76
|
+
const registry = await getPluginManager().refreshRegistry();
|
|
77
|
+
json(res, Array.from(registry.values()).filter(isNonAppRegistryPlugin));
|
|
78
|
+
} catch (err) {
|
|
79
|
+
error(res, `Failed to list plugins: ${err instanceof Error ? err.message : String(err)}`, 502);
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (method === "GET" && pathname === "/api/apps/plugins/search") {
|
|
84
|
+
const query = url.searchParams.get("q") ?? "";
|
|
85
|
+
if (!query.trim()) {
|
|
86
|
+
json(res, []);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const limit = parseBoundedLimit(url.searchParams.get("limit"));
|
|
91
|
+
json(res, (await getPluginManager().searchRegistry(query, limit)).filter(isNonAppSearchResult));
|
|
92
|
+
} catch (err) {
|
|
93
|
+
error(res, `Plugin search failed: ${err instanceof Error ? err.message : String(err)}`, 502);
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
if (method === "POST" && pathname === "/api/apps/refresh") {
|
|
98
|
+
try {
|
|
99
|
+
const registry = await getPluginManager().refreshRegistry();
|
|
100
|
+
const count = Array.from(registry.values()).filter(isNonAppRegistryPlugin).length;
|
|
101
|
+
json(res, {
|
|
102
|
+
ok: true,
|
|
103
|
+
count
|
|
104
|
+
});
|
|
105
|
+
} catch (err) {
|
|
106
|
+
error(res, `Refresh failed: ${err instanceof Error ? err.message : String(err)}`, 502);
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
export { handleAppsRoutes };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
|
|
3
|
+
//#region src/api/auth-routes.ts
|
|
4
|
+
async function handleAuthRoutes(ctx) {
|
|
5
|
+
const { req, res, method, pathname, readJsonBody, json, error, pairingEnabled, ensurePairingCode, normalizePairingCode, rateLimitPairing, getPairingExpiresAt, clearPairing } = ctx;
|
|
6
|
+
if (!pathname.startsWith("/api/auth/")) return false;
|
|
7
|
+
if (method === "GET" && pathname === "/api/auth/status") {
|
|
8
|
+
const required = Boolean(process.env.MILADY_API_TOKEN?.trim());
|
|
9
|
+
const enabled = pairingEnabled();
|
|
10
|
+
if (enabled) ensurePairingCode();
|
|
11
|
+
json(res, {
|
|
12
|
+
required,
|
|
13
|
+
pairingEnabled: enabled,
|
|
14
|
+
expiresAt: enabled ? getPairingExpiresAt() : null
|
|
15
|
+
});
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (method === "POST" && pathname === "/api/auth/pair") {
|
|
19
|
+
const body = await readJsonBody(req, res);
|
|
20
|
+
if (!body) return true;
|
|
21
|
+
const token = process.env.MILADY_API_TOKEN?.trim();
|
|
22
|
+
if (!token) {
|
|
23
|
+
error(res, "Pairing not enabled", 400);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (!pairingEnabled()) {
|
|
27
|
+
error(res, "Pairing disabled", 403);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (!rateLimitPairing(req.socket.remoteAddress ?? null)) {
|
|
31
|
+
error(res, "Too many attempts. Try again later.", 429);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
const provided = normalizePairingCode(body.code ?? "");
|
|
35
|
+
const current = ensurePairingCode();
|
|
36
|
+
if (!current || Date.now() > getPairingExpiresAt()) {
|
|
37
|
+
ensurePairingCode();
|
|
38
|
+
error(res, "Pairing code expired. Check server logs for a new code.", 410);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const expected = normalizePairingCode(current);
|
|
42
|
+
const a = Buffer.from(expected, "utf8");
|
|
43
|
+
const b = Buffer.from(provided, "utf8");
|
|
44
|
+
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
|
|
45
|
+
error(res, "Invalid pairing code", 403);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
clearPairing();
|
|
49
|
+
json(res, { token });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { handleAuthRoutes };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/api/autonomy-routes.ts
|
|
2
|
+
/** Helper to retrieve the AutonomyService from a runtime (may be null). */
|
|
3
|
+
function getAutonomySvc(runtime) {
|
|
4
|
+
if (!runtime) return null;
|
|
5
|
+
return runtime.getService("AUTONOMY");
|
|
6
|
+
}
|
|
7
|
+
function getAutonomyState(runtime) {
|
|
8
|
+
const svc = getAutonomySvc(runtime);
|
|
9
|
+
const statusEnabled = svc?.getStatus?.().enabled;
|
|
10
|
+
const runtimeEnabled = runtime?.enableAutonomy === true;
|
|
11
|
+
return {
|
|
12
|
+
enabled: typeof statusEnabled === "boolean" ? statusEnabled : runtimeEnabled || Boolean(svc),
|
|
13
|
+
thinking: svc?.isLoopRunning() ?? false
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function handleAutonomyRoutes(ctx) {
|
|
17
|
+
const { req, res, method, pathname, runtime, readJsonBody, json } = ctx;
|
|
18
|
+
if (method === "POST" && pathname === "/api/agent/autonomy") {
|
|
19
|
+
const body = await readJsonBody(req, res);
|
|
20
|
+
if (!body) return true;
|
|
21
|
+
const svc = getAutonomySvc(runtime);
|
|
22
|
+
if (typeof body.enabled === "boolean" && svc) if (body.enabled) await svc.enableAutonomy();
|
|
23
|
+
else await svc.disableAutonomy();
|
|
24
|
+
const autonomy = getAutonomyState(runtime);
|
|
25
|
+
json(res, {
|
|
26
|
+
ok: true,
|
|
27
|
+
autonomy: autonomy.enabled,
|
|
28
|
+
thinking: autonomy.thinking
|
|
29
|
+
});
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
if (method === "GET" && pathname === "/api/agent/autonomy") {
|
|
33
|
+
const autonomy = getAutonomyState(runtime);
|
|
34
|
+
json(res, {
|
|
35
|
+
enabled: autonomy.enabled,
|
|
36
|
+
thinking: autonomy.thinking
|
|
37
|
+
});
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { getAutonomyState, getAutonomySvc, handleAutonomyRoutes };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { sweepExpiredEntries } from "./memory-bounds.js";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
|
|
4
|
+
//#region src/api/bug-report-routes.ts
|
|
5
|
+
const BUG_REPORT_REPO = "milady-ai/milady";
|
|
6
|
+
const GITHUB_ISSUES_URL = `https://api.github.com/repos/${BUG_REPORT_REPO}/issues`;
|
|
7
|
+
const GITHUB_NEW_ISSUE_URL = `https://github.com/${BUG_REPORT_REPO}/issues/new?template=bug_report.yml`;
|
|
8
|
+
const BUG_REPORT_WINDOW_MS = 600 * 1e3;
|
|
9
|
+
const BUG_REPORT_MAX_SUBMISSIONS = 5;
|
|
10
|
+
const bugReportAttempts = /* @__PURE__ */ new Map();
|
|
11
|
+
function rateLimitBugReport(ip) {
|
|
12
|
+
const key = ip ?? "unknown";
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
sweepExpiredEntries(bugReportAttempts, now, 100);
|
|
15
|
+
const current = bugReportAttempts.get(key);
|
|
16
|
+
if (!current || now > current.resetAt) {
|
|
17
|
+
bugReportAttempts.set(key, {
|
|
18
|
+
count: 1,
|
|
19
|
+
resetAt: now + BUG_REPORT_WINDOW_MS
|
|
20
|
+
});
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (current.count >= BUG_REPORT_MAX_SUBMISSIONS) return false;
|
|
24
|
+
current.count += 1;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Strip HTML tags and limit length to prevent markdown injection.
|
|
29
|
+
* GitHub's renderer already sanitizes HTML, but we defensively strip
|
|
30
|
+
* tags and cap field length to reduce abuse surface.
|
|
31
|
+
*/
|
|
32
|
+
function sanitize(input, maxLen = 1e4) {
|
|
33
|
+
return input.replace(/<[^>]*>/g, "").slice(0, maxLen);
|
|
34
|
+
}
|
|
35
|
+
function formatIssueBody(body) {
|
|
36
|
+
const sections = [];
|
|
37
|
+
sections.push(`### Description\n\n${sanitize(body.description)}`);
|
|
38
|
+
sections.push(`### Steps to Reproduce\n\n${sanitize(body.stepsToReproduce)}`);
|
|
39
|
+
if (body.expectedBehavior) sections.push(`### Expected Behavior\n\n${sanitize(body.expectedBehavior)}`);
|
|
40
|
+
if (body.actualBehavior) sections.push(`### Actual Behavior\n\n${sanitize(body.actualBehavior)}`);
|
|
41
|
+
if (body.environment) sections.push(`### Environment\n\n${sanitize(body.environment, 200)}`);
|
|
42
|
+
if (body.nodeVersion) sections.push(`### Node Version\n\n${sanitize(body.nodeVersion, 200)}`);
|
|
43
|
+
if (body.modelProvider) sections.push(`### Model Provider\n\n${sanitize(body.modelProvider, 200)}`);
|
|
44
|
+
if (body.logs) sections.push(`### Logs\n\n\`\`\`\n${sanitize(body.logs, 5e4)}\n\`\`\``);
|
|
45
|
+
return sections.join("\n\n");
|
|
46
|
+
}
|
|
47
|
+
async function handleBugReportRoutes(ctx) {
|
|
48
|
+
const { req, res, method, pathname, json, error, readJsonBody } = ctx;
|
|
49
|
+
if (method === "GET" && pathname === "/api/bug-report/info") {
|
|
50
|
+
json(res, {
|
|
51
|
+
nodeVersion: process.version,
|
|
52
|
+
platform: os.platform()
|
|
53
|
+
});
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (method === "POST" && pathname === "/api/bug-report") {
|
|
57
|
+
if (!rateLimitBugReport(req.socket.remoteAddress ?? null)) {
|
|
58
|
+
error(res, "Too many bug reports. Try again later.", 429);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
const body = await readJsonBody(req, res);
|
|
62
|
+
if (!body) return true;
|
|
63
|
+
if (!body.description?.trim() || !body.stepsToReproduce?.trim()) {
|
|
64
|
+
error(res, "description and stepsToReproduce are required", 400);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
const githubToken = process.env.GITHUB_TOKEN;
|
|
68
|
+
if (!githubToken) {
|
|
69
|
+
json(res, { fallback: GITHUB_NEW_ISSUE_URL });
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const sanitizedTitle = sanitize(body.description, 80).replace(/[\r\n]+/g, " ");
|
|
74
|
+
const issueBody = formatIssueBody(body);
|
|
75
|
+
const issueRes = await fetch(GITHUB_ISSUES_URL, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${githubToken}`,
|
|
79
|
+
Accept: "application/vnd.github.v3+json",
|
|
80
|
+
"Content-Type": "application/json"
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify({
|
|
83
|
+
title: `[Bug] ${sanitizedTitle}`,
|
|
84
|
+
body: issueBody,
|
|
85
|
+
labels: [
|
|
86
|
+
"bug",
|
|
87
|
+
"triage",
|
|
88
|
+
"user-reported"
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
if (!issueRes.ok) {
|
|
93
|
+
error(res, `GitHub API error (${issueRes.status})`, 502);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
const url = (await issueRes.json()).html_url;
|
|
97
|
+
if (typeof url !== "string" || !url.startsWith(`https://github.com/${BUG_REPORT_REPO}/issues/`)) {
|
|
98
|
+
error(res, "Unexpected response from GitHub API", 502);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
json(res, { url });
|
|
102
|
+
} catch (_err) {
|
|
103
|
+
error(res, "Failed to create GitHub issue", 500);
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
export { handleBugReportRoutes };
|