wogiflow 2.0.0 → 2.0.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/package.json
CHANGED
package/scripts/flow-paths.js
CHANGED
|
@@ -116,6 +116,8 @@ const PATHS = {
|
|
|
116
116
|
epics: path.join(WORKFLOW_DIR, 'epics'),
|
|
117
117
|
features: path.join(WORKFLOW_DIR, 'features'),
|
|
118
118
|
plans: path.join(WORKFLOW_DIR, 'plans'),
|
|
119
|
+
// Scratch directory for temporary files (auto-cleaned at session end)
|
|
120
|
+
scratch: path.join(WORKFLOW_DIR, 'scratch'),
|
|
119
121
|
// Additional workflow directories
|
|
120
122
|
runs: path.join(WORKFLOW_DIR, 'runs'),
|
|
121
123
|
checkpoints: path.join(WORKFLOW_DIR, 'checkpoints'),
|
|
@@ -119,17 +119,20 @@ function checkClaudeCodeVersionOnce() {
|
|
|
119
119
|
return `Claude Code ${version} is below the minimum required version (${HARD_MIN.major}.${HARD_MIN.minor}.${HARD_MIN.patch}). WogiFlow hooks will not work correctly. Update with: npm install -g @anthropic-ai/claude-code@latest`;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
// Soft gates —
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
// Soft gates — generate informational warning listing disabled features
|
|
123
|
+
const SOFT_GATES = [
|
|
124
|
+
{ version: [2, 1, 50], features: 'worktree hooks, agent isolation' },
|
|
125
|
+
{ version: [2, 1, 72], features: 'ConfigChange/InstructionsLoaded hooks, effort levels' },
|
|
126
|
+
{ version: [2, 1, 76], features: 'PostCompact hook (state recovery after compaction)' },
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
const disabledFeatures = SOFT_GATES
|
|
130
|
+
.filter(gate => !meetsVersion(major, minor, patch, ...gate.version))
|
|
131
|
+
.map(gate => ` - ${gate.features} (requires ${gate.version.join('.')}+)`);
|
|
132
|
+
|
|
133
|
+
if (disabledFeatures.length > 0) {
|
|
134
|
+
return `Claude Code ${version} — some WogiFlow features are disabled:\n${disabledFeatures.join('\n')}\nUpdate for full functionality: npm i -g @anthropic-ai/claude-code@latest`;
|
|
135
|
+
}
|
|
133
136
|
|
|
134
137
|
return null;
|
|
135
138
|
}
|
|
@@ -796,6 +796,18 @@ function formatContextForInjection(context) {
|
|
|
796
796
|
output += `\`\`\`bash\nunset CLAUDE_CODE_SIMPLE\n\`\`\`\n\n`;
|
|
797
797
|
}
|
|
798
798
|
|
|
799
|
+
// Version compatibility warning (Claude Code below hard minimum or missing features)
|
|
800
|
+
if (ctx.versionWarning) {
|
|
801
|
+
output += `### Version Warning\n`;
|
|
802
|
+
output += `${ctx.versionWarning}\n\n`;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// WogiFlow npm update available
|
|
806
|
+
if (ctx.updateWarning) {
|
|
807
|
+
output += `### Update Available\n`;
|
|
808
|
+
output += `${ctx.updateWarning}\n\n`;
|
|
809
|
+
}
|
|
810
|
+
|
|
799
811
|
// PRIORITY: Setup required - show first if needs setup
|
|
800
812
|
if (ctx.setupRequired && ctx.setupRequired.needsSetup) {
|
|
801
813
|
output += `### ⚠️ Setup Required\n`;
|
|
@@ -68,6 +68,38 @@ function handleSessionEnd(input) {
|
|
|
68
68
|
result.logged = false;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// Scratch directory cleanup — remove temp files created during session
|
|
72
|
+
try {
|
|
73
|
+
const fs = require('node:fs');
|
|
74
|
+
const path = require('node:path');
|
|
75
|
+
const scratchDir = path.join(PATHS.workflow, 'scratch');
|
|
76
|
+
if (fs.existsSync(scratchDir)) {
|
|
77
|
+
const files = fs.readdirSync(scratchDir);
|
|
78
|
+
let scratchCleaned = 0;
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
if (file === '.gitkeep') continue; // Keep the directory marker
|
|
81
|
+
try {
|
|
82
|
+
const filePath = path.join(scratchDir, file);
|
|
83
|
+
const stat = fs.statSync(filePath);
|
|
84
|
+
if (stat.isFile()) {
|
|
85
|
+
fs.unlinkSync(filePath);
|
|
86
|
+
scratchCleaned++;
|
|
87
|
+
} else if (stat.isDirectory()) {
|
|
88
|
+
fs.rmSync(filePath, { recursive: true, force: true });
|
|
89
|
+
scratchCleaned++;
|
|
90
|
+
}
|
|
91
|
+
} catch (_err) {
|
|
92
|
+
// Skip files that can't be deleted
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (scratchCleaned > 0) {
|
|
96
|
+
result.scratchCleaned = scratchCleaned;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (_err) {
|
|
100
|
+
// Non-critical — never block session end
|
|
101
|
+
}
|
|
102
|
+
|
|
71
103
|
// State folder hygiene — clean stale/orphan files (fire-and-forget)
|
|
72
104
|
try {
|
|
73
105
|
const hygiene = cleanStaleFiles();
|
package/scripts/postinstall.js
CHANGED
|
@@ -105,7 +105,8 @@ function createMinimalStructure() {
|
|
|
105
105
|
WORKFLOW_DIR,
|
|
106
106
|
STATE_DIR,
|
|
107
107
|
path.join(WORKFLOW_DIR, 'changes'),
|
|
108
|
-
path.join(WORKFLOW_DIR, 'specs')
|
|
108
|
+
path.join(WORKFLOW_DIR, 'specs'),
|
|
109
|
+
path.join(WORKFLOW_DIR, 'scratch')
|
|
109
110
|
];
|
|
110
111
|
|
|
111
112
|
for (const dir of dirs) {
|
|
@@ -244,6 +245,82 @@ function copyDir(src, dest, mergeMode = false, depth = 0) {
|
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Hook types and the minimum Claude Code version that supports them.
|
|
250
|
+
* Claude Code rejects the ENTIRE settings.json if any hook key is unrecognized,
|
|
251
|
+
* so we must exclude hooks that the installed version doesn't support.
|
|
252
|
+
*/
|
|
253
|
+
const HOOK_VERSION_MAP = {
|
|
254
|
+
// Hooks available since 2.1.23 (HARD_MIN)
|
|
255
|
+
SessionStart: { major: 2, minor: 1, patch: 23 },
|
|
256
|
+
UserPromptSubmit: { major: 2, minor: 1, patch: 23 },
|
|
257
|
+
PreToolUse: { major: 2, minor: 1, patch: 23 },
|
|
258
|
+
PostToolUse: { major: 2, minor: 1, patch: 23 },
|
|
259
|
+
Stop: { major: 2, minor: 1, patch: 23 },
|
|
260
|
+
SessionEnd: { major: 2, minor: 1, patch: 23 },
|
|
261
|
+
TaskCompleted: { major: 2, minor: 1, patch: 23 },
|
|
262
|
+
// Hooks added in 2.1.50+
|
|
263
|
+
WorktreeCreate: { major: 2, minor: 1, patch: 50 },
|
|
264
|
+
WorktreeRemove: { major: 2, minor: 1, patch: 50 },
|
|
265
|
+
// Hooks added in 2.1.72+
|
|
266
|
+
ConfigChange: { major: 2, minor: 1, patch: 72 },
|
|
267
|
+
InstructionsLoaded: { major: 2, minor: 1, patch: 72 },
|
|
268
|
+
// Hooks added in 2.1.76+
|
|
269
|
+
PostCompact: { major: 2, minor: 1, patch: 76 },
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Detect Claude Code version.
|
|
274
|
+
* @returns {{ major: number, minor: number, patch: number } | null}
|
|
275
|
+
*/
|
|
276
|
+
function detectClaudeCodeVersion() {
|
|
277
|
+
try {
|
|
278
|
+
const output = execFileSync('claude', ['--version'], {
|
|
279
|
+
encoding: 'utf-8',
|
|
280
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
281
|
+
timeout: 5000
|
|
282
|
+
}).trim();
|
|
283
|
+
const match = output.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
284
|
+
if (match) {
|
|
285
|
+
return { major: parseInt(match[1], 10), minor: parseInt(match[2], 10), patch: parseInt(match[3], 10) };
|
|
286
|
+
}
|
|
287
|
+
} catch (_err) {
|
|
288
|
+
// Claude CLI not available — can't detect version
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Check if version A meets minimum version B.
|
|
295
|
+
* @returns {boolean}
|
|
296
|
+
*/
|
|
297
|
+
function versionMeetsMinimum(version, minimum) {
|
|
298
|
+
if (version.major !== minimum.major) return version.major > minimum.major;
|
|
299
|
+
if (version.minor !== minimum.minor) return version.minor > minimum.minor;
|
|
300
|
+
return version.patch >= minimum.patch;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Remove hook types from settings.json that the installed Claude Code version doesn't support.
|
|
305
|
+
* Claude Code rejects the ENTIRE settings file if any hook key is unrecognized.
|
|
306
|
+
* @param {Object} settings - Parsed settings object (mutated in place)
|
|
307
|
+
* @param {{ major: number, minor: number, patch: number } | null} ccVersion - Detected version
|
|
308
|
+
* @returns {string[]} List of removed hook names
|
|
309
|
+
*/
|
|
310
|
+
function stripUnsupportedHooks(settings, ccVersion) {
|
|
311
|
+
if (!settings || !settings.hooks || !ccVersion) return [];
|
|
312
|
+
|
|
313
|
+
const removed = [];
|
|
314
|
+
for (const hookName of Object.keys(settings.hooks)) {
|
|
315
|
+
const minVersion = HOOK_VERSION_MAP[hookName];
|
|
316
|
+
if (minVersion && !versionMeetsMinimum(ccVersion, minVersion)) {
|
|
317
|
+
delete settings.hooks[hookName];
|
|
318
|
+
removed.push(`${hookName} (requires ${minVersion.major}.${minVersion.minor}.${minVersion.patch}+)`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return removed;
|
|
322
|
+
}
|
|
323
|
+
|
|
247
324
|
/**
|
|
248
325
|
* Rewrite hook command paths from local dev paths to package paths.
|
|
249
326
|
* The package's settings.json uses local paths (node scripts/hooks/...)
|
|
@@ -319,6 +396,18 @@ function copyClaudeResources() {
|
|
|
319
396
|
// Rewrite hook paths: package uses local dev paths (node scripts/hooks/...)
|
|
320
397
|
// but user projects need package paths (node node_modules/wogiflow/scripts/hooks/...)
|
|
321
398
|
rewriteHookPaths(ours);
|
|
399
|
+
// Strip hooks unsupported by the installed Claude Code version.
|
|
400
|
+
// Claude Code rejects the ENTIRE settings.json if any hook key is unrecognized,
|
|
401
|
+
// so we must exclude hooks that the version doesn't support.
|
|
402
|
+
const ccVersion = detectClaudeCodeVersion();
|
|
403
|
+
const removedHooks = stripUnsupportedHooks(ours, ccVersion);
|
|
404
|
+
if (removedHooks.length > 0) {
|
|
405
|
+
console.log(`[wogiflow] Claude Code ${ccVersion.major}.${ccVersion.minor}.${ccVersion.patch} detected. Excluded unsupported hooks:`);
|
|
406
|
+
for (const h of removedHooks) {
|
|
407
|
+
console.log(` - ${h}`);
|
|
408
|
+
}
|
|
409
|
+
console.log('[wogiflow] Update Claude Code for full functionality: npm i -g @anthropic-ai/claude-code@latest');
|
|
410
|
+
}
|
|
322
411
|
// Always update hooks (core WogiFlow functionality)
|
|
323
412
|
existing.hooks = ours.hooks;
|
|
324
413
|
existing._wogiFlowManaged = true;
|