wogiflow 2.21.0 → 2.22.1
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-finalize.md +83 -0
- package/.claude/commands/wogi-start.md +3 -3
- package/.claude/commands/wogi-story.md +27 -0
- package/.claude/docs/claude-code-compatibility.md +32 -1
- package/.claude/rules/_internal/self-maintenance.md +1 -1
- package/.claude/settings.json +1 -1
- package/lib/commands/login.js +1 -1
- package/lib/installer.js +5 -5
- package/lib/release-channel.js +1 -1
- package/lib/skill-registry.js +3 -3
- package/lib/workspace-dispatch-tracking.js +175 -0
- package/lib/workspace-events.js +1 -1
- package/lib/workspace-gates.js +2 -2
- package/lib/workspace-intelligence.js +1 -1
- package/lib/workspace-messages.js +1 -0
- package/lib/workspace-routing.js +18 -1
- package/lib/workspace.js +16 -17
- package/package.json +2 -2
- package/scripts/base-workflow-step.js +2 -2
- package/scripts/flow-adaptive-learning.js +6 -6
- package/scripts/flow-api-index.js +2 -2
- package/scripts/flow-architect-pass.js +1 -1
- package/scripts/flow-ask.js +1 -1
- package/scripts/flow-assumption-detector.js +1 -1
- package/scripts/flow-audit-gates.js +38 -12
- package/scripts/flow-audit.js +4 -4
- package/scripts/flow-auto-context.js +3 -3
- package/scripts/flow-background.js +1 -1
- package/scripts/flow-best-of-n.js +7 -7
- package/scripts/flow-bridge.js +3 -3
- package/scripts/flow-bug.js +2 -2
- package/scripts/flow-bulk-loop.js +7 -7
- package/scripts/flow-cascade-completion.js +2 -2
- package/scripts/flow-cascade.js +1 -1
- package/scripts/flow-checkpoint.js +2 -2
- package/scripts/flow-clarifying-questions.js +2 -2
- package/scripts/flow-cli.js +2 -2
- package/scripts/flow-code-intelligence.js +4 -4
- package/scripts/flow-community-sync.js +6 -6
- package/scripts/flow-community.js +1 -1
- package/scripts/flow-completion-truth-gate.js +161 -5
- package/scripts/flow-complexity.js +1 -1
- package/scripts/flow-config-defaults.js +18 -1
- package/scripts/flow-config-interactive.js +2 -2
- package/scripts/flow-config-loader.js +1 -1
- package/scripts/flow-config-migrate.js +5 -6
- package/scripts/flow-consistency-check.js +5 -5
- package/scripts/flow-context-compact/expander.js +1 -1
- package/scripts/flow-context-compact/index.js +2 -2
- package/scripts/flow-context-compact/section-extractor.js +3 -3
- package/scripts/flow-context-compact/summary-tree.js +1 -1
- package/scripts/flow-context-estimator.js +1 -1
- package/scripts/flow-context-gatherer.js +6 -6
- package/scripts/flow-context-generator.js +6 -6
- package/scripts/flow-context-init.js +2 -2
- package/scripts/flow-context-manager.js +1 -1
- package/scripts/flow-context-manifest.js +1 -1
- package/scripts/flow-context-monitor.js +5 -5
- package/scripts/flow-context-orchestrator.js +2 -2
- package/scripts/flow-context-scoring.js +4 -4
- package/scripts/flow-contract-scan.js +1 -1
- package/scripts/flow-correct.js +3 -3
- package/scripts/flow-damage-control.js +2 -2
- package/scripts/flow-deploy-gate.js +2 -2
- package/scripts/flow-deploy-history.js +1 -1
- package/scripts/flow-diff.js +3 -3
- package/scripts/flow-done-gates.js +1 -1
- package/scripts/flow-done.js +7 -7
- package/scripts/flow-durable-session.js +1 -1
- package/scripts/flow-entropy-monitor.js +3 -3
- package/scripts/flow-epics.js +5 -5
- package/scripts/flow-error-recovery.js +4 -4
- package/scripts/flow-eval-judge.js +5 -5
- package/scripts/flow-eval.js +7 -7
- package/scripts/flow-export-scanner.js +5 -5
- package/scripts/flow-extraction-review.js +1 -1
- package/scripts/flow-failure-learning.js +9 -9
- package/scripts/flow-feature.js +5 -5
- package/scripts/flow-figma-confirm.js +1 -1
- package/scripts/flow-figma-extract.js +2 -2
- package/scripts/flow-figma-index.js +2 -2
- package/scripts/flow-figma-match.js +1 -1
- package/scripts/flow-figma-mcp-server.js +3 -3
- package/scripts/flow-figma-orchestrator.js +1 -1
- package/scripts/flow-figma-registry.js +2 -2
- package/scripts/flow-function-index.js +2 -2
- package/scripts/flow-gate-confidence.js +2 -2
- package/scripts/flow-gate-telemetry.js +1 -1
- package/scripts/flow-gitignore.js +1 -1
- package/scripts/flow-guided-edit.js +3 -3
- package/scripts/flow-health.js +95 -8
- package/scripts/flow-hooks.js +3 -3
- package/scripts/flow-hybrid-detect.js +2 -2
- package/scripts/flow-hybrid-interactive.js +1 -1
- package/scripts/flow-hybrid-test.js +1 -1
- package/scripts/flow-hypothesis-generator.js +4 -4
- package/scripts/flow-instruction-richness.js +11 -11
- package/scripts/flow-intent-bootstrap.js +1 -1
- package/scripts/flow-intent-framing.js +1 -1
- package/scripts/flow-item-link.js +2 -2
- package/scripts/flow-knowledge-router.js +7 -7
- package/scripts/flow-knowledge-sync.js +3 -3
- package/scripts/flow-learning-orchestrator.js +1 -1
- package/scripts/flow-links.js +2 -2
- package/scripts/flow-log-manager.js +2 -2
- package/scripts/flow-logic-adversary.js +5 -4
- package/scripts/flow-long-input-chunking.js +1 -1
- package/scripts/flow-long-input-cli.js +3 -3
- package/scripts/flow-long-input.js +18 -18
- package/scripts/flow-loop-retry-learning.js +2 -2
- package/scripts/flow-lsp.js +4 -4
- package/scripts/flow-mcp-docs.js +1 -1
- package/scripts/flow-memory-blocks.js +5 -5
- package/scripts/flow-memory-compactor.js +3 -3
- package/scripts/flow-memory-db.js +4 -4
- package/scripts/flow-memory-sync.js +3 -3
- package/scripts/flow-metrics.js +2 -2
- package/scripts/flow-migrate-igr.js +2 -2
- package/scripts/flow-migrate.js +2 -2
- package/scripts/flow-model-adapter.js +4 -4
- package/scripts/flow-model-caller.js +8 -8
- package/scripts/flow-model-config.js +5 -5
- package/scripts/flow-model-profile.js +7 -7
- package/scripts/flow-model-router.js +5 -5
- package/scripts/flow-model-types.js +3 -3
- package/scripts/flow-models.js +8 -8
- package/scripts/flow-morning.js +1 -1
- package/scripts/flow-multi-approach.js +1 -1
- package/scripts/flow-orchestrate-context.js +2 -2
- package/scripts/flow-orchestrate-llm.js +4 -4
- package/scripts/flow-orchestrate-rollback.js +1 -1
- package/scripts/flow-orchestrate-state.js +6 -6
- package/scripts/flow-orchestrate-templates.js +1 -1
- package/scripts/flow-orchestrate-validation.js +2 -2
- package/scripts/flow-orchestrate-validator.js +1 -1
- package/scripts/flow-orchestrate.js +25 -25
- package/scripts/flow-parallel.js +1 -1
- package/scripts/flow-pattern-enforcer.js +7 -7
- package/scripts/flow-pattern-extractor.js +3 -3
- package/scripts/flow-peer-review.js +8 -8
- package/scripts/flow-pending.js +1 -1
- package/scripts/flow-permissions.js +1 -1
- package/scripts/flow-phased-task.js +1 -1
- package/scripts/flow-plan.js +1 -1
- package/scripts/flow-prd-manager.js +2 -2
- package/scripts/flow-product-scanner.js +2 -2
- package/scripts/flow-progress-tracker.js +2 -2
- package/scripts/flow-progress.js +1 -1
- package/scripts/flow-project-analyzer.js +3 -3
- package/scripts/flow-prompt-capture.js +2 -2
- package/scripts/flow-prompt-composer.js +3 -3
- package/scripts/flow-prompt-template.js +4 -4
- package/scripts/flow-providers.js +31 -23
- package/scripts/flow-queue.js +1 -1
- package/scripts/flow-registry-manager.js +4 -4
- package/scripts/flow-regression.js +1 -1
- package/scripts/flow-response-parser.js +1 -1
- package/scripts/flow-resume.js +1 -1
- package/scripts/flow-review-passes/index.js +2 -2
- package/scripts/flow-review-passes/integration.js +3 -3
- package/scripts/flow-review-passes/logic.js +3 -3
- package/scripts/flow-review-passes/security.js +2 -2
- package/scripts/flow-review-passes/structure.js +1 -1
- package/scripts/flow-review.js +11 -11
- package/scripts/flow-revision-tracker.js +2 -2
- package/scripts/flow-roadmap.js +2 -2
- package/scripts/flow-run-trace.js +1 -1
- package/scripts/flow-safety.js +3 -3
- package/scripts/flow-scanner-base.js +1 -1
- package/scripts/flow-scenario-engine.js +7 -7
- package/scripts/flow-schema-drift.js +4 -3
- package/scripts/flow-section-index.js +2 -2
- package/scripts/flow-section-resolver.js +4 -4
- package/scripts/flow-semantic-match.js +3 -3
- package/scripts/flow-session-end.js +56 -0
- package/scripts/flow-session-learning.js +2 -2
- package/scripts/flow-setup-hooks.js +1 -1
- package/scripts/flow-skill-create.js +3 -3
- package/scripts/flow-skill-freshness.js +2 -2
- package/scripts/flow-skill-generator.js +6 -6
- package/scripts/flow-skill-learn.js +7 -7
- package/scripts/flow-skill-matcher.js +2 -2
- package/scripts/flow-solution-optimizer.js +1 -1
- package/scripts/flow-spec-generator.js +5 -5
- package/scripts/flow-spec-verifier.js +2 -2
- package/scripts/flow-stack-wizard.js +6 -6
- package/scripts/flow-standards-checker.js +8 -8
- package/scripts/flow-standards-gate.js +4 -4
- package/scripts/flow-standards-learner.js +2 -2
- package/scripts/flow-start.js +9 -9
- package/scripts/flow-stats-collector.js +2 -2
- package/scripts/flow-status.js +1 -1
- package/scripts/flow-step-changelog.js +3 -3
- package/scripts/flow-step-complexity.js +1 -1
- package/scripts/flow-step-coverage.js +3 -3
- package/scripts/flow-step-knowledge.js +2 -2
- package/scripts/flow-step-pr-tests.js +2 -2
- package/scripts/flow-step-regression.js +3 -3
- package/scripts/flow-step-review.js +5 -5
- package/scripts/flow-story-gates.js +504 -0
- package/scripts/flow-story.js +207 -9
- package/scripts/flow-strict-adherence.js +2 -2
- package/scripts/flow-structure-sensor.js +283 -0
- package/scripts/flow-sync-anonymizer.js +3 -3
- package/scripts/flow-task-checkpoint.js +2 -2
- package/scripts/flow-task-classifier.js +2 -2
- package/scripts/flow-task-completion-summary.js +1 -1
- package/scripts/flow-task-enforcer.js +5 -5
- package/scripts/flow-tech-debt.js +3 -3
- package/scripts/flow-template-extractor.js +3 -3
- package/scripts/flow-templates.js +1 -1
- package/scripts/flow-test-api.js +12 -12
- package/scripts/flow-test-discovery.js +9 -9
- package/scripts/flow-test-generate.js +5 -5
- package/scripts/flow-test-integrity.js +3 -3
- package/scripts/flow-test-ui.js +8 -8
- package/scripts/flow-testing-deps.js +4 -4
- package/scripts/flow-tiered-learning.js +3 -3
- package/scripts/flow-todowrite-sync.js +1 -1
- package/scripts/flow-trap-zone.js +1 -1
- package/scripts/flow-verification-profile.js +9 -9
- package/scripts/flow-verify.js +2 -2
- package/scripts/flow-version-check.js +2 -2
- package/scripts/flow-webmcp-generator.js +3 -3
- package/scripts/flow-wiring-verifier.js +13 -13
- package/scripts/flow-workflow-steps.js +3 -3
- package/scripts/flow-workflow.js +1 -1
- package/scripts/flow-worktree.js +1 -1
- package/scripts/hooks/adapters/base-adapter.js +2 -2
- package/scripts/hooks/adapters/claude-code.js +18 -37
- package/scripts/hooks/core/commit-log-gate.js +2 -2
- package/scripts/hooks/core/component-check.js +3 -3
- package/scripts/hooks/core/config-change.js +1 -1
- package/scripts/hooks/core/deploy-gate.js +2 -1
- package/scripts/hooks/core/git-safety-gate.js +1 -1
- package/scripts/hooks/core/instructions-loaded.js +1 -1
- package/scripts/hooks/core/loop-check.js +1 -1
- package/scripts/hooks/core/manager-boundary-gate.js +3 -2
- package/scripts/hooks/core/observation-capture.js +6 -6
- package/scripts/hooks/core/overdue-dispatches.js +159 -0
- package/scripts/hooks/core/phase-gate.js +4 -4
- package/scripts/hooks/core/pre-compact.js +1 -1
- package/scripts/hooks/core/routing-gate.js +1 -1
- package/scripts/hooks/core/session-context.js +1 -1
- package/scripts/hooks/core/session-end.js +3 -3
- package/scripts/hooks/core/session-history.js +1 -1
- package/scripts/hooks/core/setup-handler.js +1 -1
- package/scripts/hooks/core/task-boundary-reset.js +2 -4
- package/scripts/hooks/core/task-completed.js +13 -7
- package/scripts/hooks/core/task-created.js +1 -1
- package/scripts/hooks/core/worktree-lifecycle.js +1 -1
- package/scripts/hooks/entry/claude-code/permission-denied.js +4 -2
- package/scripts/hooks/entry/claude-code/stop.js +92 -47
- package/scripts/hooks/entry/claude-code/user-prompt-submit.js +19 -1
- package/scripts/hooks/git/post-commit.js +1 -1
- package/scripts/postinstall.js +7 -7
- package/scripts/preuninstall.js +5 -5
- package/scripts/registries/component-registry.js +2 -2
- package/scripts/registries/contract-scanner.js +11 -11
- package/scripts/registries/schema-registry.js +5 -5
- package/scripts/registries/service-registry.js +9 -9
|
@@ -79,6 +79,79 @@ Pre-finalization checks:
|
|
|
79
79
|
|
|
80
80
|
If checks fail, display warnings and suggest fixes before proceeding.
|
|
81
81
|
|
|
82
|
+
### Step 2.5: Merge-Plan Gate (when `mergePlan.threshold` exceeded)
|
|
83
|
+
|
|
84
|
+
**Activates when** the branch carries more commits than `config.finalization.mergePlan.threshold` (default **5**) OR the diff is flagged cross-repo by the workspace manifest. The gate writes — and requires the AI to fill in — `.workflow/scratch/merge-plan.md`. The gate exists because the "1-2h mostly mechanical" audit that predicted a 27-conflict merge (wogi-hub, 2026-04-16) counted commits-per-file without reading diff content; the fix is to force per-commit action assignment in a file.
|
|
85
|
+
|
|
86
|
+
**Mechanical invariants (gate blocks on violation):**
|
|
87
|
+
|
|
88
|
+
1. For every commit in `git log <base>..<branch>`, the plan MUST contain one line starting with the short SHA and a tagged action. No commits in an "unaccounted" bucket.
|
|
89
|
+
2. Allowed actions: `port | adapt | skip-style | superseded | skip-with-reason`.
|
|
90
|
+
3. `git log <base>..<branch> | wc -l` MUST equal the count of SHA-prefixed lines in the plan. Mismatch → hard-stop until reconciled.
|
|
91
|
+
4. `skip-with-reason` entries MUST include a one-line reason after a `—` (em dash).
|
|
92
|
+
|
|
93
|
+
**Structural-change detection (before plan write):**
|
|
94
|
+
|
|
95
|
+
Run the structure-change sensor (`scripts/flow-structure-sensor.js`) on the diff. If ≥ `config.finalization.mergePlan.restructureThreshold` (default **20%**) of changed files match one of these restructure patterns, display a STRUCTURAL CHANGE warning at the top of the plan and bias the default action for affected commits to `adapt`:
|
|
96
|
+
|
|
97
|
+
| Pattern | Example | Meaning |
|
|
98
|
+
|---------|---------|---------|
|
|
99
|
+
| `X.tsx` deleted + `X/X.tsx` added | `Card.tsx` → `Card/Card.tsx` | folder-per-component |
|
|
100
|
+
| `X.ts` deleted + `<dir>/X.ts` added at deeper depth | `utils.ts` → `utils/date.ts` | split into submodule |
|
|
101
|
+
| `X` deleted + `X.<ext>` added elsewhere | `types.ts` → `types/index.ts` | barrel introduction |
|
|
102
|
+
|
|
103
|
+
**Procedure:**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# 1. Gather commit list
|
|
107
|
+
git log --pretty='%h %s' <base>..<branch> > .workflow/scratch/.merge-plan-commits.txt
|
|
108
|
+
|
|
109
|
+
# 2. Run structure sensor
|
|
110
|
+
node node_modules/wogiflow/scripts/flow-structure-sensor.js <base>..<branch> > .workflow/scratch/.merge-plan-sensor.json
|
|
111
|
+
|
|
112
|
+
# 3. Write .workflow/scratch/merge-plan.md using the template below,
|
|
113
|
+
# one SHA-prefixed line per commit. Read the FULL diff of each commit
|
|
114
|
+
# (not just the subject line) before assigning an action — that is
|
|
115
|
+
# the whole point of this gate.
|
|
116
|
+
|
|
117
|
+
# 4. Verify the mechanical invariant
|
|
118
|
+
test "$(git log --oneline <base>..<branch> | wc -l)" -eq \
|
|
119
|
+
"$(grep -cE '^[a-f0-9]{7,}\s' .workflow/scratch/merge-plan.md)"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Plan template** (write verbatim, then fill each row by reading the full diff):
|
|
123
|
+
|
|
124
|
+
```markdown
|
|
125
|
+
# Merge plan: <branch> → <base>
|
|
126
|
+
|
|
127
|
+
Commits: N (from `git log <base>..<branch>`)
|
|
128
|
+
Structural-change sensor: <WARN|clean> — N/M files match restructure patterns
|
|
129
|
+
Cross-repo impact: <list workspace members affected, or "single-repo">
|
|
130
|
+
|
|
131
|
+
## Per-commit actions
|
|
132
|
+
|
|
133
|
+
| SHA | Subject | Action | Notes |
|
|
134
|
+
|-----|---------|--------|-------|
|
|
135
|
+
| abc1234 | feat: add login form | port | — |
|
|
136
|
+
| def5678 | refactor: split Card.tsx into Card/ | adapt | folder-per-component restructure |
|
|
137
|
+
| ghi9012 | chore: lint fixes | skip-style | — |
|
|
138
|
+
| jkl3456 | revert: roll back header | skip-with-reason | superseded by mno7890 |
|
|
139
|
+
|
|
140
|
+
## Structural risks
|
|
141
|
+
|
|
142
|
+
<leave empty if sensor is clean; otherwise list each pattern hit>
|
|
143
|
+
|
|
144
|
+
## Content risks
|
|
145
|
+
|
|
146
|
+
<list overlaps in shared types, DTOs, API surface that need manual review>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**When the plan is complete**, the gate verifies the commit-count invariant (step 4) and proceeds to Step 3 (options). If invariant fails, the command stops with the reconciliation command printed.
|
|
150
|
+
|
|
151
|
+
**Skip conditions:**
|
|
152
|
+
- `config.finalization.mergePlan.enabled: false` — opt-out for users who don't want the gate
|
|
153
|
+
- Branch commits ≤ threshold AND single-repo — small merges don't need a plan
|
|
154
|
+
|
|
82
155
|
### Step 3: Present Options
|
|
83
156
|
|
|
84
157
|
```
|
|
@@ -241,6 +314,12 @@ When `/wogi-start` completes a task that was executed in a worktree, the finaliz
|
|
|
241
314
|
"includeTaskSpec": true,
|
|
242
315
|
"includeCommitList": true,
|
|
243
316
|
"includeFileSummary": true
|
|
317
|
+
},
|
|
318
|
+
"mergePlan": {
|
|
319
|
+
"enabled": true,
|
|
320
|
+
"threshold": 5,
|
|
321
|
+
"restructureThreshold": 0.20,
|
|
322
|
+
"alwaysForCrossRepo": true
|
|
244
323
|
}
|
|
245
324
|
}
|
|
246
325
|
}
|
|
@@ -254,6 +333,10 @@ When `/wogi-start` completes a task that was executed in a worktree, the finaliz
|
|
|
254
333
|
| `requirePRForTypes` | `[]` | Task types that must create a PR (useful for teams) |
|
|
255
334
|
| `squashOnMerge` | `true` | Squash commits when merging |
|
|
256
335
|
| `prTemplate` | `{...}` | What to include in auto-generated PR body |
|
|
336
|
+
| `mergePlan.enabled` | `true` | Require per-commit merge plan on large or cross-repo merges |
|
|
337
|
+
| `mergePlan.threshold` | `5` | Commit count above which the merge plan is required |
|
|
338
|
+
| `mergePlan.restructureThreshold` | `0.20` | % of changed files matching restructure patterns that triggers a structural-change warning |
|
|
339
|
+
| `mergePlan.alwaysForCrossRepo` | `true` | Require the plan on any cross-repo merge regardless of commit count |
|
|
257
340
|
|
|
258
341
|
## Examples
|
|
259
342
|
|
|
@@ -180,18 +180,18 @@ When epic creation adds 2+ stories to ready.json and `config.bulkOrchestrator.en
|
|
|
180
180
|
|
|
181
181
|
Non-blocking if transition fails.
|
|
182
182
|
|
|
183
|
-
### Effort Level Optimization (Claude Code 2.1.72+)
|
|
183
|
+
### Effort Level Optimization (Claude Code 2.1.72+, xhigh added 2.1.111+)
|
|
184
184
|
|
|
185
185
|
After task level classification (L0-L3), set the reasoning effort level to optimize token usage:
|
|
186
186
|
|
|
187
187
|
| Task Level | Effort | Rationale |
|
|
188
188
|
|------------|--------|-----------|
|
|
189
|
-
| L0 (Epic) | high | Complex planning, multi-file architecture |
|
|
189
|
+
| L0 (Epic) | high (xhigh on Opus 4.7 for deep architectural reasoning) | Complex planning, multi-file architecture |
|
|
190
190
|
| L1 (Story) | high | Multi-criteria implementation |
|
|
191
191
|
| L2 (Task) | medium | Standard 1-5 file changes |
|
|
192
192
|
| L3 (Subtask) | low | Single file, trivial change |
|
|
193
193
|
|
|
194
|
-
This is advisory
|
|
194
|
+
This is advisory. Claude Code's effort levels: `low` / `medium` / `high` are universal. Claude Code 2.1.111+ added `xhigh` (between high and max) and `max` as Opus 4.7-only levels — other models fall back to `high`. Use `/effort` interactively (slider as of 2.1.111) to switch mid-session. The AI should adjust reasoning depth during implementation phases accordingly.
|
|
195
195
|
|
|
196
196
|
### Task Checkpoints (when `config.proactiveCompaction.enabled`)
|
|
197
197
|
|
|
@@ -8,11 +8,38 @@ Run `./scripts/flow story "<title>"` to create a story.
|
|
|
8
8
|
|
|
9
9
|
Load `agents/story-writer.md` for the full story format.
|
|
10
10
|
|
|
11
|
+
## Anti-Deferral Rule (MANDATORY)
|
|
12
|
+
|
|
13
|
+
**Every item the user provides MUST become a work item** (criterion or sub-task). Never silently filter items. If you believe an item should be deferred, **ASK the user** — do not decide autonomously.
|
|
14
|
+
|
|
15
|
+
For multi-item inputs, the command output MUST include: **"All {N} items captured as {criteria|sub-tasks}."** If any item cannot be mapped, the "Unmapped" warning must be surfaced, not suppressed.
|
|
16
|
+
|
|
17
|
+
This rule applies equally to deep-decomposition mode and flat stories.
|
|
18
|
+
|
|
19
|
+
## Specification-Quality Gates (wf-63c0f4cc)
|
|
20
|
+
|
|
21
|
+
Five P0 gates run automatically at creation time (all fail-open):
|
|
22
|
+
|
|
23
|
+
| Gate | Fires When | Effect |
|
|
24
|
+
|------|-----------|--------|
|
|
25
|
+
| 1. Long Input | input ≥40 lines OR ≥5 discrete items | routes to `/wogi-extract-review` |
|
|
26
|
+
| 2. Item Reconciliation | input has ≥3 discrete items | writes manifest, verifies coverage |
|
|
27
|
+
| 3. Consumer Impact | input contains refactor/rename/migrate/etc. | greps consumers, flags phased migration at ≥5 breaking |
|
|
28
|
+
| 4. Scope-Confidence | input mentions "new X" / "existing Y" / "the Z service" | audits assumptions → "Pending Clarifications" block |
|
|
29
|
+
| 5. Intent Bootstrap | IGR artifacts missing + not already scheduled | schedules background bootstrap via session-state.json |
|
|
30
|
+
|
|
31
|
+
Gates enforce **specification quality at creation time**; runtime-quality gates (wiring, typecheck, tests) remain `/wogi-start`'s job.
|
|
32
|
+
|
|
33
|
+
Config: `storyFlow.consumerImpactAnalysis`, `storyFlow.scopeConfidenceAudit`, `storyFlow.itemReconciliation`. All default-true.
|
|
34
|
+
|
|
11
35
|
## Options
|
|
12
36
|
|
|
13
37
|
- `--deep` - Enable deep decomposition mode (auto-generate granular sub-tasks)
|
|
14
38
|
- `--priority <P>` - Set priority P0-P4 (default: P2 from config)
|
|
15
39
|
- `--json` - Output JSON for programmatic access
|
|
40
|
+
- `--skip-gates` - Skip all P0 gates (testing/debug only)
|
|
41
|
+
- `--bypass-long-input` - Skip Gate 1 (set by `/wogi-start` when it already routed long input)
|
|
42
|
+
- `--full-input <txt>` - Full user input for gates (when title is a summary)
|
|
16
43
|
|
|
17
44
|
Examples:
|
|
18
45
|
```bash
|
|
@@ -408,6 +408,37 @@ await cancelTask('wf-123', 'superseded', false);
|
|
|
408
408
|
|
|
409
409
|
- **Hardened "Open in editor" against command injection**: Security hardening for untrusted filenames. **Impact on WogiFlow**: Validates the same pattern in `.claude/rules/security/security-patterns.md` — external inputs going into shell commands must be validated. No WogiFlow code change needed.
|
|
410
410
|
|
|
411
|
+
### Features in 2.1.111+
|
|
412
|
+
|
|
413
|
+
- **`xhigh` effort level for Opus 4.7**: New effort level sitting between `high` and `max`, available via `/effort`, `--effort`, and the model picker. Other models fall back to `high`. `/effort` now opens an interactive slider when called without arguments. **Impact on WogiFlow**: The effort-level mapping in `wogi-start.md` now acknowledges `xhigh`/`max` as Opus 4.7-only. For L0 epics running on Opus 4.7, users may prefer `xhigh` over `high` for deeper architectural reasoning — the mapping table documents this as an option. No code change needed; the mapping is advisory.
|
|
414
|
+
|
|
415
|
+
- **`/ultrareview` built-in command**: Claude Code now ships a native `/ultrareview` that runs parallel multi-agent analysis and critique in the cloud — invoke with no arguments to review the current branch, or `/ultrareview <PR#>` to fetch and review a specific GitHub PR. **Relationship to WogiFlow's review commands**: No collision (`wogi-*` prefix). How to choose:
|
|
416
|
+
- `/ultrareview` — cloud-side parallel multi-agent critique. Zero local setup. Best for standalone branch/PR reviews when you don't have peer models configured.
|
|
417
|
+
- `/wogi-peer-review` — uses the peer models you configured via `/wogi-models-setup` (local/BYO models). Best when you want specific perspectives (e.g., a different vendor's model) or offline/cost-controlled review.
|
|
418
|
+
- `/wogi-review` — single-reviewer code review wired into WogiFlow task state (findings logged to `last-review.json`, triaged via `/wogi-triage`). Best for in-flow review during task execution.
|
|
419
|
+
- `/wogi-review-fix` — auto-applies fixes from `/wogi-review` findings.
|
|
420
|
+
Users can combine them: run `/ultrareview` for a wide-angle cloud critique, then `/wogi-review` for task-linked findings.
|
|
421
|
+
|
|
422
|
+
- **`/less-permission-prompts` built-in skill**: Scans recent transcripts for common read-only Bash and MCP tool calls and proposes a prioritized allowlist for `.claude/settings.json`. **Relationship to WogiFlow**: Complementary to `computeLeanConfig()` in `lib/installer.js` — the installer produces a minimal allowlist at install time, while `/less-permission-prompts` tunes the allowlist based on actual session usage. Suggested workflow: after a few WogiFlow sessions, run `/less-permission-prompts` to prune redundant prompts. Future opportunity: surface this suggestion in `/wogi-health` output.
|
|
423
|
+
|
|
424
|
+
- **Auto-allow for read-only bash with globs and `cd <project-dir> &&` prefix**: Read-only commands like `ls *.ts` and commands starting with `cd <project-dir> &&` no longer trigger a permission prompt. **Impact on WogiFlow**: Reduces prompts during WogiFlow hook-driven validation (lint/typecheck) and user-driven exploration. Allowlist rules in `lib/installer.js` that duplicated these patterns are now redundant — minor cleanup opportunity (tracked, low priority). No action required; the installer's lean-config approach already avoids over-emitting.
|
|
425
|
+
|
|
426
|
+
- **Auto mode for Max subscribers on Opus 4.7**: Auto mode is now available for Max subscribers when using Opus 4.7, and no longer requires `--enable-auto-mode`. 2.1.112 fixed a "claude-opus-4-7 is temporarily unavailable" error in auto mode. **Impact on WogiFlow**: WogiFlow's model registry already lists Opus 4.7 (v2.22.0); auto-mode routing is orthogonal to WogiFlow's hybrid mode. Users on Max with Opus 4.7 benefit automatically.
|
|
427
|
+
|
|
428
|
+
- **`OTEL_LOG_RAW_API_BODIES` env var**: Emits full API request and response bodies as OpenTelemetry log events for debugging. **Impact on WogiFlow**: Useful when debugging hybrid mode (`/wogi-hybrid`) routing and peer-review (`/wogi-peer-review`) model calls — set this env var to see the exact payloads reaching each model. Complements WogiFlow's gate telemetry (`/wogi-gate-stats`) which tracks pass/catch/miss rates at a higher level. Set with: `export OTEL_LOG_RAW_API_BODIES=1`. Note: payloads may contain sensitive data — only enable in development.
|
|
429
|
+
|
|
430
|
+
- **Headless `--output-format stream-json` includes `plugin_errors` on init**: Plugin demotion errors (unsatisfied dependencies, conflicting versions) are now surfaced on the init event in headless mode. **WogiFlow opportunity**: `/wogi-health` could read this stream when running in CI/headless mode to flag plugin-registry issues before they cause silent failures. Tracked as an enhancement.
|
|
431
|
+
|
|
432
|
+
- **Opus 4.7 availability fix (2.1.112)**: Fixed a "claude-opus-4-7 is temporarily unavailable" error in auto mode. Aligned with WogiFlow v2.22.0 registry update. No WogiFlow code change needed.
|
|
433
|
+
|
|
434
|
+
- **Windows improvements**: `CLAUDE_ENV_FILE` and SessionStart hook environment files now apply on Windows (previously a no-op). Permission rules with drive-letter paths are now correctly root-anchored, and paths differing only by drive-letter case are recognized as the same path. **Impact on WogiFlow**: Windows users of WogiFlow's SessionStart hook can now configure environment variables via `CLAUDE_ENV_FILE`. Drive-letter-path permission rules generated by the installer now behave correctly. Automatic improvement after upgrade.
|
|
435
|
+
|
|
436
|
+
- **Miscellaneous UX**: Plan files named after the originating prompt (e.g. `fix-auth-race-snug-otter.md`), `/skills` menu supports sorting by estimated token count (press `t`), Ctrl+U clears the entire input buffer (Ctrl+Y restores), Ctrl+L forces a full redraw, and typo suggestions on near-miss subcommands. Documentation-only for WogiFlow.
|
|
437
|
+
|
|
438
|
+
- **Fixed "Unknown skill: commit" error**: Users without a custom `/commit` skill were seeing this error when Claude Code tried to invoke a non-existent built-in. **Impact on WogiFlow**: No WogiFlow-shipped `/commit` skill (commits go through `/wogi-finalize` and git commit instructions). Users benefit passively from the fix.
|
|
439
|
+
|
|
440
|
+
- **Reliability fixes (all automatic after upgrade)**: Terminal display tearing in iTerm2+tmux, `@`-file suggestions re-scanning entire project in non-git directories, LSP diagnostics from before an edit appearing after it, tab-completing `/resume` behavior, `/context` grid rendering, `/clear` dropping session name, spurious decompression/network/transient errors in the TUI. Reverted v2.1.110 cap on non-streaming fallback retries (now uncapped again). Fixed Bedrock/Vertex/Foundry 429 retries pointing users at the wrong status page, bare URLs unclickable when wrapped in tool output, feedback surveys appearing back-to-back. WogiFlow sessions benefit from all of these automatically.
|
|
441
|
+
|
|
411
442
|
### Simple Mode Naming Distinction
|
|
412
443
|
|
|
413
444
|
Claude Code's `CLAUDE_CODE_SIMPLE` environment variable (which enables a simplified tool set) is **unrelated** to WogiFlow's `loops.simpleMode` (a lightweight task completion loop using string detection). They are separate features that happen to share the word "simple":
|
|
@@ -542,4 +573,4 @@ Run `/keybindings` in Claude Code to customize your shortcuts.
|
|
|
542
573
|
|
|
543
574
|
---
|
|
544
575
|
|
|
545
|
-
*Last updated: 2026-04-
|
|
576
|
+
*Last updated: 2026-04-17*
|
|
@@ -75,7 +75,7 @@ Don't confuse them. `agents/security.md` (persona) is different from `.workflow/
|
|
|
75
75
|
|
|
76
76
|
When modifying flow-*.js scripts:
|
|
77
77
|
- Run `node --check scripts/<file>.js` after edits
|
|
78
|
-
- WogiFlow has
|
|
78
|
+
- Run `npm test` — WogiFlow has a native-Node test suite (50+ files under `tests/`, 1800+ assertions) covering hooks, flow-io, security, session state, workspace gates, and more
|
|
79
79
|
- Check for circular dependencies when moving shared functions
|
|
80
80
|
|
|
81
81
|
## 8. Feature Refactoring Cleanup
|
package/.claude/settings.json
CHANGED
|
@@ -170,6 +170,6 @@
|
|
|
170
170
|
},
|
|
171
171
|
"_comment_dynamicHooks": "TaskCreated (2.1.84+) and PermissionDenied (2.1.88+) are added by postinstall.js when the CC version supports them. They must NOT be committed statically — CC rejects the entire settings file if it encounters an unknown hook event name.",
|
|
172
172
|
"_wogiFlowManaged": true,
|
|
173
|
-
"_wogiFlowVersion": "2.
|
|
173
|
+
"_wogiFlowVersion": "2.22.0",
|
|
174
174
|
"_comment": "Shared WogiFlow hook configuration. Committed to repo for team use. User-specific overrides go in settings.local.json."
|
|
175
175
|
}
|
package/lib/commands/login.js
CHANGED
package/lib/installer.js
CHANGED
|
@@ -194,7 +194,7 @@ function detectProjectScripts(projectRoot) {
|
|
|
194
194
|
let pkgData;
|
|
195
195
|
try {
|
|
196
196
|
pkgData = safeReadJson(packageJsonPath);
|
|
197
|
-
} catch (
|
|
197
|
+
} catch (_err) {
|
|
198
198
|
return detected;
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -989,7 +989,7 @@ async function init(args) {
|
|
|
989
989
|
try {
|
|
990
990
|
const analyzer = require('../scripts/flow-project-analyzer');
|
|
991
991
|
detection = analyzer.detectProjectType(projectRoot);
|
|
992
|
-
} catch (
|
|
992
|
+
} catch (_err) {
|
|
993
993
|
// Fallback: use basic projectType from installer's own detection
|
|
994
994
|
detection = {
|
|
995
995
|
projectType: config.projectType || 'unknown',
|
|
@@ -1030,7 +1030,7 @@ async function init(args) {
|
|
|
1030
1030
|
// Non-fatal — profile can be generated later via /wogi-test
|
|
1031
1031
|
}
|
|
1032
1032
|
}
|
|
1033
|
-
} catch (
|
|
1033
|
+
} catch (_err) {
|
|
1034
1034
|
// Non-fatal — flow-verification-profile may not exist yet during initial install
|
|
1035
1035
|
}
|
|
1036
1036
|
|
|
@@ -1083,7 +1083,7 @@ function updateManifestAfterInit(cliDir) {
|
|
|
1083
1083
|
if (!manifest || !Array.isArray(manifest.files)) {
|
|
1084
1084
|
manifest = { version: 1, files: [], directories: ['.workflow'] };
|
|
1085
1085
|
}
|
|
1086
|
-
} catch (
|
|
1086
|
+
} catch (_err) {
|
|
1087
1087
|
// No manifest yet — create a fresh one
|
|
1088
1088
|
manifest = { version: 1, files: [], directories: ['.workflow'] };
|
|
1089
1089
|
}
|
|
@@ -1129,7 +1129,7 @@ function walkDirForManifest(dir, baseDir, fileSet) {
|
|
|
1129
1129
|
fileSet.add(path.relative(baseDir, fullPath));
|
|
1130
1130
|
}
|
|
1131
1131
|
}
|
|
1132
|
-
} catch (
|
|
1132
|
+
} catch (_err) {
|
|
1133
1133
|
// Non-critical — skip unreadable dirs
|
|
1134
1134
|
}
|
|
1135
1135
|
}
|
package/lib/release-channel.js
CHANGED
|
@@ -128,7 +128,7 @@ async function getLatestVersion(channel) {
|
|
|
128
128
|
// Get version for the channel's npm tag
|
|
129
129
|
const distTags = pkg['dist-tags'] || {};
|
|
130
130
|
return distTags[channelConfig.npmTag] || distTags.latest || pkg.version;
|
|
131
|
-
} catch (
|
|
131
|
+
} catch (_err) {
|
|
132
132
|
return null;
|
|
133
133
|
}
|
|
134
134
|
}
|
package/lib/skill-registry.js
CHANGED
|
@@ -154,7 +154,7 @@ async function fetchSkillIndex(projectRoot) {
|
|
|
154
154
|
throw new Error('Invalid index data');
|
|
155
155
|
}
|
|
156
156
|
return parsed;
|
|
157
|
-
} catch (
|
|
157
|
+
} catch (_err) {
|
|
158
158
|
// Return mock index for development/offline
|
|
159
159
|
return {
|
|
160
160
|
version: '1.0',
|
|
@@ -201,7 +201,7 @@ async function fetchSkillManifest(skillName, projectRoot) {
|
|
|
201
201
|
throw new Error('Invalid manifest data');
|
|
202
202
|
}
|
|
203
203
|
return parsed;
|
|
204
|
-
} catch (
|
|
204
|
+
} catch (_err) {
|
|
205
205
|
throw new Error(`Skill '${skillName}' not found in registry`);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
@@ -213,7 +213,7 @@ async function fetchSkillManifest(skillName, projectRoot) {
|
|
|
213
213
|
* @param {string} projectRoot - Project root directory
|
|
214
214
|
* @returns {Promise<Object>} Downloaded files
|
|
215
215
|
*/
|
|
216
|
-
async function downloadSkillFiles(skillName, manifest,
|
|
216
|
+
async function downloadSkillFiles(skillName, manifest, _projectRoot) {
|
|
217
217
|
const files = {};
|
|
218
218
|
const baseUrl = `${REGISTRY_CONFIG.baseUrl}/${REGISTRY_CONFIG.branch}/skills/${skillName}`;
|
|
219
219
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Workspace — Dispatch Tracking (wf-d3e67abe)
|
|
5
|
+
*
|
|
6
|
+
* Silent-worker-halt detection via file-based dispatch records.
|
|
7
|
+
*
|
|
8
|
+
* Manager records every dispatch; any pending dispatch past its
|
|
9
|
+
* expectedDeadline without a matching completion/stop message =
|
|
10
|
+
* silent death. Surfaced on the next manager turn via the
|
|
11
|
+
* UserPromptSubmit hook (no background processes).
|
|
12
|
+
*
|
|
13
|
+
* State file: .workspace/state/dispatched-tasks.json
|
|
14
|
+
* Ring buffer of last MAX_ACTIVE records; older overflow to
|
|
15
|
+
* .workspace/state/dispatched-tasks.archive.jsonl (append-only).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('node:fs');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
const { safeReadJson } = require('./utils');
|
|
21
|
+
|
|
22
|
+
const DEFAULT_DURATION_MS = 30 * 60 * 1000; // 30 min — matches waitForCompletion default
|
|
23
|
+
const MAX_ACTIVE = 100;
|
|
24
|
+
const SCHEMA_VERSION = 1;
|
|
25
|
+
|
|
26
|
+
const VALID_STATUSES = new Set(['pending', 'completed', 'graceful-stop', 'silent-halt']);
|
|
27
|
+
|
|
28
|
+
function stateFilePath(workspaceRoot) {
|
|
29
|
+
return path.join(workspaceRoot, '.workspace', 'state', 'dispatched-tasks.json');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function archiveFilePath(workspaceRoot) {
|
|
33
|
+
return path.join(workspaceRoot, '.workspace', 'state', 'dispatched-tasks.archive.jsonl');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function loadState(workspaceRoot) {
|
|
37
|
+
const data = safeReadJson(stateFilePath(workspaceRoot), null);
|
|
38
|
+
if (data && typeof data === 'object' && Array.isArray(data.dispatches)) {
|
|
39
|
+
return { version: data.version || SCHEMA_VERSION, dispatches: data.dispatches };
|
|
40
|
+
}
|
|
41
|
+
return { version: SCHEMA_VERSION, dispatches: [] };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function saveState(workspaceRoot, state) {
|
|
45
|
+
const filePath = stateFilePath(workspaceRoot);
|
|
46
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
47
|
+
fs.writeFileSync(filePath, JSON.stringify(state, null, 2));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function archiveRecord(workspaceRoot, record) {
|
|
51
|
+
const filePath = archiveFilePath(workspaceRoot);
|
|
52
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
53
|
+
fs.appendFileSync(filePath, JSON.stringify(record) + '\n');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Record a dispatch. Appends to state and trims ring buffer.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} workspaceRoot
|
|
60
|
+
* @param {Object} params
|
|
61
|
+
* @param {string} params.taskId - wf-XXXXXXXX
|
|
62
|
+
* @param {string} params.repoName
|
|
63
|
+
* @param {number} [params.expectedDurationMs=DEFAULT_DURATION_MS]
|
|
64
|
+
* @param {string} [params.dispatchedBy='manager']
|
|
65
|
+
* @returns {Object} the created record
|
|
66
|
+
*/
|
|
67
|
+
function recordDispatch(workspaceRoot, { taskId, repoName, expectedDurationMs, dispatchedBy }) {
|
|
68
|
+
if (!workspaceRoot || typeof workspaceRoot !== 'string') {
|
|
69
|
+
throw new Error('workspaceRoot required');
|
|
70
|
+
}
|
|
71
|
+
if (!/^wf-[0-9a-f]{8}$/i.test(taskId || '')) {
|
|
72
|
+
throw new Error(`Invalid taskId: ${taskId}`);
|
|
73
|
+
}
|
|
74
|
+
if (!repoName || typeof repoName !== 'string') {
|
|
75
|
+
throw new Error('repoName required');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const durationMs = Number.isFinite(expectedDurationMs) && expectedDurationMs > 0
|
|
79
|
+
? expectedDurationMs
|
|
80
|
+
: DEFAULT_DURATION_MS;
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
const dispatchedAt = new Date(now).toISOString();
|
|
83
|
+
const expectedDeadline = new Date(now + durationMs).toISOString();
|
|
84
|
+
|
|
85
|
+
const record = {
|
|
86
|
+
taskId,
|
|
87
|
+
repoName,
|
|
88
|
+
dispatchedAt,
|
|
89
|
+
expectedDeadline,
|
|
90
|
+
expectedDurationMs: durationMs,
|
|
91
|
+
status: 'pending',
|
|
92
|
+
dispatchedBy: dispatchedBy || 'manager',
|
|
93
|
+
reconciledAt: null,
|
|
94
|
+
reconciledReason: null
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const state = loadState(workspaceRoot);
|
|
98
|
+
state.dispatches.push(record);
|
|
99
|
+
|
|
100
|
+
// Ring buffer: overflow oldest records to archive
|
|
101
|
+
while (state.dispatches.length > MAX_ACTIVE) {
|
|
102
|
+
const overflow = state.dispatches.shift();
|
|
103
|
+
try { archiveRecord(workspaceRoot, overflow); }
|
|
104
|
+
catch (_err) { /* non-fatal — archive is best-effort */ }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
saveState(workspaceRoot, state);
|
|
108
|
+
return record;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Reconcile the most recent pending record for a task.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} workspaceRoot
|
|
115
|
+
* @param {string} taskId
|
|
116
|
+
* @param {string} status - 'completed' | 'graceful-stop' | 'silent-halt'
|
|
117
|
+
* @param {string} [reason]
|
|
118
|
+
* @returns {Object|null} updated record, or null if not found
|
|
119
|
+
*/
|
|
120
|
+
function reconcileDispatch(workspaceRoot, taskId, status, reason) {
|
|
121
|
+
if (!VALID_STATUSES.has(status) || status === 'pending') {
|
|
122
|
+
throw new Error(`Invalid reconcile status: ${status}`);
|
|
123
|
+
}
|
|
124
|
+
const state = loadState(workspaceRoot);
|
|
125
|
+
// Find most recent pending record for this taskId (last wins — most recent dispatch)
|
|
126
|
+
for (let i = state.dispatches.length - 1; i >= 0; i--) {
|
|
127
|
+
const r = state.dispatches[i];
|
|
128
|
+
if (r && r.taskId === taskId && r.status === 'pending') {
|
|
129
|
+
r.status = status;
|
|
130
|
+
r.reconciledAt = new Date().toISOString();
|
|
131
|
+
r.reconciledReason = reason || null;
|
|
132
|
+
saveState(workspaceRoot, state);
|
|
133
|
+
return r;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Read all currently-active dispatch records (not archived).
|
|
141
|
+
*
|
|
142
|
+
* @param {string} workspaceRoot
|
|
143
|
+
* @returns {Array<Object>}
|
|
144
|
+
*/
|
|
145
|
+
function readDispatches(workspaceRoot) {
|
|
146
|
+
return loadState(workspaceRoot).dispatches;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get dispatches whose expectedDeadline has passed and are still pending.
|
|
151
|
+
*
|
|
152
|
+
* @param {string} workspaceRoot
|
|
153
|
+
* @param {number} [now=Date.now()]
|
|
154
|
+
* @returns {Array<Object>} overdue records
|
|
155
|
+
*/
|
|
156
|
+
function getOverdueDispatches(workspaceRoot, now) {
|
|
157
|
+
const ts = Number.isFinite(now) ? now : Date.now();
|
|
158
|
+
const dispatches = readDispatches(workspaceRoot);
|
|
159
|
+
return dispatches.filter(r => {
|
|
160
|
+
if (!r || r.status !== 'pending') return false;
|
|
161
|
+
const deadline = Date.parse(r.expectedDeadline || '');
|
|
162
|
+
return Number.isFinite(deadline) && deadline < ts;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = {
|
|
167
|
+
DEFAULT_DURATION_MS,
|
|
168
|
+
MAX_ACTIVE,
|
|
169
|
+
recordDispatch,
|
|
170
|
+
reconcileDispatch,
|
|
171
|
+
readDispatches,
|
|
172
|
+
getOverdueDispatches,
|
|
173
|
+
stateFilePath,
|
|
174
|
+
archiveFilePath
|
|
175
|
+
};
|
package/lib/workspace-events.js
CHANGED
|
@@ -46,7 +46,7 @@ const EVENT_TYPES = [
|
|
|
46
46
|
|
|
47
47
|
const EVENTS_FILE = 'events.json';
|
|
48
48
|
const MAX_EVENTS = 500; // Keep last 500 events
|
|
49
|
-
const
|
|
49
|
+
const _EVENT_ID_PATTERN = /^evt-[a-f0-9]{8}$/;
|
|
50
50
|
|
|
51
51
|
// ============================================================
|
|
52
52
|
// Event Creation
|
package/lib/workspace-gates.js
CHANGED
|
@@ -470,7 +470,7 @@ function broadcastPostChange(workspaceRoot, fromRepo, context, options = {}) {
|
|
|
470
470
|
* @param {Object} taskMeta
|
|
471
471
|
* @returns {{ passed: boolean, message: string, severity: string }}
|
|
472
472
|
*/
|
|
473
|
-
function gateDeploymentReadiness(workspaceRoot,
|
|
473
|
+
function gateDeploymentReadiness(workspaceRoot, _context, taskMeta) {
|
|
474
474
|
const { execFileSync } = require('node:child_process');
|
|
475
475
|
|
|
476
476
|
try {
|
|
@@ -668,7 +668,7 @@ function gatePeerNotification(workspaceRoot, context, taskMeta) {
|
|
|
668
668
|
* Gate: cascadeVerification
|
|
669
669
|
* For library repos, verify all consumers were notified.
|
|
670
670
|
*/
|
|
671
|
-
function gateCascadeVerification(workspaceRoot, context,
|
|
671
|
+
function gateCascadeVerification(workspaceRoot, context, _taskMeta) {
|
|
672
672
|
const gate = WORKSPACE_GATES.find(g => g.name === 'cascadeVerification');
|
|
673
673
|
|
|
674
674
|
if (!context.currentMember || context.currentMember.role !== 'library') {
|
|
@@ -694,7 +694,7 @@ function analyzeReviewForCrossRepoImpact(workspaceRoot, manifest, changedFiles,
|
|
|
694
694
|
result.endpointChanges = changedApiFiles;
|
|
695
695
|
|
|
696
696
|
// Check if contract was also updated
|
|
697
|
-
const
|
|
697
|
+
const _contractsDir = path.join(workspaceRoot, '.workspace', 'contracts');
|
|
698
698
|
const contractFiles = changedFiles.filter(f => f.includes('.workspace/contracts'));
|
|
699
699
|
|
|
700
700
|
if (contractFiles.length === 0 && changedApiFiles.length > 0) {
|
|
@@ -22,6 +22,7 @@ const MESSAGE_TYPES = [
|
|
|
22
22
|
'question', // "Does your side handle X?"
|
|
23
23
|
'bug-report', // "Your endpoint returns 500 when I send Y"
|
|
24
24
|
'task-complete', // "I finished my side of feature Z"
|
|
25
|
+
'worker-stopped', // Graceful Stop hook — worker session ending, not necessarily at task completion
|
|
25
26
|
'needs-help', // "I'm stuck, can you check X on your side?"
|
|
26
27
|
'heads-up', // "I'm about to change Y, just FYI"
|
|
27
28
|
'impact-query', // Pre-dev: "I'm about to change X, will this break you?"
|
package/lib/workspace-routing.js
CHANGED
|
@@ -344,7 +344,7 @@ function generateParallelInvestigation(workspaceRoot, bugDescription, manifest)
|
|
|
344
344
|
const investigators = [];
|
|
345
345
|
|
|
346
346
|
for (const [name, member] of Object.entries(manifest.members)) {
|
|
347
|
-
const
|
|
347
|
+
const _repoPath = path.resolve(workspaceRoot, member.path);
|
|
348
348
|
|
|
349
349
|
investigators.push({
|
|
350
350
|
repoName: name,
|
|
@@ -700,6 +700,8 @@ function checkWorkerHealth(port) {
|
|
|
700
700
|
* @param {string} taskId — task ID to start
|
|
701
701
|
* @param {Object} [opts] — dispatch options
|
|
702
702
|
* @param {string} [opts.effortLevel] — reasoning effort to propagate ('low'|'medium'|'high')
|
|
703
|
+
* @param {number} [opts.expectedDurationMs] — override deadline for silent-halt detection
|
|
704
|
+
* (wf-d3e67abe). Defaults to DEFAULT_DURATION_MS from workspace-dispatch-tracking.
|
|
703
705
|
* @returns {Promise<{ ok: boolean, message: string }>}
|
|
704
706
|
*/
|
|
705
707
|
async function dispatchToChannel(workspaceRoot, repoName, taskId, opts = {}) {
|
|
@@ -739,6 +741,21 @@ async function dispatchToChannel(workspaceRoot, repoName, taskId, opts = {}) {
|
|
|
739
741
|
const dispatchBody = `${effortPrefix}/wogi-start ${taskId}`;
|
|
740
742
|
const result = await httpPost('127.0.0.1', port, dispatchBody);
|
|
741
743
|
if (result.ok) {
|
|
744
|
+
// wf-d3e67abe — record dispatch for silent-halt detection.
|
|
745
|
+
// Fail-open: if tracking write fails, dispatch itself still succeeds.
|
|
746
|
+
try {
|
|
747
|
+
const { recordDispatch } = require('./workspace-dispatch-tracking');
|
|
748
|
+
recordDispatch(workspaceRoot, {
|
|
749
|
+
taskId,
|
|
750
|
+
repoName,
|
|
751
|
+
expectedDurationMs: opts.expectedDurationMs,
|
|
752
|
+
dispatchedBy: process.env.WOGI_REPO_NAME || 'manager'
|
|
753
|
+
});
|
|
754
|
+
} catch (err) {
|
|
755
|
+
if (process.env.DEBUG) {
|
|
756
|
+
console.error(`[dispatchToChannel] Dispatch tracking failed (non-fatal): ${err.message}`);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
742
759
|
return { ok: true, message: `Dispatched /wogi-start ${taskId} to ${repoName} (port ${port})${effortLevel ? ` [effort: ${effortLevel}]` : ''}` };
|
|
743
760
|
}
|
|
744
761
|
|