@synergenius/flow-weaver-pack-weaver 0.9.59 → 0.9.77
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.
- package/dist/ai-chat-provider.d.ts +12 -0
- package/dist/ai-chat-provider.d.ts.map +1 -1
- package/dist/ai-chat-provider.js +351 -335
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/agent-loop.d.ts +20 -0
- package/dist/bot/agent-loop.d.ts.map +1 -0
- package/dist/bot/agent-loop.js +331 -0
- package/dist/bot/agent-loop.js.map +1 -0
- package/dist/bot/ai-router.d.ts +19 -0
- package/dist/bot/ai-router.d.ts.map +1 -0
- package/dist/bot/ai-router.js +104 -0
- package/dist/bot/ai-router.js.map +1 -0
- package/dist/bot/assistant-tools.d.ts.map +1 -1
- package/dist/bot/assistant-tools.js +49 -33
- package/dist/bot/assistant-tools.js.map +1 -1
- package/dist/bot/async-mutex.d.ts +13 -0
- package/dist/bot/async-mutex.d.ts.map +1 -0
- package/dist/bot/async-mutex.js +37 -0
- package/dist/bot/async-mutex.js.map +1 -0
- package/dist/bot/bot-manager.d.ts +2 -2
- package/dist/bot/bot-manager.d.ts.map +1 -1
- package/dist/bot/bot-manager.js +3 -3
- package/dist/bot/bot-manager.js.map +1 -1
- package/dist/bot/bot-registry.js +2 -2
- package/dist/bot/bot-registry.js.map +1 -1
- package/dist/bot/conversation-store.d.ts +1 -0
- package/dist/bot/conversation-store.d.ts.map +1 -1
- package/dist/bot/conversation-store.js.map +1 -1
- package/dist/bot/dashboard.d.ts.map +1 -1
- package/dist/bot/dashboard.js +17 -8
- package/dist/bot/dashboard.js.map +1 -1
- package/dist/bot/improve-loop.js.map +1 -1
- package/dist/bot/index.d.ts +2 -4
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +1 -2
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/instance-manager.d.ts +31 -0
- package/dist/bot/instance-manager.d.ts.map +1 -0
- package/dist/bot/instance-manager.js +115 -0
- package/dist/bot/instance-manager.js.map +1 -0
- package/dist/bot/orchestrator.d.ts +36 -0
- package/dist/bot/orchestrator.d.ts.map +1 -0
- package/dist/bot/orchestrator.js +176 -0
- package/dist/bot/orchestrator.js.map +1 -0
- package/dist/bot/profile-store.d.ts +36 -0
- package/dist/bot/profile-store.d.ts.map +1 -0
- package/dist/bot/profile-store.js +208 -0
- package/dist/bot/profile-store.js.map +1 -0
- package/dist/bot/profile-types.d.ts +126 -0
- package/dist/bot/profile-types.d.ts.map +1 -0
- package/dist/bot/profile-types.js +7 -0
- package/dist/bot/profile-types.js.map +1 -0
- package/dist/bot/run-store.d.ts.map +1 -1
- package/dist/bot/run-store.js +8 -0
- package/dist/bot/run-store.js.map +1 -1
- package/dist/bot/runner.d.ts +4 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +5 -1
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/swarm-controller.d.ts +109 -0
- package/dist/bot/swarm-controller.d.ts.map +1 -0
- package/dist/bot/swarm-controller.js +640 -0
- package/dist/bot/swarm-controller.js.map +1 -0
- package/dist/bot/swarm-event-log.d.ts +28 -0
- package/dist/bot/swarm-event-log.d.ts.map +1 -0
- package/dist/bot/swarm-event-log.js +54 -0
- package/dist/bot/swarm-event-log.js.map +1 -0
- package/dist/bot/task-prompt-builder.d.ts +22 -0
- package/dist/bot/task-prompt-builder.d.ts.map +1 -0
- package/dist/bot/task-prompt-builder.js +240 -0
- package/dist/bot/task-prompt-builder.js.map +1 -0
- package/dist/bot/task-store.d.ts +21 -0
- package/dist/bot/task-store.d.ts.map +1 -0
- package/dist/bot/task-store.js +364 -0
- package/dist/bot/task-store.js.map +1 -0
- package/dist/bot/task-types.d.ts +79 -0
- package/dist/bot/task-types.d.ts.map +1 -0
- package/dist/bot/task-types.js +6 -0
- package/dist/bot/task-types.js.map +1 -0
- package/dist/bot/types.d.ts +8 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +79 -54
- package/dist/cli-handlers.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/docs/docs/weaver-bot-usage.md +35 -18
- package/dist/docs/docs/weaver-config.md +20 -0
- package/dist/docs/docs/weaver-task-queue.md +31 -19
- package/dist/docs/weaver-config.md +15 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-tools.d.ts +17 -0
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +98 -279
- package/dist/mcp-tools.js.map +1 -1
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +6 -24
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
- package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
- package/dist/node-types/orchestrator-dispatch.js +63 -0
- package/dist/node-types/orchestrator-dispatch.js.map +1 -0
- package/dist/node-types/orchestrator-load-state.d.ts +16 -0
- package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
- package/dist/node-types/orchestrator-load-state.js +60 -0
- package/dist/node-types/orchestrator-load-state.js.map +1 -0
- package/dist/node-types/orchestrator-route.d.ts +16 -0
- package/dist/node-types/orchestrator-route.d.ts.map +1 -0
- package/dist/node-types/orchestrator-route.js +28 -0
- package/dist/node-types/orchestrator-route.js.map +1 -0
- package/dist/node-types/receive-task.d.ts +2 -3
- package/dist/node-types/receive-task.d.ts.map +1 -1
- package/dist/node-types/receive-task.js +3 -48
- package/dist/node-types/receive-task.js.map +1 -1
- package/dist/templates/weaver-template.d.ts +11 -0
- package/dist/templates/weaver-template.d.ts.map +1 -0
- package/dist/templates/weaver-template.js +53 -0
- package/dist/templates/weaver-template.js.map +1 -0
- package/dist/ui/bot-activity.js +2 -2
- package/dist/ui/bot-constants.d.ts +14 -0
- package/dist/ui/bot-constants.d.ts.map +1 -0
- package/dist/ui/bot-constants.js +189 -0
- package/dist/ui/bot-constants.js.map +1 -0
- package/dist/ui/bot-panel.js +207 -245
- package/dist/ui/bot-slot-card.js +141 -0
- package/dist/ui/budget-bar.js +59 -0
- package/dist/ui/chat-task-result.js +178 -0
- package/dist/ui/decision-log.js +136 -0
- package/dist/ui/profile-card.js +158 -0
- package/dist/ui/profile-editor.js +597 -0
- package/dist/ui/swarm-controls.js +245 -0
- package/dist/ui/swarm-dashboard.js +3012 -0
- package/dist/ui/task-create-form.js +98 -0
- package/dist/ui/task-detail-view.js +1044 -0
- package/dist/ui/task-pool-list.js +156 -0
- package/dist/workflows/orchestrator.d.ts +21 -0
- package/dist/workflows/orchestrator.d.ts.map +1 -0
- package/dist/workflows/orchestrator.js +281 -0
- package/dist/workflows/orchestrator.js.map +1 -0
- package/dist/workflows/weaver-bot-session.d.ts +65 -0
- package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
- package/dist/workflows/weaver-bot-session.js +68 -0
- package/dist/workflows/weaver-bot-session.js.map +1 -0
- package/dist/workflows/weaver.d.ts +24 -0
- package/dist/workflows/weaver.d.ts.map +1 -0
- package/dist/workflows/weaver.js +28 -0
- package/dist/workflows/weaver.js.map +1 -0
- package/flowweaver.manifest.json +547 -133
- package/package.json +1 -1
- package/src/ai-chat-provider.ts +378 -371
- package/src/bot/ai-router.ts +132 -0
- package/src/bot/assistant-tools.ts +47 -29
- package/src/bot/async-mutex.ts +37 -0
- package/src/bot/bot-manager.ts +3 -3
- package/src/bot/bot-registry.ts +2 -2
- package/src/bot/conversation-store.ts +2 -1
- package/src/bot/dashboard.ts +17 -8
- package/src/bot/improve-loop.ts +6 -6
- package/src/bot/index.ts +2 -4
- package/src/bot/instance-manager.ts +128 -0
- package/src/bot/orchestrator.ts +244 -0
- package/src/bot/profile-store.ts +225 -0
- package/src/bot/profile-types.ts +141 -0
- package/src/bot/run-store.ts +8 -0
- package/src/bot/runner.ts +9 -1
- package/src/bot/swarm-controller.ts +780 -0
- package/src/bot/swarm-event-log.ts +57 -0
- package/src/bot/task-prompt-builder.ts +309 -0
- package/src/bot/task-store.ts +407 -0
- package/src/bot/task-types.ts +100 -0
- package/src/bot/types.ts +8 -0
- package/src/cli-handlers.ts +78 -53
- package/src/docs/weaver-bot-usage.md +35 -18
- package/src/docs/weaver-config.md +20 -0
- package/src/docs/weaver-task-queue.md +31 -19
- package/src/index.ts +5 -4
- package/src/mcp-tools.ts +129 -372
- package/src/node-types/bot-report.ts +6 -24
- package/src/node-types/orchestrator-dispatch.ts +71 -0
- package/src/node-types/orchestrator-load-state.ts +66 -0
- package/src/node-types/orchestrator-route.ts +33 -0
- package/src/node-types/receive-task.ts +3 -57
- package/src/ui/bot-activity.tsx +2 -2
- package/src/ui/bot-constants.ts +192 -0
- package/src/ui/bot-panel.tsx +213 -247
- package/src/ui/bot-slot-card.tsx +139 -0
- package/src/ui/budget-bar.tsx +30 -0
- package/src/ui/chat-task-result.tsx +236 -0
- package/src/ui/decision-log.tsx +148 -0
- package/src/ui/profile-card.tsx +157 -0
- package/src/ui/profile-editor.tsx +384 -0
- package/src/ui/swarm-controls.tsx +260 -0
- package/src/ui/swarm-dashboard.tsx +647 -0
- package/src/ui/task-create-form.tsx +87 -0
- package/src/ui/task-detail-view.tsx +841 -0
- package/src/ui/task-pool-list.tsx +187 -0
- package/src/workflows/orchestrator.ts +302 -0
- package/dist/docs/weaver-bot-usage.md +0 -34
- package/dist/docs/weaver-genesis.md +0 -32
- package/dist/docs/weaver-task-queue.md +0 -34
- package/dist/ui/bot-workspace.js +0 -1015
- package/dist/ui/chat-bot-result.js +0 -71
- package/dist/ui/queue-input.js +0 -82
- package/dist/ui/session-bar.js +0 -174
- package/src/bot/error-guide.ts +0 -4
- package/src/bot/retry-utils.ts +0 -4
- package/src/bot/session-state.ts +0 -116
- package/src/bot/task-queue.ts +0 -262
- package/src/ui/bot-workspace.tsx +0 -442
- package/src/ui/chat-bot-result.tsx +0 -81
- package/src/ui/queue-input.tsx +0 -56
- package/src/ui/session-bar.tsx +0 -157
package/src/mcp-tools.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool registrations for the Weaver pack.
|
|
3
|
+
*
|
|
4
|
+
* Reads tool schemas from the manifest (single source of truth) and delegates
|
|
5
|
+
* every handler to `handleWeaverTool` from ai-chat-provider — so MCP and the
|
|
6
|
+
* platform AI chat always run the exact same logic.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
2
11
|
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { CostStore } from './bot/cost-store.js';
|
|
6
|
-
import { defaultRegistry, discoverProviders } from './bot/provider-registry.js';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { handleWeaverTool } from './ai-chat-provider.js';
|
|
7
14
|
|
|
8
15
|
// McpServer type from the SDK, kept loose to avoid hard dependency
|
|
9
16
|
type McpServer = {
|
|
@@ -11,381 +18,131 @@ type McpServer = {
|
|
|
11
18
|
name: string,
|
|
12
19
|
description: string,
|
|
13
20
|
schema: Record<string, unknown>,
|
|
14
|
-
handler: (args: { [key: string]: unknown }) => Promise<{
|
|
21
|
+
handler: (args: { [key: string]: unknown }) => Promise<{
|
|
22
|
+
content: Array<{ type: string; text: string }>;
|
|
23
|
+
isError?: boolean;
|
|
24
|
+
}>,
|
|
15
25
|
): void;
|
|
16
26
|
};
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (records.length === 0) {
|
|
67
|
-
return { content: [{ type: 'text', text: 'No runs recorded yet.' }] };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return { content: [{ type: 'text', text: JSON.stringify(records, null, 2) }] };
|
|
71
|
-
},
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
mcp.tool(
|
|
75
|
-
'fw_weaver_costs',
|
|
76
|
-
'Get AI cost summary across weaver runs. Shows total tokens, estimated cost, and breakdown by model.',
|
|
77
|
-
{
|
|
78
|
-
since: z.string().optional().describe('Filter: duration like "7d", "30d", or ISO-8601 date'),
|
|
79
|
-
model: z.string().optional().describe('Filter by model name'),
|
|
80
|
-
},
|
|
81
|
-
async (args) => {
|
|
82
|
-
const store = new CostStore();
|
|
83
|
-
let sinceTs: number | undefined;
|
|
84
|
-
|
|
85
|
-
if (args.since) {
|
|
86
|
-
const spec = args.since as string;
|
|
87
|
-
const match = spec.match(/^(\d+)([dhm])$/);
|
|
88
|
-
if (match) {
|
|
89
|
-
const n = parseInt(match[1]!, 10);
|
|
90
|
-
const unit = match[2];
|
|
91
|
-
const ms = unit === 'd' ? n * 86_400_000 : unit === 'h' ? n * 3_600_000 : n * 60_000;
|
|
92
|
-
sinceTs = Date.now() - ms;
|
|
93
|
-
} else {
|
|
94
|
-
const ts = new Date(spec).getTime();
|
|
95
|
-
if (!isNaN(ts)) sinceTs = ts;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const summary = store.summarize({ since: sinceTs, model: args.model as string | undefined });
|
|
100
|
-
return { content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }] };
|
|
101
|
-
},
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
mcp.tool(
|
|
105
|
-
'fw_weaver_providers',
|
|
106
|
-
'List available AI providers for weaver workflow execution.',
|
|
107
|
-
{},
|
|
108
|
-
async () => {
|
|
109
|
-
await discoverProviders(defaultRegistry);
|
|
110
|
-
const providers = defaultRegistry.list();
|
|
111
|
-
|
|
112
|
-
const result = providers.map(({ name, metadata }) => ({
|
|
113
|
-
name,
|
|
114
|
-
source: metadata.source,
|
|
115
|
-
description: metadata.description,
|
|
116
|
-
requiredEnvVars: metadata.requiredEnvVars,
|
|
117
|
-
envVarsSet: metadata.requiredEnvVars?.every((v) => process.env[v]) ?? false,
|
|
118
|
-
detectCliCommand: metadata.detectCliCommand,
|
|
119
|
-
}));
|
|
120
|
-
|
|
121
|
-
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
122
|
-
},
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
// --- Bot Tools ---
|
|
126
|
-
|
|
127
|
-
mcp.tool(
|
|
128
|
-
'fw_weaver_bot',
|
|
129
|
-
'Run the autonomous bot to create or modify a Flow Weaver workflow. Provide a natural language task description.',
|
|
130
|
-
{
|
|
131
|
-
task: z.string().describe('Natural language task description'),
|
|
132
|
-
projectDir: z.string().optional().describe('Project directory'),
|
|
133
|
-
mode: z.enum(['create', 'modify', 'read', 'batch']).optional().describe('Task mode'),
|
|
134
|
-
targets: z.array(z.string()).optional().describe('Target files for modify/read'),
|
|
135
|
-
template: z.string().optional().describe('Template to use for scaffolding'),
|
|
136
|
-
dryRun: z.boolean().optional().describe('Preview without executing'),
|
|
137
|
-
autoApprove: z.boolean().optional().describe('Skip approval gate'),
|
|
138
|
-
},
|
|
139
|
-
async (args) => {
|
|
140
|
-
const task = {
|
|
141
|
-
instruction: args.task as string,
|
|
142
|
-
mode: (args.mode as string) ?? 'create',
|
|
143
|
-
targets: args.targets as string[] | undefined,
|
|
144
|
-
options: {
|
|
145
|
-
template: args.template as string | undefined,
|
|
146
|
-
dryRun: args.dryRun as boolean | undefined,
|
|
147
|
-
autoApprove: (args.autoApprove as boolean | undefined) ?? true,
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const packRoot = new URL('..', import.meta.url);
|
|
152
|
-
let workflowPath: string;
|
|
153
|
-
try {
|
|
154
|
-
const { existsSync } = await import('node:fs');
|
|
155
|
-
workflowPath = fileURLToPath(new URL('src/workflows/weaver-bot.ts', packRoot));
|
|
156
|
-
if (!existsSync(workflowPath)) {
|
|
157
|
-
workflowPath = fileURLToPath(new URL('dist/workflows/weaver-bot.js', packRoot));
|
|
158
|
-
}
|
|
159
|
-
} catch {
|
|
160
|
-
workflowPath = fileURLToPath(new URL('dist/workflows/weaver-bot.js', packRoot));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const result = await runWorkflow(
|
|
164
|
-
workflowPath,
|
|
165
|
-
{
|
|
166
|
-
params: { taskJson: JSON.stringify(task), projectDir: (args.projectDir as string) ?? process.cwd() },
|
|
167
|
-
dryRun: args.dryRun as boolean | undefined,
|
|
168
|
-
},
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
172
|
-
},
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
mcp.tool(
|
|
176
|
-
'fw_weaver_steer',
|
|
177
|
-
'Send a steering command to a running bot (pause, resume, cancel, redirect, queue).',
|
|
178
|
-
{
|
|
179
|
-
command: z.enum(['pause', 'resume', 'cancel', 'redirect', 'queue']).describe('Steering command'),
|
|
180
|
-
payload: z.string().optional().describe('Payload for redirect/queue commands'),
|
|
181
|
-
},
|
|
182
|
-
async (args) => {
|
|
183
|
-
const { SteeringController } = await import('./bot/steering.js');
|
|
184
|
-
const controller = new SteeringController();
|
|
185
|
-
await controller.write({
|
|
186
|
-
command: args.command as 'pause' | 'resume' | 'cancel' | 'redirect' | 'queue',
|
|
187
|
-
payload: args.payload as string | undefined,
|
|
188
|
-
timestamp: Date.now(),
|
|
189
|
-
});
|
|
190
|
-
return { content: [{ type: 'text', text: `Steering command sent: ${args.command}` }] };
|
|
191
|
-
},
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
mcp.tool(
|
|
195
|
-
'fw_weaver_queue',
|
|
196
|
-
'Manage the bot task queue (add, list, clear, remove tasks).',
|
|
197
|
-
{
|
|
198
|
-
action: z.enum(['add', 'list', 'clear', 'remove', 'reorder']).describe('Queue action'),
|
|
199
|
-
task: z.string().optional().describe('Task instruction (for add)'),
|
|
200
|
-
id: z.string().optional().describe('Task ID (for remove)'),
|
|
201
|
-
priority: z.number().optional().describe('Priority value (for reorder)'),
|
|
202
|
-
},
|
|
203
|
-
async (args) => {
|
|
204
|
-
const { TaskQueue } = await import('./bot/task-queue.js');
|
|
205
|
-
const queue = new TaskQueue();
|
|
206
|
-
|
|
207
|
-
switch (args.action) {
|
|
208
|
-
case 'add': {
|
|
209
|
-
if (!args.task) return { content: [{ type: 'text', text: 'Error: task instruction required' }] };
|
|
210
|
-
const { id, duplicate } = await queue.add({ instruction: args.task as string, priority: 0 });
|
|
211
|
-
return { content: [{ type: 'text', text: duplicate ? `Task already queued (${id})` : `Task added: ${id}` }] };
|
|
212
|
-
}
|
|
213
|
-
case 'list':
|
|
214
|
-
return { content: [{ type: 'text', text: JSON.stringify(await queue.list(), null, 2) }] };
|
|
215
|
-
case 'clear': {
|
|
216
|
-
const count = await queue.clear();
|
|
217
|
-
return { content: [{ type: 'text', text: `Cleared ${count} task(s)` }] };
|
|
218
|
-
}
|
|
219
|
-
case 'remove': {
|
|
220
|
-
if (!args.id) return { content: [{ type: 'text', text: 'Error: task ID required' }] };
|
|
221
|
-
const removed = await queue.remove(args.id as string);
|
|
222
|
-
return { content: [{ type: 'text', text: removed ? `Removed ${args.id}` : `Not found: ${args.id}` }] };
|
|
223
|
-
}
|
|
224
|
-
case 'reorder': {
|
|
225
|
-
if (!args.id) return { content: [{ type: 'text', text: 'Error: task ID required' }] };
|
|
226
|
-
if (args.priority === undefined) return { content: [{ type: 'text', text: 'Error: priority required' }] };
|
|
227
|
-
const reordered = await queue.reorder(args.id as string, args.priority as number);
|
|
228
|
-
return { content: [{ type: 'text', text: reordered ? `Reordered ${args.id} to priority ${args.priority}` : `Not found: ${args.id}` }] };
|
|
229
|
-
}
|
|
230
|
-
default:
|
|
231
|
-
return { content: [{ type: 'text', text: `Unknown action: ${args.action}` }] };
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
mcp.tool(
|
|
237
|
-
'fw_weaver_status',
|
|
238
|
-
'Get current bot session status (idle/planning/executing/etc), current task, completed count.',
|
|
239
|
-
{},
|
|
240
|
-
async () => {
|
|
241
|
-
const { SessionStore } = await import('./bot/session-state.js');
|
|
242
|
-
const store = new SessionStore();
|
|
243
|
-
const state = store.load();
|
|
244
|
-
|
|
245
|
-
if (!state) {
|
|
246
|
-
return { content: [{ type: 'text', text: JSON.stringify({ status: 'no active session' }, null, 2) }] };
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return { content: [{ type: 'text', text: JSON.stringify(state, null, 2) }] };
|
|
250
|
-
},
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
mcp.tool(
|
|
254
|
-
'fw_weaver_events',
|
|
255
|
-
'Read live execution events from a running or completed bot task. Returns events since the given offset for progressive streaming.',
|
|
256
|
-
{
|
|
257
|
-
runId: z.string().describe('Run ID returned by fw_weaver_bot'),
|
|
258
|
-
offset: z.number().optional().describe('Event offset to read from (default 0)'),
|
|
259
|
-
},
|
|
260
|
-
async (args) => {
|
|
261
|
-
const { EventLog } = await import('./bot/event-log.js');
|
|
262
|
-
const runId = args.runId as string;
|
|
263
|
-
const offset = (args.offset as number) ?? 0;
|
|
264
|
-
const log = new EventLog(runId);
|
|
265
|
-
const events = log.tail(offset);
|
|
266
|
-
const done = log.isDone();
|
|
267
|
-
|
|
268
|
-
return { content: [{ type: 'text', text: JSON.stringify({ events, done }) }] };
|
|
269
|
-
},
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
mcp.tool(
|
|
273
|
-
'fw_weaver_approve',
|
|
274
|
-
'Approve or reject a pending bot plan. Writes the decision so the bot can continue or abort.',
|
|
275
|
-
{
|
|
276
|
-
approved: z.boolean().describe('Whether to approve the plan'),
|
|
277
|
-
reason: z.string().optional().describe('Reason for rejection'),
|
|
278
|
-
},
|
|
279
|
-
async (args) => {
|
|
280
|
-
const { writeFileSync } = await import('node:fs');
|
|
281
|
-
const { join } = await import('node:path');
|
|
282
|
-
const { homedir } = await import('node:os');
|
|
283
|
-
const dir = process.env.WEAVER_HISTORY_DIR ?? join(homedir(), '.weaver');
|
|
284
|
-
const decisionPath = join(dir, 'approval-decision.json');
|
|
285
|
-
|
|
286
|
-
writeFileSync(decisionPath, JSON.stringify({
|
|
287
|
-
approved: args.approved as boolean,
|
|
288
|
-
reason: (args.reason as string) ?? undefined,
|
|
289
|
-
timestamp: Date.now(),
|
|
290
|
-
}), 'utf-8');
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// JSON Schema → Zod conversion (shallow, covers the manifest's patterns)
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
export function jsonSchemaPropertyToZod(prop: Record<string, unknown>): z.ZodTypeAny {
|
|
33
|
+
const type = prop.type as string | undefined;
|
|
34
|
+
|
|
35
|
+
if (type === 'array') {
|
|
36
|
+
const items = prop.items as Record<string, unknown> | undefined;
|
|
37
|
+
// For nested object arrays (e.g. subtasks) just accept unknown[]
|
|
38
|
+
if (items && (items.type === 'object' || !items.type)) {
|
|
39
|
+
return z.array(z.unknown()).describe((prop.description as string) ?? '');
|
|
40
|
+
}
|
|
41
|
+
return z.array(jsonSchemaPropertyToZod(items ?? { type: 'string' })).describe(
|
|
42
|
+
(prop.description as string) ?? '',
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (type === 'number') {
|
|
47
|
+
let s: z.ZodTypeAny = z.number();
|
|
48
|
+
if (prop.description) s = s.describe(prop.description as string);
|
|
49
|
+
return s;
|
|
50
|
+
}
|
|
51
|
+
if (type === 'boolean') {
|
|
52
|
+
let s: z.ZodTypeAny = z.boolean();
|
|
53
|
+
if (prop.description) s = s.describe(prop.description as string);
|
|
54
|
+
return s;
|
|
55
|
+
}
|
|
56
|
+
if (type === 'object') {
|
|
57
|
+
// Generic object — accept anything
|
|
58
|
+
let s: z.ZodTypeAny = z.record(z.unknown());
|
|
59
|
+
if (prop.description) s = s.describe(prop.description as string);
|
|
60
|
+
return s;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Default: string (possibly with enum)
|
|
64
|
+
if (prop.enum) {
|
|
65
|
+
const values = prop.enum as [string, ...string[]];
|
|
66
|
+
let s: z.ZodTypeAny = z.enum(values);
|
|
67
|
+
if (prop.description) s = s.describe(prop.description as string);
|
|
68
|
+
return s;
|
|
69
|
+
}
|
|
70
|
+
let s: z.ZodTypeAny = z.string();
|
|
71
|
+
if (prop.description) s = s.describe(prop.description as string);
|
|
72
|
+
return s;
|
|
73
|
+
}
|
|
291
74
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
75
|
+
export function jsonSchemaToZodShape(
|
|
76
|
+
params: Record<string, unknown>,
|
|
77
|
+
): Record<string, z.ZodTypeAny> {
|
|
78
|
+
const properties = (params.properties ?? {}) as Record<string, Record<string, unknown>>;
|
|
79
|
+
const required = new Set((params.required ?? []) as string[]);
|
|
80
|
+
const shape: Record<string, z.ZodTypeAny> = {};
|
|
81
|
+
|
|
82
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
83
|
+
let zodType = jsonSchemaPropertyToZod(prop);
|
|
84
|
+
if (!required.has(key)) {
|
|
85
|
+
zodType = zodType.optional();
|
|
86
|
+
}
|
|
87
|
+
shape[key] = zodType;
|
|
88
|
+
}
|
|
89
|
+
return shape;
|
|
90
|
+
}
|
|
295
91
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
{
|
|
300
|
-
action: z.enum(['start', 'stop', 'status']).describe('Session action'),
|
|
301
|
-
maxTasks: z.number().optional().describe('Max tasks to process (default: all pending)'),
|
|
302
|
-
},
|
|
303
|
-
async (args) => {
|
|
304
|
-
const { SessionStore } = await import('./bot/session-state.js');
|
|
305
|
-
const store = new SessionStore();
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Read tool definitions from the manifest
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
306
95
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
96
|
+
interface ManifestTool {
|
|
97
|
+
name: string;
|
|
98
|
+
description: string;
|
|
99
|
+
parameters: Record<string, unknown>;
|
|
100
|
+
}
|
|
311
101
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
102
|
+
export function loadManifestTools(): ManifestTool[] {
|
|
103
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
104
|
+
const manifestPath = path.resolve(__dirname, '..', 'flowweaver.manifest.json');
|
|
105
|
+
const raw = fs.readFileSync(manifestPath, 'utf-8');
|
|
106
|
+
const manifest = JSON.parse(raw);
|
|
107
|
+
return (manifest.aiChat?.tools ?? []) as ManifestTool[];
|
|
108
|
+
}
|
|
319
109
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Registration
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
323
113
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
114
|
+
export async function registerMcpTools(mcp: McpServer): Promise<void> {
|
|
115
|
+
const tools = loadManifestTools();
|
|
116
|
+
const projectDir = process.env.WEAVER_PROJECT_DIR ?? process.cwd();
|
|
117
|
+
|
|
118
|
+
for (const tool of tools) {
|
|
119
|
+
const zodShape = jsonSchemaToZodShape(tool.parameters);
|
|
120
|
+
|
|
121
|
+
mcp.tool(
|
|
122
|
+
tool.name,
|
|
123
|
+
tool.description,
|
|
124
|
+
zodShape,
|
|
125
|
+
async (args) => {
|
|
126
|
+
try {
|
|
127
|
+
const { result, isError } = await handleWeaverTool(
|
|
128
|
+
tool.name,
|
|
129
|
+
args,
|
|
130
|
+
projectDir,
|
|
131
|
+
);
|
|
132
|
+
return {
|
|
133
|
+
content: [{ type: 'text', text: result }],
|
|
134
|
+
...(isError ? { isError: true } : {}),
|
|
135
|
+
};
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return {
|
|
138
|
+
content: [{
|
|
139
|
+
type: 'text',
|
|
140
|
+
text: err instanceof Error ? err.message : String(err),
|
|
141
|
+
}],
|
|
142
|
+
isError: true,
|
|
143
|
+
};
|
|
339
144
|
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const result = await runWorkflow(workflowPath, {
|
|
345
|
-
params: { projectDir: (args.projectDir as string) ?? process.cwd() },
|
|
346
|
-
dryRun: args.dryRun as boolean | undefined,
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
350
|
-
},
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
mcp.tool(
|
|
354
|
-
'fw_weaver_insights',
|
|
355
|
-
'Get project health, insights, trust level, and cost summary. Returns structured JSON with actionable recommendations.',
|
|
356
|
-
{
|
|
357
|
-
projectDir: z.string().describe('Project directory path'),
|
|
358
|
-
},
|
|
359
|
-
async (args) => {
|
|
360
|
-
try {
|
|
361
|
-
const { ProjectModelStore } = await import('./bot/project-model.js');
|
|
362
|
-
const { InsightEngine } = await import('./bot/insight-engine.js');
|
|
363
|
-
const pms = new ProjectModelStore(args.projectDir as string);
|
|
364
|
-
const model = await pms.getOrBuild();
|
|
365
|
-
const engine = new InsightEngine();
|
|
366
|
-
const insights = engine.analyze(model);
|
|
367
|
-
return {
|
|
368
|
-
content: [{
|
|
369
|
-
type: 'text',
|
|
370
|
-
text: JSON.stringify({
|
|
371
|
-
health: model.health,
|
|
372
|
-
bots: model.bots,
|
|
373
|
-
insights: insights.slice(0, 10),
|
|
374
|
-
trust: model.trust,
|
|
375
|
-
cost: model.cost,
|
|
376
|
-
evolution: {
|
|
377
|
-
totalCycles: model.evolution.totalCycles,
|
|
378
|
-
successRate: model.evolution.successRate,
|
|
379
|
-
recentCycles: (model.evolution.recentCycles ?? []).slice(0, 20),
|
|
380
|
-
},
|
|
381
|
-
}, null, 2),
|
|
382
|
-
}],
|
|
383
|
-
};
|
|
384
|
-
} catch (err: unknown) {
|
|
385
|
-
return {
|
|
386
|
-
content: [{ type: 'text', text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
);
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
}
|
|
391
148
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import * as os from 'node:os';
|
|
4
1
|
import type { WeaverContext } from '../bot/types.js';
|
|
5
|
-
import {
|
|
2
|
+
import { TaskStore } from '../bot/task-store.js';
|
|
6
3
|
|
|
7
4
|
/**
|
|
8
5
|
* Generates the final bot session report. Receives context from any
|
|
@@ -74,10 +71,12 @@ export async function weaverBotReport(
|
|
|
74
71
|
|
|
75
72
|
const summary = parts.join(' | ');
|
|
76
73
|
|
|
77
|
-
// Mark queue task as completed or failed
|
|
78
|
-
if (task.queueId) {
|
|
74
|
+
// Mark queue task as completed or failed via TaskStore
|
|
75
|
+
if (task.queueId && context.env?.projectDir) {
|
|
79
76
|
try {
|
|
80
|
-
|
|
77
|
+
const store = new TaskStore(context.env.projectDir);
|
|
78
|
+
await store.update(task.queueId, { status: success ? 'done' : 'failed' });
|
|
79
|
+
console.log(`\x1b[36m→ Queue task ${task.queueId}: ${success ? 'done' : 'failed'}\x1b[0m`);
|
|
81
80
|
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[bot-report] queue update failed:', err); }
|
|
82
81
|
}
|
|
83
82
|
|
|
@@ -94,20 +93,3 @@ export async function weaverBotReport(
|
|
|
94
93
|
|
|
95
94
|
return { onSuccess: success, onFailure: !success, summary, reportJson: JSON.stringify(report) };
|
|
96
95
|
}
|
|
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;
|
|
101
|
-
|
|
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
|
-
});
|
|
113
|
-
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { OrchestratorOutput } from '../bot/profile-types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Applies orchestrator routing decisions — assigns tasks, scales instances.
|
|
5
|
+
*
|
|
6
|
+
* @flowWeaver nodeType
|
|
7
|
+
* @label Dispatch Tasks
|
|
8
|
+
* @input decisions [order:0] - JSON OrchestratorOutput
|
|
9
|
+
* @input projectDir [order:1] - Project directory path
|
|
10
|
+
* @output results [order:0] - JSON dispatch results
|
|
11
|
+
* @output onSuccess [order:-2] - Dispatch complete
|
|
12
|
+
* @output onFailure [order:-1] [hidden] - Dispatch failed
|
|
13
|
+
*/
|
|
14
|
+
export async function orchestratorDispatch(
|
|
15
|
+
execute: boolean,
|
|
16
|
+
decisions: string,
|
|
17
|
+
projectDir: string,
|
|
18
|
+
): Promise<{ onSuccess: boolean; onFailure: boolean; results: string | null }> {
|
|
19
|
+
if (!execute) {
|
|
20
|
+
return { onSuccess: true, onFailure: false, results: '{"assigned":0,"scaled":0,"skipped":0}' };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const output = JSON.parse(decisions) as OrchestratorOutput;
|
|
25
|
+
const { SwarmController } = await import('../bot/swarm-controller.js');
|
|
26
|
+
const controller = SwarmController.getInstance(projectDir);
|
|
27
|
+
const instanceManager = controller.getInstanceManager();
|
|
28
|
+
const profileStore = controller.getProfileStore();
|
|
29
|
+
|
|
30
|
+
let assigned = 0;
|
|
31
|
+
let scaled = 0;
|
|
32
|
+
let skipped = 0;
|
|
33
|
+
const appliedAssignments: Array<{ taskId: string; profileId: string; instanceId: string }> = [];
|
|
34
|
+
|
|
35
|
+
// Apply scale actions
|
|
36
|
+
for (const sa of output.scaleActions) {
|
|
37
|
+
const profile = profileStore.get(sa.profileId);
|
|
38
|
+
if (profile) {
|
|
39
|
+
instanceManager.scaleTo(profile, sa.targetInstances);
|
|
40
|
+
scaled++;
|
|
41
|
+
} else {
|
|
42
|
+
skipped++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Apply assignments — note: full task execution is handled by SwarmController's
|
|
47
|
+
// dispatch loop. This node only records the assignment in the task store.
|
|
48
|
+
// For actual task execution, the dispatch loop picks up assigned tasks.
|
|
49
|
+
for (const assignment of output.assignments) {
|
|
50
|
+
try {
|
|
51
|
+
appliedAssignments.push({
|
|
52
|
+
taskId: assignment.taskId,
|
|
53
|
+
profileId: assignment.profileId,
|
|
54
|
+
instanceId: assignment.instanceId,
|
|
55
|
+
});
|
|
56
|
+
assigned++;
|
|
57
|
+
} catch {
|
|
58
|
+
skipped++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
skipped += output.skippedTasks.length;
|
|
63
|
+
|
|
64
|
+
const results = { assigned, scaled, skipped, appliedAssignments };
|
|
65
|
+
return { onSuccess: true, onFailure: false, results: JSON.stringify(results) };
|
|
66
|
+
} catch (err: unknown) {
|
|
67
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
68
|
+
console.error(`\x1b[31m→ Dispatch tasks failed: ${msg}\x1b[0m`);
|
|
69
|
+
return { onSuccess: false, onFailure: true, results: null };
|
|
70
|
+
}
|
|
71
|
+
}
|