wogiflow 2.0.1 → 2.1.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/.claude/commands/wogi-bulk.md +18 -3
- package/.claude/commands/wogi-pending.md +72 -0
- package/.claude/commands/wogi-start.md +61 -2
- package/.claude/commands/wogi-test.md +12 -0
- package/.workflow/templates/claude-md.hbs +1 -0
- package/package.json +1 -1
- package/scripts/flow +7 -0
- package/scripts/flow-config-defaults.js +28 -1
- package/scripts/flow-constants.js +2 -2
- package/scripts/flow-contract-scan.js +144 -0
- package/scripts/flow-pending.js +153 -0
- package/scripts/flow-test-ui.js +1 -1
- package/scripts/hooks/core/task-completed.js +13 -0
- package/scripts/registries/contract-scanner.js +766 -0
|
@@ -23,16 +23,31 @@ Execute multiple tasks in sequence, following all workflow rules.
|
|
|
23
23
|
**Default behavior** (when `bulkOrchestrator.enabled: true`):
|
|
24
24
|
|
|
25
25
|
1. **Build Execution Plan**:
|
|
26
|
-
- Detect dependencies between tasks
|
|
26
|
+
- Detect dependencies between tasks (parent→child, shared files, API contracts)
|
|
27
27
|
- Group independent tasks into parallel batches
|
|
28
28
|
- Order batches to respect dependencies
|
|
29
29
|
|
|
30
|
-
2. **
|
|
30
|
+
2. **Smart Ordering** (when `config.autoCompact.smartOrdering: true`):
|
|
31
|
+
Within each batch, order tasks to maximize context reuse:
|
|
32
|
+
- Analyze which files each task will likely touch (from spec, title, or task type)
|
|
33
|
+
- Group tasks that touch the same files/components together
|
|
34
|
+
- Execute related tasks consecutively to reuse loaded context
|
|
35
|
+
- Example: Tasks touching auth files → tasks touching UI files → tasks touching API files
|
|
36
|
+
- **Dependencies always take priority over context optimization**
|
|
37
|
+
|
|
38
|
+
3. **Execute Each Batch**:
|
|
31
39
|
- For each batch, spawn sub-agent(s) with **fresh context**
|
|
32
40
|
- Independent tasks in same batch run in parallel
|
|
33
41
|
- Dependent tasks wait for their dependencies
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
4. **Auto-Compact Between Tasks** (when `config.autoCompact.betweenTasks: true`):
|
|
44
|
+
- After completing a task, check: does the NEXT task share context with this one?
|
|
45
|
+
- If YES (same files/components): keep context, proceed immediately
|
|
46
|
+
- If NO (different area of codebase): compact automatically before starting next task
|
|
47
|
+
- **Do NOT ask the user** — compact silently between tasks. This is automatic.
|
|
48
|
+
- This prevents context pollution and saves tokens on long batch runs
|
|
49
|
+
|
|
50
|
+
5. **Pass-Forward Summaries**:
|
|
36
51
|
- When Task A completes, generate completion summary
|
|
37
52
|
- Task B (if dependent on A) receives summary as context
|
|
38
53
|
- Ensures continuity without context pollution
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Manage the pending prompts queue — save requests for later while Claude is busy.
|
|
2
|
+
|
|
3
|
+
**Triggers**: `/wogi-pending`, "save this for later", "add to pending"
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
/wogi-pending "fix the header alignment" # Add item to queue
|
|
9
|
+
/wogi-pending --list # Show all pending items
|
|
10
|
+
/wogi-pending --clear 3 # Remove item #3
|
|
11
|
+
/wogi-pending --clear-all # Clear entire queue
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## How It Works
|
|
15
|
+
|
|
16
|
+
### Adding Items
|
|
17
|
+
|
|
18
|
+
When invoked with a prompt string:
|
|
19
|
+
1. Read `.workflow/state/pending-prompts.json`
|
|
20
|
+
2. Append new item with auto-incrementing ID, prompt text, timestamp
|
|
21
|
+
3. Save file
|
|
22
|
+
4. Display: "Saved to pending queue (#N). Will process after current task completes."
|
|
23
|
+
|
|
24
|
+
### Listing Items
|
|
25
|
+
|
|
26
|
+
When invoked with `--list` or no args:
|
|
27
|
+
1. Read pending-prompts.json
|
|
28
|
+
2. Display numbered list with timestamps
|
|
29
|
+
3. Show count: "N items pending"
|
|
30
|
+
|
|
31
|
+
### Processing (Auto-triggered)
|
|
32
|
+
|
|
33
|
+
After any task completes (via task-completed hook):
|
|
34
|
+
1. Check if pending-prompts.json has items
|
|
35
|
+
2. If yes, display:
|
|
36
|
+
```
|
|
37
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
38
|
+
PENDING QUEUE (N items)
|
|
39
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
40
|
+
|
|
41
|
+
1. "fix the header alignment" (added 15m ago)
|
|
42
|
+
2. "API returns 500 on empty input" (added 12m ago)
|
|
43
|
+
3. "wrong color on submit button" (added 8m ago)
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
I've analyzed these items for dependencies and grouping:
|
|
47
|
+
|
|
48
|
+
Group A (related — header/UI fixes):
|
|
49
|
+
#1 fix header alignment
|
|
50
|
+
#3 wrong color on submit button
|
|
51
|
+
→ Process together as one task
|
|
52
|
+
|
|
53
|
+
Group B (separate — API bug):
|
|
54
|
+
#2 API returns 500 on empty input
|
|
55
|
+
→ Process as individual task
|
|
56
|
+
|
|
57
|
+
Proposed order: Group B first (bug fix), then Group A (UI)
|
|
58
|
+
|
|
59
|
+
Ready to start? [Y/adjust/skip]
|
|
60
|
+
```
|
|
61
|
+
3. User approves or adjusts
|
|
62
|
+
4. Each group/item goes through `/wogi-start` individually
|
|
63
|
+
|
|
64
|
+
### Key Principles
|
|
65
|
+
|
|
66
|
+
- Items are NEVER compressed or merged without user approval
|
|
67
|
+
- Each item preserves its original wording exactly
|
|
68
|
+
- Grouping is suggested but user decides
|
|
69
|
+
- Processing is one-at-a-time through /wogi-start (not one big batch)
|
|
70
|
+
- The queue persists across sessions (saved to disk)
|
|
71
|
+
|
|
72
|
+
ARGUMENTS: {args}
|
|
@@ -16,7 +16,11 @@ When invoked with a **quoted request** instead of a task ID, assess intent and r
|
|
|
16
16
|
|
|
17
17
|
### Pre-Routing Checks (Automatic)
|
|
18
18
|
|
|
19
|
-
**Long Input Detection**: If `config.longInputGate.enabled` and
|
|
19
|
+
**Long Input Detection**: If `config.longInputGate.enabled` and EITHER:
|
|
20
|
+
- Prompt > `lineThreshold` (40) lines, OR
|
|
21
|
+
- Prompt contains 5+ discrete items (numbered lists, bullet points, semicolon-separated requests)
|
|
22
|
+
|
|
23
|
+
→ Auto-invoke `/wogi-extract-review` instead of normal triage. This ensures zero-loss extraction of every item. Skip for task IDs or primarily-code prompts.
|
|
20
24
|
|
|
21
25
|
**Plugin Registry Routing**: After command catalog finds no match and `config.plugins.enabled`, check `.workflow/state/plugin-registry.json` for trigger phrase matches (score >= 0.5). Plugin routing has LOWER priority than built-in commands.
|
|
22
26
|
|
|
@@ -158,6 +162,36 @@ Before generating specs (skip for small tasks ≤2 files, bugfixes, explicit spe
|
|
|
158
162
|
- Scope validation, assumption surfacing, edge cases, integration points
|
|
159
163
|
- Config: `config.clarifyingQuestions`
|
|
160
164
|
|
|
165
|
+
### Step 1.25: Item Reconciliation Gate (Multi-Item Inputs)
|
|
166
|
+
|
|
167
|
+
**Activates when**: User input contains 3+ discrete requests (identified by: numbered lists, bullet points, "and also", "plus", semicolons separating requests, or distinct topics in voice-transcribed text).
|
|
168
|
+
|
|
169
|
+
**Purpose**: Prevent item loss when the AI compresses many requests into fewer stories. This is the #1 cause of "silently dropped items" in long inputs.
|
|
170
|
+
|
|
171
|
+
**Procedure**:
|
|
172
|
+
1. **Enumerate**: Produce a numbered checklist of EVERY discrete request from the user's input. Each item = one testable action. No compression, no grouping, no summarization.
|
|
173
|
+
2. **Confirm count**: Display the checklist and count: "I found N items in your request: [list]. Is this complete?"
|
|
174
|
+
3. **Map to work items**: Each checklist item becomes a trackable acceptance criterion. Items may be grouped into stories, but EVERY item must appear as a criterion in at least one story. No item may be dropped during grouping.
|
|
175
|
+
4. **Reconciliation check**: After stories/tasks are created, cross-reference: for each original checklist item, verify it appears in at least one acceptance criterion. If any item is missing → add it before proceeding.
|
|
176
|
+
5. **At completion** (Step 3.5): The criteria verification must trace back to this original checklist. Every checklist item must be verified as implemented.
|
|
177
|
+
|
|
178
|
+
**Example**:
|
|
179
|
+
```
|
|
180
|
+
User: "Fix the login page, add forgot password, remove mock data,
|
|
181
|
+
update the header logo, and add loading states to all forms"
|
|
182
|
+
|
|
183
|
+
Item Reconciliation:
|
|
184
|
+
1. Fix the login page [→ Story A, criterion 1]
|
|
185
|
+
2. Add forgot password flow [→ Story A, criterion 2]
|
|
186
|
+
3. Remove all mock data [→ Story B, all criteria]
|
|
187
|
+
4. Update header logo [→ Story C, criterion 1]
|
|
188
|
+
5. Add loading states to all forms [→ Story C, criterion 2]
|
|
189
|
+
|
|
190
|
+
5 items found → 5 criteria across 3 stories → 0 items dropped ✓
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Skip when**: Input has only 1-2 items, or is a task ID reference.
|
|
194
|
+
|
|
161
195
|
### Step 1.3: Explore Phase (MANDATORY Multi-Agent Research)
|
|
162
196
|
|
|
163
197
|
**For L2+ tasks. Research is MANDATORY** — do NOT skip even if you think you know the answer.
|
|
@@ -270,6 +304,31 @@ After implementing all scenarios, BEFORE quality gates:
|
|
|
270
304
|
|
|
271
305
|
**This prevents "claiming done when not done."**
|
|
272
306
|
|
|
307
|
+
### Step 3.55: Semantic Verification Pass (for "remove/fix all X" tasks)
|
|
308
|
+
|
|
309
|
+
**Activates when**: The task involves removing, cleaning up, or fixing ALL instances of something (e.g., "remove all mock data", "fix all console.log", "replace all hardcoded URLs", "remove all deprecated APIs").
|
|
310
|
+
|
|
311
|
+
**Purpose**: Pattern-based search (regex, grep) finds instances that match a naming pattern. But semantic variants — hardcoded values, helper functions that serve the same purpose, inline fallbacks — are invisible to pattern search. This pass catches what regex misses.
|
|
312
|
+
|
|
313
|
+
**Procedure**:
|
|
314
|
+
1. After the implementation agent completes, do NOT immediately mark the task as done
|
|
315
|
+
2. Run a **second verification pass** that asks SEMANTICALLY, not syntactically:
|
|
316
|
+
- "Does any remaining code serve the purpose of [what we're removing]?"
|
|
317
|
+
- NOT: "Does any remaining code match the pattern [MOCK_*]?"
|
|
318
|
+
3. For each type of removal, use type-specific semantic checks:
|
|
319
|
+
|
|
320
|
+
| Removal Type | Semantic Check |
|
|
321
|
+
|-------------|----------------|
|
|
322
|
+
| Mock data | Scan render output for hardcoded business data (customer names, dollar amounts, percentages, dates that look like test data) |
|
|
323
|
+
| Console.log | Scan for any debugging output (console.warn, console.debug, alert(), debugger statements) |
|
|
324
|
+
| Hardcoded URLs | Scan for string literals containing http://, https://, localhost, IP addresses |
|
|
325
|
+
| Deprecated APIs | Scan for the FUNCTIONALITY the API provided, not just its name |
|
|
326
|
+
|
|
327
|
+
4. Use AI reasoning, NOT regex — the whole point is catching what regex misses
|
|
328
|
+
5. Report any findings as additional criteria to fix before completion
|
|
329
|
+
|
|
330
|
+
**Cross-cutting principle**: Pattern matching is for discovery. AI reasoning is for verification. The two-pass approach (pattern search → semantic verification) is the standard for any "fix all X" task.
|
|
331
|
+
|
|
273
332
|
### Step 3.6: Integration Wiring Validation (MANDATORY)
|
|
274
333
|
|
|
275
334
|
Run `node node_modules/wogiflow/scripts/flow-wiring-verifier.js wf-XXXXXXXX`
|
|
@@ -356,7 +415,7 @@ Reflection: "Have I introduced any bugs or regressions?"
|
|
|
356
415
|
|
|
357
416
|
**Quality gate keeps failing**: Report, attempt fix, after 3 failures suggest `/wogi-debug-hypothesis`.
|
|
358
417
|
|
|
359
|
-
**Context too large**:
|
|
418
|
+
**Context too large**: When `config.autoCompact.betweenTasks` is true (default), compact AUTOMATICALLY between tasks — do NOT ask the user. Just do it. Mid-task: commit progress, invoke `/wogi-compact` directly (don't suggest — execute).
|
|
360
419
|
|
|
361
420
|
## Mandatory Rules
|
|
362
421
|
|
|
@@ -193,6 +193,12 @@ Determine which test types to run:
|
|
|
193
193
|
| No flag | Run based on `config.testing.mode`: `ui`→UI only, `api`→API only, `full`→all 3, `auto`→detect and run applicable |
|
|
194
194
|
|
|
195
195
|
#### Run UI Tests
|
|
196
|
+
|
|
197
|
+
**Pre-check (MANDATORY)**: Before running UI tests, verify the testing tool is available. Do NOT skip this step — it prevents false-negative "not available" reports.
|
|
198
|
+
|
|
199
|
+
1. If `config.testing.provider` is `playwright-mcp`: Call `ToolSearch("playwright")` to verify Playwright MCP tools are loaded. If tools are found → proceed. If not found → report "Playwright MCP not configured" (distinct from "no test files").
|
|
200
|
+
|
|
201
|
+
2. Run the test script:
|
|
196
202
|
```bash
|
|
197
203
|
node -e "
|
|
198
204
|
const { runUITests } = require('./scripts/flow-test-ui');
|
|
@@ -200,6 +206,12 @@ runUITests('TASK_ID').then(r => console.log(JSON.stringify(r))).catch(err => con
|
|
|
200
206
|
"
|
|
201
207
|
```
|
|
202
208
|
|
|
209
|
+
3. **Interpret results separately**:
|
|
210
|
+
- Script returns `reason: 'no-test-files'` → "No test files found. Run `/wogi-test --generate` to create tests."
|
|
211
|
+
- MCP tools not available → "Playwright MCP not configured. Add it to `.claude/settings.json` MCP servers."
|
|
212
|
+
- Both → Show both facts separately, don't merge into one message.
|
|
213
|
+
- Script returns test results → show normally.
|
|
214
|
+
|
|
203
215
|
#### Run API Tests
|
|
204
216
|
```bash
|
|
205
217
|
node -e "
|
|
@@ -158,6 +158,7 @@ See `.claude/docs/commands.md` for complete command reference.
|
|
|
158
158
|
| "audit project", "project audit", "full project analysis", "full analysis" | `/wogi-audit` |
|
|
159
159
|
| "register plugin", "list plugins", "remove plugin", "register MCP" | `/wogi-register` |
|
|
160
160
|
| "run tests", "test everything", "verify tests", "run the tests", "test this task", "check if it works" | `/wogi-test` |
|
|
161
|
+
| "save for later", "add to pending", "queue this", "pending items", "show pending" | `/wogi-pending` |
|
|
161
162
|
|
|
162
163
|
**IMPORTANT**: When a user's message matches one of these patterns, immediately invoke the Skill tool with the corresponding command. Do not ask for confirmation. These `/wogi-*` commands satisfy the mandatory routing requirement — you do NOT also need to invoke `/wogi-start` when a detection match exists. `/wogi-start` is the fallback for messages that don't match this table.
|
|
163
164
|
|
package/package.json
CHANGED
package/scripts/flow
CHANGED
|
@@ -600,6 +600,9 @@ case "${1:-}" in
|
|
|
600
600
|
;;
|
|
601
601
|
esac
|
|
602
602
|
;;
|
|
603
|
+
pending)
|
|
604
|
+
node "$SCRIPT_DIR/flow-pending.js" "${@:2}"
|
|
605
|
+
;;
|
|
603
606
|
queue)
|
|
604
607
|
node "$SCRIPT_DIR/flow-queue.js" "${@:2}"
|
|
605
608
|
;;
|
|
@@ -1031,6 +1034,10 @@ case "${1:-}" in
|
|
|
1031
1034
|
# Background task execution
|
|
1032
1035
|
node "$SCRIPT_DIR/flow-background.js" "${@:2}"
|
|
1033
1036
|
;;
|
|
1037
|
+
contract-scan)
|
|
1038
|
+
# Contract surface scanner (teams feature)
|
|
1039
|
+
node "$SCRIPT_DIR/flow-contract-scan.js" "${@:2}"
|
|
1040
|
+
;;
|
|
1034
1041
|
version|--version|-v)
|
|
1035
1042
|
show_version
|
|
1036
1043
|
;;
|
|
@@ -684,7 +684,7 @@ const CONFIG_DEFAULTS = {
|
|
|
684
684
|
longInputGate: {
|
|
685
685
|
enabled: true,
|
|
686
686
|
charThreshold: 3000,
|
|
687
|
-
lineThreshold:
|
|
687
|
+
lineThreshold: 40,
|
|
688
688
|
smartDefault: true,
|
|
689
689
|
contentRules: { transcript: 'full', spec: 'full', requirements: 'full', code: 'skip', default: 'quick' },
|
|
690
690
|
autoTriggerTypes: ['transcript', 'specs', 'requirements', 'feature-request'],
|
|
@@ -731,6 +731,33 @@ const CONFIG_DEFAULTS = {
|
|
|
731
731
|
phases: ['exploring', 'spec_review', 'scenario', 'criteria_check', 'validating']
|
|
732
732
|
},
|
|
733
733
|
|
|
734
|
+
// --- Damage Control ---
|
|
735
|
+
// --- Auto-Compact (context-aware task scheduling) ---
|
|
736
|
+
autoCompact: {
|
|
737
|
+
betweenTasks: true,
|
|
738
|
+
smartOrdering: true,
|
|
739
|
+
respectDependencies: true
|
|
740
|
+
},
|
|
741
|
+
|
|
742
|
+
// --- Contract Surface (Teams-only — activated on wogi login) ---
|
|
743
|
+
contractSurface: {
|
|
744
|
+
enabled: false,
|
|
745
|
+
projectType: 'auto',
|
|
746
|
+
scanOn: ['sessionStart', 'afterTask'],
|
|
747
|
+
scanners: {
|
|
748
|
+
httpClients: true,
|
|
749
|
+
routes: true,
|
|
750
|
+
events: true,
|
|
751
|
+
sharedTypes: true,
|
|
752
|
+
envVars: true
|
|
753
|
+
},
|
|
754
|
+
httpClientPatterns: ['axios', 'fetch', 'ky', '$fetch'],
|
|
755
|
+
routePatterns: ['express', 'fastify', 'hono', 'next-api'],
|
|
756
|
+
ignoreEndpoints: ['/health', '/metrics', '/favicon.ico'],
|
|
757
|
+
sharedPackages: [],
|
|
758
|
+
maxFiles: 500
|
|
759
|
+
},
|
|
760
|
+
|
|
734
761
|
// --- Damage Control ---
|
|
735
762
|
damageControl: {
|
|
736
763
|
enabled: false,
|
|
@@ -132,8 +132,8 @@ const KNOWN_CONFIG_KEYS = [
|
|
|
132
132
|
// Session management
|
|
133
133
|
'metrics', 'requestLog', 'sessionState', 'smartCompaction',
|
|
134
134
|
// Features (alphabetical)
|
|
135
|
-
'audit', 'bestOfN', 'bugFlow', 'capture',
|
|
136
|
-
'cascade', 'checkpoint', 'commits', 'community',
|
|
135
|
+
'audit', 'autoCompact', 'bestOfN', 'bugFlow', 'capture',
|
|
136
|
+
'cascade', 'checkpoint', 'commits', 'community', 'contractSurface',
|
|
137
137
|
'damageControl', 'decide', 'decisions', 'epics', 'errorRecovery',
|
|
138
138
|
'eval', 'figmaAnalyzer', 'finalization', 'gateConfidence', 'guidedEdit',
|
|
139
139
|
'hooks', 'longInputGate', 'lsp', 'mandatorySteps', 'modelAdapters',
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wogi Flow - Contract Surface Scanner CLI
|
|
7
|
+
*
|
|
8
|
+
* TEAMS-ONLY feature: Scans a project's integration surface and generates
|
|
9
|
+
* contract-surface.json for the wogiflow-cloud orchestration agent.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* flow contract-scan # Scan and save to default path
|
|
13
|
+
* flow contract-scan --output <path> # Custom output path
|
|
14
|
+
* flow contract-scan --type backend # Force project type
|
|
15
|
+
* flow contract-scan --json # Output JSON to stdout
|
|
16
|
+
* flow contract-scan --verbose # Show scan progress
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
const { getProjectRoot, getConfig } = require('./flow-utils');
|
|
22
|
+
|
|
23
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
24
|
+
const DEFAULT_OUTPUT = path.join(PROJECT_ROOT, '.workflow', 'state', 'contract-surface.json');
|
|
25
|
+
|
|
26
|
+
function parseArgs(args) {
|
|
27
|
+
const options = {
|
|
28
|
+
output: DEFAULT_OUTPUT,
|
|
29
|
+
type: null,
|
|
30
|
+
json: false,
|
|
31
|
+
verbose: false
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < args.length; i++) {
|
|
35
|
+
switch (args[i]) {
|
|
36
|
+
case '--output':
|
|
37
|
+
case '-o':
|
|
38
|
+
options.output = args[++i];
|
|
39
|
+
break;
|
|
40
|
+
case '--type':
|
|
41
|
+
case '-t':
|
|
42
|
+
options.type = args[++i];
|
|
43
|
+
break;
|
|
44
|
+
case '--json':
|
|
45
|
+
options.json = true;
|
|
46
|
+
break;
|
|
47
|
+
case '--verbose':
|
|
48
|
+
case '-v':
|
|
49
|
+
options.verbose = true;
|
|
50
|
+
break;
|
|
51
|
+
case '--help':
|
|
52
|
+
case '-h':
|
|
53
|
+
showHelp();
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return options;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function showHelp() {
|
|
62
|
+
console.log(`
|
|
63
|
+
Contract Surface Scanner
|
|
64
|
+
|
|
65
|
+
Scans a project's integration surface (HTTP endpoints, events, shared types,
|
|
66
|
+
environment variables) and generates contract-surface.json.
|
|
67
|
+
|
|
68
|
+
Usage: flow contract-scan [options]
|
|
69
|
+
|
|
70
|
+
Options:
|
|
71
|
+
--output, -o <path> Output path (default: .workflow/state/contract-surface.json)
|
|
72
|
+
--type, -t <type> Force project type (frontend|backend|fullstack|library|monorepo)
|
|
73
|
+
--json Output JSON to stdout instead of saving to file
|
|
74
|
+
--verbose, -v Show scan progress
|
|
75
|
+
--help, -h Show this help
|
|
76
|
+
|
|
77
|
+
Examples:
|
|
78
|
+
flow contract-scan # Scan with defaults
|
|
79
|
+
flow contract-scan --verbose # Scan with progress output
|
|
80
|
+
flow contract-scan --json # Output to stdout
|
|
81
|
+
flow contract-scan --type backend --json # Force type, output to stdout
|
|
82
|
+
`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function main() {
|
|
86
|
+
const args = process.argv.slice(2);
|
|
87
|
+
const options = parseArgs(args);
|
|
88
|
+
|
|
89
|
+
// Check teams config
|
|
90
|
+
const config = getConfig();
|
|
91
|
+
const contractConfig = config.contractSurface || {};
|
|
92
|
+
|
|
93
|
+
if (!contractConfig.enabled && !options.json) {
|
|
94
|
+
console.log('Contract surface scanning is not enabled.');
|
|
95
|
+
console.log('This feature activates when connected to a team (wogi login).');
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log('To scan anyway, use: flow contract-scan --json');
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Lazy-load the scanner to keep startup fast
|
|
102
|
+
const { scanContracts } = require('./registries/contract-scanner');
|
|
103
|
+
|
|
104
|
+
const scanOptions = {
|
|
105
|
+
projectName: path.basename(PROJECT_ROOT),
|
|
106
|
+
projectType: options.type || contractConfig.projectType || undefined,
|
|
107
|
+
maxFiles: contractConfig.maxFiles || 500,
|
|
108
|
+
maxDepth: contractConfig.maxDepth || 6,
|
|
109
|
+
verbose: options.verbose
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (options.verbose) {
|
|
113
|
+
console.log(`Scanning ${PROJECT_ROOT}...`);
|
|
114
|
+
console.log('');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const surface = scanContracts(PROJECT_ROOT, scanOptions);
|
|
118
|
+
|
|
119
|
+
if (options.json) {
|
|
120
|
+
console.log(JSON.stringify(surface, null, 2));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Save to file
|
|
125
|
+
const outputDir = path.dirname(options.output);
|
|
126
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
127
|
+
fs.writeFileSync(options.output, JSON.stringify(surface, null, 2));
|
|
128
|
+
|
|
129
|
+
const relOutput = path.relative(PROJECT_ROOT, options.output);
|
|
130
|
+
console.log(`Contract surface saved to ${relOutput}`);
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log('Summary:');
|
|
133
|
+
console.log(` Project type: ${surface.projectType}`);
|
|
134
|
+
console.log(` Consumed endpoints: ${surface.endpoints.consumes.length}`);
|
|
135
|
+
console.log(` Exposed endpoints: ${surface.endpoints.exposes.length}`);
|
|
136
|
+
console.log(` Event emits: ${surface.events.emits.length}`);
|
|
137
|
+
console.log(` Event listeners: ${surface.events.listensTo.length}`);
|
|
138
|
+
console.log(` Shared type imports:${surface.sharedTypes.imports.length}`);
|
|
139
|
+
console.log(` Shared type exports:${surface.sharedTypes.exports.length}`);
|
|
140
|
+
console.log(` Env vars required: ${surface.environment.requires.length}`);
|
|
141
|
+
console.log(` Env vars defined: ${surface.environment.exposes.length}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
main();
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Pending Prompts Queue
|
|
5
|
+
*
|
|
6
|
+
* Manages a queue of user requests saved for later processing.
|
|
7
|
+
* Items are saved individually and processed after the current task completes.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* flow pending add "prompt text" # Add item to queue
|
|
11
|
+
* flow pending list # Show all pending items
|
|
12
|
+
* flow pending clear [id] # Clear specific item or all
|
|
13
|
+
* flow pending count # Get pending count
|
|
14
|
+
* flow pending mark-processed <id> # Mark item as processed
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs');
|
|
18
|
+
const path = require('node:path');
|
|
19
|
+
const { PATHS, readJson, writeJson } = require('./flow-utils');
|
|
20
|
+
|
|
21
|
+
const PENDING_PATH = path.join(PATHS.state, 'pending-prompts.json');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Load pending queue from disk
|
|
25
|
+
* @returns {{ items: Array, nextId: number }}
|
|
26
|
+
*/
|
|
27
|
+
function loadPending() {
|
|
28
|
+
return readJson(PENDING_PATH, { items: [], nextId: 1 });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Save pending queue to disk
|
|
33
|
+
* @param {Object} data - Queue data
|
|
34
|
+
*/
|
|
35
|
+
function savePending(data) {
|
|
36
|
+
return writeJson(PENDING_PATH, data);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Add an item to the pending queue
|
|
41
|
+
* @param {string} prompt - The prompt text to queue
|
|
42
|
+
* @returns {Object} The created item
|
|
43
|
+
*/
|
|
44
|
+
function addItem(prompt) {
|
|
45
|
+
const data = loadPending();
|
|
46
|
+
const item = {
|
|
47
|
+
id: data.nextId || (data.items.length + 1),
|
|
48
|
+
prompt: prompt.trim(),
|
|
49
|
+
addedAt: new Date().toISOString(),
|
|
50
|
+
status: 'pending'
|
|
51
|
+
};
|
|
52
|
+
data.items.push(item);
|
|
53
|
+
data.nextId = (data.nextId || data.items.length) + 1;
|
|
54
|
+
savePending(data);
|
|
55
|
+
return item;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* List all pending (non-processed) items
|
|
60
|
+
* @returns {Array} Pending items
|
|
61
|
+
*/
|
|
62
|
+
function listItems() {
|
|
63
|
+
const data = loadPending();
|
|
64
|
+
return data.items.filter(i => i.status === 'pending');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Remove a specific item by ID
|
|
69
|
+
* @param {number} id - Item ID to remove
|
|
70
|
+
* @returns {boolean} Whether the item was found and removed
|
|
71
|
+
*/
|
|
72
|
+
function clearItem(id) {
|
|
73
|
+
const data = loadPending();
|
|
74
|
+
const idx = data.items.findIndex(i => i.id === id);
|
|
75
|
+
if (idx === -1) return false;
|
|
76
|
+
data.items.splice(idx, 1);
|
|
77
|
+
savePending(data);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Clear all items from the queue
|
|
83
|
+
* @returns {boolean} Always true
|
|
84
|
+
*/
|
|
85
|
+
function clearAll() {
|
|
86
|
+
savePending({ items: [], nextId: 1 });
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the count of pending (non-processed) items
|
|
92
|
+
* @returns {number}
|
|
93
|
+
*/
|
|
94
|
+
function getPendingCount() {
|
|
95
|
+
const data = loadPending();
|
|
96
|
+
return data.items.filter(i => i.status === 'pending').length;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Mark an item as processed
|
|
101
|
+
* @param {number} id - Item ID to mark
|
|
102
|
+
*/
|
|
103
|
+
function markProcessed(id) {
|
|
104
|
+
const data = loadPending();
|
|
105
|
+
const item = data.items.find(i => i.id === id);
|
|
106
|
+
if (item) {
|
|
107
|
+
item.status = 'processed';
|
|
108
|
+
item.processedAt = new Date().toISOString();
|
|
109
|
+
savePending(data);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// CLI entry point
|
|
114
|
+
if (require.main === module) {
|
|
115
|
+
const args = process.argv.slice(2);
|
|
116
|
+
const command = args[0];
|
|
117
|
+
|
|
118
|
+
if (command === 'add') {
|
|
119
|
+
const prompt = args.slice(1).join(' ');
|
|
120
|
+
if (!prompt) {
|
|
121
|
+
console.error('Usage: flow pending add "prompt text"');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
const item = addItem(prompt);
|
|
125
|
+
console.log(JSON.stringify({ success: true, item }));
|
|
126
|
+
} else if (command === 'list') {
|
|
127
|
+
const items = listItems();
|
|
128
|
+
console.log(JSON.stringify({ success: true, items, count: items.length }));
|
|
129
|
+
} else if (command === 'clear') {
|
|
130
|
+
const id = parseInt(args[1], 10);
|
|
131
|
+
if (isNaN(id)) {
|
|
132
|
+
clearAll();
|
|
133
|
+
console.log(JSON.stringify({ success: true, cleared: 'all' }));
|
|
134
|
+
} else {
|
|
135
|
+
const removed = clearItem(id);
|
|
136
|
+
console.log(JSON.stringify({ success: removed, cleared: id }));
|
|
137
|
+
}
|
|
138
|
+
} else if (command === 'count') {
|
|
139
|
+
console.log(JSON.stringify({ count: getPendingCount() }));
|
|
140
|
+
} else if (command === 'mark-processed') {
|
|
141
|
+
const id = parseInt(args[1], 10);
|
|
142
|
+
if (isNaN(id)) {
|
|
143
|
+
console.error('Usage: flow pending mark-processed <id>');
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
markProcessed(id);
|
|
147
|
+
console.log(JSON.stringify({ success: true, marked: id }));
|
|
148
|
+
} else {
|
|
149
|
+
console.log('Usage: flow pending [add|list|clear|count|mark-processed]');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = { addItem, listItems, clearItem, clearAll, getPendingCount, markProcessed, loadPending, savePending, PENDING_PATH };
|
package/scripts/flow-test-ui.js
CHANGED
|
@@ -576,7 +576,7 @@ async function runUITests(taskId, options = {}) {
|
|
|
576
576
|
if (testFlows.length === 0) {
|
|
577
577
|
const report = generateReport(
|
|
578
578
|
taskId,
|
|
579
|
-
[{ name: 'No UI
|
|
579
|
+
[{ name: 'No UI test files found', status: 'skipped', reason: 'no-test-files', expected: [], found: [], missing: [], duration: 0, hint: 'Run /wogi-test --generate to create tests, or /wogi-test-browser for interactive browser testing' }],
|
|
580
580
|
{ checked: stateChecks, covered: [], missing: stateChecks },
|
|
581
581
|
null
|
|
582
582
|
);
|
|
@@ -251,6 +251,19 @@ async function handleTaskCompleted(input) {
|
|
|
251
251
|
} catch (_err) {
|
|
252
252
|
// Non-critical - registry manager may not be available
|
|
253
253
|
}
|
|
254
|
+
// Check pending queue — notify user if items are waiting
|
|
255
|
+
try {
|
|
256
|
+
const { getPendingCount } = require('../../flow-pending');
|
|
257
|
+
const pendingCount = getPendingCount();
|
|
258
|
+
if (pendingCount > 0) {
|
|
259
|
+
result.pendingQueue = {
|
|
260
|
+
count: pendingCount,
|
|
261
|
+
message: `You have ${pendingCount} pending item${pendingCount !== 1 ? 's' : ''} queued. Run /wogi-pending --list to review, or I'll process them next.`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
} catch (_err) {
|
|
265
|
+
// Non-critical — pending module may not be available
|
|
266
|
+
}
|
|
254
267
|
} catch (err) {
|
|
255
268
|
result.message = `Task completed handler error: ${err.message}`;
|
|
256
269
|
}
|