wogiflow 2.32.0 → 2.34.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.
Files changed (39) hide show
  1. package/.claude/docs/claude-code-compatibility.md +51 -0
  2. package/.claude/docs/scheduled-mode.md +213 -0
  3. package/.claude/docs/skill-portability.md +190 -0
  4. package/.claude/rules/alternative-hook-args-exec-form.md +6 -0
  5. package/.claude/settings.json +2 -1
  6. package/.claude/skills/_template/skill.md +1 -0
  7. package/.claude/skills/conventional-commit/knowledge/examples.md +65 -0
  8. package/.claude/skills/conventional-commit/skill.md +76 -0
  9. package/bin/flow +16 -0
  10. package/lib/scheduled-mode.js +374 -0
  11. package/lib/skill-export-agentskills.js +211 -0
  12. package/lib/skill-export-claude-plugin.js +183 -0
  13. package/lib/skill-portability.js +342 -0
  14. package/lib/skill-registry.js +32 -2
  15. package/lib/workspace-channel-server.js +106 -3
  16. package/lib/workspace-channel-tracking.js +102 -1
  17. package/lib/workspace-dispatch-tracking.js +28 -0
  18. package/lib/workspace-messages.js +32 -4
  19. package/lib/workspace-subtask-state.js +215 -0
  20. package/lib/workspace.js +81 -0
  21. package/package.json +2 -2
  22. package/scripts/flow +25 -0
  23. package/scripts/flow-config-defaults.js +20 -0
  24. package/scripts/flow-constants.js +3 -1
  25. package/scripts/flow-schedule.js +486 -0
  26. package/scripts/flow-scheduled-runner.js +659 -0
  27. package/scripts/flow-skill-export.js +334 -0
  28. package/scripts/flow-standards-checker.js +37 -0
  29. package/scripts/hooks/adapters/claude-code.js +18 -3
  30. package/scripts/hooks/core/git-safety-gate.js +118 -27
  31. package/scripts/hooks/core/long-input-enforcement.js +139 -4
  32. package/scripts/hooks/core/overdue-dispatches.js +28 -6
  33. package/scripts/hooks/core/session-start-worker.js +52 -0
  34. package/scripts/hooks/core/stop-orchestrator.js +17 -2
  35. package/scripts/hooks/core/validation.js +8 -0
  36. package/scripts/hooks/core/worker-continuation-gate.js +326 -0
  37. package/scripts/hooks/core/workspace-stop-gates.js +21 -0
  38. package/scripts/hooks/core/workspace-stop-notify.js +174 -59
  39. package/scripts/hooks/entry/claude-code/post-tool-use.js +26 -0
package/lib/workspace.js CHANGED
@@ -1209,6 +1209,18 @@ You are a workspace worker. There is NO human watching your terminal. You MUST o
1209
1209
 
1210
1210
  The \`TaskCompleted\` hook will inject an auto-pickup directive when channel dispatches are queued (v2.20.0+). The \`Stop\` hook will BLOCK end-of-turn if you try to stop while dispatches are queued and no task is in progress. These enforcements exist because the silent-stall pattern was incident-worthy (2026-04-16).
1211
1211
 
1212
+ ### Sustained Execution — Grind a Dispatched Task to Completion (v2.34.0+)
1213
+
1214
+ **A dispatched task runs to COMPLETION across turns. Do NOT stop to "report progress" after each sub-task.** When you decompose a task into sub-tasks (TodoWrite), work through ALL of them in the same session — the decomposition is mirrored to durable state (\`subtask-state.json\`) so it survives turn boundaries.
1215
+
1216
+ "The work" in *"reply to the manager after completing the work"* means the **entire dispatched task** (all its sub-tasks), not one increment. Reply with \`## Results\` ONLY when:
1217
+ - the task is **complete** (you ran \`flow done <id>\` and it left inProgress), or
1218
+ - you are **escalating** a genuine blocker (\`## QUESTION:\` / \`## BLOCKED:\`).
1219
+
1220
+ The \`Stop\` hook's **in-progress continuation gate** will force you to keep going (\`{continue:true}\`) while a task is in-progress in the coding/validating phase with sub-tasks remaining. If you stop early to "give visibility," it will re-prompt you to continue. Make real progress every turn (an edit, a test, a completed sub-task) — idle turns with no file changes are detected across a few continuations and stop with an escalation.
1221
+
1222
+ **Escalate instead of proceeding** when the next step is destructive, irreversible, touches production, needs external credentials, or genuinely needs a human decision. Otherwise: keep grinding until done.
1223
+
1212
1224
  ### Tool-First Turn Contract (v2.27.0+)
1213
1225
 
1214
1226
  **Every worker turn after a UserPromptSubmit MUST contain at least one tool call. In strict mode (default), the FIRST content block must be a tool call, not text.**
@@ -1768,6 +1780,61 @@ function startWorkerSession(cwd) {
1768
1780
  * Handle workspace subcommands
1769
1781
  * @param {string[]} args
1770
1782
  */
1783
+ /**
1784
+ * S5 (wf-ee87a24e): manager-triggered worker restart. Resolves the worker's
1785
+ * channel port from the workspace config and POSTs /restart. The worker's
1786
+ * channel server writes the wrapper restart flag and SIGTERMs claude, so the
1787
+ * wogi-claude wrapper relaunches it with a fresh require cache (reloading any
1788
+ * upgraded wogiflow code). Resume of the in-progress task is handled by the
1789
+ * worker's SessionStart hook (resume-in-progress branch).
1790
+ */
1791
+ async function restartWorkerSession(cwd, workerName) {
1792
+ // Find workspace root
1793
+ let workspaceRoot = null;
1794
+ let dir = cwd;
1795
+ while (dir !== path.dirname(dir)) {
1796
+ if (fs.existsSync(path.join(dir, WORKSPACE_CONFIG_FILE))) { workspaceRoot = dir; break; }
1797
+ dir = path.dirname(dir);
1798
+ }
1799
+ if (!workspaceRoot) {
1800
+ console.error('Error: Not inside a workspace (no wogi-workspace.json found).');
1801
+ process.exit(1);
1802
+ }
1803
+ const config = safeJsonParse(path.join(workspaceRoot, WORKSPACE_CONFIG_FILE), null);
1804
+ const member = config?.channels?.members?.[workerName];
1805
+ if (!member || !member.port) {
1806
+ console.error(`Error: unknown worker "${workerName}". Known workers: ${Object.keys(config?.channels?.members || {}).join(', ') || '(none)'}`);
1807
+ process.exit(1);
1808
+ }
1809
+
1810
+ const http = require('node:http');
1811
+ const result = await new Promise((resolve) => {
1812
+ const req = http.request({
1813
+ hostname: '127.0.0.1', port: member.port, path: '/restart', method: 'POST',
1814
+ headers: { 'X-Wogi-From': 'manager', 'Content-Length': 0 }, timeout: 5000
1815
+ }, (res) => {
1816
+ let data = '';
1817
+ res.on('data', c => { data += c; });
1818
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
1819
+ });
1820
+ req.on('error', (err) => resolve({ error: err.message }));
1821
+ req.on('timeout', () => { req.destroy(); resolve({ error: 'timeout' }); });
1822
+ req.end();
1823
+ });
1824
+
1825
+ if (result.error) {
1826
+ console.error(`✗ Could not reach worker "${workerName}" on port ${member.port}: ${result.error}`);
1827
+ console.error(` Is the worker running? Start it with: cd ${member.path || workerName} && flow workspace start`);
1828
+ process.exit(1);
1829
+ }
1830
+ if (result.status === 202) {
1831
+ console.log(`✓ Restart signalled to "${workerName}" (port ${member.port}). The worker will relaunch with fresh code and resume its in-progress task.`);
1832
+ } else {
1833
+ console.error(`✗ Worker "${workerName}" returned HTTP ${result.status}: ${result.body}`);
1834
+ process.exit(1);
1835
+ }
1836
+ }
1837
+
1771
1838
  async function workspace(args) {
1772
1839
  const subcommand = args[0];
1773
1840
 
@@ -1816,6 +1883,18 @@ async function workspace(args) {
1816
1883
  startWorkerSession(process.cwd());
1817
1884
  break;
1818
1885
  }
1886
+ case 'restart': {
1887
+ // S5 (wf-ee87a24e): cycle a worker session so it reloads upgraded code.
1888
+ // POSTs /restart to the worker's channel; the channel server writes the
1889
+ // wrapper flag and SIGTERMs claude → wogi-claude relaunches it fresh.
1890
+ const workerName = args[1];
1891
+ if (!workerName) {
1892
+ console.error('Usage: flow workspace restart <worker>');
1893
+ process.exit(1);
1894
+ }
1895
+ await restartWorkerSession(process.cwd(), workerName);
1896
+ break;
1897
+ }
1819
1898
  default:
1820
1899
  console.log(`
1821
1900
  Wogi Workspace — Multi-Repo Orchestration
@@ -1829,12 +1908,14 @@ Commands:
1829
1908
  add Add a member repo to the workspace
1830
1909
  remove Remove a member repo from the workspace
1831
1910
  start Start a worker session with channel (run from a member repo)
1911
+ restart Cycle a worker session so it reloads upgraded code + resumes its task
1832
1912
 
1833
1913
  Examples:
1834
1914
  flow workspace init # Create workspace from subdirectories
1835
1915
  flow workspace sync # Refresh after external changes
1836
1916
  flow workspace status # Show all repos, tasks, contracts
1837
1917
  cd frontend/ && flow workspace start # Start worker session
1918
+ flow workspace restart backend # Restart the 'backend' worker (after npm upgrade)
1838
1919
  `);
1839
1920
  }
1840
1921
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wogiflow",
3
- "version": "2.32.0",
3
+ "version": "2.34.1",
4
4
  "description": "AI-powered development workflow management system with multi-model support",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "scripts": {
12
12
  "flow": "./scripts/flow",
13
- "test": "NODE_ENV=test node --test tests/auto-compact-prompt.test.js tests/flow-paths.test.js tests/flow-io.test.js tests/flow-audit-gates.test.js tests/flow-standards-hook-three-layer.test.js tests/flow-correction-detector-reconcile.test.js tests/flow-correction-backfill.test.js tests/flow-audit-gates-feature-output-health.test.js tests/flow-config-loader.test.js tests/flow-damage-control.test.js tests/flow-output.test.js tests/flow-constants.test.js tests/flow-session-state.test.js tests/flow-hooks-integration.test.js tests/flow-utils.test.js tests/flow-security.test.js tests/flow-memory-db.test.js tests/flow-durable-session.test.js tests/flow-skill-matcher.test.js tests/flow-bridge.test.js tests/flow-proactive-compact.test.js tests/flow-cascade-completion.test.js tests/flow-capture-gate.test.js tests/flow-correction-detector-hybrid.test.js tests/flow-promote.test.js tests/flow-archive-runs.test.js tests/flow-memory.test.js tests/flow-hooks-pre-tool-helpers.test.js tests/flow-hooks-bugfix-scope-gate.test.js tests/flow-hooks-routing-gate.test.js tests/flow-hooks-phase-read-gate.test.js tests/flow-hooks-commit-log-gate.test.js tests/flow-hooks-deploy-gate.test.js tests/flow-hooks-todowrite-gate.test.js tests/flow-hooks-git-safety-gate.test.js tests/flow-hooks-scope-mutation-gate.test.js tests/flow-hooks-strike-gate.test.js tests/flow-hooks-component-check.test.js tests/flow-hooks-scope-gate.test.js tests/flow-hooks-implementation-gate.test.js tests/flow-hooks-research-gate.test.js tests/flow-hooks-loop-check.test.js tests/flow-hooks-manager-boundary-gate.test.js tests/flow-hooks-phase-gate.test.js tests/flow-hooks-pre-tool-orchestrator.test.js tests/flow-hooks-observation-capture.test.js tests/flow-hooks-task-gate.test.js tests/flow-durable-session-suspension.test.js tests/flow-health-mcp-scopes.test.js tests/flow-lean-config.test.js tests/flow-workspace-autopickup.test.js tests/flow-worker-boundary-gate.test.js tests/flow-worker-question-classifier.test.js tests/flow-completion-truth-gate-contradictions.test.js tests/flow-structure-sensor.test.js tests/flow-workspace-dispatch-tracking.test.js tests/workspace-ipc-sqlite.test.js tests/workspace-ipc-multi-worker.test.js tests/flow-story-gates.test.js tests/flow-workspace-restart-handoff.test.js tests/flow-wogi-claude-wrapper.test.js tests/flow-wave1-integrations.test.js tests/flow-wave2-integrations.test.js tests/flow-wave3-integrations.test.js tests/flow-commit-claims-gate.test.js tests/auto-review.test.js tests/gate-telemetry-surface.test.js tests/agents-md-alias.test.js tests/flow-skill-manage.test.js tests/fuzzy-patch.test.js tests/mode-schema.test.js tests/flow-feature-dossier.test.js tests/flow-autonomous-mode.test.js tests/flow-epic-cascade.test.js tests/flow-workspace-summary.test.js tests/flow-hooks-research-evidence-gate.test.js tests/flow-worker-mcp-strip.test.js tests/flow-orchestrate-corrections.test.js tests/flow-source-fidelity.test.js tests/flow-hooks-long-input-enforcement.test.js tests/workspace-channel-tracking.test.js tests/flow-hooks-deletion-log.test.js tests/flow-task-boundary-reset.test.js tests/flow-deferral-gate.test.js tests/flow-research-required-gate.test.js tests/flow-standards-forbidden-patterns.test.js tests/flow-hooks-architect-required-gate.test.js tests/flow-architect-runs.test.js tests/flow-installer-forbidden-patterns.test.js tests/flow-deferral-classifier-ai.test.js tests/flow-no-defer-policy.test.js tests/flow-self-adversary-loop.test.js tests/flow-impl-question-classifier.test.js tests/flow-hooks-self-adversary-gate.test.js && NODE_ENV=test node tests/run-quality-gates.test.js",
13
+ "test": "NODE_ENV=test node --test tests/auto-compact-prompt.test.js tests/flow-paths.test.js tests/flow-io.test.js tests/flow-audit-gates.test.js tests/flow-standards-hook-three-layer.test.js tests/flow-correction-detector-reconcile.test.js tests/flow-correction-backfill.test.js tests/flow-audit-gates-feature-output-health.test.js tests/flow-config-loader.test.js tests/flow-damage-control.test.js tests/flow-output.test.js tests/flow-constants.test.js tests/flow-session-state.test.js tests/flow-hooks-integration.test.js tests/flow-utils.test.js tests/flow-security.test.js tests/flow-memory-db.test.js tests/flow-durable-session.test.js tests/flow-skill-matcher.test.js tests/flow-bridge.test.js tests/flow-proactive-compact.test.js tests/flow-cascade-completion.test.js tests/flow-capture-gate.test.js tests/flow-correction-detector-hybrid.test.js tests/flow-promote.test.js tests/flow-archive-runs.test.js tests/flow-memory.test.js tests/flow-hooks-pre-tool-helpers.test.js tests/flow-hooks-bugfix-scope-gate.test.js tests/flow-hooks-routing-gate.test.js tests/flow-hooks-phase-read-gate.test.js tests/flow-hooks-commit-log-gate.test.js tests/flow-hooks-deploy-gate.test.js tests/flow-hooks-todowrite-gate.test.js tests/flow-hooks-git-safety-gate.test.js tests/flow-hooks-scope-mutation-gate.test.js tests/flow-hooks-strike-gate.test.js tests/flow-hooks-component-check.test.js tests/flow-hooks-scope-gate.test.js tests/flow-hooks-implementation-gate.test.js tests/flow-hooks-research-gate.test.js tests/flow-hooks-loop-check.test.js tests/flow-hooks-manager-boundary-gate.test.js tests/flow-hooks-phase-gate.test.js tests/flow-hooks-pre-tool-orchestrator.test.js tests/flow-hooks-observation-capture.test.js tests/flow-hooks-task-gate.test.js tests/flow-durable-session-suspension.test.js tests/flow-health-mcp-scopes.test.js tests/flow-lean-config.test.js tests/flow-workspace-autopickup.test.js tests/flow-worker-boundary-gate.test.js tests/flow-worker-question-classifier.test.js tests/flow-completion-truth-gate-contradictions.test.js tests/flow-structure-sensor.test.js tests/flow-workspace-dispatch-tracking.test.js tests/workspace-ipc-sqlite.test.js tests/workspace-ipc-multi-worker.test.js tests/flow-story-gates.test.js tests/flow-workspace-restart-handoff.test.js tests/flow-wogi-claude-wrapper.test.js tests/flow-wave1-integrations.test.js tests/flow-wave2-integrations.test.js tests/flow-wave3-integrations.test.js tests/flow-commit-claims-gate.test.js tests/auto-review.test.js tests/gate-telemetry-surface.test.js tests/agents-md-alias.test.js tests/flow-skill-manage.test.js tests/fuzzy-patch.test.js tests/mode-schema.test.js tests/flow-feature-dossier.test.js tests/flow-autonomous-mode.test.js tests/flow-epic-cascade.test.js tests/flow-workspace-summary.test.js tests/flow-hooks-research-evidence-gate.test.js tests/flow-worker-mcp-strip.test.js tests/flow-orchestrate-corrections.test.js tests/flow-source-fidelity.test.js tests/flow-hooks-long-input-enforcement.test.js tests/workspace-channel-tracking.test.js tests/flow-hooks-deletion-log.test.js tests/flow-task-boundary-reset.test.js tests/flow-deferral-gate.test.js tests/flow-research-required-gate.test.js tests/flow-standards-forbidden-patterns.test.js tests/flow-hooks-architect-required-gate.test.js tests/flow-architect-runs.test.js tests/flow-installer-forbidden-patterns.test.js tests/flow-deferral-classifier-ai.test.js tests/flow-no-defer-policy.test.js tests/flow-self-adversary-loop.test.js tests/flow-impl-question-classifier.test.js tests/flow-hooks-self-adversary-gate.test.js tests/flow-scheduled-runner.test.js tests/flow-schedule-cli.test.js tests/flow-skill-portability.test.js tests/flow-skill-export.test.js tests/flow-workspace-subtask-state.test.js tests/flow-worker-continuation-gate.test.js tests/flow-workspace-stop-notify.test.js tests/flow-workspace-channel-status.test.js tests/flow-workspace-restart-resume.test.js tests/flow-workspace-sustained-execution.test.js && NODE_ENV=test node tests/run-quality-gates.test.js",
14
14
  "test:syntax": "find scripts/ lib/ -name '*.js' -not -path '*/node_modules/*' -exec node --check {} +",
15
15
  "lint": "eslint scripts/ lib/ tests/",
16
16
  "lint:ci": "eslint scripts/ lib/ tests/ --max-warnings 0",
package/scripts/flow CHANGED
@@ -123,6 +123,7 @@ show_help() {
123
123
  echo " skill remove <name> Remove installed skill"
124
124
  echo " skill update [name] Update skill(s)"
125
125
  echo " skill info <name> Show skill details"
126
+ echo " skill export <name> Export portable skill (agentskills@v1 | claude-plugin)"
126
127
  echo " correct Capture a correction/learning"
127
128
  echo " correct \"desc\" Quick mode with description"
128
129
  echo " correct list List recent corrections"
@@ -380,6 +381,23 @@ case "${1:-}" in
380
381
  ready)
381
382
  node "$SCRIPT_DIR/flow-ready.js" "${@:2}"
382
383
  ;;
384
+ # F11 (R-379): bin/flow (npm-installed dispatcher) had `schedule` wired
385
+ # at line 232, but scripts/flow (dev/repo dispatcher) did not — so
386
+ # `flow schedule install` failed silently inside the dev repo. Wire it
387
+ # here so both dispatchers stay in sync. Same for `skill export`, which
388
+ # ships in v2.33.0 but was only reachable from the npm-installed path.
389
+ schedule)
390
+ node "$SCRIPT_DIR/flow-schedule.js" "${@:2}"
391
+ ;;
392
+ skill|skills)
393
+ # Sub-subcommand: `flow skill export ...` → flow-skill-export.js
394
+ # Other `flow skill ...` subcommands → flow-skill-manage.js (existing).
395
+ if [ "${2:-}" = "export" ]; then
396
+ node "$SCRIPT_DIR/flow-skill-export.js" "${@:3}"
397
+ else
398
+ node "$SCRIPT_DIR/flow-skill-manage.js" "${@:2}"
399
+ fi
400
+ ;;
383
401
  start)
384
402
  node "$SCRIPT_DIR/flow-start.js" "${@:2}"
385
403
  ;;
@@ -696,6 +714,10 @@ case "${1:-}" in
696
714
  # List skills from registry
697
715
  node -e "require('$SCRIPT_DIR/../lib/skill-registry').skill(['list'])"
698
716
  ;;
717
+ export)
718
+ # Phase 1B (wf-0342fc33): portable skill export to agentskills.io / claude-plugin formats
719
+ node "$SCRIPT_DIR/flow-skill-export.js" "${@:3}"
720
+ ;;
699
721
  propose|patch|promote|reject|archive|pending)
700
722
  # Agent proposal CLI (staged, user-approved at session-end)
701
723
  node "$SCRIPT_DIR/flow-skill-manage.js" "${@:2}"
@@ -715,6 +737,9 @@ case "${1:-}" in
715
737
  echo " update [name] Update skill(s)"
716
738
  echo " info <name> Show skill details"
717
739
  echo ""
740
+ echo "Portable Export (Phase 1B):"
741
+ echo " export <name> [--format=agentskills@v1|claude-plugin] [--out=<dir>]"
742
+ echo ""
718
743
  echo "Agent Proposals (staged, user-approved at session-end):"
719
744
  echo " propose --name <n> --content <f> Stage new skill"
720
745
  echo " patch --name <n> --content <f> Stage edit to existing skill"
@@ -1242,6 +1242,26 @@ const CONFIG_DEFAULTS = {
1242
1242
  }
1243
1243
  },
1244
1244
 
1245
+ // --- Scheduled / Background Mode (Phase 1A — wf-b211a076) ---
1246
+ // Default OFF; enable per-project via `.workflow/config.json`.
1247
+ // Headless runner at `scripts/flow-scheduled-runner.js`; GH workflow at
1248
+ // `.github/workflows/wogi-scheduled.yml`. CLI installer: `flow schedule install`.
1249
+ // Hard invariants (also enforced by the runner): operates only on the default
1250
+ // branch in a temp worktree; never `git push origin master`, never
1251
+ // `gh pr merge`, never writes to `.workflow/state/decisions.md`.
1252
+ scheduledMode: {
1253
+ enabled: false,
1254
+ dailyTokenBudget: 5000000,
1255
+ perJobModel: {
1256
+ 'nightly-regression': 'haiku',
1257
+ 'weekly-audit': 'sonnet',
1258
+ 'weekly-digest': 'sonnet',
1259
+ 'per-pr-review': 'opus'
1260
+ },
1261
+ dryRun: false,
1262
+ jobs: ['nightly-regression', 'weekly-audit', 'weekly-digest', 'per-pr-review']
1263
+ },
1264
+
1245
1265
  // --- Workflow Steps ---
1246
1266
  workflowSteps: WORKFLOW_STEP_DEFAULTS
1247
1267
  };
@@ -148,7 +148,9 @@ const KNOWN_CONFIG_KEYS = [
148
148
  // Task-boundary session restart (wf-39e9dc09) — opt-in, experimental
149
149
  'taskBoundaryReset',
150
150
  // Session hydration recency filter (wf-729ab5c0)
151
- 'sessionHydration'
151
+ 'sessionHydration',
152
+ // Workspace (multi-repo manager/worker) — epic-workspace-sustained-exec
153
+ 'workspace'
152
154
  ];
153
155
 
154
156
  module.exports = {