wogiflow 1.0.12 → 1.0.13
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/.workflow/specs/architecture.md.template +24 -0
- package/.workflow/specs/stack.md.template +33 -0
- package/.workflow/specs/testing.md.template +36 -0
- package/README.md +90 -1
- package/package.json +1 -1
- package/scripts/MEMORY-ARCHITECTURE.md +150 -0
- package/scripts/flow +20 -19
- package/scripts/flow-auto-context.js +97 -3
- package/scripts/flow-conflict-resolver.js +735 -0
- package/scripts/flow-context-gatherer.js +520 -0
- package/scripts/flow-context-monitor.js +148 -19
- package/scripts/flow-damage-control.js +5 -1
- package/scripts/flow-export-profile +168 -1
- package/scripts/flow-import-profile +257 -6
- package/scripts/flow-instruction-richness.js +182 -18
- package/scripts/flow-knowledge-router.js +2 -0
- package/scripts/flow-knowledge-sync.js +2 -0
- package/scripts/{flow-transcript-chunking.js → flow-long-input-chunking.js} +4 -2
- package/scripts/{flow-transcript-parsing.js → flow-long-input-parsing.js} +35 -0
- package/scripts/{flow-transcript-stories.js → flow-long-input-stories.js} +86 -38
- package/scripts/{flow-transcript-digest.js → flow-long-input.js} +231 -15
- package/scripts/flow-memory-db.js +386 -1
- package/scripts/flow-memory-sync.js +2 -0
- package/scripts/flow-model-adapter.js +53 -29
- package/scripts/flow-model-router.js +246 -1
- package/scripts/flow-morning.js +94 -0
- package/scripts/flow-onboard +223 -10
- package/scripts/flow-orchestrate-validation.js +539 -0
- package/scripts/flow-orchestrate.js +16 -507
- package/scripts/flow-pattern-extractor.js +1265 -0
- package/scripts/flow-prompt-composer.js +222 -2
- package/scripts/flow-quality-guard.js +594 -0
- package/scripts/flow-section-index.js +713 -0
- package/scripts/flow-section-resolver.js +484 -0
- package/scripts/flow-session-end.js +188 -2
- package/scripts/flow-skill-create.js +19 -3
- package/scripts/flow-skill-matcher.js +122 -7
- package/scripts/flow-statusline-setup.js +218 -0
- package/scripts/flow-step-review.js +19 -0
- package/scripts/flow-tech-debt.js +734 -0
- package/scripts/flow-utils.js +2 -0
- package/scripts/hooks/core/long-input-gate.js +293 -0
- package/scripts/flow-parallel-detector.js +0 -399
- package/scripts/flow-parallel-dispatch.js +0 -987
- /package/scripts/{flow-transcript-language.js → flow-long-input-language.js} +0 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Dynamic Context Gatherer
|
|
5
|
+
*
|
|
6
|
+
* Intelligently gathers context for tasks based on:
|
|
7
|
+
* - Task description analysis
|
|
8
|
+
* - Section-level references (not full files)
|
|
9
|
+
* - Model context preferences
|
|
10
|
+
* - Token budget optimization
|
|
11
|
+
*
|
|
12
|
+
* Replaces hardcoded limits with dynamic, quality-aware selection.
|
|
13
|
+
*
|
|
14
|
+
* Part of Smart Context System (Phase 2)
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* const { gatherContext } = require('./flow-context-gatherer');
|
|
18
|
+
*
|
|
19
|
+
* const context = await gatherContext({
|
|
20
|
+
* task: 'Add user authentication',
|
|
21
|
+
* model: 'claude-sonnet-4',
|
|
22
|
+
* maxTokens: 50000
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
PATHS,
|
|
31
|
+
getConfig,
|
|
32
|
+
fileExists,
|
|
33
|
+
readFile,
|
|
34
|
+
estimateTokens,
|
|
35
|
+
info,
|
|
36
|
+
warn,
|
|
37
|
+
success
|
|
38
|
+
} = require('./flow-utils');
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
getSectionsForTask,
|
|
42
|
+
getSecuritySections,
|
|
43
|
+
getComponentSections,
|
|
44
|
+
getNamingConventionSections,
|
|
45
|
+
formatSectionsAsContext,
|
|
46
|
+
ensureIndex
|
|
47
|
+
} = require('./flow-section-resolver');
|
|
48
|
+
|
|
49
|
+
// Use model preferences from instruction-richness (single source of truth)
|
|
50
|
+
const { getModelContextPreferences } = require('./flow-instruction-richness');
|
|
51
|
+
|
|
52
|
+
// ============================================================
|
|
53
|
+
// Configuration
|
|
54
|
+
// ============================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Default context gathering configuration
|
|
58
|
+
*/
|
|
59
|
+
const DEFAULT_CONFIG = {
|
|
60
|
+
strategy: 'dynamic', // 'dynamic' | 'fixed'
|
|
61
|
+
maxContextTokens: 100000,
|
|
62
|
+
reserveOutputTokens: 8000,
|
|
63
|
+
minRelevanceScore: 0.1,
|
|
64
|
+
fallbackToFullContext: true,
|
|
65
|
+
includeContent: true,
|
|
66
|
+
useSectionReferences: true,
|
|
67
|
+
fallbackLimits: {
|
|
68
|
+
maxFilesHard: 50,
|
|
69
|
+
maxTokensHard: 150000
|
|
70
|
+
},
|
|
71
|
+
// Maximum budget overflow allowed for forced includes (10%)
|
|
72
|
+
maxBudgetOverflow: 0.1
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Context type priorities
|
|
77
|
+
*/
|
|
78
|
+
const CONTEXT_PRIORITIES = {
|
|
79
|
+
security_rules: 1.0,
|
|
80
|
+
required_patterns: 0.95,
|
|
81
|
+
target_sections: 0.90,
|
|
82
|
+
component_rules: 0.85,
|
|
83
|
+
naming_conventions: 0.80,
|
|
84
|
+
related_sections: 0.70,
|
|
85
|
+
general_patterns: 0.60
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ============================================================
|
|
89
|
+
// Configuration Loading
|
|
90
|
+
// ============================================================
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get context gathering configuration
|
|
94
|
+
*/
|
|
95
|
+
function getContextConfig() {
|
|
96
|
+
const config = getConfig();
|
|
97
|
+
return {
|
|
98
|
+
...DEFAULT_CONFIG,
|
|
99
|
+
...(config.autoContext || {})
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get model context preferences
|
|
105
|
+
* Uses the single source of truth from flow-instruction-richness.js
|
|
106
|
+
* @param {string} modelName - Model name
|
|
107
|
+
* @returns {Object} - Context preferences for the model
|
|
108
|
+
*/
|
|
109
|
+
function getModelPreferences(modelName) {
|
|
110
|
+
return getModelContextPreferences(modelName);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============================================================
|
|
114
|
+
// Task Analysis
|
|
115
|
+
// ============================================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Analyze task to determine context requirements
|
|
119
|
+
* @param {string} taskDescription - Task description
|
|
120
|
+
* @returns {Object} - Task analysis
|
|
121
|
+
*/
|
|
122
|
+
function analyzeTask(taskDescription) {
|
|
123
|
+
const descLower = taskDescription.toLowerCase();
|
|
124
|
+
|
|
125
|
+
const analysis = {
|
|
126
|
+
needsSecurityContext: false,
|
|
127
|
+
needsComponentContext: false,
|
|
128
|
+
needsNamingContext: false,
|
|
129
|
+
needsAPIContext: false,
|
|
130
|
+
needsFileContext: false,
|
|
131
|
+
complexity: 'medium',
|
|
132
|
+
estimatedContextNeeds: 'standard'
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Security keywords
|
|
136
|
+
if (/security|auth|password|token|encrypt|validate|sanitize|injection/i.test(descLower)) {
|
|
137
|
+
analysis.needsSecurityContext = true;
|
|
138
|
+
analysis.estimatedContextNeeds = 'high';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Component keywords
|
|
142
|
+
if (/component|button|input|form|modal|dialog|ui|widget|screen/i.test(descLower)) {
|
|
143
|
+
analysis.needsComponentContext = true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Naming/style keywords
|
|
147
|
+
if (/name|rename|naming|convention|style|format|file/i.test(descLower)) {
|
|
148
|
+
analysis.needsNamingContext = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// API keywords
|
|
152
|
+
if (/api|endpoint|route|controller|service|request|response/i.test(descLower)) {
|
|
153
|
+
analysis.needsAPIContext = true;
|
|
154
|
+
analysis.estimatedContextNeeds = 'high';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// File operation keywords
|
|
158
|
+
if (/file|read|write|fs|path|directory/i.test(descLower)) {
|
|
159
|
+
analysis.needsFileContext = true;
|
|
160
|
+
analysis.needsSecurityContext = true; // File ops need security rules
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Complexity estimation
|
|
164
|
+
const wordCount = taskDescription.split(/\s+/).length;
|
|
165
|
+
if (wordCount < 10) {
|
|
166
|
+
analysis.complexity = 'small';
|
|
167
|
+
analysis.estimatedContextNeeds = 'minimal';
|
|
168
|
+
} else if (wordCount > 50) {
|
|
169
|
+
analysis.complexity = 'large';
|
|
170
|
+
analysis.estimatedContextNeeds = 'high';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return analysis;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ============================================================
|
|
177
|
+
// Context Gathering
|
|
178
|
+
// ============================================================
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Gather all potentially relevant sections for a task
|
|
182
|
+
* @param {string} taskDescription - Task description
|
|
183
|
+
* @param {Object} taskAnalysis - Task analysis from analyzeTask()
|
|
184
|
+
* @returns {Object[]} - All relevant sections with priorities
|
|
185
|
+
*/
|
|
186
|
+
async function gatherAllSections(taskDescription, taskAnalysis) {
|
|
187
|
+
const sections = [];
|
|
188
|
+
|
|
189
|
+
// Ensure index is up to date
|
|
190
|
+
await ensureIndex();
|
|
191
|
+
|
|
192
|
+
// 1. Get sections directly matching task description
|
|
193
|
+
const taskSections = await getSectionsForTask(taskDescription, {
|
|
194
|
+
limit: 10,
|
|
195
|
+
minScore: 0.05
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
for (const section of taskSections) {
|
|
199
|
+
sections.push({
|
|
200
|
+
...section,
|
|
201
|
+
priority: CONTEXT_PRIORITIES.target_sections,
|
|
202
|
+
reason: 'Matches task description'
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 2. Add security sections if needed
|
|
207
|
+
if (taskAnalysis.needsSecurityContext) {
|
|
208
|
+
const securitySections = await getSecuritySections();
|
|
209
|
+
for (const section of securitySections) {
|
|
210
|
+
if (!sections.find(s => s.id === section.id)) {
|
|
211
|
+
sections.push({
|
|
212
|
+
...section,
|
|
213
|
+
priority: CONTEXT_PRIORITIES.security_rules,
|
|
214
|
+
reason: 'Task involves security-sensitive operations'
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 3. Add component sections if needed
|
|
221
|
+
if (taskAnalysis.needsComponentContext) {
|
|
222
|
+
const componentSections = await getComponentSections();
|
|
223
|
+
for (const section of componentSections) {
|
|
224
|
+
if (!sections.find(s => s.id === section.id)) {
|
|
225
|
+
sections.push({
|
|
226
|
+
...section,
|
|
227
|
+
priority: CONTEXT_PRIORITIES.component_rules,
|
|
228
|
+
reason: 'Task involves UI components'
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 4. Add naming convention sections if needed
|
|
235
|
+
if (taskAnalysis.needsNamingContext) {
|
|
236
|
+
const namingSections = await getNamingConventionSections();
|
|
237
|
+
for (const section of namingSections) {
|
|
238
|
+
if (!sections.find(s => s.id === section.id)) {
|
|
239
|
+
sections.push({
|
|
240
|
+
...section,
|
|
241
|
+
priority: CONTEXT_PRIORITIES.naming_conventions,
|
|
242
|
+
reason: 'Task involves naming/style'
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return sections;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Score and rank sections for inclusion
|
|
253
|
+
* @param {Object[]} sections - Sections to score
|
|
254
|
+
* @param {Object} taskAnalysis - Task analysis
|
|
255
|
+
* @param {Object} modelPrefs - Model preferences
|
|
256
|
+
* @returns {Object[]} - Scored and sorted sections
|
|
257
|
+
*/
|
|
258
|
+
function scoreSections(sections, taskAnalysis, modelPrefs) {
|
|
259
|
+
return sections.map(section => {
|
|
260
|
+
let score = section.priority || 0.5;
|
|
261
|
+
|
|
262
|
+
// Boost based on match score from section resolver
|
|
263
|
+
if (section.score) {
|
|
264
|
+
score = score * 0.7 + section.score * 0.3;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Boost security sections for security-sensitive tasks
|
|
268
|
+
if (taskAnalysis.needsSecurityContext && section.category?.includes('Security')) {
|
|
269
|
+
score *= 1.2;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Model-specific adjustments
|
|
273
|
+
if (modelPrefs.density === 'concise' && section.content?.length > 1000) {
|
|
274
|
+
score *= 0.8; // Prefer shorter sections for concise models
|
|
275
|
+
}
|
|
276
|
+
if (modelPrefs.density === 'comprehensive') {
|
|
277
|
+
score *= 1.1; // Include more for comprehensive models
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
...section,
|
|
282
|
+
finalScore: Math.min(score, 1.0)
|
|
283
|
+
};
|
|
284
|
+
}).sort((a, b) => b.finalScore - a.finalScore);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Fit sections within token budget
|
|
289
|
+
* @param {Object[]} scoredSections - Scored sections
|
|
290
|
+
* @param {number} tokenBudget - Available tokens
|
|
291
|
+
* @param {Object} modelPrefs - Model preferences
|
|
292
|
+
* @returns {Object} - { selected, excluded, totalTokens }
|
|
293
|
+
*/
|
|
294
|
+
function fitWithinBudget(scoredSections, tokenBudget, modelPrefs) {
|
|
295
|
+
const selected = [];
|
|
296
|
+
const excluded = [];
|
|
297
|
+
let totalTokens = 0;
|
|
298
|
+
|
|
299
|
+
// Reserve minimum context for quality
|
|
300
|
+
const minBudget = tokenBudget * modelPrefs.minContextForQuality;
|
|
301
|
+
|
|
302
|
+
// Hard ceiling to prevent budget overflow (configured max overflow, default 10%)
|
|
303
|
+
const config = getContextConfig();
|
|
304
|
+
const maxOverflow = config.maxBudgetOverflow || 0.1;
|
|
305
|
+
const hardCeiling = tokenBudget * (1 + maxOverflow);
|
|
306
|
+
|
|
307
|
+
for (const section of scoredSections) {
|
|
308
|
+
const sectionTokens = estimateTokens(section.content || '');
|
|
309
|
+
|
|
310
|
+
if (totalTokens + sectionTokens <= tokenBudget) {
|
|
311
|
+
selected.push({
|
|
312
|
+
...section,
|
|
313
|
+
tokens: sectionTokens
|
|
314
|
+
});
|
|
315
|
+
totalTokens += sectionTokens;
|
|
316
|
+
} else if (totalTokens < minBudget && totalTokens + sectionTokens <= hardCeiling) {
|
|
317
|
+
// Force include if below minimum quality threshold, but respect hard ceiling
|
|
318
|
+
selected.push({
|
|
319
|
+
...section,
|
|
320
|
+
tokens: sectionTokens,
|
|
321
|
+
forcedInclude: true
|
|
322
|
+
});
|
|
323
|
+
totalTokens += sectionTokens;
|
|
324
|
+
} else {
|
|
325
|
+
excluded.push({
|
|
326
|
+
...section,
|
|
327
|
+
tokens: sectionTokens,
|
|
328
|
+
reason: totalTokens >= hardCeiling ? 'Hard ceiling exceeded' : 'Token budget exceeded'
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
selected,
|
|
335
|
+
excluded,
|
|
336
|
+
totalTokens,
|
|
337
|
+
budgetUsed: totalTokens / tokenBudget
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ============================================================
|
|
342
|
+
// Main API
|
|
343
|
+
// ============================================================
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Gather context for a task
|
|
347
|
+
* @param {Object} params - { task, model, maxTokens, format }
|
|
348
|
+
* @returns {Object} - { context, sections, stats }
|
|
349
|
+
*/
|
|
350
|
+
async function gatherContext(params) {
|
|
351
|
+
const {
|
|
352
|
+
task,
|
|
353
|
+
model = 'claude-sonnet-4',
|
|
354
|
+
maxTokens = null,
|
|
355
|
+
format = 'full' // 'full' | 'summary' | 'reference'
|
|
356
|
+
} = params;
|
|
357
|
+
|
|
358
|
+
const config = getContextConfig();
|
|
359
|
+
const modelPrefs = getModelPreferences(model);
|
|
360
|
+
|
|
361
|
+
// Calculate token budget
|
|
362
|
+
const tokenBudget = maxTokens || (config.maxContextTokens - config.reserveOutputTokens);
|
|
363
|
+
|
|
364
|
+
// Analyze task
|
|
365
|
+
const taskAnalysis = analyzeTask(task);
|
|
366
|
+
|
|
367
|
+
// Gather all potentially relevant sections
|
|
368
|
+
const allSections = await gatherAllSections(task, taskAnalysis);
|
|
369
|
+
|
|
370
|
+
// Score and rank
|
|
371
|
+
const scoredSections = scoreSections(allSections, taskAnalysis, modelPrefs);
|
|
372
|
+
|
|
373
|
+
// Fit within budget
|
|
374
|
+
const budgetResult = fitWithinBudget(scoredSections, tokenBudget, modelPrefs);
|
|
375
|
+
|
|
376
|
+
// Format sections as context
|
|
377
|
+
const context = formatSectionsAsContext(budgetResult.selected, { format });
|
|
378
|
+
|
|
379
|
+
// Build stats
|
|
380
|
+
const stats = {
|
|
381
|
+
taskAnalysis,
|
|
382
|
+
model,
|
|
383
|
+
modelPrefs: {
|
|
384
|
+
density: modelPrefs.density,
|
|
385
|
+
minContextForQuality: modelPrefs.minContextForQuality
|
|
386
|
+
},
|
|
387
|
+
tokenBudget,
|
|
388
|
+
totalSectionsConsidered: allSections.length,
|
|
389
|
+
sectionsIncluded: budgetResult.selected.length,
|
|
390
|
+
sectionsExcluded: budgetResult.excluded.length,
|
|
391
|
+
totalTokens: budgetResult.totalTokens,
|
|
392
|
+
budgetUsed: `${(budgetResult.budgetUsed * 100).toFixed(1)}%`
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
context,
|
|
397
|
+
sections: budgetResult.selected,
|
|
398
|
+
excluded: budgetResult.excluded,
|
|
399
|
+
stats
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Quick gather - get minimal context for simple tasks
|
|
405
|
+
* @param {string} task - Task description
|
|
406
|
+
* @returns {string} - Context string
|
|
407
|
+
*/
|
|
408
|
+
async function quickGather(task) {
|
|
409
|
+
const result = await gatherContext({
|
|
410
|
+
task,
|
|
411
|
+
model: 'claude-opus-4-5',
|
|
412
|
+
maxTokens: 10000,
|
|
413
|
+
format: 'summary'
|
|
414
|
+
});
|
|
415
|
+
return result.context;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Full gather - get comprehensive context
|
|
420
|
+
* @param {string} task - Task description
|
|
421
|
+
* @param {string} model - Model name
|
|
422
|
+
* @returns {Object} - Full result with sections and stats
|
|
423
|
+
*/
|
|
424
|
+
async function fullGather(task, model = 'claude-sonnet-4') {
|
|
425
|
+
return await gatherContext({
|
|
426
|
+
task,
|
|
427
|
+
model,
|
|
428
|
+
format: 'full'
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// ============================================================
|
|
433
|
+
// CLI Interface
|
|
434
|
+
// ============================================================
|
|
435
|
+
|
|
436
|
+
async function main() {
|
|
437
|
+
const args = process.argv.slice(2);
|
|
438
|
+
const taskDesc = args.join(' ');
|
|
439
|
+
|
|
440
|
+
if (!taskDesc) {
|
|
441
|
+
console.log(`
|
|
442
|
+
Usage: node scripts/flow-context-gatherer.js "<task description>"
|
|
443
|
+
|
|
444
|
+
Options (via environment):
|
|
445
|
+
MODEL=<model> Model to optimize for (default: claude-sonnet-4)
|
|
446
|
+
TOKENS=<n> Max tokens to use (default: 92000)
|
|
447
|
+
FORMAT=<fmt> Output format: full, summary, reference (default: full)
|
|
448
|
+
|
|
449
|
+
Examples:
|
|
450
|
+
node scripts/flow-context-gatherer.js "Add user authentication"
|
|
451
|
+
MODEL=claude-opus-4-5 node scripts/flow-context-gatherer.js "Fix security bug"
|
|
452
|
+
`);
|
|
453
|
+
process.exit(0);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const model = process.env.MODEL || 'claude-sonnet-4';
|
|
457
|
+
const maxTokens = parseInt(process.env.TOKENS) || null;
|
|
458
|
+
const format = process.env.FORMAT || 'full';
|
|
459
|
+
|
|
460
|
+
info(`Gathering context for: "${taskDesc}"`);
|
|
461
|
+
info(`Model: ${model}`);
|
|
462
|
+
|
|
463
|
+
const result = await gatherContext({
|
|
464
|
+
task: taskDesc,
|
|
465
|
+
model,
|
|
466
|
+
maxTokens,
|
|
467
|
+
format
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
console.log('\n--- STATS ---');
|
|
471
|
+
console.log(JSON.stringify(result.stats, null, 2));
|
|
472
|
+
|
|
473
|
+
console.log('\n--- INCLUDED SECTIONS ---');
|
|
474
|
+
for (const section of result.sections) {
|
|
475
|
+
console.log(` ${section.id} (score: ${section.finalScore?.toFixed(2)}, tokens: ${section.tokens})`);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (result.excluded.length > 0) {
|
|
479
|
+
console.log('\n--- EXCLUDED SECTIONS ---');
|
|
480
|
+
for (const section of result.excluded.slice(0, 5)) {
|
|
481
|
+
console.log(` ${section.id} (reason: ${section.reason})`);
|
|
482
|
+
}
|
|
483
|
+
if (result.excluded.length > 5) {
|
|
484
|
+
console.log(` ... and ${result.excluded.length - 5} more`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
console.log('\n--- CONTEXT ---');
|
|
489
|
+
console.log(result.context);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// ============================================================
|
|
493
|
+
// Exports
|
|
494
|
+
// ============================================================
|
|
495
|
+
|
|
496
|
+
module.exports = {
|
|
497
|
+
// Main API
|
|
498
|
+
gatherContext,
|
|
499
|
+
quickGather,
|
|
500
|
+
fullGather,
|
|
501
|
+
|
|
502
|
+
// Utilities
|
|
503
|
+
analyzeTask,
|
|
504
|
+
gatherAllSections,
|
|
505
|
+
scoreSections,
|
|
506
|
+
fitWithinBudget,
|
|
507
|
+
|
|
508
|
+
// Configuration
|
|
509
|
+
getContextConfig,
|
|
510
|
+
getModelPreferences,
|
|
511
|
+
|
|
512
|
+
// Constants
|
|
513
|
+
CONTEXT_PRIORITIES,
|
|
514
|
+
DEFAULT_CONFIG
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
// Run if called directly
|
|
518
|
+
if (require.main === module) {
|
|
519
|
+
main().catch(console.error);
|
|
520
|
+
}
|