@synergenius/flow-weaver-pack-weaver 0.9.199 → 0.9.201
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.js +5 -5
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/acceptance-merge.d.ts +21 -0
- package/dist/bot/acceptance-merge.d.ts.map +1 -0
- package/dist/bot/acceptance-merge.js +46 -0
- package/dist/bot/acceptance-merge.js.map +1 -0
- package/dist/bot/ai-client.d.ts +14 -2
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +71 -24
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/assistant-tools.js +3 -3
- package/dist/bot/assistant-tools.js.map +1 -1
- package/dist/bot/audit-logger.d.ts.map +1 -1
- package/dist/bot/audit-logger.js +34 -14
- package/dist/bot/audit-logger.js.map +1 -1
- package/dist/bot/audit-trail.d.ts +67 -0
- package/dist/bot/audit-trail.d.ts.map +1 -0
- package/dist/bot/audit-trail.js +153 -0
- package/dist/bot/audit-trail.js.map +1 -0
- package/dist/bot/behavior-defaults.d.ts +1 -1
- package/dist/bot/behavior-defaults.d.ts.map +1 -1
- package/dist/bot/behavior-defaults.js +7 -3
- package/dist/bot/behavior-defaults.js.map +1 -1
- package/dist/bot/capability-registry.d.ts +9 -0
- package/dist/bot/capability-registry.d.ts.map +1 -1
- package/dist/bot/capability-registry.js +81 -27
- package/dist/bot/capability-registry.js.map +1 -1
- package/dist/bot/capability-types.d.ts +10 -0
- package/dist/bot/capability-types.d.ts.map +1 -1
- package/dist/bot/cli-provider.d.ts.map +1 -1
- package/dist/bot/cli-provider.js +8 -7
- package/dist/bot/cli-provider.js.map +1 -1
- package/dist/bot/preflight.d.ts +48 -0
- package/dist/bot/preflight.d.ts.map +1 -0
- package/dist/bot/preflight.js +247 -0
- package/dist/bot/preflight.js.map +1 -0
- package/dist/bot/provider-shim.d.ts +74 -0
- package/dist/bot/provider-shim.d.ts.map +1 -0
- package/dist/bot/provider-shim.js +176 -0
- package/dist/bot/provider-shim.js.map +1 -0
- package/dist/bot/runner.d.ts +2 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +60 -17
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +72 -115
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/swarm-controller.d.ts +2 -0
- package/dist/bot/swarm-controller.d.ts.map +1 -1
- package/dist/bot/swarm-controller.js +92 -20
- package/dist/bot/swarm-controller.js.map +1 -1
- package/dist/bot/task-create-handler.d.ts +37 -0
- package/dist/bot/task-create-handler.d.ts.map +1 -0
- package/dist/bot/task-create-handler.js +124 -0
- package/dist/bot/task-create-handler.js.map +1 -0
- package/dist/bot/task-store.d.ts +1 -0
- package/dist/bot/task-store.d.ts.map +1 -1
- package/dist/bot/task-store.js +67 -0
- package/dist/bot/task-store.js.map +1 -1
- package/dist/bot/types.d.ts +1 -1
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/bot/weaver-tools.d.ts.map +1 -1
- package/dist/bot/weaver-tools.js +7 -39
- package/dist/bot/weaver-tools.js.map +1 -1
- package/dist/node-types/agent-execute.d.ts +25 -8
- package/dist/node-types/agent-execute.d.ts.map +1 -1
- package/dist/node-types/agent-execute.js +89 -23
- package/dist/node-types/agent-execute.js.map +1 -1
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +24 -3
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/plan-task.d.ts +8 -17
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +217 -256
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/node-types/review-result.js +8 -6
- package/dist/node-types/review-result.js.map +1 -1
- package/dist/palindrome.d.ts +9 -0
- package/dist/palindrome.d.ts.map +1 -0
- package/dist/palindrome.js +14 -0
- package/dist/palindrome.js.map +1 -0
- package/dist/ui/approval-card.js +91 -82
- package/dist/ui/bot-activity.js +73 -56
- package/dist/ui/bot-config.js +48 -31
- package/dist/ui/bot-dashboard.js +52 -36
- package/dist/ui/bot-panel.js +230 -228
- package/dist/ui/bot-slot-card.js +100 -90
- package/dist/ui/bot-status.js +37 -15
- package/dist/ui/budget-bar.js +57 -31
- package/dist/ui/capability-editor.js +447 -378
- package/dist/ui/chat-task-result.js +78 -71
- package/dist/ui/decision-log.js +68 -81
- package/dist/ui/genesis-block.js +86 -95
- package/dist/ui/instance-stream-view.js +722 -0
- package/dist/ui/profile-card.js +96 -221
- package/dist/ui/profile-editor.js +532 -575
- package/dist/ui/settings-section.js +41 -45
- package/dist/ui/swarm-controls.js +212 -135
- package/dist/ui/swarm-dashboard.js +3992 -2715
- package/dist/ui/task-detail-view.js +415 -521
- package/dist/ui/task-editor.js +339 -390
- package/dist/ui/task-pool-list.js +60 -55
- package/dist/workflows/src/palindrome.d.ts +11 -0
- package/dist/workflows/src/palindrome.d.ts.map +1 -0
- package/dist/workflows/src/palindrome.js +16 -0
- package/dist/workflows/src/palindrome.js.map +1 -0
- package/dist/workflows/tests/palindrome.test.d.ts +2 -0
- package/dist/workflows/tests/palindrome.test.d.ts.map +1 -0
- package/dist/workflows/tests/palindrome.test.js +41 -0
- package/dist/workflows/tests/palindrome.test.js.map +1 -0
- package/dist/workflows/weaver-bot-batch.js +1 -1
- package/dist/workflows/weaver-bot-batch.js.map +1 -1
- package/dist/workflows/weaver-bot.js +1 -1
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +1 -1
- package/package.json +8 -2
- package/src/ai-chat-provider.ts +5 -5
- package/src/bot/acceptance-merge.ts +62 -0
- package/src/bot/ai-client.ts +77 -21
- package/src/bot/assistant-tools.ts +3 -3
- package/src/bot/audit-logger.ts +42 -14
- package/src/bot/audit-trail.ts +211 -0
- package/src/bot/behavior-defaults.ts +7 -2
- package/src/bot/capability-registry.ts +84 -28
- package/src/bot/capability-types.ts +11 -0
- package/src/bot/cli-provider.ts +8 -7
- package/src/bot/preflight.ts +285 -0
- package/src/bot/provider-shim.ts +218 -0
- package/src/bot/runner.ts +68 -20
- package/src/bot/step-executor.ts +69 -127
- package/src/bot/swarm-controller.ts +94 -20
- package/src/bot/task-create-handler.ts +164 -0
- package/src/bot/task-store.ts +83 -0
- package/src/bot/types.ts +4 -1
- package/src/bot/weaver-tools.ts +7 -45
- package/src/node-types/agent-execute.ts +102 -16
- package/src/node-types/bot-report.ts +24 -3
- package/src/node-types/plan-task.ts +238 -280
- package/src/node-types/review-result.ts +8 -6
- package/src/palindrome.ts +14 -0
- package/src/ui/approval-card.tsx +78 -62
- package/src/ui/bot-activity.tsx +12 -10
- package/src/ui/bot-config.tsx +12 -10
- package/src/ui/bot-dashboard.tsx +13 -11
- package/src/ui/bot-panel.tsx +189 -171
- package/src/ui/bot-slot-card.tsx +125 -70
- package/src/ui/bot-status.tsx +4 -4
- package/src/ui/budget-bar.tsx +86 -25
- package/src/ui/capability-editor.tsx +392 -257
- package/src/ui/chat-task-result.tsx +81 -78
- package/src/ui/decision-log.tsx +76 -73
- package/src/ui/genesis-block.tsx +91 -61
- package/src/ui/instance-stream-view.tsx +861 -0
- package/src/ui/profile-card.tsx +195 -168
- package/src/ui/profile-editor.tsx +453 -370
- package/src/ui/settings-section.tsx +46 -39
- package/src/ui/swarm-controls.tsx +252 -123
- package/src/ui/swarm-dashboard.tsx +999 -466
- package/src/ui/task-detail-view.tsx +485 -428
- package/src/ui/task-editor.tsx +329 -271
- package/src/ui/task-pool-list.tsx +68 -62
- package/src/workflows/src/palindrome.ts +16 -0
- package/src/workflows/tests/palindrome.test.ts +49 -0
- package/src/workflows/weaver-bot-batch.ts +1 -1
- package/src/workflows/weaver-bot.ts +1 -1
- package/dist/ui/bot-constants.d.ts +0 -14
- package/dist/ui/bot-constants.d.ts.map +0 -1
- package/dist/ui/bot-constants.js +0 -189
- package/dist/ui/bot-constants.js.map +0 -1
- package/dist/ui/steer-api.d.ts +0 -7
- package/dist/ui/steer-api.d.ts.map +0 -1
- package/dist/ui/steer-api.js +0 -11
- package/dist/ui/steer-api.js.map +0 -1
- package/dist/ui/trace-to-timeline.d.ts +0 -91
- package/dist/ui/trace-to-timeline.d.ts.map +0 -1
- package/dist/ui/trace-to-timeline.js +0 -116
- package/dist/ui/trace-to-timeline.js.map +0 -1
- package/dist/ui/use-stream-timeline.d.ts +0 -50
- package/dist/ui/use-stream-timeline.d.ts.map +0 -1
- package/dist/ui/use-stream-timeline.js +0 -245
- package/dist/ui/use-stream-timeline.js.map +0 -1
|
@@ -23,7 +23,7 @@ const CAP_CORE: CapabilityDefinition = {
|
|
|
23
23
|
prompt: `You are Weaver. Execute tasks by calling tools — do not describe what you would do.
|
|
24
24
|
|
|
25
25
|
## System Constraints
|
|
26
|
-
- All file paths
|
|
26
|
+
- All file paths MUST be relative to the workspace root (e.g. "src/index.ts", not "/home/user/project/src/index.ts"). NEVER use absolute paths. "../" is blocked.
|
|
27
27
|
- Writes that shrink a file >50% or write empty content are BLOCKED by the system.
|
|
28
28
|
- Blocked shell commands: rm -rf, git push, npm publish, sudo, curl|sh.`,
|
|
29
29
|
};
|
|
@@ -36,46 +36,69 @@ const CAP_ROLE_ORCHESTRATOR: CapabilityDefinition = {
|
|
|
36
36
|
name: 'role-orchestrator',
|
|
37
37
|
description: 'Orchestrator role: decomposes objectives into subtask DAGs.',
|
|
38
38
|
tools: [OP_TASK_CREATE, OP_LIST_FILES, OP_READ_FILE],
|
|
39
|
+
acceptance: [
|
|
40
|
+
{ name: 'subtasks-created', command: 'python3 -c "import json; tasks=json.load(open(\'.weaver/tasks.json\')); exit(0 if len(tasks)>=3 else 1)"' },
|
|
41
|
+
{ name: 'deps-defined', command: 'python3 -c "import json; tasks=json.load(open(\'.weaver/tasks.json\')); exit(0 if any(t.get(\'dependsOn\') for t in tasks) else 1)"' },
|
|
42
|
+
],
|
|
39
43
|
prompt: `## YOUR ROLE: Orchestrator
|
|
40
44
|
You decompose objectives into subtasks. You never write code or create files directly.
|
|
41
45
|
Your only output is task_create calls + done.
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
|
|
47
|
+
### Execution Planning Protocol
|
|
48
|
+
Before creating subtasks, you MUST:
|
|
49
|
+
1. Use list_files and read_file to read every source file. Map the dependency graph (which files import which).
|
|
50
|
+
2. IDENTIFY the critical path — the longest sequential chain. This is your bottleneck.
|
|
51
|
+
3. GROUP tasks to match worker count (shown in context as maxConcurrent=N).
|
|
52
|
+
- Each dependency level should have at most N parallel tasks.
|
|
53
|
+
- Combine small independent files into single tasks to reduce overhead.
|
|
54
|
+
- Separate high-risk files (many bugs/complexity) from clean ones.
|
|
55
|
+
- Never create more sequential levels than necessary.
|
|
56
|
+
4. SHOW YOUR REASONING in the first task_create description:
|
|
57
|
+
- Dependency graph you found
|
|
58
|
+
- Critical path identified
|
|
59
|
+
- Why you grouped tasks this way
|
|
60
|
+
|
|
61
|
+
### Task Creation Rules
|
|
62
|
+
- Create subtasks via task_create with parentId: "@self".
|
|
63
|
+
- Assign profiles: developer (code), reviewer (review), ops (infra/setup).
|
|
64
|
+
- Set dependsOn using task titles (resolved to IDs automatically).
|
|
65
|
+
- Fewer tasks with more work each > many tiny serial tasks.
|
|
66
|
+
- A file and its only dependent CAN be in the same task.
|
|
67
|
+
- Tests can be combined with the last implementation task.
|
|
68
|
+
- Your LAST subtask: "Review & Steer" assigned to orchestrator, dependsOn all others.
|
|
56
69
|
|
|
57
70
|
### Acceptance Criteria
|
|
58
71
|
Every subtask MUST have acceptance.checks — shell commands that verify "done" (exit 0 = pass).
|
|
72
|
+
Checks must test BEHAVIOR (run the code, import the module), not string patterns (grep for text).
|
|
59
73
|
The system runs them automatically after each run. If any fail, the task stays open.
|
|
60
74
|
Examples:
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
75
|
+
- Compiles: npx tsc --noEmit
|
|
76
|
+
- Tests pass: npx vitest run
|
|
77
|
+
- Module works: node -e "import('./src/db.js').then(m => process.exit(m.getById ? 0 : 1))"
|
|
78
|
+
- File exists: test -f src/types.ts
|
|
79
|
+
|
|
80
|
+
### Design First
|
|
81
|
+
For multi-file projects, your FIRST subtask should create a .design.md with:
|
|
82
|
+
- Module map: which files, what each exports (function signatures with types)
|
|
83
|
+
- Conventions: naming, error handling, patterns
|
|
84
|
+
All subsequent developer tasks must read .design.md before writing code.
|
|
65
85
|
|
|
66
86
|
### Steering Mode (when running a Review & Steer task)
|
|
67
87
|
Read the sibling task list in your context — it shows status, run count, and check failures with error details.
|
|
68
88
|
- All checks pass → done.
|
|
69
89
|
- Tasks with 0 runs still open → they will be picked up, do not recreate them.
|
|
70
|
-
- Checks failing → read the specific error in the check detail, then create a targeted fix task addressing that exact error.
|
|
90
|
+
- Checks failing → read the specific error in the check detail, then create a targeted fix task addressing that exact error.
|
|
71
91
|
- Task stagnant (3+ failed runs) → redefine with smaller scope or reassign to different profile.
|
|
72
|
-
- Before creating ANY task, check if an existing open sibling already covers the same work.
|
|
92
|
+
- Before creating ANY task, check if an existing open sibling already covers the same work.
|
|
73
93
|
- After creating fix tasks, create one more Review & Steer depending on them, then done.`,
|
|
74
94
|
};
|
|
75
95
|
|
|
76
96
|
const CAP_ROLE_DEVELOPER: CapabilityDefinition = {
|
|
77
97
|
name: 'role-developer',
|
|
78
98
|
description: 'Developer role: writes code, creates files, runs commands.',
|
|
99
|
+
acceptance: [
|
|
100
|
+
{ name: 'file-changes-produced', command: 'test $(find src tests -name "*.ts" -newer .weaver/swarm.json 2>/dev/null | wc -l) -gt 0 || test $(find src tests -name "*.js" -newer .weaver/swarm.json 2>/dev/null | wc -l) -gt 0', condition: 'src' },
|
|
101
|
+
],
|
|
79
102
|
prompt: `## YOUR ROLE: Developer
|
|
80
103
|
You write code and produce files. Execute the task directly — do not delegate.
|
|
81
104
|
|
|
@@ -128,8 +151,8 @@ const CAP_SHELL: CapabilityDefinition = {
|
|
|
128
151
|
|
|
129
152
|
const CAP_TASK_MGMT: CapabilityDefinition = {
|
|
130
153
|
name: 'task-mgmt',
|
|
131
|
-
description: 'Create swarm subtasks.',
|
|
132
|
-
tools: [OP_TASK_CREATE],
|
|
154
|
+
description: 'Create and inspect swarm subtasks.',
|
|
155
|
+
tools: [OP_TASK_CREATE, 'task_list', 'task_get', 'task_update'],
|
|
133
156
|
prompt: `## Task Management
|
|
134
157
|
- task_create(title, description?, assignedProfile?, parentId?, dependsOn?, complexity?, acceptance?):
|
|
135
158
|
Creates a subtask in the swarm task pool. Returns task ID.
|
|
@@ -138,6 +161,9 @@ const CAP_TASK_MGMT: CapabilityDefinition = {
|
|
|
138
161
|
- assignedProfile: "developer" | "reviewer" | "ops" | "orchestrator". Omit for auto-routing.
|
|
139
162
|
- parentId: "@self" to nest under current task. Omit for top-level.
|
|
140
163
|
- dependsOn: Array of task titles. Resolved to IDs automatically.
|
|
164
|
+
- task_list(status?): List tasks in the swarm. Optionally filter by status (pending, in-progress, done, failed).
|
|
165
|
+
- task_get(id): Get full details of a specific task.
|
|
166
|
+
- task_update(id, notes?, files?, description?): Update a task's notes, files list, or description.
|
|
141
167
|
- complexity: "trivial" | "simple" | "moderate" | "complex".
|
|
142
168
|
- acceptance: { checks: [{ name: string, command: string }] } — shell commands that exit 0 on success.`,
|
|
143
169
|
};
|
|
@@ -254,9 +280,13 @@ const CAP_VERIFICATION: CapabilityDefinition = {
|
|
|
254
280
|
name: 'verification',
|
|
255
281
|
description: 'TypeScript compilation and test runner verification.',
|
|
256
282
|
tools: [OP_RUN_SHELL],
|
|
283
|
+
acceptance: [
|
|
284
|
+
{ name: 'tsc-compiles', command: 'npx tsc --noEmit', condition: "find src -name '*.ts' | head -1 | grep -q ." },
|
|
285
|
+
],
|
|
257
286
|
prompt: `## Verification
|
|
258
|
-
|
|
259
|
-
-
|
|
287
|
+
Use run_shell for compilation and test verification:
|
|
288
|
+
- npx tsc --noEmit — returns TypeScript compilation errors or empty on success.
|
|
289
|
+
- npx vitest run — returns test results with pass/fail counts.`,
|
|
260
290
|
};
|
|
261
291
|
|
|
262
292
|
const CAP_CROSS_FILE_CHECK: CapabilityDefinition = {
|
|
@@ -264,8 +294,9 @@ const CAP_CROSS_FILE_CHECK: CapabilityDefinition = {
|
|
|
264
294
|
description: 'Cross-file dependency verification.',
|
|
265
295
|
tools: [OP_READ_FILE, OP_LIST_FILES, OP_RUN_SHELL],
|
|
266
296
|
prompt: `## Cross-File Checks
|
|
267
|
-
Use
|
|
268
|
-
|
|
297
|
+
Use list_files to find relevant files, read_file to inspect them,
|
|
298
|
+
and run_shell with grep to find all import/export references across files.
|
|
299
|
+
Verify import paths resolve to actual exports.`,
|
|
269
300
|
};
|
|
270
301
|
|
|
271
302
|
const CAP_PROJECT_SETUP: CapabilityDefinition = {
|
|
@@ -282,7 +313,7 @@ const CAP_SECURITY: CapabilityDefinition = {
|
|
|
282
313
|
description: 'Security audit tools.',
|
|
283
314
|
tools: [OP_READ_FILE, OP_LIST_FILES, OP_RUN_SHELL],
|
|
284
315
|
prompt: `## Security
|
|
285
|
-
Use
|
|
316
|
+
Use list_files to discover files, read_file to inspect them, and run_shell with grep to scan for hardcoded secrets, eval(), shell injection patterns.
|
|
286
317
|
Use npm audit (via run_shell) for dependency vulnerabilities.
|
|
287
318
|
Finding format: FILE:LINE | SEVERITY (critical/high/medium/low) | ISSUE.`,
|
|
288
319
|
};
|
|
@@ -358,7 +389,7 @@ export const BUILT_IN_CAPABILITIES: readonly CapabilityDefinition[] = [
|
|
|
358
389
|
|
|
359
390
|
/** Capability pools per profile role. Triage selects from these per task. */
|
|
360
391
|
export const PROFILE_CAPABILITIES: Record<string, string[]> = {
|
|
361
|
-
orchestrator: ['core', 'role-orchestrator', 'decomposition', 'routing', 'task-mgmt', 'context'],
|
|
392
|
+
orchestrator: ['core', 'role-orchestrator', 'decomposition', 'routing', 'task-mgmt', 'shell', 'context'],
|
|
362
393
|
developer: ['core', 'role-developer', 'file-ops', 'shell', 'verification', 'cross-file-check', 'context'],
|
|
363
394
|
'fw-developer': ['core', 'role-developer', 'file-ops', 'shell', 'verification', 'cross-file-check', 'fw-grammar', 'fw-validate', 'fw-cli', 'context'],
|
|
364
395
|
reviewer: ['core', 'role-reviewer', 'code-review', 'security', 'context'],
|
|
@@ -374,6 +405,31 @@ export function getCapability(name: string): CapabilityDefinition | undefined {
|
|
|
374
405
|
return capabilityMap.get(name);
|
|
375
406
|
}
|
|
376
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Collect all acceptance checks from a profile's capabilities.
|
|
410
|
+
* Deduplicates by check name — first occurrence wins.
|
|
411
|
+
*/
|
|
412
|
+
export function getCapabilityAcceptanceChecks(profileId: string): Array<{ name: string; command: string; condition?: string }> {
|
|
413
|
+
const capNames = PROFILE_CAPABILITIES[profileId];
|
|
414
|
+
if (!capNames) return [];
|
|
415
|
+
|
|
416
|
+
const seen = new Set<string>();
|
|
417
|
+
const checks: Array<{ name: string; command: string; condition?: string }> = [];
|
|
418
|
+
|
|
419
|
+
for (const capName of capNames) {
|
|
420
|
+
const cap = capabilityMap.get(capName);
|
|
421
|
+
if (!cap?.acceptance) continue;
|
|
422
|
+
for (const check of cap.acceptance) {
|
|
423
|
+
if (!seen.has(check.name)) {
|
|
424
|
+
seen.add(check.name);
|
|
425
|
+
checks.push(check);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return checks;
|
|
431
|
+
}
|
|
432
|
+
|
|
377
433
|
/** List all available capabilities. */
|
|
378
434
|
export function listCapabilities(): CapabilityDefinition[] {
|
|
379
435
|
return [...BUILT_IN_CAPABILITIES];
|
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
* Built-in capabilities ship with the pack. Custom capabilities can be
|
|
12
12
|
* added per-workspace via .weaver/capabilities/.
|
|
13
13
|
*/
|
|
14
|
+
export interface CapabilityAcceptanceCheck {
|
|
15
|
+
/** Human-readable check name (e.g. 'compiles', 'tests-pass'). */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Shell command that exits 0 on success. */
|
|
18
|
+
command: string;
|
|
19
|
+
/** Only run if this file exists in the workspace (e.g. 'tsconfig.json'). */
|
|
20
|
+
condition?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
export interface CapabilityDefinition {
|
|
15
24
|
/** Unique identifier (e.g. 'typescript', 'fw-grammar'). */
|
|
16
25
|
name: string;
|
|
@@ -20,4 +29,6 @@ export interface CapabilityDefinition {
|
|
|
20
29
|
prompt: string;
|
|
21
30
|
/** Tool operation names this capability grants (e.g. ['write_file', 'patch_file']). */
|
|
22
31
|
tools?: string[];
|
|
32
|
+
/** Deterministic acceptance checks auto-merged into every task using this capability. */
|
|
33
|
+
acceptance?: CapabilityAcceptanceCheck[];
|
|
23
34
|
}
|
package/src/bot/cli-provider.ts
CHANGED
|
@@ -88,13 +88,14 @@ export class CliAgentProvider implements BotAgentProvider {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
private async *streamRaw(userPrompt: string, systemPrompt?: string): AsyncGenerator<StreamChunk> {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
// Use centralized CLI config — enforces --tools "" and --strict-mcp-config
|
|
92
|
+
const { getCliBaseArgs } = await import('@synergenius/flow-weaver/agent');
|
|
93
|
+
const args = getCliBaseArgs({
|
|
94
|
+
model: this.model,
|
|
95
|
+
systemPrompt,
|
|
96
|
+
outputFormat: 'stream-json',
|
|
97
|
+
includePartialMessages: true,
|
|
98
|
+
});
|
|
98
99
|
|
|
99
100
|
const child = spawn('claude', args, {
|
|
100
101
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-flight validator — runs before the swarm starts to catch config bugs.
|
|
3
|
+
*
|
|
4
|
+
* Validates that the tool pipeline is intact:
|
|
5
|
+
* 1. Every BOT_TOOLS entry has a TOOL_SCHEMAS entry (schema completeness)
|
|
6
|
+
* 2. Every schema'd tool has an execution handler (handler completeness)
|
|
7
|
+
* 3. Every mode's resolveToolsForTask produces only schema'd tools
|
|
8
|
+
* 4. Capability-granted tools are all schema'd
|
|
9
|
+
* 5. MCP bridge round-trip (create bridge, call tool via socket, verify result)
|
|
10
|
+
*
|
|
11
|
+
* Fails fast with clear error messages before any AI calls are made.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as net from 'node:net';
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import { ALL_TOOLS, BOT_TOOLS, resolveToolsForTask } from './tool-registry.js';
|
|
17
|
+
import { TOOL_SCHEMAS } from '../node-types/plan-task.js';
|
|
18
|
+
|
|
19
|
+
// Known execution handlers — tools handled by weaver-tools.ts (bot context)
|
|
20
|
+
// and assistant-tools.ts (assistant context). Maintained manually because
|
|
21
|
+
// the handlers are switch/case statements, not a registry.
|
|
22
|
+
const WEAVER_TOOL_HANDLERS = new Set([
|
|
23
|
+
'read_file', 'write_file', 'patch_file', 'list_files', 'run_shell',
|
|
24
|
+
'validate', 'tsc_check', 'run_tests', 'learn', 'recall', 'remember',
|
|
25
|
+
'web_fetch', 'task_create', 'task_list', 'task_get', 'task_update',
|
|
26
|
+
'ask_user', 'done', 'complete', 'respond',
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
export interface PreflightError {
|
|
30
|
+
check: string;
|
|
31
|
+
tool: string;
|
|
32
|
+
message: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PreflightResult {
|
|
36
|
+
passed: boolean;
|
|
37
|
+
errors: PreflightError[];
|
|
38
|
+
warnings: PreflightError[];
|
|
39
|
+
checks: { name: string; passed: boolean; count: number }[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Run all pre-flight checks. Returns a result with errors and warnings.
|
|
44
|
+
* Call this before starting the swarm — if errors exist, abort.
|
|
45
|
+
*/
|
|
46
|
+
export function runPreflight(options?: {
|
|
47
|
+
capabilities?: string[];
|
|
48
|
+
mode?: string;
|
|
49
|
+
}): PreflightResult {
|
|
50
|
+
const errors: PreflightError[] = [];
|
|
51
|
+
const warnings: PreflightError[] = [];
|
|
52
|
+
const checks: { name: string; passed: boolean; count: number }[] = [];
|
|
53
|
+
|
|
54
|
+
// 1. Schema completeness — every BOT_TOOLS entry has a TOOL_SCHEMAS entry
|
|
55
|
+
{
|
|
56
|
+
const missing = BOT_TOOLS
|
|
57
|
+
.map(t => t.name)
|
|
58
|
+
.filter(name => !TOOL_SCHEMAS[name]);
|
|
59
|
+
checks.push({
|
|
60
|
+
name: 'schema-completeness',
|
|
61
|
+
passed: missing.length === 0,
|
|
62
|
+
count: BOT_TOOLS.length - missing.length,
|
|
63
|
+
});
|
|
64
|
+
for (const name of missing) {
|
|
65
|
+
errors.push({
|
|
66
|
+
check: 'schema-completeness',
|
|
67
|
+
tool: name,
|
|
68
|
+
message: `Tool '${name}' is in BOT_TOOLS (described in system prompt) but has no TOOL_SCHEMAS entry. The model will see it but cannot call it.`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 2. Handler completeness — every TOOL_SCHEMAS entry has an execution handler
|
|
74
|
+
{
|
|
75
|
+
const schemaNames = Object.keys(TOOL_SCHEMAS);
|
|
76
|
+
const missing = schemaNames.filter(name => !WEAVER_TOOL_HANDLERS.has(name));
|
|
77
|
+
checks.push({
|
|
78
|
+
name: 'handler-completeness',
|
|
79
|
+
passed: missing.length === 0,
|
|
80
|
+
count: schemaNames.length - missing.length,
|
|
81
|
+
});
|
|
82
|
+
for (const name of missing) {
|
|
83
|
+
errors.push({
|
|
84
|
+
check: 'handler-completeness',
|
|
85
|
+
tool: name,
|
|
86
|
+
message: `Tool '${name}' has a TOOL_SCHEMAS entry but no execution handler in weaver-tools.ts or assistant-tools.ts. Calls will return "Unknown tool".`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 3. Mode consistency — every mode produces only schema'd tools
|
|
92
|
+
{
|
|
93
|
+
let modeErrors = 0;
|
|
94
|
+
for (const mode of ['create', 'modify', 'read', 'batch']) {
|
|
95
|
+
const modeTools = resolveToolsForTask({ mode });
|
|
96
|
+
for (const name of modeTools) {
|
|
97
|
+
if (!TOOL_SCHEMAS[name]) {
|
|
98
|
+
modeErrors++;
|
|
99
|
+
errors.push({
|
|
100
|
+
check: 'mode-consistency',
|
|
101
|
+
tool: name,
|
|
102
|
+
message: `Mode '${mode}' grants tool '${name}' via resolveToolsForTask but it has no TOOL_SCHEMAS entry.`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
checks.push({
|
|
108
|
+
name: 'mode-consistency',
|
|
109
|
+
passed: modeErrors === 0,
|
|
110
|
+
count: 4 - (modeErrors > 0 ? 1 : 0),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 4. Registry-schema alignment — every ALL_TOOLS entry should have a schema
|
|
115
|
+
{
|
|
116
|
+
const allNames = ALL_TOOLS.map(t => t.name);
|
|
117
|
+
const missing = allNames.filter(name => !TOOL_SCHEMAS[name]);
|
|
118
|
+
checks.push({
|
|
119
|
+
name: 'registry-schema-alignment',
|
|
120
|
+
passed: true, // warnings only — not a blocker
|
|
121
|
+
count: allNames.length - missing.length,
|
|
122
|
+
});
|
|
123
|
+
for (const name of missing) {
|
|
124
|
+
warnings.push({
|
|
125
|
+
check: 'registry-schema-alignment',
|
|
126
|
+
tool: name,
|
|
127
|
+
message: `Tool '${name}' is in ALL_TOOLS but has no TOOL_SCHEMAS entry. If it's a bot-only or assistant-only tool, this may be intentional.`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
passed: errors.length === 0,
|
|
134
|
+
errors,
|
|
135
|
+
warnings,
|
|
136
|
+
checks,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Runtime check: create a real MCP bridge, send a test tool call through the
|
|
142
|
+
* Unix socket, verify the round-trip. Catches MCP tool server startup failures,
|
|
143
|
+
* socket connectivity issues, and executor wiring bugs.
|
|
144
|
+
*
|
|
145
|
+
* Returns a PreflightResult that can be merged with the static checks.
|
|
146
|
+
*/
|
|
147
|
+
export async function runBridgePreflight(): Promise<PreflightResult> {
|
|
148
|
+
const errors: PreflightError[] = [];
|
|
149
|
+
const checks: { name: string; passed: boolean; count: number }[] = [];
|
|
150
|
+
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
152
|
+
let bridge: any = null;
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const { createMcpBridge } = await import('@synergenius/flow-weaver/agent');
|
|
156
|
+
const { WEAVER_TOOLS } = await import('./weaver-tools.js');
|
|
157
|
+
|
|
158
|
+
// Create a bridge with a test executor
|
|
159
|
+
let testCallReceived = false;
|
|
160
|
+
bridge = await createMcpBridge(
|
|
161
|
+
WEAVER_TOOLS.slice(0, 1), // one tool is enough
|
|
162
|
+
async (name: string) => {
|
|
163
|
+
testCallReceived = true;
|
|
164
|
+
return { result: `preflight-ok:${name}`, isError: false };
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// 5a. Config file exists and is valid JSON
|
|
169
|
+
const configExists = fs.existsSync(bridge!.configPath);
|
|
170
|
+
if (!configExists) {
|
|
171
|
+
errors.push({ check: 'bridge-config', tool: '', message: 'MCP bridge config file not created' });
|
|
172
|
+
checks.push({ name: 'bridge-config', passed: false, count: 0 });
|
|
173
|
+
return { passed: false, errors, warnings: [], checks };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const config = JSON.parse(fs.readFileSync(bridge!.configPath, 'utf-8'));
|
|
177
|
+
const serverConfig = config?.mcpServers?.['fw-agent'];
|
|
178
|
+
if (!serverConfig) {
|
|
179
|
+
errors.push({ check: 'bridge-config', tool: '', message: 'MCP config missing fw-agent server entry' });
|
|
180
|
+
checks.push({ name: 'bridge-config', passed: false, count: 0 });
|
|
181
|
+
return { passed: false, errors, warnings: [], checks };
|
|
182
|
+
}
|
|
183
|
+
checks.push({ name: 'bridge-config', passed: true, count: 1 });
|
|
184
|
+
|
|
185
|
+
// 5b. Socket is listening and accepts connections
|
|
186
|
+
const socketPath = serverConfig.env?.FW_TOOL_SOCKET;
|
|
187
|
+
if (!socketPath || !fs.existsSync(socketPath)) {
|
|
188
|
+
errors.push({ check: 'bridge-socket', tool: '', message: `Bridge socket not found: ${socketPath}` });
|
|
189
|
+
checks.push({ name: 'bridge-socket', passed: false, count: 0 });
|
|
190
|
+
return { passed: false, errors, warnings: [], checks };
|
|
191
|
+
}
|
|
192
|
+
checks.push({ name: 'bridge-socket', passed: true, count: 1 });
|
|
193
|
+
|
|
194
|
+
// 5c. Round-trip: send a tool call, get a result
|
|
195
|
+
const toolName = WEAVER_TOOLS[0]?.name ?? 'test';
|
|
196
|
+
const roundTripResult = await new Promise<{ result: string; isError: boolean }>((resolve, reject) => {
|
|
197
|
+
const client = net.createConnection(socketPath, () => {
|
|
198
|
+
client.write(JSON.stringify({ name: toolName, args: {} }) + '\n');
|
|
199
|
+
});
|
|
200
|
+
let buf = '';
|
|
201
|
+
client.on('data', (chunk) => { buf += chunk.toString(); });
|
|
202
|
+
client.on('end', () => {
|
|
203
|
+
try { resolve(JSON.parse(buf.trim())); }
|
|
204
|
+
catch { reject(new Error(`Invalid bridge response: ${buf.slice(0, 200)}`)); }
|
|
205
|
+
});
|
|
206
|
+
client.on('error', (err) => reject(err));
|
|
207
|
+
setTimeout(() => { client.destroy(); reject(new Error('Bridge socket round-trip timed out (5s)')); }, 5000);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const roundTripOk = roundTripResult.result.startsWith('preflight-ok:') && testCallReceived;
|
|
211
|
+
if (!roundTripOk) {
|
|
212
|
+
errors.push({
|
|
213
|
+
check: 'bridge-roundtrip',
|
|
214
|
+
tool: toolName,
|
|
215
|
+
message: `Bridge round-trip failed: received=${JSON.stringify(roundTripResult).slice(0, 200)}, callReceived=${testCallReceived}`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
checks.push({ name: 'bridge-roundtrip', passed: roundTripOk, count: roundTripOk ? 1 : 0 });
|
|
219
|
+
|
|
220
|
+
// 5d. Tool server script exists
|
|
221
|
+
const scriptArgs: string[] = serverConfig.args ?? [];
|
|
222
|
+
const scriptPath = scriptArgs[scriptArgs.length - 1];
|
|
223
|
+
const scriptExists = scriptPath && (
|
|
224
|
+
fs.existsSync(scriptPath) ||
|
|
225
|
+
fs.existsSync(scriptPath.replace(/\.ts$/, '.js')) ||
|
|
226
|
+
fs.existsSync(scriptPath.replace(/\.js$/, '.ts'))
|
|
227
|
+
);
|
|
228
|
+
if (!scriptExists) {
|
|
229
|
+
errors.push({ check: 'bridge-script', tool: '', message: `MCP tool server script not found: ${scriptPath}` });
|
|
230
|
+
}
|
|
231
|
+
checks.push({ name: 'bridge-script', passed: !!scriptExists, count: scriptExists ? 1 : 0 });
|
|
232
|
+
|
|
233
|
+
} catch (err) {
|
|
234
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
235
|
+
errors.push({ check: 'bridge-runtime', tool: '', message: `MCP bridge preflight failed: ${msg}` });
|
|
236
|
+
checks.push({ name: 'bridge-runtime', passed: false, count: 0 });
|
|
237
|
+
} finally {
|
|
238
|
+
bridge?.cleanup();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
passed: errors.length === 0,
|
|
243
|
+
errors,
|
|
244
|
+
warnings: [],
|
|
245
|
+
checks,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Format preflight result for console output.
|
|
251
|
+
*/
|
|
252
|
+
export function formatPreflightResult(result: PreflightResult): string {
|
|
253
|
+
const lines: string[] = ['[swarm-preflight] Validating tool pipeline...'];
|
|
254
|
+
|
|
255
|
+
for (const check of result.checks) {
|
|
256
|
+
const icon = check.passed ? '✓' : '✗';
|
|
257
|
+
lines.push(` ${icon} ${check.name} (${check.count} passed)`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (result.errors.length > 0) {
|
|
261
|
+
lines.push('');
|
|
262
|
+
lines.push(`Errors (${result.errors.length}):`);
|
|
263
|
+
for (const err of result.errors) {
|
|
264
|
+
lines.push(` ✗ [${err.check}] ${err.tool}: ${err.message}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (result.warnings.length > 0) {
|
|
269
|
+
lines.push('');
|
|
270
|
+
lines.push(`Warnings (${result.warnings.length}):`);
|
|
271
|
+
for (const warn of result.warnings) {
|
|
272
|
+
lines.push(` ⚠ [${warn.check}] ${warn.tool}: ${warn.message}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (result.passed) {
|
|
277
|
+
lines.push('');
|
|
278
|
+
lines.push('Preflight passed. Tool pipeline is intact.');
|
|
279
|
+
} else {
|
|
280
|
+
lines.push('');
|
|
281
|
+
lines.push(`Preflight FAILED: ${result.errors.length} error(s). Fix before starting swarm.`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return lines.join('\n');
|
|
285
|
+
}
|