@jungjaehoon/mama-os 0.9.3 → 0.9.5

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 (168) hide show
  1. package/README.md +18 -34
  2. package/dist/agent/agent-loop.d.ts +9 -3
  3. package/dist/agent/agent-loop.d.ts.map +1 -1
  4. package/dist/agent/agent-loop.js +220 -84
  5. package/dist/agent/agent-loop.js.map +1 -1
  6. package/dist/agent/claude-cli-wrapper.d.ts +6 -4
  7. package/dist/agent/claude-cli-wrapper.d.ts.map +1 -1
  8. package/dist/agent/claude-cli-wrapper.js +17 -5
  9. package/dist/agent/claude-cli-wrapper.js.map +1 -1
  10. package/dist/agent/claude-client.js +3 -3
  11. package/dist/agent/claude-client.js.map +1 -1
  12. package/dist/agent/codex-mcp-process.d.ts +10 -0
  13. package/dist/agent/codex-mcp-process.d.ts.map +1 -1
  14. package/dist/agent/codex-mcp-process.js +226 -58
  15. package/dist/agent/codex-mcp-process.js.map +1 -1
  16. package/dist/agent/gateway-tool-executor.d.ts +23 -1
  17. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  18. package/dist/agent/gateway-tool-executor.js +210 -8
  19. package/dist/agent/gateway-tool-executor.js.map +1 -1
  20. package/dist/agent/gateway-tools.md +25 -0
  21. package/dist/agent/persistent-cli-adapter.d.ts.map +1 -1
  22. package/dist/agent/persistent-cli-adapter.js +1 -0
  23. package/dist/agent/persistent-cli-adapter.js.map +1 -1
  24. package/dist/agent/persistent-cli-process.d.ts +2 -0
  25. package/dist/agent/persistent-cli-process.d.ts.map +1 -1
  26. package/dist/agent/persistent-cli-process.js +15 -0
  27. package/dist/agent/persistent-cli-process.js.map +1 -1
  28. package/dist/agent/prompt-enhancer.d.ts +12 -3
  29. package/dist/agent/prompt-enhancer.d.ts.map +1 -1
  30. package/dist/agent/prompt-enhancer.js +239 -23
  31. package/dist/agent/prompt-enhancer.js.map +1 -1
  32. package/dist/agent/types.d.ts +8 -4
  33. package/dist/agent/types.d.ts.map +1 -1
  34. package/dist/agent/types.js.map +1 -1
  35. package/dist/api/graph-api-types.d.ts +13 -0
  36. package/dist/api/graph-api-types.d.ts.map +1 -1
  37. package/dist/api/graph-api.d.ts.map +1 -1
  38. package/dist/api/graph-api.js +56 -8
  39. package/dist/api/graph-api.js.map +1 -1
  40. package/dist/api/skills-handler.d.ts.map +1 -1
  41. package/dist/api/skills-handler.js +26 -0
  42. package/dist/api/skills-handler.js.map +1 -1
  43. package/dist/api/upload-handler.d.ts.map +1 -1
  44. package/dist/api/upload-handler.js +60 -25
  45. package/dist/api/upload-handler.js.map +1 -1
  46. package/dist/cli/commands/run.js +1 -1
  47. package/dist/cli/commands/run.js.map +1 -1
  48. package/dist/cli/commands/start.d.ts.map +1 -1
  49. package/dist/cli/commands/start.js +384 -36
  50. package/dist/cli/commands/start.js.map +1 -1
  51. package/dist/cli/commands/status.js +1 -1
  52. package/dist/cli/commands/status.js.map +1 -1
  53. package/dist/cli/commands/stop.d.ts +7 -1
  54. package/dist/cli/commands/stop.d.ts.map +1 -1
  55. package/dist/cli/commands/stop.js +129 -0
  56. package/dist/cli/commands/stop.js.map +1 -1
  57. package/dist/cli/config/config-manager.d.ts +9 -0
  58. package/dist/cli/config/config-manager.d.ts.map +1 -1
  59. package/dist/cli/config/config-manager.js +64 -1
  60. package/dist/cli/config/config-manager.js.map +1 -1
  61. package/dist/cli/config/types.d.ts +6 -5
  62. package/dist/cli/config/types.d.ts.map +1 -1
  63. package/dist/cli/config/types.js +3 -3
  64. package/dist/cli/config/types.js.map +1 -1
  65. package/dist/gateways/attachment-utils.d.ts +28 -0
  66. package/dist/gateways/attachment-utils.d.ts.map +1 -0
  67. package/dist/gateways/attachment-utils.js +201 -0
  68. package/dist/gateways/attachment-utils.js.map +1 -0
  69. package/dist/gateways/discord.d.ts +0 -14
  70. package/dist/gateways/discord.d.ts.map +1 -1
  71. package/dist/gateways/discord.js +61 -172
  72. package/dist/gateways/discord.js.map +1 -1
  73. package/dist/gateways/image-analyzer.d.ts.map +1 -1
  74. package/dist/gateways/image-analyzer.js +12 -4
  75. package/dist/gateways/image-analyzer.js.map +1 -1
  76. package/dist/gateways/message-router.d.ts +3 -0
  77. package/dist/gateways/message-router.d.ts.map +1 -1
  78. package/dist/gateways/message-router.js +34 -9
  79. package/dist/gateways/message-router.js.map +1 -1
  80. package/dist/gateways/slack.d.ts +5 -0
  81. package/dist/gateways/slack.d.ts.map +1 -1
  82. package/dist/gateways/slack.js +136 -15
  83. package/dist/gateways/slack.js.map +1 -1
  84. package/dist/gateways/tool-status-tracker.d.ts +87 -0
  85. package/dist/gateways/tool-status-tracker.d.ts.map +1 -0
  86. package/dist/gateways/tool-status-tracker.js +283 -0
  87. package/dist/gateways/tool-status-tracker.js.map +1 -0
  88. package/dist/multi-agent/agent-process-manager.d.ts +15 -10
  89. package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
  90. package/dist/multi-agent/agent-process-manager.js +205 -110
  91. package/dist/multi-agent/agent-process-manager.js.map +1 -1
  92. package/dist/multi-agent/bmad-templates.d.ts +67 -0
  93. package/dist/multi-agent/bmad-templates.d.ts.map +1 -0
  94. package/dist/multi-agent/bmad-templates.js +248 -0
  95. package/dist/multi-agent/bmad-templates.js.map +1 -0
  96. package/dist/multi-agent/delegation-manager.d.ts +27 -0
  97. package/dist/multi-agent/delegation-manager.d.ts.map +1 -1
  98. package/dist/multi-agent/delegation-manager.js +41 -0
  99. package/dist/multi-agent/delegation-manager.js.map +1 -1
  100. package/dist/multi-agent/multi-agent-base.d.ts +5 -0
  101. package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
  102. package/dist/multi-agent/multi-agent-base.js +17 -20
  103. package/dist/multi-agent/multi-agent-base.js.map +1 -1
  104. package/dist/multi-agent/multi-agent-discord.d.ts.map +1 -1
  105. package/dist/multi-agent/multi-agent-discord.js +66 -95
  106. package/dist/multi-agent/multi-agent-discord.js.map +1 -1
  107. package/dist/multi-agent/multi-agent-slack.d.ts +3 -0
  108. package/dist/multi-agent/multi-agent-slack.d.ts.map +1 -1
  109. package/dist/multi-agent/multi-agent-slack.js +128 -21
  110. package/dist/multi-agent/multi-agent-slack.js.map +1 -1
  111. package/dist/multi-agent/runtime-process.d.ts +3 -0
  112. package/dist/multi-agent/runtime-process.d.ts.map +1 -1
  113. package/dist/multi-agent/runtime-process.js +4 -0
  114. package/dist/multi-agent/runtime-process.js.map +1 -1
  115. package/dist/multi-agent/swarm/swarm-task-runner.d.ts.map +1 -1
  116. package/dist/multi-agent/swarm/swarm-task-runner.js +58 -37
  117. package/dist/multi-agent/swarm/swarm-task-runner.js.map +1 -1
  118. package/dist/multi-agent/types.d.ts +20 -6
  119. package/dist/multi-agent/types.d.ts.map +1 -1
  120. package/dist/multi-agent/types.js.map +1 -1
  121. package/dist/multi-agent/workflow-engine.d.ts +7 -0
  122. package/dist/multi-agent/workflow-engine.d.ts.map +1 -1
  123. package/dist/multi-agent/workflow-engine.js +212 -31
  124. package/dist/multi-agent/workflow-engine.js.map +1 -1
  125. package/dist/multi-agent/workflow-types.d.ts +5 -1
  126. package/dist/multi-agent/workflow-types.d.ts.map +1 -1
  127. package/dist/onboarding/phase-7-integrations.js +1 -1
  128. package/dist/onboarding/phase-7-integrations.js.map +1 -1
  129. package/dist/setup/setup-prompt.d.ts +1 -1
  130. package/dist/setup/setup-prompt.d.ts.map +1 -1
  131. package/dist/setup/setup-prompt.js +1 -1
  132. package/dist/skills/skill-registry.d.ts +7 -0
  133. package/dist/skills/skill-registry.d.ts.map +1 -1
  134. package/dist/skills/skill-registry.js +18 -0
  135. package/dist/skills/skill-registry.js.map +1 -1
  136. package/package.json +1 -1
  137. package/public/viewer/js/modules/chat.js +145 -76
  138. package/public/viewer/js/modules/playground.js +148 -0
  139. package/public/viewer/js/modules/settings.js +110 -15
  140. package/public/viewer/js/modules/skills.js +59 -4
  141. package/public/viewer/js/utils/api.js +6 -0
  142. package/public/viewer/js/utils/format.js +11 -8
  143. package/public/viewer/src/modules/chat.ts +223 -83
  144. package/public/viewer/src/modules/playground.ts +173 -0
  145. package/public/viewer/src/modules/settings.ts +133 -16
  146. package/public/viewer/src/modules/skills.ts +61 -4
  147. package/public/viewer/src/utils/api.ts +14 -1
  148. package/public/viewer/src/utils/format.ts +11 -8
  149. package/public/viewer/viewer.html +171 -5
  150. package/templates/bmad/LICENSE +28 -0
  151. package/templates/bmad/architecture.md +343 -0
  152. package/templates/bmad/bmm-workflow-status.template.yaml +66 -0
  153. package/templates/bmad/prd.md +198 -0
  154. package/templates/bmad/product-brief.md +149 -0
  155. package/templates/bmad/sprint-status.template.yaml +35 -0
  156. package/templates/bmad/tech-spec.md +151 -0
  157. package/templates/personas/conductor.md +86 -15
  158. package/templates/playgrounds/cron-workflow-lab.html +1601 -0
  159. package/templates/playgrounds/skill-lab-playground.html +1625 -0
  160. package/templates/playgrounds/wave-visualizer.html +694 -0
  161. package/templates/skills/frontend-design.md +71 -0
  162. package/templates/skills/multi-agent-collab.md +145 -0
  163. package/templates/skills/playground.md +197 -0
  164. package/templates/skills/scheduling.md +84 -0
  165. package/dist/multi-agent/agent-process-pool.d.ts +0 -148
  166. package/dist/multi-agent/agent-process-pool.d.ts.map +0 -1
  167. package/dist/multi-agent/agent-process-pool.js +0 -308
  168. package/dist/multi-agent/agent-process-pool.js.map +0 -1
package/README.md CHANGED
@@ -156,6 +156,9 @@ gateways:
156
156
  # In Slack
157
157
  @mama what's the status?
158
158
  @mama /report
159
+
160
+ # File upload support
161
+ @mama [attach image] translate this
159
162
  ```
160
163
 
161
164
  ### Telegram Bot
@@ -222,6 +225,20 @@ Built-in web interface for managing MAMA and chatting with your configured backe
222
225
  - Topic filtering and search
223
226
  - Export decisions (JSON, Markdown, CSV)
224
227
 
228
+ **🧩 Skills Tab**
229
+
230
+ - Browse installed skills with status badges (published/draft/coworking)
231
+ - Click to open in Skill Lab Playground for editing
232
+ - Skill verification with 12-point checklist
233
+
234
+ **🧪 Playground Tab**
235
+
236
+ - **Skill Lab** — Step-by-step skill creation, modification, and verification
237
+ - **Cron Workflow Lab** — Visual cron-scheduled workflow designer
238
+ - **Wave Visualizer** — Audio waveform playground for voice skill development
239
+ - Bidirectional sync with Skills Tab (select skill → opens in Skill Lab)
240
+ - "Open in new tab" for full-screen editing
241
+
225
242
  **⚙️ Settings Tab**
226
243
 
227
244
  - Configure gateway tokens
@@ -400,7 +417,6 @@ multi_agent:
400
417
  bot_token: 'DISCORD_BOT_TOKEN_2'
401
418
  tier: 1 # Full access for code changes
402
419
  auto_continue: true
403
- pool_size: 3 # Enable 3 parallel processes for this agent
404
420
  auto_respond_keywords: ['bug', 'code', 'implement', '구현']
405
421
 
406
422
  reviewer:
@@ -439,38 +455,6 @@ multi_agent:
439
455
  global_cooldown_ms: 2000
440
456
  ```
441
457
 
442
- ### Process Pool (Parallel Execution)
443
-
444
- Each agent runs as a separate backend CLI subprocess. By default, each agent has **1 process** (sequential execution). Configure `pool_size` to enable parallel task execution per agent.
445
-
446
- ```yaml
447
- multi_agent:
448
- agents:
449
- developer:
450
- pool_size: 5 # 5 parallel backend CLI processes for this agent
451
- ```
452
-
453
- **How it works:**
454
-
455
- - When a task arrives and all processes are busy, a new process is spawned (up to `pool_size`)
456
- - Idle processes are reused automatically (no cold start penalty)
457
- - Processes auto-terminate after 5 minutes of inactivity (`idleTimeoutMs`)
458
- - Hung processes (busy > 15 minutes) are auto-killed (`hungTimeoutMs`)
459
-
460
- **Pool status per agent:**
461
-
462
- | State | Description |
463
- | ------- | ----------------------------------- |
464
- | `total` | Total processes currently in pool |
465
- | `busy` | Processes handling active requests |
466
- | `idle` | Processes ready for immediate reuse |
467
-
468
- **Default:** `pool_size: 1` (sequential execution, safe default)
469
-
470
- **Recommendation:** Start with `pool_size: 3` for implementation agents (Developer) and keep `pool_size: 1` for advisory agents (Reviewer, Explorer).
471
-
472
- > **Note:** Each process spawns a separate backend CLI subprocess. Higher pool sizes increase memory and API usage proportionally.
473
-
474
458
  ### Delegation
475
459
 
476
460
  Tier 1 agents can delegate tasks to other agents:
@@ -910,4 +894,4 @@ The multi-agent swarm architecture was inspired by [oh-my-opencode](https://gith
910
894
  ---
911
895
 
912
896
  **Author:** SpineLift Team
913
- **Last Updated:** 2026-02-06
897
+ **Last Updated:** 2026-02-20
@@ -11,12 +11,17 @@
11
11
  */
12
12
  import type { OAuthManager } from '../auth/index.js';
13
13
  import type { ContentBlock, ToolDefinition, AgentLoopOptions, AgentLoopResult, ClaudeClientOptions, GatewayToolExecutorOptions, AgentContext } from './types.js';
14
+ /**
15
+ * Load full skill content on-demand for per-message injection.
16
+ * @param skillId - Skill identifier like "mama/playground"
17
+ */
18
+ export declare function loadSkillContent(skillId: string): string | null;
14
19
  /**
15
20
  * Load installed & enabled skills from ~/.mama/skills/
16
- * Returns skill content blocks for system prompt injection.
17
- * Reads all .md files recursively (commands/, skills/, etc.)
21
+ * Returns skill catalog lines for system prompt injection (on-demand mode).
22
+ * Full skill content is injected per-message via detectSkillMatch() in PromptEnhancer.
18
23
  */
19
- export declare function loadInstalledSkills(verbose?: boolean, options?: {
24
+ export declare function loadInstalledSkills(verbose?: boolean, _options?: {
20
25
  onlyCommands?: boolean;
21
26
  }): string[];
22
27
  export declare function loadComposedSystemPrompt(verbose?: boolean, context?: AgentContext): string;
@@ -46,6 +51,7 @@ export declare class AgentLoop {
46
51
  private readonly stopContinuationHandler;
47
52
  private readonly preCompactHandler;
48
53
  private preCompactInjected;
54
+ private currentStreamCallbacks?;
49
55
  constructor(_oauthManager: OAuthManager, options?: AgentLoopOptions, _clientOptions?: ClaudeClientOptions, executorOptions?: GatewayToolExecutorOptions);
50
56
  /**
51
57
  * Set session key for lane-based concurrency
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,OAAO,KAAK,EAEV,YAAY,EAIZ,cAAc,EACd,gBAAgB,EAChB,eAAe,EAIf,mBAAmB,EACnB,0BAA0B,EAE1B,YAAY,EACb,MAAM,YAAY,CAAC;AA6IpB;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,UAAQ,EACf,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,MAAM,EAAE,CAqFV;AAED,wBAAgB,wBAAwB,CAAC,OAAO,UAAQ,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,CAoFxF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAuB9C;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyC;IAC/D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;IACnE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAClD,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA2B;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAA8D;IACzF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAOnB;IACX,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;IAC1D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;IACzD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAiC;IACzE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2B;IAC7D,OAAO,CAAC,kBAAkB,CAAS;gBAGjC,aAAa,EAAE,YAAY,EAC3B,OAAO,GAAE,gBAAqB,EAC9B,cAAc,CAAC,EAAE,mBAAmB,EACpC,eAAe,CAAC,EAAE,0BAA0B;IA2K9C;;;OAGG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB,OAAO,CAAC,2BAA2B;IASnC;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIjD;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE;QACzB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/E,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAClF,GAAG,IAAI;IAIR;;;;;;;;;;;;OAYG;IACG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAkB/E;;;;;;;;;OASG;IACG,cAAc,CAClB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC;IAiB3B;;OAEG;YACW,sBAAsB;IAubpC;;OAEG;YACW,YAAY;IAuD1B;;;;;;OAMG;YACW,sBAAsB;IA4CpC;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA0B9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,sBAAsB;IAO9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuB3B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA8E7B;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,cAAc,EAAE;IAI7C;;OAEG;IACH,MAAM,CAAC,sBAAsB,IAAI,MAAM;IAIvC;;OAEG;IACH,OAAO,CAAC,OAAO,CAAS;IAExB,IAAI,IAAI,IAAI;CAmBb"}
1
+ {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"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"}
@@ -45,6 +45,7 @@ var __importStar = (this && this.__importStar) || (function () {
45
45
  })();
46
46
  Object.defineProperty(exports, "__esModule", { value: true });
47
47
  exports.AgentLoop = void 0;
48
+ exports.loadSkillContent = loadSkillContent;
48
49
  exports.loadInstalledSkills = loadInstalledSkills;
49
50
  exports.loadComposedSystemPrompt = loadComposedSystemPrompt;
50
51
  exports.getGatewayToolsPrompt = getGatewayToolsPrompt;
@@ -183,16 +184,57 @@ function collectMarkdownFiles(dir, prefix = '') {
183
184
  }
184
185
  return results;
185
186
  }
187
+ // ─── Skill On-Demand Injection ───────────────────────────────────────────────
186
188
  /**
187
- * Load installed & enabled skills from ~/.mama/skills/
188
- * Returns skill content blocks for system prompt injection.
189
- * Reads all .md files recursively (commands/, skills/, etc.)
189
+ * Parse YAML frontmatter from skill .md file
190
+ */
191
+ function parseSkillFrontmatter(content) {
192
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
193
+ if (!match)
194
+ return { name: '', description: '', keywords: [] };
195
+ const block = match[1];
196
+ const name = (block.match(/^name:\s*(.+)$/m)?.[1] ?? '').trim();
197
+ const description = (block.match(/^description:\s*(.+)$/m)?.[1] ?? '').trim();
198
+ const kwBlock = block.match(/^keywords:\n((?:[ \t]+-[ \t]*.+\n?)+)/m);
199
+ const keywords = kwBlock
200
+ ? kwBlock[1]
201
+ .trim()
202
+ .split('\n')
203
+ .map((l) => l.replace(/^[ \t]*-[ \t]*/, '').trim())
204
+ .filter((k) => k.length > 0)
205
+ : [];
206
+ return { name, description, keywords };
207
+ }
208
+ /**
209
+ * Find the main .md file for a directory skill (for frontmatter parsing)
190
210
  */
191
- function loadInstalledSkills(verbose = false, options = {}) {
211
+ function findMainSkillFile(skillDir, skillName) {
212
+ for (const name of [`${skillName}.md`, 'skill.md', 'index.md']) {
213
+ const p = (0, path_1.join)(skillDir, name);
214
+ if ((0, fs_1.existsSync)(p))
215
+ return p;
216
+ }
217
+ try {
218
+ const entries = (0, fs_1.readdirSync)(skillDir, { withFileTypes: true });
219
+ for (const e of entries) {
220
+ if (e.isFile() && e.name.endsWith('.md') && !EXCLUDED_SKILL_FILES.has(e.name)) {
221
+ return (0, path_1.join)(skillDir, e.name);
222
+ }
223
+ }
224
+ }
225
+ catch {
226
+ /* ignore */
227
+ }
228
+ return null;
229
+ }
230
+ /**
231
+ * Build skill catalog (one line per enabled skill) for system prompt.
232
+ * Format: "- [source/skillId] keywords: kw1, kw2 | description"
233
+ */
234
+ function buildSkillCatalog(verbose = false) {
192
235
  const skillsBase = (0, path_1.join)((0, os_1.homedir)(), '.mama', 'skills');
193
236
  const stateFile = (0, path_1.join)(skillsBase, 'state.json');
194
- const blocks = [];
195
- // Load state (enabled/disabled tracking)
237
+ const catalog = [];
196
238
  let state = {};
197
239
  try {
198
240
  if ((0, fs_1.existsSync)(stateFile)) {
@@ -200,7 +242,7 @@ function loadInstalledSkills(verbose = false, options = {}) {
200
242
  }
201
243
  }
202
244
  catch {
203
- // No state file
245
+ /* no state file */
204
246
  }
205
247
  const sources = ['mama', 'cowork', 'external'];
206
248
  for (const source of sources) {
@@ -213,60 +255,100 @@ function loadInstalledSkills(verbose = false, options = {}) {
213
255
  if (!entry.isDirectory())
214
256
  continue;
215
257
  const stateKey = `${source}/${entry.name}`;
216
- // Skip disabled skills
217
258
  if (state[stateKey]?.enabled === false)
218
259
  continue;
219
260
  const skillDir = (0, path_1.join)(sourceDir, entry.name);
220
- let mdFiles = collectMarkdownFiles(skillDir);
221
- if (options.onlyCommands) {
222
- mdFiles = mdFiles.filter((f) => f.path.startsWith('commands/'));
223
- }
224
- if (mdFiles.length > 0) {
225
- const parts = mdFiles.map((f) => `## ${f.path}\n\n${f.content}`);
226
- blocks.push(`# [Skill: ${source}/${entry.name}]\n\n${parts.join('\n\n---\n\n')}`);
261
+ const mainFile = findMainSkillFile(skillDir, entry.name);
262
+ if (!mainFile)
263
+ continue;
264
+ try {
265
+ const content = (0, fs_1.readFileSync)(mainFile, 'utf-8');
266
+ const fm = parseSkillFrontmatter(content);
267
+ const description = fm.description || '';
268
+ const keywords = fm.keywords.length > 0 ? fm.keywords.join(', ') : entry.name;
269
+ catalog.push(`- [${stateKey}] keywords: ${keywords} | ${description}`);
227
270
  if (verbose)
228
- console.log(`[AgentLoop] Loaded skill: ${source}/${entry.name} (${mdFiles.length} files)`);
271
+ console.log(`[AgentLoop] Skill catalog: ${stateKey}`);
272
+ }
273
+ catch {
274
+ /* skip unreadable */
229
275
  }
230
276
  }
231
277
  }
232
278
  catch {
233
- // Directory read failed
279
+ /* directory read failed */
234
280
  }
235
281
  }
236
- // Also load flat .md skill files from ~/.mama/skills/ root
282
+ // Flat .md files at root
237
283
  try {
238
284
  const rootEntries = (0, fs_1.readdirSync)(skillsBase, { withFileTypes: true });
239
285
  for (const entry of rootEntries) {
240
- if (!entry.isFile() || !entry.name.endsWith('.md')) {
286
+ if (!entry.isFile() || !entry.name.endsWith('.md'))
241
287
  continue;
242
- }
243
- if (EXCLUDED_SKILL_FILES.has(entry.name)) {
288
+ if (EXCLUDED_SKILL_FILES.has(entry.name))
244
289
  continue;
245
- }
246
290
  const id = entry.name.replace(/\.md$/, '');
247
291
  const stateKey = `mama/${id}`;
248
- // Skip disabled skills (check state like subdirectory skills)
249
- if (state[stateKey]?.enabled === false) {
292
+ if (state[stateKey]?.enabled === false)
250
293
  continue;
251
- }
252
- // Skip if already loaded from subdirectory
253
- if (blocks.some((b) => b.includes(`[Skill: mama/${id}]`))) {
294
+ if (catalog.some((l) => l.includes(`[${stateKey}]`)))
254
295
  continue;
296
+ try {
297
+ const content = (0, fs_1.readFileSync)((0, path_1.join)(skillsBase, entry.name), 'utf-8');
298
+ const fm = parseSkillFrontmatter(content);
299
+ const description = fm.description || '';
300
+ const keywords = fm.keywords.length > 0 ? fm.keywords.join(', ') : id;
301
+ catalog.push(`- [${stateKey}] keywords: ${keywords} | ${description}`);
302
+ if (verbose)
303
+ console.log(`[AgentLoop] Skill catalog (flat): ${stateKey}`);
255
304
  }
256
- const fullPath = (0, path_1.join)(skillsBase, entry.name);
257
- let content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
258
- if (content.length > MAX_SKILL_FILE_CHARS) {
259
- content = content.slice(0, MAX_SKILL_FILE_CHARS) + '\n\n[... truncated]';
305
+ catch {
306
+ /* skip */
260
307
  }
261
- blocks.push(`# [Skill: mama/${id}]\n\n${content}`);
262
- if (verbose)
263
- console.log(`[AgentLoop] Loaded root skill: ${id}`);
264
308
  }
265
309
  }
266
310
  catch {
267
- // Root directory read failed
311
+ /* root directory read failed */
268
312
  }
269
- return blocks;
313
+ return catalog;
314
+ }
315
+ /**
316
+ * Load full skill content on-demand for per-message injection.
317
+ * @param skillId - Skill identifier like "mama/playground"
318
+ */
319
+ function loadSkillContent(skillId) {
320
+ const skillsBase = (0, path_1.join)((0, os_1.homedir)(), '.mama', 'skills');
321
+ // Try directory skill first
322
+ const skillDir = (0, path_1.join)(skillsBase, skillId);
323
+ if ((0, fs_1.existsSync)(skillDir)) {
324
+ const mdFiles = collectMarkdownFiles(skillDir);
325
+ if (mdFiles.length > 0) {
326
+ const parts = mdFiles.map((f) => `## ${f.path}\n\n${f.content}`);
327
+ return `# [Skill: ${skillId}]\n\n${parts.join('\n\n---\n\n')}`;
328
+ }
329
+ }
330
+ // Try flat .md file: "mama/playground" → skills/playground.md
331
+ const idParts = skillId.split('/');
332
+ if (idParts.length >= 2) {
333
+ const flatPath = (0, path_1.join)(skillsBase, `${idParts[idParts.length - 1]}.md`);
334
+ if ((0, fs_1.existsSync)(flatPath)) {
335
+ try {
336
+ return (0, fs_1.readFileSync)(flatPath, 'utf-8');
337
+ }
338
+ catch {
339
+ /* skip */
340
+ }
341
+ }
342
+ }
343
+ return null;
344
+ }
345
+ /**
346
+ * Load installed & enabled skills from ~/.mama/skills/
347
+ * Returns skill catalog lines for system prompt injection (on-demand mode).
348
+ * Full skill content is injected per-message via detectSkillMatch() in PromptEnhancer.
349
+ */
350
+ function loadInstalledSkills(verbose = false, _options = {}) {
351
+ return buildSkillCatalog(verbose);
270
352
  }
271
353
  function loadComposedSystemPrompt(verbose = false, context) {
272
354
  const mamaHome = (0, path_1.join)((0, os_1.homedir)(), '.mama');
@@ -298,26 +380,20 @@ function loadComposedSystemPrompt(verbose = false, context) {
298
380
  console.log(`[AgentLoop] Persona file not found (skipping): ${file}`);
299
381
  }
300
382
  }
301
- // Load installed & enabled skills (HIGH PRIORITYbefore CLAUDE.md)
302
- const skillBlocks = loadInstalledSkills(verbose);
303
- if (skillBlocks.length > 0) {
383
+ // Load skill catalog (on-demand modefull content injected per-message by PromptEnhancer)
384
+ const skillCatalog = loadInstalledSkills(verbose);
385
+ if (skillCatalog.length > 0) {
304
386
  const skillDirective = [
305
- '# Installed Skills (PRIORITY)',
387
+ '# Installed Skills',
306
388
  '',
307
- '**IMPORTANT:** The following skills/plugins are installed by the user.',
308
- 'When a user request matches a skill by keywords or description, you MUST:',
309
- '1. Find the matching skill section below (check "keywords" in frontmatter or skill name)',
310
- '2. Follow its "지시사항" / instructions EXACTLY as written — do NOT improvise alternatives',
311
- '3. Use the tools available to you (fetch, Bash, etc.) as the skill directs',
312
- '4. DO NOT create separate scripts or files unless the skill explicitly instructs it',
313
- '5. For [INSTALLED PLUGIN COMMAND] messages, find matching "commands/{name}.md"',
314
- '6. DO NOT use the Skill tool — these are NOT system skills',
389
+ 'To invoke a skill, include its keywords in your message.',
390
+ 'The full skill instructions will be injected automatically when matched.',
315
391
  '',
316
- skillBlocks.join('\n\n---\n\n'),
392
+ ...skillCatalog,
317
393
  ].join('\n');
318
394
  layers.push(skillDirective);
319
395
  if (verbose)
320
- console.log(`[AgentLoop] Injected ${skillBlocks.length} installed skills`);
396
+ console.log(`[AgentLoop] Skill catalog: ${skillCatalog.length} skills`);
321
397
  }
322
398
  // Add context prompt if AgentContext is provided (role awareness)
323
399
  if (context) {
@@ -395,6 +471,7 @@ class AgentLoop {
395
471
  stopContinuationHandler;
396
472
  preCompactHandler;
397
473
  preCompactInjected = false;
474
+ currentStreamCallbacks;
398
475
  constructor(_oauthManager, options = {}, _clientOptions, executorOptions) {
399
476
  // Initialize tools config (hybrid Gateway/MCP routing)
400
477
  this.toolsConfig = {
@@ -423,38 +500,88 @@ class AgentLoop {
423
500
  else {
424
501
  logger.debug('⚙️ Gateway-only mode');
425
502
  }
426
- // Build system prompt
427
- const basePrompt = options.systemPrompt || loadComposedSystemPrompt();
428
- // Only include Gateway Tools prompt if using Gateway mode
429
- const gatewayToolsPrompt = useGatewayMode ? getGatewayToolsPrompt() : '';
430
- let defaultSystemPrompt = gatewayToolsPrompt
431
- ? `${basePrompt}\n\n---\n\n${gatewayToolsPrompt}`
432
- : basePrompt;
433
- // Monitor and enforce prompt size limits
503
+ // Build system prompt with layered truncation support
434
504
  const monitor = new prompt_size_monitor_js_1.PromptSizeMonitor();
435
- const promptLayers = [
436
- { name: 'base', content: basePrompt, priority: 1 },
437
- ...(gatewayToolsPrompt
438
- ? [{ name: 'gatewayTools', content: gatewayToolsPrompt, priority: 2 }]
439
- : []),
440
- ];
505
+ let promptLayers;
506
+ if (options.systemPrompt) {
507
+ // Custom system prompt (e.g., multi-agent): treat as a single critical layer
508
+ promptLayers = [{ name: 'custom', content: options.systemPrompt, priority: 1 }];
509
+ }
510
+ else {
511
+ // Composed prompt: build layers with individual priorities for graceful truncation
512
+ // Priority 1 (never cut): CLAUDE.md base instructions
513
+ // Priority 2 (cut if extreme): personas (SOUL, IDENTITY, USER) + gateway tools
514
+ // Priority 3 (cut first): context prompt + skills + onboarding
515
+ const mamaHome = (0, path_1.join)((0, os_1.homedir)(), '.mama');
516
+ const claudeMd = loadSystemPrompt();
517
+ const personaFiles = ['SOUL.md', 'IDENTITY.md', 'USER.md'];
518
+ const personaParts = [];
519
+ for (const file of personaFiles) {
520
+ const p = (0, path_1.join)(mamaHome, file);
521
+ if ((0, fs_1.existsSync)(p))
522
+ personaParts.push((0, fs_1.readFileSync)(p, 'utf-8'));
523
+ }
524
+ const skillCatalog = loadInstalledSkills();
525
+ const onboardingPath = (0, path_1.join)(mamaHome, 'ONBOARDING.md');
526
+ const onboardingContent = (0, fs_1.existsSync)(onboardingPath)
527
+ ? (0, fs_1.readFileSync)(onboardingPath, 'utf-8')
528
+ : '';
529
+ promptLayers = [
530
+ { name: 'claudeMd', content: claudeMd, priority: 1 },
531
+ ...(personaParts.length > 0
532
+ ? [
533
+ {
534
+ name: 'personas',
535
+ content: personaParts.join('\n\n---\n\n'),
536
+ priority: 2,
537
+ },
538
+ ]
539
+ : []),
540
+ ...(skillCatalog.length > 0
541
+ ? [
542
+ {
543
+ name: 'skills',
544
+ content: [
545
+ '# Installed Skills',
546
+ '',
547
+ 'To invoke a skill, include its keywords in your message.',
548
+ '',
549
+ ...skillCatalog,
550
+ ].join('\n'),
551
+ priority: 3,
552
+ },
553
+ ]
554
+ : []),
555
+ ...(onboardingContent
556
+ ? [{ name: 'onboarding', content: onboardingContent, priority: 4 }]
557
+ : []),
558
+ ];
559
+ }
560
+ if (useGatewayMode) {
561
+ const gatewayToolsPrompt = getGatewayToolsPrompt();
562
+ if (gatewayToolsPrompt) {
563
+ promptLayers.push({ name: 'gatewayTools', content: gatewayToolsPrompt, priority: 2 });
564
+ }
565
+ }
441
566
  const checkResult = monitor.check(promptLayers);
442
567
  if (checkResult.warning) {
443
568
  logger.warn(checkResult.warning);
444
569
  }
445
- // Actually enforce truncation if over budget
570
+ // Enforce truncation if over budget (priority > 1 layers trimmed first)
446
571
  if (!checkResult.withinBudget) {
447
572
  const { layers: trimmedLayers, result: enforceResult } = monitor.enforce(promptLayers);
448
573
  if (enforceResult.truncatedLayers.length > 0) {
449
574
  logger.warn(`Truncated layers: ${enforceResult.truncatedLayers.join(', ')}`);
450
575
  }
451
- const trimmedBase = trimmedLayers.find((l) => l.name === 'base')?.content || basePrompt;
452
- const trimmedTools = trimmedLayers.find((l) => l.name === 'gatewayTools')?.content || '';
453
- defaultSystemPrompt = trimmedTools ? `${trimmedBase}\n\n---\n\n${trimmedTools}` : trimmedBase;
454
- logger.debug(`System prompt truncated: ${checkResult.totalChars} → ${defaultSystemPrompt.length} chars`);
576
+ promptLayers = trimmedLayers;
577
+ logger.debug(`System prompt truncated: ${checkResult.totalChars} ${enforceResult.totalChars} chars`);
455
578
  }
579
+ const defaultSystemPrompt = promptLayers
580
+ .filter((l) => l.content.length > 0)
581
+ .map((l) => l.content)
582
+ .join('\n\n---\n\n');
456
583
  // Choose backend (default: claude)
457
- this.backend = options.backend ?? 'claude';
584
+ this.backend = options.backend;
458
585
  if (this.backend === 'codex-mcp') {
459
586
  // Codex MCP mode: standard MCP protocol
460
587
  const workspaceDir = (0, path_1.join)((0, os_1.homedir)(), '.mama', 'workspace');
@@ -475,17 +602,19 @@ class AgentLoop {
475
602
  else {
476
603
  // Claude backend: always use PersistentCLI for fast responses (~2-3s vs ~16-30s)
477
604
  this.persistentCLI = new persistent_cli_adapter_js_1.PersistentCLIAdapter({
478
- model: options.model ?? 'claude-sonnet-4-20250514',
605
+ model: options.model,
479
606
  sessionId,
480
607
  systemPrompt: defaultSystemPrompt,
481
608
  // Hybrid mode: pass MCP config even with Gateway tools enabled
482
609
  mcpConfigPath: useMCPMode ? mcpConfigPath : undefined,
483
- // Headless daemon requires skipping permission prompts (no TTY available).
484
- // Security is enforced by MAMA's RoleManager, not Claude CLI's interactive prompts.
485
- // MAMA_TRUSTED_ENV must be set to enable this flag (defense in depth)
486
- dangerouslySkipPermissions: process.env.MAMA_TRUSTED_ENV === 'true' && (options.dangerouslySkipPermissions ?? false),
610
+ // MAMA OS is a headless daemon (no TTY) — Claude CLI's interactive permission prompts
611
+ // cannot work. Security is enforced by MAMA's own RoleManager layer (config.yaml roles).
612
+ // DO NOT gate this on env vars MAMA manages permissions via its config, not Claude CLI.
613
+ dangerouslySkipPermissions: options.dangerouslySkipPermissions ?? false,
487
614
  // Gateway tools are processed by GatewayToolExecutor (hybrid with MCP)
488
615
  useGatewayTools: useGatewayMode,
616
+ // Pass configured timeout (default in PersistentCLI: 120s — too short for complex tasks)
617
+ requestTimeout: options.timeoutMs,
489
618
  });
490
619
  this.agent = this.persistentCLI;
491
620
  logger.debug('🚀 Claude PersistentCLI mode enabled - faster responses');
@@ -497,8 +626,7 @@ class AgentLoop {
497
626
  this.mcpExecutor = new gateway_tool_executor_js_1.GatewayToolExecutor(executorOptions);
498
627
  this.systemPromptOverride = options.systemPrompt;
499
628
  this.maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;
500
- // Use the same default model as CLI wrappers above (L252, L264)
501
- this.model = options.model ?? 'claude-sonnet-4-20250514';
629
+ this.model = options.model;
502
630
  this.onTurn = options.onTurn;
503
631
  this.onToolUse = options.onToolUse;
504
632
  this.onTokenUsage = options.onTokenUsage;
@@ -624,6 +752,7 @@ class AgentLoop {
624
752
  * Internal implementation of runWithContent (without lane queueing)
625
753
  */
626
754
  async runWithContentInternal(content, options) {
755
+ this.currentStreamCallbacks = options?.streamCallbacks;
627
756
  const history = [];
628
757
  const totalUsage = { input_tokens: 0, output_tokens: 0 };
629
758
  let turn = 0;
@@ -711,19 +840,19 @@ class AgentLoop {
711
840
  throw new types_js_1.AgentError(`Emergency stop: Agent loop exceeded emergency maximum turns (${EMERGENCY_MAX_TURNS})`, 'EMERGENCY_MAX_TURNS', undefined, false);
712
841
  }
713
842
  let response;
843
+ const ext = this.currentStreamCallbacks;
714
844
  const callbacks = {
715
845
  onDelta: (text) => {
716
- console.log('[Streaming] Delta received:', text.length, 'chars');
846
+ ext?.onDelta?.(text);
717
847
  },
718
- onToolUse: (name, _input) => {
719
- console.log(`[Streaming] Tool called: ${name}`);
848
+ onToolUse: (name, input) => {
849
+ ext?.onToolUse?.(name, input);
720
850
  },
721
- onFinal: (_finalResponse) => {
722
- console.log('[Streaming] Stream complete');
851
+ onFinal: (finalResponse) => {
852
+ ext?.onFinal?.(finalResponse);
723
853
  },
724
854
  onError: (error) => {
725
- console.error('[Streaming] Error:', error);
726
- // Don't throw - let the promise rejection handle it
855
+ ext?.onError?.(error);
727
856
  },
728
857
  };
729
858
  let piResult;
@@ -971,6 +1100,7 @@ class AgentLoop {
971
1100
  if (ownedSession) {
972
1101
  this.sessionPool.releaseSession(channelKey);
973
1102
  }
1103
+ this.currentStreamCallbacks = undefined;
974
1104
  }
975
1105
  }
976
1106
  /**
@@ -982,6 +1112,8 @@ class AgentLoop {
982
1112
  for (const toolUse of toolUseBlocks) {
983
1113
  let result;
984
1114
  let isError = false;
1115
+ // Notify stream: tool execution starting
1116
+ this.currentStreamCallbacks?.onToolUse?.(toolUse.name, toolUse.input);
985
1117
  try {
986
1118
  // PreToolUse: search MAMA for contracts before Write operations
987
1119
  let contractContext = '';
@@ -997,12 +1129,16 @@ class AgentLoop {
997
1129
  this.onToolUse?.(toolUse.name, toolUse.input, toolResult);
998
1130
  // PostToolUse: auto-extract contracts (fire-and-forget)
999
1131
  this.postToolHandler?.processInBackground(toolUse.name, toolUse.input, toolResult);
1132
+ // Notify stream: tool completed successfully
1133
+ this.currentStreamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, false);
1000
1134
  }
1001
1135
  catch (error) {
1002
1136
  isError = true;
1003
1137
  result = error instanceof Error ? error.message : String(error);
1004
1138
  // Notify tool use callback with error
1005
1139
  this.onToolUse?.(toolUse.name, toolUse.input, { error: result });
1140
+ // Notify stream: tool completed with error
1141
+ this.currentStreamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, true);
1006
1142
  }
1007
1143
  results.push({
1008
1144
  type: 'tool_result',