zefiro 0.4.0 → 0.5.0
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/agents/workflow-agent-v3.md +288 -98
- package/dist/cli.js +2 -1
- package/package.json +1 -1
|
@@ -5,61 +5,271 @@ max_tokens: 8192
|
|
|
5
5
|
temperature: 0.2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# QA Map V3 — Orchestration Guide
|
|
9
9
|
|
|
10
|
-
You are a
|
|
10
|
+
You are an orchestrator that builds a complete V3 QA map by splitting work across parallel subagents, then merging and cross-linking the results. This pattern keeps each agent's context small and focused.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Why Split?
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
A full-app QA map can have 200+ source files, dozens of features, and hundreds of workflow steps. Stuffing all of this into a single agent blows up context and produces worse results. Instead:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- `forms`: array - FormNode objects for forms in this feature
|
|
16
|
+
- **Each subagent** reads ~20-40 files for ONE feature domain
|
|
17
|
+
- **Each subagent** produces a self-contained JSON fragment
|
|
18
|
+
- **The merge step** is lightweight — just concatenation + cross-linking
|
|
19
|
+
- **Fragments are saved to disk** so work is never lost if a step fails
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Pipeline Overview
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
┌─────────┐ ┌───────────┐ ┌─────────────────┐ ┌───────────┐ ┌──────────┐
|
|
27
|
+
│ 1.Scan │────▶│ 2.Partition│────▶│ 3.Analyze (×N) │────▶│ 4.Merge │────▶│ 5.Link │
|
|
28
|
+
│ (AST) │ │ (domains) │ │ (parallel agents)│ │ (concat) │ │ (x-refs) │
|
|
29
|
+
└─────────┘ └───────────┘ └─────────────────┘ └───────────┘ └──────────┘
|
|
30
|
+
│
|
|
31
|
+
┌──────▼──────┐
|
|
32
|
+
│ 6.Validate │
|
|
33
|
+
│ & Save │
|
|
34
|
+
└─────────────┘
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 1: Scan
|
|
40
|
+
|
|
41
|
+
Run the AST scanner to get a structural overview of the codebase.
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
zefiro_scan_ast({ scanDir: "src" }) // or "apps/myapp/src"
|
|
45
|
+
zefiro_scan_ast_detail({ category: "routes" })
|
|
46
|
+
zefiro_scan_ast_detail({ category: "components" })
|
|
47
|
+
zefiro_scan_ast_detail({ category: "hooks" })
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Output:** A mental model of routes, components, hooks, and directory groups.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Step 2: Partition into Feature Domains
|
|
55
|
+
|
|
56
|
+
Group the scanned entities into **3-8 feature domains**. Each domain should be:
|
|
57
|
+
|
|
58
|
+
- **Self-contained**: its routes, components, hooks, and API endpoints are mostly independent
|
|
59
|
+
- **Manageable**: ~20-40 source files per domain (sweet spot for agent context)
|
|
60
|
+
- **Cohesive**: files that change together belong together
|
|
61
|
+
|
|
62
|
+
### Partitioning Heuristics
|
|
63
|
+
|
|
64
|
+
| Signal | How to use it |
|
|
65
|
+
|--------|---------------|
|
|
66
|
+
| Route groups `(authenticated)`, `(public)` | Top-level section boundaries |
|
|
67
|
+
| Shared URL prefix `/app/[appSlug]/chat/*` | Same feature domain |
|
|
68
|
+
| Component directory `components/chat/*` | Same feature domain as matching routes |
|
|
69
|
+
| Hook names `useChat*`, `useConversations` | Belong with their consuming components |
|
|
70
|
+
| API routes `/api/apps/[appId]/conversations/*` | Backend for the matching feature domain |
|
|
71
|
+
|
|
72
|
+
### Example Partition
|
|
73
|
+
|
|
74
|
+
| Domain | Routes | Components | Hooks | API Routes |
|
|
75
|
+
|--------|--------|------------|-------|------------|
|
|
76
|
+
| Auth & Navigation | sign-in, sign-up, invite, dashboard | navigation/*, layout/* | useAppScope | - |
|
|
77
|
+
| Feature Map | features, app root | feature-tree/*, feature-details/*, workflow-graph/* | useFeatures, useWorkflows, useSections | features, workflows, sections, coverage, complexity |
|
|
78
|
+
| AI Chat | chat, chat/[id] | chat/* | useAppChat, useConversations, useMemoryBanks | conversations/*, memory-banks/* |
|
|
79
|
+
| Test Cases | test-cases | test-cases/* | useTestCases, useTestCaseSearch | test-cases/* |
|
|
80
|
+
| Settings | org/settings, project/settings, app/settings | settings/* | useJiraIntegration, useAvailableModels | orgs/*, integrations/*, invitations/* |
|
|
81
|
+
| Knowledge & Versions | knowledge, versions, reports, runs, sessions | knowledge/* | useMapVersions | qa-map, versions/*, push/* |
|
|
82
|
+
|
|
83
|
+
Present the partition to the user and get confirmation before proceeding.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Step 3: Analyze (Parallel Subagents)
|
|
88
|
+
|
|
89
|
+
Launch **one subagent per domain**, all in parallel. Each subagent:
|
|
90
|
+
|
|
91
|
+
1. Reads only its assigned source files
|
|
92
|
+
2. Identifies sections, features, and components for its domain
|
|
93
|
+
3. Generates DAG workflows using the two-pass method (see [Workflow Generation](#workflow-generation))
|
|
94
|
+
4. Generates scenarios that trace DAG paths
|
|
95
|
+
5. Writes its fragment to `.qai/zefiro/map-pieces/<domain-slug>.json`
|
|
23
96
|
|
|
24
|
-
|
|
97
|
+
### Fragment Shape
|
|
98
|
+
|
|
99
|
+
Each subagent writes a JSON file with this structure:
|
|
25
100
|
|
|
26
101
|
```json
|
|
27
102
|
{
|
|
103
|
+
"sections": [
|
|
104
|
+
{
|
|
105
|
+
"id": "sec:<slug>",
|
|
106
|
+
"name": "Section Name",
|
|
107
|
+
"description": "What this section covers",
|
|
108
|
+
"featureIds": ["feat:<slug>"]
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"features": [
|
|
112
|
+
{
|
|
113
|
+
"id": "feat:<slug>",
|
|
114
|
+
"name": "Feature Name",
|
|
115
|
+
"description": "User-facing description",
|
|
116
|
+
"sectionId": "sec:<parent>",
|
|
117
|
+
"parentFeatureId": null,
|
|
118
|
+
"subFeatureIds": [],
|
|
119
|
+
"routes": ["/path"],
|
|
120
|
+
"workflowIds": ["wf:<id>"],
|
|
121
|
+
"sourceFiles": ["relative/path.tsx"],
|
|
122
|
+
"entryPoints": [
|
|
123
|
+
{ "type": "sidebar-nav", "description": "Main nav link" }
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
],
|
|
28
127
|
"workflows": [
|
|
29
128
|
{
|
|
30
129
|
"id": "wf:<kebab-name>",
|
|
31
|
-
"name": "
|
|
32
|
-
"featureId": "feat:<
|
|
33
|
-
"type": "
|
|
34
|
-
"preconditions": [
|
|
35
|
-
|
|
36
|
-
],
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
130
|
+
"name": "Workflow Name",
|
|
131
|
+
"featureId": "feat:<id>",
|
|
132
|
+
"type": "crud",
|
|
133
|
+
"preconditions": [{ "entity": "user", "state": "status", "operator": "equals", "value": "authenticated" }],
|
|
134
|
+
"postconditions": [],
|
|
135
|
+
"steps": [{ "id": "step:<wfId>:<slug>", "description": "...", "action": "user-action", "componentIds": [], "apiCalls": [], "nextStepIds": [], "branchCondition": null }],
|
|
136
|
+
"edges": [{ "fromStepId": "step:...", "toStepId": "step:...", "edgeType": "default" }],
|
|
137
|
+
"entryStepIds": ["step:..."],
|
|
138
|
+
"componentIds": ["comp:..."]
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"components": [
|
|
142
|
+
{
|
|
143
|
+
"id": "comp:<kebab>",
|
|
144
|
+
"name": "ComponentName",
|
|
145
|
+
"filePath": "relative/path.tsx",
|
|
146
|
+
"props": [],
|
|
147
|
+
"hooks": [],
|
|
148
|
+
"guardPatterns": []
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"scenarios": [
|
|
152
|
+
{
|
|
153
|
+
"id": "sc:<slug>",
|
|
154
|
+
"workflowId": "wf:<id>",
|
|
155
|
+
"featureId": "feat:<id>",
|
|
156
|
+
"name": "Scenario Name",
|
|
157
|
+
"description": "What this tests",
|
|
158
|
+
"category": "happy-path",
|
|
159
|
+
"preconditions": [],
|
|
160
|
+
"path": ["step:..."],
|
|
161
|
+
"steps": [{ "order": 1, "action": "...", "expectedResult": "..." }],
|
|
162
|
+
"expectedOutcome": "...",
|
|
163
|
+
"componentIds": [],
|
|
164
|
+
"priority": "critical"
|
|
44
165
|
}
|
|
45
166
|
]
|
|
46
167
|
}
|
|
47
168
|
```
|
|
48
169
|
|
|
49
|
-
|
|
170
|
+
### Subagent Prompt Template
|
|
50
171
|
|
|
51
|
-
|
|
52
|
-
|
|
172
|
+
Give each subagent:
|
|
173
|
+
- The list of files it must read (absolute paths)
|
|
174
|
+
- The fragment shape above
|
|
175
|
+
- The workflow generation rules (see below)
|
|
176
|
+
- The output file path: `.qai/zefiro/map-pieces/<domain-slug>.json`
|
|
177
|
+
- Instruction: "Write the output JSON using the Write tool. Do NOT call MCP tools."
|
|
53
178
|
|
|
54
|
-
|
|
55
|
-
For each step that has validation, permissions, or business logic decisions, add branching:
|
|
56
|
-
- Create a `conditional` step with a `branchCondition`
|
|
57
|
-
- Add edges from the conditional step to different target steps
|
|
58
|
-
- Add convergence where branches rejoin the main flow
|
|
179
|
+
### Important Constraints for Subagents
|
|
59
180
|
|
|
60
|
-
|
|
181
|
+
- **No cross-domain references.** Subagents must NOT reference features, components, or workflows from other domains. Cross-linking happens in Step 5.
|
|
182
|
+
- **Use relative paths** from the app's src/ directory for all sourceFiles and filePaths.
|
|
183
|
+
- **IDs must be globally unique.** Use domain-specific prefixes or suffixes to avoid collisions (e.g., `feat:chat-conversations`, `feat:settings-llm-config`).
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Step 4: Merge
|
|
188
|
+
|
|
189
|
+
Once all subagents complete, merge their fragments:
|
|
190
|
+
|
|
191
|
+
1. Read all files from `.qai/zefiro/map-pieces/*.json`
|
|
192
|
+
2. Concatenate each array: sections, features, workflows, components, scenarios
|
|
193
|
+
3. Deduplicate components by `id` (shared components may appear in multiple fragments)
|
|
194
|
+
4. Add the envelope: `{ schemaVersion: 3, sections, features, workflows, components, scenarios }`
|
|
195
|
+
|
|
196
|
+
This step is lightweight — no LLM reasoning needed, just array concatenation.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Step 5: Cross-Link Features
|
|
201
|
+
|
|
202
|
+
This is the final intelligence step. Review all features across domains and add cross-references:
|
|
203
|
+
|
|
204
|
+
### 5a. Entry Point Cross-References
|
|
205
|
+
|
|
206
|
+
For each feature, check if it is reachable from features in OTHER domains. Add `entryPoints` with `sourceFeatureId`:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"type": "button",
|
|
211
|
+
"sourceFeatureId": "feat:chat-conversations",
|
|
212
|
+
"description": "Chat can generate test cases, linking to Test Cases feature"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Common cross-domain links:
|
|
217
|
+
- **Chat → Test Cases**: AI chat generates test cases
|
|
218
|
+
- **Feature Map → Chat**: Feature details link to chat for analysis
|
|
219
|
+
- **Settings → All**: Settings affect behavior across all features
|
|
220
|
+
- **Navigation → All**: Nav/switchers provide entry to every feature
|
|
221
|
+
- **Test Cases → Feature Map**: Test cases link to features/workflows they cover
|
|
222
|
+
- **Knowledge → Chat**: Knowledge entries are referenced in chat context
|
|
223
|
+
|
|
224
|
+
### 5b. Parent/Child Feature Hierarchy
|
|
225
|
+
|
|
226
|
+
If features span domains but have parent-child relationships, set `parentFeatureId` and `subFeatureIds` across fragments.
|
|
227
|
+
|
|
228
|
+
### 5c. Shared Component Reconciliation
|
|
229
|
+
|
|
230
|
+
Components used by multiple domains (e.g., layout components, toasts) should appear once with their `referencedByWorkflows` array including workflows from all domains.
|
|
231
|
+
|
|
232
|
+
### Cross-Link Output
|
|
233
|
+
|
|
234
|
+
Update the merged payload in-place. The cross-link step should produce a summary:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
Cross-links added:
|
|
238
|
+
feat:chat-conversations → feat:test-case-management (button: "Generate test case from chat")
|
|
239
|
+
feat:feature-map → feat:chat-conversations (button: "Ask AI about this feature")
|
|
240
|
+
feat:settings-jira → feat:test-case-management (integration: "Jira issues linked to test cases")
|
|
241
|
+
...
|
|
242
|
+
Total: 8 cross-links across 6 domains
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Step 6: Validate & Save
|
|
248
|
+
|
|
249
|
+
1. Call `levante_build_qa_map({ payload, dryRun: true })` to validate
|
|
250
|
+
2. Fix any errors (broken references, missing IDs)
|
|
251
|
+
3. Show the user: section/feature/workflow/component/scenario counts + cross-link summary
|
|
252
|
+
4. Once approved, call `levante_build_qa_map({ payload, dryRun: false })` to write
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Workflow Generation (Reference for Subagents)
|
|
257
|
+
|
|
258
|
+
Each subagent uses this two-pass method when generating workflows:
|
|
259
|
+
|
|
260
|
+
### Pass 1: Happy-Path Linear Sequence
|
|
261
|
+
|
|
262
|
+
Map the most common user journey as a sequence of steps.
|
|
263
|
+
|
|
264
|
+
### Pass 2: Conditional Forks & Convergence
|
|
265
|
+
|
|
266
|
+
For each step with validation, permissions, or business logic:
|
|
267
|
+
- Create a `conditional` step with `branchCondition`
|
|
268
|
+
- Add edges to different target steps
|
|
269
|
+
- Add convergence where branches rejoin
|
|
270
|
+
|
|
271
|
+
### Step Structure
|
|
61
272
|
|
|
62
|
-
Each step must have:
|
|
63
273
|
```json
|
|
64
274
|
{
|
|
65
275
|
"id": "step:<workflowId>:<slug>",
|
|
@@ -72,9 +282,8 @@ Each step must have:
|
|
|
72
282
|
}
|
|
73
283
|
```
|
|
74
284
|
|
|
75
|
-
|
|
285
|
+
### Edge Structure
|
|
76
286
|
|
|
77
|
-
Edges describe flow between steps:
|
|
78
287
|
```json
|
|
79
288
|
{
|
|
80
289
|
"fromStepId": "step:<wf>:<from>",
|
|
@@ -84,20 +293,19 @@ Edges describe flow between steps:
|
|
|
84
293
|
}
|
|
85
294
|
```
|
|
86
295
|
|
|
87
|
-
|
|
296
|
+
### DAG Structural Rules
|
|
88
297
|
|
|
89
|
-
1. Every step
|
|
90
|
-
2. `entryStepIds` = steps with NO incoming edges
|
|
91
|
-
3.
|
|
298
|
+
1. Every step ID follows: `step:<workflowId>:<kebab-slug>`
|
|
299
|
+
2. `entryStepIds` = steps with NO incoming edges
|
|
300
|
+
3. `conditional` steps MUST have 2+ `nextStepIds`
|
|
92
301
|
4. Terminal steps have `nextStepIds: []`
|
|
93
302
|
5. Every step must be reachable from an entry step
|
|
94
|
-
6. NO cycles
|
|
303
|
+
6. NO cycles — the graph must be a DAG
|
|
95
304
|
7. Every edge must reference existing steps
|
|
96
|
-
8. `edges[]`
|
|
305
|
+
8. `edges[]` must be consistent with `nextStepIds`
|
|
97
306
|
|
|
98
|
-
|
|
307
|
+
### Condition Structure
|
|
99
308
|
|
|
100
|
-
For preconditions, postconditions, and branchConditions:
|
|
101
309
|
```json
|
|
102
310
|
{
|
|
103
311
|
"entity": "user|form|list|session|data",
|
|
@@ -107,16 +315,29 @@ For preconditions, postconditions, and branchConditions:
|
|
|
107
315
|
}
|
|
108
316
|
```
|
|
109
317
|
|
|
110
|
-
|
|
318
|
+
### Workflow Types
|
|
319
|
+
|
|
320
|
+
`navigation`, `crud`, `multi-step`, `configuration`, `search-filter`, `authentication`, `notification`, `integration`
|
|
321
|
+
|
|
322
|
+
### Rules
|
|
323
|
+
|
|
324
|
+
1. Map each distinct user journey as a separate workflow
|
|
325
|
+
2. For forms: step for filling + step for submitting + validation branch
|
|
326
|
+
3. For CRUD: separate workflows for Create, Read/List, Update, Delete
|
|
327
|
+
4. Use `guardPatterns` from components as hints for conditional branches
|
|
328
|
+
5. Link components to steps based on which UI elements are involved
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Worked Example: Login Flow
|
|
111
333
|
|
|
112
|
-
### Example 1: Simple Linear (Login Flow)
|
|
113
334
|
```json
|
|
114
335
|
{
|
|
115
336
|
"steps": [
|
|
116
|
-
{ "id": "step:wf-login:navigate", "description": "
|
|
117
|
-
{ "id": "step:wf-login:fill-form", "description": "
|
|
118
|
-
{ "id": "step:wf-login:submit", "description": "
|
|
119
|
-
{ "id": "step:wf-login:check-result", "description": "
|
|
337
|
+
{ "id": "step:wf-login:navigate", "description": "Navigate to login page", "action": "navigation", "componentIds": [], "apiCalls": [], "nextStepIds": ["step:wf-login:fill-form"] },
|
|
338
|
+
{ "id": "step:wf-login:fill-form", "description": "Fill email and password", "action": "user-action", "componentIds": ["comp:login-form"], "apiCalls": [], "nextStepIds": ["step:wf-login:submit"] },
|
|
339
|
+
{ "id": "step:wf-login:submit", "description": "Click submit", "action": "api-call", "componentIds": [], "apiCalls": ["POST /api/auth/login"], "nextStepIds": ["step:wf-login:check-result"] },
|
|
340
|
+
{ "id": "step:wf-login:check-result", "description": "Check credentials", "action": "conditional", "componentIds": [], "apiCalls": [], "nextStepIds": ["step:wf-login:success", "step:wf-login:error"], "branchCondition": { "entity": "session", "state": "isAuthenticated", "operator": "equals", "value": true } },
|
|
120
341
|
{ "id": "step:wf-login:success", "description": "Redirect to dashboard", "action": "navigation", "componentIds": [], "apiCalls": [], "nextStepIds": [] },
|
|
121
342
|
{ "id": "step:wf-login:error", "description": "Show error message", "action": "system-response", "componentIds": ["comp:error-toast"], "apiCalls": [], "nextStepIds": [] }
|
|
122
343
|
],
|
|
@@ -131,54 +352,23 @@ For preconditions, postconditions, and branchConditions:
|
|
|
131
352
|
}
|
|
132
353
|
```
|
|
133
354
|
|
|
134
|
-
|
|
135
|
-
```json
|
|
136
|
-
{
|
|
137
|
-
"steps": [
|
|
138
|
-
{ "id": "step:wf-settings:load", "description": "Load settings page", "action": "navigation", "componentIds": [], "apiCalls": [], "nextStepIds": ["step:wf-settings:check-role"] },
|
|
139
|
-
{ "id": "step:wf-settings:check-role", "description": "Check user role", "action": "conditional", "componentIds": [], "apiCalls": [], "nextStepIds": ["step:wf-settings:admin-view", "step:wf-settings:member-view"], "branchCondition": { "entity": "user", "state": "role", "operator": "equals", "value": "admin" } },
|
|
140
|
-
{ "id": "step:wf-settings:admin-view", "description": "Show full settings with admin controls", "action": "system-response", "componentIds": ["comp:admin-settings"], "apiCalls": [], "nextStepIds": ["step:wf-settings:save"] },
|
|
141
|
-
{ "id": "step:wf-settings:member-view", "description": "Show limited settings", "action": "system-response", "componentIds": ["comp:member-settings"], "apiCalls": [], "nextStepIds": ["step:wf-settings:save"] },
|
|
142
|
-
{ "id": "step:wf-settings:save", "description": "Save settings changes", "action": "api-call", "componentIds": [], "apiCalls": ["PUT /api/settings"], "nextStepIds": [] }
|
|
143
|
-
],
|
|
144
|
-
"edges": [
|
|
145
|
-
{ "fromStepId": "step:wf-settings:load", "toStepId": "step:wf-settings:check-role", "edgeType": "default" },
|
|
146
|
-
{ "fromStepId": "step:wf-settings:check-role", "toStepId": "step:wf-settings:admin-view", "label": "admin", "edgeType": "branch" },
|
|
147
|
-
{ "fromStepId": "step:wf-settings:check-role", "toStepId": "step:wf-settings:member-view", "label": "member", "edgeType": "branch" },
|
|
148
|
-
{ "fromStepId": "step:wf-settings:admin-view", "toStepId": "step:wf-settings:save", "edgeType": "convergence" },
|
|
149
|
-
{ "fromStepId": "step:wf-settings:member-view", "toStepId": "step:wf-settings:save", "edgeType": "convergence" }
|
|
150
|
-
],
|
|
151
|
-
"entryStepIds": ["step:wf-settings:load"]
|
|
152
|
-
}
|
|
153
|
-
```
|
|
355
|
+
---
|
|
154
356
|
|
|
155
|
-
|
|
156
|
-
```json
|
|
157
|
-
{
|
|
158
|
-
"steps": [
|
|
159
|
-
{ "id": "step:wf-delete:confirm", "description": "Show delete confirmation dialog", "action": "user-action", "componentIds": ["comp:confirm-dialog"], "apiCalls": [], "nextStepIds": ["step:wf-delete:check-confirm"] },
|
|
160
|
-
{ "id": "step:wf-delete:check-confirm", "description": "User confirms or cancels", "action": "conditional", "componentIds": [], "apiCalls": [], "nextStepIds": ["step:wf-delete:execute", "step:wf-delete:cancelled"], "branchCondition": { "entity": "form", "state": "confirmed", "operator": "equals", "value": true } },
|
|
161
|
-
{ "id": "step:wf-delete:execute", "description": "Execute deletion", "action": "api-call", "componentIds": [], "apiCalls": ["DELETE /api/items/:id"], "nextStepIds": ["step:wf-delete:success"] },
|
|
162
|
-
{ "id": "step:wf-delete:cancelled", "description": "Dialog dismissed, no action taken", "action": "system-response", "componentIds": [], "apiCalls": [], "nextStepIds": [] },
|
|
163
|
-
{ "id": "step:wf-delete:success", "description": "Show success message and refresh list", "action": "system-response", "componentIds": ["comp:success-toast"], "apiCalls": [], "nextStepIds": [] }
|
|
164
|
-
],
|
|
165
|
-
"edges": [
|
|
166
|
-
{ "fromStepId": "step:wf-delete:confirm", "toStepId": "step:wf-delete:check-confirm", "edgeType": "default" },
|
|
167
|
-
{ "fromStepId": "step:wf-delete:check-confirm", "toStepId": "step:wf-delete:execute", "label": "confirmed", "edgeType": "branch" },
|
|
168
|
-
{ "fromStepId": "step:wf-delete:check-confirm", "toStepId": "step:wf-delete:cancelled", "label": "cancelled", "edgeType": "branch" },
|
|
169
|
-
{ "fromStepId": "step:wf-delete:execute", "toStepId": "step:wf-delete:success", "edgeType": "default" }
|
|
170
|
-
],
|
|
171
|
-
"entryStepIds": ["step:wf-delete:confirm"]
|
|
172
|
-
}
|
|
173
|
-
```
|
|
357
|
+
## Incremental Updates
|
|
174
358
|
|
|
175
|
-
|
|
359
|
+
If a QA map already exists:
|
|
360
|
+
1. Call `levante_read_qa_map()` to load it
|
|
361
|
+
2. Identify which domains changed (compare file timestamps, git diff)
|
|
362
|
+
3. Re-run only the affected domain subagents
|
|
363
|
+
4. Re-merge, preserving unchanged domains' fragments
|
|
364
|
+
5. Re-run cross-linking (always needed — changes in one domain may affect links)
|
|
365
|
+
6. Validate and save
|
|
176
366
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Error Recovery
|
|
370
|
+
|
|
371
|
+
- If a subagent fails, its fragment file won't exist. Re-run just that agent.
|
|
372
|
+
- If merge finds duplicate IDs, the fragment that was written last wins. Fix the source fragment and re-merge.
|
|
373
|
+
- If validation fails, check the error details — usually broken `featureId`/`workflowId` references from the cross-linking step.
|
|
374
|
+
- Fragments in `.qai/zefiro/map-pieces/` persist across runs. Delete stale ones before a fresh full scan.
|
package/dist/cli.js
CHANGED
|
@@ -8301,7 +8301,8 @@ import { join as join7 } from "node:path";
|
|
|
8301
8301
|
|
|
8302
8302
|
// src/scanner/push.ts
|
|
8303
8303
|
async function pushToApi(payload, apiUrl, apiKey) {
|
|
8304
|
-
const
|
|
8304
|
+
const isV3 = payload.schemaVersion === 3;
|
|
8305
|
+
const url = isV3 ? apiUrl.replace("/v2/push", "/v3/push") : apiUrl.replace("/v3/push", "/v2/push");
|
|
8305
8306
|
const response = await fetch(url, {
|
|
8306
8307
|
method: "POST",
|
|
8307
8308
|
headers: {
|