morpheus-cli 0.9.4 → 0.9.6

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 (76) hide show
  1. package/README.md +63 -43
  2. package/dist/channels/discord.js +3 -6
  3. package/dist/channels/telegram.js +3 -6
  4. package/dist/cli/commands/restart.js +15 -0
  5. package/dist/cli/commands/start.js +16 -0
  6. package/dist/config/manager.js +61 -0
  7. package/dist/config/paths.js +1 -0
  8. package/dist/config/schemas.js +11 -3
  9. package/dist/http/api.js +3 -0
  10. package/dist/http/routers/link.js +239 -0
  11. package/dist/http/routers/skills.js +1 -8
  12. package/dist/http/routers/smiths.js +14 -4
  13. package/dist/runtime/apoc.js +1 -1
  14. package/dist/runtime/audit/repository.js +1 -1
  15. package/dist/runtime/link-chunker.js +214 -0
  16. package/dist/runtime/link-repository.js +301 -0
  17. package/dist/runtime/link-search.js +298 -0
  18. package/dist/runtime/link-worker.js +284 -0
  19. package/dist/runtime/link.js +295 -0
  20. package/dist/runtime/memory/sati/service.js +1 -1
  21. package/dist/runtime/neo.js +1 -1
  22. package/dist/runtime/oracle.js +81 -44
  23. package/dist/runtime/scaffold.js +4 -17
  24. package/dist/runtime/skills/__tests__/loader.test.js +7 -10
  25. package/dist/runtime/skills/__tests__/registry.test.js +2 -18
  26. package/dist/runtime/skills/__tests__/tool.test.js +55 -224
  27. package/dist/runtime/skills/index.js +1 -2
  28. package/dist/runtime/skills/loader.js +0 -2
  29. package/dist/runtime/skills/registry.js +8 -20
  30. package/dist/runtime/skills/schema.js +0 -4
  31. package/dist/runtime/skills/tool.js +42 -209
  32. package/dist/runtime/smiths/delegator.js +1 -1
  33. package/dist/runtime/smiths/registry.js +1 -1
  34. package/dist/runtime/tasks/worker.js +12 -44
  35. package/dist/runtime/trinity.js +1 -1
  36. package/dist/types/config.js +14 -0
  37. package/dist/ui/assets/AuditDashboard-93LCGHG1.js +1 -0
  38. package/dist/ui/assets/{Chat-5AeRYuRj.js → Chat-CK5sNcQ1.js} +8 -8
  39. package/dist/ui/assets/{Chronos-BrKldYVw.js → Chronos-m2h--GEe.js} +1 -1
  40. package/dist/ui/assets/{ConfirmationModal-DsbS3XkJ.js → ConfirmationModal-Dd5pUJme.js} +1 -1
  41. package/dist/ui/assets/{Dashboard-DvrTXLdo.js → Dashboard-ODwl7d-a.js} +1 -1
  42. package/dist/ui/assets/{DeleteConfirmationModal-BfSjv04R.js → DeleteConfirmationModal-CCcojDmr.js} +1 -1
  43. package/dist/ui/assets/Documents-dWnSoxFO.js +7 -0
  44. package/dist/ui/assets/{Logs-B0ZYWs5x.js → Logs-Dc9Z2LBj.js} +1 -1
  45. package/dist/ui/assets/{MCPManager-BwHGTeNs.js → MCPManager-CMkb8vMn.js} +1 -1
  46. package/dist/ui/assets/{ModelPricing-CYhGRQr8.js → ModelPricing-DtHPPbEQ.js} +1 -1
  47. package/dist/ui/assets/{Notifications-BYMAtVMq.js → Notifications-BPvo-DWP.js} +1 -1
  48. package/dist/ui/assets/{Pagination-oTGieBLM.js → Pagination-BHZKk42X.js} +1 -1
  49. package/dist/ui/assets/{SatiMemories-I1vsYtP2.js → SatiMemories-BUPu1Lxr.js} +1 -1
  50. package/dist/ui/assets/SessionAudit-CFKF4DA8.js +9 -0
  51. package/dist/ui/assets/Settings-C4JrXfsR.js +47 -0
  52. package/dist/ui/assets/{Skills-lGU3I5DO.js → Skills-BUlvJgJ4.js} +1 -1
  53. package/dist/ui/assets/Smiths-CDtJdY0I.js +1 -0
  54. package/dist/ui/assets/{Tasks-Bz92GPWK.js → Tasks-DK_cOsNK.js} +1 -1
  55. package/dist/ui/assets/{TrinityDatabases-BUY-3j7Q.js → TrinityDatabases-X07by-19.js} +1 -1
  56. package/dist/ui/assets/{UsageStats-Dr5eSgJc.js → UsageStats-dYcgckLq.js} +1 -1
  57. package/dist/ui/assets/{WebhookManager-DIASAC-1.js → WebhookManager-DDw5eX2R.js} +1 -1
  58. package/dist/ui/assets/{audit-CcAEDbZh.js → audit-DZ5WLUEm.js} +1 -1
  59. package/dist/ui/assets/{chronos-2Z9E96_1.js → chronos-B_HI4mlq.js} +1 -1
  60. package/dist/ui/assets/{config-DdfK4DX6.js → config-B-YxlVrc.js} +1 -1
  61. package/dist/ui/assets/index-DVjwJ8jT.css +1 -0
  62. package/dist/ui/assets/{index-Dpd1Mkgp.js → index-DfJwcKqG.js} +5 -5
  63. package/dist/ui/assets/{mcp-BWMt8aY7.js → mcp-k-_pwbqA.js} +1 -1
  64. package/dist/ui/assets/{skills-D7JjK7JH.js → skills-xMXangks.js} +1 -1
  65. package/dist/ui/assets/{stats-DoIhtLot.js → stats-C4QZIv5O.js} +1 -1
  66. package/dist/ui/assets/{vendor-icons-DMd9RGvJ.js → vendor-icons-NHF9HNeN.js} +1 -1
  67. package/dist/ui/index.html +3 -3
  68. package/dist/ui/sw.js +1 -1
  69. package/package.json +3 -1
  70. package/dist/runtime/__tests__/keymaker.test.js +0 -148
  71. package/dist/runtime/keymaker.js +0 -157
  72. package/dist/ui/assets/AuditDashboard-C1f6Hbdw.js +0 -1
  73. package/dist/ui/assets/SessionAudit-BCecQWde.js +0 -9
  74. package/dist/ui/assets/Settings-Cu4D-7tb.js +0 -47
  75. package/dist/ui/assets/Smiths-DnEH3nID.js +0 -1
  76. package/dist/ui/assets/index-D4fzIKy1.css +0 -1
@@ -10,19 +10,21 @@ import { TaskRequestContext } from "./tasks/context.js";
10
10
  import { TaskRepository } from "./tasks/repository.js";
11
11
  import { Neo } from "./neo.js";
12
12
  import { Trinity } from "./trinity.js";
13
+ import { Link } from "./link.js";
13
14
  import { SmithDelegateTool } from "./tools/smith-tool.js";
14
15
  import { TaskQueryTool, chronosTools, timeVerifierTool } from "./tools/index.js";
15
16
  import { Construtor } from "./tools/factory.js";
16
17
  import { MCPManager } from "../config/mcp-manager.js";
17
- import { SkillRegistry, SkillExecuteTool, SkillDelegateTool, updateSkillToolDescriptions } from "./skills/index.js";
18
+ import { SkillRegistry, createLoadSkillTool } from "./skills/index.js";
18
19
  import { SmithRegistry } from "./smiths/registry.js";
19
20
  import { AuditRepository } from "./audit/repository.js";
20
21
  import { SetupRepository } from './setup/repository.js';
21
22
  import { buildSetupTool } from './tools/setup-tool.js';
22
23
  import { emitToolAuditEvents } from "./subagent-utils.js";
24
+ import { PATHS } from "../config/paths.js";
25
+ import { writeFileSync } from "fs";
23
26
  const ORACLE_DELEGATION_TOOLS = new Set([
24
- 'apoc_delegate', 'neo_delegate', 'trinity_delegate', 'smith_delegate',
25
- 'skill_delegate', 'skill_execute',
27
+ 'apoc_delegate', 'neo_delegate', 'trinity_delegate', 'smith_delegate', 'link_delegate',
26
28
  ]);
27
29
  export class Oracle {
28
30
  provider;
@@ -119,7 +121,7 @@ export class Oracle {
119
121
  const toolCalls = msg.tool_calls ?? [];
120
122
  if (!Array.isArray(toolCalls))
121
123
  continue;
122
- if (toolCalls.some((tc) => tc?.name === "apoc_delegate" || tc?.name === "neo_delegate" || tc?.name === "trinity_delegate" || tc?.name === "smith_delegate")) {
124
+ if (toolCalls.some((tc) => tc?.name === "apoc_delegate" || tc?.name === "neo_delegate" || tc?.name === "trinity_delegate" || tc?.name === "smith_delegate" || tc?.name === "link_delegate")) {
123
125
  return true;
124
126
  }
125
127
  }
@@ -154,7 +156,7 @@ export class Oracle {
154
156
  // Fail-open: Oracle can still initialize even if catalog refresh fails.
155
157
  await Neo.refreshDelegateCatalog().catch(() => { });
156
158
  await Trinity.refreshDelegateCatalog().catch(() => { });
157
- updateSkillToolDescriptions();
159
+ await Link.refreshDelegateCatalog().catch(() => { });
158
160
  // Build tool list — conditionally include SmithDelegateTool based on config
159
161
  // Initialize setup repository (creates table if needed)
160
162
  SetupRepository.getInstance();
@@ -164,8 +166,8 @@ export class Oracle {
164
166
  Neo.getInstance().createDelegateTool(),
165
167
  Apoc.getInstance().createDelegateTool(),
166
168
  Trinity.getInstance().createDelegateTool(),
167
- SkillExecuteTool,
168
- SkillDelegateTool,
169
+ Link.getInstance().createDelegateTool(),
170
+ createLoadSkillTool(),
169
171
  timeVerifierTool,
170
172
  ...chronosTools,
171
173
  ];
@@ -245,11 +247,14 @@ Do NOT proceed with other tasks until all required fields have been collected an
245
247
  `;
246
248
  }
247
249
  }
248
- const systemMessage = new SystemMessage(`${setupBlock}You are ${this.config.agent.name}, ${this.config.agent.personality}, the Oracle.
250
+ const systemMessage = new SystemMessage(`
251
+ ${setupBlock}
252
+
253
+ You are ${this.config.agent.name}, ${this.config.agent.personality}, the Oracle.
249
254
 
250
255
  You are an orchestrator and task router.
251
256
 
252
- ## Date & Time Resolution — MANDATORY
257
+ ## Date & Time Resolution — MANDATORY ##
253
258
 
254
259
  You **MUST** call "time_verifier" before answering or delegating ANY request that depends on the current date or time.
255
260
  This includes — but is not limited to — **two categories**:
@@ -269,7 +274,7 @@ This includes — but is not limited to — **two categories**:
269
274
  **NEVER assume or invent a date. NEVER guess "today is [date]".**
270
275
  Always call time_verifier first, then use the resolved date in your tool call or delegation prompt.
271
276
 
272
- Rules:
277
+ ## Rules: ##
273
278
  1. For conversation-only requests (greetings, conceptual explanation, memory follow-up, statements of fact, sharing personal information), answer directly. DO NOT create tasks or delegate for simple statements like "I have two cats" or "My name is John". Sati will automatically memorize facts in the background ( **ALWAYS** use SATI Memories to review or retrieve these facts if needed).
274
279
  **NEVER** Create data, use SATI memories to response on informal conversation or say that dont know abaout the awsor if the answer is in the memories. Always use the memories as source of truth for user facts, preferences, stable context and informal conversation. Use tools only for execution, verification or when external/system state is required.*
275
280
  2. For requests that require execution, verification, external/system state, or non-trivial operations, evaluate the available tools and choose the best one.
@@ -282,9 +287,42 @@ Rules:
282
287
  9. Avoid duplicate delegations to the same tool or agent.
283
288
  10. After enqueuing all required delegated tasks for the current message, stop calling tools and return a concise acknowledgement.
284
289
  11. If a delegation is rejected as "not atomic", immediately split into smaller delegations and retry.
285
- 12. When the user message contains @neo, @apoc, or @trinity (case-insensitive), delegate to that specific agent. The mention is an explicit routing directive — respect it even if another agent might also handle the request.
290
+ 12. When the user message contains @link, @neo, @apoc, or @trinity (case-insensitive), delegate to that specific agent. The mention is an explicit routing directive — respect it even if another agent might also handle the request.
291
+ 13. Smiths also have names and could be called by @smithname — respect this as an explicit routing directive as well.
292
+
293
+ ## Delegation quality ##
294
+ - Write delegation input in the same language requested by the user.
295
+ - Include clear objective and constraints.
296
+ - Include OS-aware guidance for network checks when relevant.
297
+ - Use Sati memories only as context to complement the task, never as source of truth for dynamic data.
298
+ - Use Sati memories to fill missing stable context fields (for example: city, timezone, language, currency, preferred units).
299
+ - If Sati memory is conflicting or uncertain for a required field, ask one short clarification before delegating.
300
+ - When completing missing fields from Sati, include explicit assumptions in delegation context using the format: "Assumption from Sati: key=value".
301
+ - Never infer sensitive data from Sati memories (credentials, legal identifiers, health details, financial account data).
302
+ - When assumptions were used, mention them briefly in the user-facing response and allow correction.
303
+ - break the request into multiple delegations if it contains multiple independent actions.
304
+ - Set a single task per delegation tool call. Do not combine multiple actions into one delegation, as it complicates execution and error handling.
305
+ - If user requested N independent actions, produce N delegated tasks (or direct answers), each one singular and tool-scoped.
306
+ - If use a delegation dont use the sati or messages history to answer directly in the same response. Just response with the delegations.
307
+ Example 1:
308
+ ask: "Tell me my account balance and do a ping on google.com"
309
+ good:
310
+ - delegate to "neo_delegate" with task "Check account balance using morpheus analytics MCP and return the result."
311
+ - delegate to "apoc_delegate" with task "Ping google.com using the network diagnostics MCP and return reachability status. Use '-n' flag for Windows and '-c' for Linux/macOS."
312
+ bad:
313
+ - delegate to "neo_delegate" with task "Check account balance using morpheus analytics MCP and ping google.com using the network diagnostics MCP, then return both results." (combines two independent actions into one delegation, which is not atomic and complicates execution and error handling)
314
+
315
+ Example 2:
316
+ ask: "I have two cats" or "My name is John"
317
+ good:
318
+ - Answer directly acknowledging the fact. Do NOT delegate.
319
+ bad:
320
+ - delegate to "neo_delegate" or "apoc_delegate" to save the fact. (Sati handles this automatically in the background)
286
321
 
287
- ## Chronos Channel Routing
322
+ --------------------------------------------------
323
+ CHRONOS SCHEDULING RULES
324
+ --------------------------------------------------
325
+ ## Chronos Channel Routing ##
288
326
  When calling chronos_schedule, set notify_channels based on the user's message:
289
327
  - User mentions a specific channel (e.g., "no Discord", "no Telegram", "on Discord", "me avise pelo Discord"): set notify_channels to that channel — e.g. ["discord"] or ["telegram"].
290
328
  - User says "all channels", "todos os canais", "em todos os canais": set notify_channels to [] (empty = broadcast to all active channels).
@@ -339,38 +377,33 @@ Behavior rules for Chronos execution context:
339
377
  - **Action / task prompts** (e.g., "executar npm build", "verificar se o servidor está online", "enviar relatório"): execute normally using the appropriate tools.
340
378
  - NEVER re-schedule or create new Chronos jobs from within a Chronos execution.
341
379
 
342
- Delegation quality:
343
- - Write delegation input in the same language requested by the user.
344
- - Include clear objective and constraints.
345
- - Include OS-aware guidance for network checks when relevant.
346
- - Use Sati memories only as context to complement the task, never as source of truth for dynamic data.
347
- - Use Sati memories to fill missing stable context fields (for example: city, timezone, language, currency, preferred units).
348
- - If Sati memory is conflicting or uncertain for a required field, ask one short clarification before delegating.
349
- - When completing missing fields from Sati, include explicit assumptions in delegation context using the format: "Assumption from Sati: key=value".
350
- - Never infer sensitive data from Sati memories (credentials, legal identifiers, health details, financial account data).
351
- - When assumptions were used, mention them briefly in the user-facing response and allow correction.
352
- - break the request into multiple delegations if it contains multiple independent actions.
353
- - Set a single task per delegation tool call. Do not combine multiple actions into one delegation, as it complicates execution and error handling.
354
- - If user requested N independent actions, produce N delegated tasks (or direct answers), each one singular and tool-scoped.
355
- - If use a delegation dont use the sati or messages history to answer directly in the same response. Just response with the delegations.
356
- Example 1:
357
- ask: "Tell me my account balance and do a ping on google.com"
358
- good:
359
- - delegate to "neo_delegate" with task "Check account balance using morpheus analytics MCP and return the result."
360
- - delegate to "apoc_delegate" with task "Ping google.com using the network diagnostics MCP and return reachability status. Use '-n' flag for Windows and '-c' for Linux/macOS."
361
- bad:
362
- - delegate to "neo_delegate" with task "Check account balance using morpheus analytics MCP and ping google.com using the network diagnostics MCP, then return both results." (combines two independent actions into one delegation, which is not atomic and complicates execution and error handling)
380
+ ---------------------
381
+ LINK DELEGATION RULES
382
+ ---------------------
383
+ When delegating to Link:
384
+ - Include the user's original request and intent.
385
+ - Include a clear objective for what the Link agent should achieve.
386
+ - **NEVER inject Sati memories, assumptions, or pre-existing knowledge into the search query.** Link searches documents — the query must reflect ONLY what the user asked, not what you already know or assume.
387
+ - If the user asks "qual empresa trabalho atualmente?", delegate as-is: "Find the user's current company in their CV." Do NOT add specific names, values, or context from Sati memories to the query.
388
+ - Sati context may be included ONLY as a separate "context for interpretation" section, clearly separated from the search objective, so Link can use it to interpret results — never to filter or bias the search itself.
389
+ - Constraints such as response length, specific documents to search, or resources to avoid may be included.
363
390
 
364
- Example 2:
365
- ask: "I have two cats" or "My name is John"
366
- good:
367
- - Answer directly acknowledging the fact. Do NOT delegate.
368
- bad:
369
- - delegate to "neo_delegate" or "apoc_delegate" to save the fact. (Sati handles this automatically in the background)
370
391
 
392
+ ---------------------
393
+ SKILLS
394
+ ---------------------
371
395
  ${SkillRegistry.getInstance().getSystemPromptSection()}
396
+
397
+ ---------------------
398
+ SMITHS
399
+ ---------------------
372
400
  ${SmithRegistry.getInstance().getSystemPromptSection()}
373
401
  `);
402
+ //save the system prompt on ~/.morpheus/system_prompt.txt for debugging and prompt engineering purposes
403
+ try {
404
+ writeFileSync(`${PATHS.root}/system_prompt.txt`, String(systemMessage.content), 'utf-8');
405
+ }
406
+ catch { }
374
407
  // Resolve the authoritative session ID for this call.
375
408
  // Priority: explicit taskContext > current history instance > fallback.
376
409
  const currentSessionId = taskContext?.session_id
@@ -421,6 +454,7 @@ Use it to inform your response and tool selection (if needed), but do not assume
421
454
  Apoc.setSessionId(currentSessionId);
422
455
  Neo.setSessionId(currentSessionId);
423
456
  Trinity.setSessionId(currentSessionId);
457
+ Link.setSessionId(currentSessionId);
424
458
  const invokeContext = {
425
459
  origin_channel: taskContext?.origin_channel ?? "api",
426
460
  session_id: taskContext?.session_id ?? currentSessionId ?? "default",
@@ -431,7 +465,7 @@ Use it to inform your response and tool selection (if needed), but do not assume
431
465
  let syncDelegationCount = 0;
432
466
  const oracleStartMs = Date.now();
433
467
  const response = await TaskRequestContext.run(invokeContext, async () => {
434
- const agentResponse = await this.provider.invoke({ messages }, { recursionLimit: 50 });
468
+ const agentResponse = await this.provider.invoke({ messages }, { recursionLimit: 10 });
435
469
  contextDelegationAcks = TaskRequestContext.getDelegationAcks();
436
470
  syncDelegationCount = TaskRequestContext.getSyncDelegationCount();
437
471
  return agentResponse;
@@ -464,7 +498,7 @@ Use it to inform your response and tool selection (if needed), but do not assume
464
498
  const startNewMessagesIndex = messages.length;
465
499
  const newGeneratedMessages = response.messages.slice(startNewMessagesIndex);
466
500
  // Emit tool_call audit events for Oracle's independent tool calls.
467
- // Delegation tools (apoc/neo/trinity/smith/skill) are already audited
501
+ // Delegation tools (apoc/neo/trinity/smith/skill/link) are already audited
468
502
  // inside buildDelegationTool or the task system — skip them here.
469
503
  emitToolAuditEvents(newGeneratedMessages, currentSessionId ?? 'default', 'oracle', {
470
504
  skipTools: ORACLE_DELEGATION_TOOLS,
@@ -648,19 +682,22 @@ Use it to inform your response and tool selection (if needed), but do not assume
648
682
  await Construtor.reload();
649
683
  await Neo.refreshDelegateCatalog().catch(() => { });
650
684
  await Trinity.refreshDelegateCatalog().catch(() => { });
651
- updateSkillToolDescriptions();
685
+ await Link.refreshDelegateCatalog().catch(() => { });
652
686
  this.provider = await ProviderFactory.create(this.config.llm, [
653
687
  buildSetupTool(),
654
688
  TaskQueryTool,
655
689
  Neo.getInstance().createDelegateTool(),
656
690
  Apoc.getInstance().createDelegateTool(),
657
691
  Trinity.getInstance().createDelegateTool(),
658
- SkillExecuteTool,
659
- SkillDelegateTool,
692
+ Link.getInstance().createDelegateTool(),
693
+ createLoadSkillTool(),
660
694
  timeVerifierTool,
661
695
  ...chronosTools,
662
696
  ]);
663
697
  await Neo.getInstance().reload();
698
+ await Apoc.getInstance().reload();
699
+ await Trinity.getInstance().reload();
700
+ await Link.getInstance().reload();
664
701
  this.display.log(`Oracle and Neo tools reloaded`, { source: 'Oracle' });
665
702
  }
666
703
  }
@@ -22,7 +22,6 @@ This folder contains custom skills for Morpheus.
22
22
  ---
23
23
  name: my-skill
24
24
  description: What this skill does (max 500 chars)
25
- execution_mode: sync
26
25
  version: 1.0.0
27
26
  author: your-name
28
27
  tags:
@@ -33,7 +32,7 @@ This folder contains custom skills for Morpheus.
33
32
 
34
33
  # My Skill
35
34
 
36
- Instructions for Keymaker to follow when executing this skill.
35
+ Instructions for Oracle to follow when handling this skill.
37
36
 
38
37
  ## Steps
39
38
  1. First step
@@ -43,23 +42,11 @@ This folder contains custom skills for Morpheus.
43
42
  How to format the result.
44
43
  \`\`\`
45
44
 
46
- ## Execution Modes
47
-
48
- | Mode | Tool | Description |
49
- |------|------|-------------|
50
- | sync | skill_execute | Result returned immediately (default) |
51
- | async | skill_delegate | Runs in background, notifies when done |
52
-
53
- **sync** (default): Best for quick tasks like code review, analysis.
54
- **async**: Best for long-running tasks like builds, deployments.
55
-
56
45
  ## How It Works
57
46
 
58
47
  - Oracle lists available skills in its system prompt
59
- - When a request matches a sync skill, Oracle calls \`skill_execute\`
60
- - When a request matches an async skill, Oracle calls \`skill_delegate\`
61
- - Keymaker has access to ALL tools (filesystem, shell, git, MCP, databases)
62
- - Keymaker follows SKILL.md instructions to complete the task
48
+ - When a request matches a skill, Oracle calls \`load_skill\` to load its instructions
49
+ - Oracle then follows the skill instructions using its existing tools (DevKit, MCP, databases, etc.)
63
50
 
64
51
  ## Frontmatter Schema
65
52
 
@@ -67,7 +54,6 @@ This folder contains custom skills for Morpheus.
67
54
  |-------|----------|---------|-------------|
68
55
  | name | Yes | - | Unique identifier (a-z, 0-9, hyphens) |
69
56
  | description | Yes | - | Short description (max 500 chars) |
70
- | execution_mode | No | sync | sync or async |
71
57
  | version | No | - | Semver (e.g., 1.0.0) |
72
58
  | author | No | - | Your name |
73
59
  | enabled | No | true | true/false |
@@ -85,6 +71,7 @@ export async function scaffold() {
85
71
  fs.ensureDir(PATHS.cache),
86
72
  fs.ensureDir(PATHS.commands),
87
73
  fs.ensureDir(PATHS.skills),
74
+ fs.ensureDir(PATHS.docs),
88
75
  ]);
89
76
  // Migrate config.yaml -> zaion.yaml if needed
90
77
  await migrateConfigFile();
@@ -53,7 +53,6 @@ describe('SkillLoader', () => {
53
53
  version: '1.0.0',
54
54
  author: 'Test Author',
55
55
  enabled: true,
56
- execution_mode: 'sync',
57
56
  tags: ['test', 'unit'],
58
57
  examples: ['do something', 'do another thing'],
59
58
  }, '# Test Skill\n\nInstructions here.');
@@ -66,7 +65,6 @@ describe('SkillLoader', () => {
66
65
  expect(skill.version).toBe('1.0.0');
67
66
  expect(skill.author).toBe('Test Author');
68
67
  expect(skill.enabled).toBe(true);
69
- expect(skill.execution_mode).toBe('sync');
70
68
  expect(skill.tags).toEqual(['test', 'unit']);
71
69
  expect(skill.examples).toEqual(['do something', 'do another thing']);
72
70
  expect(skill.content).toBe('# Test Skill\n\nInstructions here.');
@@ -84,7 +82,6 @@ describe('SkillLoader', () => {
84
82
  const skill = result.skills[0];
85
83
  expect(skill.name).toBe('minimal-skill');
86
84
  expect(skill.enabled).toBe(true); // default
87
- expect(skill.execution_mode).toBe('sync'); // default
88
85
  });
89
86
  it('should report error for missing SKILL.md', async () => {
90
87
  const skillDir = path.join(testDir, 'no-md-skill');
@@ -152,17 +149,17 @@ describe('SkillLoader', () => {
152
149
  expect(result.skills).toHaveLength(0);
153
150
  expect(result.errors).toHaveLength(0);
154
151
  });
155
- it('should load async skill correctly', async () => {
156
- const skillDir = path.join(testDir, 'async-skill');
152
+ it('should load skill with tags correctly', async () => {
153
+ const skillDir = path.join(testDir, 'tagged-skill');
157
154
  fs.ensureDirSync(skillDir);
158
155
  createSkillMd(skillDir, {
159
- name: 'async-skill',
160
- description: 'An async skill',
161
- execution_mode: 'async',
162
- }, 'Long-running task instructions');
156
+ name: 'tagged-skill',
157
+ description: 'A tagged skill',
158
+ tags: ['ops', 'deploy'],
159
+ }, 'Tagged task instructions');
163
160
  const result = await loader.scan();
164
161
  expect(result.skills).toHaveLength(1);
165
- expect(result.skills[0].execution_mode).toBe('async');
162
+ expect(result.skills[0].tags).toEqual(['ops', 'deploy']);
166
163
  });
167
164
  });
168
165
  describe('content handling', () => {
@@ -129,13 +129,12 @@ describe('SkillRegistry', () => {
129
129
  });
130
130
  });
131
131
  describe('getSystemPromptSection()', () => {
132
- it('should generate prompt section with sync skills', async () => {
132
+ it('should generate prompt section with skills', async () => {
133
133
  const skillDir = path.join(TEST_DIR, 'prompt-skill');
134
134
  fs.ensureDirSync(skillDir);
135
135
  createSkillMd(skillDir, {
136
136
  name: 'prompt-skill',
137
137
  description: 'A skill for prompts',
138
- execution_mode: 'sync',
139
138
  examples: ['example usage'],
140
139
  }, 'Instructions for prompt skill');
141
140
  const registry = SkillRegistry.getInstance();
@@ -144,22 +143,7 @@ describe('SkillRegistry', () => {
144
143
  expect(section).toContain('Available Skills');
145
144
  expect(section).toContain('prompt-skill');
146
145
  expect(section).toContain('A skill for prompts');
147
- expect(section).toContain('skill_execute');
148
- });
149
- it('should generate prompt section with async skills', async () => {
150
- const skillDir = path.join(TEST_DIR, 'async-skill');
151
- fs.ensureDirSync(skillDir);
152
- createSkillMd(skillDir, {
153
- name: 'async-skill',
154
- description: 'An async skill',
155
- execution_mode: 'async',
156
- }, 'Instructions for async skill');
157
- const registry = SkillRegistry.getInstance();
158
- await registry.load();
159
- const section = registry.getSystemPromptSection();
160
- expect(section).toContain('Async Skills');
161
- expect(section).toContain('async-skill');
162
- expect(section).toContain('skill_delegate');
146
+ expect(section).toContain('load_skill');
163
147
  });
164
148
  it('should return empty string when no skills', async () => {
165
149
  const registry = SkillRegistry.getInstance();