@cloudpftc/opencode-orchestrator 3.6.0 → 3.6.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.
Files changed (39) hide show
  1. package/.opencode/helpers/auto-memory-hook.mjs +104 -0
  2. package/.opencode/helpers/hook-handler.cjs +223 -0
  3. package/.opencode/helpers/intelligence.cjs +197 -0
  4. package/.opencode/helpers/memory.js +83 -0
  5. package/.opencode/helpers/post-commit +16 -0
  6. package/.opencode/helpers/pre-commit +26 -0
  7. package/.opencode/helpers/router.js +66 -0
  8. package/.opencode/helpers/session.js +127 -0
  9. package/.opencode/helpers/statusline.cjs +774 -0
  10. package/.opencode/settings.json +319 -0
  11. package/package.json +1 -1
  12. package/v3/@claude-flow/cli/README.md +391 -534
  13. package/v3/@claude-flow/cli/dist/src/commands/benchmark.js +2 -2
  14. package/v3/@claude-flow/cli/dist/src/commands/claims.js +1 -1
  15. package/v3/@claude-flow/cli/dist/src/commands/config.js +1 -1
  16. package/v3/@claude-flow/cli/dist/src/commands/daemon.js +3 -3
  17. package/v3/@claude-flow/cli/dist/src/commands/deployment.js +1 -1
  18. package/v3/@claude-flow/cli/dist/src/commands/doctor.js +1 -1
  19. package/v3/@claude-flow/cli/dist/src/commands/embeddings.js +1 -1
  20. package/v3/@claude-flow/cli/dist/src/commands/hooks.js +1 -1
  21. package/v3/@claude-flow/cli/dist/src/commands/init.js +9 -9
  22. package/v3/@claude-flow/cli/dist/src/commands/neural.js +1 -1
  23. package/v3/@claude-flow/cli/dist/src/commands/performance.js +1 -1
  24. package/v3/@claude-flow/cli/dist/src/commands/plugins.js +1 -1
  25. package/v3/@claude-flow/cli/dist/src/commands/providers.js +1 -1
  26. package/v3/@claude-flow/cli/dist/src/commands/security.js +1 -1
  27. package/v3/@claude-flow/cli/dist/src/commands/start.js +10 -10
  28. package/v3/@claude-flow/cli/dist/src/commands/status.js +2 -2
  29. package/v3/@claude-flow/cli/dist/src/commands/transfer-store.js +1 -1
  30. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +1 -1
  31. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +1 -1
  32. package/v3/@claude-flow/cli/dist/src/plugins/store/discovery.js +1 -1
  33. package/v3/@claude-flow/cli/dist/src/runtime/headless.js +3 -3
  34. package/v3/@claude-flow/cli/dist/src/services/claim-service.js +1 -1
  35. package/v3/@claude-flow/cli/dist/src/types.d.ts +1 -1
  36. package/v3/@claude-flow/cli/dist/src/types.js +1 -1
  37. package/v3/@claude-flow/cli/package.json +1 -1
  38. package/v3/@claude-flow/cli/dist/src/init/claudemd-generator.d.ts +0 -25
  39. package/v3/@claude-flow/cli/dist/src/init/claudemd-generator.js +0 -486
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Auto Memory Bridge Hook (ADR-048/049) — Minimal Fallback
4
+ * Full version is copied from package source when available.
5
+ *
6
+ * Usage:
7
+ * node auto-memory-hook.mjs import # SessionStart
8
+ * node auto-memory-hook.mjs sync # SessionEnd / Stop
9
+ * node auto-memory-hook.mjs status # Show bridge status
10
+ */
11
+
12
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
13
+ import { join, dirname } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = dirname(__filename);
18
+ const PROJECT_ROOT = join(__dirname, '../..');
19
+ const DATA_DIR = join(PROJECT_ROOT, '.opencode', 'data');
20
+ const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
21
+
22
+ const DIM = '\x1b[2m';
23
+ const RESET = '\x1b[0m';
24
+ const dim = (msg) => console.log(` ${DIM}${msg}${RESET}`);
25
+
26
+ // Ensure data dir
27
+ if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
28
+
29
+ async function loadMemoryPackage() {
30
+ // Strategy 1: Use createRequire for CJS-style resolution (handles nested node_modules
31
+ // when installed as a transitive dependency via npx ruflo / npx claude-flow)
32
+ try {
33
+ const { createRequire } = await import('module');
34
+ const require = createRequire(join(PROJECT_ROOT, 'package.json'));
35
+ return require('@claude-flow/memory');
36
+ } catch { /* fall through */ }
37
+
38
+ // Strategy 2: ESM import (works when @claude-flow/memory is a direct dependency)
39
+ try { return await import('@claude-flow/memory'); } catch { /* fall through */ }
40
+
41
+ // Strategy 3: Walk up from PROJECT_ROOT looking for the package in any node_modules
42
+ let searchDir = PROJECT_ROOT;
43
+ const { parse } = await import('path');
44
+ while (searchDir !== parse(searchDir).root) {
45
+ const candidate = join(searchDir, 'node_modules', '@claude-flow', 'memory', 'dist', 'index.js');
46
+ if (existsSync(candidate)) {
47
+ try { return await import(`file://${candidate}`); } catch { /* fall through */ }
48
+ }
49
+ searchDir = dirname(searchDir);
50
+ }
51
+
52
+ return null;
53
+ }
54
+
55
+ async function doImport() {
56
+ const memPkg = await loadMemoryPackage();
57
+
58
+ if (!memPkg || !memPkg.AutoMemoryBridge) {
59
+ dim('Memory package not available — auto memory import skipped (non-critical)');
60
+ return;
61
+ }
62
+
63
+ // Full implementation deferred to copied version
64
+ dim('Auto memory import available — run init --upgrade for full support');
65
+ }
66
+
67
+ async function doSync() {
68
+ if (!existsSync(STORE_PATH)) {
69
+ dim('No entries to sync');
70
+ return;
71
+ }
72
+
73
+ const memPkg = await loadMemoryPackage();
74
+
75
+ if (!memPkg || !memPkg.AutoMemoryBridge) {
76
+ dim('Memory package not available — sync skipped (non-critical)');
77
+ return;
78
+ }
79
+
80
+ dim('Auto memory sync available — run init --upgrade for full support');
81
+ }
82
+
83
+ function doStatus() {
84
+ console.log('\n=== Auto Memory Bridge Status ===\n');
85
+ console.log(' Package: Fallback mode (run init --upgrade for full)');
86
+ console.log(` Store: ${existsSync(STORE_PATH) ? 'Initialized' : 'Not initialized'}`);
87
+ console.log('');
88
+ }
89
+
90
+ const command = process.argv[2] || 'status';
91
+
92
+ try {
93
+ switch (command) {
94
+ case 'import': await doImport(); break;
95
+ case 'sync': await doSync(); break;
96
+ case 'status': doStatus(); break;
97
+ default:
98
+ console.log('Usage: auto-memory-hook.mjs <import|sync|status>');
99
+ process.exit(1);
100
+ }
101
+ } catch (err) {
102
+ // Hooks must never crash Claude Code - fail silently
103
+ dim(`Error (non-critical): ${err.message}`);
104
+ }
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Claude Flow Hook Handler (Cross-Platform)
4
+ * Dispatches hook events to the appropriate helper modules.
5
+ */
6
+
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+
10
+ const helpersDir = __dirname;
11
+
12
+ function safeRequire(modulePath) {
13
+ try {
14
+ if (fs.existsSync(modulePath)) {
15
+ const origLog = console.log;
16
+ const origError = console.error;
17
+ console.log = () => {};
18
+ console.error = () => {};
19
+ try {
20
+ const mod = require(modulePath);
21
+ return mod;
22
+ } finally {
23
+ console.log = origLog;
24
+ console.error = origError;
25
+ }
26
+ }
27
+ } catch (e) {
28
+ // silently fail
29
+ }
30
+ return null;
31
+ }
32
+
33
+ const router = safeRequire(path.join(helpersDir, 'router.js'));
34
+ const session = safeRequire(path.join(helpersDir, 'session.js'));
35
+ const memory = safeRequire(path.join(helpersDir, 'memory.js'));
36
+ const intelligence = safeRequire(path.join(helpersDir, 'intelligence.cjs'));
37
+
38
+ const [,, command, ...args] = process.argv;
39
+
40
+ // Read stdin with timeout — Claude Code sends hook data as JSON via stdin.
41
+ // Timeout prevents hanging when stdin is in an ambiguous state (not TTY, not pipe).
42
+ async function readStdin() {
43
+ if (process.stdin.isTTY) return "";
44
+ return new Promise((resolve) => {
45
+ let data = "";
46
+ const timer = setTimeout(() => {
47
+ process.stdin.removeAllListeners();
48
+ process.stdin.pause();
49
+ resolve(data);
50
+ }, 500);
51
+ process.stdin.setEncoding("utf8");
52
+ process.stdin.on("data", (chunk) => { data += chunk; });
53
+ process.stdin.on("end", () => { clearTimeout(timer); resolve(data); });
54
+ process.stdin.on("error", () => { clearTimeout(timer); resolve(data); });
55
+ process.stdin.resume();
56
+ });
57
+ }
58
+
59
+ async function main() {
60
+ let stdinData = "";
61
+ try { stdinData = await readStdin(); } catch (e) { /* ignore */ }
62
+ let hookInput = {};
63
+ if (stdinData.trim()) {
64
+ try { hookInput = JSON.parse(stdinData); } catch (e) { /* ignore */ }
65
+ }
66
+ // Prefer stdin fields, then env, then argv
67
+ var prompt = hookInput.prompt || hookInput.command || hookInput.toolInput || process.env.PROMPT || process.env.TOOL_INPUT_command || args.join(' ') || '';
68
+
69
+ const handlers = {
70
+ 'route': () => {
71
+ if (intelligence && intelligence.getContext) {
72
+ try {
73
+ const ctx = intelligence.getContext(prompt);
74
+ if (ctx) console.log(ctx);
75
+ } catch (e) { /* non-fatal */ }
76
+ }
77
+ if (router && router.routeTask) {
78
+ const result = router.routeTask(prompt);
79
+ var output = [];
80
+ output.push('[INFO] Routing task: ' + (prompt.substring(0, 80) || '(no prompt)'));
81
+ output.push('');
82
+ output.push('+------------------- Primary Recommendation -------------------+');
83
+ output.push('| Agent: ' + result.agent.padEnd(53) + '|');
84
+ output.push('| Confidence: ' + (result.confidence * 100).toFixed(1) + '%' + ' '.repeat(44) + '|');
85
+ output.push('| Reason: ' + result.reason.substring(0, 53).padEnd(53) + '|');
86
+ output.push('+--------------------------------------------------------------+');
87
+ console.log(output.join('\n'));
88
+ } else {
89
+ console.log('[INFO] Router not available, using default routing');
90
+ }
91
+ },
92
+
93
+ 'pre-bash': () => {
94
+ var cmd = prompt.toLowerCase();
95
+ var dangerous = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:'];
96
+ for (var i = 0; i < dangerous.length; i++) {
97
+ if (cmd.includes(dangerous[i])) {
98
+ console.error('[BLOCKED] Dangerous command detected: ' + dangerous[i]);
99
+ process.exit(1);
100
+ }
101
+ }
102
+ console.log('[OK] Command validated');
103
+ },
104
+
105
+ 'post-edit': () => {
106
+ if (session && session.metric) {
107
+ try { session.metric('edits'); } catch (e) { /* no active session */ }
108
+ }
109
+ if (intelligence && intelligence.recordEdit) {
110
+ try {
111
+ var file = process.env.TOOL_INPUT_file_path || args[0] || '';
112
+ intelligence.recordEdit(file);
113
+ } catch (e) { /* non-fatal */ }
114
+ }
115
+ console.log('[OK] Edit recorded');
116
+ },
117
+
118
+ 'session-restore': () => {
119
+ if (session) {
120
+ var existing = session.restore && session.restore();
121
+ if (!existing) {
122
+ session.start && session.start();
123
+ }
124
+ } else {
125
+ console.log('[OK] Session restored: session-' + Date.now());
126
+ }
127
+ if (intelligence && intelligence.init) {
128
+ try {
129
+ var result = intelligence.init();
130
+ if (result && result.nodes > 0) {
131
+ console.log('[INTELLIGENCE] Loaded ' + result.nodes + ' patterns, ' + result.edges + ' edges');
132
+ }
133
+ } catch (e) { /* non-fatal */ }
134
+ }
135
+ },
136
+
137
+ 'session-end': () => {
138
+ if (intelligence && intelligence.consolidate) {
139
+ try {
140
+ var result = intelligence.consolidate();
141
+ if (result && result.entries > 0) {
142
+ var msg = '[INTELLIGENCE] Consolidated: ' + result.entries + ' entries, ' + result.edges + ' edges';
143
+ if (result.newEntries > 0) msg += ', ' + result.newEntries + ' new';
144
+ msg += ', PageRank recomputed';
145
+ console.log(msg);
146
+ }
147
+ } catch (e) { /* non-fatal */ }
148
+ }
149
+ if (session && session.end) {
150
+ session.end();
151
+ } else {
152
+ console.log('[OK] Session ended');
153
+ }
154
+ },
155
+
156
+ 'pre-task': () => {
157
+ if (session && session.metric) {
158
+ try { session.metric('tasks'); } catch (e) { /* no active session */ }
159
+ }
160
+ if (router && router.routeTask && prompt) {
161
+ var result = router.routeTask(prompt);
162
+ console.log('[INFO] Task routed to: ' + result.agent + ' (confidence: ' + result.confidence + ')');
163
+ } else {
164
+ console.log('[OK] Task started');
165
+ }
166
+ },
167
+
168
+ 'post-task': () => {
169
+ if (intelligence && intelligence.feedback) {
170
+ try {
171
+ intelligence.feedback(true);
172
+ } catch (e) { /* non-fatal */ }
173
+ }
174
+ console.log('[OK] Task completed');
175
+ },
176
+
177
+ 'compact-manual': () => {
178
+ console.log('PreCompact Guidance:');
179
+ console.log('IMPORTANT: Review CLAUDE.md in project root for:');
180
+ console.log(' - Available agents and concurrent usage patterns');
181
+ console.log(' - Swarm coordination strategies (hierarchical, mesh, adaptive)');
182
+ console.log(' - Critical concurrent execution rules (1 MESSAGE = ALL OPERATIONS)');
183
+ console.log('Ready for compact operation');
184
+ },
185
+
186
+ 'compact-auto': () => {
187
+ console.log('Auto-Compact Guidance (Context Window Full):');
188
+ console.log('CRITICAL: Before compacting, ensure you understand:');
189
+ console.log(' - All agents available in .claude/agents/ directory');
190
+ console.log(' - Concurrent execution patterns from CLAUDE.md');
191
+ console.log(' - Swarm coordination strategies for complex tasks');
192
+ console.log('Apply GOLDEN RULE: Always batch operations in single messages');
193
+ console.log('Auto-compact proceeding with full agent context');
194
+ },
195
+
196
+ 'status': () => {
197
+ console.log('[OK] Status check');
198
+ },
199
+
200
+ 'stats': () => {
201
+ if (intelligence && intelligence.stats) {
202
+ intelligence.stats(args.includes('--json'));
203
+ } else {
204
+ console.log('[WARN] Intelligence module not available. Run session-restore first.');
205
+ }
206
+ },
207
+ };
208
+
209
+ if (command && handlers[command]) {
210
+ try {
211
+ handlers[command]();
212
+ } catch (e) {
213
+ console.log('[WARN] Hook ' + command + ' encountered an error: ' + e.message);
214
+ }
215
+ } else if (command) {
216
+ console.log('[OK] Hook: ' + command);
217
+ } else {
218
+ console.log('Usage: hook-handler.cjs <route|pre-bash|post-edit|session-restore|session-end|pre-task|post-task|compact-manual|compact-auto|status|stats>');
219
+ }
220
+ } // end main
221
+
222
+ process.exitCode = 0;
223
+ main().catch(() => { process.exitCode = 0; });
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Intelligence Layer Stub (ADR-050)
4
+ * Minimal fallback — full version is copied from package source.
5
+ * Provides: init, getContext, recordEdit, feedback, consolidate
6
+ */
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const os = require('os');
12
+
13
+ const DATA_DIR = path.join(process.cwd(), '.opencode', 'data');
14
+ const STORE_PATH = path.join(DATA_DIR, 'auto-memory-store.json');
15
+ const RANKED_PATH = path.join(DATA_DIR, 'ranked-context.json');
16
+ const PENDING_PATH = path.join(DATA_DIR, 'pending-insights.jsonl');
17
+ const SESSION_DIR = path.join(process.cwd(), '.opencode', 'sessions');
18
+ const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
19
+
20
+ function ensureDir(dir) {
21
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
22
+ }
23
+
24
+ function readJSON(p) {
25
+ try { return fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, "utf-8")) : null; }
26
+ catch { return null; }
27
+ }
28
+
29
+ function writeJSON(p, data) {
30
+ ensureDir(path.dirname(p));
31
+ fs.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
32
+ }
33
+
34
+ // Read session context key
35
+ function sessionGet(key) {
36
+ var session = readJSON(SESSION_FILE);
37
+ if (!session) return null;
38
+ return key ? (session.context || {})[key] : session.context;
39
+ }
40
+
41
+ // Write session context key
42
+ function sessionSet(key, value) {
43
+ var session = readJSON(SESSION_FILE);
44
+ if (!session) return;
45
+ if (!session.context) session.context = {};
46
+ session.context[key] = value;
47
+ writeJSON(SESSION_FILE, session);
48
+ }
49
+
50
+ // Tokenize text into words
51
+ function tokenize(text) {
52
+ if (!text) return [];
53
+ return text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter(function(w) { return w.length > 2; });
54
+ }
55
+
56
+ // Bootstrap entries from MEMORY.md files when store is empty
57
+ function bootstrapFromMemoryFiles() {
58
+ var entries = [];
59
+ var candidates = [
60
+ path.join(os.homedir(), ".opencode", "projects"),
61
+ path.join(process.cwd(), ".opencode", "memory"),
62
+ path.join(process.cwd(), ".claude", "memory"),
63
+ ];
64
+ for (var i = 0; i < candidates.length; i++) {
65
+ try {
66
+ if (!fs.existsSync(candidates[i])) continue;
67
+ var files = [];
68
+ try {
69
+ var items = fs.readdirSync(candidates[i], { withFileTypes: true, recursive: true });
70
+ for (var j = 0; j < items.length; j++) {
71
+ if (items[j].name === "MEMORY.md") {
72
+ var fp = items[j].path ? path.join(items[j].path, items[j].name) : path.join(candidates[i], items[j].name);
73
+ files.push(fp);
74
+ }
75
+ }
76
+ } catch (e) { continue; }
77
+ for (var k = 0; k < files.length; k++) {
78
+ try {
79
+ var content = fs.readFileSync(files[k], "utf-8");
80
+ var sections = content.split(/^##\s+/m).filter(function(s) { return s.trim().length > 20; });
81
+ for (var s = 0; s < sections.length; s++) {
82
+ var lines2 = sections[s].split("\n");
83
+ var title = lines2[0] ? lines2[0].trim() : "section-" + s;
84
+ entries.push({
85
+ id: "mem-" + entries.length,
86
+ content: sections[s].substring(0, 500),
87
+ summary: title.substring(0, 100),
88
+ category: "memory",
89
+ confidence: 0.5,
90
+ sourceFile: files[k],
91
+ words: tokenize(sections[s].substring(0, 500)),
92
+ });
93
+ }
94
+ } catch (e) { /* skip */ }
95
+ }
96
+ } catch (e) { /* skip */ }
97
+ }
98
+ return entries;
99
+ }
100
+
101
+ // Load entries from auto-memory-store or bootstrap from MEMORY.md
102
+ function loadEntries() {
103
+ var store = readJSON(STORE_PATH);
104
+ if (store && store.entries && store.entries.length > 0) {
105
+ return store.entries.map(function(e, i) {
106
+ return {
107
+ id: e.id || ("entry-" + i),
108
+ content: e.content || e.value || "",
109
+ summary: e.summary || e.key || "",
110
+ category: e.category || e.namespace || "default",
111
+ confidence: e.confidence || 0.5,
112
+ sourceFile: e.sourceFile || "",
113
+ words: tokenize((e.content || e.value || "") + " " + (e.summary || e.key || "")),
114
+ };
115
+ });
116
+ }
117
+ return bootstrapFromMemoryFiles();
118
+ }
119
+
120
+ // Simple keyword match score
121
+ function matchScore(promptWords, entryWords) {
122
+ if (!promptWords.length || !entryWords.length) return 0;
123
+ var entrySet = {};
124
+ for (var i = 0; i < entryWords.length; i++) entrySet[entryWords[i]] = true;
125
+ var overlap = 0;
126
+ for (var j = 0; j < promptWords.length; j++) {
127
+ if (entrySet[promptWords[j]]) overlap++;
128
+ }
129
+ var union = Object.keys(entrySet).length + promptWords.length - overlap;
130
+ return union > 0 ? overlap / union : 0;
131
+ }
132
+
133
+ var cachedEntries = null;
134
+
135
+ module.exports = {
136
+ init: function() {
137
+ cachedEntries = loadEntries();
138
+ var ranked = cachedEntries.map(function(e) {
139
+ return { id: e.id, content: e.content, summary: e.summary, category: e.category, confidence: e.confidence, words: e.words };
140
+ });
141
+ writeJSON(RANKED_PATH, { version: 1, computedAt: Date.now(), entries: ranked });
142
+ return { nodes: cachedEntries.length, edges: 0 };
143
+ },
144
+
145
+ getContext: function(prompt) {
146
+ if (!prompt) return null;
147
+ var ranked = readJSON(RANKED_PATH);
148
+ var entries = (ranked && ranked.entries) || (cachedEntries || []);
149
+ if (!entries.length) return null;
150
+ var promptWords = tokenize(prompt);
151
+ if (!promptWords.length) return null;
152
+ var scored = entries.map(function(e) {
153
+ return { entry: e, score: matchScore(promptWords, e.words || tokenize(e.content + " " + e.summary)) };
154
+ }).filter(function(s) { return s.score > 0.05; });
155
+ scored.sort(function(a, b) { return b.score - a.score; });
156
+ var top = scored.slice(0, 5);
157
+ if (!top.length) return null;
158
+ var prevMatched = sessionGet("lastMatchedPatterns");
159
+ var matchedIds = top.map(function(s) { return s.entry.id; });
160
+ sessionSet("lastMatchedPatterns", matchedIds);
161
+ if (prevMatched && Array.isArray(prevMatched)) {
162
+ var newSet = {};
163
+ for (var i = 0; i < matchedIds.length; i++) newSet[matchedIds[i]] = true;
164
+ }
165
+ var lines2 = ["[INTELLIGENCE] Relevant patterns for this task:"];
166
+ for (var j = 0; j < top.length; j++) {
167
+ var e = top[j];
168
+ var conf = e.entry.confidence || 0.5;
169
+ var summary = (e.entry.summary || e.entry.content || "").substring(0, 80);
170
+ lines2.push(" * (" + conf.toFixed(2) + ") " + summary);
171
+ }
172
+ return lines2.join("\n");
173
+ },
174
+
175
+ recordEdit: function(file) {
176
+ if (!file) return;
177
+ ensureDir(DATA_DIR);
178
+ var line = JSON.stringify({ type: "edit", file: file, timestamp: Date.now() }) + "\n";
179
+ fs.appendFileSync(PENDING_PATH, line, "utf-8");
180
+ },
181
+
182
+ feedback: function(success) {
183
+ // Stub: no-op in minimal version
184
+ },
185
+
186
+ consolidate: function() {
187
+ var count = 0;
188
+ if (fs.existsSync(PENDING_PATH)) {
189
+ try {
190
+ var content = fs.readFileSync(PENDING_PATH, "utf-8").trim();
191
+ count = content ? content.split("\n").length : 0;
192
+ fs.writeFileSync(PENDING_PATH, "", "utf-8");
193
+ } catch (e) { /* skip */ }
194
+ }
195
+ return { entries: count, edges: 0, newEntries: 0 };
196
+ },
197
+ };
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Claude Flow Memory Helper
4
+ * Simple key-value memory for cross-session context
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const MEMORY_DIR = path.join(process.cwd(), '.opencode', 'data');
11
+ const MEMORY_FILE = path.join(MEMORY_DIR, 'memory.json');
12
+
13
+ function loadMemory() {
14
+ try {
15
+ if (fs.existsSync(MEMORY_FILE)) {
16
+ return JSON.parse(fs.readFileSync(MEMORY_FILE, 'utf-8'));
17
+ }
18
+ } catch (e) {
19
+ // Ignore
20
+ }
21
+ return {};
22
+ }
23
+
24
+ function saveMemory(memory) {
25
+ fs.mkdirSync(MEMORY_DIR, { recursive: true });
26
+ fs.writeFileSync(MEMORY_FILE, JSON.stringify(memory, null, 2));
27
+ }
28
+
29
+ const commands = {
30
+ get: (key) => {
31
+ const memory = loadMemory();
32
+ const value = key ? memory[key] : memory;
33
+ console.log(JSON.stringify(value, null, 2));
34
+ return value;
35
+ },
36
+
37
+ set: (key, value) => {
38
+ if (!key) {
39
+ console.error('Key required');
40
+ return;
41
+ }
42
+ const memory = loadMemory();
43
+ memory[key] = value;
44
+ memory._updated = new Date().toISOString();
45
+ saveMemory(memory);
46
+ console.log(`Set: ${key}`);
47
+ },
48
+
49
+ delete: (key) => {
50
+ if (!key) {
51
+ console.error('Key required');
52
+ return;
53
+ }
54
+ const memory = loadMemory();
55
+ delete memory[key];
56
+ saveMemory(memory);
57
+ console.log(`Deleted: ${key}`);
58
+ },
59
+
60
+ clear: () => {
61
+ saveMemory({});
62
+ console.log('Memory cleared');
63
+ },
64
+
65
+ keys: () => {
66
+ const memory = loadMemory();
67
+ const keys = Object.keys(memory).filter(k => !k.startsWith('_'));
68
+ console.log(keys.join('\n'));
69
+ return keys;
70
+ },
71
+ };
72
+
73
+ // CLI
74
+ const [,, command, key, ...valueParts] = process.argv;
75
+ const value = valueParts.join(' ');
76
+
77
+ if (command && commands[command]) {
78
+ commands[command](key, value);
79
+ } else {
80
+ console.log('Usage: memory.js <get|set|delete|clear|keys> [key] [value]');
81
+ }
82
+
83
+ module.exports = commands;
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+ # Claude Flow Post-Commit Hook
3
+ # Records commit metrics and trains patterns
4
+
5
+ COMMIT_HASH=$(git rev-parse HEAD)
6
+ COMMIT_MSG=$(git log -1 --pretty=%B)
7
+
8
+ echo "📊 Recording commit metrics..."
9
+
10
+ # Notify claude-flow of commit
11
+ npx @claude-flow/cli hooks notify \
12
+ --message "Commit: $COMMIT_MSG" \
13
+ --level info \
14
+ --metadata '{"hash": "'$COMMIT_HASH'"}' 2>/dev/null || true
15
+
16
+ echo "✅ Commit recorded"
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+ # Claude Flow Pre-Commit Hook
3
+ # Validates code quality before commit
4
+
5
+ set -e
6
+
7
+ echo "🔍 Running Claude Flow pre-commit checks..."
8
+
9
+ # Get staged files
10
+ STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
11
+
12
+ # Run validation for each staged file
13
+ for FILE in $STAGED_FILES; do
14
+ if [[ "$FILE" =~ \.(ts|js|tsx|jsx)$ ]]; then
15
+ echo " Validating: $FILE"
16
+ npx @claude-flow/cli hooks pre-edit --file "$FILE" --validate-syntax 2>/dev/null || true
17
+ fi
18
+ done
19
+
20
+ # Run tests if available
21
+ if [ -f "package.json" ] && grep -q '"test"' package.json; then
22
+ echo "🧪 Running tests..."
23
+ npm test --if-present 2>/dev/null || echo " Tests skipped or failed"
24
+ fi
25
+
26
+ echo "✅ Pre-commit checks complete"