@claude-flow/cli 3.56.10 → 3.57.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 (73) hide show
  1. package/.claude/helpers/.helpers-version +1 -1
  2. package/.claude/helpers/helpers.manifest.json +2 -2
  3. package/README.md +12 -3
  4. package/catalog-manifest.json +2 -2
  5. package/dist/src/commands/daemon.js +8 -2
  6. package/dist/src/commands/doctor.js +95 -18
  7. package/dist/src/commands/policy.js +6 -1
  8. package/dist/src/index.js +5 -5
  9. package/dist/src/init/settings-generator.js +4 -58
  10. package/dist/src/mcp-tools/memory-tools.d.ts +1 -1
  11. package/dist/src/mcp-tools/memory-tools.js +30 -5
  12. package/dist/src/mcp-tools/metaharness-tools.js +1 -1
  13. package/dist/src/mcp-tools/neural-tools.js +20 -50
  14. package/dist/src/mcp-tools/policy-tools.js +5 -3
  15. package/dist/src/memory/intelligence.js +80 -33
  16. package/dist/src/memory/stats-file-lock.d.ts +7 -0
  17. package/dist/src/memory/stats-file-lock.js +53 -0
  18. package/dist/src/missions/schemas.d.ts +113 -113
  19. package/dist/src/mods/command-registry/schema.d.ts +193 -193
  20. package/dist/src/services/distill-oracle.d.ts +1 -1
  21. package/dist/src/services/distill-oracle.js +2 -2
  22. package/dist/src/services/policy-anchor-log.d.ts +13 -0
  23. package/dist/src/services/policy-anchor-log.js +242 -0
  24. package/dist/src/services/policy-archive-scan.d.ts +7 -0
  25. package/dist/src/services/policy-archive-scan.js +50 -0
  26. package/dist/src/services/policy-ledger-anchor.d.ts +14 -8
  27. package/dist/src/services/policy-ledger-anchor.js +356 -40
  28. package/dist/src/services/policy-ledger-audit.d.ts +22 -0
  29. package/dist/src/services/policy-ledger-audit.js +260 -0
  30. package/dist/src/services/policy-ledger-record.d.ts +3 -0
  31. package/dist/src/services/policy-ledger-record.js +22 -0
  32. package/dist/src/services/policy-runtime.d.ts +1 -0
  33. package/dist/src/services/policy-runtime.js +261 -40
  34. package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
  35. package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
  36. package/node_modules/@claude-flow/security/dist/input-validator.d.ts +6 -6
  37. package/node_modules/@claude-flow/security/dist/policy/engine.d.ts +17 -1
  38. package/node_modules/@claude-flow/security/dist/policy/engine.d.ts.map +1 -1
  39. package/node_modules/@claude-flow/security/dist/policy/engine.js +99 -24
  40. package/node_modules/@claude-flow/security/dist/policy/engine.js.map +1 -1
  41. package/node_modules/@claude-flow/security/dist/policy/types.d.ts +14 -1
  42. package/node_modules/@claude-flow/security/dist/policy/types.d.ts.map +1 -1
  43. package/node_modules/@claude-flow/security/dist/policy/types.js +3 -1
  44. package/node_modules/@claude-flow/security/dist/policy/types.js.map +1 -1
  45. package/package.json +3 -3
  46. package/plugins/ruflo-console/dist/tui.mjs +153 -153
  47. package/plugins/ruflo-metaharness/hooks/screen.ts +7 -1
  48. package/plugins/ruflo-metaharness/scripts/_darwin.mjs +4 -4
  49. package/plugins/ruflo-metaharness/.claude-flow/daemon-state.json +0 -179
  50. package/plugins/ruflo-metaharness/.claude-flow/daemon.pid +0 -1
  51. package/plugins/ruflo-metaharness/.claude-flow/logs/daemon.log +0 -32
  52. package/plugins/ruflo-metaharness/.claude-flow/metrics/backup.json +0 -23
  53. package/plugins/ruflo-metaharness/.claude-flow/metrics/codebase-map.json +0 -11
  54. package/plugins/ruflo-metaharness/.claude-flow/metrics/consolidation.json +0 -16
  55. package/plugins/ruflo-metaharness/.claude-flow/metrics/harness-loop.json +0 -91
  56. package/plugins/ruflo-metaharness/.claude-flow/metrics/performance.json +0 -17
  57. package/plugins/ruflo-metaharness/.claude-flow/metrics/security-audit.json +0 -12
  58. package/plugins/ruflo-metaharness/.claude-flow/metrics/test-gaps.json +0 -8
  59. package/plugins/ruflo-metaharness/.claude-flow/neural/patterns.json +0 -2809
  60. package/plugins/ruflo-metaharness/.claude-flow/neural/stats.json +0 -6
  61. package/plugins/ruflo-metaharness/.claude-flow/policy/state.json +0 -11
  62. package/plugins/ruflo-metaharness/.swarm/agentdb-memory.db +0 -0
  63. package/plugins/ruflo-metaharness/.swarm/agentdb-memory.db-shm +0 -0
  64. package/plugins/ruflo-metaharness/.swarm/agentdb-memory.db-wal +0 -0
  65. package/plugins/ruflo-metaharness/.swarm/backups/memory-2026-10-14T16-09-38-164Z.db +0 -0
  66. package/plugins/ruflo-metaharness/.swarm/backups/store-agentdb-memory.db-2026-10-14T16-09-38-166Z.db +0 -0
  67. package/plugins/ruflo-metaharness/.swarm/ewc-fisher.json +0 -397
  68. package/plugins/ruflo-metaharness/.swarm/memory.db +0 -0
  69. package/plugins/ruflo-metaharness/.swarm/memory.db-shm +0 -0
  70. package/plugins/ruflo-metaharness/.swarm/memory.db-wal +0 -0
  71. package/plugins/ruflo-metaharness/agentdb.rvf +0 -0
  72. package/plugins/ruflo-metaharness/agentdb.rvf.lock +0 -0
  73. package/plugins/ruflo-metaharness/ruvector.db +0 -0
@@ -908,9 +908,6 @@ export const neuralTools = [
908
908
  if (!v.valid)
909
909
  return { success: false, error: v.error };
910
910
  }
911
- // Resolve provider so embeddingProvider in the result matches the old
912
- // eager-init reporting.
913
- await ensureEmbeddings();
914
911
  const store = loadNeuralStore();
915
912
  const method = input.method || 'quantize';
916
913
  const targetReduction = input.targetSize || 0.5;
@@ -919,38 +916,25 @@ export const neuralTools = [
919
916
  return { success: false, error: 'No patterns to compress. Train patterns first with neural_train.' };
920
917
  }
921
918
  const beforeCount = patterns.length;
922
- const beforeSize = patterns.reduce((s, p) => s + (p.embedding?.length || 0) * 4, 0); // Float32 = 4 bytes
923
919
  if (method === 'quantize') {
924
- try {
925
- const { quantizeInt8, getQuantizationStats } = await import('../memory/memory-initializer.js');
926
- let totalCompressed = 0;
927
- for (const pattern of patterns) {
928
- if (pattern.embedding && pattern.embedding.length > 0) {
929
- const stats = getQuantizationStats(pattern.embedding);
930
- const quantized = quantizeInt8(pattern.embedding);
931
- // Store quantized metadata (keep original embedding for search)
932
- pattern._quantized = {
933
- scale: quantized.scale,
934
- zeroPoint: quantized.zeroPoint,
935
- compressionRatio: stats.compressionRatio,
936
- };
937
- totalCompressed++;
938
- }
939
- }
940
- saveNeuralStore(store);
941
- return {
942
- success: true, _real: true, method,
943
- embeddingProvider: embeddingServiceName,
944
- patternsCompressed: totalCompressed,
945
- compressionRatio: '3.92x (Int8)',
946
- beforeBytes: beforeSize,
947
- afterBytes: Math.round(beforeSize / 3.92),
948
- };
949
- }
950
- catch {
951
- return { success: false, error: 'Quantization requires memory-initializer. Run `memory init` first.' };
952
- }
920
+ // Neural-store readers consume `embedding` as a full-precision number[]
921
+ // (search, prediction, deduplication, and optimization). The former
922
+ // implementation discarded the Int8 vector, persisted only metadata,
923
+ // and reported a calculated 3.92x reduction. Refuse until the store has
924
+ // a persisted representation with a reader-side decode contract.
925
+ const storedBytes = readFileSync(getNeuralPath()).byteLength;
926
+ return {
927
+ success: false,
928
+ error: 'Quantized embeddings are not persisted: neural-store readers require full-precision embedding arrays.',
929
+ method,
930
+ patternsCompressed: 0,
931
+ beforeBytes: storedBytes,
932
+ afterBytes: storedBytes,
933
+ compressionRatio: '1.00x (unchanged JSON storage)',
934
+ };
953
935
  }
936
+ // Resolve provider only for operations that actually use embeddings.
937
+ await ensureEmbeddings();
954
938
  if (method === 'prune') {
955
939
  // Prune patterns with low usage count below threshold (targetReduction as min usage)
956
940
  const threshold = targetReduction;
@@ -1136,24 +1120,10 @@ export const neuralTools = [
1136
1120
  if (duplicatesRemoved > 0)
1137
1121
  actions.push(`Removed ${duplicatesRemoved} near-duplicate patterns`);
1138
1122
  }
1139
- // memory / balanced: quantize large embeddings
1123
+ // memory / balanced: report the unsupported persisted representation
1124
+ // instead of attaching metadata for a discarded Int8 vector.
1140
1125
  if (target === 'memory' || target === 'balanced') {
1141
- try {
1142
- const { quantizeInt8, getQuantizationStats } = await import('../memory/memory-initializer.js');
1143
- for (const p of Object.values(store.patterns)) {
1144
- if (p.embedding && p.embedding.length > 0 && !p._quantized) {
1145
- const stats = getQuantizationStats(p.embedding);
1146
- const q = quantizeInt8(p.embedding);
1147
- p._quantized = { scale: q.scale, zeroPoint: q.zeroPoint, compressionRatio: stats.compressionRatio };
1148
- patternsQuantized++;
1149
- }
1150
- }
1151
- if (patternsQuantized > 0)
1152
- actions.push(`Quantized ${patternsQuantized} pattern embeddings (Int8, ~3.92x)`);
1153
- }
1154
- catch {
1155
- actions.push('Quantization skipped (memory-initializer not available)');
1156
- }
1126
+ actions.push('Quantization skipped: neural-store readers require persisted full-precision embedding arrays.');
1157
1127
  }
1158
1128
  // accuracy / balanced: prune low-usage, zero-embedding patterns
1159
1129
  if (target === 'accuracy' || target === 'balanced') {
@@ -24,9 +24,11 @@ export const policyTools = [
24
24
  category: 'security',
25
25
  inputSchema: {
26
26
  type: 'object',
27
- properties: {},
27
+ properties: {
28
+ full: { type: 'boolean', description: 'Also replay the archived receipts to verify the complete historical ledger, not just the retained hot tail (#3164)' },
29
+ },
28
30
  },
29
- handler: async (_input, context) => {
31
+ handler: async (input, context) => {
30
32
  const root = typeof context?.projectRoot === 'string' ? context.projectRoot : process.cwd();
31
33
  const state = loadPolicyState(root);
32
34
  return {
@@ -39,7 +41,7 @@ export const policyTools = [
39
41
  approvals: state.approvals.length,
40
42
  receipts: state.receipts.length,
41
43
  },
42
- ledger: await verifyPolicyLedger(root),
44
+ ledger: await verifyPolicyLedger(root, { full: input.full === true }),
43
45
  };
44
46
  },
45
47
  },
@@ -16,6 +16,7 @@ import { createRequire } from 'node:module';
16
16
  import { join } from 'node:path';
17
17
  import { resolveTrainingBackend } from '../ruvector/lora-adapter.js';
18
18
  import { getProjectCwd } from '../mcp-tools/types.js';
19
+ import { withStatsFileLock } from './stats-file-lock.js';
19
20
  // ============================================================================
20
21
  // Persistence Configuration
21
22
  // ============================================================================
@@ -664,11 +665,9 @@ function bumpStat(key, n = 1) {
664
665
  }
665
666
  function readStatsFile() {
666
667
  try {
667
- const path = getStatsPath();
668
- if (!existsSync(path))
669
- return null;
670
- const data = JSON.parse(readFileSync(path, 'utf-8'));
671
- return data && typeof data === 'object' ? data : null;
668
+ // Read-only callers keep their unavailable-on-error contract, while invalid
669
+ // disk values cannot poison local state and a later repaired-file flush.
670
+ return readStatsForWrite(getStatsPath());
672
671
  }
673
672
  catch {
674
673
  return null;
@@ -701,33 +700,79 @@ function maxTimestamp(a, b) {
701
700
  return a;
702
701
  return Math.max(a, b);
703
702
  }
704
- /**
705
- * Save stats to disk: merge this process's unsaved deltas into whatever is
706
- * currently on disk (read-merge-write, atomic rename), then adopt the merged
707
- * totals locally so this process also sees other writers' progress.
708
- */
703
+ /** Missing files are first use; unreadable or invalid files must not be replaced. */
704
+ function readStatsForWrite(path) {
705
+ let text;
706
+ try {
707
+ text = readFileSync(path, 'utf-8');
708
+ }
709
+ catch (error) {
710
+ if (error.code === 'ENOENT')
711
+ return null;
712
+ throw error;
713
+ }
714
+ let data;
715
+ try {
716
+ data = JSON.parse(text);
717
+ }
718
+ catch {
719
+ throw Object.assign(new Error('Invalid learning stats JSON'), { code: 'EINVALIDSTATS' });
720
+ }
721
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
722
+ throw Object.assign(new Error('Invalid learning stats object'), { code: 'EINVALIDSTATS' });
723
+ }
724
+ for (const key of ['trajectoriesRecorded', 'patternsLearned', 'signalsProcessed']) {
725
+ const value = data[key];
726
+ // Older files may omit a counter, but present counters must be exact counts.
727
+ if (value === undefined)
728
+ continue;
729
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
730
+ throw Object.assign(new Error(`Invalid learning stats field: ${key}`), { code: 'EINVALIDSTATS' });
731
+ }
732
+ }
733
+ const timestamp = data.lastAdaptation;
734
+ if (timestamp != null && (typeof timestamp !== 'number' || !Number.isFinite(timestamp) || timestamp < 0)) {
735
+ throw Object.assign(new Error('Invalid learning stats timestamp'), { code: 'EINVALIDSTATS' });
736
+ }
737
+ return data;
738
+ }
739
+ /** Merge pending deltas under the cooperating-writer lock, then adopt committed totals. */
709
740
  function savePersistedStats() {
741
+ let statsPath;
710
742
  try {
711
- ensureDataDir();
712
- const path = getStatsPath();
713
- const disk = readStatsFile();
714
- const merged = disk
715
- ? {
716
- trajectoriesRecorded: (disk.trajectoriesRecorded ?? 0) + pendingDelta.trajectoriesRecorded,
717
- patternsLearned: (disk.patternsLearned ?? 0) + pendingDelta.patternsLearned,
718
- signalsProcessed: (disk.signalsProcessed ?? 0) + pendingDelta.signalsProcessed,
719
- lastAdaptation: maxTimestamp(disk.lastAdaptation ?? null, globalStats.lastAdaptation),
743
+ statsPath = join(ensureDataDir(), 'stats.json');
744
+ withStatsFileLock(statsPath, (path) => {
745
+ const disk = readStatsForWrite(path);
746
+ const merged = disk
747
+ ? {
748
+ trajectoriesRecorded: (disk.trajectoriesRecorded ?? 0) + pendingDelta.trajectoriesRecorded,
749
+ patternsLearned: (disk.patternsLearned ?? 0) + pendingDelta.patternsLearned,
750
+ signalsProcessed: (disk.signalsProcessed ?? 0) + pendingDelta.signalsProcessed,
751
+ lastAdaptation: maxTimestamp(disk.lastAdaptation ?? null, globalStats.lastAdaptation),
752
+ }
753
+ : { ...globalStats };
754
+ for (const key of ['trajectoriesRecorded', 'patternsLearned', 'signalsProcessed']) {
755
+ if (!Number.isSafeInteger(merged[key]) || merged[key] < 0) {
756
+ throw Object.assign(new Error('Learning stats counter overflow'), { code: 'EINVALIDSTATS' });
757
+ }
758
+ }
759
+ if (merged.lastAdaptation != null &&
760
+ (!Number.isFinite(merged.lastAdaptation) || merged.lastAdaptation < 0)) {
761
+ throw Object.assign(new Error('Invalid merged learning stats timestamp'), { code: 'EINVALIDSTATS' });
720
762
  }
721
- : { ...globalStats };
722
- const tmp = `${path}.${process.pid}.tmp`;
723
- writeFileSync(tmp, JSON.stringify(merged, null, 2), 'utf-8');
724
- renameSync(tmp, path);
725
- globalStats = merged;
726
- pendingDelta = { trajectoriesRecorded: 0, patternsLearned: 0, signalsProcessed: 0 };
727
- persistedStatsLoaded = true;
763
+ const tmp = `${path}.${process.pid}.tmp`;
764
+ writeFileSync(tmp, JSON.stringify(merged, null, 2), 'utf-8');
765
+ renameSync(tmp, path);
766
+ // Commit local state before release: a failed release must not replay it.
767
+ globalStats = merged;
768
+ pendingDelta = { trajectoriesRecorded: 0, patternsLearned: 0, signalsProcessed: 0 };
769
+ persistedStatsLoaded = true;
770
+ });
728
771
  }
729
- catch {
730
- // Ignore save errors (deltas are retained for the next save)
772
+ catch (error) {
773
+ const { code = 'UNKNOWN', path = statsPath || 'neural stats directory' } = error;
774
+ // Do not print file contents, which may be malformed or user-controlled.
775
+ console.warn(`[intelligence] Could not persist learning stats at ${path} (${code}); pending increments retained`);
731
776
  }
732
777
  }
733
778
  /**
@@ -1015,13 +1060,15 @@ export async function recordTrajectory(steps, verdict) {
1015
1060
  const avgQuality = verdict === 'success' ? 1.0 : verdict === 'partial' ? 0.5 : 0.0;
1016
1061
  ruvllmCoord.recordTrajectory({
1017
1062
  steps: enrichedSteps.map(s => ({
1018
- state: s.content,
1019
- action: s.type,
1020
- reward: avgQuality,
1021
- embedding: s.embedding || []
1063
+ type: ['query', 'route', 'generate', 'memory', 'feedback'].includes(s.type)
1064
+ ? s.type : 'generate',
1065
+ input: s.content,
1066
+ output: '',
1067
+ durationMs: 0,
1068
+ confidence: avgQuality
1022
1069
  })),
1023
1070
  totalReward: avgQuality,
1024
- success: verdict === 'success'
1071
+ outcome: verdict
1025
1072
  });
1026
1073
  }
1027
1074
  catch {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Serialize cooperating local writers without stealing a paused writer's lock.
3
+ * Abnormal termination can leave an orphan: recovery requires confirming that
4
+ * no writer still owns the directory before removing it. Never age-reap it.
5
+ */
6
+ export declare function withStatsFileLock<T>(file: string, write: (canonicalFile: string) => T): T;
7
+ //# sourceMappingURL=stats-file-lock.d.ts.map
@@ -0,0 +1,53 @@
1
+ import { mkdirSync, realpathSync, rmdirSync } from 'node:fs';
2
+ import { basename, dirname, join } from 'node:path';
3
+ /**
4
+ * Serialize cooperating local writers without stealing a paused writer's lock.
5
+ * Abnormal termination can leave an orphan: recovery requires confirming that
6
+ * no writer still owns the directory before removing it. Never age-reap it.
7
+ */
8
+ export function withStatsFileLock(file, write) {
9
+ const canonicalFile = join(realpathSync(dirname(file)), basename(file));
10
+ const lock = `${canonicalFile}.lock`;
11
+ const deadline = performance.now() + 1000;
12
+ const sleeper = new Int32Array(new SharedArrayBuffer(4));
13
+ for (;;) {
14
+ try {
15
+ mkdirSync(lock, { mode: 0o700 });
16
+ break;
17
+ }
18
+ catch (error) {
19
+ if (error.code !== 'EEXIST')
20
+ throw error;
21
+ const remaining = deadline - performance.now();
22
+ if (remaining <= 0) {
23
+ throw Object.assign(new Error('Learning stats lock is busy'), { code: 'ELOCKED', path: lock });
24
+ }
25
+ Atomics.wait(sleeper, 0, 0, Math.min(10, remaining));
26
+ }
27
+ }
28
+ const cleanup = () => {
29
+ // Only remove our empty directory. Never recursively remove foreign data.
30
+ rmdirSync(lock);
31
+ };
32
+ const onExit = () => {
33
+ try {
34
+ cleanup();
35
+ }
36
+ catch { /* abnormal exits may require deliberate recovery */ }
37
+ };
38
+ process.once('exit', onExit);
39
+ try {
40
+ return write(canonicalFile);
41
+ }
42
+ finally {
43
+ process.removeListener('exit', onExit);
44
+ try {
45
+ cleanup();
46
+ }
47
+ catch (error) {
48
+ const code = error.code || 'UNKNOWN';
49
+ console.warn(`[intelligence] Could not release learning stats lock at ${lock} (${code}); verify ownership before recovery`);
50
+ }
51
+ }
52
+ }
53
+ //# sourceMappingURL=stats-file-lock.js.map