mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-09-28 06:22:58 +08:00
fix(memory): keep home-level helpers on the active project root
This commit is contained in:
@@ -12,12 +12,16 @@
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { join, dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
// Home-level helpers can serve a different project. Keep the memory writer on
|
||||
// the same project root as intelligence.cjs, which reads CLAUDE_PROJECT_DIR.
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
|
||||
const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
|
||||
|
||||
|
||||
@@ -19,14 +19,16 @@
|
||||
|
||||
import { createRequire } from 'module';
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { join, dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { execSync, spawn } from 'child_process';
|
||||
import Database from 'better-sqlite3';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const DATA_DIR = join(PROJECT_ROOT, '.claude-flow/learning');
|
||||
const DB_PATH = join(DATA_DIR, 'patterns.db');
|
||||
const METRICS_PATH = join(DATA_DIR, 'learning-metrics.json');
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
|
||||
import initSqlJs from 'sql.js';
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync, openSync, writeSync, fsyncSync, closeSync, renameSync, rmSync } from 'fs';
|
||||
import { dirname, join, basename } from 'path';
|
||||
import { dirname, join, basename, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const V3_DIR = join(PROJECT_ROOT, 'v3');
|
||||
const DB_PATH = join(PROJECT_ROOT, '.claude-flow', 'metrics.db');
|
||||
|
||||
|
||||
@@ -12,12 +12,16 @@
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { join, dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
// Home-level helpers can serve a different project. Keep the memory writer on
|
||||
// the same project root as intelligence.cjs, which reads CLAUDE_PROJECT_DIR.
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
|
||||
const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
|
||||
|
||||
|
||||
@@ -19,14 +19,16 @@
|
||||
|
||||
import { createRequire } from 'module';
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { join, dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { execSync, spawn } from 'child_process';
|
||||
import Database from 'better-sqlite3';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const DATA_DIR = join(PROJECT_ROOT, '.claude-flow/learning');
|
||||
const DB_PATH = join(DATA_DIR, 'patterns.db');
|
||||
const METRICS_PATH = join(DATA_DIR, 'learning-metrics.json');
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
|
||||
import initSqlJs from 'sql.js';
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync, openSync, writeSync, fsyncSync, closeSync, renameSync, rmSync } from 'fs';
|
||||
import { dirname, join, basename } from 'path';
|
||||
import { dirname, join, basename, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const V3_DIR = join(PROJECT_ROOT, 'v3');
|
||||
const DB_PATH = join(PROJECT_ROOT, '.claude-flow', 'metrics.db');
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/** Regression for #3286: home-level helpers must write to the active project. */
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { generateAutoMemoryHook } from '../src/init/helpers-generator.js';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const packageHook = resolve(here, '../.claude/helpers/auto-memory-hook.mjs');
|
||||
const dogfoodHook = resolve(here, '../../../../.claude/helpers/auto-memory-hook.mjs');
|
||||
const tempRoots: string[] = [];
|
||||
|
||||
function fixture(source: string | null) {
|
||||
const root = mkdtempSync(join(tmpdir(), 'ruflo-root-3286-'));
|
||||
tempRoots.push(root);
|
||||
const project = join(root, 'project');
|
||||
const home = join(root, 'home');
|
||||
const hook = join(home, '.claude', 'helpers', 'auto-memory-hook.mjs');
|
||||
mkdirSync(project, { recursive: true });
|
||||
mkdirSync(dirname(hook), { recursive: true });
|
||||
if (source) copyFileSync(source, hook);
|
||||
else writeFileSync(hook, generateAutoMemoryHook());
|
||||
return { project, home, hook };
|
||||
}
|
||||
|
||||
function run(hook: string, project: string, command: string) {
|
||||
const result = spawnSync(process.execPath, [hook, command], {
|
||||
cwd: project,
|
||||
env: { ...process.env, CLAUDE_PROJECT_DIR: project },
|
||||
encoding: 'utf8',
|
||||
timeout: 10_000,
|
||||
});
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.status).toBe(0);
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of tempRoots.splice(0)) rmSync(root, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe('#3286 auto-memory project root', () => {
|
||||
for (const [name, source] of [['package', packageHook], ['repository', dogfoodHook]] as const) {
|
||||
it(`${name} helper imports and syncs into the project when invoked from HOME`, () => {
|
||||
const { project, home, hook } = fixture(source);
|
||||
const mockMemory = join(project, 'mock-memory.mjs');
|
||||
writeFileSync(mockMemory, `
|
||||
import { writeFileSync } from 'node:fs';
|
||||
export class AutoMemoryBridge {
|
||||
constructor(backend, config) { this.backend = backend; this.config = config; }
|
||||
async importFromAutoMemory() {
|
||||
await this.backend.store({ id: 'scope', key: 'scope', content: this.config.workingDir });
|
||||
return { imported: 1, skipped: 0 };
|
||||
}
|
||||
async syncToAutoMemory() {
|
||||
writeFileSync(new URL('./sync-root.txt', import.meta.url), this.config.workingDir);
|
||||
return { synced: 1, categories: [] };
|
||||
}
|
||||
async curateIndex() {}
|
||||
}
|
||||
`);
|
||||
mkdirSync(join(project, '.claude-flow'), { recursive: true });
|
||||
writeFileSync(join(project, '.claude-flow', 'memory-package.json'), JSON.stringify({ distPath: mockMemory }));
|
||||
|
||||
expect(run(hook, project, 'import')).toContain('Imported 1 entries');
|
||||
const store = join(project, '.claude-flow', 'data', 'auto-memory-store.json');
|
||||
expect(JSON.parse(readFileSync(store, 'utf8'))[0].content).toBe(project);
|
||||
expect(run(hook, project, 'sync')).toContain('Synced 1 entries');
|
||||
expect(readFileSync(join(project, 'sync-root.txt'), 'utf8')).toBe(project);
|
||||
expect(existsSync(join(home, '.claude-flow', 'data', 'auto-memory-store.json'))).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
it('generated fallback reads the project store when invoked from HOME', () => {
|
||||
const { project, home, hook } = fixture(null);
|
||||
const data = join(project, '.claude-flow', 'data');
|
||||
mkdirSync(data, { recursive: true });
|
||||
writeFileSync(join(data, 'auto-memory-store.json'), '[]');
|
||||
|
||||
expect(run(hook, project, 'status')).toContain('Store: Initialized');
|
||||
expect(existsSync(join(home, '.claude-flow', 'data'))).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1015,12 +1015,14 @@ export function generateAutoMemoryHook(): string {
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { join, dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR
|
||||
? resolve(process.env.CLAUDE_PROJECT_DIR)
|
||||
: join(__dirname, '../..');
|
||||
const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
|
||||
const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user