@synergenius/flow-weaver-pack-weaver 0.9.0 → 0.9.4

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 (235) hide show
  1. package/dist/bot/ai-client.d.ts +22 -2
  2. package/dist/bot/ai-client.d.ts.map +1 -1
  3. package/dist/bot/ai-client.js +168 -20
  4. package/dist/bot/ai-client.js.map +1 -1
  5. package/dist/bot/ansi.d.ts +13 -0
  6. package/dist/bot/ansi.d.ts.map +1 -0
  7. package/dist/bot/ansi.js +13 -0
  8. package/dist/bot/ansi.js.map +1 -0
  9. package/dist/bot/assistant-core.d.ts +25 -0
  10. package/dist/bot/assistant-core.d.ts.map +1 -0
  11. package/dist/bot/assistant-core.js +272 -0
  12. package/dist/bot/assistant-core.js.map +1 -0
  13. package/dist/bot/assistant-tools.d.ts +10 -0
  14. package/dist/bot/assistant-tools.d.ts.map +1 -0
  15. package/dist/bot/assistant-tools.js +324 -0
  16. package/dist/bot/assistant-tools.js.map +1 -0
  17. package/dist/bot/audit-logger.d.ts.map +1 -1
  18. package/dist/bot/audit-logger.js +9 -5
  19. package/dist/bot/audit-logger.js.map +1 -1
  20. package/dist/bot/bot-manager.d.ts +49 -0
  21. package/dist/bot/bot-manager.d.ts.map +1 -0
  22. package/dist/bot/bot-manager.js +279 -0
  23. package/dist/bot/bot-manager.js.map +1 -0
  24. package/dist/bot/child-process-tracker.d.ts +6 -0
  25. package/dist/bot/child-process-tracker.d.ts.map +1 -0
  26. package/dist/bot/child-process-tracker.js +35 -0
  27. package/dist/bot/child-process-tracker.js.map +1 -0
  28. package/dist/bot/cli-provider.d.ts.map +1 -1
  29. package/dist/bot/cli-provider.js +13 -8
  30. package/dist/bot/cli-provider.js.map +1 -1
  31. package/dist/bot/conversation-store.d.ts +40 -0
  32. package/dist/bot/conversation-store.d.ts.map +1 -0
  33. package/dist/bot/conversation-store.js +182 -0
  34. package/dist/bot/conversation-store.js.map +1 -0
  35. package/dist/bot/error-classifier.d.ts +27 -0
  36. package/dist/bot/error-classifier.d.ts.map +1 -0
  37. package/dist/bot/error-classifier.js +71 -0
  38. package/dist/bot/error-classifier.js.map +1 -0
  39. package/dist/bot/error-guide.d.ts +5 -0
  40. package/dist/bot/error-guide.d.ts.map +1 -0
  41. package/dist/bot/error-guide.js +5 -0
  42. package/dist/bot/error-guide.js.map +1 -0
  43. package/dist/bot/knowledge-store.d.ts +17 -0
  44. package/dist/bot/knowledge-store.d.ts.map +1 -0
  45. package/dist/bot/knowledge-store.js +53 -0
  46. package/dist/bot/knowledge-store.js.map +1 -0
  47. package/dist/bot/paths.d.ts +11 -0
  48. package/dist/bot/paths.d.ts.map +1 -0
  49. package/dist/bot/paths.js +26 -0
  50. package/dist/bot/paths.js.map +1 -0
  51. package/dist/bot/retry-utils.d.ts +5 -0
  52. package/dist/bot/retry-utils.d.ts.map +1 -0
  53. package/dist/bot/retry-utils.js +5 -0
  54. package/dist/bot/retry-utils.js.map +1 -0
  55. package/dist/bot/runner.d.ts.map +1 -1
  56. package/dist/bot/runner.js +12 -1
  57. package/dist/bot/runner.js.map +1 -1
  58. package/dist/bot/safety.d.ts +10 -0
  59. package/dist/bot/safety.d.ts.map +1 -0
  60. package/dist/bot/safety.js +14 -0
  61. package/dist/bot/safety.js.map +1 -0
  62. package/dist/bot/session-state.d.ts.map +1 -1
  63. package/dist/bot/session-state.js +3 -1
  64. package/dist/bot/session-state.js.map +1 -1
  65. package/dist/bot/steering.js +2 -2
  66. package/dist/bot/steering.js.map +1 -1
  67. package/dist/bot/step-executor.d.ts +10 -5
  68. package/dist/bot/step-executor.d.ts.map +1 -1
  69. package/dist/bot/step-executor.js +252 -3
  70. package/dist/bot/step-executor.js.map +1 -1
  71. package/dist/bot/system-prompt.d.ts +1 -1
  72. package/dist/bot/system-prompt.d.ts.map +1 -1
  73. package/dist/bot/system-prompt.js +69 -43
  74. package/dist/bot/system-prompt.js.map +1 -1
  75. package/dist/bot/task-decomposer.d.ts +24 -0
  76. package/dist/bot/task-decomposer.d.ts.map +1 -0
  77. package/dist/bot/task-decomposer.js +75 -0
  78. package/dist/bot/task-decomposer.js.map +1 -0
  79. package/dist/bot/task-queue.d.ts +17 -4
  80. package/dist/bot/task-queue.d.ts.map +1 -1
  81. package/dist/bot/task-queue.js +83 -5
  82. package/dist/bot/task-queue.js.map +1 -1
  83. package/dist/bot/terminal-renderer.d.ts +60 -0
  84. package/dist/bot/terminal-renderer.d.ts.map +1 -0
  85. package/dist/bot/terminal-renderer.js +204 -0
  86. package/dist/bot/terminal-renderer.js.map +1 -0
  87. package/dist/bot/tool-registry.d.ts +24 -0
  88. package/dist/bot/tool-registry.d.ts.map +1 -0
  89. package/dist/bot/tool-registry.js +458 -0
  90. package/dist/bot/tool-registry.js.map +1 -0
  91. package/dist/bot/types.d.ts +7 -0
  92. package/dist/bot/types.d.ts.map +1 -1
  93. package/dist/bot/weaver-tools.d.ts +18 -0
  94. package/dist/bot/weaver-tools.d.ts.map +1 -0
  95. package/dist/bot/weaver-tools.js +124 -0
  96. package/dist/bot/weaver-tools.js.map +1 -0
  97. package/dist/cli-bridge.d.ts.map +1 -1
  98. package/dist/cli-bridge.js +5 -1
  99. package/dist/cli-bridge.js.map +1 -1
  100. package/dist/cli-handlers.d.ts +13 -1
  101. package/dist/cli-handlers.d.ts.map +1 -1
  102. package/dist/cli-handlers.js +615 -48
  103. package/dist/cli-handlers.js.map +1 -1
  104. package/dist/mcp-tools.js +2 -2
  105. package/dist/mcp-tools.js.map +1 -1
  106. package/dist/node-types/abort-task.d.ts.map +1 -1
  107. package/dist/node-types/abort-task.js +4 -3
  108. package/dist/node-types/abort-task.js.map +1 -1
  109. package/dist/node-types/agent-execute.d.ts +38 -0
  110. package/dist/node-types/agent-execute.d.ts.map +1 -0
  111. package/dist/node-types/agent-execute.js +252 -0
  112. package/dist/node-types/agent-execute.js.map +1 -0
  113. package/dist/node-types/bot-report.d.ts +5 -3
  114. package/dist/node-types/bot-report.d.ts.map +1 -1
  115. package/dist/node-types/bot-report.js +39 -7
  116. package/dist/node-types/bot-report.js.map +1 -1
  117. package/dist/node-types/build-context.d.ts +3 -3
  118. package/dist/node-types/build-context.d.ts.map +1 -1
  119. package/dist/node-types/build-context.js +108 -24
  120. package/dist/node-types/build-context.js.map +1 -1
  121. package/dist/node-types/detect-provider.d.ts +2 -2
  122. package/dist/node-types/detect-provider.d.ts.map +1 -1
  123. package/dist/node-types/detect-provider.js +3 -1
  124. package/dist/node-types/detect-provider.js.map +1 -1
  125. package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
  126. package/dist/node-types/exec-validate-retry.js +43 -6
  127. package/dist/node-types/exec-validate-retry.js.map +1 -1
  128. package/dist/node-types/execute-plan.d.ts.map +1 -1
  129. package/dist/node-types/execute-plan.js +31 -8
  130. package/dist/node-types/execute-plan.js.map +1 -1
  131. package/dist/node-types/execute-target.d.ts.map +1 -1
  132. package/dist/node-types/execute-target.js +3 -1
  133. package/dist/node-types/execute-target.js.map +1 -1
  134. package/dist/node-types/fix-errors.d.ts.map +1 -1
  135. package/dist/node-types/fix-errors.js +21 -5
  136. package/dist/node-types/fix-errors.js.map +1 -1
  137. package/dist/node-types/genesis-observe.d.ts.map +1 -1
  138. package/dist/node-types/genesis-observe.js +3 -1
  139. package/dist/node-types/genesis-observe.js.map +1 -1
  140. package/dist/node-types/genesis-report.js +4 -1
  141. package/dist/node-types/genesis-report.js.map +1 -1
  142. package/dist/node-types/git-ops.d.ts.map +1 -1
  143. package/dist/node-types/git-ops.js +98 -4
  144. package/dist/node-types/git-ops.js.map +1 -1
  145. package/dist/node-types/index.d.ts +2 -0
  146. package/dist/node-types/index.d.ts.map +1 -1
  147. package/dist/node-types/index.js +2 -0
  148. package/dist/node-types/index.js.map +1 -1
  149. package/dist/node-types/load-config.d.ts +2 -2
  150. package/dist/node-types/load-config.d.ts.map +1 -1
  151. package/dist/node-types/load-config.js.map +1 -1
  152. package/dist/node-types/plan-task.d.ts.map +1 -1
  153. package/dist/node-types/plan-task.js +14 -2
  154. package/dist/node-types/plan-task.js.map +1 -1
  155. package/dist/node-types/read-workflow.js +8 -2
  156. package/dist/node-types/read-workflow.js.map +1 -1
  157. package/dist/node-types/receive-task.d.ts.map +1 -1
  158. package/dist/node-types/receive-task.js +35 -26
  159. package/dist/node-types/receive-task.js.map +1 -1
  160. package/dist/node-types/send-notify.js +2 -1
  161. package/dist/node-types/send-notify.js.map +1 -1
  162. package/dist/node-types/validate-gate.d.ts +18 -0
  163. package/dist/node-types/validate-gate.d.ts.map +1 -0
  164. package/dist/node-types/validate-gate.js +96 -0
  165. package/dist/node-types/validate-gate.js.map +1 -0
  166. package/dist/workflows/genesis-task.d.ts +20 -12
  167. package/dist/workflows/genesis-task.d.ts.map +1 -1
  168. package/dist/workflows/genesis-task.js +20 -12
  169. package/dist/workflows/genesis-task.js.map +1 -1
  170. package/dist/workflows/weaver-agent.d.ts +35 -0
  171. package/dist/workflows/weaver-agent.d.ts.map +1 -0
  172. package/dist/workflows/weaver-agent.js +777 -0
  173. package/dist/workflows/weaver-agent.js.map +1 -0
  174. package/dist/workflows/weaver-bot-batch.d.ts +19 -26
  175. package/dist/workflows/weaver-bot-batch.d.ts.map +1 -1
  176. package/dist/workflows/weaver-bot-batch.js +1043 -27
  177. package/dist/workflows/weaver-bot-batch.js.map +1 -1
  178. package/dist/workflows/weaver-bot.d.ts +21 -35
  179. package/dist/workflows/weaver-bot.d.ts.map +1 -1
  180. package/dist/workflows/weaver-bot.js +1119 -36
  181. package/dist/workflows/weaver-bot.js.map +1 -1
  182. package/flowweaver.manifest.json +21 -1
  183. package/package.json +5 -2
  184. package/src/bot/ai-client.ts +180 -19
  185. package/src/bot/ansi.ts +12 -0
  186. package/src/bot/assistant-core.ts +312 -0
  187. package/src/bot/assistant-tools.ts +318 -0
  188. package/src/bot/audit-logger.ts +6 -5
  189. package/src/bot/bot-manager.ts +293 -0
  190. package/src/bot/child-process-tracker.ts +40 -0
  191. package/src/bot/cli-provider.ts +13 -8
  192. package/src/bot/conversation-store.ts +222 -0
  193. package/src/bot/error-classifier.ts +90 -0
  194. package/src/bot/error-guide.ts +4 -0
  195. package/src/bot/knowledge-store.ts +59 -0
  196. package/src/bot/paths.ts +27 -0
  197. package/src/bot/retry-utils.ts +4 -0
  198. package/src/bot/runner.ts +12 -1
  199. package/src/bot/safety.ts +16 -0
  200. package/src/bot/session-state.ts +2 -1
  201. package/src/bot/steering.ts +2 -2
  202. package/src/bot/step-executor.ts +313 -5
  203. package/src/bot/system-prompt.ts +70 -47
  204. package/src/bot/task-decomposer.ts +100 -0
  205. package/src/bot/task-queue.ts +100 -8
  206. package/src/bot/terminal-renderer.ts +238 -0
  207. package/src/bot/tool-registry.ts +477 -0
  208. package/src/bot/types.ts +8 -0
  209. package/src/bot/weaver-tools.ts +134 -0
  210. package/src/cli-bridge.ts +7 -1
  211. package/src/cli-handlers.ts +624 -48
  212. package/src/mcp-tools.ts +2 -2
  213. package/src/node-types/abort-task.ts +5 -4
  214. package/src/node-types/agent-execute.ts +303 -0
  215. package/src/node-types/bot-report.ts +40 -9
  216. package/src/node-types/build-context.ts +112 -25
  217. package/src/node-types/detect-provider.ts +4 -3
  218. package/src/node-types/exec-validate-retry.ts +47 -8
  219. package/src/node-types/execute-plan.ts +32 -8
  220. package/src/node-types/execute-target.ts +2 -1
  221. package/src/node-types/fix-errors.ts +20 -5
  222. package/src/node-types/genesis-observe.ts +2 -1
  223. package/src/node-types/genesis-report.ts +1 -1
  224. package/src/node-types/git-ops.ts +93 -4
  225. package/src/node-types/index.ts +2 -0
  226. package/src/node-types/load-config.ts +3 -3
  227. package/src/node-types/plan-task.ts +15 -3
  228. package/src/node-types/read-workflow.ts +2 -2
  229. package/src/node-types/receive-task.ts +31 -26
  230. package/src/node-types/send-notify.ts +1 -1
  231. package/src/node-types/validate-gate.ts +112 -0
  232. package/src/workflows/genesis-task.ts +20 -12
  233. package/src/workflows/weaver-agent.ts +799 -0
  234. package/src/workflows/weaver-bot-batch.ts +1049 -27
  235. package/src/workflows/weaver-bot.ts +1123 -36
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Assistant Core — provider-agnostic conversational loop.
3
+ * The user types, the assistant responds with text and tool calls.
4
+ * UI-agnostic: terminal is one frontend, platform AI chat is another.
5
+ *
6
+ * Supports two provider modes:
7
+ * - CLI provider: tools handled internally via MCP bridge (tool_result events)
8
+ * - API provider: tools collected and executed manually (tool_use_start/end events)
9
+ */
10
+ import * as readline from 'node:readline';
11
+ import { runAgentLoop, } from '@synergenius/flow-weaver/agent';
12
+ import { c } from './ansi.js';
13
+ import { VERBOSE_TOOL_NAMES } from './tool-registry.js';
14
+ import { generateToolPromptSection, generateVerboseToolList } from './tool-registry.js';
15
+ import { CHARS_PER_TOKEN } from './safety.js';
16
+ const DEFAULT_SYSTEM_PROMPT = `You are Weaver Assistant — a director-level AI that manages bot workers and the flow-weaver ecosystem.
17
+
18
+ You help users with the following tools (grouped by category):
19
+
20
+ ${generateToolPromptSection()}
21
+ USE TOOLS to fulfill requests. Don't describe what you'd do — actually do it.
22
+ When the user asks to "start a bot", call bot_spawn.
23
+ When they ask for status, call bot_list or bot_status.
24
+ When they ask to add tasks, call queue_add or queue_add_batch.
25
+
26
+ Be concise. Show results, not explanations.
27
+ The user is a senior engineer — don't over-explain.
28
+
29
+ CRITICAL: You are running in a terminal. Do NOT use markdown formatting.
30
+ - No **bold**, no _italic_, no \`backticks\`, no tables with |pipes|
31
+ - No emoji (✅, 🔴, etc.)
32
+ - Use plain text with indentation for structure
33
+ - Use UPPERCASE or quotes for emphasis instead of markdown
34
+ - For lists, use simple dashes: - item
35
+ - For key-value pairs, use: key: value (one per line)
36
+ - Keep output scannable and clean
37
+
38
+ IMPORTANT: Some tool results are displayed DIRECTLY to the user in the terminal.
39
+ These tools show FULL output — the user already sees everything:
40
+ ${generateVerboseToolList()}
41
+ For these: do NOT repeat, summarize, or reformat the output. Just add a brief comment if needed.
42
+ Never re-type ASCII art, diagrams, or large text blocks that were already printed.
43
+
44
+ Other tools show only a short preview.
45
+ For those: you may summarize or explain the result as needed.`;
46
+ export async function runAssistant(opts) {
47
+ const { provider, tools, executor, projectDir } = opts;
48
+ // Build system prompt — include project plan if it exists
49
+ let systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
50
+ try {
51
+ const fs = await import('node:fs');
52
+ const path = await import('node:path');
53
+ const planPath = path.resolve(projectDir, '.weaver-plan.md');
54
+ if (fs.existsSync(planPath)) {
55
+ const plan = fs.readFileSync(planPath, 'utf-8').trim();
56
+ systemPrompt += '\n\n## Project Plan & Vision\n\nAll bots you spawn and tasks you queue MUST align with this plan.\n\n' + plan;
57
+ }
58
+ }
59
+ catch { /* plan not available */ }
60
+ const out = (s) => process.stderr.write(s);
61
+ // Persistent conversation store
62
+ const { ConversationStore } = await import('./conversation-store.js');
63
+ const store = new ConversationStore();
64
+ // Resolve conversation: resume, new, or auto
65
+ let conversation;
66
+ const history = [];
67
+ if (opts.resumeId) {
68
+ const existing = store.get(opts.resumeId);
69
+ if (!existing) {
70
+ out(` ${c.red('Conversation not found:')} ${opts.resumeId}\n`);
71
+ return;
72
+ }
73
+ conversation = existing;
74
+ history.push(...store.loadMessages(existing.id));
75
+ compressHistory(history);
76
+ }
77
+ else if (opts.newConversation) {
78
+ conversation = store.create(projectDir);
79
+ }
80
+ else {
81
+ // Auto-resume most recent if within 1 hour, else create new
82
+ const recent = store.getMostRecent();
83
+ if (recent && Date.now() - recent.lastMessageAt < 3600_000) {
84
+ conversation = recent;
85
+ history.push(...store.loadMessages(recent.id));
86
+ compressHistory(history);
87
+ }
88
+ else {
89
+ conversation = store.create(projectDir);
90
+ }
91
+ }
92
+ // Welcome
93
+ out(`\n ${c.bold('weaver assistant')}\n`);
94
+ out(` ${c.dim(`Project: ${projectDir}`)}\n`);
95
+ if (conversation.title) {
96
+ out(` ${c.dim(`Resuming: "${conversation.title}" (${conversation.messageCount} messages)`)}\n`);
97
+ }
98
+ else {
99
+ out(` ${c.dim(`Conversation: ${conversation.id}`)}\n`);
100
+ }
101
+ out(` ${c.dim('Type your request. Ctrl+C to exit.')}\n\n`);
102
+ // Input source
103
+ const rl = opts.inputMessages
104
+ ? null
105
+ : readline.createInterface({ input: process.stdin, output: process.stderr, prompt: `${c.cyan('❯')} ` });
106
+ const getNextInput = opts.inputMessages
107
+ ? (() => {
108
+ let i = 0;
109
+ return () => Promise.resolve(opts.inputMessages[i++] ?? null);
110
+ })()
111
+ : () => new Promise((resolve) => {
112
+ rl.prompt();
113
+ rl.once('line', (line) => resolve(line.trim() || null));
114
+ rl.once('close', () => resolve(null));
115
+ });
116
+ const onStreamEvent = (event) => {
117
+ if (event.type === 'text_delta') {
118
+ out(event.text);
119
+ }
120
+ else if (event.type === 'thinking_delta') {
121
+ out(c.dim(event.text));
122
+ }
123
+ };
124
+ const onToolEvent = (event) => {
125
+ if (event.type === 'tool_call_start') {
126
+ const preview = toolPreview(event.name, event.args ?? {});
127
+ out(`\n ${c.cyan('◆')} ${event.name}${preview ? c.dim(`(${preview})`) : ''}\n`);
128
+ }
129
+ if (event.type === 'tool_call_result') {
130
+ const icon = event.isError ? c.red('✗') : c.dim('→');
131
+ const raw = event.result ?? '';
132
+ // Show full output for diagram/describe/docs tools; truncate others
133
+ const isVerboseTool = VERBOSE_TOOL_NAMES.has(event.name);
134
+ if (isVerboseTool && raw.length > 150) {
135
+ out(` ${icon}\n${raw}\n`);
136
+ }
137
+ else {
138
+ const result = raw.replace(/\n/g, ' ').slice(0, 200);
139
+ out(` ${icon} ${result}\n`);
140
+ }
141
+ }
142
+ };
143
+ // Main conversation loop
144
+ while (true) {
145
+ const input = await getNextInput();
146
+ if (input === null)
147
+ break;
148
+ if (!input.trim())
149
+ continue;
150
+ out('\n');
151
+ // Add user message to history
152
+ history.push({ role: 'user', content: input });
153
+ try {
154
+ const result = await runAgentLoop(provider, tools, executor, history, // full conversation history
155
+ {
156
+ systemPrompt,
157
+ maxIterations: 20,
158
+ onStreamEvent,
159
+ onToolEvent,
160
+ });
161
+ // Collect new messages from the agent loop
162
+ const newMessages = [];
163
+ if (result.messages.length > history.length) {
164
+ for (let i = history.length; i < result.messages.length; i++) {
165
+ history.push(result.messages[i]);
166
+ newMessages.push(result.messages[i]);
167
+ }
168
+ }
169
+ // Persist to disk
170
+ const tokensUsed = result.usage.promptTokens + result.usage.completionTokens;
171
+ store.appendMessages(conversation.id, [{ role: 'user', content: input }, ...newMessages]);
172
+ store.updateAfterTurn(conversation.id, [{ role: 'user', content: input }, ...newMessages], tokensUsed);
173
+ // Auto-title from first assistant response
174
+ if (!conversation.title) {
175
+ const firstAssistant = newMessages.find(m => m.role === 'assistant');
176
+ if (firstAssistant && typeof firstAssistant.content === 'string') {
177
+ const title = firstAssistant.content.split('\n')[0].slice(0, 80).trim();
178
+ if (title) {
179
+ conversation.title = title;
180
+ store.setTitle(conversation.id, title);
181
+ }
182
+ }
183
+ }
184
+ // Token-aware compression
185
+ compressHistory(history);
186
+ if (!result.success && result.summary) {
187
+ out(`\n ${c.red(result.summary)}\n`);
188
+ }
189
+ }
190
+ catch (err) {
191
+ const msg = err instanceof Error ? err.message : String(err);
192
+ out(`\n ${c.red('Error:')} ${msg}\n`);
193
+ }
194
+ out('\n');
195
+ }
196
+ rl?.close();
197
+ out(`\n ${c.dim('Goodbye.')}\n\n`);
198
+ }
199
+ function toolPreview(name, args) {
200
+ if (args.name)
201
+ return String(args.name);
202
+ if (args.bot)
203
+ return String(args.bot);
204
+ if (args.file)
205
+ return String(args.file).split('/').pop() ?? '';
206
+ if (args.path)
207
+ return String(args.path).split('/').pop() ?? '';
208
+ if (args.instruction)
209
+ return String(args.instruction).slice(0, 40);
210
+ if (args.command)
211
+ return String(args.command).slice(0, 40);
212
+ return '';
213
+ }
214
+ // --- Token-aware history compression ---
215
+ // Budget: leave room for system prompt (~2k) + tools (~3k) + response (~4k)
216
+ const MAX_HISTORY_TOKENS = 80_000;
217
+ // When compressing, truncate tool results to this size
218
+ const COMPRESSED_TOOL_RESULT_SIZE = 200;
219
+ function estimateTokens(msg) {
220
+ const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
221
+ return Math.ceil(content.length / CHARS_PER_TOKEN);
222
+ }
223
+ function totalTokens(history) {
224
+ return history.reduce((sum, m) => sum + estimateTokens(m), 0);
225
+ }
226
+ /**
227
+ * Compress conversation history to stay within token budget.
228
+ * Strategy (progressive, stops as soon as under budget):
229
+ * 1. Truncate long tool results to 200 chars (keep tool call structure)
230
+ * 2. Summarize old tool results to just "[tool_name: ok/error]"
231
+ * 3. Drop oldest turns (keep most recent 10 turns)
232
+ */
233
+ function compressHistory(history) {
234
+ if (totalTokens(history) <= MAX_HISTORY_TOKENS)
235
+ return;
236
+ // Phase 1: Truncate tool results older than last 6 messages
237
+ const cutoff = Math.max(0, history.length - 6);
238
+ for (let i = 0; i < cutoff; i++) {
239
+ const msg = history[i];
240
+ if (msg.role === 'tool' && typeof msg.content === 'string' && msg.content.length > COMPRESSED_TOOL_RESULT_SIZE) {
241
+ msg.content = msg.content.slice(0, COMPRESSED_TOOL_RESULT_SIZE) + '... (truncated)';
242
+ }
243
+ }
244
+ if (totalTokens(history) <= MAX_HISTORY_TOKENS)
245
+ return;
246
+ // Phase 2: Summarize all tool results older than last 10 messages
247
+ const summaryCutoff = Math.max(0, history.length - 10);
248
+ for (let i = 0; i < summaryCutoff; i++) {
249
+ const msg = history[i];
250
+ if (msg.role === 'tool' && typeof msg.content === 'string') {
251
+ const isError = msg.content.toLowerCase().includes('error') || msg.content.toLowerCase().includes('not found');
252
+ msg.content = isError ? '(error — details truncated)' : '(ok — details truncated)';
253
+ }
254
+ // Also truncate long assistant messages
255
+ if (msg.role === 'assistant' && typeof msg.content === 'string' && msg.content.length > 500) {
256
+ msg.content = msg.content.slice(0, 500) + '... (truncated)';
257
+ }
258
+ }
259
+ if (totalTokens(history) <= MAX_HISTORY_TOKENS)
260
+ return;
261
+ // Phase 3: Drop oldest turns, keep last 10 messages
262
+ const keep = 10;
263
+ if (history.length > keep) {
264
+ // Insert a summary of what was dropped
265
+ const dropped = history.length - keep;
266
+ history.splice(0, dropped, {
267
+ role: 'user',
268
+ content: `(${dropped} earlier messages compressed. Key context: this is an ongoing assistant session managing bots and workflows.)`,
269
+ });
270
+ }
271
+ }
272
+ //# sourceMappingURL=assistant-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant-core.js","sourceRoot":"","sources":["../../src/bot/assistant-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Assistant tool definitions and executor.
3
+ * These are the tools the AI assistant uses to manage bots,
4
+ * queues, and the flow-weaver ecosystem.
5
+ */
6
+ import type { ToolExecutor } from '@synergenius/flow-weaver/agent';
7
+ import { ASSISTANT_TOOLS } from './tool-registry.js';
8
+ export { ASSISTANT_TOOLS };
9
+ export declare function createAssistantExecutor(projectDir: string): ToolExecutor;
10
+ //# sourceMappingURL=assistant-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant-tools.d.ts","sourceRoot":"","sources":["../../src/bot/assistant-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAMnF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,CAAC;AAS3B,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAqSxE"}
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Assistant tool definitions and executor.
3
+ * These are the tools the AI assistant uses to manage bots,
4
+ * queues, and the flow-weaver ecosystem.
5
+ */
6
+ import { BotManager } from './bot-manager.js';
7
+ import { execFileSync } from 'node:child_process';
8
+ import * as fs from 'node:fs';
9
+ import * as os from 'node:os';
10
+ import * as path from 'node:path';
11
+ import { ASSISTANT_TOOLS } from './tool-registry.js';
12
+ import { isBlockedCommand, isBlockedUrl } from './safety.js';
13
+ export { ASSISTANT_TOOLS };
14
+ // Shared bot manager instance
15
+ let manager = null;
16
+ function getManager() {
17
+ if (!manager)
18
+ manager = new BotManager();
19
+ return manager;
20
+ }
21
+ export function createAssistantExecutor(projectDir) {
22
+ const mgr = getManager();
23
+ return async (name, args) => {
24
+ try {
25
+ switch (name) {
26
+ // Bot management
27
+ case 'bot_spawn': {
28
+ const botName = String(args.name ?? `bot-${Date.now()}`);
29
+ const dir = String(args.project_dir ?? projectDir);
30
+ const bot = mgr.spawn(botName, {
31
+ projectDir: dir,
32
+ parallel: args.parallel,
33
+ deadline: args.deadline,
34
+ branch: args.branch,
35
+ });
36
+ return { result: JSON.stringify(bot), isError: false };
37
+ }
38
+ case 'bot_list': {
39
+ const bots = mgr.list();
40
+ if (bots.length === 0)
41
+ return { result: 'No bots running.', isError: false };
42
+ const lines = bots.map(b => {
43
+ const uptime = Math.round((Date.now() - b.startedAt) / 1000);
44
+ return `${b.name}: ${b.status} (pid ${b.pid}, ${uptime}s uptime)`;
45
+ });
46
+ return { result: lines.join('\n'), isError: false };
47
+ }
48
+ case 'bot_status': {
49
+ const botName = String(args.name);
50
+ const bot = mgr.get(botName);
51
+ if (!bot)
52
+ return { result: `Bot "${botName}" not found.`, isError: true };
53
+ const queue = mgr.getQueue(botName);
54
+ const tasks = await queue.list();
55
+ const pending = tasks.filter(t => t.status === 'pending').length;
56
+ const running = tasks.filter(t => t.status === 'running').length;
57
+ const completed = tasks.filter(t => t.status === 'completed').length;
58
+ const failed = tasks.filter(t => t.status === 'failed').length;
59
+ const failedTasks = tasks.filter(t => t.status === 'failed');
60
+ let result = `Bot "${botName}": ${bot.status}\n`;
61
+ result += `Tasks: ${completed} completed, ${failed} failed, ${running} running, ${pending} pending\n`;
62
+ if (failedTasks.length > 0) {
63
+ result += `\nFailed tasks:\n`;
64
+ for (const t of failedTasks) {
65
+ result += ` - ${t.instruction.slice(0, 80)}\n`;
66
+ }
67
+ }
68
+ return { result, isError: false };
69
+ }
70
+ case 'bot_pause': {
71
+ await mgr.steer(String(args.name), 'pause');
72
+ return { result: `Paused bot "${args.name}".`, isError: false };
73
+ }
74
+ case 'bot_resume': {
75
+ await mgr.steer(String(args.name), 'resume');
76
+ return { result: `Resumed bot "${args.name}".`, isError: false };
77
+ }
78
+ case 'bot_stop': {
79
+ mgr.stop(String(args.name));
80
+ return { result: `Stopping bot "${args.name}" (will finish current task).`, isError: false };
81
+ }
82
+ case 'bot_logs': {
83
+ const logs = mgr.logs(String(args.name), args.lines ?? 30);
84
+ return { result: logs || '(no output yet)', isError: false };
85
+ }
86
+ // Queue management
87
+ case 'queue_add': {
88
+ const queue = mgr.getQueue(String(args.bot));
89
+ const { id, duplicate } = await queue.add({
90
+ instruction: String(args.instruction),
91
+ targets: args.targets,
92
+ priority: 0,
93
+ });
94
+ if (duplicate)
95
+ return { result: `Task already queued (${id}).`, isError: false };
96
+ return { result: `Added task ${id} to "${args.bot}" queue.`, isError: false };
97
+ }
98
+ case 'queue_add_batch': {
99
+ const queue = mgr.getQueue(String(args.bot));
100
+ const tasks = args.tasks;
101
+ let added = 0, skipped = 0;
102
+ for (const t of tasks) {
103
+ const { duplicate } = await queue.add({ instruction: t.instruction, targets: t.targets, priority: 0 });
104
+ if (duplicate)
105
+ skipped++;
106
+ else
107
+ added++;
108
+ }
109
+ const msg = skipped > 0 ? `Added ${added} tasks, ${skipped} duplicates skipped.` : `Added ${added} tasks to "${args.bot}" queue.`;
110
+ return { result: msg, isError: false };
111
+ }
112
+ case 'queue_list': {
113
+ const queue = mgr.getQueue(String(args.bot));
114
+ const tasks = await queue.list();
115
+ if (tasks.length === 0)
116
+ return { result: 'Queue is empty.', isError: false };
117
+ const lines = tasks.map(t => `[${t.status}] ${t.instruction.slice(0, 70)}`);
118
+ return { result: lines.join('\n'), isError: false };
119
+ }
120
+ case 'queue_retry': {
121
+ const queue = mgr.getQueue(String(args.bot));
122
+ const count = await queue.retryAll();
123
+ return { result: `Reset ${count} failed task(s) to pending.`, isError: false };
124
+ }
125
+ // Flow-weaver tools
126
+ case 'fw_validate': {
127
+ const output = execFileSync('npx', ['flow-weaver', 'validate', String(args.path)], {
128
+ encoding: 'utf-8', cwd: projectDir, timeout: 30_000, stdio: ['pipe', 'pipe', 'pipe'],
129
+ });
130
+ return { result: output.trim() || 'Validation complete.', isError: false };
131
+ }
132
+ case 'fw_diagram': {
133
+ const output = execFileSync('npx', ['flow-weaver', 'diagram', String(args.file), '--format', 'ascii-compact'], {
134
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
135
+ });
136
+ return { result: output.trim(), isError: false };
137
+ }
138
+ case 'fw_describe': {
139
+ const output = execFileSync('npx', ['flow-weaver', 'describe', String(args.file)], {
140
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
141
+ });
142
+ return { result: output.trim(), isError: false };
143
+ }
144
+ case 'fw_docs': {
145
+ const output = execFileSync('npx', ['flow-weaver', 'docs', String(args.topic), '--compact'], {
146
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
147
+ });
148
+ return { result: output.trim().slice(0, 5000), isError: false };
149
+ }
150
+ // Project tools
151
+ case 'read_file': {
152
+ const filePath = path.isAbsolute(String(args.file)) ? String(args.file) : path.resolve(projectDir, String(args.file));
153
+ const stat = fs.statSync(filePath);
154
+ if (stat.isDirectory()) {
155
+ const entries = fs.readdirSync(filePath).slice(0, 100);
156
+ return { result: `Directory listing (${entries.length} entries):\n${entries.join('\n')}`, isError: false };
157
+ }
158
+ if (stat.size > 1_048_576)
159
+ return { result: 'File too large (>1MB).', isError: true };
160
+ return { result: fs.readFileSync(filePath, 'utf-8'), isError: false };
161
+ }
162
+ case 'list_files': {
163
+ const dir = path.isAbsolute(String(args.directory)) ? String(args.directory) : path.resolve(projectDir, String(args.directory));
164
+ if (!fs.existsSync(dir))
165
+ return { result: `Directory not found: ${dir}`, isError: true };
166
+ let entries = fs.readdirSync(dir, { recursive: false });
167
+ if (args.pattern) {
168
+ const re = new RegExp(String(args.pattern));
169
+ entries = entries.filter(e => re.test(e));
170
+ }
171
+ return { result: entries.slice(0, 200).join('\n') || '(empty)', isError: false };
172
+ }
173
+ case 'run_shell': {
174
+ const cmd = String(args.command);
175
+ // Safety: block destructive commands
176
+ if (isBlockedCommand(cmd)) {
177
+ return { result: `Blocked: "${cmd}" is not allowed.`, isError: true };
178
+ }
179
+ const output = execFileSync('sh', ['-c', cmd], {
180
+ encoding: 'utf-8', cwd: projectDir, timeout: 30_000, stdio: ['pipe', 'pipe', 'pipe'],
181
+ });
182
+ return { result: output.trim().slice(0, 5000) || '(no output)', isError: false };
183
+ }
184
+ // Conversation management
185
+ case 'conversation_list': {
186
+ const { ConversationStore } = await import('./conversation-store.js');
187
+ const cStore = new ConversationStore();
188
+ const convos = cStore.list();
189
+ if (convos.length === 0)
190
+ return { result: 'No saved conversations.', isError: false };
191
+ const lines = convos.map(cv => {
192
+ const ago = Math.round((Date.now() - cv.lastMessageAt) / 60_000);
193
+ const agoStr = ago < 60 ? `${ago}m ago` : ago < 1440 ? `${Math.round(ago / 60)}h ago` : `${Math.round(ago / 1440)}d ago`;
194
+ const title = cv.title || '(untitled)';
195
+ return `${cv.id} "${title}" ${cv.messageCount} msgs ${agoStr}`;
196
+ });
197
+ return { result: `Conversations (${convos.length}):\n${lines.join('\n')}`, isError: false };
198
+ }
199
+ case 'conversation_delete': {
200
+ const { ConversationStore } = await import('./conversation-store.js');
201
+ const cStore = new ConversationStore();
202
+ const existing = cStore.get(String(args.id));
203
+ if (!existing)
204
+ return { result: `Conversation "${args.id}" not found.`, isError: true };
205
+ cStore.delete(String(args.id));
206
+ return { result: `Deleted conversation "${args.id}" (${existing.title || 'untitled'}).`, isError: false };
207
+ }
208
+ case 'conversation_summary': {
209
+ const { ConversationStore } = await import('./conversation-store.js');
210
+ const cStore = new ConversationStore();
211
+ const recent = cStore.getMostRecent();
212
+ if (!recent)
213
+ return { result: 'No active conversation.', isError: false };
214
+ const elapsed = Math.round((Date.now() - recent.createdAt) / 60_000);
215
+ return {
216
+ result: `Current conversation: ${recent.id}\n Title: ${recent.title || '(untitled)'}\n Messages: ${recent.messageCount}\n Tokens: ${recent.totalTokens}\n Bots: ${recent.botIds.length > 0 ? recent.botIds.join(', ') : 'none'}\n Duration: ${elapsed}m`,
217
+ isError: false,
218
+ };
219
+ }
220
+ case 'web_fetch': {
221
+ const url = String(args.url);
222
+ if (isBlockedUrl(url)) {
223
+ return { result: 'Blocked: cannot fetch internal/localhost URLs.', isError: true };
224
+ }
225
+ const resp = await fetch(url, { method: args.method ?? 'GET', signal: AbortSignal.timeout(15_000) });
226
+ const text = await resp.text();
227
+ return { result: text.slice(0, 10_000), isError: !resp.ok };
228
+ }
229
+ case 'github_status': {
230
+ const ghArgs = args.pr
231
+ ? ['pr', 'checks', String(args.pr), '--json', 'name,state,conclusion']
232
+ : ['run', 'list', '--branch', String(args.branch ?? ''), '--json', 'status,conclusion,name,headBranch', '--limit', '5'];
233
+ try {
234
+ const output = execFileSync('gh', ghArgs, { encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'] });
235
+ return { result: output.trim(), isError: false };
236
+ }
237
+ catch (err) {
238
+ return { result: `gh CLI error: ${(err.message ?? '').slice(0, 300)}`, isError: true };
239
+ }
240
+ }
241
+ case 'project_list': {
242
+ const projectsDir = path.join(os.homedir(), '.weaver', 'projects');
243
+ if (!fs.existsSync(projectsDir))
244
+ return { result: 'No projects found.', isError: false };
245
+ const dirs = fs.readdirSync(projectsDir);
246
+ // Each dir is a hash — try to find meta or queue files
247
+ const projects = dirs.map(d => {
248
+ const queuePath = path.join(projectsDir, d, 'task-queue.ndjson');
249
+ const exists = fs.existsSync(queuePath);
250
+ return `${d}: ${exists ? 'has queue' : 'empty'}`;
251
+ });
252
+ return { result: projects.join('\n') || 'No projects found.', isError: false };
253
+ }
254
+ case 'project_context': {
255
+ const dir = String(args.directory);
256
+ const parts = [];
257
+ const pkgPath = path.join(dir, 'package.json');
258
+ if (fs.existsSync(pkgPath)) {
259
+ try {
260
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
261
+ parts.push(`Package: ${pkg.name}@${pkg.version}`);
262
+ parts.push(`Description: ${pkg.description ?? 'none'}`);
263
+ }
264
+ catch {
265
+ parts.push('package.json: parse error');
266
+ }
267
+ }
268
+ const planPath = path.join(dir, '.weaver-plan.md');
269
+ if (fs.existsSync(planPath)) {
270
+ parts.push(`Plan:\n${fs.readFileSync(planPath, 'utf-8').slice(0, 2000)}`);
271
+ }
272
+ const configPath = path.join(dir, '.weaver.json');
273
+ if (fs.existsSync(configPath)) {
274
+ parts.push(`Weaver config: ${fs.readFileSync(configPath, 'utf-8').trim()}`);
275
+ }
276
+ return { result: parts.join('\n') || `No context found in ${dir}`, isError: false };
277
+ }
278
+ case 'fw_diagram_mermaid': {
279
+ try {
280
+ // Try mermaid format first, fall back to text
281
+ let output;
282
+ try {
283
+ output = execFileSync('npx', ['flow-weaver', 'diagram', String(args.file), '--format', 'mermaid'], {
284
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
285
+ }).trim();
286
+ }
287
+ catch {
288
+ output = execFileSync('npx', ['flow-weaver', 'diagram', String(args.file)], {
289
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
290
+ }).trim();
291
+ }
292
+ return { result: output, isError: false };
293
+ }
294
+ catch (err) {
295
+ return { result: (err.message ?? '').slice(0, 500), isError: true };
296
+ }
297
+ }
298
+ case 'knowledge_list': {
299
+ const { KnowledgeStore } = await import('./knowledge-store.js');
300
+ const kStore = new KnowledgeStore(projectDir);
301
+ const entries = kStore.list();
302
+ if (entries.length === 0)
303
+ return { result: 'No stored knowledge.', isError: false };
304
+ return { result: entries.map(e => `${e.key}: ${e.value}`).join('\n'), isError: false };
305
+ }
306
+ case 'knowledge_search': {
307
+ const { KnowledgeStore } = await import('./knowledge-store.js');
308
+ const kStore = new KnowledgeStore(projectDir);
309
+ const entries = kStore.recall(String(args.query));
310
+ if (entries.length === 0)
311
+ return { result: 'No matching knowledge found.', isError: false };
312
+ return { result: entries.map(e => `${e.key}: ${e.value}`).join('\n'), isError: false };
313
+ }
314
+ default:
315
+ return { result: `Unknown tool: ${name}`, isError: true };
316
+ }
317
+ }
318
+ catch (err) {
319
+ const msg = err instanceof Error ? err.message : String(err);
320
+ return { result: msg.slice(0, 500), isError: true };
321
+ }
322
+ };
323
+ }
324
+ //# sourceMappingURL=assistant-tools.js.map