@synergenius/flow-weaver-pack-weaver 0.9.153 → 0.9.155

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 (42) hide show
  1. package/dist/bot/capability-registry.d.ts.map +1 -1
  2. package/dist/bot/capability-registry.js +67 -12
  3. package/dist/bot/capability-registry.js.map +1 -1
  4. package/dist/bot/profile-store.d.ts.map +1 -1
  5. package/dist/bot/profile-store.js +13 -7
  6. package/dist/bot/profile-store.js.map +1 -1
  7. package/dist/bot/system-prompt.d.ts.map +1 -1
  8. package/dist/bot/system-prompt.js +2 -0
  9. package/dist/bot/system-prompt.js.map +1 -1
  10. package/dist/bot/tool-registry.js +1 -1
  11. package/dist/bot/tool-registry.js.map +1 -1
  12. package/dist/bot/weaver-tools.d.ts.map +1 -1
  13. package/dist/bot/weaver-tools.js +6 -0
  14. package/dist/bot/weaver-tools.js.map +1 -1
  15. package/dist/node-types/build-context.d.ts.map +1 -1
  16. package/dist/node-types/build-context.js +11 -0
  17. package/dist/node-types/build-context.js.map +1 -1
  18. package/dist/ui/capability-editor.js +67 -12
  19. package/dist/ui/chat-task-result.js +7 -7
  20. package/dist/ui/profile-editor.js +67 -12
  21. package/dist/ui/swarm-dashboard.js +79 -24
  22. package/dist/ui/task-detail-view.js +10 -10
  23. package/dist/ui/task-editor.js +1 -1
  24. package/dist/ui/task-pool-list.js +1 -1
  25. package/dist/workflows/weaver-bot.d.ts +3 -2
  26. package/dist/workflows/weaver-bot.d.ts.map +1 -1
  27. package/dist/workflows/weaver-bot.js +4 -4
  28. package/dist/workflows/weaver-bot.js.map +1 -1
  29. package/flowweaver.manifest.json +1 -1
  30. package/package.json +1 -1
  31. package/src/bot/capability-registry.ts +67 -12
  32. package/src/bot/profile-store.ts +13 -7
  33. package/src/bot/system-prompt.ts +2 -0
  34. package/src/bot/tool-registry.ts +1 -1
  35. package/src/bot/weaver-tools.ts +7 -0
  36. package/src/node-types/build-context.ts +11 -0
  37. package/src/ui/chat-task-result.tsx +10 -8
  38. package/src/ui/swarm-dashboard.tsx +1 -1
  39. package/src/ui/task-detail-view.tsx +11 -11
  40. package/src/ui/task-editor.tsx +2 -2
  41. package/src/ui/task-pool-list.tsx +2 -2
  42. package/src/workflows/weaver-bot.ts +4 -4
@@ -29,6 +29,7 @@ Do NOT describe what you would do — actually do it by calling tools.
29
29
 
30
30
  ## Safety Rules
31
31
  - Writes that shrink a file by >50% or write empty content are automatically BLOCKED.
32
+ - NEVER write empty or placeholder files. Every write_file call MUST contain complete, meaningful content.
32
33
  - Blocked shell commands: rm -rf, git push, npm publish, sudo, curl|sh.
33
34
  - Always validate BEFORE and AFTER patching.
34
35
  - Always read a file before patching it (you need exact strings for find/replace).
@@ -50,8 +51,8 @@ You DECOMPOSE and ASSIGN. You never write code or create files directly.
50
51
  Your job:
51
52
  1. Analyze the objective
52
53
  2. Break it into focused subtasks via task_create. Set parentId to "@self" on every subtask.
53
- 3. ALWAYS set assignedProfile: "developer", "reviewer", or "ops".
54
- NEVER set assignedProfile to "orchestrator" assigning to yourself creates an infinite loop.
54
+ 3. ALWAYS set assignedProfile: "developer", "reviewer", or "ops" for work tasks.
55
+ The ONLY exception: your final "Verify & Iterate" task should be assignedProfile: "orchestrator".
55
56
  4. Use the EXACT title of a previous subtask as dependsOn. The system resolves titles to real task IDs.
56
57
  5. Include a project brief in every subtask: "PROJECT: [what]. FILES: [exact paths from workspace root]. CONVENTIONS: [patterns]."
57
58
 
@@ -65,11 +66,35 @@ Every subsequent developer task MUST read .design.md before writing code.
65
66
 
66
67
  ### Subtask Quality
67
68
  Each subtask: focused (one concern), self-contained, properly routed, ordered by dependsOn.
69
+ - If an implementation task covers more than 2 files, SPLIT IT. Each task should produce 1-2 files max.
70
+ - Design/architecture tasks → assignedProfile: "developer" (not ops). Ops is for infra only.
71
+ - Add scope boundaries: "You may ONLY create/modify these files: [list]."
72
+
73
+ ### Maximize Parallelism
74
+ - Minimize dependencies. Tasks that don't share files should NOT depend on each other.
75
+ - Design and Setup can often run in parallel (setup doesn't need .design.md to create boilerplate).
76
+ - Aim for at least 2 tasks that can run in parallel. If all tasks are serial, reconsider.
77
+ - BAD: A → B → C → D (serial, slow)
78
+ - GOOD: A → [B + C + D] → E (A blocks all, B/C/D run in parallel, E waits for all)
79
+
80
+ ### Build Verification Gate
81
+ After implementation tasks, create a verification task (ops profile) that runs \`tsc --noEmit\`.
82
+ This catches compilation errors before tests run, saving time and token spend.
83
+
84
+ ### Verify & Iterate Loop
85
+ Your LAST subtask MUST be a "Verify & Iterate" task assigned to yourself (orchestrator):
86
+ - dependsOn: ALL other subtasks
87
+ - When it runs: review all task results, check for failures, gaps, or quality issues
88
+ - If everything passes: signal done
89
+ - If issues found: create fix tasks + another verify gate
90
+ This creates a self-correcting loop: plan → execute → verify → fix → verify → done.
68
91
 
69
92
  ### Example
70
- { operation: "task_create", args: { title: "Design: Create project contract", parentId: "@self", assignedProfile: "ops", complexity: "complex", description: "Create todo-app/.design.md with module map, TypeScript interfaces, export contracts.", dependsOn: [] } }
71
- { operation: "task_create", args: { title: "Setup project", parentId: "@self", assignedProfile: "ops", dependsOn: ["Design: Create project contract"] } }
72
- { operation: "task_create", args: { title: "Write code", parentId: "@self", assignedProfile: "developer", dependsOn: ["Setup project"] } }`,
93
+ { operation: "task_create", args: { title: "Design: Create project contract", parentId: "@self", assignedProfile: "developer", complexity: "moderate", description: "Create .design.md with interfaces and contracts.", dependsOn: [] } }
94
+ { operation: "task_create", args: { title: "Setup project", parentId: "@self", assignedProfile: "ops", dependsOn: [] } }
95
+ { operation: "task_create", args: { title: "Implement storage module", parentId: "@self", assignedProfile: "developer", dependsOn: ["Design: Create project contract", "Setup project"], description: "You may ONLY create: src/types.ts, src/storage.ts" } }
96
+ { operation: "task_create", args: { title: "Implement HTTP server", parentId: "@self", assignedProfile: "developer", dependsOn: ["Implement storage module"], description: "You may ONLY create: src/server.ts" } }
97
+ { operation: "task_create", args: { title: "Verify & Iterate", parentId: "@self", assignedProfile: "orchestrator", dependsOn: ["Implement HTTP server"], description: "Review all task results. If issues found, create fix tasks. If all good, signal done." } }`,
73
98
  };
74
99
 
75
100
  const CAP_ROLE_DEVELOPER: CapabilityDefinition = {
@@ -90,6 +115,18 @@ If the task seems too large, do your best — the orchestrator already decompose
90
115
  ### File Paths
91
116
  All paths in write_file/patch_file are RELATIVE TO THE WORKSPACE ROOT. If the task says "inside todo-app/", your paths MUST start with todo-app/ (e.g., todo-app/src/cli.ts, NOT src/cli.ts).
92
117
 
118
+ ### Write Protocol
119
+ Before writing ANY file:
120
+ 1. list_files to check if the file already exists
121
+ 2. If it exists → read_file, then patch_file with targeted changes
122
+ 3. If it does NOT exist → write_file with COMPLETE content
123
+ Never call write_file on a file that already exists — the shrink guard will block you and waste a tool call.
124
+
125
+ ### Sibling Awareness
126
+ Your context may include files modified by sibling tasks. Before writing a file:
127
+ - Check "Previous Task Completions" → if a sibling already created it, READ it first, then patch_file
128
+ - Never blindly overwrite files your siblings created
129
+
93
130
  ### Code Quality
94
131
  - Write COMPLETE, WORKING code. No TODOs, no placeholders, no empty function bodies, no "// implement later".
95
132
  - Every function must be fully implemented with real logic.
@@ -156,7 +193,14 @@ const CAP_FILE_OPS: CapabilityDefinition = {
156
193
  PREFER patch_file over write_file for modifying existing files (surgical edits, no truncation risk).
157
194
  Use read_file to understand a file before modifying it.
158
195
  Use list_files to discover project structure.
159
- Writes that shrink a file by >50% or write empty content are automatically BLOCKED.`,
196
+
197
+ ## Write Protocol
198
+ Before writing ANY file:
199
+ 1. Use list_files to check if the file already exists
200
+ 2. If it EXISTS → read_file first, then patch_file with targeted changes
201
+ 3. If it does NOT exist → write_file with COMPLETE content
202
+ NEVER call write_file on a file that already exists — use patch_file instead.
203
+ Empty content and writes that shrink an existing file by >50% are automatically BLOCKED and waste a tool call.`,
160
204
  };
161
205
 
162
206
  const CAP_SHELL: CapabilityDefinition = {
@@ -285,8 +329,9 @@ const CAP_CODE_REVIEW: CapabilityDefinition = {
285
329
  tools: [OP_READ_FILE, OP_PATCH_FILE, OP_RUN_SHELL],
286
330
  prompt: `## Code Review Checklist
287
331
 
288
- ### 1. Correctness
332
+ ### 1. Correctness & Contract Compliance
289
333
  - Does the code do what the task asked?
334
+ - If .design.md exists, verify: exported functions match contracts, interface shapes match, error behavior matches spec
290
335
  - Edge cases handled (empty input, null, invalid types)?
291
336
  - Error paths covered (try/catch, validation)?
292
337
  - Return types match function signature?
@@ -298,16 +343,19 @@ const CAP_CODE_REVIEW: CapabilityDefinition = {
298
343
  - User input validated and sanitized before use
299
344
  - File paths validated (no ../ traversal)
300
345
 
301
- ### 3. Style
346
+ ### 3. Style & Dead Code
302
347
  - Naming is clear and consistent with project conventions
303
- - No dead code (unused variables, unreachable branches)
348
+ - No dead code (unused variables, unreachable branches, duplicated functions across files)
349
+ - No duplicated logic — if two files define the same function, flag it
304
350
  - No debug statements left in (console.log, debugger)
305
- - Imports organized, no duplicates
351
+ - Imports organized, no duplicates, no unused imports
306
352
 
307
353
  ### 4. Testing
308
354
  - Unit tests exist for new/changed functions
309
355
  - Tests cover happy path AND edge cases
310
356
  - Error cases have tests
357
+ - Test isolation: state reset between tests, server handles returned and closed in afterEach
358
+ - No order-dependent tests (each test must pass in isolation)
311
359
  - Code coverage adequate (aim for 80%+ of changed code)
312
360
 
313
361
  ### 5. Performance
@@ -328,11 +376,18 @@ const CAP_WEB: CapabilityDefinition = {
328
376
 
329
377
  const CAP_CONTEXT: CapabilityDefinition = {
330
378
  name: 'context',
331
- description: 'Project file listings, directory structure, and workspace context.',
379
+ description: 'Project file listings, directory structure, workspace context, and sibling task awareness.',
332
380
  prompt: `## Project Context
333
381
 
334
382
  Use list_files to understand the project structure before making changes.
335
- The context bundle (when available) provides a snapshot of the workspace.`,
383
+ The context bundle (when available) provides a snapshot of the workspace.
384
+
385
+ ## Sibling Awareness
386
+ Your context includes files modified by sibling tasks (in "Previous Task Completions").
387
+ Before writing a file:
388
+ - Check if it appears in previous task completions → if yes, read_file first, then patch_file
389
+ - NEVER blindly overwrite files your siblings created
390
+ - If you need to extend a sibling's work, READ their output first and build on it`,
336
391
  };
337
392
 
338
393
  // ---------------------------------------------------------------------------
@@ -251,17 +251,23 @@ const DEFAULT_PROFILES: Record<string, Array<Omit<CreateProfileInput, 'botId'>>>
251
251
 
252
252
  ## Protocol
253
253
  1. ANALYZE: Understand the objective. What files, features, and concerns are involved?
254
- 2. DECOMPOSE: Break into subtasks. Each subtask should be completable by a single bot.
254
+ 2. DECOMPOSE: Break into subtasks. Each subtask should produce 1-2 files max. Split large tasks.
255
255
  3. ASSIGN: Set assignedProfile per task (developer, reviewer, ops). Set complexity and priority.
256
- 4. DEPENDENCIES: Use dependsOn to model blocking relationships. Minimize deps for parallelism.
256
+ 4. DEPENDENCIES: Minimize deps for parallelism. Tasks that don't share files should NOT depend on each other.
257
+ 5. VERIFY: Your LAST subtask must be a "Verify & Iterate" task assigned to "orchestrator" that reviews results.
257
258
 
258
259
  ## Rules
259
260
  - You do NOT write code yourself. You create tasks for other bots.
260
- - CRITICAL: Every subtask MUST have assignedProfile set to "developer", "reviewer", or "ops". NEVER leave it empty or set it to "orchestrator".
261
- - Every subtask needs: title, description, assignedProfile, complexity.
262
- - Code/file tasks → assignedProfile: "developer". Setup/infra assignedProfile: "ops". Review → assignedProfile: "reviewer".
263
- - Structure as: setup independent implementations integration review.
264
- - If a task is simple enough (single file, clear scope), don't decompose further.`,
261
+ - Every work subtask MUST have assignedProfile: "developer", "reviewer", or "ops".
262
+ - The ONLY exception: your final "Verify & Iterate" task uses assignedProfile: "orchestrator".
263
+ - Add scope boundaries: "You may ONLY create/modify these files: [list]."
264
+ - Design/architecture tasks"developer" (not ops). Ops is for infra/config only.
265
+ - Aim for at least 2 tasks that can run in parallel. If all tasks are serial, reconsider.
266
+
267
+ ## Verify & Iterate Loop
268
+ Your LAST subtask MUST be:
269
+ { title: "Verify & Iterate", assignedProfile: "orchestrator", dependsOn: [all other tasks] }
270
+ When this runs: review results, check for failures/gaps, create fix tasks if needed, or signal done.`,
265
271
  behavior: {
266
272
  capabilities: PROFILE_CAPABILITIES.orchestrator,
267
273
  phases: {
@@ -208,6 +208,8 @@ USE TOOLS to complete tasks. Do NOT describe what you would do — actually do i
208
208
 
209
209
  ### Knowledge tools
210
210
  - learn(key, value), recall(query)
211
+ - When you discover project facts (test runner, build tool, conventions, common patterns), use learn() to persist them for future runs
212
+ - Previous knowledge is auto-loaded into your context — avoid re-discovering what's already known
211
213
 
212
214
  ### Web & interaction tools
213
215
  - web_fetch(url), ask_user(question)
@@ -294,7 +294,7 @@ export const ALL_TOOLS: WeaverTool[] = [
294
294
  },
295
295
  {
296
296
  name: 'write_file',
297
- description: 'Write content to a file (creates or overwrites). Use patch_file instead for modifications to existing files.',
297
+ description: 'Write content to a NEW file. ONLY for files that do not exist yet use patch_file for existing files. Empty content and writes that shrink an existing file by >50% are automatically BLOCKED.',
298
298
  inputSchema: {
299
299
  type: 'object',
300
300
  properties: {
@@ -185,6 +185,13 @@ export function createWeaverExecutor(projectDir: string) {
185
185
  break;
186
186
  }
187
187
 
188
+ // Ignore Claude Code built-in tools that leak through when disallowed list is incomplete.
189
+ // These are no-ops — the bot should use the MCP bridge tools instead.
190
+ const IGNORED_BUILTINS = new Set(['TodoWrite', 'TodoRead', 'Agent', 'WebFetch', 'WebSearch', 'MultiTool', 'Skill']);
191
+ if (IGNORED_BUILTINS.has(name) || IGNORED_BUILTINS.has(rawName)) {
192
+ return { result: `Tool "${name}" is not available. Use the provided tools instead.`, isError: true };
193
+ }
194
+
188
195
  // Existing step-executor-based tools
189
196
  const operation = OPERATION_MAP[name];
190
197
  if (!operation) {
@@ -45,6 +45,17 @@ export function weaverBuildContext(ctx: string): { ctx: string } {
45
45
  }
46
46
  } catch { /* non-fatal — memory is best-effort */ }
47
47
 
48
+ // Auto-recall learned knowledge from previous bot runs
49
+ try {
50
+ const { KnowledgeStore } = require('../bot/knowledge-store.js') as typeof import('../bot/knowledge-store.js');
51
+ const knowledge = new KnowledgeStore(projectDir);
52
+ const entries = knowledge.list();
53
+ if (entries.length > 0) {
54
+ const knowledgeLines = entries.map((e: { key: string; value: string }) => `- **${e.key}**: ${e.value}`);
55
+ sections.push(`## Learned Knowledge\n\nFacts discovered by previous runs — use these instead of re-discovering:\n${knowledgeLines.join('\n')}`);
56
+ }
57
+ } catch { /* non-fatal — knowledge recall is best-effort */ }
58
+
48
59
  // Include sibling context from hierarchy events (previous task completions in same hierarchy)
49
60
  try {
50
61
  const parsedTask = JSON.parse(context.taskJson!) as { parentId?: string };
@@ -18,16 +18,18 @@ const { Flex, Typography, StatusIcon, Button } = require('@fw/plugin-ui-kit');
18
18
  interface TaskData {
19
19
  id: string;
20
20
  title: string;
21
- status: 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
21
+ status: 'open' | 'pending' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
22
22
  isParent: boolean;
23
23
  currentBotId?: string;
24
24
  assignedProfile?: string;
25
+ attempt?: number;
26
+ maxAttempts?: number;
25
27
  }
26
28
 
27
29
  interface SubtaskData {
28
30
  id: string;
29
31
  title: string;
30
- status: 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
32
+ status: 'open' | 'pending' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
31
33
  }
32
34
 
33
35
  interface ChatTaskResultProps {
@@ -59,6 +61,7 @@ type StatusKind = 'running' | 'completed' | 'failed' | 'pending';
59
61
 
60
62
  function statusToIcon(status: TaskData['status']): StatusKind {
61
63
  switch (status) {
64
+ case 'open':
62
65
  case 'pending':
63
66
  case 'blocked':
64
67
  return 'pending';
@@ -66,7 +69,6 @@ function statusToIcon(status: TaskData['status']): StatusKind {
66
69
  return 'running';
67
70
  case 'done':
68
71
  return 'completed';
69
- case 'failed':
70
72
  case 'cancelled':
71
73
  return 'failed';
72
74
  default:
@@ -76,18 +78,18 @@ function statusToIcon(status: TaskData['status']): StatusKind {
76
78
 
77
79
  function statusLabel(status: TaskData['status']): string {
78
80
  switch (status) {
79
- case 'pending': return 'Pending';
80
- case 'in-progress': return 'In Progress';
81
+ case 'open': return 'Open';
82
+ case 'pending': return 'Queued';
83
+ case 'in-progress': return 'Running';
81
84
  case 'blocked': return 'Blocked';
82
85
  case 'done': return 'Done';
83
- case 'failed': return 'Failed';
84
86
  case 'cancelled': return 'Cancelled';
85
87
  default: return status;
86
88
  }
87
89
  }
88
90
 
89
91
  function isTerminal(status: TaskData['status']): boolean {
90
- return status === 'done' || status === 'failed' || status === 'cancelled';
92
+ return status === 'done' || status === 'cancelled';
91
93
  }
92
94
 
93
95
  // ---------------------------------------------------------------------------
@@ -204,7 +206,7 @@ function ChatTaskResult(props: ChatTaskResultProps | null) {
204
206
  React.createElement(Typography, {
205
207
  variant: 'smallCaption-regular',
206
208
  color: task.status === 'done' ? 'color-text-positive' :
207
- task.status === 'failed' ? 'color-text-negative' :
209
+ task.status === 'cancelled' ? 'color-text-negative' :
208
210
  task.status === 'in-progress' ? 'color-text-info' :
209
211
  'color-text-medium',
210
212
  }, statusLabel(task.status)),
@@ -77,7 +77,7 @@ interface SwarmStatus {
77
77
  packVersion?: string;
78
78
  }
79
79
 
80
- type TaskStatus = 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
80
+ type TaskStatus = 'open' | 'pending' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
81
81
 
82
82
  interface PoolTask {
83
83
  id: string;
@@ -24,7 +24,7 @@ import type { HistoricalRun } from './trace-to-timeline';
24
24
  // Types
25
25
  // ---------------------------------------------------------------------------
26
26
 
27
- type TaskStatus = 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
27
+ type TaskStatus = 'open' | 'pending' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
28
28
 
29
29
  interface TaskContext {
30
30
  files: string[];
@@ -89,19 +89,19 @@ interface TaskDetailViewProps {
89
89
  // ---------------------------------------------------------------------------
90
90
 
91
91
  const statusToIcon: Record<TaskStatus, string> = {
92
+ 'open': 'pending',
92
93
  'pending': 'pending',
93
94
  'in-progress': 'running',
94
95
  'done': 'completed',
95
- 'failed': 'failed',
96
96
  'blocked': 'pending',
97
97
  'cancelled': 'failed',
98
98
  };
99
99
 
100
100
  const statusToLabel: Record<TaskStatus, string> = {
101
- 'pending': 'Pending',
102
- 'in-progress': 'In Progress',
101
+ 'open': 'Open',
102
+ 'pending': 'Queued',
103
+ 'in-progress': 'Running',
103
104
  'done': 'Done',
104
- 'failed': 'Failed',
105
105
  'blocked': 'Blocked',
106
106
  'cancelled': 'Cancelled',
107
107
  };
@@ -568,10 +568,10 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
568
568
  // Meta row: status tag, assigned profile, priority, attempts
569
569
  React.createElement(Flex, { variant: 'row-center-start-wrap-6' },
570
570
  React.createElement(Chip, {
571
- label: statusToLabel[task.status] || task.status || 'pending',
571
+ label: statusToLabel[task.status as TaskStatus] || task.status || 'open',
572
572
  size: 'small',
573
573
  color: task.status === 'done' ? 'color-status-positive'
574
- : task.status === 'failed' ? 'color-status-negative'
574
+ : task.status === 'cancelled' ? 'color-status-negative'
575
575
  : task.status === 'in-progress' ? 'color-status-info'
576
576
  : task.status === 'blocked' ? 'color-status-caution'
577
577
  : 'color-brand-alt',
@@ -583,10 +583,10 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
583
583
  label: `P${task.priority}`, size: 'small', color: task.priority >= 3 ? 'color-status-caution' : 'color-status-info',
584
584
  }),
585
585
 
586
- (task.attempt != null && task.maxAttempts != null) && React.createElement(Typography, {
586
+ task.maxAttempts != null && task.maxAttempts > 1 && React.createElement(Typography, {
587
587
  variant: 'smallCaption-regular',
588
588
  color: 'color-text-subtle',
589
- }, `Attempt ${task.attempt}/${task.maxAttempts}`),
589
+ }, `${task.runs?.length ?? 0}/${task.maxAttempts} runs`),
590
590
  ),
591
591
 
592
592
  // Description
@@ -696,14 +696,14 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
696
696
  React.createElement(Flex, { variant: 'column-stretch-start-nowrap-8' },
697
697
  React.createElement(Typography, { variant: 'caption-thick', color: 'color-text-medium' }, 'Status'),
698
698
  React.createElement(Flex, { variant: 'row-center-start-nowrap-6' },
699
- (task.status === 'failed' || (task.status === 'open' && task.attempt >= task.maxAttempts)) && React.createElement(Button, {
699
+ (task.status === 'open' && (task.attempt ?? 0) > 0) && React.createElement(Button, {
700
700
  size: 'xs', variant: 'fill', color: 'primary',
701
701
  onClick: handleRetry,
702
702
  loading: actionLoading === 'retry',
703
703
  disabled: !!actionLoading,
704
704
  }, 'Retry Task'),
705
705
 
706
- (task.status === 'pending' || task.status === 'in-progress' || task.status === 'blocked') && React.createElement(Button, {
706
+ (task.status === 'open' || task.status === 'pending' || task.status === 'in-progress' || task.status === 'blocked') && React.createElement(Button, {
707
707
  size: 'xs', variant: 'outlined', color: 'danger',
708
708
  onClick: handleCancel,
709
709
  loading: actionLoading === 'cancel',
@@ -29,7 +29,7 @@ interface TaskEditorProps {
29
29
  onDelete?: () => void;
30
30
  }
31
31
 
32
- type TaskStatus = 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
32
+ type TaskStatus = 'open' | 'pending' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
33
33
 
34
34
  interface TaskData {
35
35
  id: string;
@@ -77,11 +77,11 @@ const COMPLEXITY_OPTIONS = [
77
77
  ];
78
78
 
79
79
  const STATUS_COLOR: Record<string, string> = {
80
+ 'open': 'color-brand-alt',
80
81
  'pending': 'color-brand-alt',
81
82
  'in-progress': 'color-status-info',
82
83
  'blocked': 'color-status-caution',
83
84
  'done': 'color-status-positive',
84
- 'failed': 'color-status-negative',
85
85
  'cancelled': 'color-status-negative',
86
86
  };
87
87
 
@@ -11,7 +11,7 @@ const { Flex, Typography, Icon, StatusIcon, Chip, ScrollArea, Badge, EmptyState
11
11
 
12
12
  // --- Types ---
13
13
 
14
- type TaskStatus = 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
14
+ type TaskStatus = 'open' | 'pending' | 'in-progress' | 'blocked' | 'done' | 'cancelled';
15
15
 
16
16
  interface Task {
17
17
  id: string;
@@ -32,10 +32,10 @@ interface TaskPoolListProps {
32
32
  // --- Status mapping ---
33
33
 
34
34
  const statusToIcon: Record<TaskStatus, string> = {
35
+ 'open': 'pending',
35
36
  'pending': 'pending',
36
37
  'in-progress': 'running',
37
38
  'done': 'completed',
38
- 'failed': 'failed',
39
39
  'blocked': 'pending',
40
40
  'cancelled': 'failed',
41
41
  };
@@ -423,7 +423,7 @@ class GeneratedExecutionContext {
423
423
 
424
424
  /**
425
425
  * @flowWeaver workflow
426
- * @node cfg weaverLoadConfig [color: "teal"] [icon: "settings"] [position: 200 200]
426
+ * @node cfg weaverLoadConfig [color: "teal"] [icon: "settings"] [suppress: "AGENT_UNGUARDED_TOOL_EXECUTOR"] [position: 200 200]
427
427
  * @node detect weaverDetectProvider [color: "cyan"] [icon: "search"] [suppress: "OBJECT_TYPE_MISMATCH", "ANNOTATION_SIGNATURE_TYPE_MISMATCH"] [position: 400 200]
428
428
  * @node receive weaverReceiveTask [color: "blue"] [icon: "send"] [position: 600 200]
429
429
  * @node route weaverRouteTask [color: "purple"] [icon: "flow"] [position: 800 200]
@@ -441,7 +441,7 @@ class GeneratedExecutionContext {
441
441
  * @node resolveReviewModel weaverResolveModel [label: "Review Model"] [expr: phaseName="'review'"] [minimized] [color: "green"] [icon: "tune"] [position: 1900 50]
442
442
  * @node review weaverReviewResult [color: "green"] [icon: "spellcheck"] [position: 1950 100]
443
443
  * @node mergeReview weaverCtxMerge [label: "Merge Review"] [minimized] [color: "teal"] [icon: "callMerge"] [position: 2050 200]
444
- * @node gitOps weaverGitOps [color: "green"] [icon: "code"] [position: 2150 100]
444
+ * @node gitOps weaverGitOps [color: "green"] [icon: "code"] [suppress: "UNUSED_OUTPUT_PORT"] [position: 2150 100]
445
445
  * @node notify weaverSendNotify [color: "yellow"] [icon: "send"] [suppress: "UNUSED_OUTPUT_PORT"] [position: 2050 400]
446
446
  * @node report weaverBotReport [color: "green"] [icon: "description"] [suppress: "UNUSED_OUTPUT_PORT", "DESIGN_ASYNC_NO_ERROR_PATH"] [position: 2350 200]
447
447
  * @path Start -> cfg -> detect -> receive -> route -> context -> gatePlan -> resolvePlanModel -> plan -> mergePlan -> approve -> resolveExecModel -> execRetry -> gateReview -> resolveReviewModel -> review -> mergeReview -> gitOps -> report -> Exit
@@ -470,6 +470,7 @@ class GeneratedExecutionContext {
470
470
  * @connect abort.ctx -> report.abortCtx
471
471
  * @connect plan.ctx -> report.failCtx
472
472
  * @connect report.summary -> Exit.summary
473
+ * @connect review.onFailure -> report.execute
473
474
  * @param execute [order:-1] - Execute
474
475
  * @param taskJson [order:0] - TaskJson
475
476
  * @param projectDir [order:1] - ProjectDir
@@ -2116,7 +2117,7 @@ export async function weaverBot(
2116
2117
  });
2117
2118
 
2118
2119
  try {
2119
- const report_execute = (readWfIdx !== undefined ? await ctx.getVariable({ id: 'readWf', portName: 'onSuccess', executionIndex: readWfIdx }) as boolean : false) || (abortIdx !== undefined ? await ctx.getVariable({ id: 'abort', portName: 'onSuccess', executionIndex: abortIdx }) as boolean : false) || (notifyIdx !== undefined ? await ctx.getVariable({ id: 'notify', portName: 'onSuccess', executionIndex: notifyIdx }) as boolean : false) || (gitOpsIdx !== undefined ? await ctx.getVariable({ id: 'gitOps', portName: 'onSuccess', executionIndex: gitOpsIdx }) as boolean : false) || (receiveIdx !== undefined ? await ctx.getVariable({ id: 'receive', portName: 'onFailure', executionIndex: receiveIdx }) as boolean : false) || (planIdx !== undefined ? await ctx.getVariable({ id: 'plan', portName: 'onFailure', executionIndex: planIdx }) as boolean : false) || (execRetryIdx !== undefined ? await ctx.getVariable({ id: 'execRetry', portName: 'onFailure', executionIndex: execRetryIdx }) as boolean : false);
2120
+ const report_execute = (readWfIdx !== undefined ? await ctx.getVariable({ id: 'readWf', portName: 'onSuccess', executionIndex: readWfIdx }) as boolean : false) || (abortIdx !== undefined ? await ctx.getVariable({ id: 'abort', portName: 'onSuccess', executionIndex: abortIdx }) as boolean : false) || (notifyIdx !== undefined ? await ctx.getVariable({ id: 'notify', portName: 'onSuccess', executionIndex: notifyIdx }) as boolean : false) || (gitOpsIdx !== undefined ? await ctx.getVariable({ id: 'gitOps', portName: 'onSuccess', executionIndex: gitOpsIdx }) as boolean : false) || (receiveIdx !== undefined ? await ctx.getVariable({ id: 'receive', portName: 'onFailure', executionIndex: receiveIdx }) as boolean : false) || (planIdx !== undefined ? await ctx.getVariable({ id: 'plan', portName: 'onFailure', executionIndex: planIdx }) as boolean : false) || (execRetryIdx !== undefined ? await ctx.getVariable({ id: 'execRetry', portName: 'onFailure', executionIndex: execRetryIdx }) as boolean : false) || (reviewIdx !== undefined ? await ctx.getVariable({ id: 'review', portName: 'onFailure', executionIndex: reviewIdx }) as boolean : false);
2120
2121
  await ctx.setVariable({ id: 'report', portName: 'execute', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, report_execute);
2121
2122
  const report_mainCtx = mergePlanIdx !== undefined ? await ctx.getVariable({ id: 'mergePlan', portName: 'ctx', executionIndex: mergePlanIdx }) as string : undefined;
2122
2123
  await ctx.setVariable({ id: 'report', portName: 'mainCtx', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, report_mainCtx);
@@ -2128,7 +2129,6 @@ export async function weaverBot(
2128
2129
  await ctx.setVariable({ id: 'report', portName: 'failCtx', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, report_failCtx);
2129
2130
  const reportResult = await weaverBotReport(report_execute, report_mainCtx, report_readCtx, report_abortCtx, report_failCtx);
2130
2131
  await ctx.setVariable({ id: 'report', portName: 'summary', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, reportResult.summary);
2131
- await ctx.setVariable({ id: 'report', portName: 'report', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, reportResult.report);
2132
2132
  await ctx.setVariable({ id: 'report', portName: 'reportJson', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, reportResult.reportJson);
2133
2133
  await ctx.setVariable({ id: 'report', portName: 'onFailure', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, reportResult.onFailure);
2134
2134
  await ctx.setVariable({ id: 'report', portName: 'onSuccess', executionIndex: reportIdx, nodeTypeName: 'weaverBotReport' }, reportResult.onSuccess);