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,297 @@
1
+ import { createEngine, detectBestEngine } from "./sandbox-engine.js";
2
+ import os from "node:os";
3
+ import { join } from "node:path";
4
+ import { mkdirSync } from "node:fs";
5
+
6
+ //#region src/services/sandbox-manager.ts
7
+ /** Sandbox container lifecycle: create, exec, health check, teardown. */
8
+ var SandboxManager = class {
9
+ constructor(config) {
10
+ this.state = "uninitialized";
11
+ this.containerId = null;
12
+ this.browserContainerId = null;
13
+ this.eventLog = [];
14
+ this.config = {
15
+ image: "milady-sandbox:bookworm-slim",
16
+ containerPrefix: "milady-sandbox",
17
+ workdir: "/workspace",
18
+ network: "none",
19
+ user: "1000:1000",
20
+ capDrop: ["ALL"],
21
+ memory: "512m",
22
+ cpus: 1,
23
+ pidsLimit: 256,
24
+ ...config
25
+ };
26
+ this.engine = config.engineType ? createEngine(config.engineType) : detectBestEngine();
27
+ }
28
+ getState() {
29
+ return this.state;
30
+ }
31
+ getMode() {
32
+ return this.config.mode;
33
+ }
34
+ isReady() {
35
+ return this.state === "ready";
36
+ }
37
+ getMainContainerConfig() {
38
+ const image = this.config.image ?? "milady-sandbox:bookworm-slim";
39
+ const containerPrefix = this.config.containerPrefix ?? "milady-sandbox";
40
+ const workdir = this.config.workdir ?? "/workspace";
41
+ const network = this.config.network ?? "none";
42
+ const user = this.config.user ?? "1000:1000";
43
+ const wsRoot = this.config.workspaceRoot ?? join(process.env.HOME ?? process.env.USERPROFILE ?? os.tmpdir(), ".milady", "sandbox-workspace");
44
+ mkdirSync(wsRoot, { recursive: true });
45
+ return {
46
+ image,
47
+ containerPrefix,
48
+ workdir,
49
+ network,
50
+ user,
51
+ wsRoot
52
+ };
53
+ }
54
+ async createMainContainer() {
55
+ const config = this.getMainContainerConfig();
56
+ return this.engine.runContainer({
57
+ image: config.image,
58
+ name: `${config.containerPrefix}-${Date.now()}`,
59
+ detach: true,
60
+ mounts: [{
61
+ host: config.wsRoot,
62
+ container: config.workdir,
63
+ readonly: false
64
+ }],
65
+ env: this.config.env ?? {},
66
+ network: config.network,
67
+ user: config.user,
68
+ capDrop: this.config.capDrop ?? [],
69
+ memory: this.config.memory,
70
+ cpus: this.config.cpus,
71
+ pidsLimit: this.config.pidsLimit,
72
+ readOnlyRoot: this.config.readOnlyRoot,
73
+ dns: this.config.dns
74
+ });
75
+ }
76
+ async cleanupContainer(containerId) {
77
+ if (!containerId) return;
78
+ await this.engine.stopContainer(containerId);
79
+ await this.engine.removeContainer(containerId);
80
+ }
81
+ setState(newState) {
82
+ const oldState = this.state;
83
+ this.state = newState;
84
+ this.emitEvent({
85
+ timestamp: Date.now(),
86
+ type: "state_change",
87
+ detail: `${oldState} → ${newState}`
88
+ });
89
+ }
90
+ async start() {
91
+ if (this.config.mode === "off") {
92
+ this.setState("stopped");
93
+ return;
94
+ }
95
+ if (this.config.mode === "light") {
96
+ this.setState("ready");
97
+ return;
98
+ }
99
+ this.setState("initializing");
100
+ try {
101
+ const config = this.getMainContainerConfig();
102
+ if (!this.engine.isAvailable()) throw new Error(`Container engine "${this.engine.engineType}" is not available. Install Docker or Apple Container.`);
103
+ if (!this.engine.imageExists(config.image)) try {
104
+ await this.engine.pullImage(config.image);
105
+ } catch {
106
+ throw new Error(`Sandbox image "${config.image}" not found. Build with: scripts/sandbox-setup.sh`);
107
+ }
108
+ const orphans = this.engine.listContainers(config.containerPrefix);
109
+ for (const id of orphans) {
110
+ await this.engine.stopContainer(id);
111
+ await this.engine.removeContainer(id);
112
+ }
113
+ this.containerId = await this.createMainContainer();
114
+ this.emitEvent({
115
+ timestamp: Date.now(),
116
+ type: "container_start",
117
+ detail: `Container started: ${this.containerId}`
118
+ });
119
+ if (this.config.browser?.enabled && this.config.browser?.autoStart) try {
120
+ this.browserContainerId = await this.createBrowserContainer();
121
+ } catch (err) {
122
+ this.emitEvent({
123
+ timestamp: Date.now(),
124
+ type: "error",
125
+ detail: `Browser container start failed: ${err instanceof Error ? err.message : String(err)}`
126
+ });
127
+ }
128
+ if (await this.healthCheck()) this.setState("ready");
129
+ else this.setState("degraded");
130
+ } catch (err) {
131
+ this.emitEvent({
132
+ timestamp: Date.now(),
133
+ type: "error",
134
+ detail: `Sandbox start failed: ${err instanceof Error ? err.message : String(err)}`
135
+ });
136
+ this.setState("degraded");
137
+ throw err;
138
+ }
139
+ }
140
+ async recover() {
141
+ if (this.state !== "degraded") return;
142
+ this.setState("recovering");
143
+ this.emitEvent({
144
+ timestamp: Date.now(),
145
+ type: "state_change",
146
+ detail: "Attempting recovery from degraded state"
147
+ });
148
+ try {
149
+ const config = this.getMainContainerConfig();
150
+ await this.cleanupContainer(this.containerId);
151
+ await this.cleanupContainer(this.browserContainerId);
152
+ this.containerId = null;
153
+ this.browserContainerId = null;
154
+ const orphans = this.engine.listContainers(config.containerPrefix);
155
+ for (const id of orphans) {
156
+ await this.engine.stopContainer(id);
157
+ await this.engine.removeContainer(id);
158
+ }
159
+ this.containerId = await this.createMainContainer();
160
+ if (await this.healthCheck()) this.setState("ready");
161
+ else this.setState("degraded");
162
+ } catch (err) {
163
+ this.emitEvent({
164
+ timestamp: Date.now(),
165
+ type: "error",
166
+ detail: `Recovery failed: ${err instanceof Error ? err.message : String(err)}`
167
+ });
168
+ this.setState("degraded");
169
+ }
170
+ }
171
+ async stop() {
172
+ this.setState("stopping");
173
+ try {
174
+ await this.cleanupContainer(this.browserContainerId);
175
+ await this.cleanupContainer(this.containerId);
176
+ this.browserContainerId = null;
177
+ this.containerId = null;
178
+ } catch (err) {
179
+ this.emitEvent({
180
+ timestamp: Date.now(),
181
+ type: "error",
182
+ detail: `Sandbox stop error: ${err instanceof Error ? err.message : String(err)}`
183
+ });
184
+ }
185
+ this.setState("stopped");
186
+ }
187
+ async exec(options) {
188
+ const start = Date.now();
189
+ if (this.config.mode === "off" || this.config.mode === "light") return {
190
+ exitCode: 1,
191
+ stdout: "",
192
+ stderr: "Sandbox exec not available in current mode",
193
+ durationMs: Date.now() - start,
194
+ executedInSandbox: false
195
+ };
196
+ if (!this.containerId || this.state !== "ready") {
197
+ this.emitEvent({
198
+ timestamp: Date.now(),
199
+ type: "exec_denied",
200
+ detail: `Sandbox not ready (state=${this.state})`
201
+ });
202
+ return {
203
+ exitCode: 1,
204
+ stdout: "",
205
+ stderr: `Sandbox not ready (state=${this.state})`,
206
+ durationMs: Date.now() - start,
207
+ executedInSandbox: false
208
+ };
209
+ }
210
+ this.emitEvent({
211
+ timestamp: Date.now(),
212
+ type: "exec",
213
+ detail: options.command.substring(0, 200),
214
+ metadata: { workdir: options.workdir ?? this.config.workdir ?? "/workspace" }
215
+ });
216
+ try {
217
+ return {
218
+ ...await this.engine.execInContainer({
219
+ containerId: this.containerId,
220
+ command: options.command,
221
+ workdir: options.workdir,
222
+ env: options.env,
223
+ timeoutMs: options.timeoutMs,
224
+ stdin: options.stdin
225
+ }),
226
+ executedInSandbox: true
227
+ };
228
+ } catch (err) {
229
+ return {
230
+ exitCode: 1,
231
+ stdout: "",
232
+ stderr: `Exec error: ${err instanceof Error ? err.message : String(err)}`,
233
+ durationMs: Date.now() - start,
234
+ executedInSandbox: false
235
+ };
236
+ }
237
+ }
238
+ getBrowserCdpEndpoint() {
239
+ if (!this.browserContainerId) return null;
240
+ return `http://localhost:${this.config.browser?.cdpPort ?? 9222}`;
241
+ }
242
+ getBrowserWsEndpoint() {
243
+ if (!this.browserContainerId) return null;
244
+ return `ws://localhost:${this.config.browser?.cdpPort ?? 9222}`;
245
+ }
246
+ async createBrowserContainer() {
247
+ const name = `${this.config.containerPrefix}-browser-${Date.now()}`;
248
+ const cdpPort = this.config.browser?.cdpPort ?? 9222;
249
+ const vncPort = this.config.browser?.vncPort ?? 5900;
250
+ const image = this.config.browser?.image ?? "milady-sandbox-browser:bookworm-slim";
251
+ return this.engine.runContainer({
252
+ image,
253
+ name,
254
+ detach: true,
255
+ mounts: [],
256
+ env: {},
257
+ network: "bridge",
258
+ user: "1000:1000",
259
+ capDrop: [],
260
+ ports: [{
261
+ host: cdpPort,
262
+ container: 9222
263
+ }, {
264
+ host: vncPort,
265
+ container: 5900
266
+ }]
267
+ });
268
+ }
269
+ async healthCheck() {
270
+ if (!this.containerId) return false;
271
+ const healthy = await this.engine.healthCheck(this.containerId);
272
+ this.emitEvent({
273
+ timestamp: Date.now(),
274
+ type: "health_check",
275
+ detail: healthy ? "healthy" : "unhealthy"
276
+ });
277
+ return healthy;
278
+ }
279
+ emitEvent(event) {
280
+ this.eventLog.push(event);
281
+ if (this.eventLog.length > 1e3) this.eventLog = this.eventLog.slice(-500);
282
+ }
283
+ getEventLog() {
284
+ return [...this.eventLog];
285
+ }
286
+ getStatus() {
287
+ return {
288
+ state: this.state,
289
+ mode: this.config.mode,
290
+ containerId: this.containerId,
291
+ browserContainerId: this.browserContainerId
292
+ };
293
+ }
294
+ };
295
+
296
+ //#endregion
297
+ export { SandboxManager };
@@ -0,0 +1,175 @@
1
+ import { CHANNEL_DIST_TAGS } from "./update-checker.js";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+ import { execSync, spawn } from "node:child_process";
6
+
7
+ //#region src/services/self-updater.ts
8
+ /**
9
+ * Detects the installation method and runs the appropriate upgrade command.
10
+ * Falls back to npm if detection is ambiguous.
11
+ */
12
+ const NPM_PACKAGE_NAME = "miladyai";
13
+ function whichSync(binary) {
14
+ try {
15
+ return execSync(`which ${binary}`, {
16
+ stdio: [
17
+ "ignore",
18
+ "pipe",
19
+ "ignore"
20
+ ],
21
+ timeout: 5e3
22
+ }).toString().trim();
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+ function isLocalDev() {
28
+ try {
29
+ const rootPkg = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../package.json");
30
+ return JSON.parse(fs.readFileSync(rootPkg, "utf-8")).devDependencies !== void 0;
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
35
+ function detectInstallMethod() {
36
+ const miladyBin = whichSync("milady");
37
+ if (!miladyBin) return isLocalDev() ? "local-dev" : "unknown";
38
+ let resolved;
39
+ try {
40
+ resolved = fs.realpathSync(miladyBin);
41
+ } catch {
42
+ resolved = miladyBin;
43
+ }
44
+ if (resolved.includes("/Cellar/") || resolved.includes("/homebrew/")) return "homebrew";
45
+ if (resolved.includes("/snap/")) return "snap";
46
+ if (resolved.includes("/flatpak/") || resolved.includes("ai.milady.Milady")) return "flatpak";
47
+ if (resolved.startsWith("/usr/") && !resolved.includes("node_modules")) return "apt";
48
+ if (resolved.includes("/.bun/")) return "bun-global";
49
+ if (resolved.includes("node_modules")) return "npm-global";
50
+ return "unknown";
51
+ }
52
+ function buildUpdateCommand(method, channel) {
53
+ const spec = `${NPM_PACKAGE_NAME}@${CHANNEL_DIST_TAGS[channel]}`;
54
+ switch (method) {
55
+ case "npm-global": return {
56
+ command: "npm",
57
+ args: [
58
+ "install",
59
+ "-g",
60
+ spec
61
+ ]
62
+ };
63
+ case "bun-global": return {
64
+ command: "bun",
65
+ args: [
66
+ "install",
67
+ "-g",
68
+ spec
69
+ ]
70
+ };
71
+ case "homebrew": return {
72
+ command: "brew",
73
+ args: ["upgrade", "milady"]
74
+ };
75
+ case "snap": return {
76
+ command: "sudo",
77
+ args: [
78
+ "snap",
79
+ "refresh",
80
+ "milady",
81
+ `--channel=${channel === "nightly" ? "edge" : channel === "beta" ? "beta" : "stable"}`
82
+ ]
83
+ };
84
+ case "apt": return {
85
+ command: "sh",
86
+ args: ["-c", "sudo apt-get update && sudo apt-get install --only-upgrade -y milady"]
87
+ };
88
+ case "flatpak": return {
89
+ command: "flatpak",
90
+ args: ["update", "ai.milady.Milady"]
91
+ };
92
+ case "local-dev": return null;
93
+ case "unknown": return {
94
+ command: "npm",
95
+ args: [
96
+ "install",
97
+ "-g",
98
+ spec
99
+ ]
100
+ };
101
+ }
102
+ }
103
+ function runCommand(command, args) {
104
+ return new Promise((resolve) => {
105
+ const child = spawn(command, args, { stdio: [
106
+ "inherit",
107
+ "inherit",
108
+ "pipe"
109
+ ] });
110
+ let stderr = "";
111
+ child.stderr?.on("data", (chunk) => {
112
+ stderr += chunk.toString();
113
+ process.stderr.write(chunk);
114
+ });
115
+ child.on("error", (err) => {
116
+ resolve({
117
+ exitCode: 1,
118
+ stderr: err.message
119
+ });
120
+ });
121
+ child.on("close", (code) => {
122
+ resolve({
123
+ exitCode: code ?? 1,
124
+ stderr
125
+ });
126
+ });
127
+ });
128
+ }
129
+ function readPostUpdateVersion() {
130
+ try {
131
+ return execSync("milady --version", {
132
+ stdio: [
133
+ "ignore",
134
+ "pipe",
135
+ "ignore"
136
+ ],
137
+ timeout: 1e4
138
+ }).toString().trim().match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/)?.[1] ?? null;
139
+ } catch {
140
+ return null;
141
+ }
142
+ }
143
+ async function performUpdate(currentVersion, channel, method) {
144
+ method ??= detectInstallMethod();
145
+ const cmdInfo = buildUpdateCommand(method, channel);
146
+ if (!cmdInfo) return {
147
+ success: false,
148
+ method,
149
+ command: "",
150
+ previousVersion: currentVersion,
151
+ newVersion: null,
152
+ error: "Cannot auto-update a local development install. Use git pull instead."
153
+ };
154
+ const commandString = `${cmdInfo.command} ${cmdInfo.args.join(" ")}`;
155
+ const { exitCode, stderr } = await runCommand(cmdInfo.command, cmdInfo.args);
156
+ if (exitCode !== 0) return {
157
+ success: false,
158
+ method,
159
+ command: commandString,
160
+ previousVersion: currentVersion,
161
+ newVersion: null,
162
+ error: stderr || `Update command exited with code ${exitCode}.`
163
+ };
164
+ return {
165
+ success: true,
166
+ method,
167
+ command: commandString,
168
+ previousVersion: currentVersion,
169
+ newVersion: readPostUpdateVersion(),
170
+ error: null
171
+ };
172
+ }
173
+
174
+ //#endregion
175
+ export { detectInstallMethod, performUpdate };
@@ -0,0 +1,119 @@
1
+ import path from "node:path";
2
+ import { logger } from "@elizaos/core";
3
+ import { fileURLToPath } from "node:url";
4
+ import fs from "node:fs/promises";
5
+
6
+ //#region src/services/skill-catalog-client.ts
7
+ /**
8
+ * Skill Catalog Client for Milady.
9
+ *
10
+ * Provides a cached skill catalog (memory → file) sourced from the
11
+ * local skills/.cache/catalog.json. Supports search and browse.
12
+ *
13
+ * @module services/skill-catalog-client
14
+ */
15
+ let memoryCache = null;
16
+ const MEMORY_TTL_MS = 6e5;
17
+ /**
18
+ * Find the catalog.json file. Checks:
19
+ * 1. MILADY_SKILLS_CATALOG env override
20
+ * 2. skills/.cache/catalog.json relative to package root
21
+ * 3. ~/.milady/skills/catalog.json
22
+ */
23
+ function findCatalogPaths() {
24
+ const paths = [];
25
+ const envPath = process.env.MILADY_SKILLS_CATALOG?.trim();
26
+ if (envPath) return [envPath];
27
+ let dir = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url));
28
+ for (let i = 0; i < 5; i++) {
29
+ paths.push(path.join(dir, "skills", ".cache", "catalog.json"));
30
+ const parent = path.dirname(dir);
31
+ if (parent === dir) break;
32
+ dir = parent;
33
+ }
34
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
35
+ if (home) paths.push(path.join(home, ".milady", "skills", "catalog.json"));
36
+ return paths;
37
+ }
38
+ async function readCatalogFile() {
39
+ for (const catalogPath of findCatalogPaths()) try {
40
+ const raw = await fs.readFile(catalogPath, "utf-8");
41
+ const parsed = JSON.parse(raw);
42
+ if (Array.isArray(parsed.data) && parsed.data.length > 0) {
43
+ logger.debug(`[skill-catalog] Loaded ${parsed.data.length} skills from ${catalogPath}`);
44
+ return parsed.data;
45
+ }
46
+ } catch {}
47
+ return null;
48
+ }
49
+ /** Get all skills from the catalog. Resolution: memory → file. */
50
+ async function getCatalogSkills() {
51
+ if (memoryCache && Date.now() - memoryCache.loadedAt < MEMORY_TTL_MS) return memoryCache.skills;
52
+ const skills = await readCatalogFile();
53
+ if (!skills) {
54
+ logger.warn("[skill-catalog] No catalog file found");
55
+ return [];
56
+ }
57
+ memoryCache = {
58
+ skills,
59
+ loadedAt: Date.now()
60
+ };
61
+ return skills;
62
+ }
63
+ /** Force-refresh from file. */
64
+ async function refreshCatalog() {
65
+ memoryCache = null;
66
+ return getCatalogSkills();
67
+ }
68
+ /** Get a single skill by slug. */
69
+ async function getCatalogSkill(slug) {
70
+ return (await getCatalogSkills()).find((s) => s.slug === slug) ?? null;
71
+ }
72
+ /** Search skills by query (local fuzzy match on name/summary/slug). */
73
+ async function searchCatalogSkills(query, limit = 30) {
74
+ const skills = await getCatalogSkills();
75
+ const lq = query.toLowerCase();
76
+ const terms = lq.split(/\s+/).filter((t) => t.length > 1);
77
+ const scored = [];
78
+ for (const skill of skills) {
79
+ const slug = skill.slug.toLowerCase();
80
+ const name = (skill.displayName ?? "").toLowerCase();
81
+ const summary = (skill.summary ?? "").toLowerCase();
82
+ let score = 0;
83
+ if (slug === lq || name === lq) score += 100;
84
+ else if (slug.includes(lq)) score += 50;
85
+ else if (name.includes(lq)) score += 45;
86
+ if (summary.includes(lq)) score += 30;
87
+ for (const tag of Object.keys(skill.tags)) if (tag.toLowerCase().includes(lq)) score += 20;
88
+ for (const term of terms) {
89
+ if (slug.includes(term)) score += 15;
90
+ if (name.includes(term)) score += 12;
91
+ if (summary.includes(term)) score += 8;
92
+ }
93
+ if (score > 0) {
94
+ if (skill.stats.downloads > 50) score += 3;
95
+ if (skill.stats.downloads > 200) score += 3;
96
+ if (skill.stats.stars > 0) score += 2;
97
+ if (skill.stats.installsCurrent > 0) score += 2;
98
+ scored.push({
99
+ s: skill,
100
+ score
101
+ });
102
+ }
103
+ }
104
+ scored.sort((a, b) => b.score - a.score || b.s.stats.downloads - a.s.stats.downloads);
105
+ const max = scored[0]?.score || 1;
106
+ return scored.slice(0, limit).map(({ s, score }) => ({
107
+ slug: s.slug,
108
+ displayName: s.displayName,
109
+ summary: s.summary,
110
+ score: score / max,
111
+ latestVersion: s.latestVersion?.version ?? null,
112
+ downloads: s.stats.downloads,
113
+ stars: s.stats.stars,
114
+ installs: s.stats.installsAllTime
115
+ }));
116
+ }
117
+
118
+ //#endregion
119
+ export { getCatalogSkill, getCatalogSkills, refreshCatalog, searchCatalogSkills };