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.
Files changed (241) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +7 -0
  2. package/dist/actions/emote.js +64 -0
  3. package/dist/actions/restart.js +81 -0
  4. package/dist/actions/send-message.js +152 -0
  5. package/dist/agent-admin-routes.js +82 -0
  6. package/dist/agent-lifecycle-routes.js +79 -0
  7. package/dist/agent-transfer-routes.js +102 -0
  8. package/dist/api/agent-admin-routes.js +82 -0
  9. package/dist/api/agent-lifecycle-routes.js +79 -0
  10. package/dist/api/agent-transfer-routes.js +102 -0
  11. package/dist/api/apps-hyperscape-routes.js +58 -0
  12. package/dist/api/apps-routes.js +114 -0
  13. package/dist/api/auth-routes.js +56 -0
  14. package/dist/api/autonomy-routes.js +44 -0
  15. package/dist/api/bug-report-routes.js +111 -0
  16. package/dist/api/character-routes.js +195 -0
  17. package/dist/api/cloud-routes.js +330 -0
  18. package/dist/api/cloud-status-routes.js +155 -0
  19. package/dist/api/compat-utils.js +111 -0
  20. package/dist/api/database.js +735 -0
  21. package/dist/api/diagnostics-routes.js +205 -0
  22. package/dist/api/drop-service.js +134 -0
  23. package/dist/api/early-logs.js +86 -0
  24. package/dist/api/http-helpers.js +131 -0
  25. package/dist/api/knowledge-routes.js +534 -0
  26. package/dist/api/memory-bounds.js +71 -0
  27. package/dist/api/models-routes.js +28 -0
  28. package/dist/api/og-tracker.js +36 -0
  29. package/dist/api/permissions-routes.js +109 -0
  30. package/dist/api/plugin-validation.js +198 -0
  31. package/dist/api/provider-switch-config.js +41 -0
  32. package/dist/api/registry-routes.js +86 -0
  33. package/dist/api/registry-service.js +164 -0
  34. package/dist/api/sandbox-routes.js +1112 -0
  35. package/dist/api/server.js +7949 -0
  36. package/dist/api/subscription-routes.js +172 -0
  37. package/dist/api/terminal-run-limits.js +24 -0
  38. package/dist/api/training-routes.js +158 -0
  39. package/dist/api/trajectory-routes.js +300 -0
  40. package/dist/api/trigger-routes.js +246 -0
  41. package/dist/api/twitter-verify.js +134 -0
  42. package/dist/api/tx-service.js +108 -0
  43. package/dist/api/wallet-routes.js +266 -0
  44. package/dist/api/wallet.js +568 -0
  45. package/dist/api/whatsapp-routes.js +182 -0
  46. package/dist/api/zip-utils.js +109 -0
  47. package/dist/apps-hyperscape-routes.js +58 -0
  48. package/dist/apps-routes.js +114 -0
  49. package/dist/ascii.js +20 -0
  50. package/dist/auth/anthropic.js +44 -0
  51. package/dist/auth/apply-stealth.js +41 -0
  52. package/dist/auth/claude-code-stealth.js +78 -0
  53. package/dist/auth/credentials.js +156 -0
  54. package/dist/auth/index.js +5 -0
  55. package/dist/auth/openai-codex.js +66 -0
  56. package/dist/auth/types.js +9 -0
  57. package/dist/auth-routes.js +56 -0
  58. package/dist/autonomy-routes.js +44 -0
  59. package/dist/bug-report-routes.js +111 -0
  60. package/dist/build-info.json +6 -0
  61. package/dist/character-routes.js +195 -0
  62. package/dist/cli/argv.js +63 -0
  63. package/dist/cli/banner.js +34 -0
  64. package/dist/cli/cli-name.js +21 -0
  65. package/dist/cli/cli-utils.js +16 -0
  66. package/dist/cli/git-commit.js +78 -0
  67. package/dist/cli/parse-duration.js +15 -0
  68. package/dist/cli/plugins-cli.js +590 -0
  69. package/dist/cli/profile-utils.js +9 -0
  70. package/dist/cli/profile.js +95 -0
  71. package/dist/cli/program/build-program.js +17 -0
  72. package/dist/cli/program/command-registry.js +23 -0
  73. package/dist/cli/program/help.js +47 -0
  74. package/dist/cli/program/preaction.js +33 -0
  75. package/dist/cli/program/register.config.js +106 -0
  76. package/dist/cli/program/register.configure.js +20 -0
  77. package/dist/cli/program/register.dashboard.js +124 -0
  78. package/dist/cli/program/register.models.js +23 -0
  79. package/dist/cli/program/register.setup.js +36 -0
  80. package/dist/cli/program/register.start.js +22 -0
  81. package/dist/cli/program/register.subclis.js +70 -0
  82. package/dist/cli/program/register.tui.js +163 -0
  83. package/dist/cli/program/register.update.js +154 -0
  84. package/dist/cli/program.js +3 -0
  85. package/dist/cli/run-main.js +37 -0
  86. package/dist/cli/version.js +7 -0
  87. package/dist/cloud/validate-url.js +93 -0
  88. package/dist/cloud-routes.js +330 -0
  89. package/dist/cloud-status-routes.js +155 -0
  90. package/dist/compat-utils.js +111 -0
  91. package/dist/config/config.js +69 -0
  92. package/dist/config/env-vars.js +19 -0
  93. package/dist/config/includes.js +121 -0
  94. package/dist/config/object-utils.js +7 -0
  95. package/dist/config/paths.js +38 -0
  96. package/dist/config/plugin-auto-enable.js +231 -0
  97. package/dist/config/schema.js +864 -0
  98. package/dist/config/telegram-custom-commands.js +76 -0
  99. package/dist/config/zod-schema.agent-runtime.js +519 -0
  100. package/dist/config/zod-schema.core.js +538 -0
  101. package/dist/config/zod-schema.hooks.js +103 -0
  102. package/dist/config/zod-schema.js +488 -0
  103. package/dist/config/zod-schema.providers-core.js +785 -0
  104. package/dist/config/zod-schema.session.js +73 -0
  105. package/dist/core-plugins.js +37 -0
  106. package/dist/custom-actions.js +250 -0
  107. package/dist/database.js +735 -0
  108. package/dist/diagnostics/integration-observability.js +57 -0
  109. package/dist/diagnostics-routes.js +205 -0
  110. package/dist/drop-service.js +134 -0
  111. package/dist/early-logs.js +24 -0
  112. package/dist/eliza.js +2061 -0
  113. package/dist/emotes/catalog.js +271 -0
  114. package/dist/entry.js +40 -0
  115. package/dist/hooks/discovery.js +167 -0
  116. package/dist/hooks/eligibility.js +64 -0
  117. package/dist/hooks/index.js +4 -0
  118. package/dist/hooks/loader.js +147 -0
  119. package/dist/hooks/registry.js +55 -0
  120. package/dist/http-helpers.js +131 -0
  121. package/dist/index.js +49 -0
  122. package/dist/knowledge-routes.js +534 -0
  123. package/dist/memory-bounds.js +71 -0
  124. package/dist/milady-plugin.js +90 -0
  125. package/dist/models-routes.js +28 -0
  126. package/dist/onboarding-names.js +78 -0
  127. package/dist/onboarding-presets.js +922 -0
  128. package/dist/package.json +1 -0
  129. package/dist/permissions-routes.js +109 -0
  130. package/dist/plugin-validation.js +107 -0
  131. package/dist/plugins/whatsapp/actions.js +91 -0
  132. package/dist/plugins/whatsapp/index.js +16 -0
  133. package/dist/plugins/whatsapp/service.js +270 -0
  134. package/dist/provider-switch-config.js +41 -0
  135. package/dist/providers/admin-trust.js +46 -0
  136. package/dist/providers/autonomous-state.js +101 -0
  137. package/dist/providers/session-bridge.js +86 -0
  138. package/dist/providers/session-utils.js +36 -0
  139. package/dist/providers/simple-mode.js +50 -0
  140. package/dist/providers/ui-catalog.js +15 -0
  141. package/dist/providers/workspace-provider.js +93 -0
  142. package/dist/providers/workspace.js +348 -0
  143. package/dist/registry-routes.js +86 -0
  144. package/dist/registry-service.js +164 -0
  145. package/dist/restart.js +40 -0
  146. package/dist/runtime/core-plugins.js +37 -0
  147. package/dist/runtime/custom-actions.js +250 -0
  148. package/dist/runtime/eliza.js +2061 -0
  149. package/dist/runtime/embedding-manager-support.js +185 -0
  150. package/dist/runtime/embedding-manager.js +193 -0
  151. package/dist/runtime/embedding-presets.js +54 -0
  152. package/dist/runtime/embedding-state.js +8 -0
  153. package/dist/runtime/milady-plugin.js +90 -0
  154. package/dist/runtime/onboarding-names.js +78 -0
  155. package/dist/runtime/restart.js +40 -0
  156. package/dist/runtime/version.js +7 -0
  157. package/dist/sandbox-routes.js +1112 -0
  158. package/dist/security/audit-log.js +149 -0
  159. package/dist/security/network-policy.js +70 -0
  160. package/dist/server.js +7949 -0
  161. package/dist/services/agent-export.js +559 -0
  162. package/dist/services/app-manager.js +389 -0
  163. package/dist/services/browser-capture.js +86 -0
  164. package/dist/services/fallback-training-service.js +128 -0
  165. package/dist/services/mcp-marketplace.js +134 -0
  166. package/dist/services/plugin-installer.js +396 -0
  167. package/dist/services/plugin-manager-types.js +15 -0
  168. package/dist/services/registry-client-app-meta.js +144 -0
  169. package/dist/services/registry-client-endpoints.js +166 -0
  170. package/dist/services/registry-client-local.js +271 -0
  171. package/dist/services/registry-client-network.js +93 -0
  172. package/dist/services/registry-client-queries.js +70 -0
  173. package/dist/services/registry-client.js +157 -0
  174. package/dist/services/sandbox-engine.js +511 -0
  175. package/dist/services/sandbox-manager.js +297 -0
  176. package/dist/services/self-updater.js +175 -0
  177. package/dist/services/skill-catalog-client.js +119 -0
  178. package/dist/services/skill-marketplace.js +521 -0
  179. package/dist/services/stream-manager.js +236 -0
  180. package/dist/services/update-checker.js +121 -0
  181. package/dist/services/update-notifier.js +29 -0
  182. package/dist/services/version-compat.js +78 -0
  183. package/dist/services/whatsapp-pairing.js +196 -0
  184. package/dist/shared/ui-catalog-prompt.js +728 -0
  185. package/dist/subscription-routes.js +172 -0
  186. package/dist/terminal/links.js +19 -0
  187. package/dist/terminal/palette.js +14 -0
  188. package/dist/terminal/theme.js +25 -0
  189. package/dist/terminal-run-limits.js +24 -0
  190. package/dist/training-routes.js +158 -0
  191. package/dist/trajectory-routes.js +300 -0
  192. package/dist/trigger-routes.js +246 -0
  193. package/dist/triggers/action.js +218 -0
  194. package/dist/triggers/runtime.js +281 -0
  195. package/dist/triggers/scheduling.js +295 -0
  196. package/dist/triggers/types.js +5 -0
  197. package/dist/tui/components/assistant-message.js +76 -0
  198. package/dist/tui/components/chat-editor.js +34 -0
  199. package/dist/tui/components/embeddings-overlay.js +46 -0
  200. package/dist/tui/components/footer.js +60 -0
  201. package/dist/tui/components/index.js +15 -0
  202. package/dist/tui/components/modal-frame.js +45 -0
  203. package/dist/tui/components/modal-style.js +15 -0
  204. package/dist/tui/components/model-selector.js +70 -0
  205. package/dist/tui/components/pinned-chat-layout.js +46 -0
  206. package/dist/tui/components/plugins-endpoints-tab.js +196 -0
  207. package/dist/tui/components/plugins-installed-tab-view.js +69 -0
  208. package/dist/tui/components/plugins-installed-tab.js +319 -0
  209. package/dist/tui/components/plugins-overlay-catalog.js +81 -0
  210. package/dist/tui/components/plugins-overlay-data-api.js +21 -0
  211. package/dist/tui/components/plugins-overlay-data-shared.js +20 -0
  212. package/dist/tui/components/plugins-overlay-data.js +323 -0
  213. package/dist/tui/components/plugins-overlay.js +117 -0
  214. package/dist/tui/components/plugins-store-tab.js +148 -0
  215. package/dist/tui/components/settings-overlay.js +61 -0
  216. package/dist/tui/components/status-bar.js +64 -0
  217. package/dist/tui/components/tool-execution.js +68 -0
  218. package/dist/tui/components/user-message.js +22 -0
  219. package/dist/tui/eliza-tui-bridge.js +606 -0
  220. package/dist/tui/index.js +370 -0
  221. package/dist/tui/modal-presets.js +33 -0
  222. package/dist/tui/model-spec.js +46 -0
  223. package/dist/tui/sse-parser.js +78 -0
  224. package/dist/tui/theme.js +110 -0
  225. package/dist/tui/titlebar-spinner.js +62 -0
  226. package/dist/tui/tui-app.js +311 -0
  227. package/dist/tui/ws-client.js +215 -0
  228. package/dist/twitter-verify.js +134 -0
  229. package/dist/tx-service.js +108 -0
  230. package/dist/utils/exec-safety.js +17 -0
  231. package/dist/utils/globals.js +20 -0
  232. package/dist/utils/milady-root.js +61 -0
  233. package/dist/utils/number-parsing.js +37 -0
  234. package/dist/version-resolver.js +37 -0
  235. package/dist/version.js +7 -0
  236. package/dist/wallet-routes.js +266 -0
  237. package/dist/wallet.js +568 -0
  238. package/dist/whatsapp-routes.js +182 -0
  239. package/dist/zip-utils.js +109 -0
  240. package/milady.mjs +14 -0
  241. package/package.json +111 -0
@@ -0,0 +1,156 @@
1
+ import { SUBSCRIPTION_PROVIDER_MAP } from "./types.js";
2
+ import { refreshAnthropicToken } from "./anthropic.js";
3
+ import { refreshCodexToken } from "./openai-codex.js";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { logger } from "@elizaos/core";
7
+ import fs from "node:fs";
8
+
9
+ //#region src/auth/credentials.ts
10
+ /**
11
+ * Credential storage and token refresh for subscription providers.
12
+ *
13
+ * Stores OAuth credentials in ~/.milady/auth/ as JSON files.
14
+ */
15
+ const AUTH_DIR = path.join(process.env.MILADY_HOME || path.join(os.homedir(), ".milady"), "auth");
16
+ /** Buffer before expiry to trigger refresh (5 minutes) */
17
+ const REFRESH_BUFFER_MS = 300 * 1e3;
18
+ function ensureAuthDir() {
19
+ if (!fs.existsSync(AUTH_DIR)) fs.mkdirSync(AUTH_DIR, {
20
+ recursive: true,
21
+ mode: 448
22
+ });
23
+ }
24
+ function credentialPath(provider) {
25
+ return path.join(AUTH_DIR, `${provider}.json`);
26
+ }
27
+ /**
28
+ * Save credentials for a provider.
29
+ */
30
+ function saveCredentials(provider, credentials) {
31
+ ensureAuthDir();
32
+ const stored = {
33
+ provider,
34
+ credentials,
35
+ createdAt: Date.now(),
36
+ updatedAt: Date.now()
37
+ };
38
+ fs.writeFileSync(credentialPath(provider), JSON.stringify(stored, null, 2), {
39
+ encoding: "utf-8",
40
+ mode: 384
41
+ });
42
+ logger.info(`[auth] Saved ${provider} credentials`);
43
+ }
44
+ /**
45
+ * Load stored credentials for a provider.
46
+ */
47
+ function loadCredentials(provider) {
48
+ const filePath = credentialPath(provider);
49
+ try {
50
+ const data = fs.readFileSync(filePath, "utf-8");
51
+ return JSON.parse(data);
52
+ } catch (err) {
53
+ if (err.code === "ENOENT") return null;
54
+ throw err;
55
+ }
56
+ }
57
+ /**
58
+ * Delete stored credentials for a provider.
59
+ */
60
+ function deleteCredentials(provider) {
61
+ const filePath = credentialPath(provider);
62
+ try {
63
+ fs.unlinkSync(filePath);
64
+ logger.info(`[auth] Deleted ${provider} credentials`);
65
+ } catch (err) {
66
+ if (err.code !== "ENOENT") throw err;
67
+ }
68
+ }
69
+ /**
70
+ * Get a valid access token, refreshing if needed.
71
+ * Returns null if no credentials stored or refresh fails.
72
+ */
73
+ async function getAccessToken(provider) {
74
+ const stored = loadCredentials(provider);
75
+ if (!stored) return null;
76
+ const { credentials } = stored;
77
+ if (credentials.expires > Date.now() + REFRESH_BUFFER_MS) return credentials.access;
78
+ logger.info(`[auth] Refreshing ${provider} token...`);
79
+ try {
80
+ let refreshed;
81
+ if (provider === "anthropic-subscription") refreshed = await refreshAnthropicToken(credentials.refresh);
82
+ else if (provider === "openai-codex") refreshed = await refreshCodexToken(credentials.refresh);
83
+ else {
84
+ logger.error(`[auth] Unknown provider: ${provider}`);
85
+ return null;
86
+ }
87
+ saveCredentials(provider, refreshed);
88
+ return refreshed.access;
89
+ } catch (err) {
90
+ logger.error(`[auth] Failed to refresh ${provider} token: ${err}`);
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * Get all configured subscription providers and their status.
96
+ */
97
+ function getSubscriptionStatus() {
98
+ return ["anthropic-subscription", "openai-codex"].map((provider) => {
99
+ const stored = loadCredentials(provider);
100
+ return {
101
+ provider,
102
+ configured: stored !== null,
103
+ valid: stored ? stored.credentials.expires > Date.now() : false,
104
+ expiresAt: stored?.credentials.expires ?? null
105
+ };
106
+ });
107
+ }
108
+ /**
109
+ * Apply subscription credentials to the environment.
110
+ * Called at startup to make credentials available to ElizaOS plugins.
111
+ *
112
+ * When a `config` is provided and the active subscription provider has
113
+ * credentials, `model.primary` is auto-set so the user doesn't need to
114
+ * configure it manually.
115
+ */
116
+ async function applySubscriptionCredentials(config) {
117
+ const anthropicToken = await getAccessToken("anthropic-subscription");
118
+ if (anthropicToken) {
119
+ process.env.ANTHROPIC_API_KEY = anthropicToken;
120
+ logger.info("[auth] Applied Anthropic subscription credentials to environment");
121
+ try {
122
+ const { applyClaudeCodeStealth } = await import("./apply-stealth.js");
123
+ applyClaudeCodeStealth();
124
+ } catch (err) {
125
+ logger.warn(`[auth] Failed to apply Claude stealth: ${err instanceof Error ? err.message : err}`);
126
+ }
127
+ }
128
+ const codexToken = await getAccessToken("openai-codex");
129
+ if (codexToken) {
130
+ process.env.OPENAI_API_KEY = codexToken;
131
+ logger.info("[auth] Applied OpenAI Codex subscription credentials to environment");
132
+ try {
133
+ const { applyOpenAICodexStealth } = await import("./apply-stealth.js");
134
+ await applyOpenAICodexStealth();
135
+ } catch (err) {
136
+ logger.warn(`[auth] Failed to apply OpenAI Codex stealth: ${err instanceof Error ? err.message : err}`);
137
+ }
138
+ }
139
+ if (config?.agents?.defaults) {
140
+ const defaults = config.agents.defaults;
141
+ const provider = defaults.subscriptionProvider;
142
+ const modelId = provider ? SUBSCRIPTION_PROVIDER_MAP[provider] : void 0;
143
+ if (modelId) {
144
+ if (!defaults.model) {
145
+ defaults.model = { primary: modelId };
146
+ logger.info(`[auth] Auto-set model.primary to "${modelId}" from subscription provider`);
147
+ } else if (!defaults.model.primary) {
148
+ defaults.model.primary = modelId;
149
+ logger.info(`[auth] Auto-set model.primary to "${modelId}" from subscription provider`);
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ //#endregion
156
+ export { applySubscriptionCredentials, deleteCredentials, getAccessToken, getSubscriptionStatus, loadCredentials, saveCredentials };
@@ -0,0 +1,5 @@
1
+ import { refreshAnthropicToken, startAnthropicLogin } from "./anthropic.js";
2
+ import { refreshCodexToken, startCodexLogin } from "./openai-codex.js";
3
+ import { applySubscriptionCredentials, deleteCredentials, getAccessToken, getSubscriptionStatus, loadCredentials, saveCredentials } from "./credentials.js";
4
+
5
+ export { applySubscriptionCredentials, deleteCredentials, getSubscriptionStatus, saveCredentials, startAnthropicLogin, startCodexLogin };
@@ -0,0 +1,66 @@
1
+ import { loginOpenAICodex, refreshOpenAICodexToken } from "@mariozechner/pi-ai";
2
+
3
+ //#region src/auth/openai-codex.ts
4
+ /**
5
+ * OpenAI Codex (ChatGPT Plus/Pro subscription) OAuth flow
6
+ *
7
+ * Wraps @mariozechner/pi-ai's loginOpenAICodex for server-side use.
8
+ * Handles local callback server + manual code paste fallback.
9
+ */
10
+ /**
11
+ * Start the OpenAI Codex OAuth flow.
12
+ * Starts a local callback server on port 1455 and returns the auth URL.
13
+ */
14
+ function startCodexLogin() {
15
+ return new Promise((resolveFlow, rejectFlow) => {
16
+ let authUrl = "";
17
+ let flowState = "";
18
+ let resolveManual = null;
19
+ let closeServer = null;
20
+ let credentials;
21
+ const manualPromise = new Promise((resolve) => {
22
+ resolveManual = resolve;
23
+ });
24
+ try {
25
+ credentials = loginOpenAICodex({
26
+ onAuth: ({ url }) => {
27
+ authUrl = url;
28
+ try {
29
+ flowState = new URL(url).searchParams.get("state") || "";
30
+ } catch {}
31
+ resolveFlow({
32
+ get authUrl() {
33
+ return authUrl;
34
+ },
35
+ state: flowState,
36
+ submitCode: (code) => resolveManual?.(code),
37
+ credentials,
38
+ close: () => closeServer?.()
39
+ });
40
+ },
41
+ onPrompt: async () => {
42
+ return manualPromise;
43
+ },
44
+ onManualCodeInput: () => manualPromise,
45
+ onProgress: () => {},
46
+ originator: "milady"
47
+ });
48
+ credentials.catch(() => {});
49
+ } catch (err) {
50
+ rejectFlow(err);
51
+ return;
52
+ }
53
+ closeServer = () => {
54
+ resolveManual?.("");
55
+ };
56
+ });
57
+ }
58
+ /**
59
+ * Refresh an expired OpenAI Codex token.
60
+ */
61
+ async function refreshCodexToken(refreshToken) {
62
+ return refreshOpenAICodexToken(refreshToken);
63
+ }
64
+
65
+ //#endregion
66
+ export { refreshCodexToken, startCodexLogin };
@@ -0,0 +1,9 @@
1
+ //#region src/auth/types.ts
2
+ /** Maps subscription provider IDs to their model provider short names. */
3
+ const SUBSCRIPTION_PROVIDER_MAP = {
4
+ "anthropic-subscription": "anthropic",
5
+ "openai-codex": "openai"
6
+ };
7
+
8
+ //#endregion
9
+ export { SUBSCRIPTION_PROVIDER_MAP };
@@ -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 };
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": "2.0.0-alpha.27",
3
+ "channel": "alpha",
4
+ "commit": "55ff7b657bc3db661ea23b4e64932f68cf183835",
5
+ "builtAt": "2026-02-23T03:34:19.379Z"
6
+ }
@@ -0,0 +1,195 @@
1
+ import { CharacterSchema } from "./config/zod-schema.js";
2
+ import { ModelType, logger } from "@elizaos/core";
3
+
4
+ //#region src/api/character-routes.ts
5
+ function buildCharacterSummary(ctx) {
6
+ return [
7
+ ctx.name ? `Name: ${ctx.name}` : "",
8
+ ctx.system ? `System prompt: ${ctx.system}` : "",
9
+ ctx.bio ? `Bio: ${ctx.bio}` : "",
10
+ ctx.style?.all?.length ? `Style rules: ${ctx.style.all.join("; ")}` : ""
11
+ ].filter(Boolean).join("\n");
12
+ }
13
+ function buildGeneratePrompt(field, context, mode) {
14
+ const charSummary = buildCharacterSummary(context);
15
+ if (field === "bio") return `Given this character:\n${charSummary}\n\nWrite a concise, compelling bio for this character (3-4 short paragraphs, one per line). Just output the bio lines, nothing else. Match the character's voice and personality.`;
16
+ if (field === "style") return `Given this character:\n${charSummary}${mode === "append" && context.style?.all?.length ? `\nExisting style rules (add to these, don't repeat):\n${context.style.all.join("\n")}` : ""}\n\nGenerate 4-6 communication style rules for this character. Output a JSON object with keys "all", "chat", "post", each containing an array of short rule strings. Just output the JSON, nothing else.`;
17
+ if (field === "chatExamples") return `Given this character:\n${charSummary}\n\nGenerate 3 example chat conversations showing how this character responds. Output a JSON array where each element is an array of message objects like [{"user":"{{user1}}","content":{"text":"..."}},{"user":"{{agentName}}","content":{"text":"..."}}]. Just output the JSON array, nothing else.`;
18
+ return `Given this character:\n${charSummary}${mode === "append" && context.postExamples?.length ? `\nExisting posts (add new ones, don't repeat):\n${context.postExamples.join("\n")}` : ""}\n\nGenerate 3-5 example social media posts this character would write. Output a JSON array of strings. Just output the JSON array, nothing else.`;
19
+ }
20
+ const CHARACTER_SCHEMA_FIELDS = [
21
+ {
22
+ key: "name",
23
+ type: "string",
24
+ label: "Name",
25
+ description: "Agent display name",
26
+ maxLength: 100
27
+ },
28
+ {
29
+ key: "username",
30
+ type: "string",
31
+ label: "Username",
32
+ description: "Agent username for platforms",
33
+ maxLength: 50
34
+ },
35
+ {
36
+ key: "bio",
37
+ type: "string | string[]",
38
+ label: "Bio",
39
+ description: "Biography — single string or array of points"
40
+ },
41
+ {
42
+ key: "system",
43
+ type: "string",
44
+ label: "System Prompt",
45
+ description: "System prompt defining core behavior",
46
+ maxLength: 1e4
47
+ },
48
+ {
49
+ key: "adjectives",
50
+ type: "string[]",
51
+ label: "Adjectives",
52
+ description: "Personality adjectives (e.g. curious, witty)"
53
+ },
54
+ {
55
+ key: "topics",
56
+ type: "string[]",
57
+ label: "Topics",
58
+ description: "Topics the agent is knowledgeable about"
59
+ },
60
+ {
61
+ key: "style",
62
+ type: "object",
63
+ label: "Style",
64
+ description: "Communication style guides",
65
+ children: [
66
+ {
67
+ key: "all",
68
+ type: "string[]",
69
+ label: "All",
70
+ description: "Style guidelines for all responses"
71
+ },
72
+ {
73
+ key: "chat",
74
+ type: "string[]",
75
+ label: "Chat",
76
+ description: "Style guidelines for chat responses"
77
+ },
78
+ {
79
+ key: "post",
80
+ type: "string[]",
81
+ label: "Post",
82
+ description: "Style guidelines for social media posts"
83
+ }
84
+ ]
85
+ },
86
+ {
87
+ key: "messageExamples",
88
+ type: "array",
89
+ label: "Message Examples",
90
+ description: "Example conversations demonstrating the agent's voice"
91
+ },
92
+ {
93
+ key: "postExamples",
94
+ type: "string[]",
95
+ label: "Post Examples",
96
+ description: "Example social media posts"
97
+ }
98
+ ];
99
+ async function handleCharacterRoutes(ctx) {
100
+ const { req, res, method, pathname, state, readJsonBody, json, error, pickRandomNames } = ctx;
101
+ if (method === "GET" && pathname === "/api/character") {
102
+ const runtime = state.runtime;
103
+ const merged = {};
104
+ if (runtime) {
105
+ const character = runtime.character;
106
+ if (character.name) merged.name = character.name;
107
+ if (character.bio) merged.bio = character.bio;
108
+ if (character.system) merged.system = character.system;
109
+ if (character.adjectives) merged.adjectives = character.adjectives;
110
+ if (character.topics) merged.topics = character.topics;
111
+ if (character.style) merged.style = character.style;
112
+ if (character.postExamples) merged.postExamples = character.postExamples;
113
+ }
114
+ json(res, {
115
+ character: merged,
116
+ agentName: state.agentName
117
+ });
118
+ return true;
119
+ }
120
+ if (method === "PUT" && pathname === "/api/character") {
121
+ const body = await readJsonBody(req, res);
122
+ if (!body) return true;
123
+ const result = CharacterSchema.safeParse(body);
124
+ if (!result.success) {
125
+ json(res, {
126
+ ok: false,
127
+ validationErrors: result.error.issues.map((issue) => ({
128
+ path: issue.path.join("."),
129
+ message: issue.message
130
+ }))
131
+ }, 422);
132
+ return true;
133
+ }
134
+ if (state.runtime) {
135
+ const character = state.runtime.character;
136
+ if (body.name != null) character.name = String(body.name);
137
+ if (body.bio != null) character.bio = Array.isArray(body.bio) ? body.bio : [String(body.bio)];
138
+ if (body.system != null) character.system = String(body.system);
139
+ if (body.adjectives != null) character.adjectives = body.adjectives;
140
+ if (body.topics != null) character.topics = body.topics;
141
+ if (body.style != null) character.style = body.style;
142
+ if (body.postExamples != null) character.postExamples = body.postExamples;
143
+ }
144
+ if (body.name) state.agentName = String(body.name);
145
+ json(res, {
146
+ ok: true,
147
+ character: body,
148
+ agentName: state.agentName
149
+ });
150
+ return true;
151
+ }
152
+ if (method === "GET" && pathname === "/api/character/random-name") {
153
+ json(res, { name: pickRandomNames(1)[0] ?? "Reimu" });
154
+ return true;
155
+ }
156
+ if (method === "POST" && pathname === "/api/character/generate") {
157
+ const body = await readJsonBody(req, res);
158
+ if (!body) return true;
159
+ if (!body.field || !body.context) {
160
+ error(res, "field and context are required", 400);
161
+ return true;
162
+ }
163
+ const runtime = state.runtime;
164
+ if (!runtime) {
165
+ error(res, "Agent runtime not available. Start the agent first.", 503);
166
+ return true;
167
+ }
168
+ if (body.field !== "bio" && body.field !== "style" && body.field !== "chatExamples" && body.field !== "postExamples") {
169
+ error(res, `Unknown field: ${body.field}`, 400);
170
+ return true;
171
+ }
172
+ const prompt = buildGeneratePrompt(body.field, body.context, body.mode);
173
+ try {
174
+ const result = await runtime.useModel(ModelType.TEXT_SMALL, {
175
+ prompt,
176
+ temperature: .8,
177
+ maxTokens: 1500
178
+ });
179
+ json(res, { generated: String(result) });
180
+ } catch (err) {
181
+ const message = err instanceof Error ? err.message : "generation failed";
182
+ logger.error(`[character-generate] ${message}`);
183
+ error(res, message, 500);
184
+ }
185
+ return true;
186
+ }
187
+ if (method === "GET" && pathname === "/api/character/schema") {
188
+ json(res, { fields: CHARACTER_SCHEMA_FIELDS });
189
+ return true;
190
+ }
191
+ return false;
192
+ }
193
+
194
+ //#endregion
195
+ export { handleCharacterRoutes };