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,109 @@
1
+ //#region src/api/permissions-routes.ts
2
+ async function handlePermissionRoutes(ctx) {
3
+ const { req, res, method, pathname, state, readJsonBody, json, error, saveConfig, scheduleRuntimeRestart } = ctx;
4
+ if (!pathname.startsWith("/api/permissions")) return false;
5
+ if (method === "GET" && pathname === "/api/permissions") {
6
+ json(res, {
7
+ permissions: state.permissionStates ?? {},
8
+ platform: process.platform,
9
+ shellEnabled: state.shellEnabled ?? true
10
+ });
11
+ return true;
12
+ }
13
+ if (method === "GET" && pathname === "/api/permissions/shell") {
14
+ const enabled = state.shellEnabled ?? true;
15
+ if (!state.permissionStates) state.permissionStates = {};
16
+ const shellState = state.permissionStates.shell;
17
+ const permission = {
18
+ id: "shell",
19
+ status: enabled ? "granted" : "denied",
20
+ lastChecked: shellState?.lastChecked ?? Date.now(),
21
+ canRequest: false
22
+ };
23
+ state.permissionStates.shell = permission;
24
+ json(res, {
25
+ enabled,
26
+ ...permission,
27
+ permission
28
+ });
29
+ return true;
30
+ }
31
+ if (method === "GET" && pathname.startsWith("/api/permissions/")) {
32
+ const permId = pathname.slice(17);
33
+ if (!permId || permId.includes("/")) {
34
+ error(res, "Invalid permission ID", 400);
35
+ return true;
36
+ }
37
+ const permState = (state.permissionStates ?? {})[permId];
38
+ if (!permState) {
39
+ json(res, {
40
+ id: permId,
41
+ status: "not-applicable",
42
+ lastChecked: Date.now(),
43
+ canRequest: false
44
+ });
45
+ return true;
46
+ }
47
+ json(res, permState);
48
+ return true;
49
+ }
50
+ if (method === "POST" && pathname === "/api/permissions/refresh") {
51
+ json(res, {
52
+ message: "Permission refresh requested",
53
+ action: "ipc:permissions:refresh"
54
+ });
55
+ return true;
56
+ }
57
+ if (method === "POST" && pathname.match(/^\/api\/permissions\/[^/]+\/request$/)) {
58
+ const permId = pathname.split("/")[3];
59
+ json(res, {
60
+ message: `Permission request for ${permId}`,
61
+ action: `ipc:permissions:request:${permId}`
62
+ });
63
+ return true;
64
+ }
65
+ if (method === "POST" && pathname.match(/^\/api\/permissions\/[^/]+\/open-settings$/)) {
66
+ const permId = pathname.split("/")[3];
67
+ json(res, {
68
+ message: `Opening settings for ${permId}`,
69
+ action: `ipc:permissions:openSettings:${permId}`
70
+ });
71
+ return true;
72
+ }
73
+ if (method === "PUT" && pathname === "/api/permissions/shell") {
74
+ const body = await readJsonBody(req, res);
75
+ if (!body) return true;
76
+ const enabled = body.enabled === true;
77
+ state.shellEnabled = enabled;
78
+ if (!state.permissionStates) state.permissionStates = {};
79
+ state.permissionStates.shell = {
80
+ id: "shell",
81
+ status: enabled ? "granted" : "denied",
82
+ lastChecked: Date.now(),
83
+ canRequest: false
84
+ };
85
+ if (!state.config.features) state.config.features = {};
86
+ state.config.features.shellEnabled = enabled;
87
+ saveConfig(state.config);
88
+ if (state.runtime) scheduleRuntimeRestart(`Shell access ${enabled ? "enabled" : "disabled"}`);
89
+ json(res, {
90
+ shellEnabled: enabled,
91
+ permission: state.permissionStates.shell
92
+ });
93
+ return true;
94
+ }
95
+ if (method === "PUT" && pathname === "/api/permissions/state") {
96
+ const body = await readJsonBody(req, res);
97
+ if (!body) return true;
98
+ if (body.permissions && typeof body.permissions === "object") state.permissionStates = body.permissions;
99
+ json(res, {
100
+ updated: true,
101
+ permissions: state.permissionStates
102
+ });
103
+ return true;
104
+ }
105
+ return false;
106
+ }
107
+
108
+ //#endregion
109
+ export { handlePermissionRoutes };
@@ -0,0 +1,198 @@
1
+ //#region src/api/plugin-validation.ts
2
+ const KEY_PREFIX_HINTS = {
3
+ ANTHROPIC_API_KEY: {
4
+ prefix: "sk-ant-",
5
+ label: "Anthropic"
6
+ },
7
+ OPENAI_API_KEY: {
8
+ prefix: "sk-",
9
+ label: "OpenAI"
10
+ },
11
+ GROQ_API_KEY: {
12
+ prefix: "gsk_",
13
+ label: "Groq"
14
+ },
15
+ XAI_API_KEY: {
16
+ prefix: "xai-",
17
+ label: "xAI"
18
+ },
19
+ OPENROUTER_API_KEY: {
20
+ prefix: "sk-or-",
21
+ label: "OpenRouter"
22
+ }
23
+ };
24
+ /**
25
+ * Validate a plugin's configuration.
26
+ *
27
+ * Checks all required parameters (from the plugin's package.json metadata)
28
+ * and applies format-specific warnings for known API key patterns.
29
+ *
30
+ * @param pluginId - The plugin identifier (e.g. "anthropic", "discord")
31
+ * @param category - Plugin category
32
+ * @param envKey - Primary environment variable key (legacy, used as fallback)
33
+ * @param configKeys - All known config key names for this plugin
34
+ * @param providedConfig - Config values being set (for PUT validation)
35
+ * @param paramDefs - Full parameter definitions with required/sensitive metadata
36
+ */
37
+ function validatePluginConfig(_pluginId, _category, envKey, configKeys, providedConfig, paramDefs) {
38
+ const errors = [];
39
+ const warnings = [];
40
+ const allowedConfigKeys = new Set(configKeys);
41
+ const canonicalKeyByNormalized = new Map(configKeys.map((key) => [key.trim().toUpperCase(), key]));
42
+ if (providedConfig) for (const key of Object.keys(providedConfig)) {
43
+ if (allowedConfigKeys.has(key)) continue;
44
+ const canonical = canonicalKeyByNormalized.get(key.trim().toUpperCase());
45
+ if (canonical) {
46
+ errors.push({
47
+ field: key,
48
+ message: `${key} does not match declared config key casing; use ${canonical}`
49
+ });
50
+ continue;
51
+ }
52
+ errors.push({
53
+ field: key,
54
+ message: `${key} is not a declared config key for this plugin`
55
+ });
56
+ }
57
+ if (paramDefs && paramDefs.length > 0) for (const param of paramDefs) {
58
+ if (!param.required) continue;
59
+ const value = providedConfig?.[param.key] ?? process.env[param.key];
60
+ if (!value || !value.trim()) {
61
+ if (param.default) warnings.push({
62
+ field: param.key,
63
+ message: `${param.key} is not set (will use default: ${param.default})`
64
+ });
65
+ else errors.push({
66
+ field: param.key,
67
+ message: `${param.key} is required but not set`
68
+ });
69
+ continue;
70
+ }
71
+ const hint = KEY_PREFIX_HINTS[param.key];
72
+ if (hint && !value.startsWith(hint.prefix)) warnings.push({
73
+ field: param.key,
74
+ message: `${hint.label} key should start with "${hint.prefix}" — the current value may be invalid`
75
+ });
76
+ if (param.sensitive && value.trim().length < 10) warnings.push({
77
+ field: param.key,
78
+ message: `${param.key} looks too short (${value.trim().length} chars)`
79
+ });
80
+ }
81
+ else if (envKey) {
82
+ const currentValue = providedConfig?.[envKey] ?? process.env[envKey];
83
+ if (!currentValue || !currentValue.trim()) errors.push({
84
+ field: envKey,
85
+ message: `${envKey} is required but not set`
86
+ });
87
+ else {
88
+ const hint = KEY_PREFIX_HINTS[envKey];
89
+ if (hint && !currentValue.startsWith(hint.prefix)) warnings.push({
90
+ field: envKey,
91
+ message: `${hint.label} key should start with "${hint.prefix}" — the current value may be invalid`
92
+ });
93
+ if (currentValue.trim().length < 10) warnings.push({
94
+ field: envKey,
95
+ message: `${envKey} looks too short (${currentValue.trim().length} chars)`
96
+ });
97
+ }
98
+ }
99
+ return {
100
+ valid: errors.length === 0,
101
+ errors,
102
+ warnings
103
+ };
104
+ }
105
+ /**
106
+ * Validate a runtime context object for null, undefined, empty, and
107
+ * non-serializable fields.
108
+ *
109
+ * Used after provider + plugin resolution to detect and surface invalid
110
+ * or malformed context early — before it reaches the agent runtime.
111
+ *
112
+ * @param context - The context object to validate.
113
+ * @param maxDepth - Maximum nesting depth to inspect (default: 5).
114
+ */
115
+ function validateRuntimeContext(context, maxDepth = 5) {
116
+ const nullFields = [];
117
+ const undefinedFields = [];
118
+ const emptyFields = [];
119
+ const nonSerializableFields = [];
120
+ function walk(obj, prefix, depth) {
121
+ if (depth > maxDepth) return;
122
+ for (const [key, value] of Object.entries(obj)) {
123
+ const path = prefix ? `${prefix}.${key}` : key;
124
+ if (value === null) {
125
+ nullFields.push(path);
126
+ continue;
127
+ }
128
+ if (value === void 0) {
129
+ undefinedFields.push(path);
130
+ continue;
131
+ }
132
+ if (typeof value === "string" && value.trim() === "") {
133
+ emptyFields.push(path);
134
+ continue;
135
+ }
136
+ if (typeof value === "function") {
137
+ nonSerializableFields.push(path);
138
+ continue;
139
+ }
140
+ if (typeof value === "symbol") {
141
+ nonSerializableFields.push(path);
142
+ continue;
143
+ }
144
+ if (typeof value === "bigint") {
145
+ nonSerializableFields.push(path);
146
+ continue;
147
+ }
148
+ if (typeof value === "object" && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp)) walk(value, path, depth + 1);
149
+ }
150
+ }
151
+ walk(context, "", 0);
152
+ let serializable = true;
153
+ if (nonSerializableFields.length > 0) serializable = false;
154
+ else try {
155
+ JSON.stringify(context);
156
+ } catch {
157
+ serializable = false;
158
+ }
159
+ return {
160
+ valid: nullFields.length === 0 && undefinedFields.length === 0 && emptyFields.length === 0,
161
+ serializable,
162
+ nullFields,
163
+ undefinedFields,
164
+ emptyFields,
165
+ nonSerializableFields
166
+ };
167
+ }
168
+ /**
169
+ * Log the full resolved plugin/provider context for debugging.
170
+ *
171
+ * Prints a structured summary of all loaded plugins, providers,
172
+ * and any validation issues detected in the context.
173
+ *
174
+ * @param plugins - Array of resolved plugin names.
175
+ * @param providers - Array of resolved provider names.
176
+ * @param context - The runtime context object to inspect.
177
+ * @param log - Logger function (defaults to console.debug).
178
+ */
179
+ function debugLogResolvedContext(plugins, providers, context, log = console.debug) {
180
+ log("[milady:debug] ══════ Resolved Plugin/Provider Context ══════");
181
+ log(`[milady:debug] Plugins loaded (${plugins.length}):`);
182
+ for (const name of plugins) log(`[milady:debug] • ${name}`);
183
+ log(`[milady:debug] Providers loaded (${providers.length}):`);
184
+ for (const name of providers) log(`[milady:debug] • ${name}`);
185
+ const validation = validateRuntimeContext(context);
186
+ if (validation.valid && validation.serializable) log("[milady:debug] Context validation: ✓ PASS (all fields valid, serializable)");
187
+ else {
188
+ log("[milady:debug] Context validation: ✗ ISSUES DETECTED");
189
+ if (validation.nullFields.length > 0) log(`[milady:debug] null fields: ${validation.nullFields.join(", ")}`);
190
+ if (validation.undefinedFields.length > 0) log(`[milady:debug] undefined fields: ${validation.undefinedFields.join(", ")}`);
191
+ if (validation.emptyFields.length > 0) log(`[milady:debug] empty fields: ${validation.emptyFields.join(", ")}`);
192
+ if (validation.nonSerializableFields.length > 0) log(`[milady:debug] non-serializable fields: ${validation.nonSerializableFields.join(", ")}`);
193
+ }
194
+ log("[milady:debug] ══════════════════════════════════════════════");
195
+ }
196
+
197
+ //#endregion
198
+ export { debugLogResolvedContext, validatePluginConfig, validateRuntimeContext };
@@ -0,0 +1,41 @@
1
+ import { SUBSCRIPTION_PROVIDER_MAP } from "../auth/types.js";
2
+
3
+ //#region src/api/provider-switch-config.ts
4
+ /**
5
+ * Apply subscription provider configuration to the config object.
6
+ *
7
+ * Sets `agents.defaults.subscriptionProvider` and `agents.defaults.model.primary`
8
+ * so the runtime auto-detects the correct provider on restart.
9
+ *
10
+ * Mutates `config` in place.
11
+ */
12
+ function applySubscriptionProviderConfig(config, provider) {
13
+ config.agents ??= {};
14
+ config.agents.defaults ??= {};
15
+ const defaults = config.agents.defaults;
16
+ const subscriptionKey = provider === "openai-subscription" ? "openai-codex" : provider;
17
+ const modelProvider = SUBSCRIPTION_PROVIDER_MAP[subscriptionKey];
18
+ if (modelProvider) {
19
+ defaults.subscriptionProvider = subscriptionKey;
20
+ defaults.model = {
21
+ ...defaults.model,
22
+ primary: modelProvider
23
+ };
24
+ }
25
+ }
26
+ /**
27
+ * Clear subscription provider configuration from the config object.
28
+ *
29
+ * Removes `agents.defaults.subscriptionProvider` so the runtime
30
+ * doesn't try to auto-detect a subscription provider on restart.
31
+ *
32
+ * Mutates `config` in place.
33
+ */
34
+ function clearSubscriptionProviderConfig(config) {
35
+ config.agents ??= {};
36
+ config.agents.defaults ??= {};
37
+ delete config.agents.defaults.subscriptionProvider;
38
+ }
39
+
40
+ //#endregion
41
+ export { applySubscriptionProviderConfig, clearSubscriptionProviderConfig };
@@ -0,0 +1,86 @@
1
+ import { parseClampedInteger } from "../utils/number-parsing.js";
2
+
3
+ //#region src/api/registry-routes.ts
4
+ async function handleRegistryRoutes(ctx) {
5
+ const { res, method, pathname, url, json, error, getPluginManager, getLoadedPluginNames, getBundledPluginIds } = ctx;
6
+ if (method === "GET" && pathname === "/api/registry/plugins") {
7
+ try {
8
+ const pluginManager = getPluginManager();
9
+ const registry = await pluginManager.refreshRegistry();
10
+ const installed = await pluginManager.listInstalledPlugins();
11
+ const installedNames = new Set(installed.map((plugin) => plugin.name));
12
+ const loadedNames = new Set(getLoadedPluginNames());
13
+ const bundledIds = getBundledPluginIds();
14
+ const plugins = Array.from(registry.values()).map((plugin) => {
15
+ const shortId = plugin.name.replace(/^@[^/]+\/plugin-/, "").replace(/^@[^/]+\//, "").replace(/^plugin-/, "");
16
+ return {
17
+ ...plugin,
18
+ installed: installedNames.has(plugin.name),
19
+ installedVersion: installed.find((entry) => entry.name === plugin.name)?.version ?? null,
20
+ loaded: loadedNames.has(plugin.name) || loadedNames.has(plugin.name.replace("@elizaos/", "")),
21
+ bundled: bundledIds.has(shortId)
22
+ };
23
+ });
24
+ json(res, {
25
+ count: plugins.length,
26
+ plugins
27
+ });
28
+ } catch (err) {
29
+ error(res, `Failed to fetch registry: ${err instanceof Error ? err.message : String(err)}`, 502);
30
+ }
31
+ return true;
32
+ }
33
+ if (method === "GET" && pathname.startsWith("/api/registry/plugins/") && pathname.length > 22) {
34
+ const name = decodeURIComponent(pathname.slice(22));
35
+ try {
36
+ const info = await getPluginManager().getRegistryPlugin(name);
37
+ if (!info) {
38
+ error(res, `Plugin "${name}" not found in registry`, 404);
39
+ return true;
40
+ }
41
+ json(res, { plugin: info });
42
+ } catch (err) {
43
+ error(res, `Failed to look up plugin: ${err instanceof Error ? err.message : String(err)}`, 502);
44
+ }
45
+ return true;
46
+ }
47
+ if (method === "GET" && pathname === "/api/registry/search") {
48
+ const query = url.searchParams.get("q") || "";
49
+ if (!query.trim()) {
50
+ error(res, "Query parameter 'q' is required", 400);
51
+ return true;
52
+ }
53
+ try {
54
+ const limitParam = url.searchParams.get("limit");
55
+ const limit = limitParam ? parseClampedInteger(limitParam, {
56
+ min: 1,
57
+ max: 50,
58
+ fallback: 15
59
+ }) : 15;
60
+ const results = await getPluginManager().searchRegistry(query, limit);
61
+ json(res, {
62
+ query,
63
+ count: results.length,
64
+ results
65
+ });
66
+ } catch (err) {
67
+ error(res, `Search failed: ${err instanceof Error ? err.message : String(err)}`, 502);
68
+ }
69
+ return true;
70
+ }
71
+ if (method === "POST" && pathname === "/api/registry/refresh") {
72
+ try {
73
+ json(res, {
74
+ ok: true,
75
+ count: (await getPluginManager().refreshRegistry()).size
76
+ });
77
+ } catch (err) {
78
+ error(res, `Refresh failed: ${err instanceof Error ? err.message : String(err)}`, 502);
79
+ }
80
+ return true;
81
+ }
82
+ return false;
83
+ }
84
+
85
+ //#endregion
86
+ export { handleRegistryRoutes };
@@ -0,0 +1,164 @@
1
+ import { logger } from "@elizaos/core";
2
+ import { ethers } from "ethers";
3
+
4
+ //#region src/api/registry-service.ts
5
+ /**
6
+ * ERC-8004 Agent Identity Registry service.
7
+ *
8
+ * Handles all interactions with the MiladyAgentRegistry contract:
9
+ * - Registration (self and delegated)
10
+ * - Profile updates
11
+ * - Metadata (tokenURI) management
12
+ * - Status queries
13
+ */
14
+ const REGISTRY_ABI = [
15
+ "function registerAgent(string,string,bytes32,string) external returns (uint256)",
16
+ "function registerAgentFor(address,string,string,bytes32,string) external returns (uint256)",
17
+ "function updateAgent(string,bytes32) external",
18
+ "function updateAgentProfile(string,string,bytes32,string) external",
19
+ "function updateTokenURI(uint256,string) external",
20
+ "function deactivateAgent() external",
21
+ "function reactivateAgent() external",
22
+ "function getAgentInfo(uint256) view returns (string,string,bytes32,bool)",
23
+ "function addressToTokenId(address) view returns (uint256)",
24
+ "function isRegistered(address) view returns (bool)",
25
+ "function getTokenId(address) view returns (uint256)",
26
+ "function totalAgents() view returns (uint256)",
27
+ "function isEndpointTaken(string) view returns (bool)",
28
+ "function balanceOf(address) view returns (uint256)",
29
+ "function ownerOf(uint256) view returns (address)",
30
+ "function tokenURI(uint256) view returns (string)",
31
+ "event AgentRegistered(uint256 indexed tokenId, address indexed owner, string name, string endpoint)",
32
+ "event AgentUpdated(uint256 indexed tokenId, string endpoint, bytes32 capabilitiesHash)"
33
+ ];
34
+ const DEFAULT_CAPABILITIES_HASH = ethers.id("milady-agent");
35
+ var RegistryService = class {
36
+ constructor(txService, registryAddress) {
37
+ this.txService = txService;
38
+ this.registryAddress = registryAddress;
39
+ this.contract = txService.getContract(registryAddress, REGISTRY_ABI);
40
+ }
41
+ get address() {
42
+ return this.txService.address;
43
+ }
44
+ get contractAddress() {
45
+ return this.registryAddress;
46
+ }
47
+ async getChainId() {
48
+ return this.txService.getChainId();
49
+ }
50
+ /**
51
+ * Get the full registration status for the current wallet.
52
+ */
53
+ async getStatus() {
54
+ const addr = this.txService.address;
55
+ const [registered, totalAgentsBN] = await Promise.all([this.contract.isRegistered(addr), this.contract.totalAgents()]);
56
+ if (!registered) return {
57
+ registered: false,
58
+ tokenId: 0,
59
+ agentName: "",
60
+ agentEndpoint: "",
61
+ capabilitiesHash: "",
62
+ isActive: false,
63
+ tokenURI: "",
64
+ walletAddress: addr,
65
+ totalAgents: Number(totalAgentsBN)
66
+ };
67
+ const tokenId = Number(await this.contract.getTokenId(addr));
68
+ const [[name, endpoint, capHash, isActive], uri] = await Promise.all([this.contract.getAgentInfo(tokenId), this.contract.tokenURI(tokenId)]);
69
+ return {
70
+ registered: true,
71
+ tokenId,
72
+ agentName: name,
73
+ agentEndpoint: endpoint,
74
+ capabilitiesHash: capHash,
75
+ isActive,
76
+ tokenURI: uri,
77
+ walletAddress: addr,
78
+ totalAgents: Number(totalAgentsBN)
79
+ };
80
+ }
81
+ /**
82
+ * Register the current wallet as an agent.
83
+ * The NFT is minted to the wallet address stored in EVM_PRIVATE_KEY.
84
+ */
85
+ async register(params) {
86
+ const capHash = params.capabilitiesHash || DEFAULT_CAPABILITIES_HASH;
87
+ logger.info(`[registry] Registering agent "${params.name}" from ${this.txService.address}`);
88
+ const nonce = await this.txService.getFreshNonce();
89
+ const tx = await this.contract.registerAgent(params.name, params.endpoint, capHash, params.tokenURI, { nonce });
90
+ logger.info(`[registry] Registration tx submitted: ${tx.hash}`);
91
+ const receipt = await tx.wait();
92
+ const iface = new ethers.Interface(REGISTRY_ABI);
93
+ let tokenId = 0;
94
+ for (const log of receipt.logs) {
95
+ const parsed = iface.parseLog({
96
+ topics: log.topics,
97
+ data: log.data
98
+ });
99
+ if (parsed && parsed.name === "AgentRegistered") {
100
+ tokenId = Number(parsed.args[0]);
101
+ break;
102
+ }
103
+ }
104
+ if (tokenId === 0) tokenId = Number(await this.contract.getTokenId(this.txService.address));
105
+ logger.info(`[registry] Agent registered: tokenId=${tokenId} txHash=${receipt.hash}`);
106
+ return {
107
+ tokenId,
108
+ txHash: receipt.hash
109
+ };
110
+ }
111
+ /**
112
+ * Update the tokenURI (metadata pointer) for the current wallet's agent.
113
+ * Called when the character is edited.
114
+ */
115
+ async updateTokenURI(newURI) {
116
+ const tokenId = Number(await this.contract.getTokenId(this.txService.address));
117
+ if (tokenId === 0) throw new Error("Agent not registered, cannot update token URI");
118
+ logger.info(`[registry] Updating tokenURI for token ${tokenId}: ${newURI}`);
119
+ const nonce = await this.txService.getFreshNonce();
120
+ const receipt = await (await this.contract.updateTokenURI(tokenId, newURI, { nonce })).wait();
121
+ logger.info(`[registry] TokenURI updated: txHash=${receipt.hash}`);
122
+ return receipt.hash;
123
+ }
124
+ /**
125
+ * Update the agent's endpoint and capabilities hash.
126
+ */
127
+ async updateAgent(endpoint, capabilitiesHash) {
128
+ const capHash = capabilitiesHash || DEFAULT_CAPABILITIES_HASH;
129
+ logger.info(`[registry] Updating agent profile: endpoint=${endpoint}`);
130
+ const nonce = await this.txService.getFreshNonce();
131
+ const receipt = await (await this.contract.updateAgent(endpoint, capHash, { nonce })).wait();
132
+ logger.info(`[registry] Agent updated: txHash=${receipt.hash}`);
133
+ return receipt.hash;
134
+ }
135
+ /**
136
+ * Check if a specific address is registered.
137
+ */
138
+ /**
139
+ * Sync the full agent profile on-chain: name, endpoint, capabilities, and tokenURI.
140
+ * Called when the character is edited and user wants to push changes to chain.
141
+ */
142
+ async syncProfile(params) {
143
+ const capHash = params.capabilitiesHash || DEFAULT_CAPABILITIES_HASH;
144
+ logger.info(`[registry] Syncing profile: name="${params.name}" endpoint="${params.endpoint}"`);
145
+ const nonce = await this.txService.getFreshNonce();
146
+ const tx = await this.contract.updateAgentProfile(params.name, params.endpoint, capHash, params.tokenURI, { nonce });
147
+ logger.info(`[registry] Sync tx submitted: ${tx.hash}`);
148
+ const receipt = await tx.wait();
149
+ logger.info(`[registry] Profile synced: txHash=${receipt.hash}`);
150
+ return receipt.hash;
151
+ }
152
+ async isRegistered(address) {
153
+ return this.contract.isRegistered(address);
154
+ }
155
+ /**
156
+ * Build the default capabilities hash used for Milady agents.
157
+ */
158
+ static defaultCapabilitiesHash() {
159
+ return DEFAULT_CAPABILITIES_HASH;
160
+ }
161
+ };
162
+
163
+ //#endregion
164
+ export { RegistryService };