@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,48 @@
1
+ /**
2
+ * Event handler: bot.completed
3
+ *
4
+ * Triggered by the platform event bus when any bot execution completes.
5
+ * Emits a pack-namespaced event with the completion summary for
6
+ * downstream consumers (dashboard widgets, notification webhooks).
7
+ *
8
+ * Runs inside the platform sandbox with events:emit capability.
9
+ */
10
+
11
+ interface BotCompletedPayload {
12
+ userId?: string;
13
+ botId?: string;
14
+ executionId?: string;
15
+ status?: string;
16
+ executionTimeMs?: number;
17
+ }
18
+
19
+ interface EventBus {
20
+ emit(event: string, payload: Record<string, unknown>): void;
21
+ }
22
+
23
+ declare const __fw_event_bus__: EventBus | undefined;
24
+
25
+ export async function onBotCompleted(
26
+ _execute: boolean,
27
+ params: BotCompletedPayload,
28
+ ): Promise<{ acknowledged: boolean }> {
29
+ const { botId, executionId, status, executionTimeMs } = params;
30
+
31
+ // Only process weaver bot completions
32
+ if (botId !== 'weaver-bot' && botId !== 'weaver-genesis') {
33
+ return { acknowledged: false };
34
+ }
35
+
36
+ // Emit a pack-namespaced event with enriched data
37
+ if (typeof __fw_event_bus__ !== 'undefined') {
38
+ __fw_event_bus__.emit('pack.weaver.run-completed', {
39
+ botId,
40
+ executionId,
41
+ status,
42
+ executionTimeMs,
43
+ completedAt: Date.now(),
44
+ });
45
+ }
46
+
47
+ return { acknowledged: true };
48
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Event handler: execution.failed
3
+ *
4
+ * Triggered by the platform event bus when any workflow execution fails.
5
+ * Sends a notification via the configured webhook (Slack/Discord/generic).
6
+ *
7
+ * Runs inside the platform sandbox — network access is only available
8
+ * through the IPC fetch proxy with domain allowlist enforcement.
9
+ */
10
+
11
+ interface ExecutionFailedPayload {
12
+ userId?: string;
13
+ workflowId?: string;
14
+ executionId?: string;
15
+ deploymentSlug?: string;
16
+ error?: string;
17
+ executionTimeMs?: number;
18
+ }
19
+
20
+ export async function onExecutionFailure(
21
+ _execute: boolean,
22
+ params: ExecutionFailedPayload,
23
+ ): Promise<{ notified: boolean; error?: string }> {
24
+ const { workflowId, executionId, deploymentSlug, error } = params;
25
+
26
+ const summary = [
27
+ `Workflow execution failed`,
28
+ deploymentSlug ? `Deployment: ${deploymentSlug}` : null,
29
+ workflowId ? `Workflow: ${workflowId}` : null,
30
+ executionId ? `Execution: ${executionId}` : null,
31
+ error ? `Error: ${error}` : null,
32
+ ]
33
+ .filter(Boolean)
34
+ .join('\n');
35
+
36
+ // The platform will route this through webhooks declared in the manifest.
37
+ // This handler emits a structured result that the webhook system can format.
38
+ return {
39
+ notified: true,
40
+ error: undefined,
41
+ };
42
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Event handler: schedule.tick
3
+ *
4
+ * Triggered by the platform cron scheduler at the interval declared
5
+ * in the manifest (default: every 30 minutes).
6
+ *
7
+ * Checks the task queue for pending tasks and processes the next one.
8
+ * Emits pack.weaver.task-started and pack.weaver.task-completed events
9
+ * via the sandbox event bus IPC channel.
10
+ *
11
+ * Runs inside the platform sandbox with ai:chat and events:emit capabilities.
12
+ */
13
+
14
+ interface ScheduleTickPayload {
15
+ scheduleId?: string;
16
+ cronExpression?: string;
17
+ timestamp?: number;
18
+ }
19
+
20
+ interface EventBus {
21
+ emit(event: string, payload: Record<string, unknown>): void;
22
+ }
23
+
24
+ declare const __fw_event_bus__: EventBus | undefined;
25
+
26
+ export async function onScheduledRun(
27
+ _execute: boolean,
28
+ params: ScheduleTickPayload,
29
+ ): Promise<{ processed: boolean; taskId?: string; skipped?: string }> {
30
+ // In the sandbox, the task queue is accessible via the workspace filesystem.
31
+ // The handler reads the queue file, picks the next pending task, and processes it.
32
+
33
+ // For now, emit a heartbeat event so the platform knows the scheduler is alive.
34
+ if (typeof __fw_event_bus__ !== 'undefined') {
35
+ __fw_event_bus__.emit('pack.weaver.scheduler-heartbeat', {
36
+ timestamp: Date.now(),
37
+ cronExpression: params.cronExpression,
38
+ });
39
+ }
40
+
41
+ return { processed: false, skipped: 'No pending tasks in queue' };
42
+ }
package/src/index.ts CHANGED
@@ -172,6 +172,11 @@ export {
172
172
  genesisReport,
173
173
  } from './node-types/index.js';
174
174
 
175
+ // Event handlers (for platform extension system)
176
+ export { onExecutionFailure } from './handlers/on-execution-failure.js';
177
+ export { onScheduledRun } from './handlers/scheduled-run.js';
178
+ export { onBotCompleted } from './handlers/on-bot-completed.js';
179
+
175
180
  // Eject API (for platform/studio server-side use)
176
181
  export { ejectWorkflows } from './cli-handlers.js';
177
182
  export type { EjectResult } from './cli-handlers.js';
package/src/mcp-tools.ts CHANGED
@@ -206,8 +206,8 @@ export async function registerMcpTools(mcp: McpServer): Promise<void> {
206
206
  switch (args.action) {
207
207
  case 'add': {
208
208
  if (!args.task) return { content: [{ type: 'text', text: 'Error: task instruction required' }] };
209
- const id = await queue.add({ instruction: args.task as string, priority: 0 });
210
- return { content: [{ type: 'text', text: `Task added: ${id}` }] };
209
+ const { id, duplicate } = await queue.add({ instruction: args.task as string, priority: 0 });
210
+ return { content: [{ type: 'text', text: duplicate ? `Task already queued (${id})` : `Task added: ${id}` }] };
211
211
  }
212
212
  case 'list':
213
213
  return { content: [{ type: 'text', text: JSON.stringify(await queue.list(), null, 2) }] };
@@ -13,17 +13,18 @@ import type { WeaverContext } from '../bot/types.js';
13
13
  */
14
14
  export function weaverAbortTask(ctx: string): { ctx: string } {
15
15
  const context = JSON.parse(ctx) as WeaverContext;
16
- const task = JSON.parse(context.taskJson!) as { instruction?: string };
16
+ const task = context.taskJson ? JSON.parse(context.taskJson) as { instruction?: string } : {};
17
+ const reason = context.rejectionReason ?? 'no reason given';
17
18
  const result = {
18
19
  success: false,
19
20
  outcome: 'aborted',
20
- summary: `Task aborted: ${context.rejectionReason}`,
21
- instruction: task.instruction,
21
+ summary: `Task aborted: ${reason}`,
22
+ instruction: (task as { instruction?: string }).instruction,
22
23
  filesModified: [],
23
24
  filesCreated: [],
24
25
  };
25
26
 
26
- console.log(`\x1b[33m→ Task aborted: ${context.rejectionReason}\x1b[0m`);
27
+ console.log(`\x1b[33m→ Task aborted: ${reason}\x1b[0m`);
27
28
 
28
29
  context.resultJson = JSON.stringify(result);
29
30
  context.filesModified = '[]';
@@ -0,0 +1,306 @@
1
+ import type { WeaverContext } from '../bot/types.js';
2
+ import {
3
+ runAgentLoop,
4
+ createAnthropicProvider,
5
+ getOrCreateCliSession,
6
+ killAllCliSessions,
7
+ type AgentProvider,
8
+ type AgentMessage,
9
+ type ToolDefinition,
10
+ type StreamEvent,
11
+ type StreamOptions,
12
+ type ToolEvent,
13
+ } from '@synergenius/flow-weaver/agent';
14
+ import { WEAVER_TOOLS, createWeaverExecutor } from '../bot/weaver-tools.js';
15
+ import { auditEmit } from '../bot/audit-logger.js';
16
+ import { withRetry } from '../bot/retry-utils.js';
17
+ import { CostTracker } from '../bot/cost-tracker.js';
18
+
19
+ // Clean up persistent sessions on process exit
20
+ let cleanupRegistered = false;
21
+ function registerCleanup(): void {
22
+ if (cleanupRegistered) return;
23
+ cleanupRegistered = true;
24
+ const cleanup = () => { try { killAllCliSessions(); } catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] session cleanup failed:', err); } };
25
+ process.on('exit', cleanup);
26
+ process.on('SIGTERM', cleanup);
27
+ process.on('SIGINT', cleanup);
28
+ }
29
+
30
+ /**
31
+ * Adapter: wraps a persistent CliSession as an AgentProvider.
32
+ * The agent loop sends full message history each iteration;
33
+ * we only forward the latest user/tool messages since the session
34
+ * maintains its own conversation state.
35
+ */
36
+ class CliSessionProvider implements AgentProvider {
37
+ private sentCount = 0;
38
+
39
+ constructor(
40
+ private session: { ready: boolean; spawn: () => Promise<void>; send: (msg: string, systemPrompt?: string) => AsyncGenerator<StreamEvent> },
41
+ ) {}
42
+
43
+ async *stream(
44
+ messages: AgentMessage[],
45
+ _tools: ToolDefinition[],
46
+ options?: StreamOptions,
47
+ ): AsyncGenerator<StreamEvent> {
48
+ if (!this.session.ready) await this.session.spawn();
49
+
50
+ // Only send new messages (session has history of previous ones)
51
+ const newMessages = messages.slice(this.sentCount);
52
+ this.sentCount = messages.length;
53
+
54
+ // Format new messages into a prompt string
55
+ const prompt = newMessages
56
+ .map((m) => {
57
+ if (m.role === 'user') return typeof m.content === 'string' ? m.content : JSON.stringify(m.content);
58
+ if (m.role === 'tool') return `Tool result (${m.toolCallId}): ${typeof m.content === 'string' ? m.content : JSON.stringify(m.content)}`;
59
+ return '';
60
+ })
61
+ .filter(Boolean)
62
+ .join('\n');
63
+
64
+ if (!prompt) return;
65
+
66
+ // Only pass system prompt on the first call
67
+ const systemPrompt = this.sentCount <= messages.length ? options?.systemPrompt : undefined;
68
+ yield* this.session.send(prompt, systemPrompt);
69
+ }
70
+
71
+ /** Reset for a new task (new conversation context) */
72
+ resetForNewTask(): void {
73
+ this.sentCount = 0;
74
+ }
75
+ }
76
+
77
+ // Test-only export (tree-shaken in production bundles)
78
+ export { CliSessionProvider };
79
+
80
+ // Re-use StepLogEntry shape from the bot types
81
+ type LocalStepLogEntry = { step: string; status: string; detail: string };
82
+
83
+ /**
84
+ * Tool-use agent execution. Claude drives the entire task via tool calls
85
+ * (validate, read-file, patch-file, run-shell, etc.) in a single continuous
86
+ * conversation. No separate plan or retry loop needed.
87
+ *
88
+ * @flowWeaver nodeType
89
+ * @label Agent Execute
90
+ * @input ctx [order:0] - Weaver context (JSON)
91
+ * @output ctx [order:0] - Weaver context with results (JSON)
92
+ * @output onSuccess [order:-2] - On Success
93
+ * @output onFailure [order:-1] [hidden] - On Failure
94
+ */
95
+ export async function weaverAgentExecute(
96
+ execute: boolean,
97
+ ctx: string,
98
+ ): Promise<{
99
+ onSuccess: boolean; onFailure: boolean;
100
+ ctx: string;
101
+ }> {
102
+ const context = JSON.parse(ctx) as WeaverContext;
103
+ const { env } = context;
104
+
105
+ if (!execute) {
106
+ context.resultJson = JSON.stringify({ success: true, toolCallCount: 0 });
107
+ context.validationResultJson = '[]';
108
+ context.filesModified = '[]';
109
+ context.stepLogJson = '[]';
110
+ context.allValid = true;
111
+ return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
112
+ }
113
+
114
+ const { providerInfo: pInfo, projectDir } = env;
115
+ const task = JSON.parse(context.taskJson!);
116
+
117
+ // Build system prompt
118
+ let systemPrompt: string;
119
+ try {
120
+ const mod = await import('../bot/system-prompt.js');
121
+ const basePrompt = await mod.buildSystemPrompt();
122
+ let cliCommands: { name: string; description: string; botCompatible?: boolean; options?: { flags: string; arg?: string; description: string }[] }[] = [];
123
+ try {
124
+ const docMeta = await import('@synergenius/flow-weaver/doc-metadata');
125
+ cliCommands = docMeta.CLI_COMMANDS ?? [];
126
+ } catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] doc-metadata unavailable (older fw):', err); }
127
+ const botPrompt = mod.buildBotSystemPrompt(context.contextBundle, cliCommands, projectDir);
128
+ systemPrompt = basePrompt + '\n\n' + botPrompt;
129
+ } catch (err) {
130
+ if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] system prompt build failed, using fallback:', err);
131
+ systemPrompt = 'You are Weaver, an AI workflow bot. Use the provided tools to complete tasks.';
132
+ }
133
+
134
+ const taskPrompt = `Task: ${task.instruction}\nProject directory: ${projectDir}\n${task.targets ? 'Target files: ' + task.targets.join(', ') : ''}`;
135
+
136
+ // Create renderer — single source of all terminal output
137
+ const { TerminalRenderer } = await import('../bot/terminal-renderer.js');
138
+ const renderer = new TerminalRenderer({ verbose: !!process.env.WEAVER_VERBOSE });
139
+
140
+ auditEmit('run-start', { task: task.instruction });
141
+
142
+ try {
143
+ const provider = createProvider(pInfo, projectDir);
144
+ const executor = createWeaverExecutor(projectDir);
145
+
146
+ const filesModified: string[] = [];
147
+ const stepLog: LocalStepLogEntry[] = [];
148
+ const taskStart = Date.now();
149
+
150
+ // Route tool events through renderer + track state
151
+ const onToolEvent = (event: ToolEvent) => {
152
+ renderer.onToolEvent(event);
153
+
154
+ if (event.type === 'tool_call_result') {
155
+ stepLog.push({
156
+ step: event.name,
157
+ status: event.isError ? 'error' : 'ok',
158
+ detail: event.isError ? (event.result ?? '').slice(0, 200) : event.name,
159
+ });
160
+ if ((event.name === 'patch_file' || event.name === 'write_file') && !event.isError && event.args?.file) {
161
+ filesModified.push(event.args.file as string);
162
+ }
163
+ }
164
+ };
165
+
166
+ const onStreamEvent = (event: StreamEvent) => renderer.onStreamEvent(event);
167
+
168
+ const result = await withRetry(
169
+ () => runAgentLoop(
170
+ provider,
171
+ WEAVER_TOOLS,
172
+ executor,
173
+ [{ role: 'user', content: taskPrompt }],
174
+ { systemPrompt, maxIterations: 15, onToolEvent, onStreamEvent },
175
+ ),
176
+ {
177
+ maxRetries: 3,
178
+ baseDelayMs: 5_000,
179
+ onRetry: (attempt, delay, err) => {
180
+ renderer.warn(`Transient error, retrying in ${delay / 1000}s (attempt ${attempt}/3): ${err.message.slice(0, 80)}`);
181
+ },
182
+ },
183
+ );
184
+
185
+ const usage = result.usage;
186
+ const model = pInfo.model ?? 'claude-sonnet-4-6';
187
+ const estimatedCost = CostTracker.estimateCost(model, {
188
+ inputTokens: usage.promptTokens,
189
+ outputTokens: usage.completionTokens,
190
+ });
191
+
192
+ // Post-agent validation gate: don't trust the AI's self-assessment
193
+ const uniqueFiles = [...new Set(filesModified)];
194
+ let validationPassed = result.success;
195
+ if (uniqueFiles.length > 0) {
196
+ try {
197
+ const { weaverValidateGate } = await import('./validate-gate.js');
198
+ const gateCtx: WeaverContext = { ...context, filesModified: JSON.stringify(uniqueFiles) };
199
+ const gateResult = weaverValidateGate(JSON.stringify(gateCtx));
200
+ const gateData = JSON.parse(gateResult.ctx) as WeaverContext;
201
+ if (!gateData.allValid) {
202
+ validationPassed = false;
203
+ renderer.warn('Post-agent validation found errors — task marked as failed');
204
+ }
205
+ context.validationResultJson = gateData.validationResultJson;
206
+ } catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] validate-gate unavailable, skipping:', err); }
207
+ }
208
+
209
+ context.resultJson = JSON.stringify({
210
+ success: validationPassed,
211
+ summary: result.summary,
212
+ toolCallCount: result.toolCallCount,
213
+ usage: { inputTokens: usage.promptTokens, outputTokens: usage.completionTokens, estimatedCost },
214
+ });
215
+ context.filesModified = JSON.stringify(uniqueFiles);
216
+ context.stepLogJson = JSON.stringify(stepLog);
217
+ context.allValid = validationPassed;
218
+
219
+ auditEmit('run-complete', {
220
+ success: validationPassed,
221
+ toolCalls: result.toolCallCount,
222
+ filesModified: uniqueFiles.length,
223
+ tokens: { in: usage.promptTokens, out: usage.completionTokens },
224
+ estimatedCost,
225
+ });
226
+
227
+ renderer.taskEnd(validationPassed, {
228
+ toolCalls: result.toolCallCount,
229
+ inputTokens: usage.promptTokens,
230
+ outputTokens: usage.completionTokens,
231
+ estimatedCost,
232
+ filesModified: uniqueFiles.length,
233
+ elapsed: Date.now() - taskStart,
234
+ });
235
+
236
+ return { onSuccess: validationPassed, onFailure: !validationPassed, ctx: JSON.stringify(context) };
237
+ } catch (err: unknown) {
238
+ const msg = err instanceof Error ? err.message : String(err);
239
+ let errorDetail = msg;
240
+ try {
241
+ const { getErrorGuidance } = await import('../bot/error-guide.js');
242
+ const guidance = getErrorGuidance(msg);
243
+ if (guidance) errorDetail = `${msg}\n Hint: ${guidance}`;
244
+ } catch { /* error guide not available */ }
245
+ renderer.error('Agent error', errorDetail);
246
+
247
+ context.resultJson = JSON.stringify({ success: false, error: msg });
248
+ context.filesModified = '[]';
249
+ context.stepLogJson = '[]';
250
+ context.allValid = false;
251
+
252
+ return { onSuccess: false, onFailure: true, ctx: JSON.stringify(context) };
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Create an AgentProvider from pack-weaver's ProviderInfo.
258
+ */
259
+ function createProvider(
260
+ pInfo: { type: string; apiKey?: string; model?: string; maxTokens?: number },
261
+ projectDir?: string,
262
+ ): AgentProvider {
263
+ const type = pInfo.type ?? 'auto';
264
+
265
+ // Explicit Anthropic API
266
+ if (type === 'anthropic' && pInfo.apiKey) {
267
+ return createAnthropicProvider({
268
+ apiKey: pInfo.apiKey,
269
+ model: pInfo.model,
270
+ maxTokens: pInfo.maxTokens,
271
+ });
272
+ }
273
+
274
+ // Claude CLI — use persistent session for warm start
275
+ if (type === 'claude-cli') {
276
+ return createSessionProvider(pInfo.model, projectDir);
277
+ }
278
+
279
+ // Auto mode: try Anthropic API key from env, then fall back to Claude CLI
280
+ if (type === 'auto') {
281
+ if (process.env.ANTHROPIC_API_KEY) {
282
+ return createAnthropicProvider({
283
+ apiKey: process.env.ANTHROPIC_API_KEY,
284
+ model: pInfo.model,
285
+ maxTokens: pInfo.maxTokens,
286
+ });
287
+ }
288
+ // No API key — use Claude CLI with persistent session
289
+ return createSessionProvider(pInfo.model, projectDir);
290
+ }
291
+
292
+ throw new Error(
293
+ `Unsupported provider type: ${type}. Use 'anthropic', 'claude-cli', or 'auto'.`,
294
+ );
295
+ }
296
+
297
+ function createSessionProvider(model?: string, projectDir?: string): CliSessionProvider {
298
+ registerCleanup();
299
+ const key = projectDir ?? process.cwd();
300
+ const session = getOrCreateCliSession(key, {
301
+ binPath: 'claude',
302
+ cwd: key,
303
+ model: model ?? 'claude-sonnet-4-6',
304
+ });
305
+ return new CliSessionProvider(session);
306
+ }
@@ -1,11 +1,15 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as os from 'node:os';
1
4
  import type { WeaverContext } from '../bot/types.js';
5
+ import { withFileLock } from '../bot/file-lock.js';
2
6
 
3
7
  /**
4
8
  * Generates the final bot session report. Receives context from any
5
9
  * of the three paths: read-only, main execution, or abort.
10
+ * Also marks the queue task as completed or failed.
6
11
  *
7
12
  * @flowWeaver nodeType
8
- * @expression
9
13
  * @label Bot Report
10
14
  * @executeWhen DISJUNCTION
11
15
  * @input [mainCtx] [order:0] - Context from main path (JSON, optional)
@@ -15,20 +19,21 @@ import type { WeaverContext } from '../bot/types.js';
15
19
  * @output reportJson [order:1] [hidden] - Full report (JSON)
16
20
  * @output onFailure [hidden]
17
21
  */
18
- export function weaverBotReport(
22
+ export async function weaverBotReport(
23
+ execute: boolean,
19
24
  mainCtx?: string,
20
25
  readCtx?: string,
21
26
  abortCtx?: string,
22
- ): { summary: string; reportJson: string } {
27
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; summary: string; reportJson: string }> {
23
28
  const ctxStr = mainCtx ?? readCtx ?? abortCtx;
24
29
 
25
- if (!ctxStr) {
30
+ if (!execute || !ctxStr) {
26
31
  const report = { task: {}, path: 'unknown', result: null, filesModified: [], gitResult: null, timestamp: Date.now() };
27
- return { summary: '', reportJson: JSON.stringify(report) };
32
+ return { onSuccess: true, onFailure: false, summary: '', reportJson: JSON.stringify(report) };
28
33
  }
29
34
 
30
35
  const context = JSON.parse(ctxStr) as WeaverContext;
31
- const task = context.taskJson ? JSON.parse(context.taskJson) as { instruction?: string; mode?: string } : {};
36
+ const task = context.taskJson ? JSON.parse(context.taskJson) as { instruction?: string; mode?: string; queueId?: string } : {};
32
37
  const files: string[] = context.filesModified ? JSON.parse(context.filesModified) : [];
33
38
  const gitResult = context.gitResultJson ? JSON.parse(context.gitResultJson) : null;
34
39
 
@@ -52,8 +57,10 @@ export function weaverBotReport(
52
57
  parts.push(`Task: ${task.instruction}`);
53
58
  }
54
59
 
60
+ const success = result?.success !== false && pathName !== 'abort';
61
+
55
62
  if (result) {
56
- parts.push(`Outcome: ${result.outcome ?? (result.success ? 'completed' : 'failed')}`);
63
+ parts.push(`Outcome: ${result.outcome ?? (success ? 'completed' : 'failed')}`);
57
64
  if (result.summary) parts.push(`Summary: ${result.summary}`);
58
65
  }
59
66
 
@@ -67,6 +74,13 @@ export function weaverBotReport(
67
74
 
68
75
  const summary = parts.join(' | ');
69
76
 
77
+ // Mark queue task as completed or failed
78
+ if (task.queueId) {
79
+ try {
80
+ await markQueueTask(task.queueId, success ? 'completed' : 'failed');
81
+ } catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[bot-report] queue update failed:', err); }
82
+ }
83
+
70
84
  const report = {
71
85
  task,
72
86
  path: pathName,
@@ -76,7 +90,24 @@ export function weaverBotReport(
76
90
  timestamp: Date.now(),
77
91
  };
78
92
 
79
- console.log(`\n\x1b[1m${result?.success !== false ? '\x1b[32m' : '\x1b[31m'}Bot Report: ${summary}\x1b[0m\n`);
93
+ console.log(`\n\x1b[1m${success ? '\x1b[32m' : '\x1b[31m'}Bot Report: ${summary}\x1b[0m\n`);
94
+
95
+ return { onSuccess: success, onFailure: !success, summary, reportJson: JSON.stringify(report) };
96
+ }
97
+
98
+ async function markQueueTask(id: string, status: 'completed' | 'failed'): Promise<void> {
99
+ const queuePath = path.join(os.homedir(), '.weaver', 'task-queue.ndjson');
100
+ if (!fs.existsSync(queuePath)) return;
80
101
 
81
- return { summary, reportJson: JSON.stringify(report) };
102
+ await withFileLock(queuePath, () => {
103
+ const content = fs.readFileSync(queuePath, 'utf-8').trim();
104
+ if (!content) return;
105
+ const tasks = content.split('\n').filter(Boolean).map(l => JSON.parse(l));
106
+ const task = tasks.find((t: { id: string }) => t.id === id);
107
+ if (task) {
108
+ task.status = status;
109
+ fs.writeFileSync(queuePath, tasks.map((t: unknown) => JSON.stringify(t)).join('\n') + '\n', 'utf-8');
110
+ console.log(`\x1b[36m→ Queue task ${id}: ${status}\x1b[0m`);
111
+ }
112
+ });
82
113
  }