wogiflow 2.1.3 → 2.3.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 +189 -3
- package/.claude/commands/wogi-onboard.md +30 -8
- package/.claude/commands/wogi-review.md +86 -13
- package/.claude/commands/wogi-start.md +66 -21
- package/.claude/docs/claude-code-compatibility.md +28 -0
- package/.workflow/templates/claude-md.hbs +32 -2
- package/package.json +1 -1
- package/scripts/flow-api-index.js +128 -63
- package/scripts/flow-audit.js +158 -1
- package/scripts/flow-function-index.js +65 -63
- package/scripts/flow-pattern-extractor.js +1 -1
- package/scripts/flow-progress-tracker.js +289 -0
- package/scripts/flow-prompt-capture.js +263 -170
- package/scripts/flow-scanner-base.js +200 -7
- package/scripts/flow-skill-generator.js +1 -0
- package/scripts/flow-standards-learner.js +167 -3
- package/scripts/flow-task-checkpoint.js +2 -0
- package/scripts/flow-template-extractor.js +1 -1
- package/scripts/flow-version-check.js +1 -0
- package/scripts/hooks/core/commit-log-gate.js +146 -0
- package/scripts/hooks/core/post-compact.js +81 -8
- package/scripts/hooks/core/task-completed.js +19 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +60 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +27 -0
- package/scripts/registries/component-registry.js +141 -4
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Progress Tracker
|
|
5
|
+
*
|
|
6
|
+
* Manages progress state for long-running tasks (reviews, audits, multi-criteria).
|
|
7
|
+
* Writes to .workflow/state/task-progress.json for hook/status line consumption.
|
|
8
|
+
* Optionally updates task title in ready.json with progress prefix for status line.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* flow-progress-tracker.js update <json> Update progress state
|
|
12
|
+
* flow-progress-tracker.js get Get current progress
|
|
13
|
+
* flow-progress-tracker.js clear Clear progress state
|
|
14
|
+
* flow-progress-tracker.js format <json> Format a progress bar string
|
|
15
|
+
*
|
|
16
|
+
* The AI calls this at natural checkpoints during execution.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
const { PATHS, safeJsonParse, safeJsonParseString, getReadyData, saveReadyData } = require('./flow-utils');
|
|
22
|
+
|
|
23
|
+
const PROGRESS_PATH = path.join(PATHS.state, 'task-progress.json');
|
|
24
|
+
|
|
25
|
+
// ============================================================
|
|
26
|
+
// Progress State Management
|
|
27
|
+
// ============================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Update the progress state file.
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} progress
|
|
33
|
+
* @param {string} progress.taskId - Current task ID
|
|
34
|
+
* @param {string} progress.command - Command running (e.g., "/wogi-review")
|
|
35
|
+
* @param {string} progress.phase - Current phase name
|
|
36
|
+
* @param {number} progress.phaseNum - Current phase number (1-based)
|
|
37
|
+
* @param {number} progress.totalPhases - Total phases
|
|
38
|
+
* @param {string} [progress.step] - Current sub-step description
|
|
39
|
+
* @param {number} [progress.stepNum] - Current sub-step number
|
|
40
|
+
* @param {number} [progress.totalSteps] - Total sub-steps in this phase
|
|
41
|
+
* @param {boolean} [progress.updateTitle] - Update task title in ready.json
|
|
42
|
+
* @returns {{ saved: boolean }}
|
|
43
|
+
*/
|
|
44
|
+
function updateProgress(progress) {
|
|
45
|
+
const state = {
|
|
46
|
+
taskId: progress.taskId,
|
|
47
|
+
command: progress.command,
|
|
48
|
+
phase: progress.phase,
|
|
49
|
+
phaseNum: progress.phaseNum || 0,
|
|
50
|
+
totalPhases: progress.totalPhases || 0,
|
|
51
|
+
step: progress.step || null,
|
|
52
|
+
stepNum: progress.stepNum || 0,
|
|
53
|
+
totalSteps: progress.totalSteps || 0,
|
|
54
|
+
percentage: calculatePercentage(progress),
|
|
55
|
+
startedAt: getExistingStartTime() || new Date().toISOString(),
|
|
56
|
+
lastUpdate: new Date().toISOString()
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
fs.mkdirSync(path.dirname(PROGRESS_PATH), { recursive: true });
|
|
61
|
+
fs.writeFileSync(PROGRESS_PATH, JSON.stringify(state, null, 2));
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { saved: false, reason: err.message };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Update task title in ready.json for status line visibility (opt-in)
|
|
67
|
+
if (progress.updateTitle === true && state.taskId) {
|
|
68
|
+
updateTaskTitle(state);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { saved: true, state };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Calculate progress percentage from phase/step numbers.
|
|
76
|
+
*/
|
|
77
|
+
function calculatePercentage(progress) {
|
|
78
|
+
const { phaseNum, totalPhases, stepNum, totalSteps } = progress;
|
|
79
|
+
if (!totalPhases || !phaseNum) return 0;
|
|
80
|
+
|
|
81
|
+
// Phase-level progress
|
|
82
|
+
const phaseProgress = ((phaseNum - 1) / totalPhases) * 100;
|
|
83
|
+
|
|
84
|
+
// Step-level progress within the current phase
|
|
85
|
+
const phaseWeight = 100 / totalPhases;
|
|
86
|
+
const stepProgress = (totalSteps && stepNum)
|
|
87
|
+
? (stepNum / totalSteps) * phaseWeight
|
|
88
|
+
: 0;
|
|
89
|
+
|
|
90
|
+
return Math.min(100, Math.round(phaseProgress + stepProgress));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get existing start time to preserve across updates.
|
|
95
|
+
*/
|
|
96
|
+
function getExistingStartTime() {
|
|
97
|
+
try {
|
|
98
|
+
const existing = safeJsonParse(PROGRESS_PATH, null);
|
|
99
|
+
return existing?.startedAt || null;
|
|
100
|
+
} catch (err) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Update task title in ready.json with progress prefix.
|
|
107
|
+
* Format: "[2/5] Original title"
|
|
108
|
+
*/
|
|
109
|
+
function updateTaskTitle(state) {
|
|
110
|
+
try {
|
|
111
|
+
const data = getReadyData();
|
|
112
|
+
const task = data.inProgress.find(t => t.id === state.taskId);
|
|
113
|
+
if (!task) return;
|
|
114
|
+
|
|
115
|
+
// Strip any existing progress prefix
|
|
116
|
+
const cleanTitle = task.title.replace(/^\[\d+\/\d+\]\s*/, '');
|
|
117
|
+
|
|
118
|
+
// Add new prefix
|
|
119
|
+
task.title = `[${state.phaseNum}/${state.totalPhases}] ${cleanTitle}`;
|
|
120
|
+
saveReadyData(data);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
// Non-fatal — title update is cosmetic
|
|
123
|
+
if (process.env.DEBUG) {
|
|
124
|
+
console.error(`[progress-tracker] Title update failed: ${err.message}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get current progress state.
|
|
131
|
+
* @returns {Object|null}
|
|
132
|
+
*/
|
|
133
|
+
function getProgress() {
|
|
134
|
+
return safeJsonParse(PROGRESS_PATH, null);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Clear progress state (called on task completion).
|
|
139
|
+
*
|
|
140
|
+
* NOTE: Title restoration (stripping [N/M] prefix) is handled inside the
|
|
141
|
+
* task-completed hook's withLock() callback to avoid race conditions on ready.json.
|
|
142
|
+
* This function only deletes the progress state file.
|
|
143
|
+
*/
|
|
144
|
+
function clearProgress() {
|
|
145
|
+
try {
|
|
146
|
+
fs.unlinkSync(PROGRESS_PATH);
|
|
147
|
+
return { cleared: true };
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (err.code === 'ENOENT') return { cleared: true };
|
|
150
|
+
return { cleared: false, reason: err.message };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Format a progress bar string for conversation output.
|
|
156
|
+
*
|
|
157
|
+
* @param {Object} opts
|
|
158
|
+
* @param {number} opts.current - Current step
|
|
159
|
+
* @param {number} opts.total - Total steps
|
|
160
|
+
* @param {string} opts.label - Label text
|
|
161
|
+
* @param {number} [opts.width=20] - Bar width
|
|
162
|
+
* @returns {string} Formatted progress line
|
|
163
|
+
*/
|
|
164
|
+
function formatProgressBar(opts) {
|
|
165
|
+
const { current, total, label, width = 20 } = opts;
|
|
166
|
+
const pct = total > 0 ? Math.round((current / total) * 100) : 0;
|
|
167
|
+
const filled = total > 0 ? Math.round((current / total) * width) : 0;
|
|
168
|
+
const empty = width - filled;
|
|
169
|
+
|
|
170
|
+
const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
|
|
171
|
+
return `[${bar}] ${pct}% ${label} (${current}/${total})`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Format a multi-level progress display for conversation output.
|
|
176
|
+
*
|
|
177
|
+
* @param {Object} opts
|
|
178
|
+
* @param {string} opts.command - Command name
|
|
179
|
+
* @param {string} opts.phase - Current phase
|
|
180
|
+
* @param {number} opts.phaseNum
|
|
181
|
+
* @param {number} opts.totalPhases
|
|
182
|
+
* @param {string} [opts.step] - Current step within phase
|
|
183
|
+
* @param {number} [opts.stepNum]
|
|
184
|
+
* @param {number} [opts.totalSteps]
|
|
185
|
+
* @returns {string} Multi-line progress display
|
|
186
|
+
*/
|
|
187
|
+
function formatProgress(opts) {
|
|
188
|
+
const lines = [];
|
|
189
|
+
const pct = calculatePercentage(opts);
|
|
190
|
+
|
|
191
|
+
// Phase-level bar
|
|
192
|
+
lines.push(formatProgressBar({
|
|
193
|
+
current: opts.phaseNum,
|
|
194
|
+
total: opts.totalPhases,
|
|
195
|
+
label: opts.phase
|
|
196
|
+
}));
|
|
197
|
+
|
|
198
|
+
// Step-level detail (if applicable)
|
|
199
|
+
if (opts.step && opts.totalSteps) {
|
|
200
|
+
lines.push(` ${opts.step} (${opts.stepNum}/${opts.totalSteps})`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return lines.join('\n');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ============================================================
|
|
207
|
+
// CLI Interface
|
|
208
|
+
// ============================================================
|
|
209
|
+
|
|
210
|
+
function main() {
|
|
211
|
+
const command = process.argv[2];
|
|
212
|
+
const arg = process.argv[3];
|
|
213
|
+
|
|
214
|
+
switch (command) {
|
|
215
|
+
case 'update': {
|
|
216
|
+
if (!arg) {
|
|
217
|
+
console.error('Usage: flow-progress-tracker.js update \'{"taskId":"...","phase":"...","phaseNum":1,"totalPhases":5}\'');
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const progress = safeJsonParseString(arg, null);
|
|
221
|
+
if (!progress) {
|
|
222
|
+
console.error('Invalid JSON argument');
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
const result = updateProgress(progress);
|
|
226
|
+
console.log(JSON.stringify(result, null, 2));
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
case 'get': {
|
|
231
|
+
const state = getProgress();
|
|
232
|
+
if (state) {
|
|
233
|
+
console.log(JSON.stringify(state, null, 2));
|
|
234
|
+
} else {
|
|
235
|
+
console.log(JSON.stringify({ active: false }));
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
case 'clear': {
|
|
241
|
+
const result = clearProgress();
|
|
242
|
+
console.log(JSON.stringify(result, null, 2));
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
case 'format': {
|
|
247
|
+
if (!arg) {
|
|
248
|
+
console.error('Usage: flow-progress-tracker.js format \'{"current":2,"total":5,"label":"Phase"}\'');
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
const opts = safeJsonParseString(arg, null);
|
|
252
|
+
if (!opts) {
|
|
253
|
+
console.error('Invalid JSON argument');
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
console.log(formatProgressBar(opts));
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
default:
|
|
261
|
+
console.log(`
|
|
262
|
+
Wogi Flow - Progress Tracker
|
|
263
|
+
|
|
264
|
+
Usage: flow-progress-tracker.js <command> [args]
|
|
265
|
+
|
|
266
|
+
Commands:
|
|
267
|
+
update <json> Update progress state + task title
|
|
268
|
+
get Get current progress state
|
|
269
|
+
clear Clear progress state
|
|
270
|
+
format <json> Format a progress bar string
|
|
271
|
+
|
|
272
|
+
Update format:
|
|
273
|
+
{"taskId":"wf-xxx","command":"/wogi-review","phase":"AI Review","phaseNum":2,"totalPhases":5}
|
|
274
|
+
`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = {
|
|
279
|
+
updateProgress,
|
|
280
|
+
getProgress,
|
|
281
|
+
clearProgress,
|
|
282
|
+
formatProgressBar,
|
|
283
|
+
formatProgress,
|
|
284
|
+
calculatePercentage
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
if (require.main === module) {
|
|
288
|
+
main();
|
|
289
|
+
}
|