wogiflow 2.17.0 → 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.
- package/.claude/commands/wogi-audit.md +212 -17
- package/.claude/commands/wogi-research.md +37 -0
- package/.claude/commands/wogi-review.md +200 -22
- package/.claude/commands/wogi-start.md +45 -0
- package/.claude/docs/claude-code-compatibility.md +46 -1
- package/.claude/docs/intent-grounded-review.md +209 -0
- package/.claude/settings.json +34 -1
- package/.workflow/agents/logic-adversary.md +8 -0
- package/.workflow/templates/claude-md.hbs +18 -0
- package/lib/installer.js +22 -0
- package/lib/utils.js +29 -3
- package/lib/workspace-changelog.js +2 -1
- package/lib/workspace-channel-server.js +4 -6
- package/lib/workspace-contracts.js +5 -4
- package/lib/workspace-events.js +8 -7
- package/lib/workspace-gates.js +4 -3
- package/lib/workspace-integration-tests.js +2 -1
- package/lib/workspace-intelligence.js +3 -2
- package/lib/workspace-locks.js +2 -1
- package/lib/workspace-messages.js +7 -6
- package/lib/workspace-routing.js +14 -26
- package/lib/workspace-session.js +7 -6
- package/lib/workspace-sync.js +9 -8
- package/package.json +4 -2
- package/scripts/base-workflow-step.js +1 -1
- package/scripts/flow +19 -0
- package/scripts/flow-adaptive-learning.js +1 -1
- package/scripts/flow-aggregate.js +2 -1
- package/scripts/flow-architect-pass.js +3 -3
- package/scripts/flow-archive-runs.js +372 -0
- package/scripts/flow-ask.js +1 -1
- package/scripts/flow-ast-grep.js +216 -0
- package/scripts/flow-audit-gates.js +1 -1
- package/scripts/flow-auto-learn.js +8 -11
- package/scripts/flow-bug.js +2 -2
- package/scripts/flow-capture-gate.js +644 -0
- package/scripts/flow-capture.js +4 -3
- package/scripts/flow-cli-flags.js +95 -0
- package/scripts/flow-community-sync.js +2 -1
- package/scripts/flow-community.js +6 -6
- package/scripts/flow-conclusion-classifier.js +310 -0
- package/scripts/flow-config-defaults.js +3 -3
- package/scripts/flow-constants.js +8 -11
- package/scripts/flow-context-scoring.js +1 -0
- package/scripts/flow-correction-detector.js +344 -3
- package/scripts/flow-damage-control.js +1 -1
- package/scripts/flow-decisions-merge.js +1 -0
- package/scripts/flow-done-gates.js +20 -0
- package/scripts/flow-done-report.js +2 -2
- package/scripts/flow-done.js +4 -4
- package/scripts/flow-epics.js +5 -11
- package/scripts/flow-health.js +145 -1
- package/scripts/flow-id.js +92 -0
- package/scripts/flow-io.js +15 -5
- package/scripts/flow-knowledge-router.js +2 -1
- package/scripts/flow-links.js +1 -1
- package/scripts/flow-log-manager.js +2 -1
- package/scripts/flow-logic-adversary.js +4 -4
- package/scripts/flow-long-input-cli.js +6 -0
- package/scripts/flow-long-input-stories.js +1 -1
- package/scripts/flow-loop-retry-learning.js +1 -1
- package/scripts/flow-mcp-capabilities.js +2 -3
- package/scripts/flow-mcp-docs.js +2 -1
- package/scripts/flow-memory-blocks.js +2 -1
- package/scripts/flow-memory-sync.js +1 -1
- package/scripts/flow-memory.js +767 -0
- package/scripts/flow-migrate-igr.js +1 -1
- package/scripts/flow-migrate.js +2 -1
- package/scripts/flow-model-adapter.js +1 -1
- package/scripts/flow-model-config.js +5 -1
- package/scripts/flow-model-profile.js +2 -1
- package/scripts/flow-orchestrate.js +3 -3
- package/scripts/flow-output.js +29 -0
- package/scripts/flow-parallel.js +10 -9
- package/scripts/flow-pattern-enforcer.js +2 -1
- package/scripts/flow-permissions-audit.js +124 -0
- package/scripts/flow-plugin-registry.js +2 -2
- package/scripts/flow-progress.js +5 -1
- package/scripts/flow-project-analyzer.js +1 -1
- package/scripts/flow-promote.js +510 -0
- package/scripts/flow-registries.js +86 -0
- package/scripts/flow-request-log.js +133 -0
- package/scripts/flow-research-protocol.js +0 -1
- package/scripts/flow-revision-tracker.js +2 -1
- package/scripts/flow-roadmap.js +2 -1
- package/scripts/flow-rules-sync.js +3 -7
- package/scripts/flow-session-end.js +3 -1
- package/scripts/flow-session-learning.js +6 -13
- package/scripts/flow-session-state.js +2 -2
- package/scripts/flow-setup-hooks.js +2 -1
- package/scripts/flow-skill-create.js +1 -1
- package/scripts/flow-skill-freshness.js +6 -7
- package/scripts/flow-skill-learn.js +1 -1
- package/scripts/flow-step-coverage.js +1 -1
- package/scripts/flow-step-security.js +1 -1
- package/scripts/flow-story.js +58 -10
- package/scripts/flow-sys.js +204 -0
- package/scripts/flow-task-hierarchy.js +88 -0
- package/scripts/flow-tech-debt.js +2 -1
- package/scripts/flow-test-api.js +1 -1
- package/scripts/flow-utils.js +60 -890
- package/scripts/hooks/core/bugfix-scope-gate.js +5 -4
- package/scripts/hooks/core/deploy-gate.js +1 -1
- package/scripts/hooks/core/pre-tool-helpers.js +72 -0
- package/scripts/hooks/core/pre-tool-orchestrator.js +442 -0
- package/scripts/hooks/core/routing-gate.js +8 -0
- package/scripts/hooks/core/session-end.js +28 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +48 -492
- package/scripts/hooks/entry/shared/hook-runner.js +1 -1
- package/scripts/registries/schema-registry.js +1 -1
- package/scripts/registries/service-registry.js +1 -1
|
@@ -50,7 +50,7 @@ const REQUIRED_IGR_SCRIPTS = [
|
|
|
50
50
|
];
|
|
51
51
|
|
|
52
52
|
const REQUIRED_PERSONAS = ['logic-adversary.md', 'architect.md'];
|
|
53
|
-
const REQUIRED_RUBRICS = ['logic-constitution-v1.md', 'logic-constitution-v2.md'];
|
|
53
|
+
const REQUIRED_RUBRICS = ['logic-constitution-v1.md', 'logic-constitution-v2.md', 'logic-constitution-v3.md'];
|
|
54
54
|
|
|
55
55
|
// ARCH-002 fix (2026-04-13): use shared parseArgs from flow-cli-utils
|
|
56
56
|
const { parseArgs } = require('./flow-cli-utils');
|
package/scripts/flow-migrate.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
const fs = require('node:fs');
|
|
29
29
|
const path = require('node:path');
|
|
30
|
-
const { getProjectRoot, getConfig, PATHS, colors, readJson } = require('./flow-utils');
|
|
30
|
+
const { getProjectRoot, getConfig, PATHS, colors, readJson, getTodayDate } = require('./flow-utils');
|
|
31
31
|
|
|
32
32
|
const ADAPTERS_DIR = PATHS.modelAdapters;
|
|
33
33
|
const MODEL_STATS_PATH = PATHS.modelStatsLegacy;
|
|
@@ -113,7 +113,11 @@ function writeConfig(config) {
|
|
|
113
113
|
* @returns {Object} Models config or empty structure
|
|
114
114
|
*/
|
|
115
115
|
function getModelsConfig() {
|
|
116
|
-
|
|
116
|
+
// Use canonical getConfig() for reads — readConfig() is kept only for
|
|
117
|
+
// read-modify-write paths (updateModelsConfig, migrateOldConfig) where a
|
|
118
|
+
// cached reference would cause mutation bugs. (wf-7072d3ac / dup-006)
|
|
119
|
+
const { getConfig } = require('./flow-config-loader');
|
|
120
|
+
const config = getConfig();
|
|
117
121
|
return config.models || { providers: {}, defaults: {} };
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -587,7 +587,7 @@ function logTokenMetrics(plan, executionResult, complexity) {
|
|
|
587
587
|
const metricsPath = path.join(PATHS.state, 'hybrid-metrics.json');
|
|
588
588
|
|
|
589
589
|
// Load existing metrics or create new array
|
|
590
|
-
|
|
590
|
+
let metrics = readJson(metricsPath, []);
|
|
591
591
|
|
|
592
592
|
// Add new metric entry
|
|
593
593
|
const entry = {
|
|
@@ -1436,7 +1436,7 @@ class Orchestrator {
|
|
|
1436
1436
|
taskType: result.taskType || taskType,
|
|
1437
1437
|
success: true
|
|
1438
1438
|
});
|
|
1439
|
-
} catch (
|
|
1439
|
+
} catch (_err) {
|
|
1440
1440
|
// Non-critical, continue
|
|
1441
1441
|
}
|
|
1442
1442
|
|
|
@@ -1510,7 +1510,7 @@ class Orchestrator {
|
|
|
1510
1510
|
log('dim', ` 📚 Applied learning from failure: ${failureLearning.learning?.category || 'unknown'}`);
|
|
1511
1511
|
continue; // Skip default refinement, use learning-based enhancement
|
|
1512
1512
|
}
|
|
1513
|
-
} catch (
|
|
1513
|
+
} catch (_err) {
|
|
1514
1514
|
// Non-critical, fall back to standard refinement
|
|
1515
1515
|
}
|
|
1516
1516
|
|
package/scripts/flow-output.js
CHANGED
|
@@ -182,6 +182,34 @@ function escapeRegex(str) {
|
|
|
182
182
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Canonical slugify — consolidates 4 duplicate impls across scripts/ per audit
|
|
187
|
+
* dup-003 (wf-7072d3ac, 2026-04-15).
|
|
188
|
+
*
|
|
189
|
+
* @param {string} str
|
|
190
|
+
* @param {Object} [opts]
|
|
191
|
+
* @param {'alnum'|'word'} [opts.mode='alnum']
|
|
192
|
+
* 'alnum' — strips everything except [a-z0-9]+ (2026 matches old auto-learn/session-learning/rules-sync behavior).
|
|
193
|
+
* 'word' — preserves word chars incl. underscores (old flow-story behavior).
|
|
194
|
+
* @param {number} [opts.maxLength] — truncate to this many chars (unset = unbounded).
|
|
195
|
+
* @returns {string}
|
|
196
|
+
*/
|
|
197
|
+
function slugify(str, opts = {}) {
|
|
198
|
+
const { mode = 'alnum', maxLength } = opts;
|
|
199
|
+
if (!str || typeof str !== 'string') return '';
|
|
200
|
+
let s = str.toLowerCase().trim();
|
|
201
|
+
if (mode === 'word') {
|
|
202
|
+
s = s
|
|
203
|
+
.replace(/[^\w\s-]/g, '') // strip non-word chars except space/hyphen
|
|
204
|
+
.replace(/[\s_]+/g, '-'); // space/underscore → hyphen
|
|
205
|
+
} else {
|
|
206
|
+
s = s.replace(/[^a-z0-9]+/g, '-'); // single pass: anything non-alnum → hyphen
|
|
207
|
+
}
|
|
208
|
+
s = s.replace(/-+/g, '-').replace(/^-+|-+$/g, '');
|
|
209
|
+
if (Number.isFinite(maxLength) && maxLength > 0) s = s.slice(0, maxLength);
|
|
210
|
+
return s;
|
|
211
|
+
}
|
|
212
|
+
|
|
185
213
|
module.exports = {
|
|
186
214
|
colors,
|
|
187
215
|
color,
|
|
@@ -195,4 +223,5 @@ module.exports = {
|
|
|
195
223
|
showHelp,
|
|
196
224
|
escapeRegex,
|
|
197
225
|
getTodayDate,
|
|
226
|
+
slugify,
|
|
198
227
|
};
|
package/scripts/flow-parallel.js
CHANGED
|
@@ -281,9 +281,9 @@ async function executeParallel(tasks, executor, options = {}) {
|
|
|
281
281
|
try {
|
|
282
282
|
if (tracker) tracker.start(task.id);
|
|
283
283
|
if (onStart) onStart(task);
|
|
284
|
-
} catch (
|
|
284
|
+
} catch (err) {
|
|
285
285
|
// Don't let callback errors prevent task execution
|
|
286
|
-
console.warn(`Callback error for ${task.id}: ${
|
|
286
|
+
console.warn(`Callback error for ${task.id}: ${err.message}`);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
try {
|
|
@@ -294,22 +294,23 @@ async function executeParallel(tasks, executor, options = {}) {
|
|
|
294
294
|
try {
|
|
295
295
|
if (tracker) tracker.complete(task.id, result);
|
|
296
296
|
if (onComplete) onComplete(task, result);
|
|
297
|
-
} catch (
|
|
298
|
-
console.warn(`Completion callback error for ${task.id}: ${
|
|
297
|
+
} catch (err) {
|
|
298
|
+
console.warn(`Completion callback error for ${task.id}: ${err.message}`);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
return { taskId: task.id, success: true, result };
|
|
302
302
|
} catch (err) {
|
|
303
303
|
finished.add(task.id); // Mark as finished but NOT succeeded
|
|
304
304
|
|
|
305
|
+
const outerErr = err;
|
|
305
306
|
try {
|
|
306
|
-
if (tracker) tracker.fail(task.id,
|
|
307
|
-
if (onError) onError(task,
|
|
308
|
-
} catch (
|
|
309
|
-
console.warn(`Error callback error for ${task.id}: ${
|
|
307
|
+
if (tracker) tracker.fail(task.id, outerErr);
|
|
308
|
+
if (onError) onError(task, outerErr);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.warn(`Error callback error for ${task.id}: ${err.message}`);
|
|
310
311
|
}
|
|
311
312
|
|
|
312
|
-
return { taskId: task.id, success: false, error:
|
|
313
|
+
return { taskId: task.id, success: false, error: outerErr.message };
|
|
313
314
|
}
|
|
314
315
|
});
|
|
315
316
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Permission Rule Audit (Claude Code settings.local.json)
|
|
5
|
+
*
|
|
6
|
+
* Analyzes Claude Code permission rules (e.g., 'Bash(git:*)') for duplicates,
|
|
7
|
+
* overly broad wildcards, and redundant specific rules covered by wildcards.
|
|
8
|
+
* Extracted from flow-utils.js (wf-94cc3b72 epic — decomposition pass).
|
|
9
|
+
*
|
|
10
|
+
* Separate from flow-permissions.js (which manages user permission grants
|
|
11
|
+
* for WogiFlow operations) — these audit the upstream Claude Code config.
|
|
12
|
+
*
|
|
13
|
+
* Pure functions with no filesystem side effects. Zero external deps.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Analyze permission rules for issues
|
|
20
|
+
* @param {string[]} permissions - Array of permission rule strings
|
|
21
|
+
* @returns {Object} Analysis result with duplicates, overbroad, shadowed, total
|
|
22
|
+
*/
|
|
23
|
+
function analyzePermissions(permissions) {
|
|
24
|
+
const result = {
|
|
25
|
+
duplicates: [],
|
|
26
|
+
overbroad: [],
|
|
27
|
+
shadowed: [],
|
|
28
|
+
total: permissions.length
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Check for duplicates
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
for (const perm of permissions) {
|
|
34
|
+
if (seen.has(perm)) {
|
|
35
|
+
result.duplicates.push(perm);
|
|
36
|
+
}
|
|
37
|
+
seen.add(perm);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check for overly broad patterns (wildcards on core tools)
|
|
41
|
+
const overbroadPatterns = ['Bash(*)', 'Edit(*)', 'Write(*)', 'Read(*)'];
|
|
42
|
+
for (const perm of permissions) {
|
|
43
|
+
if (overbroadPatterns.includes(perm)) {
|
|
44
|
+
result.overbroad.push(perm);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check for shadowed rules (specific rules covered by wildcards)
|
|
49
|
+
const wildcards = permissions.filter(p => p.includes('*'));
|
|
50
|
+
const specific = permissions.filter(p => !p.includes('*'));
|
|
51
|
+
|
|
52
|
+
for (const spec of specific) {
|
|
53
|
+
const match = spec.match(/^(\w+)\((.+)\)$/);
|
|
54
|
+
if (match) {
|
|
55
|
+
const [, tool, pattern] = match;
|
|
56
|
+
for (const wild of wildcards) {
|
|
57
|
+
const wildMatch = wild.match(/^(\w+)\((.+)\)$/);
|
|
58
|
+
if (wildMatch && wildMatch[1] === tool) {
|
|
59
|
+
const wildPattern = wildMatch[2].replace(/\*/g, '.*');
|
|
60
|
+
try {
|
|
61
|
+
const regex = new RegExp(`^${wildPattern}$`);
|
|
62
|
+
if (regex.test(pattern)) {
|
|
63
|
+
result.shadowed.push({ specific: spec, wildcard: wild });
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
} catch (_err) {
|
|
67
|
+
// Invalid regex, skip
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Validate permission rules and return classified issues + warnings.
|
|
79
|
+
* @param {string[]} permissions - Array of permission rules
|
|
80
|
+
* @returns {Object} { valid, issues, warnings, analysis }
|
|
81
|
+
*/
|
|
82
|
+
function validatePermissions(permissions) {
|
|
83
|
+
const analysis = analyzePermissions(permissions);
|
|
84
|
+
|
|
85
|
+
const issues = [];
|
|
86
|
+
const warnings = [];
|
|
87
|
+
|
|
88
|
+
if (analysis.duplicates.length > 0) {
|
|
89
|
+
warnings.push({
|
|
90
|
+
type: 'duplicate',
|
|
91
|
+
message: `${analysis.duplicates.length} duplicate rule(s) found`,
|
|
92
|
+
items: analysis.duplicates
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (analysis.overbroad.length > 0) {
|
|
97
|
+
issues.push({
|
|
98
|
+
type: 'overbroad',
|
|
99
|
+
severity: 'critical',
|
|
100
|
+
message: `${analysis.overbroad.length} overly broad rule(s) found`,
|
|
101
|
+
items: analysis.overbroad
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (analysis.shadowed.length > 0) {
|
|
106
|
+
warnings.push({
|
|
107
|
+
type: 'shadowed',
|
|
108
|
+
message: `${analysis.shadowed.length} rule(s) shadowed by wildcards (redundant)`,
|
|
109
|
+
items: analysis.shadowed.map(s => s.specific)
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
valid: issues.length === 0,
|
|
115
|
+
issues,
|
|
116
|
+
warnings,
|
|
117
|
+
analysis
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = {
|
|
122
|
+
analyzePermissions,
|
|
123
|
+
validatePermissions,
|
|
124
|
+
};
|
|
@@ -29,8 +29,8 @@ const {
|
|
|
29
29
|
printHeader, PATHS
|
|
30
30
|
} = require('./flow-utils');
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
const DANGEROUS_KEYS =
|
|
32
|
+
// Local DANGEROUS_KEYS consolidated to flow-io canonical (wf-2f6fbb12 / dup-002).
|
|
33
|
+
const { DANGEROUS_KEYS } = require('./flow-io');
|
|
34
34
|
|
|
35
35
|
// Allowlists for capability fields
|
|
36
36
|
const VALID_MODES = new Set(['standalone', 'flow-integrated', 'trigger']);
|
package/scripts/flow-progress.js
CHANGED
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const readline = require('node:readline/promises');
|
|
10
|
-
const { colors } = require('./flow-utils');
|
|
10
|
+
const { colors, getTodayDate } = require('./flow-utils');
|
|
11
|
+
|
|
12
|
+
// ANSI escape prefix (was referenced as ESC without definition — latent
|
|
13
|
+
// no-undef bug caught by eslint upgrade; wf-5a6df88a)
|
|
14
|
+
const ESC = '\x1b';
|
|
11
15
|
|
|
12
16
|
const symbols = {
|
|
13
17
|
success: '✅',
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
const fs = require('node:fs');
|
|
14
14
|
const path = require('node:path');
|
|
15
|
-
const { getProjectRoot, safeJsonParse, getConfig } = require('./flow-utils');
|
|
15
|
+
const { getProjectRoot, safeJsonParse, getConfig, getTodayDate } = require('./flow-utils');
|
|
16
16
|
|
|
17
17
|
const PROJECT_ROOT = process.argv[2] || getProjectRoot();
|
|
18
18
|
|