@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.
Files changed (181) hide show
  1. package/dist/ai-chat-provider.js +5 -5
  2. package/dist/ai-chat-provider.js.map +1 -1
  3. package/dist/bot/acceptance-merge.d.ts +21 -0
  4. package/dist/bot/acceptance-merge.d.ts.map +1 -0
  5. package/dist/bot/acceptance-merge.js +46 -0
  6. package/dist/bot/acceptance-merge.js.map +1 -0
  7. package/dist/bot/ai-client.d.ts +14 -2
  8. package/dist/bot/ai-client.d.ts.map +1 -1
  9. package/dist/bot/ai-client.js +71 -24
  10. package/dist/bot/ai-client.js.map +1 -1
  11. package/dist/bot/assistant-tools.js +3 -3
  12. package/dist/bot/assistant-tools.js.map +1 -1
  13. package/dist/bot/audit-logger.d.ts.map +1 -1
  14. package/dist/bot/audit-logger.js +34 -14
  15. package/dist/bot/audit-logger.js.map +1 -1
  16. package/dist/bot/audit-trail.d.ts +67 -0
  17. package/dist/bot/audit-trail.d.ts.map +1 -0
  18. package/dist/bot/audit-trail.js +153 -0
  19. package/dist/bot/audit-trail.js.map +1 -0
  20. package/dist/bot/behavior-defaults.d.ts +1 -1
  21. package/dist/bot/behavior-defaults.d.ts.map +1 -1
  22. package/dist/bot/behavior-defaults.js +7 -3
  23. package/dist/bot/behavior-defaults.js.map +1 -1
  24. package/dist/bot/capability-registry.d.ts +9 -0
  25. package/dist/bot/capability-registry.d.ts.map +1 -1
  26. package/dist/bot/capability-registry.js +81 -27
  27. package/dist/bot/capability-registry.js.map +1 -1
  28. package/dist/bot/capability-types.d.ts +10 -0
  29. package/dist/bot/capability-types.d.ts.map +1 -1
  30. package/dist/bot/cli-provider.d.ts.map +1 -1
  31. package/dist/bot/cli-provider.js +8 -7
  32. package/dist/bot/cli-provider.js.map +1 -1
  33. package/dist/bot/preflight.d.ts +48 -0
  34. package/dist/bot/preflight.d.ts.map +1 -0
  35. package/dist/bot/preflight.js +247 -0
  36. package/dist/bot/preflight.js.map +1 -0
  37. package/dist/bot/provider-shim.d.ts +74 -0
  38. package/dist/bot/provider-shim.d.ts.map +1 -0
  39. package/dist/bot/provider-shim.js +176 -0
  40. package/dist/bot/provider-shim.js.map +1 -0
  41. package/dist/bot/runner.d.ts +2 -0
  42. package/dist/bot/runner.d.ts.map +1 -1
  43. package/dist/bot/runner.js +60 -17
  44. package/dist/bot/runner.js.map +1 -1
  45. package/dist/bot/step-executor.d.ts.map +1 -1
  46. package/dist/bot/step-executor.js +72 -115
  47. package/dist/bot/step-executor.js.map +1 -1
  48. package/dist/bot/swarm-controller.d.ts +2 -0
  49. package/dist/bot/swarm-controller.d.ts.map +1 -1
  50. package/dist/bot/swarm-controller.js +92 -20
  51. package/dist/bot/swarm-controller.js.map +1 -1
  52. package/dist/bot/task-create-handler.d.ts +37 -0
  53. package/dist/bot/task-create-handler.d.ts.map +1 -0
  54. package/dist/bot/task-create-handler.js +124 -0
  55. package/dist/bot/task-create-handler.js.map +1 -0
  56. package/dist/bot/task-store.d.ts +1 -0
  57. package/dist/bot/task-store.d.ts.map +1 -1
  58. package/dist/bot/task-store.js +67 -0
  59. package/dist/bot/task-store.js.map +1 -1
  60. package/dist/bot/types.d.ts +1 -1
  61. package/dist/bot/types.d.ts.map +1 -1
  62. package/dist/bot/weaver-tools.d.ts.map +1 -1
  63. package/dist/bot/weaver-tools.js +7 -39
  64. package/dist/bot/weaver-tools.js.map +1 -1
  65. package/dist/node-types/agent-execute.d.ts +25 -8
  66. package/dist/node-types/agent-execute.d.ts.map +1 -1
  67. package/dist/node-types/agent-execute.js +89 -23
  68. package/dist/node-types/agent-execute.js.map +1 -1
  69. package/dist/node-types/bot-report.d.ts.map +1 -1
  70. package/dist/node-types/bot-report.js +24 -3
  71. package/dist/node-types/bot-report.js.map +1 -1
  72. package/dist/node-types/plan-task.d.ts +8 -17
  73. package/dist/node-types/plan-task.d.ts.map +1 -1
  74. package/dist/node-types/plan-task.js +217 -256
  75. package/dist/node-types/plan-task.js.map +1 -1
  76. package/dist/node-types/review-result.js +8 -6
  77. package/dist/node-types/review-result.js.map +1 -1
  78. package/dist/palindrome.d.ts +9 -0
  79. package/dist/palindrome.d.ts.map +1 -0
  80. package/dist/palindrome.js +14 -0
  81. package/dist/palindrome.js.map +1 -0
  82. package/dist/ui/approval-card.js +91 -82
  83. package/dist/ui/bot-activity.js +73 -56
  84. package/dist/ui/bot-config.js +48 -31
  85. package/dist/ui/bot-dashboard.js +52 -36
  86. package/dist/ui/bot-panel.js +230 -228
  87. package/dist/ui/bot-slot-card.js +100 -90
  88. package/dist/ui/bot-status.js +37 -15
  89. package/dist/ui/budget-bar.js +57 -31
  90. package/dist/ui/capability-editor.js +447 -378
  91. package/dist/ui/chat-task-result.js +78 -71
  92. package/dist/ui/decision-log.js +68 -81
  93. package/dist/ui/genesis-block.js +86 -95
  94. package/dist/ui/instance-stream-view.js +722 -0
  95. package/dist/ui/profile-card.js +96 -221
  96. package/dist/ui/profile-editor.js +532 -575
  97. package/dist/ui/settings-section.js +41 -45
  98. package/dist/ui/swarm-controls.js +212 -135
  99. package/dist/ui/swarm-dashboard.js +3992 -2715
  100. package/dist/ui/task-detail-view.js +415 -521
  101. package/dist/ui/task-editor.js +339 -390
  102. package/dist/ui/task-pool-list.js +60 -55
  103. package/dist/workflows/src/palindrome.d.ts +11 -0
  104. package/dist/workflows/src/palindrome.d.ts.map +1 -0
  105. package/dist/workflows/src/palindrome.js +16 -0
  106. package/dist/workflows/src/palindrome.js.map +1 -0
  107. package/dist/workflows/tests/palindrome.test.d.ts +2 -0
  108. package/dist/workflows/tests/palindrome.test.d.ts.map +1 -0
  109. package/dist/workflows/tests/palindrome.test.js +41 -0
  110. package/dist/workflows/tests/palindrome.test.js.map +1 -0
  111. package/dist/workflows/weaver-bot-batch.js +1 -1
  112. package/dist/workflows/weaver-bot-batch.js.map +1 -1
  113. package/dist/workflows/weaver-bot.js +1 -1
  114. package/dist/workflows/weaver-bot.js.map +1 -1
  115. package/flowweaver.manifest.json +1 -1
  116. package/package.json +8 -2
  117. package/src/ai-chat-provider.ts +5 -5
  118. package/src/bot/acceptance-merge.ts +62 -0
  119. package/src/bot/ai-client.ts +77 -21
  120. package/src/bot/assistant-tools.ts +3 -3
  121. package/src/bot/audit-logger.ts +42 -14
  122. package/src/bot/audit-trail.ts +211 -0
  123. package/src/bot/behavior-defaults.ts +7 -2
  124. package/src/bot/capability-registry.ts +84 -28
  125. package/src/bot/capability-types.ts +11 -0
  126. package/src/bot/cli-provider.ts +8 -7
  127. package/src/bot/preflight.ts +285 -0
  128. package/src/bot/provider-shim.ts +218 -0
  129. package/src/bot/runner.ts +68 -20
  130. package/src/bot/step-executor.ts +69 -127
  131. package/src/bot/swarm-controller.ts +94 -20
  132. package/src/bot/task-create-handler.ts +164 -0
  133. package/src/bot/task-store.ts +83 -0
  134. package/src/bot/types.ts +4 -1
  135. package/src/bot/weaver-tools.ts +7 -45
  136. package/src/node-types/agent-execute.ts +102 -16
  137. package/src/node-types/bot-report.ts +24 -3
  138. package/src/node-types/plan-task.ts +238 -280
  139. package/src/node-types/review-result.ts +8 -6
  140. package/src/palindrome.ts +14 -0
  141. package/src/ui/approval-card.tsx +78 -62
  142. package/src/ui/bot-activity.tsx +12 -10
  143. package/src/ui/bot-config.tsx +12 -10
  144. package/src/ui/bot-dashboard.tsx +13 -11
  145. package/src/ui/bot-panel.tsx +189 -171
  146. package/src/ui/bot-slot-card.tsx +125 -70
  147. package/src/ui/bot-status.tsx +4 -4
  148. package/src/ui/budget-bar.tsx +86 -25
  149. package/src/ui/capability-editor.tsx +392 -257
  150. package/src/ui/chat-task-result.tsx +81 -78
  151. package/src/ui/decision-log.tsx +76 -73
  152. package/src/ui/genesis-block.tsx +91 -61
  153. package/src/ui/instance-stream-view.tsx +861 -0
  154. package/src/ui/profile-card.tsx +195 -168
  155. package/src/ui/profile-editor.tsx +453 -370
  156. package/src/ui/settings-section.tsx +46 -39
  157. package/src/ui/swarm-controls.tsx +252 -123
  158. package/src/ui/swarm-dashboard.tsx +999 -466
  159. package/src/ui/task-detail-view.tsx +485 -428
  160. package/src/ui/task-editor.tsx +329 -271
  161. package/src/ui/task-pool-list.tsx +68 -62
  162. package/src/workflows/src/palindrome.ts +16 -0
  163. package/src/workflows/tests/palindrome.test.ts +49 -0
  164. package/src/workflows/weaver-bot-batch.ts +1 -1
  165. package/src/workflows/weaver-bot.ts +1 -1
  166. package/dist/ui/bot-constants.d.ts +0 -14
  167. package/dist/ui/bot-constants.d.ts.map +0 -1
  168. package/dist/ui/bot-constants.js +0 -189
  169. package/dist/ui/bot-constants.js.map +0 -1
  170. package/dist/ui/steer-api.d.ts +0 -7
  171. package/dist/ui/steer-api.d.ts.map +0 -1
  172. package/dist/ui/steer-api.js +0 -11
  173. package/dist/ui/steer-api.js.map +0 -1
  174. package/dist/ui/trace-to-timeline.d.ts +0 -91
  175. package/dist/ui/trace-to-timeline.d.ts.map +0 -1
  176. package/dist/ui/trace-to-timeline.js +0 -116
  177. package/dist/ui/trace-to-timeline.js.map +0 -1
  178. package/dist/ui/use-stream-timeline.d.ts +0 -50
  179. package/dist/ui/use-stream-timeline.d.ts.map +0 -1
  180. package/dist/ui/use-stream-timeline.js +0 -245
  181. 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 are relative to the workspace root. "../" is blocked.
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
- 1. Analyze the objective and list_files to understand the workspace.
44
- 2. Create subtasks via task_create with parentId: "@self".
45
- 3. Assign profiles: developer (code), reviewer (review), ops (infra/setup).
46
- 4. Set dependsOn using task titles (resolved to IDs automatically).
47
- 5. Add acceptance.checks shell commands that exit 0 on success. The system runs them after each run.
48
- 6. Maximize parallelism: tasks with no shared files should not depend on each other.
49
- 7. Your LAST subtask: "Review & Steer" assigned to orchestrator, dependsOn all others.
50
-
51
- ### Design First
52
- For multi-file projects, your FIRST subtask should create a .design.md with:
53
- - Module map: which files, what each exports (function signatures with types)
54
- - Conventions: naming, error handling, patterns (e.g., factory functions for servers)
55
- All subsequent developer tasks must read .design.md before writing code.
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
- - File exists: test -f url-shortener/src/store.ts
62
- - Compiles: cd url-shortener && npx tsc --noEmit
63
- - Tests pass: cd url-shortener && npx vitest run
64
- - Export exists: grep -q "export.*startServer" url-shortener/src/server.ts
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. Do not create broad "fix everything" tasks.
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. If yes, do not create a duplicate — the existing task will be retried.
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
- - tsc_check: npx tsc --noEmit — returns TypeScript compilation errors or empty on success.
259
- - test_run: npx vitest run — returns test results with pass/fail counts.`,
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 grep (via run_shell) to find all import/export references across files.
268
- Use read_file to verify import paths resolve to actual exports.`,
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 grep (via run_shell) to scan for hardcoded secrets, eval(), shell injection patterns.
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
  }
@@ -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
- const args = ['-p', '--output-format', 'stream-json', '--include-partial-messages'];
92
- if (this.model) {
93
- args.push('--model', this.model);
94
- }
95
- if (systemPrompt) {
96
- args.push('--system-prompt', systemPrompt);
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
+ }