claude-flow 3.7.0-alpha.20 → 3.7.0-alpha.21

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.
@@ -1 +1 @@
1
- {"sessionId":"e8acbe6b-1513-4c00-ac30-2b486317c5b1","pid":7565,"procStart":"Sat May 9 13:35:07 2026","acquiredAt":1778338395740}
1
+ {"sessionId":"47380e10-1915-412b-80f1-c03ac7d0ea24","pid":59856,"acquiredAt":1778091867601}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.7.0-alpha.20",
3
+ "version": "3.7.0-alpha.21",
4
4
  "description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -38,6 +38,11 @@ function ensureMemoryDir() {
38
38
  const MAX_KEY_LENGTH = 1024;
39
39
  const MAX_VALUE_SIZE = 1024 * 1024; // 1MB
40
40
  const MAX_QUERY_LENGTH = 4096;
41
+ // #1425 — single source of truth for the dangerous-character set rejected by
42
+ // validateMemoryInput. Imported by sanitizeMemoryKey so write-side sanitization
43
+ // and read-side rejection can never drift apart (the symmetry bug behind #1884).
44
+ const DANGEROUS_KEY_CHARS = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/g;
45
+ const DANGEROUS_KEY_PATTERN = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/;
41
46
  function validateMemoryInput(key, value, query, namespace) {
42
47
  if (key && key.length > MAX_KEY_LENGTH) {
43
48
  throw new Error(`Key exceeds maximum length of ${MAX_KEY_LENGTH} characters`);
@@ -49,14 +54,64 @@ function validateMemoryInput(key, value, query, namespace) {
49
54
  throw new Error(`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`);
50
55
  }
51
56
  // Reject path traversal and shell metacharacters in keys/namespaces (#1425)
52
- const dangerousPattern = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/;
53
- if (key && dangerousPattern.test(key)) {
57
+ if (key && DANGEROUS_KEY_PATTERN.test(key)) {
54
58
  throw new Error('Key contains disallowed characters');
55
59
  }
56
- if (namespace && dangerousPattern.test(namespace)) {
60
+ if (namespace && DANGEROUS_KEY_PATTERN.test(namespace)) {
57
61
  throw new Error('Namespace contains disallowed characters');
58
62
  }
59
63
  }
64
+ // #1884 — sanitize a key produced from arbitrary input (markdown headings,
65
+ // frontmatter names, file names) so it survives validateMemoryInput on the
66
+ // read/delete path. Replaces every dangerous char with `_`. Truncates to
67
+ // MAX_KEY_LENGTH so the bound check in validateMemoryInput also passes.
68
+ // Keep this in sync with DANGEROUS_KEY_PATTERN — they share DANGEROUS_KEY_CHARS.
69
+ function sanitizeMemoryKey(key) {
70
+ const safe = key.replace(DANGEROUS_KEY_CHARS, '_');
71
+ return safe.length > MAX_KEY_LENGTH ? safe.slice(0, MAX_KEY_LENGTH) : safe;
72
+ }
73
+ // #1883 — resolve the Claude-Code project memory directory for the *current*
74
+ // project. Claude Code hashes the project path differently per host OS, and
75
+ // our previous logic only POSIX-slash-replaced cwd, which breaks for:
76
+ // - WSL bridges where cwd is `/mnt/<drive>/...` but Claude Code is on Windows
77
+ // - paths containing spaces (Claude Code replaces spaces with dashes)
78
+ // - any leading slash on POSIX (Claude Code strips it)
79
+ // Strategy: try several candidate hashes and return the first one with a
80
+ // memory dir that exists. An explicit `projectPathOverride` short-circuits
81
+ // the heuristics for callers that know the canonical project path.
82
+ function resolveProjectMemoryDir(claudeProjectsDir, projectPathOverride) {
83
+ const candidates = new Set();
84
+ const sources = [];
85
+ if (projectPathOverride && projectPathOverride.length > 0) {
86
+ sources.push(projectPathOverride);
87
+ }
88
+ else {
89
+ sources.push(process.cwd());
90
+ }
91
+ for (const source of sources) {
92
+ // Candidate 1: legacy POSIX hash — what shipped before #1883
93
+ candidates.add(source.replace(/\//g, '-'));
94
+ // Candidate 2: WSL `/mnt/<drive>/...` translated to Claude-Code Windows hash
95
+ // e.g. `/mnt/c/Users/x/Project Name` → `C--Users-x-Project-Name`
96
+ const wsl = source.match(/^\/mnt\/([a-z])(\/.*)?$/i);
97
+ if (wsl) {
98
+ const drive = wsl[1].toUpperCase();
99
+ const rest = (wsl[2] ?? '').replace(/\//g, '-').replace(/ /g, '-');
100
+ candidates.add(`${drive}-${rest}`);
101
+ }
102
+ // Candidate 3: POSIX hash with leading dash stripped (Claude Code on macOS/Linux)
103
+ const stripped = source.replace(/\//g, '-').replace(/^-+/, '');
104
+ candidates.add(stripped);
105
+ // Candidate 4: spaces replaced with dashes (Claude Code's space rule)
106
+ candidates.add(source.replace(/\//g, '-').replace(/ /g, '-'));
107
+ }
108
+ for (const projectHash of candidates) {
109
+ const memDir = join(claudeProjectsDir, projectHash, 'memory');
110
+ if (existsSync(memDir))
111
+ return { memDir, projectHash };
112
+ }
113
+ return null;
114
+ }
60
115
  /**
61
116
  * Check if legacy JSON store exists in old .claude-flow/memory/ location
62
117
  */
@@ -613,13 +668,14 @@ export const memoryTools = [
613
668
  // ===== Claude Code Memory Bridge Tools =====
614
669
  {
615
670
  name: 'memory_import_claude',
616
- description: 'Import Claude Code auto-memory files into AgentDB with ONNX vector embeddings. Reads ~/.claude/projects/*/memory/*.md files, parses YAML frontmatter, splits into sections, and stores with 384-dim embeddings for semantic search. Use allProjects=true to import from ALL Claude projects.',
671
+ description: 'Import Claude Code auto-memory files into AgentDB with ONNX vector embeddings. Reads ~/.claude/projects/*/memory/*.md files, parses YAML frontmatter, splits into sections, and stores with 384-dim embeddings for semantic search. Use allProjects=true to import from ALL Claude projects. Pass projectPath to override cwd-based detection (#1883 — required when Ruflo runs in WSL but Claude Code is on Windows).',
617
672
  category: 'memory',
618
673
  inputSchema: {
619
674
  type: 'object',
620
675
  properties: {
621
676
  allProjects: { type: 'boolean', description: 'Import from all Claude projects (default: current project only)' },
622
677
  namespace: { type: 'string', description: 'Target namespace (default: "claude-memories")' },
678
+ projectPath: { type: 'string', description: '#1883 — explicit project path to hash, used when cwd does not match Claude Code\'s view (e.g. WSL bridge to Windows host). Pass the canonical project root as Claude Code sees it.' },
623
679
  },
624
680
  },
625
681
  handler: async (input) => {
@@ -632,6 +688,7 @@ export const memoryTools = [
632
688
  return { success: false, imported: 0, error: vNs.error };
633
689
  }
634
690
  const allProjects = input.allProjects;
691
+ const projectPathOverride = input.projectPath;
635
692
  const claudeProjectsDir = join(homedir(), '.claude', 'projects');
636
693
  // Find memory files
637
694
  const memoryFiles = [];
@@ -654,14 +711,13 @@ export const memoryTools = [
654
711
  }
655
712
  }
656
713
  else {
657
- // Current project only find by CWD hash
658
- const cwd = process.cwd();
659
- const projectHash = cwd.replace(/\//g, '-');
660
- const memDir = join(claudeProjectsDir, projectHash, 'memory');
661
- if (existsSync(memDir)) {
714
+ // #1883 — current project: try multiple candidate hashes (POSIX, WSL-translated,
715
+ // leading-dash-stripped, space-replaced). Caller can pass projectPath to override.
716
+ const resolved = resolveProjectMemoryDir(claudeProjectsDir, projectPathOverride);
717
+ if (resolved) {
662
718
  try {
663
- for (const file of readdirSync(memDir).filter((f) => f.endsWith('.md'))) {
664
- memoryFiles.push({ path: join(memDir, file), project: projectHash, file });
719
+ for (const file of readdirSync(resolved.memDir).filter((f) => f.endsWith('.md'))) {
720
+ memoryFiles.push({ path: join(resolved.memDir, file), project: resolved.projectHash, file });
665
721
  }
666
722
  }
667
723
  catch { /* scan error */ }
@@ -707,7 +763,10 @@ export const memoryTools = [
707
763
  // Split into sections for granular search
708
764
  const sections = body.split(/^(?=## )/m).filter(s => s.trim().length > 20);
709
765
  if (sections.length === 0 && body.length > 10) {
710
- await storeEntry({ key: `claude:${memFile.project}:${name}`, value: body.slice(0, 4096), namespace: ns, generateEmbeddingFlag: true });
766
+ // #1884 sanitize key so memory_delete can later remove it. Without
767
+ // this, dangerous chars from frontmatter `name` strand the key.
768
+ const key = sanitizeMemoryKey(`claude:${memFile.project}:${name}`);
769
+ await storeEntry({ key, value: body.slice(0, 4096), namespace: ns, generateEmbeddingFlag: true });
711
770
  imported++;
712
771
  }
713
772
  else {
@@ -717,7 +776,10 @@ export const memoryTools = [
717
776
  const sectionBody = section.replace(/^##\s+.+\n/, '').trim();
718
777
  if (sectionBody.length < 10)
719
778
  continue;
720
- await storeEntry({ key: `claude:${memFile.project}:${name}:${sectionTitle.slice(0, 50)}`, value: sectionBody.slice(0, 4096), namespace: ns, generateEmbeddingFlag: true });
779
+ // #1884 sanitize so any dangerous chars in the heading don't
780
+ // produce keys memory_delete will reject.
781
+ const key = sanitizeMemoryKey(`claude:${memFile.project}:${name}:${sectionTitle.slice(0, 50)}`);
782
+ await storeEntry({ key, value: sectionBody.slice(0, 4096), namespace: ns, generateEmbeddingFlag: true });
721
783
  imported++;
722
784
  }
723
785
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.7.0-alpha.20",
3
+ "version": "3.7.0-alpha.21",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",