@claude-flow/cli 3.65.0 → 3.66.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.
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "manifest": {
3
- "version": "3.65.0",
3
+ "version": "3.66.0",
4
4
  "files": {
5
5
  "auto-memory-hook.mjs": "631fac9d518835e2852a406888316bbbddddb49e7ed8e406d2e971f46833df9a",
6
- "hook-handler.cjs": "24502a3bcb78770971147940515c992e35b6736ae14ee2dc54e07d4cdef6a1d8",
6
+ "hook-handler.cjs": "0ce70981aa33f76d008b6f49626effaf4269918c4094f1a28c1ef6fceb097d6f",
7
7
  "intelligence.cjs": "1d981d6c6a35d70a66450e96458e26169e0cede11523ea246a2c129c197a5b4e",
8
8
  "statusline.cjs": "d72417ecb38634011a19f095a30e07b9929e6f97663520172ece9be7491b2eaa",
9
- "router.cjs": "16648b3c0d73b6681ac2d8d13def6a68286c57f5a11004de5b19a0fa088c833d"
9
+ "router.cjs": "16648b3c0d73b6681ac2d8d13def6a68286c57f5a11004de5b19a0fa088c833d",
10
+ "learning-loop.cjs": "d046cd6f8efb7dd40e1d2451516c181fc8b26477aefb1124c0df5f52a23f9190"
10
11
  }
11
12
  },
12
- "signature": "cwZNQ9x3YdIZ8qur+qzjhgVAubgv3FSXoWEfhkPtNc86sTPBOg6zlIb8Z2bt8ogZ8PnVmNgKas6Ft6QswIBiBg==",
13
+ "signature": "0JTgpgicsDJAdV6HhU9yPawpjklEbbSsyFjLJAqSh2jX9Jx8w4I5wS/EPnd5yp66HNpgU0up0Shay0qTdHeZAA==",
13
14
  "algorithm": "ed25519"
14
15
  }
@@ -647,6 +647,8 @@ const router = safeRequire(path.join(helpersDir, 'router.cjs'));
647
647
  const session = safeRequire(path.join(helpersDir, 'session.cjs'));
648
648
  const memory = safeRequire(path.join(helpersDir, 'memory.cjs'));
649
649
  const intelligence = safeRequire(path.join(helpersDir, 'intelligence.cjs'));
650
+ // ADR-512: the verified-outcome learning loop, bundled from the ruflo-mods loop source.
651
+ const learningLoop = safeRequire(path.join(helpersDir, 'learning-loop.cjs'));
650
652
 
651
653
  // ── Intelligence timeout protection (fixes #1530, #1531) ───────────────────
652
654
  const INTELLIGENCE_TIMEOUT_MS = 3000;
@@ -703,6 +705,50 @@ async function readStdin() {
703
705
  // keeps it from firing twice. Only side-effect events can be handed over:
704
706
  // guards such as pre-bash always run, whatever the variable says.
705
707
  const MOD_OWNABLE_EVENTS = new Set(['route', 'post-edit']);
708
+
709
+ // ADR-512: classic hooks run the verified-outcome learning loop for users without the mod. A
710
+ // mod that records turns itself says so with `learning-loop` (or, before ADR-512, owns
711
+ // `route`), so a turn is never recorded twice.
712
+ function modRecordsTurns(env = process.env) {
713
+ return String(env.RUFLO_MODS_OWNS || '').split(',').some((owned) => ['learning-loop', 'route'].includes(owned.trim()));
714
+ }
715
+
716
+ function learningLoopRoot() {
717
+ return process.env.CLAUDE_PROJECT_DIR || process.cwd();
718
+ }
719
+
720
+ // Records the turns the session transcript gained since the last look (all of them when the
721
+ // session ends). Returns the number recorded; never throws.
722
+ function recordLearningTurns(hookInput, final) {
723
+ try {
724
+ const root = learningLoopRoot();
725
+ if (!learningLoop || modRecordsTurns() || !learningLoop.enabled(root)) return 0;
726
+ const agentFor = (text) => {
727
+ try { return (router && router.routeTask && router.routeTask(text).agent) || 'coder'; } catch (e) { return 'coder'; }
728
+ };
729
+ return learningLoop.recordTurns({
730
+ root,
731
+ transcriptPath: hookInput.transcript_path || hookInput.transcriptPath,
732
+ session: hookInput.session_id || hookInput.sessionId,
733
+ final,
734
+ agentFor,
735
+ });
736
+ } catch (e) { return 0; }
737
+ }
738
+
739
+ // Trains SONA from the recorded turns in a detached `ruflo hooks verified-ingest` (a hook has
740
+ // seconds; an ingest may take longer). At most one spawn a minute per project.
741
+ function spawnLearningIngest() {
742
+ try {
743
+ const root = learningLoopRoot();
744
+ if (!learningLoop || !learningLoop.enabled(root) || !learningLoop.ingestDue(root)) return;
745
+ const stamp = path.join(root, '.claude-flow', 'data', 'verified-ingest.spawned');
746
+ try { if (Date.now() - fs.statSync(stamp).mtimeMs < 60 * 1000) return; } catch (e) { /* never spawned */ }
747
+ fs.mkdirSync(path.dirname(stamp), { recursive: true });
748
+ fs.writeFileSync(stamp, String(Date.now()));
749
+ spawnDetachedHookRefresh('verified-ingest');
750
+ } catch (e) { /* best-effort only */ }
751
+ }
706
752
  function ownedByMod(cmd, env = process.env) {
707
753
  if (!MOD_OWNABLE_EVENTS.has(cmd)) return false;
708
754
  return String(env.RUFLO_MODS_OWNS || '').split(',').some((owned) => owned.trim() === cmd);
@@ -751,6 +797,16 @@ async function main() {
751
797
  try { hookInput = JSON.parse(stdinData); } catch (e) { /* ignore parse errors */ }
752
798
  }
753
799
 
800
+ // ADR-512: record what finished and train from it, before the dedup below: it keys session-end
801
+ // on the session id, so after a PreCompact the real SessionEnd would never record the last turn.
802
+ // Recording is idempotent (a per-session transcript offset, ids from transcript positions).
803
+ // PreCompact runs mid-session, where the open turn may still edit and verify: only SessionEnd
804
+ // closes it.
805
+ if (command === 'session-end') {
806
+ recordLearningTurns(hookInput, (hookInput.hook_event_name || hookInput.hookEventName) !== 'PreCompact');
807
+ spawnLearningIngest();
808
+ }
809
+
754
810
  if ((command === 'post-edit' || command === 'session-end') &&
755
811
  !claimSideEffectEvent(command, stdinData, hookInput)) {
756
812
  return;
@@ -789,6 +845,16 @@ async function main() {
789
845
 
790
846
  const handlers = {
791
847
  'route': () => {
848
+ // ADR-512: record the turns that finished, then cite the verified lessons that fit this prompt.
849
+ recordLearningTurns(hookInput, false);
850
+ if (learningLoop && !modRecordsTurns()) {
851
+ try {
852
+ if (learningLoop.enabled(learningLoopRoot())) {
853
+ const block = learningLoop.lessonsForPrompt(learningLoopRoot(), prompt);
854
+ if (block) console.log(block);
855
+ }
856
+ } catch (e) { /* non-fatal */ }
857
+ }
792
858
  // Inject ranked intelligence context before routing
793
859
  // ADR-472: keep the detailed recall so ONE bounded log record (ids, scores, router pick; never the prompt) is appended after routing.
794
860
  let recall = null;