wogiflow 2.17.5 → 2.18.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.
@@ -74,6 +74,7 @@ flow parallel check # See available parallel tasks
74
74
  | 2.5.0+ | 2.1.84+ | TaskCreated hook, YAML glob lists in rules, CLAUDE_STREAM_IDLE_TIMEOUT_MS, WorktreeCreate HTTP transport, idle-return prompt, MCP 2KB cap |
75
75
  | 2.9.0+ | 2.1.90+ | --resume deferred-tool cache fix, MCP schema perf, PostToolUse format-on-save fix, PreToolUse exit-code-2 fix, .husky protected |
76
76
  | 2.9.2+ | 2.1.97+ | Stop/SubagentStop long-session fix, subagent worktree cwd leak fix, refreshInterval status line, workspace.git_worktree, MCP HTTP/SSE leak fix, 429 backoff, compaction transcript dedup |
77
+ | 2.18.0+ | 2.1.108+ | ENABLE_PROMPT_CACHING_1H guidance, /recap awareness, /doctor MCP duplicate-scope mirror in `/wogi-health` |
77
78
 
78
79
  ### Environment Variables (2.1.19+)
79
80
 
@@ -363,6 +364,50 @@ await cancelTask('wf-123', 'superseded', false);
363
364
 
364
365
  - **`/claude-api` skill updated for Managed Agents**: The `/claude-api` skill now covers Managed Agents (`/v1/agents`, `/v1/sessions`) alongside the Claude API. **Impact on WogiFlow**: Informational — WogiFlow's `claude-api` skill reference remains accurate.
365
366
 
367
+ ### Features in 2.1.108+
368
+
369
+ - **`ENABLE_PROMPT_CACHING_1H` env var (RECOMMENDED for non-subscribers)**: Opts into **1-hour prompt-cache TTL** on **API key, Bedrock, Vertex, and Foundry** providers. Subscribers (Claude Pro, Max, Team, Enterprise via claude.ai OAuth) already get 1h TTL by default — this flag is a **no-op for them**. The complementary `FORCE_PROMPT_CACHING_5M` pins to 5min, and the older `ENABLE_PROMPT_CACHING_1H_BEDROCK` is deprecated but still honored. **Impact on WogiFlow (HIGH)**: WogiFlow sessions load a large, stable prefix every turn — CLAUDE.md (~300 lines), state files (`ready.json`, `decisions.md`, `app-map.md`), phase files, and pinned spec context. At the default 5min TTL, any pause longer than 5 minutes (user thinking, a long `flow` CLI run, a meeting mid-session) invalidates the cache and the next turn pays the full input-token cost again. At 1h TTL, the same prefix stays cached across those pauses, yielding **substantial token-cost reduction** on typical multi-hour WogiFlow work. **Action for API-key / Bedrock / Vertex / Foundry users**: `export ENABLE_PROMPT_CACHING_1H=1` in your shell profile. **Action for subscribers**: none (already enabled). **Risk**: none — if set on a subscriber account it is ignored; if set when not supported, it silently falls back.
370
+
371
+ - **`/recap` command and session recap feature**: Provides context when returning to a session. Configurable in `/config` and manually invocable with `/recap`. For users with telemetry disabled (Bedrock/Vertex/Foundry/`DISABLE_TELEMETRY`), recap is still enabled by default; opt out via `/config` or `CLAUDE_CODE_ENABLE_AWAY_SUMMARY=0`. **Overlap with WogiFlow**: `/wogi-morning`, `/wogi-session-end`, and `/wogi-pre-compact` already provide durable recap via state files. `/recap` is ephemeral (summarizes the current session); WogiFlow's state survives session exit. Use both: `/recap` for intra-session context, `/wogi-morning` for cross-session pickup.
372
+
373
+ - **Built-in slash commands via Skill tool**: Claude can now discover and invoke `/init`, `/review`, `/security-review` via the Skill tool. **Impact on WogiFlow**: No collision — all WogiFlow commands use the `wogi-*` prefix (`/wogi-review`, `/wogi-init`, `/wogi-review-fix`). Natural-language routing in CLAUDE.md directs "code review" phrases to `/wogi-review`, not the built-in `/review`. If a user explicitly types `/review`, Claude Code handles it natively — this is expected.
374
+
375
+ - **`/model` mid-conversation warning**: `/model` now warns before switching models mid-conversation, since the next response re-reads the full history uncached. **Impact on WogiFlow**: Relevant for hybrid mode (`/wogi-hybrid`) — switching the executor model via `/model` during hybrid execution wastes the cached context. WogiFlow's `/wogi-hybrid-setup` is the correct way to change executor models between sessions rather than mid-session.
376
+
377
+ - **`DISABLE_PROMPT_CACHING*` startup warning**: Claude Code now warns at startup when prompt caching is disabled via `DISABLE_PROMPT_CACHING*` env vars. **Impact on WogiFlow**: WogiFlow's heavy context prefix makes disabled caching **expensive**. This warning helps users who accidentally disabled caching (e.g., copy-pasted env from another project) spot the regression fast.
378
+
379
+ - **`/undo` alias for `/rewind`**: Typing `/undo` now aliases to `/rewind`. WogiFlow's `/wogi-pre-compact` and `/wogi-suspend` are complementary — `/undo`/`/rewind` rolls back message turns, while the WogiFlow flows preserve state across sessions.
380
+
381
+ - **Memory footprint reductions for file reads**: Language grammars now load on demand, reducing memory for file reads, edits, and syntax highlighting. **Impact on WogiFlow**: Long WogiFlow sessions (especially `/wogi-bulk-loop` continuous runs) use noticeably less RAM. No code change needed.
382
+
383
+ ### Features in 2.1.110+
384
+
385
+ - **PreToolUse hook `additionalContext` preserved on tool failure (BUG FIX, GOOD NEWS)**: Previously, when a tool call failed, any `additionalContext` returned by PreToolUse hooks was **dropped**. Fixed in 2.1.110. **Impact on WogiFlow (HIGH)**: WogiFlow injects `additionalContext` in 8 places via `scripts/hooks/adapters/claude-code.js` (PreToolUse, UserPromptSubmit, SessionStart) for routing enforcement, phase-gate messages, component reuse hints, and session-start task context. Before this fix, if a guarded tool call failed, WogiFlow's context message vanished — producing "silent" hook behavior that was confusing to debug. After this fix, WogiFlow's hook messages are reliably delivered regardless of tool outcome. **Action**: none — automatic improvement after upgrade.
386
+
387
+ - **`/doctor` warns on duplicate MCP server definitions across scopes**: When the same MCP server is defined in user (`~/.claude/settings.json`), project (`.claude/settings.json`), and local (`.claude/settings.local.json`) scopes with different endpoints, `/doctor` now flags the conflict. **Impact on WogiFlow**: `/wogi-health` has a mirror check in `flow-health.js` that scans the same three scopes and reports duplicate MCP server names with divergent endpoints as a health finding (v2.18.0+).
388
+
389
+ - **PushNotification tool**: Claude can send mobile push notifications when Remote Control and "Push when Claude decides" config are enabled. **WogiFlow opportunity**: Long-running autonomous loops (`/wogi-bulk`, `/wogi-bulk-loop`) could emit a notification on completion, blocker, or extended hang. Tracked as a future enhancement; not auto-wired.
390
+
391
+ - **Bash tool timeout enforcement**: The Bash tool now enforces the documented maximum timeout (600000ms / 10min) instead of accepting arbitrarily large values. **Impact on WogiFlow**: No impact — all WogiFlow hook Bash timeouts are under 60s (verified across `.claude/settings.json` and `scripts/hooks/`).
392
+
393
+ - **stdio MCP servers no longer disconnect on stray non-JSON lines**: Fixed a regression from 2.1.105 where stdio MCP servers that print stray non-JSON lines to stdout were disconnected on the first stray line. **Impact on WogiFlow**: WogiFlow has no custom MCP servers in-repo. User-installed MCP servers (figma, atlassian, gmail) benefit automatically.
394
+
395
+ - **PermissionRequest hook `updatedInput` re-check**: Fixed PermissionRequest hooks returning `updatedInput` not being re-checked against `permissions.deny` rules; `setMode:'bypassPermissions'` updates now respect `disableBypassPermissionsMode`. **Impact on WogiFlow**: WogiFlow does not implement PermissionRequest hooks (only PermissionDenied for logging). Not affected.
396
+
397
+ - **`--resume`/`--continue` resurrects unexpired scheduled tasks**: Scheduled tasks (cron/CronCreate) now resume across session restarts. **Impact on WogiFlow**: WogiFlow does not currently use Claude Code's cron feature. Not affected; tracked as a future opportunity for automated maintenance tasks.
398
+
399
+ - **`/context`, `/exit`, `/reload-plugins` work from Remote Control (mobile/web) clients**: Remote Control users can now invoke these built-ins. **Impact on WogiFlow**: WogiFlow has no TTY-only code paths — all `/wogi-*` skills already work identically on Remote Control. Users can now do full WogiFlow-driven work from mobile/web.
400
+
401
+ - **`/tui` command and `tui` setting**: `/tui fullscreen` switches to flicker-free rendering in the same conversation. The focus view is now toggled separately with `/focus` (Ctrl+O now toggles verbose transcript only). **Impact on WogiFlow**: Documentation only — no runtime dependency on Ctrl+O. The WogiFlow statusline works identically in both TUI modes.
402
+
403
+ - **`autoScrollEnabled` config**: New setting to disable conversation auto-scroll in fullscreen mode. Purely UX — no WogiFlow impact.
404
+
405
+ - **Write tool reports IDE diff edits**: The Write tool now informs the model when the user edits the proposed content in the IDE diff before accepting. **Impact on WogiFlow**: Useful signal for learning — WogiFlow's `/wogi-correction` could eventually consume this to detect "user edited my output" events. Not auto-wired; tracked as an enhancement.
406
+
407
+ - **TRACEPARENT/TRACESTATE in SDK/headless sessions**: SDK and headless sessions now read W3C trace headers from the environment for distributed trace linking. **Impact on wogiflow-cloud**: Teams backend can propagate trace context from CI/CD pipelines into WogiFlow sessions for end-to-end observability. Tracked as a cloud opportunity.
408
+
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
+
366
411
  ### Simple Mode Naming Distinction
367
412
 
368
413
  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":
@@ -497,4 +542,4 @@ Run `/keybindings` in Claude Code to customize your shortcuts.
497
542
 
498
543
  ---
499
544
 
500
- *Last updated: 2026-04-09*
545
+ *Last updated: 2026-04-16*
@@ -133,10 +133,43 @@
133
133
  }
134
134
  ]
135
135
  }
136
+ ],
137
+ "TaskCreated": [
138
+ {
139
+ "hooks": [
140
+ {
141
+ "type": "command",
142
+ "command": "node scripts/hooks/entry/claude-code/task-created.js",
143
+ "timeout": 5
144
+ }
145
+ ]
146
+ }
147
+ ],
148
+ "PermissionDenied": [
149
+ {
150
+ "hooks": [
151
+ {
152
+ "type": "command",
153
+ "command": "node scripts/hooks/entry/claude-code/permission-denied.js",
154
+ "timeout": 5
155
+ }
156
+ ]
157
+ }
158
+ ],
159
+ "PreCompact": [
160
+ {
161
+ "hooks": [
162
+ {
163
+ "type": "command",
164
+ "command": "node scripts/hooks/entry/claude-code/pre-compact.js",
165
+ "timeout": 5
166
+ }
167
+ ]
168
+ }
136
169
  ]
137
170
  },
138
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.",
139
172
  "_wogiFlowManaged": true,
140
- "_wogiFlowVersion": "2.4.2",
173
+ "_wogiFlowVersion": "2.17.5",
141
174
  "_comment": "Shared WogiFlow hook configuration. Committed to repo for team use. User-specific overrides go in settings.local.json."
142
175
  }
@@ -131,6 +131,7 @@ npm install -D wogiflow && npx flow onboard
131
131
  | `/wogi-register` | Register plugins for /wogi-start routing |
132
132
 
133
133
  See `.claude/docs/commands.md` for complete command reference.
134
+ See `.claude/docs/claude-code-compatibility.md` for Claude Code version features, performance tips, and env vars (incl. **`ENABLE_PROMPT_CACHING_1H=1`** recommended for API-key / Bedrock / Vertex / Foundry users).
134
135
 
135
136
  ## Natural Language Command Detection
136
137
 
package/lib/installer.js CHANGED
@@ -1030,6 +1030,27 @@ async function init(args) {
1030
1030
  console.log(' /wogi-health - Check workflow health');
1031
1031
  console.log(' /wogi-story - Create a new story');
1032
1032
  console.log('');
1033
+ printPromptCachingTip();
1034
+ }
1035
+
1036
+ /**
1037
+ * Print the ENABLE_PROMPT_CACHING_1H recommendation for non-subscriber Claude Code users.
1038
+ *
1039
+ * Claude Pro/Max/Team/Enterprise (OAuth via claude.ai) already get 1-hour prompt-cache TTL.
1040
+ * API-key, Bedrock, Vertex, and Foundry users default to 5min TTL — any pause longer than
1041
+ * 5min during a WogiFlow session invalidates the cached CLAUDE.md + state-file prefix and
1042
+ * re-pays the full input-token cost on the next turn. Enabling 1h TTL gives substantial
1043
+ * savings on typical multi-hour sessions.
1044
+ *
1045
+ * We surface this exactly once, during `flow init` onboarding. The full rationale lives in
1046
+ * `.claude/docs/claude-code-compatibility.md` under "Features in 2.1.108+".
1047
+ */
1048
+ function printPromptCachingTip() {
1049
+ console.log('💡 Performance tip (API-key / Bedrock / Vertex / Foundry users):');
1050
+ console.log(' Set \x1b[33mENABLE_PROMPT_CACHING_1H=1\x1b[0m in your shell profile for 1-hour');
1051
+ console.log(' prompt-cache TTL (default is 5min). Claude subscribers already get 1h by default.');
1052
+ console.log(' Details: \x1b[36m.claude/docs/claude-code-compatibility.md\x1b[0m (Features in 2.1.108+)');
1053
+ console.log('');
1033
1054
  }
1034
1055
 
1035
1056
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wogiflow",
3
- "version": "2.17.5",
3
+ "version": "2.18.0",
4
4
  "description": "AI-powered development workflow management system with multi-model support",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -82,6 +82,123 @@ function checkClaudeCodeVersion() {
82
82
  }
83
83
  }
84
84
 
85
+ /**
86
+ * Normalize an MCP server config so two equivalent objects compare equal
87
+ * after JSON.stringify. Recursively sorts object keys and stringifies arrays
88
+ * in their original order (order is meaningful for args).
89
+ *
90
+ * @param {*} cfg - An MCP server config value (typically an object, but may be primitive)
91
+ * @returns {string} Canonical JSON representation suitable for equality comparison
92
+ */
93
+ function normalizeMcpConfig(cfg) {
94
+ const sortKeys = (v) => {
95
+ if (Array.isArray(v)) return v.map(sortKeys);
96
+ if (v && typeof v === 'object') {
97
+ const out = {};
98
+ for (const k of Object.keys(v).sort()) {
99
+ out[k] = sortKeys(v[k]);
100
+ }
101
+ return out;
102
+ }
103
+ return v;
104
+ };
105
+ return JSON.stringify(sortKeys(cfg));
106
+ }
107
+
108
+ /**
109
+ * Check MCP server definitions across the three Claude Code settings scopes:
110
+ * - user: ~/.claude/settings.json
111
+ * - project: <project>/.claude/settings.json
112
+ * - local: <project>/.claude/settings.local.json
113
+ *
114
+ * Mirrors the /doctor warning added in Claude Code 2.1.110: a server defined
115
+ * in multiple scopes with divergent config is almost always a mistake — the
116
+ * lowest-priority scope silently loses, and users debug ghost endpoints.
117
+ *
118
+ * Identical duplicate definitions are intentionally NOT flagged — some teams
119
+ * duplicate for portability. Only divergent configs surface.
120
+ *
121
+ * @param {Object} [opts]
122
+ * @param {string} [opts.userSettingsPath] - Override path to user scope (for tests)
123
+ * @param {string} [opts.projectSettingsPath] - Override path to project scope (for tests)
124
+ * @param {string} [opts.localSettingsPath] - Override path to local scope (for tests)
125
+ * @returns {{
126
+ * duplicates: Array<{name: string, scopes: string[]}>,
127
+ * uniqueServers: number,
128
+ * parseErrors: Array<{file: string, error: string}>,
129
+ * scopesChecked: number
130
+ * }}
131
+ */
132
+ function checkMcpScopes(opts = {}) {
133
+ const os = require('node:os');
134
+ const scopes = [
135
+ { file: opts.userSettingsPath || path.join(os.homedir(), '.claude', 'settings.json'), label: 'user' },
136
+ { file: opts.projectSettingsPath || path.join(PROJECT_ROOT, '.claude', 'settings.json'), label: 'project' },
137
+ { file: opts.localSettingsPath || path.join(PROJECT_ROOT, '.claude', 'settings.local.json'), label: 'local' }
138
+ ];
139
+
140
+ const parseErrors = [];
141
+ const serverByName = new Map();
142
+ let scopesChecked = 0;
143
+
144
+ // Sentinel object for safeJsonParse so we can distinguish "file failed to
145
+ // parse" (returned sentinel) from "file parsed but had no mcpServers" (returned
146
+ // object without the key). safeJsonParse is mandated by security-patterns.md §2
147
+ // (prototype-pollution guard + non-object validation) — we layer a raw-read
148
+ // fallback on top to categorize the failure cause for health output.
149
+ const PARSE_SENTINEL = Object.create(null);
150
+
151
+ for (const scope of scopes) {
152
+ if (!fileExists(scope.file)) continue;
153
+ scopesChecked++;
154
+ const json = safeJsonParse(scope.file, PARSE_SENTINEL);
155
+ if (json === PARSE_SENTINEL) {
156
+ // safeJsonParse returned the sentinel — categorize: read failure vs JSON
157
+ // parse failure vs non-object vs prototype-pollution rejection.
158
+ let raw;
159
+ try {
160
+ raw = fs.readFileSync(scope.file, 'utf-8');
161
+ } catch (err) {
162
+ parseErrors.push({ file: scope.file, error: `read failed: ${err.message}` });
163
+ continue;
164
+ }
165
+ try {
166
+ JSON.parse(raw);
167
+ // Raw parse succeeded — safeJsonParse rejected for structural reason
168
+ // (non-object top level, or dangerous __proto__/constructor keys).
169
+ parseErrors.push({ file: scope.file, error: 'rejected by safeJsonParse (non-object or prototype-pollution guard)' });
170
+ } catch (err) {
171
+ parseErrors.push({ file: scope.file, error: `invalid JSON: ${err.message}` });
172
+ }
173
+ continue;
174
+ }
175
+ const mcp = json.mcpServers;
176
+ if (!mcp || typeof mcp !== 'object' || Array.isArray(mcp)) continue;
177
+
178
+ for (const name of Object.keys(mcp)) {
179
+ if (!serverByName.has(name)) serverByName.set(name, []);
180
+ serverByName.get(name).push({ scope: scope.label, config: mcp[name] });
181
+ }
182
+ }
183
+
184
+ const duplicates = [];
185
+ for (const [name, entries] of serverByName.entries()) {
186
+ if (entries.length < 2) continue;
187
+ const canonical = normalizeMcpConfig(entries[0].config);
188
+ const allSame = entries.every(e => normalizeMcpConfig(e.config) === canonical);
189
+ if (!allSame) {
190
+ duplicates.push({ name, scopes: entries.map(e => e.scope) });
191
+ }
192
+ }
193
+
194
+ return {
195
+ duplicates,
196
+ uniqueServers: serverByName.size,
197
+ parseErrors,
198
+ scopesChecked
199
+ };
200
+ }
201
+
85
202
  function main() {
86
203
  console.log(color('cyan', 'Wogi Flow Health Check'));
87
204
  console.log('========================');
@@ -661,6 +778,29 @@ function main() {
661
778
  }
662
779
  }
663
780
 
781
+ // Check MCP server definitions across scopes (mirrors Claude Code 2.1.110 /doctor)
782
+ console.log('');
783
+ printSection('Checking MCP server scopes...');
784
+
785
+ const mcp = checkMcpScopes();
786
+ if (mcp.parseErrors.length > 0) {
787
+ for (const e of mcp.parseErrors) {
788
+ warn(`Could not parse ${e.file}: ${e.error}`);
789
+ }
790
+ warnings += mcp.parseErrors.length;
791
+ }
792
+ if (mcp.uniqueServers === 0) {
793
+ console.log(` ${color('dim', '○')} No MCP servers defined in user / project / local scopes`);
794
+ } else if (mcp.duplicates.length === 0) {
795
+ success(`No conflicting MCP server definitions across ${mcp.scopesChecked} scope(s)`);
796
+ } else {
797
+ for (const f of mcp.duplicates) {
798
+ warn(`MCP server "${f.name}" has divergent config in scopes: ${f.scopes.join(' + ')}`);
799
+ console.log(` ${color('dim', '→ Consolidate into a single scope; /doctor will flag this too')}`);
800
+ }
801
+ warnings += mcp.duplicates.length;
802
+ }
803
+
664
804
  // Check .gitignore sync
665
805
  console.log('');
666
806
  printSection('Checking .gitignore sync...');
@@ -1159,4 +1299,8 @@ function run() {
1159
1299
  }
1160
1300
  }
1161
1301
 
1162
- run();
1302
+ if (require.main === module) {
1303
+ run();
1304
+ }
1305
+
1306
+ module.exports = { checkMcpScopes, normalizeMcpConfig };