openbot 0.2.11 → 0.2.13

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 (141) hide show
  1. package/.prettierrc +8 -0
  2. package/AGENTS.md +68 -0
  3. package/CONTRIBUTING.md +74 -0
  4. package/LICENSE +21 -0
  5. package/README.md +117 -14
  6. package/dist/agents/system.js +106 -0
  7. package/dist/app/cli.js +27 -0
  8. package/dist/app/config.js +64 -0
  9. package/dist/app/server.js +237 -0
  10. package/dist/app/utils.js +35 -0
  11. package/dist/harness/agent-harness.js +45 -0
  12. package/dist/harness/mcp.js +61 -0
  13. package/dist/harness/orchestrator.js +273 -0
  14. package/dist/harness/process.js +7 -0
  15. package/dist/plugins/ai-sdk.js +141 -0
  16. package/dist/plugins/delegation.js +52 -0
  17. package/dist/plugins/mcp.js +140 -0
  18. package/dist/plugins/storage.js +502 -0
  19. package/dist/plugins/ui.js +47 -0
  20. package/dist/registry/plugins.js +73 -0
  21. package/dist/services/storage.js +724 -0
  22. package/docs/README.md +7 -0
  23. package/docs/agents.md +83 -0
  24. package/docs/architecture.md +34 -0
  25. package/docs/plugins.md +77 -0
  26. package/logo-black.png +0 -0
  27. package/{dist/assets/logo.js → logo-black.svg} +24 -24
  28. package/{dist/ui/sidebar.js → logo-white.svg} +23 -88
  29. package/package.json +10 -9
  30. package/src/agents/system.ts +112 -0
  31. package/src/app/cli.ts +38 -0
  32. package/src/app/config.ts +104 -0
  33. package/src/app/server.ts +284 -0
  34. package/src/app/types.ts +476 -0
  35. package/src/app/utils.ts +43 -0
  36. package/src/assets/icon.svg +1 -0
  37. package/src/harness/agent-harness.ts +58 -0
  38. package/src/harness/mcp.ts +78 -0
  39. package/src/harness/orchestrator.ts +342 -0
  40. package/src/harness/process.ts +9 -0
  41. package/src/harness/types.ts +34 -0
  42. package/src/plugins/ai-sdk.ts +197 -0
  43. package/src/plugins/delegation.ts +60 -0
  44. package/src/plugins/mcp.ts +154 -0
  45. package/src/plugins/storage.ts +725 -0
  46. package/src/plugins/ui.ts +57 -0
  47. package/src/registry/plugins.ts +85 -0
  48. package/src/services/storage.ts +957 -0
  49. package/tsconfig.json +18 -0
  50. package/dist/agents/agent-creator.js +0 -74
  51. package/dist/agents/browser-agent.js +0 -31
  52. package/dist/agents/os-agent.js +0 -32
  53. package/dist/agents/planner-agent.js +0 -32
  54. package/dist/agents/topic-agent.js +0 -46
  55. package/dist/architecture/execution-engine.js +0 -151
  56. package/dist/architecture/intent-classifier.js +0 -26
  57. package/dist/architecture/planner.js +0 -106
  58. package/dist/automation-worker.js +0 -121
  59. package/dist/automations.js +0 -52
  60. package/dist/cli.js +0 -275
  61. package/dist/config.js +0 -53
  62. package/dist/core/agents.js +0 -41
  63. package/dist/core/delegation.js +0 -230
  64. package/dist/core/manager.js +0 -96
  65. package/dist/core/plugins.js +0 -74
  66. package/dist/core/router.js +0 -191
  67. package/dist/handlers/init.js +0 -29
  68. package/dist/handlers/session-change.js +0 -21
  69. package/dist/handlers/settings.js +0 -47
  70. package/dist/handlers/tab-change.js +0 -14
  71. package/dist/installers.js +0 -156
  72. package/dist/marketplace.js +0 -80
  73. package/dist/model-catalog.js +0 -132
  74. package/dist/model-defaults.js +0 -25
  75. package/dist/models.js +0 -47
  76. package/dist/open-bot.js +0 -51
  77. package/dist/orchestrator/direct-invocation.js +0 -13
  78. package/dist/orchestrator/events.js +0 -36
  79. package/dist/orchestrator/state.js +0 -54
  80. package/dist/orchestrator.js +0 -422
  81. package/dist/plugins/agent/index.js +0 -81
  82. package/dist/plugins/approval/index.js +0 -100
  83. package/dist/plugins/brain/identity.js +0 -77
  84. package/dist/plugins/brain/index.js +0 -204
  85. package/dist/plugins/brain/memory.js +0 -120
  86. package/dist/plugins/brain/prompt.js +0 -46
  87. package/dist/plugins/brain/types.js +0 -45
  88. package/dist/plugins/brain/ui.js +0 -7
  89. package/dist/plugins/browser/index.js +0 -629
  90. package/dist/plugins/browser/ui.js +0 -13
  91. package/dist/plugins/file-system/index.js +0 -171
  92. package/dist/plugins/file-system/ui.js +0 -6
  93. package/dist/plugins/llm/context-budget.js +0 -139
  94. package/dist/plugins/llm/context-shaping.js +0 -177
  95. package/dist/plugins/llm/index.js +0 -380
  96. package/dist/plugins/memory/index.js +0 -220
  97. package/dist/plugins/memory/memory.js +0 -122
  98. package/dist/plugins/memory/prompt.js +0 -55
  99. package/dist/plugins/memory/types.js +0 -45
  100. package/dist/plugins/meta-agent/index.js +0 -570
  101. package/dist/plugins/meta-agent/ui.js +0 -11
  102. package/dist/plugins/shell/index.js +0 -100
  103. package/dist/plugins/shell/ui.js +0 -6
  104. package/dist/plugins/skills/index.js +0 -286
  105. package/dist/plugins/skills/types.js +0 -50
  106. package/dist/plugins/skills/ui.js +0 -12
  107. package/dist/registry/agent-registry.js +0 -35
  108. package/dist/registry/index.js +0 -2
  109. package/dist/registry/plugin-loader.js +0 -499
  110. package/dist/registry/plugin-registry.js +0 -44
  111. package/dist/registry/ts-agent-loader.js +0 -82
  112. package/dist/registry/yaml-agent-loader.js +0 -246
  113. package/dist/runtime/execution-trace.js +0 -41
  114. package/dist/runtime/intent-routing.js +0 -26
  115. package/dist/runtime/openbot-runtime.js +0 -354
  116. package/dist/server.js +0 -890
  117. package/dist/session.js +0 -179
  118. package/dist/ui/block.js +0 -12
  119. package/dist/ui/header.js +0 -52
  120. package/dist/ui/layout.js +0 -26
  121. package/dist/ui/navigation.js +0 -15
  122. package/dist/ui/settings.js +0 -106
  123. package/dist/ui/skills.js +0 -7
  124. package/dist/ui/thread.js +0 -16
  125. package/dist/ui/widgets/action-list.js +0 -2
  126. package/dist/ui/widgets/approval-card.js +0 -9
  127. package/dist/ui/widgets/code-snippet.js +0 -2
  128. package/dist/ui/widgets/data-block.js +0 -2
  129. package/dist/ui/widgets/data-table.js +0 -2
  130. package/dist/ui/widgets/delegation.js +0 -29
  131. package/dist/ui/widgets/empty-state.js +0 -2
  132. package/dist/ui/widgets/index.js +0 -23
  133. package/dist/ui/widgets/inquiry.js +0 -7
  134. package/dist/ui/widgets/key-value.js +0 -2
  135. package/dist/ui/widgets/progress-step.js +0 -2
  136. package/dist/ui/widgets/resource-card.js +0 -2
  137. package/dist/ui/widgets/status.js +0 -2
  138. package/dist/ui/widgets/todo-list.js +0 -2
  139. package/dist/version.js +0 -62
  140. /package/dist/{types.js → app/types.js} +0 -0
  141. /package/dist/{architecture/contracts.js → harness/types.js} +0 -0
@@ -1,570 +0,0 @@
1
- import { z } from "zod";
2
- import * as fs from "node:fs/promises";
3
- import * as path from "node:path";
4
- import matter from "gray-matter";
5
- // Tool definitions for the meta-agent capabilities
6
- export const metaAgentToolDefinitions = {
7
- loadSkill: {
8
- description: "Load a skill's full instructions when you need to use it. Call this before executing a skill.",
9
- inputSchema: z.object({
10
- skillId: z.string().describe("The skill folder name (e.g., 'code-review')"),
11
- }),
12
- },
13
- createSkill: {
14
- description: "Create a new skill from learned knowledge. Use when you discover a reusable pattern.",
15
- inputSchema: z.object({
16
- id: z.string().describe("Skill folder name in kebab-case (e.g., 'web-search')"),
17
- title: z.string().describe("Human-readable skill title"),
18
- description: z.string().describe("Brief description of what the skill does"),
19
- content: z.string().describe("Full skill instructions in markdown"),
20
- }),
21
- },
22
- updateSkill: {
23
- description: "Update an existing skill with new knowledge or improvements.",
24
- inputSchema: z.object({
25
- id: z.string().describe("The skill folder name (e.g., 'code-review')"),
26
- title: z.string().optional().describe("New title for the skill"),
27
- description: z.string().optional().describe("New description for the skill"),
28
- content: z.string().describe("Updated full skill instructions in markdown"),
29
- }),
30
- },
31
- listSkills: {
32
- description: "List all available skills with their metadata",
33
- inputSchema: z.object({}),
34
- },
35
- updateIdentity: {
36
- description: "Update your identity file to refine your personality and traits",
37
- inputSchema: z.object({
38
- content: z.string().describe("New content for IDENTITY.md"),
39
- }),
40
- },
41
- readIdentity: {
42
- description: "Read your current identity or soul configuration",
43
- inputSchema: z.object({
44
- file: z.enum(["IDENTITY.md", "SOUL.md"]).describe("Which identity file to read"),
45
- }),
46
- },
47
- appendToMemory: {
48
- description: "Add a fact or note to your long-term memory",
49
- inputSchema: z.object({
50
- category: z.enum(["facts", "journal"]).describe("Memory category"),
51
- content: z.string().describe("Content to append"),
52
- }),
53
- },
54
- };
55
- // Default content for identity files
56
- const DEFAULT_SOUL = `# Soul
57
-
58
- ## Core Values
59
- - Be helpful, honest, and harmless
60
- - Respect user privacy and data
61
- - Learn and improve continuously
62
- - Be transparent about capabilities and limitations
63
-
64
- ## Ethical Guidelines
65
- - Never assist with harmful or illegal activities
66
- - Protect sensitive information
67
- - Acknowledge uncertainty when unsure
68
- - Prioritize user well-being
69
- `;
70
- const DEFAULT_IDENTITY = `# Identity
71
-
72
- I am OpenBot, a self-evolving AI assistant built on the OpenBot framework.
73
-
74
- ## Personality
75
- - Friendly and approachable
76
- - Technically competent
77
- - Eager to learn and adapt
78
-
79
- ## Capabilities
80
- - Shell command execution
81
- - File system operations
82
- - Skill-based task execution
83
- - Self-modification and learning
84
- `;
85
- /**
86
- * Expand ~ to home directory
87
- */
88
- function expandPath(p) {
89
- if (p.startsWith("~/")) {
90
- return path.join(process.env.HOME || "", p.slice(2));
91
- }
92
- return p;
93
- }
94
- /**
95
- * Truncate a markdown file by keeping the header and the last N entries (separated by ##)
96
- */
97
- function truncateToRecent(content, limit = 10) {
98
- const parts = content.split(/\n(?=## )/);
99
- if (parts.length <= limit + 1)
100
- return content.trim();
101
- const header = parts[0].trim();
102
- const recent = parts.slice(-limit).map((p) => p.trim());
103
- return `${header}\n\n*... (older entries truncated) ...*\n\n${recent.join("\n\n")}`;
104
- }
105
- /**
106
- * Build the dynamic system prompt from identity files and skills
107
- */
108
- export async function buildSystemPrompt(baseDir, context) {
109
- const expandedBase = expandPath(baseDir);
110
- const parts = [];
111
- const state = context?.state;
112
- const currentCwd = state?.cwd || process.cwd();
113
- // Add environment context
114
- const now = new Date();
115
- parts.push(`## Environment
116
- You are running as a global system agent.
117
- - **Current Time**: ${now.toLocaleString()} (${Intl.DateTimeFormat().resolvedOptions().timeZone})
118
- - **Current Working Directory (CWD)**: ${currentCwd}
119
- - **System Access**: You have access to the entire file system (root: /).
120
- - **Bot Home (Internal State)**: ${expandedBase}
121
-
122
- ### Path Rules:
123
- 1. **Shell Commands**: All commands (executeCommand) run in the CWD: ${currentCwd}.
124
- 2. **File Operations**: Relative paths in readFile, writeFile, listFiles, etc. resolve against the CWD.
125
- 3. **Changing Directory**: Use \`cd <path>\` in executeCommand to move. Your CWD is persisted across turns.
126
- 4. **Skills/Memory**: To access your own skills and memory, use absolute paths starting with "${expandedBase}/".
127
-
128
- When you want to execute skill scripts, always use the full path to the skill directory. For example, if the skill is at "${expandedBase}/skills/my-skill", the full path to the script is "${expandedBase}/skills/my-skill/scripts/script.sh".`);
129
- // Load SOUL.md
130
- try {
131
- const soul = await fs.readFile(path.join(expandedBase, "SOUL.md"), "utf-8");
132
- parts.push(soul.trim());
133
- }
134
- catch {
135
- // File doesn't exist yet
136
- }
137
- // Load IDENTITY.md
138
- try {
139
- const identity = await fs.readFile(path.join(expandedBase, "IDENTITY.md"), "utf-8");
140
- parts.push(identity.trim());
141
- }
142
- catch {
143
- // File doesn't exist yet
144
- }
145
- // Load Memory (Facts and Journal)
146
- const memoryParts = [];
147
- try {
148
- const facts = await fs.readFile(path.join(expandedBase, "memory/facts.md"), "utf-8");
149
- if (facts.trim().length > 0) {
150
- memoryParts.push(`### Facts\n${truncateToRecent(facts, 10)}`);
151
- }
152
- }
153
- catch { }
154
- try {
155
- const journal = await fs.readFile(path.join(expandedBase, "memory/journal.md"), "utf-8");
156
- if (journal.trim().length > 0) {
157
- memoryParts.push(`### Journal\n${truncateToRecent(journal, 10)}`);
158
- }
159
- }
160
- catch { }
161
- if (memoryParts.length > 0) {
162
- parts.push(`## Memory\n\nRefer to these facts and notes to provide personalized and context-aware responses.\n\n${memoryParts.join("\n\n")}`);
163
- }
164
- // Scan skills and build index
165
- const skillsDir = path.join(expandedBase, "skills");
166
- const skillsIndex = [];
167
- try {
168
- const skillFolders = await fs.readdir(skillsDir);
169
- for (const folder of skillFolders) {
170
- if (folder.startsWith("_") || folder.startsWith("."))
171
- continue;
172
- const skillPath = path.join(skillsDir, folder, "SKILL.md");
173
- try {
174
- const content = await fs.readFile(skillPath, "utf-8");
175
- const { data } = matter(content);
176
- skillsIndex.push({
177
- id: folder,
178
- title: data.title || folder,
179
- description: data.description || "No description",
180
- version: data.version,
181
- tools: data.tools,
182
- triggers: data.triggers,
183
- });
184
- }
185
- catch {
186
- // Skill doesn't have a valid SKILL.md
187
- }
188
- }
189
- }
190
- catch {
191
- // Skills directory doesn't exist yet
192
- }
193
- // Add skills section
194
- if (skillsIndex.length > 0) {
195
- parts.push(`## Available Skills
196
-
197
- You have the following skills available. Use \`loadSkill\` with the skill id to get full instructions before executing.
198
-
199
- ${skillsIndex.map((s) => `- **${s.title}** (\`${s.id}\`): ${s.description}`).join("\n")}`);
200
- }
201
- else {
202
- parts.push(`## Skills
203
-
204
- You have no skills yet. When you learn reusable patterns, create skills using \`createSkill\` so you can use them again later.`);
205
- }
206
- // Add self-modification instructions
207
- parts.push(`## Self-Modification
208
-
209
- You can evolve and improve yourself:
210
- - Use \`updateIdentity\` to refine your personality in IDENTITY.md
211
- - Use \`createSkill\` to save reusable patterns as skills
212
- - Use \`updateSkill\` to improve or expand existing skills with new knowledge
213
- - Use \`appendToMemory\` to remember important facts or journal your learnings
214
- - SOUL.md contains your core values and is protected from modification`);
215
- return parts.join("\n\n");
216
- }
217
- /**
218
- * Meta-Agent Plugin for Melony
219
- * Provides self-modification, skill management, and identity persistence
220
- */
221
- export const metaAgentPlugin = (options) => (builder) => {
222
- const { baseDir, allowSoulModification = false } = options;
223
- const expandedBase = expandPath(baseDir);
224
- const resolvePath = (p) => path.join(expandedBase, p);
225
- // Ensure directory structure exists
226
- const ensureStructure = async () => {
227
- // Ensure base directory exists with restricted permissions (0o700)
228
- await fs.mkdir(expandedBase, { recursive: true, mode: 0o700 });
229
- await fs.mkdir(resolvePath("skills"), { recursive: true });
230
- await fs.mkdir(resolvePath("memory"), { recursive: true });
231
- // Create default files if they don't exist
232
- const defaults = {
233
- "SOUL.md": DEFAULT_SOUL,
234
- "IDENTITY.md": DEFAULT_IDENTITY,
235
- "memory/facts.md": "# Facts\n\nLearned facts about the user and environment:\n",
236
- "memory/journal.md": "# Journal\n\nSession notes and learnings:\n",
237
- };
238
- for (const [file, content] of Object.entries(defaults)) {
239
- const filePath = resolvePath(file);
240
- try {
241
- await fs.access(filePath);
242
- }
243
- catch {
244
- await fs.mkdir(path.dirname(filePath), { recursive: true });
245
- await fs.writeFile(filePath, content, "utf-8");
246
- }
247
- }
248
- };
249
- // Initialize on the "init" event
250
- builder.on("init", async function* (event, context) {
251
- yield {
252
- type: "meta:status",
253
- data: { message: "Initializing meta-agent structure..." },
254
- };
255
- await ensureStructure();
256
- const systemPrompt = await buildSystemPrompt(baseDir, context);
257
- yield {
258
- type: "meta:initialized",
259
- data: {
260
- baseDir: expandedBase,
261
- systemPrompt,
262
- },
263
- };
264
- yield {
265
- type: "meta:status",
266
- data: { message: "Meta-agent initialized", severity: "success" },
267
- };
268
- });
269
- // Load a skill's full content
270
- builder.on("action:loadSkill", async function* (event) {
271
- const { skillId, toolCallId } = event.data;
272
- const skillPath = resolvePath(`skills/${skillId}/SKILL.md`);
273
- try {
274
- const content = await fs.readFile(skillPath, "utf-8");
275
- const { data, content: body } = matter(content);
276
- yield {
277
- type: "meta:skill-loaded",
278
- data: { skillId, title: data.title || skillId, instructions: data.description || "No description" },
279
- };
280
- yield {
281
- type: "action:result",
282
- data: {
283
- action: "loadSkill",
284
- toolCallId,
285
- result: {
286
- id: skillId,
287
- meta: data,
288
- instructions: body.trim(),
289
- },
290
- },
291
- };
292
- }
293
- catch (error) {
294
- yield {
295
- type: "action:result",
296
- data: {
297
- action: "loadSkill",
298
- toolCallId,
299
- result: { error: `Skill "${skillId}" not found` },
300
- },
301
- };
302
- }
303
- });
304
- // List all available skills
305
- builder.on("action:listSkills", async function* (event) {
306
- const { toolCallId } = event.data;
307
- const skillsDir = resolvePath("skills");
308
- const skills = [];
309
- try {
310
- const folders = await fs.readdir(skillsDir);
311
- for (const folder of folders) {
312
- if (folder.startsWith("_") || folder.startsWith("."))
313
- continue;
314
- const skillPath = path.join(skillsDir, folder, "SKILL.md");
315
- try {
316
- const content = await fs.readFile(skillPath, "utf-8");
317
- const { data } = matter(content);
318
- skills.push({
319
- id: folder,
320
- title: data.title || folder,
321
- description: data.description || "No description",
322
- version: data.version,
323
- tools: data.tools,
324
- triggers: data.triggers,
325
- });
326
- }
327
- catch {
328
- // Invalid skill, skip
329
- }
330
- }
331
- }
332
- catch {
333
- // Skills directory doesn't exist
334
- }
335
- yield {
336
- type: "action:result",
337
- data: {
338
- action: "listSkills",
339
- toolCallId,
340
- result: { skills },
341
- },
342
- };
343
- });
344
- // Create a new skill
345
- builder.on("action:createSkill", async function* (event) {
346
- const { id, title, description, content, toolCallId } = event.data;
347
- // Validate skill id (kebab-case)
348
- if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(id)) {
349
- yield {
350
- type: "action:result",
351
- data: {
352
- action: "createSkill",
353
- toolCallId,
354
- result: { error: "Skill id must be kebab-case (e.g., 'my-skill')" },
355
- },
356
- };
357
- return;
358
- }
359
- try {
360
- const skillDir = resolvePath(`skills/${id}`);
361
- await fs.mkdir(skillDir, { recursive: true });
362
- // Build SKILL.md with frontmatter
363
- const skillContent = `---
364
- title: ${title}
365
- description: ${description}
366
- version: 1.0.0
367
- createdAt: ${new Date().toISOString()}
368
- ---
369
-
370
- ${content}`;
371
- await fs.writeFile(path.join(skillDir, "SKILL.md"), skillContent, "utf-8");
372
- yield {
373
- type: "meta:status",
374
- data: { message: `Skill "${title}" created`, severity: "success" },
375
- };
376
- yield {
377
- type: "action:result",
378
- data: {
379
- action: "createSkill",
380
- toolCallId,
381
- result: {
382
- success: true,
383
- path: `skills/${id}/SKILL.md`,
384
- message: `Skill "${title}" created successfully`,
385
- },
386
- },
387
- };
388
- }
389
- catch (error) {
390
- yield {
391
- type: "meta:status",
392
- data: { message: `Failed to create skill: ${error.message}`, severity: "error" },
393
- };
394
- yield {
395
- type: "action:result",
396
- data: {
397
- action: "createSkill",
398
- toolCallId,
399
- result: { error: error.message },
400
- },
401
- };
402
- }
403
- });
404
- // Update an existing skill
405
- builder.on("action:updateSkill", async function* (event) {
406
- const { id, title, description, content, toolCallId } = event.data;
407
- const skillDir = resolvePath(`skills/${id}`);
408
- const skillPath = path.join(skillDir, "SKILL.md");
409
- try {
410
- // Check if skill exists
411
- await fs.access(skillPath);
412
- // Read existing skill to get metadata if not provided
413
- const existingContent = await fs.readFile(skillPath, "utf-8");
414
- const { data: existingData } = matter(existingContent);
415
- const newTitle = title || existingData.title || id;
416
- const newDescription = description || existingData.description || "No description";
417
- // Basic versioning: bump patch version
418
- let version = existingData.version || "1.0.0";
419
- const parts = version.split(".");
420
- if (parts.length === 3) {
421
- parts[2] = (parseInt(parts[2]) + 1).toString();
422
- version = parts.join(".");
423
- }
424
- // Build updated SKILL.md
425
- const skillContent = `---
426
- title: ${newTitle}
427
- description: ${newDescription}
428
- version: ${version}
429
- updatedAt: ${new Date().toISOString()}
430
- createdAt: ${existingData.createdAt || new Date().toISOString()}
431
- ---
432
-
433
- ${content}`;
434
- await fs.writeFile(skillPath, skillContent, "utf-8");
435
- yield {
436
- type: "meta:status",
437
- data: { message: `Skill "${newTitle}" updated to v${version}`, severity: "success" },
438
- };
439
- yield {
440
- type: "action:result",
441
- data: {
442
- action: "updateSkill",
443
- toolCallId,
444
- result: {
445
- success: true,
446
- path: `skills/${id}/SKILL.md`,
447
- version,
448
- message: `Skill "${newTitle}" updated to version ${version}`,
449
- },
450
- },
451
- };
452
- }
453
- catch (error) {
454
- const errorMsg = error.code === "ENOENT" ? `Skill "${id}" does not exist` : error.message;
455
- yield {
456
- type: "meta:status",
457
- data: { message: `Failed to update skill: ${errorMsg}`, severity: "error" },
458
- };
459
- yield {
460
- type: "action:result",
461
- data: {
462
- action: "updateSkill",
463
- toolCallId,
464
- result: { error: errorMsg },
465
- },
466
- };
467
- }
468
- });
469
- // Update identity
470
- builder.on("action:updateIdentity", async function* (event) {
471
- const { content, toolCallId } = event.data;
472
- try {
473
- await fs.writeFile(resolvePath("IDENTITY.md"), content, "utf-8");
474
- yield {
475
- type: "meta:status",
476
- data: { message: "Identity updated", severity: "success" },
477
- };
478
- yield {
479
- type: "action:result",
480
- data: {
481
- action: "updateIdentity",
482
- toolCallId,
483
- result: {
484
- success: true,
485
- message: "Identity updated. Changes will take effect on next initialization.",
486
- },
487
- },
488
- };
489
- }
490
- catch (error) {
491
- yield {
492
- type: "meta:status",
493
- data: { message: `Failed to update identity: ${error.message}`, severity: "error" },
494
- };
495
- yield {
496
- type: "action:result",
497
- data: {
498
- action: "updateIdentity",
499
- toolCallId,
500
- result: { error: error.message },
501
- },
502
- };
503
- }
504
- });
505
- // Read identity files
506
- builder.on("action:readIdentity", async function* (event) {
507
- const { file, toolCallId } = event.data;
508
- try {
509
- const content = await fs.readFile(resolvePath(file), "utf-8");
510
- yield {
511
- type: "action:result",
512
- data: {
513
- action: "readIdentity",
514
- toolCallId,
515
- result: { file, content },
516
- },
517
- };
518
- }
519
- catch (error) {
520
- yield {
521
- type: "action:result",
522
- data: {
523
- action: "readIdentity",
524
- toolCallId,
525
- result: { error: `Could not read ${file}: ${error.message}` },
526
- },
527
- };
528
- }
529
- });
530
- // Append to memory
531
- builder.on("action:appendToMemory", async function* (event) {
532
- const { category, content, toolCallId } = event.data;
533
- const memoryFile = resolvePath(`memory/${category}.md`);
534
- try {
535
- const timestamp = new Date().toISOString();
536
- const entry = `\n## ${timestamp}\n${content}\n`;
537
- await fs.appendFile(memoryFile, entry, "utf-8");
538
- yield {
539
- type: "meta:status",
540
- data: { message: `Added to ${category} memory`, severity: "success" },
541
- };
542
- yield {
543
- type: "action:result",
544
- data: {
545
- action: "appendToMemory",
546
- toolCallId,
547
- result: {
548
- success: true,
549
- message: `Added to ${category} memory`,
550
- },
551
- },
552
- };
553
- }
554
- catch (error) {
555
- yield {
556
- type: "meta:status",
557
- data: { message: `Failed to append to memory: ${error.message}`, severity: "error" },
558
- };
559
- yield {
560
- type: "action:result",
561
- data: {
562
- action: "appendToMemory",
563
- toolCallId,
564
- result: { error: error.message },
565
- },
566
- };
567
- }
568
- });
569
- };
570
- export default metaAgentPlugin;
@@ -1,11 +0,0 @@
1
- import { ui } from "@melony/ui-kit/server";
2
- export const metaAgentUIPlugin = () => (builder) => {
3
- builder.on("meta:status", async function* (event) {
4
- yield ui.event(ui.status(event.data.message, event.data.severity));
5
- });
6
- builder.on("meta:skill-loaded", async function* (event) {
7
- yield ui.event(ui.resourceCard(event.data.title, '', [
8
- ui.text(event.data.instructions),
9
- ]));
10
- });
11
- };
@@ -1,100 +0,0 @@
1
- import { uiEvent } from "../../ui/block.js";
2
- import { z } from "zod";
3
- import { exec } from "node:child_process";
4
- import { promisify } from "node:util";
5
- import * as path from "node:path";
6
- import { statusWidget } from "../../ui/widgets/status.js";
7
- const execAsync = promisify(exec);
8
- export const shellToolDefinitions = {
9
- executeCommand: {
10
- description: "Execute a shell command. Use 'cd' to change the current working directory for subsequent commands.",
11
- inputSchema: z.object({
12
- command: z.string().describe("The shell command to execute"),
13
- }),
14
- },
15
- };
16
- /**
17
- * Truncates a string by keeping the first and last N characters.
18
- */
19
- function truncate(str, maxChars) {
20
- if (!str || str.length <= maxChars)
21
- return str;
22
- const half = Math.floor(maxChars / 2);
23
- const truncatedCount = str.length - maxChars;
24
- return `${str.slice(0, half)}\n\n[... ${truncatedCount} characters truncated ...]\n\n${str.slice(-half)}`;
25
- }
26
- export const shellPlugin = (options = {}) => (builder) => {
27
- const { cwd = process.cwd(), env = process.env, maxOutputLength = 10000 } = options;
28
- builder.on("action:executeCommand", async function* (event, { state }) {
29
- const { command, toolCallId } = event.data;
30
- const currentCwd = state.cwd || cwd;
31
- yield {
32
- type: "shell:status",
33
- data: { message: `Executing command: ${command} in ${currentCwd}` }
34
- };
35
- // Basic 'cd' detection and state update
36
- if (command.trim().startsWith("cd ")) {
37
- const targetDir = command.trim().slice(3).trim();
38
- const newCwd = path.resolve(currentCwd, targetDir);
39
- state.cwd = newCwd;
40
- yield {
41
- type: "shell:status",
42
- data: { message: `Directory changed to ${newCwd}`, severity: "success" }
43
- };
44
- yield {
45
- type: "action:result",
46
- data: {
47
- action: "executeCommand",
48
- toolCallId,
49
- result: {
50
- stdout: `Changed directory to ${newCwd}`,
51
- stderr: "",
52
- success: true
53
- },
54
- },
55
- };
56
- return;
57
- }
58
- try {
59
- const { stdout, stderr } = await execAsync(command, { cwd: currentCwd, env });
60
- yield {
61
- type: "shell:status",
62
- data: { message: `Command executed successfully`, severity: "success" }
63
- };
64
- yield {
65
- type: "action:result",
66
- data: {
67
- action: "executeCommand",
68
- toolCallId,
69
- result: {
70
- stdout: truncate(stdout, maxOutputLength),
71
- stderr: truncate(stderr, maxOutputLength),
72
- success: true
73
- },
74
- },
75
- };
76
- }
77
- catch (error) {
78
- yield {
79
- type: "action:result",
80
- data: {
81
- action: "executeCommand",
82
- toolCallId,
83
- result: {
84
- error: error.message,
85
- stdout: truncate(error.stdout, maxOutputLength),
86
- stderr: truncate(error.stderr, maxOutputLength),
87
- success: false,
88
- },
89
- },
90
- };
91
- yield {
92
- type: "shell:status",
93
- data: { message: `Command failed: ${error.message}`, severity: "error" }
94
- };
95
- }
96
- });
97
- builder.on("shell:status", async function* (event) {
98
- yield uiEvent(statusWidget(event.data.message, event.data.severity));
99
- });
100
- };
@@ -1,6 +0,0 @@
1
- import { ui } from "@melony/ui-kit/server";
2
- export const shellUIPlugin = () => (builder) => {
3
- builder.on("shell:status", async function* (event) {
4
- yield ui.event(ui.status(event.data.message, event.data.severity));
5
- });
6
- };