@codemieai/code 0.0.34 → 0.0.36

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 (206) hide show
  1. package/README.md +10 -5
  2. package/bin/codemie-claude-acp.js +21 -0
  3. package/bin/codemie.js +13 -0
  4. package/dist/agents/codemie-code/agent.d.ts +23 -5
  5. package/dist/agents/codemie-code/agent.d.ts.map +1 -1
  6. package/dist/agents/codemie-code/agent.js +293 -197
  7. package/dist/agents/codemie-code/agent.js.map +1 -1
  8. package/dist/agents/codemie-code/index.d.ts +1 -1
  9. package/dist/agents/codemie-code/index.d.ts.map +1 -1
  10. package/dist/agents/codemie-code/index.js +9 -6
  11. package/dist/agents/codemie-code/index.js.map +1 -1
  12. package/dist/agents/codemie-code/prompts.d.ts +9 -11
  13. package/dist/agents/codemie-code/prompts.d.ts.map +1 -1
  14. package/dist/agents/codemie-code/prompts.js +43 -16
  15. package/dist/agents/codemie-code/prompts.js.map +1 -1
  16. package/dist/agents/codemie-code/skills/core/SkillDiscovery.d.ts.map +1 -0
  17. package/dist/{skills → agents/codemie-code/skills}/core/SkillDiscovery.js +1 -1
  18. package/dist/agents/codemie-code/skills/core/SkillDiscovery.js.map +1 -0
  19. package/dist/agents/codemie-code/skills/core/SkillManager.d.ts.map +1 -0
  20. package/dist/{skills → agents/codemie-code/skills}/core/SkillManager.js +1 -1
  21. package/dist/agents/codemie-code/skills/core/SkillManager.js.map +1 -0
  22. package/dist/agents/codemie-code/skills/core/types.d.ts.map +1 -0
  23. package/dist/agents/codemie-code/skills/core/types.js.map +1 -0
  24. package/dist/agents/codemie-code/skills/index.d.ts.map +1 -0
  25. package/dist/agents/codemie-code/skills/index.js.map +1 -0
  26. package/dist/agents/codemie-code/skills/utils/content-loader.d.ts.map +1 -0
  27. package/dist/{skills → agents/codemie-code/skills}/utils/content-loader.js +1 -1
  28. package/dist/agents/codemie-code/skills/utils/content-loader.js.map +1 -0
  29. package/dist/agents/codemie-code/skills/utils/frontmatter.d.ts.map +1 -0
  30. package/dist/agents/codemie-code/skills/utils/frontmatter.js.map +1 -0
  31. package/dist/agents/codemie-code/skills/utils/pattern-matcher.d.ts.map +1 -0
  32. package/dist/agents/codemie-code/skills/utils/pattern-matcher.js.map +1 -0
  33. package/dist/agents/codemie-code/toolMetadata.d.ts.map +1 -1
  34. package/dist/agents/codemie-code/toolMetadata.js +9 -8
  35. package/dist/agents/codemie-code/toolMetadata.js.map +1 -1
  36. package/dist/agents/codemie-code/tools/assistant-invocation.d.ts +47 -0
  37. package/dist/agents/codemie-code/tools/assistant-invocation.d.ts.map +1 -0
  38. package/dist/agents/codemie-code/tools/assistant-invocation.js +129 -0
  39. package/dist/agents/codemie-code/tools/assistant-invocation.js.map +1 -0
  40. package/dist/agents/codemie-code/tools/index.d.ts +70 -4
  41. package/dist/agents/codemie-code/tools/index.d.ts.map +1 -1
  42. package/dist/agents/codemie-code/tools/index.js +57 -44
  43. package/dist/agents/codemie-code/tools/index.js.map +1 -1
  44. package/dist/agents/codemie-code/tools/planning.d.ts +6 -5
  45. package/dist/agents/codemie-code/tools/planning.d.ts.map +1 -1
  46. package/dist/agents/codemie-code/tools/planning.js +12 -10
  47. package/dist/agents/codemie-code/tools/planning.js.map +1 -1
  48. package/dist/agents/codemie-code/types.d.ts +25 -4
  49. package/dist/agents/codemie-code/types.d.ts.map +1 -1
  50. package/dist/agents/codemie-code/types.js +24 -0
  51. package/dist/agents/codemie-code/types.js.map +1 -1
  52. package/dist/agents/codemie-code/ui/autocomplete.d.ts +98 -0
  53. package/dist/agents/codemie-code/ui/autocomplete.d.ts.map +1 -0
  54. package/dist/agents/codemie-code/ui/autocomplete.js +145 -0
  55. package/dist/agents/codemie-code/ui/autocomplete.js.map +1 -0
  56. package/dist/agents/codemie-code/ui/keyHandlers.d.ts +112 -0
  57. package/dist/agents/codemie-code/ui/keyHandlers.d.ts.map +1 -0
  58. package/dist/agents/codemie-code/ui/keyHandlers.js +415 -0
  59. package/dist/agents/codemie-code/ui/keyHandlers.js.map +1 -0
  60. package/dist/agents/codemie-code/ui/mentions.d.ts +86 -0
  61. package/dist/agents/codemie-code/ui/mentions.d.ts.map +1 -0
  62. package/dist/agents/codemie-code/ui/mentions.js +122 -0
  63. package/dist/agents/codemie-code/ui/mentions.js.map +1 -0
  64. package/dist/agents/codemie-code/ui/terminalCodes.d.ts +38 -0
  65. package/dist/agents/codemie-code/ui/terminalCodes.d.ts.map +1 -0
  66. package/dist/agents/codemie-code/ui/terminalCodes.js +42 -0
  67. package/dist/agents/codemie-code/ui/terminalCodes.js.map +1 -0
  68. package/dist/agents/codemie-code/ui/todoPanel.d.ts.map +1 -1
  69. package/dist/agents/codemie-code/ui/todoPanel.js +3 -4
  70. package/dist/agents/codemie-code/ui/todoPanel.js.map +1 -1
  71. package/dist/agents/codemie-code/ui.d.ts +8 -7
  72. package/dist/agents/codemie-code/ui.d.ts.map +1 -1
  73. package/dist/agents/codemie-code/ui.js +87 -145
  74. package/dist/agents/codemie-code/ui.js.map +1 -1
  75. package/dist/agents/core/AgentCLI.d.ts +5 -0
  76. package/dist/agents/core/AgentCLI.d.ts.map +1 -1
  77. package/dist/agents/core/AgentCLI.js +22 -0
  78. package/dist/agents/core/AgentCLI.js.map +1 -1
  79. package/dist/agents/core/BaseAgentAdapter.d.ts.map +1 -1
  80. package/dist/agents/core/BaseAgentAdapter.js +58 -28
  81. package/dist/agents/core/BaseAgentAdapter.js.map +1 -1
  82. package/dist/agents/core/extension/BaseExtensionInstaller.d.ts +7 -1
  83. package/dist/agents/core/extension/BaseExtensionInstaller.d.ts.map +1 -1
  84. package/dist/agents/core/extension/BaseExtensionInstaller.js +58 -15
  85. package/dist/agents/core/extension/BaseExtensionInstaller.js.map +1 -1
  86. package/dist/agents/core/types.d.ts +17 -0
  87. package/dist/agents/core/types.d.ts.map +1 -1
  88. package/dist/agents/plugins/claude/claude-acp.plugin.d.ts +27 -0
  89. package/dist/agents/plugins/claude/claude-acp.plugin.d.ts.map +1 -0
  90. package/dist/agents/plugins/claude/claude-acp.plugin.js +63 -0
  91. package/dist/agents/plugins/claude/claude-acp.plugin.js.map +1 -0
  92. package/dist/agents/plugins/claude/claude-message-types.d.ts +1 -0
  93. package/dist/agents/plugins/claude/claude-message-types.d.ts.map +1 -1
  94. package/dist/agents/plugins/claude/claude.plugin.d.ts +1 -1
  95. package/dist/agents/plugins/claude/claude.plugin.d.ts.map +1 -1
  96. package/dist/agents/plugins/claude/claude.plugin.js +66 -29
  97. package/dist/agents/plugins/claude/claude.plugin.js.map +1 -1
  98. package/dist/agents/plugins/claude/claude.session.d.ts.map +1 -1
  99. package/dist/agents/plugins/claude/claude.session.js +14 -7
  100. package/dist/agents/plugins/claude/claude.session.js.map +1 -1
  101. package/dist/agents/plugins/claude/plugin/.claude-plugin/plugin.json +1 -1
  102. package/dist/agents/plugins/claude/plugin/commands/codemie-subagents.md +4 -4
  103. package/dist/agents/plugins/claude/session/processors/claude.conversations-processor.d.ts.map +1 -1
  104. package/dist/agents/plugins/claude/session/processors/claude.conversations-processor.js +43 -8
  105. package/dist/agents/plugins/claude/session/processors/claude.conversations-processor.js.map +1 -1
  106. package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.d.ts.map +1 -1
  107. package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.js +68 -40
  108. package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.js.map +1 -1
  109. package/dist/agents/registry.d.ts +1 -1
  110. package/dist/agents/registry.d.ts.map +1 -1
  111. package/dist/agents/registry.js +3 -1
  112. package/dist/agents/registry.js.map +1 -1
  113. package/dist/cli/commands/assistants/chat.d.ts +11 -0
  114. package/dist/cli/commands/assistants/chat.d.ts.map +1 -0
  115. package/dist/cli/commands/assistants/chat.js +201 -0
  116. package/dist/cli/commands/assistants/chat.js.map +1 -0
  117. package/dist/cli/commands/assistants/constants.d.ts +81 -0
  118. package/dist/cli/commands/assistants/constants.d.ts.map +1 -0
  119. package/dist/cli/commands/assistants/constants.js +75 -0
  120. package/dist/cli/commands/assistants/constants.js.map +1 -0
  121. package/dist/cli/commands/assistants/generators/claude-agent-generator.d.ts +26 -0
  122. package/dist/cli/commands/assistants/generators/claude-agent-generator.d.ts.map +1 -0
  123. package/dist/cli/commands/assistants/generators/claude-agent-generator.js +115 -0
  124. package/dist/cli/commands/assistants/generators/claude-agent-generator.js.map +1 -0
  125. package/dist/cli/commands/assistants/index.d.ts +11 -0
  126. package/dist/cli/commands/assistants/index.d.ts.map +1 -0
  127. package/dist/cli/commands/assistants/index.js +28 -0
  128. package/dist/cli/commands/assistants/index.js.map +1 -0
  129. package/dist/cli/commands/assistants/list.d.ts +11 -0
  130. package/dist/cli/commands/assistants/list.d.ts.map +1 -0
  131. package/dist/cli/commands/assistants/list.js +323 -0
  132. package/dist/cli/commands/assistants/list.js.map +1 -0
  133. package/dist/cli/commands/install.d.ts.map +1 -1
  134. package/dist/cli/commands/install.js +26 -6
  135. package/dist/cli/commands/install.js.map +1 -1
  136. package/dist/cli/commands/self-update.d.ts +3 -0
  137. package/dist/cli/commands/self-update.d.ts.map +1 -0
  138. package/dist/cli/commands/self-update.js +55 -0
  139. package/dist/cli/commands/self-update.js.map +1 -0
  140. package/dist/cli/commands/skill.js +1 -1
  141. package/dist/cli/commands/skill.js.map +1 -1
  142. package/dist/cli/commands/update.d.ts.map +1 -1
  143. package/dist/cli/commands/update.js +8 -0
  144. package/dist/cli/commands/update.js.map +1 -1
  145. package/dist/cli/index.d.ts.map +1 -1
  146. package/dist/cli/index.js +8 -4
  147. package/dist/cli/index.js.map +1 -1
  148. package/dist/env/types.d.ts +13 -0
  149. package/dist/env/types.d.ts.map +1 -1
  150. package/dist/env/types.js +1 -1
  151. package/dist/env/types.js.map +1 -1
  152. package/dist/utils/auth.d.ts +22 -0
  153. package/dist/utils/auth.d.ts.map +1 -0
  154. package/dist/utils/auth.js +50 -0
  155. package/dist/utils/auth.js.map +1 -0
  156. package/dist/utils/cli-updater.d.ts +70 -0
  157. package/dist/utils/cli-updater.d.ts.map +1 -0
  158. package/dist/utils/cli-updater.js +339 -0
  159. package/dist/utils/cli-updater.js.map +1 -0
  160. package/dist/utils/config.d.ts +6 -1
  161. package/dist/utils/config.d.ts.map +1 -1
  162. package/dist/utils/config.js +13 -0
  163. package/dist/utils/config.js.map +1 -1
  164. package/dist/utils/native-installer.d.ts.map +1 -1
  165. package/dist/utils/native-installer.js +85 -17
  166. package/dist/utils/native-installer.js.map +1 -1
  167. package/dist/utils/processes.js +1 -1
  168. package/dist/utils/profile.d.ts +2 -0
  169. package/dist/utils/profile.d.ts.map +1 -1
  170. package/dist/utils/profile.js +5 -0
  171. package/dist/utils/profile.js.map +1 -1
  172. package/dist/utils/sdk-client.d.ts +15 -0
  173. package/dist/utils/sdk-client.d.ts.map +1 -0
  174. package/dist/utils/sdk-client.js +92 -0
  175. package/dist/utils/sdk-client.js.map +1 -0
  176. package/dist/utils/windows-path.d.ts +54 -0
  177. package/dist/utils/windows-path.d.ts.map +1 -0
  178. package/dist/utils/windows-path.js +347 -0
  179. package/dist/utils/windows-path.js.map +1 -0
  180. package/package.json +7 -2
  181. package/dist/agents/plugins/claude/plugin/commands/codemie-pr.md +0 -25
  182. package/dist/skills/core/SkillDiscovery.d.ts.map +0 -1
  183. package/dist/skills/core/SkillDiscovery.js.map +0 -1
  184. package/dist/skills/core/SkillManager.d.ts.map +0 -1
  185. package/dist/skills/core/SkillManager.js.map +0 -1
  186. package/dist/skills/core/types.d.ts.map +0 -1
  187. package/dist/skills/core/types.js.map +0 -1
  188. package/dist/skills/index.d.ts.map +0 -1
  189. package/dist/skills/index.js.map +0 -1
  190. package/dist/skills/utils/content-loader.d.ts.map +0 -1
  191. package/dist/skills/utils/content-loader.js.map +0 -1
  192. package/dist/skills/utils/frontmatter.d.ts.map +0 -1
  193. package/dist/skills/utils/frontmatter.js.map +0 -1
  194. package/dist/skills/utils/pattern-matcher.d.ts.map +0 -1
  195. package/dist/skills/utils/pattern-matcher.js.map +0 -1
  196. /package/dist/{skills → agents/codemie-code/skills}/core/SkillDiscovery.d.ts +0 -0
  197. /package/dist/{skills → agents/codemie-code/skills}/core/SkillManager.d.ts +0 -0
  198. /package/dist/{skills → agents/codemie-code/skills}/core/types.d.ts +0 -0
  199. /package/dist/{skills → agents/codemie-code/skills}/core/types.js +0 -0
  200. /package/dist/{skills → agents/codemie-code/skills}/index.d.ts +0 -0
  201. /package/dist/{skills → agents/codemie-code/skills}/index.js +0 -0
  202. /package/dist/{skills → agents/codemie-code/skills}/utils/content-loader.d.ts +0 -0
  203. /package/dist/{skills → agents/codemie-code/skills}/utils/frontmatter.d.ts +0 -0
  204. /package/dist/{skills → agents/codemie-code/skills}/utils/frontmatter.js +0 -0
  205. /package/dist/{skills → agents/codemie-code/skills}/utils/pattern-matcher.d.ts +0 -0
  206. /package/dist/{skills → agents/codemie-code/skills}/utils/pattern-matcher.js +0 -0
@@ -3,19 +3,22 @@
3
3
  *
4
4
  * Core LangGraph ReAct agent using LangChain v1.0+ with streaming support
5
5
  */
6
+ import { randomUUID } from 'node:crypto';
6
7
  import { createReactAgent } from '@langchain/langgraph/prebuilt';
7
8
  import { ChatOpenAI } from '@langchain/openai';
8
- import { HumanMessage, SystemMessage } from '@langchain/core/messages';
9
+ import { HumanMessage, SystemMessage, AIMessage } from '@langchain/core/messages';
10
+ import { EVENT_TYPES, CodeMieAgentError } from './types.js';
9
11
  import { getSystemPrompt } from './prompts.js';
10
- import { CodeMieAgentError } from './types.js';
11
12
  import { extractToolMetadata } from './toolMetadata.js';
12
13
  import { extractTokenUsageFromStreamChunk, extractTokenUsageFromFinalState } from './tokenUtils.js';
13
14
  import { setGlobalToolEventCallback } from './tools/index.js';
14
15
  import { logger } from '../../utils/logger.js';
15
16
  import { sanitizeCookies, sanitizeAuthToken } from '../../utils/security.js';
16
17
  import { HookExecutor } from '../../hooks/executor.js';
17
- import { extractSkillPatterns } from '../../skills/utils/pattern-matcher.js';
18
- import { SkillManager } from '../../skills/core/SkillManager.js';
18
+ import { extractSkillPatterns } from './skills/utils/pattern-matcher.js';
19
+ import { SkillManager } from './skills/core/SkillManager.js';
20
+ import { parseAtMentionCommand } from './ui/mentions.js';
21
+ import { loadRegisteredAssistants } from '../../utils/config.js';
19
22
  export class CodeMieAgent {
20
23
  agent;
21
24
  config;
@@ -46,6 +49,8 @@ export class CodeMieAgent {
46
49
  this.config = config;
47
50
  this.tools = tools;
48
51
  this.skills = skills;
52
+ const sessionId = randomUUID();
53
+ logger.setSessionId(sessionId);
49
54
  // Create the appropriate LLM based on provider
50
55
  const llm = this.createLLM();
51
56
  // Create LangGraph ReAct agent with system prompt (including skills if loaded)
@@ -81,6 +86,27 @@ export class CodeMieAgent {
81
86
  logger.debug(`CodeMie Agent initialized with ${tools.length} tools`);
82
87
  }
83
88
  }
89
+ /**
90
+ * Update tools after initialization (needed for tools that require conversation history)
91
+ */
92
+ async updateTools(tools) {
93
+ this.tools = tools;
94
+ // Load registered assistants for system prompt
95
+ const assistants = await loadRegisteredAssistants();
96
+ // Recreate agent with new tools and assistant-aware prompt
97
+ const llm = this.createLLM();
98
+ this.agent = createReactAgent({
99
+ llm,
100
+ tools: this.tools,
101
+ messageModifier: getSystemPrompt(this.config.workingDirectory, [], assistants)
102
+ });
103
+ if (this.config.debug) {
104
+ logger.debug(`CodeMie Agent tools updated: ${tools.length} tools`);
105
+ if (assistants.length > 0) {
106
+ logger.debug(`Loaded ${assistants.length} assistants for system prompt:`, assistants.map(a => a.slug));
107
+ }
108
+ }
109
+ }
84
110
  /**
85
111
  * Create the appropriate LLM instance based on provider configuration
86
112
  */
@@ -155,7 +181,7 @@ export class CodeMieAgent {
155
181
  model: this.config.model,
156
182
  apiKey: this.config.authToken,
157
183
  configuration: {
158
- baseURL: this.config.baseUrl !== 'bedrock' ? this.config.baseUrl : undefined,
184
+ baseURL: this.config.baseUrl === 'bedrock' ? undefined : this.config.baseUrl,
159
185
  // Add client tracking header to all Bedrock requests
160
186
  fetch: async (input, init) => {
161
187
  const updatedInit = {
@@ -183,7 +209,7 @@ export class CodeMieAgent {
183
209
  baseURL
184
210
  };
185
211
  // Check if we have SSO cookies to inject (following codemie-ide-plugin pattern)
186
- const ssoCookies = global.codemieSSOCookies;
212
+ const ssoCookies = globalThis.codemieSSOCookies;
187
213
  if (this.config.debug) {
188
214
  logger.debug(`SSO Cookies available:`, sanitizeCookies(ssoCookies));
189
215
  logger.debug(`Auth token:`, sanitizeAuthToken(this.config.authToken));
@@ -289,6 +315,70 @@ export class CodeMieAgent {
289
315
  content: content
290
316
  });
291
317
  }
318
+ /**
319
+ * Handle @ mention invocation result by updating history and emitting events
320
+ * @param message - Original user message
321
+ * @param images - Optional images from user
322
+ * @param atMentionResult - Result from preprocessAtMention
323
+ * @param onEvent - Event callback
324
+ */
325
+ handleAtMentionResult(message, images, atMentionResult, onEvent) {
326
+ const userMessage = this.createHumanMessage(message, images);
327
+ this.conversationHistory.push(userMessage);
328
+ const assistantMessage = new AIMessage({
329
+ content: atMentionResult.response || 'No response from assistant'
330
+ });
331
+ this.conversationHistory.push(assistantMessage);
332
+ onEvent({ type: EVENT_TYPES.THINKING_END });
333
+ onEvent({ type: EVENT_TYPES.CONTENT_CHUNK, content: atMentionResult.response });
334
+ onEvent({ type: EVENT_TYPES.COMPLETE });
335
+ }
336
+ /**
337
+ * Preprocess message to detect @ mentions and invoke assistants directly
338
+ * Returns { handled: true, response: string, assistantSlug: string } if @ mention was processed,
339
+ * or { handled: false } if no @ mention found
340
+ */
341
+ async preprocessAtMention(message, onEvent) {
342
+ // Use shared mention pattern from mentions module
343
+ const parsed = parseAtMentionCommand(message);
344
+ if (!parsed) {
345
+ return { handled: false };
346
+ }
347
+ const { assistantSlug, message: assistantMessage } = parsed;
348
+ try {
349
+ // Find the invoke_assistant tool
350
+ const invokeTool = this.tools.find(tool => tool.name === 'invoke_assistant');
351
+ if (!invokeTool) {
352
+ if (this.config.debug) {
353
+ logger.debug('@ mention detected but invoke_assistant tool not available');
354
+ }
355
+ return { handled: false };
356
+ }
357
+ if (this.config.debug) {
358
+ logger.debug(`Preprocessing @ mention: @${assistantSlug} "${assistantMessage.substring(0, 50)}..."`);
359
+ }
360
+ // Emit thinking_start with assistant info
361
+ onEvent({ type: EVENT_TYPES.THINKING_START });
362
+ // Invoke the assistant tool directly
363
+ const response = await invokeTool.invoke({
364
+ assistantSlug,
365
+ message: assistantMessage,
366
+ includeHistory: false // Default to no history for @ mentions (can be made configurable)
367
+ });
368
+ return { handled: true, response: String(response), assistantSlug };
369
+ }
370
+ catch (error) {
371
+ if (this.config.debug) {
372
+ logger.debug('@ mention preprocessing failed:', error);
373
+ }
374
+ // Return error as response but mark as handled
375
+ return {
376
+ handled: true,
377
+ response: `Failed to invoke assistant @${assistantSlug}: ${error instanceof Error ? error.message : String(error)}`,
378
+ assistantSlug
379
+ };
380
+ }
381
+ }
292
382
  /**
293
383
  * Stream a chat interaction with the agent
294
384
  */
@@ -308,7 +398,7 @@ export class CodeMieAgent {
308
398
  // Set up global tool event callback for progress reporting
309
399
  setGlobalToolEventCallback((event) => {
310
400
  onEvent({
311
- type: 'tool_call_progress',
401
+ type: EVENT_TYPES.TOOL_CALL_PROGRESS,
312
402
  toolName: event.toolName,
313
403
  toolProgress: event.progress
314
404
  });
@@ -323,214 +413,220 @@ export class CodeMieAgent {
323
413
  }
324
414
  streamAborted = true;
325
415
  abortController.abort();
326
- onEvent({ type: 'error', error: 'Stream interrupted by user (Ctrl+C)' });
416
+ onEvent({ type: EVENT_TYPES.ERROR, error: 'Stream interrupted by user (Ctrl+C)' });
327
417
  };
328
418
  process.once('SIGINT', sigintHandler);
329
- try {
330
- if (this.config.debug) {
331
- logger.debug(`Processing message: ${message.substring(0, 100)}...`);
332
- }
333
- // Execute SessionStart hooks (only on first message)
334
- if (this.hookExecutor && this.conversationHistory.length === 0) {
335
- try {
336
- const sessionStartResult = await this.hookExecutor.executeSessionStart();
337
- // Handle blocking decision
338
- if (sessionStartResult.decision === 'block') {
339
- const reason = sessionStartResult.reason || 'Session blocked by SessionStart hook';
340
- const context = sessionStartResult.additionalContext;
341
- // Check if we should retry (exit code 2 behavior)
342
- if (context && this.hookLoopCounter < (this.getMaxHookRetries())) {
343
- this.hookLoopCounter++;
344
- logger.warn(`SessionStart hook blocked (attempt ${this.hookLoopCounter}/${this.getMaxHookRetries()})`);
345
- // Build feedback message
346
- const hookFeedback = [reason, context].filter(Boolean).join('\n\n');
347
- // Clear hook cache for retry
348
- this.hookExecutor.clearCache();
349
- // Retry with feedback
350
- return this.chatStream(`[Hook feedback]: ${hookFeedback}`, onEvent, images);
419
+ if (this.config.debug) {
420
+ logger.debug(`Processing message: ${message.substring(0, 100)}...`);
421
+ }
422
+ // Execute SessionStart hooks (only on first message)
423
+ if (this.hookExecutor && this.conversationHistory.length === 0) {
424
+ try {
425
+ const sessionStartResult = await this.hookExecutor.executeSessionStart();
426
+ // Handle blocking decision
427
+ if (sessionStartResult.decision === 'block') {
428
+ const reason = sessionStartResult.reason || 'Session blocked by SessionStart hook';
429
+ const context = sessionStartResult.additionalContext;
430
+ // Check if we should retry (exit code 2 behavior)
431
+ if (context && this.hookLoopCounter < (this.getMaxHookRetries())) {
432
+ this.hookLoopCounter++;
433
+ logger.warn(`SessionStart hook blocked (attempt ${this.hookLoopCounter}/${this.getMaxHookRetries()})`);
434
+ // Build feedback message
435
+ const hookFeedback = [reason, context].filter(Boolean).join('\n\n');
436
+ // Clear hook cache for retry
437
+ this.hookExecutor.clearCache();
438
+ // Retry with feedback
439
+ return this.chatStream(`[Hook feedback]: ${hookFeedback}`, onEvent, images);
440
+ }
441
+ else {
442
+ // Max retries reached or no feedback - block session
443
+ if (this.hookLoopCounter >= this.getMaxHookRetries()) {
444
+ logger.error(`SessionStart hook blocked after ${this.hookLoopCounter} attempts - aborting session`);
445
+ onEvent({
446
+ type: 'error',
447
+ error: `Session blocked after ${this.hookLoopCounter} attempts: ${reason}`
448
+ });
351
449
  }
352
450
  else {
353
- // Max retries reached or no feedback - block session
354
- if (this.hookLoopCounter >= this.getMaxHookRetries()) {
355
- logger.error(`SessionStart hook blocked after ${this.hookLoopCounter} attempts - aborting session`);
356
- onEvent({
357
- type: 'error',
358
- error: `Session blocked after ${this.hookLoopCounter} attempts: ${reason}`
359
- });
360
- }
361
- else {
362
- logger.warn('SessionStart hook blocked session start');
363
- onEvent({
364
- type: 'error',
365
- error: reason
366
- });
367
- }
368
- return; // Exit without starting session
369
- }
370
- }
371
- // Inject hook output as system context
372
- if (sessionStartResult.additionalContext) {
373
- if (this.config.debug) {
374
- logger.debug('SessionStart hook provided context, injecting into conversation');
451
+ logger.warn('SessionStart hook blocked session start');
452
+ onEvent({
453
+ type: 'error',
454
+ error: reason
455
+ });
375
456
  }
376
- // Add SessionStart output as system message before user message
377
- const systemMessage = new SystemMessage(`[SessionStart Hook Output]:\n${sessionStartResult.additionalContext}`);
378
- this.conversationHistory.push(systemMessage);
457
+ return; // Exit without starting session
379
458
  }
380
459
  }
381
- catch (error) {
382
- logger.error(`SessionStart hook failed: ${error}`);
383
- // Continue session start (fail open)
384
- }
385
- }
386
- // Execute UserPromptSubmit hooks
387
- if (this.hookExecutor && message.trim()) {
388
- try {
389
- const hookResult = await this.hookExecutor.executeUserPromptSubmit(message);
390
- // Handle blocking decision
391
- if (hookResult.decision === 'block') {
392
- logger.warn('UserPromptSubmit hook blocked prompt');
393
- onEvent({
394
- type: 'error',
395
- error: hookResult.reason || 'Prompt blocked by hook'
396
- });
397
- return; // Exit without processing
398
- }
399
- // Add context to conversation
400
- if (hookResult.additionalContext) {
401
- if (this.config.debug) {
402
- logger.debug('UserPromptSubmit hook provided context');
403
- }
404
- // Prepend context to the message
405
- message = `${hookResult.additionalContext}\n\n${message}`;
460
+ // Inject hook output as system context
461
+ if (sessionStartResult.additionalContext) {
462
+ if (this.config.debug) {
463
+ logger.debug('SessionStart hook provided context, injecting into conversation');
406
464
  }
407
- }
408
- catch (error) {
409
- logger.error(`UserPromptSubmit hook failed: ${error}`);
410
- // Continue execution
465
+ // Add SessionStart output as system message before user message
466
+ const systemMessage = new SystemMessage(`[SessionStart Hook Output]:\n${sessionStartResult.additionalContext}`);
467
+ this.conversationHistory.push(systemMessage);
411
468
  }
412
469
  }
413
- // Detect skill patterns in message
414
- const patternResult = extractSkillPatterns(message);
415
- if (patternResult.hasPatterns) {
416
- try {
417
- // Load skills with inventory
418
- const skillsWithInventory = await this.loadDetectedSkills(patternResult.patterns);
419
- if (skillsWithInventory.length > 0) {
420
- // Format and inject as system message
421
- const skillContent = this.formatSkillsForInjection(skillsWithInventory);
422
- const skillSystemMessage = new SystemMessage(`[Skill Invocation Detected]\n\n${skillContent}`);
423
- this.conversationHistory.push(skillSystemMessage);
424
- if (this.config.debug) {
425
- logger.debug(`Injected ${skillsWithInventory.length} skills: ${skillsWithInventory.map((s) => s.skill.metadata.name).join(', ')}`);
426
- }
427
- }
428
- }
429
- catch (error) {
430
- // Non-blocking: Log error but continue
431
- logger.warn('Failed to load skills for pattern injection:', error);
432
- }
470
+ catch (error) {
471
+ logger.error(`SessionStart hook failed: ${error}`);
472
+ // Continue session start (fail open)
433
473
  }
434
- // Add user message to conversation history (with optional images)
435
- const userMessage = this.createHumanMessage(message, images);
436
- this.conversationHistory.push(userMessage);
437
- // Notify start of thinking
438
- onEvent({ type: 'thinking_start' });
439
- // Start the first LLM call step
440
- currentStep = this.startLLMStep();
441
- // Create the stream with conversation history
442
- const stream = await this.agent.stream({ messages: this.conversationHistory }, {
443
- streamMode: 'updates',
444
- recursionLimit: 50,
445
- signal: abortController.signal // Add abort signal for stream cancellation
446
- });
447
- let hasContent = false;
448
- // Process stream chunks with interruption handling
449
- for await (const chunk of stream) {
450
- // Check if stream was aborted
451
- if (streamAborted || abortController.signal.aborted) {
474
+ }
475
+ // Execute UserPromptSubmit hooks
476
+ if (this.hookExecutor && message.trim()) {
477
+ try {
478
+ const hookResult = await this.hookExecutor.executeUserPromptSubmit(message);
479
+ // Handle blocking decision
480
+ if (hookResult.decision === 'block') {
481
+ logger.warn('UserPromptSubmit hook blocked prompt');
482
+ onEvent({
483
+ type: 'error',
484
+ error: hookResult.reason || 'Prompt blocked by hook'
485
+ });
486
+ return; // Exit without processing
487
+ }
488
+ // Add context to conversation
489
+ if (hookResult.additionalContext) {
452
490
  if (this.config.debug) {
453
- logger.debug('Stream processing aborted');
491
+ logger.debug('UserPromptSubmit hook provided context');
454
492
  }
455
- break;
493
+ // Prepend context to the message
494
+ message = `${hookResult.additionalContext}\n\n${message}`;
456
495
  }
457
- // Try to extract token usage from stream chunk
458
- const tokenUsage = extractTokenUsageFromStreamChunk(chunk, this.config.model, this.config.provider);
459
- if (tokenUsage && currentStep && currentStep.type === 'llm_call') {
460
- // Update current step with token usage
461
- currentStep.tokenUsage = tokenUsage;
462
- this.updateStatsWithTokenUsage(tokenUsage);
463
- // Store token usage to associate with next tool call
464
- this.currentLLMTokenUsage = tokenUsage;
496
+ }
497
+ catch (error) {
498
+ logger.error(`UserPromptSubmit hook failed: ${error}`);
499
+ // Continue execution
500
+ }
501
+ }
502
+ // Detect skill patterns in message
503
+ const patternResult = extractSkillPatterns(message);
504
+ if (patternResult.hasPatterns) {
505
+ try {
506
+ // Load skills with inventory
507
+ const skillsWithInventory = await this.loadDetectedSkills(patternResult.patterns);
508
+ if (skillsWithInventory.length > 0) {
509
+ // Format and inject as system message
510
+ const skillContent = this.formatSkillsForInjection(skillsWithInventory);
511
+ const skillSystemMessage = new SystemMessage(`[Skill Invocation Detected]\n\n${skillContent}`);
512
+ this.conversationHistory.push(skillSystemMessage);
465
513
  if (this.config.debug) {
466
- logger.debug(`Token usage: ${tokenUsage.inputTokens} in, ${tokenUsage.outputTokens} out`);
514
+ logger.debug(`Injected ${skillsWithInventory.length} skills: ${skillsWithInventory.map((s) => s.skill.metadata.name).join(', ')}`);
467
515
  }
468
516
  }
469
- await this.processStreamChunk(chunk, onEvent, (toolStarted) => {
470
- if (toolStarted) {
471
- // Complete current LLM step if it exists
472
- if (currentStep && currentStep.type === 'llm_call') {
473
- this.completeStep(currentStep);
474
- currentStep = null;
475
- }
476
- // Start tool execution step
477
- currentStep = this.startToolStep(toolStarted);
478
- currentToolCall = toolStarted;
479
- this.stats.toolCalls++;
480
- }
481
- else if (currentToolCall && currentStep) {
482
- // Complete tool step
483
- currentStep.toolSuccess = true;
517
+ }
518
+ catch (error) {
519
+ // Non-blocking: Log error but continue
520
+ logger.warn('Failed to load skills for pattern injection:', error);
521
+ }
522
+ }
523
+ // Preprocess @ mentions before normal agent processing
524
+ const atMentionResult = await this.preprocessAtMention(message, onEvent);
525
+ if (atMentionResult.handled) {
526
+ this.handleAtMentionResult(message, images, atMentionResult, onEvent);
527
+ return;
528
+ }
529
+ // Add user message to conversation history (with optional images)
530
+ const userMessage = this.createHumanMessage(message, images);
531
+ this.conversationHistory.push(userMessage);
532
+ // Notify start of thinking
533
+ onEvent({ type: EVENT_TYPES.THINKING_START });
534
+ // Start the first LLM call step
535
+ currentStep = this.startLLMStep();
536
+ // Create the stream with conversation history
537
+ const stream = await this.agent.stream({ messages: this.conversationHistory }, {
538
+ streamMode: 'updates',
539
+ recursionLimit: 50,
540
+ signal: abortController.signal // Add abort signal for stream cancellation
541
+ });
542
+ let hasContent = false;
543
+ // Process stream chunks with interruption handling
544
+ for await (const chunk of stream) {
545
+ // Check if stream was aborted
546
+ if (streamAborted || abortController.signal.aborted) {
547
+ if (this.config.debug) {
548
+ logger.debug('Stream processing aborted');
549
+ }
550
+ break;
551
+ }
552
+ // Try to extract token usage from stream chunk
553
+ const tokenUsage = extractTokenUsageFromStreamChunk(chunk, this.config.model, this.config.provider);
554
+ if (tokenUsage && currentStep?.type === 'llm_call') {
555
+ // Update current step with token usage
556
+ currentStep.tokenUsage = tokenUsage;
557
+ this.updateStatsWithTokenUsage(tokenUsage);
558
+ // Store token usage to associate with next tool call
559
+ this.currentLLMTokenUsage = tokenUsage;
560
+ if (this.config.debug) {
561
+ logger.debug(`Token usage: ${tokenUsage.inputTokens} in, ${tokenUsage.outputTokens} out`);
562
+ }
563
+ }
564
+ await this.processStreamChunk(chunk, onEvent, (toolStarted) => {
565
+ if (toolStarted) {
566
+ // Complete current LLM step if it exists
567
+ if (currentStep?.type === 'llm_call') {
484
568
  this.completeStep(currentStep);
485
569
  currentStep = null;
486
- this.stats.successfulTools++;
487
- currentToolCall = null;
488
- // Start new LLM step for next reasoning cycle (processing tool result)
489
- currentStep = this.startLLMStep();
490
- }
491
- });
492
- // Check if we have content
493
- if (chunk.agent?.messages) {
494
- const lastMessage = chunk.agent.messages.at(-1);
495
- if (lastMessage?.content && !hasContent) {
496
- hasContent = true;
497
570
  }
571
+ // Start tool execution step
572
+ currentStep = this.startToolStep(toolStarted);
573
+ currentToolCall = toolStarted;
574
+ this.stats.toolCalls++;
575
+ }
576
+ else if (currentToolCall && currentStep) {
577
+ // Complete tool step
578
+ currentStep.toolSuccess = true;
579
+ this.completeStep(currentStep);
580
+ currentStep = null;
581
+ this.stats.successfulTools++;
582
+ currentToolCall = null;
583
+ // Start new LLM step for next reasoning cycle (processing tool result)
584
+ currentStep = this.startLLMStep();
585
+ }
586
+ });
587
+ // Check if we have content
588
+ if (chunk.agent?.messages) {
589
+ const lastMessage = chunk.agent.messages.at(-1);
590
+ if (lastMessage?.content && !hasContent) {
591
+ hasContent = true;
498
592
  }
499
593
  }
500
- // Complete any remaining step
501
- if (currentStep) {
502
- this.completeStep(currentStep);
503
- }
504
- // Update conversation history with final messages and try to extract any missed token usage
505
- try {
506
- const finalState = await this.agent.getState();
507
- if (finalState?.messages) {
508
- this.conversationHistory = finalState.messages;
509
- // Try to extract token usage from final state if we missed it during streaming
510
- const finalTokenUsage = extractTokenUsageFromFinalState(finalState, this.config.model, this.config.provider);
511
- if (finalTokenUsage && this.currentExecutionSteps.length > 0) {
512
- // Find the last LLM step that doesn't have token usage
513
- for (let i = this.currentExecutionSteps.length - 1; i >= 0; i--) {
514
- const step = this.currentExecutionSteps[i];
515
- if (step.type === 'llm_call' && !step.tokenUsage) {
516
- step.tokenUsage = finalTokenUsage;
517
- this.updateStatsWithTokenUsage(finalTokenUsage);
518
- break;
519
- }
594
+ }
595
+ // Complete any remaining step
596
+ if (currentStep) {
597
+ this.completeStep(currentStep);
598
+ }
599
+ // Update conversation history with final messages and try to extract any missed token usage
600
+ try {
601
+ const finalState = await this.agent.getState();
602
+ if (finalState?.messages) {
603
+ this.conversationHistory = finalState.messages;
604
+ // Try to extract token usage from final state if we missed it during streaming
605
+ const finalTokenUsage = extractTokenUsageFromFinalState(finalState, this.config.model, this.config.provider);
606
+ if (finalTokenUsage && this.currentExecutionSteps.length > 0) {
607
+ // Find the last LLM step that doesn't have token usage
608
+ for (let i = this.currentExecutionSteps.length - 1; i >= 0; i--) {
609
+ const step = this.currentExecutionSteps[i];
610
+ if (step.type === 'llm_call' && !step.tokenUsage) {
611
+ step.tokenUsage = finalTokenUsage;
612
+ this.updateStatsWithTokenUsage(finalTokenUsage);
613
+ break;
520
614
  }
521
615
  }
522
616
  }
523
617
  }
524
- catch {
525
- // If getState fails, continue without updating history
526
- if (this.config.debug) {
527
- logger.debug('Could not get final state, continuing...');
528
- }
618
+ }
619
+ catch {
620
+ // If getState fails, continue without updating history
621
+ if (this.config.debug) {
622
+ logger.debug('Could not get final state, continuing...');
529
623
  }
530
- // Finalize execution statistics
531
- this.stats.executionTime = Date.now() - startTime;
532
- this.stats.executionSteps = [...this.currentExecutionSteps];
533
- // Execute Stop hooks
624
+ }
625
+ // Finalize execution statistics
626
+ this.stats.executionTime = Date.now() - startTime;
627
+ this.stats.executionSteps = [...this.currentExecutionSteps];
628
+ // Execute Stop hooks
629
+ try {
534
630
  if (this.hookExecutor) {
535
631
  try {
536
632
  const stopHookResult = await this.hookExecutor.executeStop(this.currentExecutionSteps, {
@@ -593,8 +689,8 @@ export class CodeMieAgent {
593
689
  }
594
690
  }
595
691
  // Notify thinking end and completion
596
- onEvent({ type: 'thinking_end' });
597
- onEvent({ type: 'complete' });
692
+ onEvent({ type: EVENT_TYPES.THINKING_END });
693
+ onEvent({ type: EVENT_TYPES.COMPLETE });
598
694
  if (this.config.debug) {
599
695
  logger.debug(`Agent completed in ${this.stats.executionTime}ms`);
600
696
  logger.debug(`Total tokens: ${this.stats.totalTokens} (${this.stats.inputTokens} in, ${this.stats.outputTokens} out)`);
@@ -613,7 +709,7 @@ export class CodeMieAgent {
613
709
  logger.debug('Stream aborted by user');
614
710
  }
615
711
  onEvent({
616
- type: 'error',
712
+ type: EVENT_TYPES.ERROR,
617
713
  error: 'Operation interrupted by user'
618
714
  });
619
715
  return; // Don't throw error for user interruptions
@@ -626,7 +722,7 @@ export class CodeMieAgent {
626
722
  logger.debug(`Model: ${this.config.model}`);
627
723
  }
628
724
  onEvent({
629
- type: 'error',
725
+ type: EVENT_TYPES.ERROR,
630
726
  error: errorMessage
631
727
  });
632
728
  throw new CodeMieAgentError(`Agent execution failed: ${errorMessage}`, 'EXECUTION_ERROR', { originalError: error, stats: this.stats });
@@ -656,7 +752,7 @@ export class CodeMieAgent {
656
752
  // Stream content chunks
657
753
  if (lastMessage?.content && typeof lastMessage.content === 'string') {
658
754
  onEvent({
659
- type: 'content_chunk',
755
+ type: EVENT_TYPES.CONTENT_CHUNK,
660
756
  content: lastMessage.content
661
757
  });
662
758
  }
@@ -697,7 +793,7 @@ export class CodeMieAgent {
697
793
  // Use tool name as key since LangGraph may not preserve IDs consistently
698
794
  this.toolCallArgs.set(toolCall.name, toolCall.args);
699
795
  onEvent({
700
- type: 'tool_call_start',
796
+ type: EVENT_TYPES.TOOL_CALL_START,
701
797
  toolName: toolCall.name,
702
798
  toolArgs: toolCall.args
703
799
  });
@@ -758,7 +854,7 @@ export class CodeMieAgent {
758
854
  }
759
855
  }
760
856
  onEvent({
761
- type: 'tool_call_result',
857
+ type: EVENT_TYPES.TOOL_CALL_RESULT,
762
858
  toolName,
763
859
  result,
764
860
  toolMetadata
@@ -775,7 +871,7 @@ export class CodeMieAgent {
775
871
  }
776
872
  // Don't throw here, just log - let the main stream continue
777
873
  onEvent({
778
- type: 'error',
874
+ type: EVENT_TYPES.ERROR,
779
875
  error: `Stream processing error: ${error instanceof Error ? error.message : String(error)}`
780
876
  });
781
877
  }
@@ -903,7 +999,7 @@ export class CodeMieAgent {
903
999
  }
904
1000
  else {
905
1001
  // Check if the previous step was a tool execution
906
- const prevStep = this.currentExecutionSteps[this.currentExecutionSteps.length - 1];
1002
+ const prevStep = this.currentExecutionSteps.at(-1);
907
1003
  llmContext = (prevStep?.type === 'tool_execution') ? 'processing_tool_result' : 'final_response';
908
1004
  }
909
1005
  const step = {