@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.
- package/dist/bot/capability-registry.d.ts.map +1 -1
- package/dist/bot/capability-registry.js +67 -12
- package/dist/bot/capability-registry.js.map +1 -1
- package/dist/bot/profile-store.d.ts.map +1 -1
- package/dist/bot/profile-store.js +13 -7
- package/dist/bot/profile-store.js.map +1 -1
- package/dist/bot/system-prompt.d.ts.map +1 -1
- package/dist/bot/system-prompt.js +2 -0
- package/dist/bot/system-prompt.js.map +1 -1
- package/dist/bot/tool-registry.js +1 -1
- package/dist/bot/tool-registry.js.map +1 -1
- package/dist/bot/weaver-tools.d.ts.map +1 -1
- package/dist/bot/weaver-tools.js +6 -0
- package/dist/bot/weaver-tools.js.map +1 -1
- package/dist/node-types/build-context.d.ts.map +1 -1
- package/dist/node-types/build-context.js +11 -0
- package/dist/node-types/build-context.js.map +1 -1
- package/dist/ui/capability-editor.js +67 -12
- package/dist/ui/chat-task-result.js +7 -7
- package/dist/ui/profile-editor.js +67 -12
- package/dist/ui/swarm-dashboard.js +79 -24
- package/dist/ui/task-detail-view.js +10 -10
- package/dist/ui/task-editor.js +1 -1
- package/dist/ui/task-pool-list.js +1 -1
- package/dist/workflows/weaver-bot.d.ts +3 -2
- package/dist/workflows/weaver-bot.d.ts.map +1 -1
- package/dist/workflows/weaver-bot.js +4 -4
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +1 -1
- package/package.json +1 -1
- package/src/bot/capability-registry.ts +67 -12
- package/src/bot/profile-store.ts +13 -7
- package/src/bot/system-prompt.ts +2 -0
- package/src/bot/tool-registry.ts +1 -1
- package/src/bot/weaver-tools.ts +7 -0
- package/src/node-types/build-context.ts +11 -0
- package/src/ui/chat-task-result.tsx +10 -8
- package/src/ui/swarm-dashboard.tsx +1 -1
- package/src/ui/task-detail-view.tsx +11 -11
- package/src/ui/task-editor.tsx +2 -2
- package/src/ui/task-pool-list.tsx +2 -2
- 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
|
-
|
|
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: "
|
|
71
|
-
{ operation: "task_create", args: { title: "Setup project", parentId: "@self", assignedProfile: "ops", dependsOn: [
|
|
72
|
-
{ operation: "task_create", args: { title: "
|
|
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
|
-
|
|
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
|
|
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
|
// ---------------------------------------------------------------------------
|
package/src/bot/profile-store.ts
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
-
-
|
|
261
|
-
-
|
|
262
|
-
-
|
|
263
|
-
-
|
|
264
|
-
-
|
|
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: {
|
package/src/bot/system-prompt.ts
CHANGED
|
@@ -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)
|
package/src/bot/tool-registry.ts
CHANGED
|
@@ -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
|
|
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: {
|
package/src/bot/weaver-tools.ts
CHANGED
|
@@ -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' | '
|
|
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' | '
|
|
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 '
|
|
80
|
-
case '
|
|
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 === '
|
|
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 === '
|
|
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' | '
|
|
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' | '
|
|
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
|
-
'
|
|
102
|
-
'
|
|
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 || '
|
|
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 === '
|
|
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
|
-
|
|
586
|
+
task.maxAttempts != null && task.maxAttempts > 1 && React.createElement(Typography, {
|
|
587
587
|
variant: 'smallCaption-regular',
|
|
588
588
|
color: 'color-text-subtle',
|
|
589
|
-
},
|
|
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 === '
|
|
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',
|
package/src/ui/task-editor.tsx
CHANGED
|
@@ -29,7 +29,7 @@ interface TaskEditorProps {
|
|
|
29
29
|
onDelete?: () => void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
type TaskStatus = 'pending' | 'in-progress' | 'blocked' | 'done' | '
|
|
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' | '
|
|
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);
|