wogiflow 1.0.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/.workflow/agents/reviewer.md +81 -0
- package/.workflow/agents/security.md +94 -0
- package/.workflow/agents/story-writer.md +58 -0
- package/.workflow/bridges/base-bridge.js +395 -0
- package/.workflow/bridges/claude-bridge.js +434 -0
- package/.workflow/bridges/index.js +130 -0
- package/.workflow/lib/assumption-detector.js +481 -0
- package/.workflow/lib/config-substitution.js +371 -0
- package/.workflow/lib/failure-categories.js +478 -0
- package/.workflow/state/app-map.md.template +15 -0
- package/.workflow/state/architecture.md.template +24 -0
- package/.workflow/state/component-index.json.template +5 -0
- package/.workflow/state/decisions.md.template +15 -0
- package/.workflow/state/feedback-patterns.md.template +9 -0
- package/.workflow/state/knowledge-sync.json.template +6 -0
- package/.workflow/state/progress.md.template +14 -0
- package/.workflow/state/ready.json.template +7 -0
- package/.workflow/state/request-log.md.template +14 -0
- package/.workflow/state/session-state.json.template +11 -0
- package/.workflow/state/stack.md.template +33 -0
- package/.workflow/state/testing.md.template +36 -0
- package/.workflow/templates/claude-md.hbs +257 -0
- package/.workflow/templates/correction-report.md +67 -0
- package/.workflow/templates/gemini-md.hbs +52 -0
- package/README.md +1802 -0
- package/bin/flow +205 -0
- package/lib/index.js +33 -0
- package/lib/installer.js +467 -0
- package/lib/release-channel.js +269 -0
- package/lib/skill-registry.js +526 -0
- package/lib/upgrader.js +401 -0
- package/lib/utils.js +305 -0
- package/package.json +64 -0
- package/scripts/flow +985 -0
- package/scripts/flow-adaptive-learning.js +1259 -0
- package/scripts/flow-aggregate.js +488 -0
- package/scripts/flow-archive +133 -0
- package/scripts/flow-auto-context.js +1015 -0
- package/scripts/flow-auto-learn.js +615 -0
- package/scripts/flow-bridge.js +223 -0
- package/scripts/flow-browser-suggest.js +316 -0
- package/scripts/flow-bug.js +247 -0
- package/scripts/flow-cascade.js +711 -0
- package/scripts/flow-changelog +85 -0
- package/scripts/flow-checkpoint.js +483 -0
- package/scripts/flow-cli.js +403 -0
- package/scripts/flow-code-intelligence.js +760 -0
- package/scripts/flow-complexity.js +502 -0
- package/scripts/flow-config-set.js +152 -0
- package/scripts/flow-constants.js +157 -0
- package/scripts/flow-context +152 -0
- package/scripts/flow-context-init.js +482 -0
- package/scripts/flow-context-monitor.js +384 -0
- package/scripts/flow-context-scoring.js +886 -0
- package/scripts/flow-correct.js +458 -0
- package/scripts/flow-damage-control.js +985 -0
- package/scripts/flow-deps +101 -0
- package/scripts/flow-diff.js +700 -0
- package/scripts/flow-done +151 -0
- package/scripts/flow-done.js +489 -0
- package/scripts/flow-durable-session.js +1541 -0
- package/scripts/flow-entropy-monitor.js +345 -0
- package/scripts/flow-export-profile +349 -0
- package/scripts/flow-export-scanner.js +1046 -0
- package/scripts/flow-figma-confirm.js +400 -0
- package/scripts/flow-figma-extract.js +496 -0
- package/scripts/flow-figma-generate.js +683 -0
- package/scripts/flow-figma-index.js +909 -0
- package/scripts/flow-figma-match.js +617 -0
- package/scripts/flow-figma-mcp-server.js +518 -0
- package/scripts/flow-figma-pipeline.js +414 -0
- package/scripts/flow-file-ops.js +301 -0
- package/scripts/flow-gate-confidence.js +825 -0
- package/scripts/flow-guided-edit.js +659 -0
- package/scripts/flow-health +185 -0
- package/scripts/flow-health.js +413 -0
- package/scripts/flow-hooks.js +556 -0
- package/scripts/flow-http-client.js +249 -0
- package/scripts/flow-hybrid-detect.js +167 -0
- package/scripts/flow-hybrid-interactive.js +591 -0
- package/scripts/flow-hybrid-test.js +152 -0
- package/scripts/flow-import-profile +439 -0
- package/scripts/flow-init +253 -0
- package/scripts/flow-instruction-richness.js +827 -0
- package/scripts/flow-jira-integration.js +579 -0
- package/scripts/flow-knowledge-router.js +522 -0
- package/scripts/flow-knowledge-sync.js +589 -0
- package/scripts/flow-linear-integration.js +631 -0
- package/scripts/flow-links.js +774 -0
- package/scripts/flow-log-manager.js +559 -0
- package/scripts/flow-loop-enforcer.js +1246 -0
- package/scripts/flow-loop-retry-learning.js +630 -0
- package/scripts/flow-lsp.js +923 -0
- package/scripts/flow-map-index +348 -0
- package/scripts/flow-map-sync +201 -0
- package/scripts/flow-memory-blocks.js +668 -0
- package/scripts/flow-memory-compactor.js +350 -0
- package/scripts/flow-memory-db.js +1110 -0
- package/scripts/flow-memory-sync.js +484 -0
- package/scripts/flow-metrics.js +353 -0
- package/scripts/flow-migrate-ids.js +370 -0
- package/scripts/flow-model-adapter.js +802 -0
- package/scripts/flow-model-router.js +884 -0
- package/scripts/flow-models.js +1231 -0
- package/scripts/flow-morning.js +517 -0
- package/scripts/flow-multi-approach.js +660 -0
- package/scripts/flow-new-feature +86 -0
- package/scripts/flow-onboard +1042 -0
- package/scripts/flow-orchestrate-llm.js +459 -0
- package/scripts/flow-orchestrate.js +3592 -0
- package/scripts/flow-output.js +123 -0
- package/scripts/flow-parallel-detector.js +399 -0
- package/scripts/flow-parallel-dispatch.js +987 -0
- package/scripts/flow-parallel.js +428 -0
- package/scripts/flow-pattern-enforcer.js +600 -0
- package/scripts/flow-prd-manager.js +282 -0
- package/scripts/flow-progress.js +323 -0
- package/scripts/flow-project-analyzer.js +975 -0
- package/scripts/flow-prompt-composer.js +487 -0
- package/scripts/flow-providers.js +1381 -0
- package/scripts/flow-queue.js +308 -0
- package/scripts/flow-ready +82 -0
- package/scripts/flow-ready.js +189 -0
- package/scripts/flow-regression.js +396 -0
- package/scripts/flow-response-parser.js +450 -0
- package/scripts/flow-resume.js +284 -0
- package/scripts/flow-rules-sync.js +439 -0
- package/scripts/flow-run-trace.js +718 -0
- package/scripts/flow-safety.js +587 -0
- package/scripts/flow-search +104 -0
- package/scripts/flow-security.js +481 -0
- package/scripts/flow-session-end +106 -0
- package/scripts/flow-session-end.js +437 -0
- package/scripts/flow-session-state.js +671 -0
- package/scripts/flow-setup-hooks +216 -0
- package/scripts/flow-setup-hooks.js +377 -0
- package/scripts/flow-skill-create.js +329 -0
- package/scripts/flow-skill-creator.js +572 -0
- package/scripts/flow-skill-generator.js +1046 -0
- package/scripts/flow-skill-learn.js +880 -0
- package/scripts/flow-skill-matcher.js +578 -0
- package/scripts/flow-spec-generator.js +820 -0
- package/scripts/flow-stack-wizard.js +895 -0
- package/scripts/flow-standup +162 -0
- package/scripts/flow-start +74 -0
- package/scripts/flow-start.js +235 -0
- package/scripts/flow-status +110 -0
- package/scripts/flow-status.js +301 -0
- package/scripts/flow-step-browser.js +83 -0
- package/scripts/flow-step-changelog.js +217 -0
- package/scripts/flow-step-comments.js +306 -0
- package/scripts/flow-step-complexity.js +234 -0
- package/scripts/flow-step-coverage.js +218 -0
- package/scripts/flow-step-knowledge.js +193 -0
- package/scripts/flow-step-pr-tests.js +364 -0
- package/scripts/flow-step-regression.js +89 -0
- package/scripts/flow-step-review.js +516 -0
- package/scripts/flow-step-security.js +162 -0
- package/scripts/flow-step-silent-failures.js +290 -0
- package/scripts/flow-step-simplifier.js +346 -0
- package/scripts/flow-story +105 -0
- package/scripts/flow-story.js +500 -0
- package/scripts/flow-suspend.js +252 -0
- package/scripts/flow-sync-daemon.js +654 -0
- package/scripts/flow-task-analyzer.js +606 -0
- package/scripts/flow-team-dashboard.js +748 -0
- package/scripts/flow-team-sync.js +752 -0
- package/scripts/flow-team.js +977 -0
- package/scripts/flow-tech-options.js +528 -0
- package/scripts/flow-templates.js +812 -0
- package/scripts/flow-tiered-learning.js +728 -0
- package/scripts/flow-trace +204 -0
- package/scripts/flow-transcript-chunking.js +1106 -0
- package/scripts/flow-transcript-digest.js +7918 -0
- package/scripts/flow-transcript-language.js +465 -0
- package/scripts/flow-transcript-parsing.js +1085 -0
- package/scripts/flow-transcript-stories.js +2194 -0
- package/scripts/flow-update-map +224 -0
- package/scripts/flow-utils.js +2242 -0
- package/scripts/flow-verification.js +644 -0
- package/scripts/flow-verify.js +1177 -0
- package/scripts/flow-voice-input.js +638 -0
- package/scripts/flow-watch +168 -0
- package/scripts/flow-workflow-steps.js +521 -0
- package/scripts/flow-workflow.js +1029 -0
- package/scripts/flow-worktree.js +489 -0
- package/scripts/hooks/adapters/base-adapter.js +102 -0
- package/scripts/hooks/adapters/claude-code.js +359 -0
- package/scripts/hooks/adapters/index.js +79 -0
- package/scripts/hooks/core/component-check.js +341 -0
- package/scripts/hooks/core/index.js +35 -0
- package/scripts/hooks/core/loop-check.js +241 -0
- package/scripts/hooks/core/session-context.js +294 -0
- package/scripts/hooks/core/task-gate.js +177 -0
- package/scripts/hooks/core/validation.js +230 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
- package/scripts/hooks/entry/claude-code/session-end.js +87 -0
- package/scripts/hooks/entry/claude-code/session-start.js +46 -0
- package/scripts/hooks/entry/claude-code/stop.js +43 -0
- package/scripts/postinstall.js +139 -0
- package/templates/browser-test-flow.json +56 -0
- package/templates/bug-report.md +43 -0
- package/templates/component-detail.md +42 -0
- package/templates/component.stories.tsx +49 -0
- package/templates/context/constraints.md +83 -0
- package/templates/context/conventions.md +177 -0
- package/templates/context/stack.md +60 -0
- package/templates/correction-report.md +90 -0
- package/templates/feature-proposal.md +35 -0
- package/templates/hybrid/_base.md +254 -0
- package/templates/hybrid/_patterns.md +45 -0
- package/templates/hybrid/create-component.md +127 -0
- package/templates/hybrid/create-file.md +56 -0
- package/templates/hybrid/create-hook.md +145 -0
- package/templates/hybrid/create-service.md +70 -0
- package/templates/hybrid/fix-bug.md +33 -0
- package/templates/hybrid/modify-file.md +55 -0
- package/templates/story.md +68 -0
- package/templates/task.json +56 -0
- package/templates/trace.md +69 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - End Session Properly
|
|
5
|
+
*
|
|
6
|
+
* Ensures all workflow state is saved, optionally commits and pushes.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { execSync, execFileSync, spawnSync } = require('child_process');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const {
|
|
13
|
+
PATHS,
|
|
14
|
+
PROJECT_ROOT,
|
|
15
|
+
fileExists,
|
|
16
|
+
getConfig,
|
|
17
|
+
getConfigValue,
|
|
18
|
+
readFile,
|
|
19
|
+
writeFile,
|
|
20
|
+
isGitRepo,
|
|
21
|
+
getGitStatus,
|
|
22
|
+
color,
|
|
23
|
+
printSection,
|
|
24
|
+
success,
|
|
25
|
+
warn
|
|
26
|
+
} = require('./flow-utils');
|
|
27
|
+
|
|
28
|
+
// v1.7.0 context memory management
|
|
29
|
+
const { showContextBreakdown, checkContextHealth } = require('./flow-context-monitor');
|
|
30
|
+
const { resetSessionContext, getSessionContext, writeMemoryBlocks, readMemoryBlocks } = require('./flow-memory-blocks');
|
|
31
|
+
const { saveSessionSummary, loadSessionState } = require('./flow-session-state');
|
|
32
|
+
const { autoArchiveIfNeeded, getLogStats } = require('./flow-log-manager');
|
|
33
|
+
|
|
34
|
+
// v1.8.0 automatic memory management
|
|
35
|
+
let memoryDb = null;
|
|
36
|
+
try {
|
|
37
|
+
memoryDb = require('./flow-memory-db');
|
|
38
|
+
} catch (err) {
|
|
39
|
+
// Memory module not available
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Prompt user for input
|
|
44
|
+
*/
|
|
45
|
+
function prompt(question) {
|
|
46
|
+
const rl = readline.createInterface({
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stdout
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return new Promise(resolve => {
|
|
52
|
+
rl.question(question, answer => {
|
|
53
|
+
rl.close();
|
|
54
|
+
resolve(answer);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Check session-end requirements from config
|
|
61
|
+
*/
|
|
62
|
+
function checkRequirements() {
|
|
63
|
+
if (!fileExists(PATHS.config)) return;
|
|
64
|
+
|
|
65
|
+
console.log(color('yellow', 'Checking session-end requirements...'));
|
|
66
|
+
|
|
67
|
+
const config = getConfig();
|
|
68
|
+
const steps = config.mandatorySteps?.onSessionEnd || [];
|
|
69
|
+
|
|
70
|
+
if (steps.length > 0) {
|
|
71
|
+
console.log('Required:');
|
|
72
|
+
for (const step of steps) {
|
|
73
|
+
console.log(` • ${step}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log('');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Handle uncommitted changes
|
|
82
|
+
*/
|
|
83
|
+
async function handleUncommittedChanges() {
|
|
84
|
+
const git = getGitStatus();
|
|
85
|
+
|
|
86
|
+
if (!git.isRepo) return;
|
|
87
|
+
|
|
88
|
+
if (git.uncommitted > 0) {
|
|
89
|
+
console.log(color('yellow', `Uncommitted changes: ${git.uncommitted} files`));
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const status = execSync('git status --short', { encoding: 'utf-8' });
|
|
93
|
+
console.log(status);
|
|
94
|
+
} catch {
|
|
95
|
+
// Ignore
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const confirm = await prompt('Commit all changes? (y/N) ');
|
|
99
|
+
|
|
100
|
+
if (confirm.toLowerCase() === 'y') {
|
|
101
|
+
const msg = await prompt('Commit message: ');
|
|
102
|
+
const commitMsg = msg || 'checkpoint: end of session';
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
execSync('git add -A', { stdio: 'pipe' });
|
|
106
|
+
// Use execFileSync to prevent command injection from commit message
|
|
107
|
+
execFileSync('git', ['commit', '-m', commitMsg], { stdio: 'pipe' });
|
|
108
|
+
success('Changes committed');
|
|
109
|
+
} catch (err) {
|
|
110
|
+
warn(`Commit failed: ${err.message}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
success('No uncommitted changes');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log('');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Update progress.md timestamp
|
|
122
|
+
*/
|
|
123
|
+
function updateProgress() {
|
|
124
|
+
if (!fileExists(PATHS.progress)) return;
|
|
125
|
+
|
|
126
|
+
console.log(color('yellow', 'Updating progress.md...'));
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
let content = readFile(PATHS.progress);
|
|
130
|
+
const now = new Date();
|
|
131
|
+
const timestamp = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
|
|
132
|
+
|
|
133
|
+
// Update or add timestamp
|
|
134
|
+
if (content.includes('## Last Updated')) {
|
|
135
|
+
content = content.replace(/## Last Updated.*(\n|$)/, `## Last Updated\n${timestamp}\n`);
|
|
136
|
+
} else {
|
|
137
|
+
content = `## Last Updated\n${timestamp}\n\n${content}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
writeFile(PATHS.progress, content);
|
|
141
|
+
success('Progress updated');
|
|
142
|
+
} catch (err) {
|
|
143
|
+
warn(`Failed to update progress: ${err.message}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Extract skill learnings if configured
|
|
149
|
+
*/
|
|
150
|
+
function extractSkillLearnings() {
|
|
151
|
+
if (!fileExists(PATHS.config)) return;
|
|
152
|
+
|
|
153
|
+
const skillLearning = getConfigValue('skillLearning', {});
|
|
154
|
+
|
|
155
|
+
if (skillLearning.enabled && skillLearning.autoExtract) {
|
|
156
|
+
console.log('');
|
|
157
|
+
console.log(color('yellow', 'Extracting skill learnings...'));
|
|
158
|
+
|
|
159
|
+
const scriptPath = path.join(PROJECT_ROOT, 'scripts', 'flow-skill-learn.js');
|
|
160
|
+
if (fileExists(scriptPath)) {
|
|
161
|
+
const result = spawnSync('node', [scriptPath, '--trigger=session-end'], {
|
|
162
|
+
encoding: 'utf-8',
|
|
163
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (result.status === 0) {
|
|
167
|
+
success('Skills updated');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Offer to push to remote
|
|
175
|
+
*/
|
|
176
|
+
async function offerPush() {
|
|
177
|
+
if (!isGitRepo()) return;
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
execSync('git remote get-url origin', { stdio: 'pipe' });
|
|
181
|
+
|
|
182
|
+
const confirm = await prompt('Push to remote? (y/N) ');
|
|
183
|
+
|
|
184
|
+
if (confirm.toLowerCase() === 'y') {
|
|
185
|
+
execSync('git push', { stdio: 'inherit' });
|
|
186
|
+
success('Pushed to remote');
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
// No remote configured, skip
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* v1.7.0: Save session summary to state
|
|
195
|
+
*/
|
|
196
|
+
function saveSessionSummaryToState() {
|
|
197
|
+
console.log('');
|
|
198
|
+
console.log(color('yellow', 'Saving session state...'));
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const sessionState = loadSessionState();
|
|
202
|
+
const memoryBlocks = readMemoryBlocks();
|
|
203
|
+
|
|
204
|
+
// Build summary from session data
|
|
205
|
+
const summary = {
|
|
206
|
+
tasksCompleted: sessionState.metrics?.tasksCompleted || 0,
|
|
207
|
+
filesModified: sessionState.recentFiles?.slice(0, 5) || [],
|
|
208
|
+
decisions: sessionState.recentDecisions?.map(d => d.decision).slice(0, 3) || [],
|
|
209
|
+
summary: memoryBlocks?.keyFacts?.slice(-3).join('; ') || 'Session ended'
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
saveSessionSummary(summary);
|
|
213
|
+
success('Session state saved');
|
|
214
|
+
} catch (err) {
|
|
215
|
+
if (process.env.DEBUG) console.error(`[DEBUG] Session save: ${err.message}`);
|
|
216
|
+
warn('Could not save session state');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* v1.7.0: Archive request log if threshold exceeded
|
|
222
|
+
*/
|
|
223
|
+
function archiveRequestLogIfNeeded() {
|
|
224
|
+
try {
|
|
225
|
+
const result = autoArchiveIfNeeded();
|
|
226
|
+
if (result && result.archived > 0) {
|
|
227
|
+
console.log('');
|
|
228
|
+
success(`Archived ${result.archived} request log entries`);
|
|
229
|
+
console.log(color('dim', ` Archive: ${result.archivePath}`));
|
|
230
|
+
}
|
|
231
|
+
} catch (err) {
|
|
232
|
+
if (process.env.DEBUG) console.error(`[DEBUG] Archive: ${err.message}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* v1.7.0: Show context health summary
|
|
238
|
+
*/
|
|
239
|
+
function showContextHealthSummary() {
|
|
240
|
+
try {
|
|
241
|
+
const health = checkContextHealth();
|
|
242
|
+
if (health.status !== 'disabled') {
|
|
243
|
+
console.log('');
|
|
244
|
+
console.log(color('yellow', 'Context health:'));
|
|
245
|
+
const statusColor = health.status === 'healthy' ? 'green'
|
|
246
|
+
: health.status === 'warning' ? 'yellow' : 'red';
|
|
247
|
+
console.log(` Status: ${color(statusColor, health.status.toUpperCase())} (${health.usagePercent}%)`);
|
|
248
|
+
|
|
249
|
+
if (health.recommendation) {
|
|
250
|
+
console.log(` ${color(statusColor, health.recommendation)}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} catch (err) {
|
|
254
|
+
if (process.env.DEBUG) console.error(`[DEBUG] Context health: ${err.message}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* v1.8.0: Automatic memory management
|
|
260
|
+
* Part of automatic memory management for teams
|
|
261
|
+
*/
|
|
262
|
+
async function automaticMemoryManagement() {
|
|
263
|
+
if (!memoryDb) return;
|
|
264
|
+
|
|
265
|
+
const config = getConfig();
|
|
266
|
+
const memConfig = config.automaticMemory || {};
|
|
267
|
+
|
|
268
|
+
if (!memConfig.enabled) return;
|
|
269
|
+
|
|
270
|
+
console.log('');
|
|
271
|
+
console.log(color('yellow', 'Automatic memory management:'));
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
// 1. Apply relevance decay
|
|
275
|
+
if (memConfig.relevanceDecay?.enabled !== false) {
|
|
276
|
+
const decayResult = await memoryDb.applyRelevanceDecay({
|
|
277
|
+
decayRate: memConfig.relevanceDecay?.decayRate || 0.033,
|
|
278
|
+
neverAccessedPenalty: memConfig.relevanceDecay?.neverAccessedPenalty || 0.1
|
|
279
|
+
});
|
|
280
|
+
if (decayResult.decayed > 0) {
|
|
281
|
+
console.log(` Relevance decay: ${decayResult.decayed} facts updated`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 2. Check entropy and compact if needed
|
|
286
|
+
const memoryConfig = { maxLocalFacts: config.memory?.maxLocalFacts || 1000 };
|
|
287
|
+
const entropy = await memoryDb.getEntropyStats(memoryConfig);
|
|
288
|
+
|
|
289
|
+
const threshold = memConfig.entropyThreshold || 0.7;
|
|
290
|
+
const statusColor = entropy.status === 'healthy' ? 'green'
|
|
291
|
+
: entropy.status === 'moderate' ? 'yellow' : 'red';
|
|
292
|
+
|
|
293
|
+
console.log(` Entropy: ${color(statusColor, entropy.entropy)} (${entropy.status})`);
|
|
294
|
+
console.log(` Facts: ${entropy.totalFacts}/${entropy.maxFacts} | Cold: ${entropy.coldFacts}`);
|
|
295
|
+
|
|
296
|
+
if (entropy.needsCompaction && memConfig.compactOnSessionEnd) {
|
|
297
|
+
console.log(color('yellow', ' Auto-compacting memory...'));
|
|
298
|
+
|
|
299
|
+
// Demote low-relevance facts
|
|
300
|
+
const demotion = await memoryDb.demoteToColdStorage({
|
|
301
|
+
relevanceThreshold: memConfig.demotion?.relevanceThreshold || 0.3
|
|
302
|
+
});
|
|
303
|
+
if (demotion.demoted > 0) {
|
|
304
|
+
console.log(` Demoted: ${demotion.demoted} facts`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Merge duplicates
|
|
308
|
+
const merge = await memoryDb.mergeSimilarFacts({ mergeSimilarityThreshold: 0.95 });
|
|
309
|
+
if (merge.merged > 0) {
|
|
310
|
+
console.log(` Merged: ${merge.merged} duplicates`);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Purge old cold facts
|
|
314
|
+
const purge = await memoryDb.purgeColdFacts({
|
|
315
|
+
coldRetentionDays: memConfig.demotion?.coldRetentionDays || 90
|
|
316
|
+
});
|
|
317
|
+
if (purge.purged > 0) {
|
|
318
|
+
console.log(` Purged: ${purge.purged} old facts`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// 3. Check for promotion candidates and auto-promote if enabled
|
|
323
|
+
const promoConfig = config.automaticPromotion || {};
|
|
324
|
+
if (promoConfig.enabled) {
|
|
325
|
+
const candidates = await memoryDb.getPromotionCandidates({
|
|
326
|
+
minRelevance: promoConfig.minRelevance || 0.8,
|
|
327
|
+
minAccessCount: promoConfig.threshold || 3
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const unpromoted = candidates.filter(c => !c.promoted_to);
|
|
331
|
+
if (unpromoted.length > 0) {
|
|
332
|
+
console.log(` ${color('cyan', `${unpromoted.length} pattern(s) ready for promotion`)}`);
|
|
333
|
+
|
|
334
|
+
// Auto-promote if approval not required
|
|
335
|
+
if (!promoConfig.requireApproval) {
|
|
336
|
+
try {
|
|
337
|
+
const memorySync = require('./flow-memory-sync');
|
|
338
|
+
if (memorySync && typeof memorySync.autoPromote === 'function') {
|
|
339
|
+
const result = await memorySync.autoPromote(config);
|
|
340
|
+
if (result.promoted > 0) {
|
|
341
|
+
console.log(` ${color('green', `Auto-promoted ${result.promoted} pattern(s) to decisions.md`)}`);
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
// Fallback: tell user to run manually
|
|
345
|
+
console.log(' Run: ./scripts/flow memory-sync --auto');
|
|
346
|
+
}
|
|
347
|
+
} catch (err) {
|
|
348
|
+
// Module not available or error, fall back to manual
|
|
349
|
+
console.log(' Run: ./scripts/flow memory-sync --auto');
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
console.log(' Run: ./scripts/flow memory-sync --auto (approval required)');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// 4. Record metric
|
|
358
|
+
await memoryDb.recordMemoryMetric('session_end');
|
|
359
|
+
|
|
360
|
+
success('Memory management complete');
|
|
361
|
+
|
|
362
|
+
} catch (err) {
|
|
363
|
+
if (process.env.DEBUG) console.error(`[DEBUG] Memory management: ${err.message}`);
|
|
364
|
+
warn('Memory management skipped');
|
|
365
|
+
} finally {
|
|
366
|
+
try {
|
|
367
|
+
memoryDb.closeDatabase();
|
|
368
|
+
} catch {}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Show status summary
|
|
374
|
+
*/
|
|
375
|
+
function showSummary() {
|
|
376
|
+
console.log('');
|
|
377
|
+
console.log(color('green', 'Session ended cleanly.'));
|
|
378
|
+
console.log('');
|
|
379
|
+
console.log('Summary:');
|
|
380
|
+
|
|
381
|
+
const statusScript = path.join(PROJECT_ROOT, 'scripts', 'flow-status.js');
|
|
382
|
+
if (fileExists(statusScript)) {
|
|
383
|
+
try {
|
|
384
|
+
spawnSync('node', [statusScript], {
|
|
385
|
+
encoding: 'utf-8',
|
|
386
|
+
stdio: 'inherit'
|
|
387
|
+
});
|
|
388
|
+
} catch {
|
|
389
|
+
console.log(" (run 'flow status' for details)");
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
console.log(" (run 'flow status' for details)");
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function main() {
|
|
397
|
+
printSection('Ending Session');
|
|
398
|
+
console.log('===============');
|
|
399
|
+
console.log('');
|
|
400
|
+
|
|
401
|
+
// Check requirements
|
|
402
|
+
checkRequirements();
|
|
403
|
+
|
|
404
|
+
// Handle uncommitted changes
|
|
405
|
+
await handleUncommittedChanges();
|
|
406
|
+
|
|
407
|
+
// Update progress
|
|
408
|
+
updateProgress();
|
|
409
|
+
|
|
410
|
+
// Extract skill learnings
|
|
411
|
+
extractSkillLearnings();
|
|
412
|
+
|
|
413
|
+
// v1.7.0: Save session summary
|
|
414
|
+
saveSessionSummaryToState();
|
|
415
|
+
|
|
416
|
+
// v1.7.0: Auto-archive request log
|
|
417
|
+
archiveRequestLogIfNeeded();
|
|
418
|
+
|
|
419
|
+
// v1.7.0: Show context health
|
|
420
|
+
showContextHealthSummary();
|
|
421
|
+
|
|
422
|
+
// v1.8.0: Automatic memory management
|
|
423
|
+
await automaticMemoryManagement();
|
|
424
|
+
|
|
425
|
+
console.log('');
|
|
426
|
+
|
|
427
|
+
// Offer to push
|
|
428
|
+
await offerPush();
|
|
429
|
+
|
|
430
|
+
// Show summary
|
|
431
|
+
showSummary();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
main().catch(e => {
|
|
435
|
+
console.error(console.error('Error:', err.message));
|
|
436
|
+
process.exit(1);
|
|
437
|
+
});
|