@synergenius/flow-weaver-pack-weaver 0.8.3 → 0.9.3

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 (265) 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/assistant-core.d.ts +25 -0
  6. package/dist/bot/assistant-core.d.ts.map +1 -0
  7. package/dist/bot/assistant-core.js +265 -0
  8. package/dist/bot/assistant-core.js.map +1 -0
  9. package/dist/bot/assistant-tools.d.ts +9 -0
  10. package/dist/bot/assistant-tools.d.ts.map +1 -0
  11. package/dist/bot/assistant-tools.js +602 -0
  12. package/dist/bot/assistant-tools.js.map +1 -0
  13. package/dist/bot/audit-logger.d.ts.map +1 -1
  14. package/dist/bot/audit-logger.js +9 -5
  15. package/dist/bot/audit-logger.js.map +1 -1
  16. package/dist/bot/audit-store.d.ts.map +1 -1
  17. package/dist/bot/audit-store.js +3 -11
  18. package/dist/bot/audit-store.js.map +1 -1
  19. package/dist/bot/bot-manager.d.ts +49 -0
  20. package/dist/bot/bot-manager.d.ts.map +1 -0
  21. package/dist/bot/bot-manager.js +279 -0
  22. package/dist/bot/bot-manager.js.map +1 -0
  23. package/dist/bot/child-process-tracker.d.ts +6 -0
  24. package/dist/bot/child-process-tracker.d.ts.map +1 -0
  25. package/dist/bot/child-process-tracker.js +35 -0
  26. package/dist/bot/child-process-tracker.js.map +1 -0
  27. package/dist/bot/cli-provider.d.ts.map +1 -1
  28. package/dist/bot/cli-provider.js +13 -8
  29. package/dist/bot/cli-provider.js.map +1 -1
  30. package/dist/bot/conversation-store.d.ts +40 -0
  31. package/dist/bot/conversation-store.d.ts.map +1 -0
  32. package/dist/bot/conversation-store.js +182 -0
  33. package/dist/bot/conversation-store.js.map +1 -0
  34. package/dist/bot/cost-store.d.ts.map +1 -1
  35. package/dist/bot/cost-store.js +10 -14
  36. package/dist/bot/cost-store.js.map +1 -1
  37. package/dist/bot/error-guide.d.ts +10 -0
  38. package/dist/bot/error-guide.d.ts.map +1 -0
  39. package/dist/bot/error-guide.js +34 -0
  40. package/dist/bot/error-guide.js.map +1 -0
  41. package/dist/bot/genesis-store.d.ts.map +1 -1
  42. package/dist/bot/genesis-store.js +11 -20
  43. package/dist/bot/genesis-store.js.map +1 -1
  44. package/dist/bot/index.d.ts +3 -0
  45. package/dist/bot/index.d.ts.map +1 -1
  46. package/dist/bot/index.js +3 -0
  47. package/dist/bot/index.js.map +1 -1
  48. package/dist/bot/knowledge-store.d.ts +17 -0
  49. package/dist/bot/knowledge-store.d.ts.map +1 -0
  50. package/dist/bot/knowledge-store.js +53 -0
  51. package/dist/bot/knowledge-store.js.map +1 -0
  52. package/dist/bot/pipeline-runner.d.ts.map +1 -1
  53. package/dist/bot/pipeline-runner.js +8 -1
  54. package/dist/bot/pipeline-runner.js.map +1 -1
  55. package/dist/bot/retry-utils.d.ts +19 -0
  56. package/dist/bot/retry-utils.d.ts.map +1 -0
  57. package/dist/bot/retry-utils.js +64 -0
  58. package/dist/bot/retry-utils.js.map +1 -0
  59. package/dist/bot/run-store.d.ts.map +1 -1
  60. package/dist/bot/run-store.js +2 -10
  61. package/dist/bot/run-store.js.map +1 -1
  62. package/dist/bot/runner.d.ts.map +1 -1
  63. package/dist/bot/runner.js +24 -3
  64. package/dist/bot/runner.js.map +1 -1
  65. package/dist/bot/safe-json.d.ts +32 -0
  66. package/dist/bot/safe-json.d.ts.map +1 -0
  67. package/dist/bot/safe-json.js +56 -0
  68. package/dist/bot/safe-json.js.map +1 -0
  69. package/dist/bot/safe-path.d.ts +18 -0
  70. package/dist/bot/safe-path.d.ts.map +1 -0
  71. package/dist/bot/safe-path.js +40 -0
  72. package/dist/bot/safe-path.js.map +1 -0
  73. package/dist/bot/session-state.d.ts.map +1 -1
  74. package/dist/bot/session-state.js +3 -1
  75. package/dist/bot/session-state.js.map +1 -1
  76. package/dist/bot/steering.js +1 -1
  77. package/dist/bot/steering.js.map +1 -1
  78. package/dist/bot/step-executor.d.ts +10 -5
  79. package/dist/bot/step-executor.d.ts.map +1 -1
  80. package/dist/bot/step-executor.js +252 -3
  81. package/dist/bot/step-executor.js.map +1 -1
  82. package/dist/bot/system-prompt.d.ts +1 -1
  83. package/dist/bot/system-prompt.d.ts.map +1 -1
  84. package/dist/bot/system-prompt.js +69 -43
  85. package/dist/bot/system-prompt.js.map +1 -1
  86. package/dist/bot/task-decomposer.d.ts +24 -0
  87. package/dist/bot/task-decomposer.d.ts.map +1 -0
  88. package/dist/bot/task-decomposer.js +75 -0
  89. package/dist/bot/task-decomposer.js.map +1 -0
  90. package/dist/bot/task-queue.d.ts +17 -4
  91. package/dist/bot/task-queue.d.ts.map +1 -1
  92. package/dist/bot/task-queue.js +102 -14
  93. package/dist/bot/task-queue.js.map +1 -1
  94. package/dist/bot/terminal-renderer.d.ts +60 -0
  95. package/dist/bot/terminal-renderer.d.ts.map +1 -0
  96. package/dist/bot/terminal-renderer.js +205 -0
  97. package/dist/bot/terminal-renderer.js.map +1 -0
  98. package/dist/bot/types.d.ts +7 -0
  99. package/dist/bot/types.d.ts.map +1 -1
  100. package/dist/bot/weaver-tools.d.ts +18 -0
  101. package/dist/bot/weaver-tools.d.ts.map +1 -0
  102. package/dist/bot/weaver-tools.js +215 -0
  103. package/dist/bot/weaver-tools.js.map +1 -0
  104. package/dist/cli-bridge.d.ts.map +1 -1
  105. package/dist/cli-bridge.js +10 -3
  106. package/dist/cli-bridge.js.map +1 -1
  107. package/dist/cli-handlers.d.ts +15 -1
  108. package/dist/cli-handlers.d.ts.map +1 -1
  109. package/dist/cli-handlers.js +742 -28
  110. package/dist/cli-handlers.js.map +1 -1
  111. package/dist/handlers/on-bot-completed.d.ts +21 -0
  112. package/dist/handlers/on-bot-completed.d.ts.map +1 -0
  113. package/dist/handlers/on-bot-completed.js +28 -0
  114. package/dist/handlers/on-bot-completed.js.map +1 -0
  115. package/dist/handlers/on-execution-failure.d.ts +23 -0
  116. package/dist/handlers/on-execution-failure.d.ts.map +1 -0
  117. package/dist/handlers/on-execution-failure.js +28 -0
  118. package/dist/handlers/on-execution-failure.js.map +1 -0
  119. package/dist/handlers/scheduled-run.d.ts +24 -0
  120. package/dist/handlers/scheduled-run.d.ts.map +1 -0
  121. package/dist/handlers/scheduled-run.js +25 -0
  122. package/dist/handlers/scheduled-run.js.map +1 -0
  123. package/dist/index.d.ts +3 -0
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +4 -0
  126. package/dist/index.js.map +1 -1
  127. package/dist/mcp-tools.js +2 -2
  128. package/dist/mcp-tools.js.map +1 -1
  129. package/dist/node-types/abort-task.d.ts.map +1 -1
  130. package/dist/node-types/abort-task.js +4 -3
  131. package/dist/node-types/abort-task.js.map +1 -1
  132. package/dist/node-types/agent-execute.d.ts +38 -0
  133. package/dist/node-types/agent-execute.d.ts.map +1 -0
  134. package/dist/node-types/agent-execute.js +256 -0
  135. package/dist/node-types/agent-execute.js.map +1 -0
  136. package/dist/node-types/bot-report.d.ts +5 -3
  137. package/dist/node-types/bot-report.d.ts.map +1 -1
  138. package/dist/node-types/bot-report.js +39 -7
  139. package/dist/node-types/bot-report.js.map +1 -1
  140. package/dist/node-types/build-context.d.ts +3 -3
  141. package/dist/node-types/build-context.d.ts.map +1 -1
  142. package/dist/node-types/build-context.js +108 -24
  143. package/dist/node-types/build-context.js.map +1 -1
  144. package/dist/node-types/detect-provider.d.ts +2 -2
  145. package/dist/node-types/detect-provider.d.ts.map +1 -1
  146. package/dist/node-types/detect-provider.js +3 -1
  147. package/dist/node-types/detect-provider.js.map +1 -1
  148. package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
  149. package/dist/node-types/exec-validate-retry.js +43 -6
  150. package/dist/node-types/exec-validate-retry.js.map +1 -1
  151. package/dist/node-types/execute-plan.d.ts.map +1 -1
  152. package/dist/node-types/execute-plan.js +31 -8
  153. package/dist/node-types/execute-plan.js.map +1 -1
  154. package/dist/node-types/execute-target.d.ts.map +1 -1
  155. package/dist/node-types/execute-target.js +3 -1
  156. package/dist/node-types/execute-target.js.map +1 -1
  157. package/dist/node-types/fix-errors.d.ts.map +1 -1
  158. package/dist/node-types/fix-errors.js +21 -5
  159. package/dist/node-types/fix-errors.js.map +1 -1
  160. package/dist/node-types/genesis-observe.d.ts.map +1 -1
  161. package/dist/node-types/genesis-observe.js +3 -1
  162. package/dist/node-types/genesis-observe.js.map +1 -1
  163. package/dist/node-types/genesis-report.js +4 -1
  164. package/dist/node-types/genesis-report.js.map +1 -1
  165. package/dist/node-types/git-ops.d.ts.map +1 -1
  166. package/dist/node-types/git-ops.js +98 -4
  167. package/dist/node-types/git-ops.js.map +1 -1
  168. package/dist/node-types/index.d.ts +2 -0
  169. package/dist/node-types/index.d.ts.map +1 -1
  170. package/dist/node-types/index.js +2 -0
  171. package/dist/node-types/index.js.map +1 -1
  172. package/dist/node-types/load-config.d.ts +2 -2
  173. package/dist/node-types/load-config.d.ts.map +1 -1
  174. package/dist/node-types/load-config.js.map +1 -1
  175. package/dist/node-types/plan-task.d.ts.map +1 -1
  176. package/dist/node-types/plan-task.js +14 -2
  177. package/dist/node-types/plan-task.js.map +1 -1
  178. package/dist/node-types/read-workflow.js +8 -2
  179. package/dist/node-types/read-workflow.js.map +1 -1
  180. package/dist/node-types/receive-task.d.ts.map +1 -1
  181. package/dist/node-types/receive-task.js +35 -26
  182. package/dist/node-types/receive-task.js.map +1 -1
  183. package/dist/node-types/send-notify.js +2 -1
  184. package/dist/node-types/send-notify.js.map +1 -1
  185. package/dist/node-types/validate-gate.d.ts +18 -0
  186. package/dist/node-types/validate-gate.d.ts.map +1 -0
  187. package/dist/node-types/validate-gate.js +96 -0
  188. package/dist/node-types/validate-gate.js.map +1 -0
  189. package/dist/workflows/genesis-task.d.ts +20 -12
  190. package/dist/workflows/genesis-task.d.ts.map +1 -1
  191. package/dist/workflows/genesis-task.js +20 -12
  192. package/dist/workflows/genesis-task.js.map +1 -1
  193. package/dist/workflows/weaver-agent.d.ts +35 -0
  194. package/dist/workflows/weaver-agent.d.ts.map +1 -0
  195. package/dist/workflows/weaver-agent.js +777 -0
  196. package/dist/workflows/weaver-agent.js.map +1 -0
  197. package/dist/workflows/weaver-bot-batch.d.ts +19 -26
  198. package/dist/workflows/weaver-bot-batch.d.ts.map +1 -1
  199. package/dist/workflows/weaver-bot-batch.js +1043 -27
  200. package/dist/workflows/weaver-bot-batch.js.map +1 -1
  201. package/dist/workflows/weaver-bot.d.ts +21 -35
  202. package/dist/workflows/weaver-bot.d.ts.map +1 -1
  203. package/dist/workflows/weaver-bot.js +1119 -36
  204. package/dist/workflows/weaver-bot.js.map +1 -1
  205. package/flowweaver.manifest.json +113 -2
  206. package/package.json +5 -2
  207. package/src/bot/ai-client.ts +180 -19
  208. package/src/bot/assistant-core.ts +306 -0
  209. package/src/bot/assistant-tools.ts +605 -0
  210. package/src/bot/audit-logger.ts +6 -5
  211. package/src/bot/audit-store.ts +3 -12
  212. package/src/bot/bot-manager.ts +293 -0
  213. package/src/bot/child-process-tracker.ts +40 -0
  214. package/src/bot/cli-provider.ts +13 -8
  215. package/src/bot/conversation-store.ts +222 -0
  216. package/src/bot/cost-store.ts +11 -12
  217. package/src/bot/error-guide.ts +34 -0
  218. package/src/bot/genesis-store.ts +11 -17
  219. package/src/bot/index.ts +5 -0
  220. package/src/bot/knowledge-store.ts +59 -0
  221. package/src/bot/pipeline-runner.ts +7 -1
  222. package/src/bot/retry-utils.ts +76 -0
  223. package/src/bot/run-store.ts +2 -11
  224. package/src/bot/runner.ts +26 -3
  225. package/src/bot/safe-json.ts +76 -0
  226. package/src/bot/safe-path.ts +44 -0
  227. package/src/bot/session-state.ts +2 -1
  228. package/src/bot/steering.ts +1 -1
  229. package/src/bot/step-executor.ts +313 -5
  230. package/src/bot/system-prompt.ts +70 -47
  231. package/src/bot/task-decomposer.ts +100 -0
  232. package/src/bot/task-queue.ts +119 -15
  233. package/src/bot/terminal-renderer.ts +241 -0
  234. package/src/bot/types.ts +8 -0
  235. package/src/bot/weaver-tools.ts +225 -0
  236. package/src/cli-bridge.ts +14 -3
  237. package/src/cli-handlers.ts +760 -29
  238. package/src/handlers/on-bot-completed.ts +48 -0
  239. package/src/handlers/on-execution-failure.ts +42 -0
  240. package/src/handlers/scheduled-run.ts +42 -0
  241. package/src/index.ts +5 -0
  242. package/src/mcp-tools.ts +2 -2
  243. package/src/node-types/abort-task.ts +5 -4
  244. package/src/node-types/agent-execute.ts +306 -0
  245. package/src/node-types/bot-report.ts +40 -9
  246. package/src/node-types/build-context.ts +112 -25
  247. package/src/node-types/detect-provider.ts +4 -3
  248. package/src/node-types/exec-validate-retry.ts +47 -8
  249. package/src/node-types/execute-plan.ts +32 -8
  250. package/src/node-types/execute-target.ts +2 -1
  251. package/src/node-types/fix-errors.ts +20 -5
  252. package/src/node-types/genesis-observe.ts +2 -1
  253. package/src/node-types/genesis-report.ts +1 -1
  254. package/src/node-types/git-ops.ts +93 -4
  255. package/src/node-types/index.ts +2 -0
  256. package/src/node-types/load-config.ts +3 -3
  257. package/src/node-types/plan-task.ts +15 -3
  258. package/src/node-types/read-workflow.ts +2 -2
  259. package/src/node-types/receive-task.ts +31 -26
  260. package/src/node-types/send-notify.ts +1 -1
  261. package/src/node-types/validate-gate.ts +112 -0
  262. package/src/workflows/genesis-task.ts +20 -12
  263. package/src/workflows/weaver-agent.ts +799 -0
  264. package/src/workflows/weaver-bot-batch.ts +1049 -27
  265. package/src/workflows/weaver-bot.ts +1123 -36
@@ -0,0 +1,605 @@
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
+
7
+ import type { ToolDefinition, ToolExecutor } from '@synergenius/flow-weaver/agent';
8
+ import { BotManager } from './bot-manager.js';
9
+ import { execFileSync } from 'node:child_process';
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+
14
+ // Shared bot manager instance
15
+ let manager: BotManager | null = null;
16
+ function getManager(): BotManager {
17
+ if (!manager) manager = new BotManager();
18
+ return manager;
19
+ }
20
+
21
+ export const ASSISTANT_TOOLS: ToolDefinition[] = [
22
+ // Bot management
23
+ {
24
+ name: 'bot_spawn',
25
+ description: 'Start a new bot session. Returns the bot name and status.',
26
+ inputSchema: {
27
+ type: 'object',
28
+ properties: {
29
+ name: { type: 'string', description: 'Unique name for this bot (e.g. "fix-templates")' },
30
+ project_dir: { type: 'string', description: 'Project directory for the bot to work in' },
31
+ parallel: { type: 'number', description: 'Number of parallel tasks (1-5, default 1)' },
32
+ deadline: { type: 'string', description: 'Stop time in HH:MM format (optional)' },
33
+ branch: { type: 'string', description: 'Git branch for commits (keeps main clean, good for overnight runs)' },
34
+ },
35
+ required: ['name'],
36
+ },
37
+ },
38
+ {
39
+ name: 'bot_list',
40
+ description: 'List all bot sessions with their status, task counts, and cost.',
41
+ inputSchema: { type: 'object', properties: {}, required: [] },
42
+ },
43
+ {
44
+ name: 'bot_status',
45
+ description: 'Get detailed status of a specific bot including queue and recent activity.',
46
+ inputSchema: {
47
+ type: 'object',
48
+ properties: { name: { type: 'string', description: 'Bot name' } },
49
+ required: ['name'],
50
+ },
51
+ },
52
+ {
53
+ name: 'bot_pause',
54
+ description: 'Pause a running bot. It will finish its current task then wait.',
55
+ inputSchema: {
56
+ type: 'object',
57
+ properties: { name: { type: 'string', description: 'Bot name' } },
58
+ required: ['name'],
59
+ },
60
+ },
61
+ {
62
+ name: 'bot_resume',
63
+ description: 'Resume a paused bot.',
64
+ inputSchema: {
65
+ type: 'object',
66
+ properties: { name: { type: 'string', description: 'Bot name' } },
67
+ required: ['name'],
68
+ },
69
+ },
70
+ {
71
+ name: 'bot_stop',
72
+ description: 'Gracefully stop a bot (finishes current task, then exits).',
73
+ inputSchema: {
74
+ type: 'object',
75
+ properties: { name: { type: 'string', description: 'Bot name' } },
76
+ required: ['name'],
77
+ },
78
+ },
79
+ {
80
+ name: 'bot_logs',
81
+ description: 'Get recent output log from a bot.',
82
+ inputSchema: {
83
+ type: 'object',
84
+ properties: {
85
+ name: { type: 'string', description: 'Bot name' },
86
+ lines: { type: 'number', description: 'Number of lines to return (default 30)' },
87
+ },
88
+ required: ['name'],
89
+ },
90
+ },
91
+
92
+ // Queue management
93
+ {
94
+ name: 'queue_add',
95
+ description: 'Add a task to a bot\'s queue.',
96
+ inputSchema: {
97
+ type: 'object',
98
+ properties: {
99
+ bot: { type: 'string', description: 'Bot name' },
100
+ instruction: { type: 'string', description: 'Task instruction' },
101
+ targets: { type: 'array', items: { type: 'string' }, description: 'Target files (optional)' },
102
+ },
103
+ required: ['bot', 'instruction'],
104
+ },
105
+ },
106
+ {
107
+ name: 'queue_add_batch',
108
+ description: 'Add multiple tasks to a bot\'s queue at once.',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: {
112
+ bot: { type: 'string', description: 'Bot name' },
113
+ tasks: {
114
+ type: 'array',
115
+ items: {
116
+ type: 'object',
117
+ properties: {
118
+ instruction: { type: 'string' },
119
+ targets: { type: 'array', items: { type: 'string' } },
120
+ },
121
+ required: ['instruction'],
122
+ },
123
+ description: 'Array of tasks to add',
124
+ },
125
+ },
126
+ required: ['bot', 'tasks'],
127
+ },
128
+ },
129
+ {
130
+ name: 'queue_list',
131
+ description: 'List all tasks in a bot\'s queue with their status.',
132
+ inputSchema: {
133
+ type: 'object',
134
+ properties: { bot: { type: 'string', description: 'Bot name' } },
135
+ required: ['bot'],
136
+ },
137
+ },
138
+ {
139
+ name: 'queue_retry',
140
+ description: 'Reset all failed tasks in a bot\'s queue to pending.',
141
+ inputSchema: {
142
+ type: 'object',
143
+ properties: { bot: { type: 'string', description: 'Bot name' } },
144
+ required: ['bot'],
145
+ },
146
+ },
147
+
148
+ // Flow-weaver tools
149
+ {
150
+ name: 'fw_validate',
151
+ description: 'Validate a workflow or directory of workflows. Returns errors and warnings.',
152
+ inputSchema: {
153
+ type: 'object',
154
+ properties: { path: { type: 'string', description: 'File or directory path' } },
155
+ required: ['path'],
156
+ },
157
+ },
158
+ {
159
+ name: 'fw_diagram',
160
+ description: 'Generate a text diagram of a workflow.',
161
+ inputSchema: {
162
+ type: 'object',
163
+ properties: { file: { type: 'string', description: 'Workflow file path' } },
164
+ required: ['file'],
165
+ },
166
+ },
167
+ {
168
+ name: 'fw_describe',
169
+ description: 'Get a natural language description of a workflow.',
170
+ inputSchema: {
171
+ type: 'object',
172
+ properties: { file: { type: 'string', description: 'Workflow file path' } },
173
+ required: ['file'],
174
+ },
175
+ },
176
+ {
177
+ name: 'fw_docs',
178
+ description: 'Look up Flow Weaver documentation by topic. Topics: concepts, jsdoc-grammar, advanced-annotations, built-in-nodes, scaffold, node-conversion, patterns, error-codes, debugging, export-interface.',
179
+ inputSchema: {
180
+ type: 'object',
181
+ properties: { topic: { type: 'string', description: 'Documentation topic slug' } },
182
+ required: ['topic'],
183
+ },
184
+ },
185
+
186
+ // Project tools
187
+ {
188
+ name: 'read_file',
189
+ description: 'Read a file and return its contents.',
190
+ inputSchema: {
191
+ type: 'object',
192
+ properties: { file: { type: 'string', description: 'File path' } },
193
+ required: ['file'],
194
+ },
195
+ },
196
+ {
197
+ name: 'list_files',
198
+ description: 'List files in a directory.',
199
+ inputSchema: {
200
+ type: 'object',
201
+ properties: {
202
+ directory: { type: 'string', description: 'Directory path' },
203
+ pattern: { type: 'string', description: 'Filter pattern (regex, optional)' },
204
+ },
205
+ required: ['directory'],
206
+ },
207
+ },
208
+ {
209
+ name: 'run_shell',
210
+ description: 'Run a shell command (read-only operations recommended).',
211
+ inputSchema: {
212
+ type: 'object',
213
+ properties: { command: { type: 'string', description: 'Shell command to execute' } },
214
+ required: ['command'],
215
+ },
216
+ },
217
+
218
+ // Conversation management
219
+ {
220
+ name: 'conversation_list',
221
+ description: 'List saved assistant conversations with message counts and timestamps.',
222
+ inputSchema: { type: 'object', properties: {}, required: [] },
223
+ },
224
+ {
225
+ name: 'conversation_delete',
226
+ description: 'Delete a saved conversation by ID.',
227
+ inputSchema: {
228
+ type: 'object',
229
+ properties: { id: { type: 'string', description: 'Conversation ID to delete' } },
230
+ required: ['id'],
231
+ },
232
+ },
233
+ {
234
+ name: 'conversation_summary',
235
+ description: 'Get a summary of the current conversation (message count, tokens, bots spawned).',
236
+ inputSchema: { type: 'object', properties: {}, required: [] },
237
+ },
238
+
239
+ // Web access
240
+ {
241
+ name: 'web_fetch',
242
+ description: 'Fetch HTTP content from a URL. Returns text body (max 10KB).',
243
+ inputSchema: {
244
+ type: 'object',
245
+ properties: {
246
+ url: { type: 'string', description: 'URL to fetch' },
247
+ method: { type: 'string', description: 'HTTP method (default GET)', enum: ['GET', 'POST'] },
248
+ },
249
+ required: ['url'],
250
+ },
251
+ },
252
+
253
+ // CI/CD
254
+ {
255
+ name: 'github_status',
256
+ description: 'Check GitHub Actions status for a branch or PR. Requires gh CLI installed.',
257
+ inputSchema: {
258
+ type: 'object',
259
+ properties: {
260
+ branch: { type: 'string', description: 'Branch name (optional, defaults to current)' },
261
+ pr: { type: 'number', description: 'PR number (optional, checks PR status instead of branch)' },
262
+ },
263
+ required: [],
264
+ },
265
+ },
266
+
267
+ // Cross-repo
268
+ {
269
+ name: 'project_list',
270
+ description: 'List known project directories that have been used with weaver.',
271
+ inputSchema: { type: 'object', properties: {}, required: [] },
272
+ },
273
+ {
274
+ name: 'project_context',
275
+ description: 'Read package.json and .weaver-plan.md from a project directory to understand its context.',
276
+ inputSchema: {
277
+ type: 'object',
278
+ properties: { directory: { type: 'string', description: 'Absolute path to project directory' } },
279
+ required: ['directory'],
280
+ },
281
+ },
282
+
283
+ // Diagrams
284
+ {
285
+ name: 'fw_diagram_mermaid',
286
+ description: 'Generate a Mermaid diagram of a workflow (can be rendered in any Mermaid viewer).',
287
+ inputSchema: {
288
+ type: 'object',
289
+ properties: { file: { type: 'string', description: 'Workflow file path' } },
290
+ required: ['file'],
291
+ },
292
+ },
293
+
294
+ // Knowledge
295
+ {
296
+ name: 'knowledge_list',
297
+ description: 'List all stored knowledge entries for the current project.',
298
+ inputSchema: { type: 'object', properties: {}, required: [] },
299
+ },
300
+ {
301
+ name: 'knowledge_search',
302
+ description: 'Search stored knowledge by keyword.',
303
+ inputSchema: {
304
+ type: 'object',
305
+ properties: { query: { type: 'string', description: 'Search query' } },
306
+ required: ['query'],
307
+ },
308
+ },
309
+ ];
310
+
311
+ export function createAssistantExecutor(projectDir: string): ToolExecutor {
312
+ const mgr = getManager();
313
+
314
+ return async (name: string, args: Record<string, unknown>) => {
315
+ try {
316
+ switch (name) {
317
+ // Bot management
318
+ case 'bot_spawn': {
319
+ const botName = String(args.name ?? `bot-${Date.now()}`);
320
+ const dir = String(args.project_dir ?? projectDir);
321
+ const bot = mgr.spawn(botName, {
322
+ projectDir: dir,
323
+ parallel: args.parallel as number | undefined,
324
+ deadline: args.deadline as string | undefined,
325
+ branch: args.branch as string | undefined,
326
+ });
327
+ return { result: JSON.stringify(bot), isError: false };
328
+ }
329
+ case 'bot_list': {
330
+ const bots = mgr.list();
331
+ if (bots.length === 0) return { result: 'No bots running.', isError: false };
332
+ const lines = bots.map(b => {
333
+ const uptime = Math.round((Date.now() - b.startedAt) / 1000);
334
+ return `${b.name}: ${b.status} (pid ${b.pid}, ${uptime}s uptime)`;
335
+ });
336
+ return { result: lines.join('\n'), isError: false };
337
+ }
338
+ case 'bot_status': {
339
+ const botName = String(args.name);
340
+ const bot = mgr.get(botName);
341
+ if (!bot) return { result: `Bot "${botName}" not found.`, isError: true };
342
+ const queue = mgr.getQueue(botName);
343
+ const tasks = await queue.list();
344
+ const pending = tasks.filter(t => t.status === 'pending').length;
345
+ const running = tasks.filter(t => t.status === 'running').length;
346
+ const completed = tasks.filter(t => t.status === 'completed').length;
347
+ const failed = tasks.filter(t => t.status === 'failed').length;
348
+ const failedTasks = tasks.filter(t => t.status === 'failed');
349
+ let result = `Bot "${botName}": ${bot.status}\n`;
350
+ result += `Tasks: ${completed} completed, ${failed} failed, ${running} running, ${pending} pending\n`;
351
+ if (failedTasks.length > 0) {
352
+ result += `\nFailed tasks:\n`;
353
+ for (const t of failedTasks) {
354
+ result += ` - ${t.instruction.slice(0, 80)}\n`;
355
+ }
356
+ }
357
+ return { result, isError: false };
358
+ }
359
+ case 'bot_pause': {
360
+ await mgr.steer(String(args.name), 'pause');
361
+ return { result: `Paused bot "${args.name}".`, isError: false };
362
+ }
363
+ case 'bot_resume': {
364
+ await mgr.steer(String(args.name), 'resume');
365
+ return { result: `Resumed bot "${args.name}".`, isError: false };
366
+ }
367
+ case 'bot_stop': {
368
+ mgr.stop(String(args.name));
369
+ return { result: `Stopping bot "${args.name}" (will finish current task).`, isError: false };
370
+ }
371
+ case 'bot_logs': {
372
+ const logs = mgr.logs(String(args.name), (args.lines as number) ?? 30);
373
+ return { result: logs || '(no output yet)', isError: false };
374
+ }
375
+
376
+ // Queue management
377
+ case 'queue_add': {
378
+ const queue = mgr.getQueue(String(args.bot));
379
+ const { id, duplicate } = await queue.add({
380
+ instruction: String(args.instruction),
381
+ targets: args.targets as string[] | undefined,
382
+ priority: 0,
383
+ });
384
+ if (duplicate) return { result: `Task already queued (${id}).`, isError: false };
385
+ return { result: `Added task ${id} to "${args.bot}" queue.`, isError: false };
386
+ }
387
+ case 'queue_add_batch': {
388
+ const queue = mgr.getQueue(String(args.bot));
389
+ const tasks = args.tasks as Array<{ instruction: string; targets?: string[] }>;
390
+ let added = 0, skipped = 0;
391
+ for (const t of tasks) {
392
+ const { duplicate } = await queue.add({ instruction: t.instruction, targets: t.targets, priority: 0 });
393
+ if (duplicate) skipped++; else added++;
394
+ }
395
+ const msg = skipped > 0 ? `Added ${added} tasks, ${skipped} duplicates skipped.` : `Added ${added} tasks to "${args.bot}" queue.`;
396
+ return { result: msg, isError: false };
397
+ }
398
+ case 'queue_list': {
399
+ const queue = mgr.getQueue(String(args.bot));
400
+ const tasks = await queue.list();
401
+ if (tasks.length === 0) return { result: 'Queue is empty.', isError: false };
402
+ const lines = tasks.map(t => `[${t.status}] ${t.instruction.slice(0, 70)}`);
403
+ return { result: lines.join('\n'), isError: false };
404
+ }
405
+ case 'queue_retry': {
406
+ const queue = mgr.getQueue(String(args.bot));
407
+ const count = await queue.retryAll();
408
+ return { result: `Reset ${count} failed task(s) to pending.`, isError: false };
409
+ }
410
+
411
+ // Flow-weaver tools
412
+ case 'fw_validate': {
413
+ const output = execFileSync('npx', ['flow-weaver', 'validate', String(args.path)], {
414
+ encoding: 'utf-8', cwd: projectDir, timeout: 30_000, stdio: ['pipe', 'pipe', 'pipe'],
415
+ });
416
+ return { result: output.trim() || 'Validation complete.', isError: false };
417
+ }
418
+ case 'fw_diagram': {
419
+ const output = execFileSync('npx', ['flow-weaver', 'diagram', String(args.file)], {
420
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
421
+ });
422
+ return { result: output.trim(), isError: false };
423
+ }
424
+ case 'fw_describe': {
425
+ const output = execFileSync('npx', ['flow-weaver', 'describe', String(args.file)], {
426
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
427
+ });
428
+ return { result: output.trim(), isError: false };
429
+ }
430
+ case 'fw_docs': {
431
+ const output = execFileSync('npx', ['flow-weaver', 'docs', String(args.topic), '--compact'], {
432
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
433
+ });
434
+ return { result: output.trim().slice(0, 5000), isError: false };
435
+ }
436
+
437
+ // Project tools
438
+ case 'read_file': {
439
+ const filePath = path.isAbsolute(String(args.file)) ? String(args.file) : path.resolve(projectDir, String(args.file));
440
+ const stat = fs.statSync(filePath);
441
+ if (stat.isDirectory()) {
442
+ const entries = fs.readdirSync(filePath).slice(0, 100);
443
+ return { result: `Directory listing (${entries.length} entries):\n${entries.join('\n')}`, isError: false };
444
+ }
445
+ if (stat.size > 1_048_576) return { result: 'File too large (>1MB).', isError: true };
446
+ return { result: fs.readFileSync(filePath, 'utf-8'), isError: false };
447
+ }
448
+ case 'list_files': {
449
+ const dir = path.isAbsolute(String(args.directory)) ? String(args.directory) : path.resolve(projectDir, String(args.directory));
450
+ if (!fs.existsSync(dir)) return { result: `Directory not found: ${dir}`, isError: true };
451
+ let entries = fs.readdirSync(dir, { recursive: false }) as string[];
452
+ if (args.pattern) {
453
+ const re = new RegExp(String(args.pattern));
454
+ entries = entries.filter(e => re.test(e));
455
+ }
456
+ return { result: entries.slice(0, 200).join('\n') || '(empty)', isError: false };
457
+ }
458
+ case 'run_shell': {
459
+ const cmd = String(args.command);
460
+ // Safety: block destructive commands
461
+ const blocked = ['rm -rf', 'git push', 'npm publish', 'sudo', 'curl|sh', 'wget|sh'];
462
+ if (blocked.some(b => cmd.includes(b))) {
463
+ return { result: `Blocked: "${cmd}" is not allowed.`, isError: true };
464
+ }
465
+ const output = execFileSync('sh', ['-c', cmd], {
466
+ encoding: 'utf-8', cwd: projectDir, timeout: 30_000, stdio: ['pipe', 'pipe', 'pipe'],
467
+ });
468
+ return { result: output.trim().slice(0, 5000) || '(no output)', isError: false };
469
+ }
470
+
471
+ // Conversation management
472
+ case 'conversation_list': {
473
+ const { ConversationStore } = await import('./conversation-store.js');
474
+ const cStore = new ConversationStore();
475
+ const convos = cStore.list();
476
+ if (convos.length === 0) return { result: 'No saved conversations.', isError: false };
477
+ const lines = convos.map(cv => {
478
+ const ago = Math.round((Date.now() - cv.lastMessageAt) / 60_000);
479
+ const agoStr = ago < 60 ? `${ago}m ago` : ago < 1440 ? `${Math.round(ago / 60)}h ago` : `${Math.round(ago / 1440)}d ago`;
480
+ const title = cv.title || '(untitled)';
481
+ return `${cv.id} "${title}" ${cv.messageCount} msgs ${agoStr}`;
482
+ });
483
+ return { result: `Conversations (${convos.length}):\n${lines.join('\n')}`, isError: false };
484
+ }
485
+ case 'conversation_delete': {
486
+ const { ConversationStore } = await import('./conversation-store.js');
487
+ const cStore = new ConversationStore();
488
+ const existing = cStore.get(String(args.id));
489
+ if (!existing) return { result: `Conversation "${args.id}" not found.`, isError: true };
490
+ cStore.delete(String(args.id));
491
+ return { result: `Deleted conversation "${args.id}" (${existing.title || 'untitled'}).`, isError: false };
492
+ }
493
+ case 'conversation_summary': {
494
+ const { ConversationStore } = await import('./conversation-store.js');
495
+ const cStore = new ConversationStore();
496
+ const recent = cStore.getMostRecent();
497
+ if (!recent) return { result: 'No active conversation.', isError: false };
498
+ const elapsed = Math.round((Date.now() - recent.createdAt) / 60_000);
499
+ return {
500
+ 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`,
501
+ isError: false,
502
+ };
503
+ }
504
+
505
+ case 'web_fetch': {
506
+ const url = String(args.url);
507
+ if (/localhost|127\.0\.0\.1|0\.0\.0\.0|10\.\d|172\.(1[6-9]|2\d|3[01])\.|192\.168\./i.test(url)) {
508
+ return { result: 'Blocked: cannot fetch internal/localhost URLs.', isError: true };
509
+ }
510
+ const resp = await fetch(url, { method: (args.method as string) ?? 'GET', signal: AbortSignal.timeout(15_000) });
511
+ const text = await resp.text();
512
+ return { result: text.slice(0, 10_000), isError: !resp.ok };
513
+ }
514
+
515
+ case 'github_status': {
516
+ const ghArgs = args.pr
517
+ ? ['pr', 'checks', String(args.pr), '--json', 'name,state,conclusion']
518
+ : ['run', 'list', '--branch', String(args.branch ?? ''), '--json', 'status,conclusion,name,headBranch', '--limit', '5'];
519
+ try {
520
+ const output = execFileSync('gh', ghArgs, { encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'] });
521
+ return { result: output.trim(), isError: false };
522
+ } catch (err: any) {
523
+ return { result: `gh CLI error: ${(err.message ?? '').slice(0, 300)}`, isError: true };
524
+ }
525
+ }
526
+
527
+ case 'project_list': {
528
+ const projectsDir = path.join(os.homedir(), '.weaver', 'projects');
529
+ if (!fs.existsSync(projectsDir)) return { result: 'No projects found.', isError: false };
530
+ const dirs = fs.readdirSync(projectsDir);
531
+ // Each dir is a hash — try to find meta or queue files
532
+ const projects = dirs.map(d => {
533
+ const queuePath = path.join(projectsDir, d, 'task-queue.ndjson');
534
+ const exists = fs.existsSync(queuePath);
535
+ return `${d}: ${exists ? 'has queue' : 'empty'}`;
536
+ });
537
+ return { result: projects.join('\n') || 'No projects found.', isError: false };
538
+ }
539
+
540
+ case 'project_context': {
541
+ const dir = String(args.directory);
542
+ const parts: string[] = [];
543
+ const pkgPath = path.join(dir, 'package.json');
544
+ if (fs.existsSync(pkgPath)) {
545
+ try {
546
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
547
+ parts.push(`Package: ${pkg.name}@${pkg.version}`);
548
+ parts.push(`Description: ${pkg.description ?? 'none'}`);
549
+ } catch { parts.push('package.json: parse error'); }
550
+ }
551
+ const planPath = path.join(dir, '.weaver-plan.md');
552
+ if (fs.existsSync(planPath)) {
553
+ parts.push(`Plan:\n${fs.readFileSync(planPath, 'utf-8').slice(0, 2000)}`);
554
+ }
555
+ const configPath = path.join(dir, '.weaver.json');
556
+ if (fs.existsSync(configPath)) {
557
+ parts.push(`Weaver config: ${fs.readFileSync(configPath, 'utf-8').trim()}`);
558
+ }
559
+ return { result: parts.join('\n') || `No context found in ${dir}`, isError: false };
560
+ }
561
+
562
+ case 'fw_diagram_mermaid': {
563
+ try {
564
+ // Try mermaid format first, fall back to text
565
+ let output: string;
566
+ try {
567
+ output = execFileSync('npx', ['flow-weaver', 'diagram', String(args.file), '--format', 'mermaid'], {
568
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
569
+ }).trim();
570
+ } catch {
571
+ output = execFileSync('npx', ['flow-weaver', 'diagram', String(args.file)], {
572
+ encoding: 'utf-8', cwd: projectDir, timeout: 15_000, stdio: ['pipe', 'pipe', 'pipe'],
573
+ }).trim();
574
+ }
575
+ return { result: output, isError: false };
576
+ } catch (err: any) {
577
+ return { result: (err.message ?? '').slice(0, 500), isError: true };
578
+ }
579
+ }
580
+
581
+ case 'knowledge_list': {
582
+ const { KnowledgeStore } = await import('./knowledge-store.js');
583
+ const kStore = new KnowledgeStore(projectDir);
584
+ const entries = kStore.list();
585
+ if (entries.length === 0) return { result: 'No stored knowledge.', isError: false };
586
+ return { result: entries.map(e => `${e.key}: ${e.value}`).join('\n'), isError: false };
587
+ }
588
+
589
+ case 'knowledge_search': {
590
+ const { KnowledgeStore } = await import('./knowledge-store.js');
591
+ const kStore = new KnowledgeStore(projectDir);
592
+ const entries = kStore.recall(String(args.query));
593
+ if (entries.length === 0) return { result: 'No matching knowledge found.', isError: false };
594
+ return { result: entries.map(e => `${e.key}: ${e.value}`).join('\n'), isError: false };
595
+ }
596
+
597
+ default:
598
+ return { result: `Unknown tool: ${name}`, isError: true };
599
+ }
600
+ } catch (err: unknown) {
601
+ const msg = err instanceof Error ? err.message : String(err);
602
+ return { result: msg.slice(0, 500), isError: true };
603
+ }
604
+ };
605
+ }
@@ -8,7 +8,8 @@ let onEvent: AuditEventCallback | undefined;
8
8
  export function initAuditLogger(runId: string, callback?: AuditEventCallback): void {
9
9
  try {
10
10
  store = new AuditStore();
11
- } catch {
11
+ } catch (err) {
12
+ if (process.env.WEAVER_VERBOSE) process.stderr.write(`[weaver] audit store init failed: ${err}\n`);
12
13
  store = null;
13
14
  }
14
15
  currentRunId = runId;
@@ -27,14 +28,14 @@ export function auditEmit(type: AuditEventType, data?: Record<string, unknown>):
27
28
 
28
29
  try {
29
30
  store?.emit(event);
30
- } catch {
31
- // non-fatal
31
+ } catch (err) {
32
+ if (process.env.WEAVER_VERBOSE) process.stderr.write(`[weaver] audit emit failed: ${err}\n`);
32
33
  }
33
34
 
34
35
  try {
35
36
  onEvent?.(event);
36
- } catch {
37
- // non-fatal
37
+ } catch (err) {
38
+ if (process.env.WEAVER_VERBOSE) process.stderr.write(`[weaver] audit callback failed: ${err}\n`);
38
39
  }
39
40
  }
40
41
 
@@ -2,6 +2,7 @@ import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import * as os from 'node:os';
4
4
  import type { AuditEvent } from './types.js';
5
+ import { parseNdjson } from './safe-json.js';
5
6
 
6
7
  export class AuditStore {
7
8
  private readonly dir: string;
@@ -53,17 +54,7 @@ export class AuditStore {
53
54
  if (!fs.existsSync(this.filePath)) return [];
54
55
 
55
56
  const content = fs.readFileSync(this.filePath, 'utf-8');
56
- const lines = content.split('\n').filter((line) => line.trim().length > 0);
57
- const events: AuditEvent[] = [];
58
-
59
- for (const line of lines) {
60
- try {
61
- events.push(JSON.parse(line) as AuditEvent);
62
- } catch {
63
- // skip corrupt line
64
- }
65
- }
66
-
67
- return events;
57
+ const { records } = parseNdjson<AuditEvent>(content, 'audit');
58
+ return records;
68
59
  }
69
60
  }