@cleocode/cleo 2026.3.32 → 2026.3.33

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.
package/dist/mcp/index.js CHANGED
@@ -12711,6 +12711,205 @@ var init_brain_retrieval = __esm({
12711
12711
  }
12712
12712
  });
12713
12713
 
12714
+ // src/core/memory/decisions.ts
12715
+ import { desc as desc3 } from "drizzle-orm";
12716
+ async function nextDecisionId(projectRoot) {
12717
+ const db = await getBrainDb(projectRoot);
12718
+ const rows = await db.select({ id: brainDecisions.id }).from(brainDecisions).orderBy(desc3(brainDecisions.id)).limit(1);
12719
+ if (rows.length === 0) {
12720
+ return "D001";
12721
+ }
12722
+ const lastId = rows[0].id;
12723
+ const num = parseInt(lastId.slice(1), 10);
12724
+ if (Number.isNaN(num)) {
12725
+ return "D001";
12726
+ }
12727
+ return `D${String(num + 1).padStart(3, "0")}`;
12728
+ }
12729
+ async function storeDecision(projectRoot, params) {
12730
+ if (!params.decision || !params.decision.trim()) {
12731
+ throw new Error("Decision text is required");
12732
+ }
12733
+ if (!params.rationale || !params.rationale.trim()) {
12734
+ throw new Error("Rationale is required");
12735
+ }
12736
+ const accessor = await getBrainAccessor(projectRoot);
12737
+ const existing = await accessor.findDecisions({ type: params.type });
12738
+ const duplicate = existing.find(
12739
+ (d) => d.decision.toLowerCase() === params.decision.toLowerCase()
12740
+ );
12741
+ if (duplicate) {
12742
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
12743
+ await accessor.updateDecision(duplicate.id, {
12744
+ rationale: params.rationale.trim(),
12745
+ confidence: params.confidence,
12746
+ outcome: params.outcome ?? duplicate.outcome,
12747
+ alternativesJson: params.alternatives ? JSON.stringify(params.alternatives) : duplicate.alternativesJson,
12748
+ updatedAt: now2
12749
+ });
12750
+ const updated = await accessor.getDecision(duplicate.id);
12751
+ return updated;
12752
+ }
12753
+ const id = await nextDecisionId(projectRoot);
12754
+ const row = {
12755
+ id,
12756
+ type: params.type,
12757
+ decision: params.decision.trim(),
12758
+ rationale: params.rationale.trim(),
12759
+ confidence: params.confidence,
12760
+ outcome: params.outcome,
12761
+ alternativesJson: params.alternatives ? JSON.stringify(params.alternatives) : void 0,
12762
+ contextEpicId: params.contextEpicId,
12763
+ contextTaskId: params.contextTaskId,
12764
+ contextPhase: params.contextPhase
12765
+ };
12766
+ return accessor.addDecision(row);
12767
+ }
12768
+ var init_decisions2 = __esm({
12769
+ "src/core/memory/decisions.ts"() {
12770
+ "use strict";
12771
+ init_brain_accessor();
12772
+ init_brain_schema();
12773
+ init_brain_sqlite();
12774
+ }
12775
+ });
12776
+
12777
+ // src/core/memory/learnings.ts
12778
+ import { randomBytes as randomBytes3 } from "node:crypto";
12779
+ function generateLearningId() {
12780
+ return `L-${randomBytes3(4).toString("hex")}`;
12781
+ }
12782
+ async function storeLearning(projectRoot, params) {
12783
+ if (!params.insight || !params.insight.trim()) {
12784
+ throw new Error("Insight text is required");
12785
+ }
12786
+ if (!params.source || !params.source.trim()) {
12787
+ throw new Error("Source is required");
12788
+ }
12789
+ if (params.confidence < 0 || params.confidence > 1) {
12790
+ throw new Error("Confidence must be between 0.0 and 1.0");
12791
+ }
12792
+ const accessor = await getBrainAccessor(projectRoot);
12793
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
12794
+ const existingLearnings = await accessor.findLearnings();
12795
+ const duplicate = existingLearnings.find(
12796
+ (e) => e.insight.toLowerCase() === params.insight.toLowerCase()
12797
+ );
12798
+ if (duplicate) {
12799
+ }
12800
+ const entry = {
12801
+ id: generateLearningId(),
12802
+ insight: params.insight.trim(),
12803
+ source: params.source.trim(),
12804
+ confidence: params.confidence,
12805
+ actionable: params.actionable ?? false,
12806
+ application: params.application ?? null,
12807
+ applicableTypesJson: params.applicableTypes ? JSON.stringify(params.applicableTypes) : "[]",
12808
+ extractedAt: now2
12809
+ };
12810
+ const saved = await accessor.addLearning(entry);
12811
+ return {
12812
+ ...saved,
12813
+ applicableTypes: JSON.parse(saved.applicableTypesJson || "[]")
12814
+ };
12815
+ }
12816
+ async function searchLearnings(projectRoot, params = {}) {
12817
+ const accessor = await getBrainAccessor(projectRoot);
12818
+ let entries = await accessor.findLearnings({
12819
+ minConfidence: params.minConfidence,
12820
+ actionable: params.actionableOnly,
12821
+ limit: params.limit
12822
+ });
12823
+ if (params.applicableType) {
12824
+ entries = entries.filter((e) => {
12825
+ const types = JSON.parse(e.applicableTypesJson || "[]");
12826
+ return types.includes(params.applicableType);
12827
+ });
12828
+ }
12829
+ if (params.query) {
12830
+ const q = params.query.toLowerCase();
12831
+ entries = entries.filter(
12832
+ (e) => e.insight.toLowerCase().includes(q) || e.source.toLowerCase().includes(q) || e.application?.toLowerCase().includes(q)
12833
+ );
12834
+ }
12835
+ entries.sort((a, b) => b.confidence - a.confidence);
12836
+ return entries.map((e) => ({
12837
+ ...e,
12838
+ applicableTypes: JSON.parse(e.applicableTypesJson || "[]")
12839
+ }));
12840
+ }
12841
+ var init_learnings = __esm({
12842
+ "src/core/memory/learnings.ts"() {
12843
+ "use strict";
12844
+ init_brain_accessor();
12845
+ }
12846
+ });
12847
+
12848
+ // src/core/memory/patterns.ts
12849
+ import { randomBytes as randomBytes4 } from "node:crypto";
12850
+ function generatePatternId() {
12851
+ return `P-${randomBytes4(4).toString("hex")}`;
12852
+ }
12853
+ async function storePattern(projectRoot, params) {
12854
+ if (!params.pattern || !params.pattern.trim()) {
12855
+ throw new Error("Pattern description is required");
12856
+ }
12857
+ if (!params.context || !params.context.trim()) {
12858
+ throw new Error("Pattern context is required");
12859
+ }
12860
+ const accessor = await getBrainAccessor(projectRoot);
12861
+ const existingPatterns = await accessor.findPatterns({ type: params.type });
12862
+ const duplicate = existingPatterns.find(
12863
+ (e) => e.pattern.toLowerCase() === params.pattern.toLowerCase()
12864
+ );
12865
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
12866
+ if (duplicate) {
12867
+ }
12868
+ const entry = {
12869
+ id: generatePatternId(),
12870
+ type: params.type,
12871
+ pattern: params.pattern.trim(),
12872
+ context: params.context.trim(),
12873
+ frequency: 1,
12874
+ successRate: params.successRate ?? null,
12875
+ impact: params.impact ?? null,
12876
+ antiPattern: params.antiPattern ?? null,
12877
+ mitigation: params.mitigation ?? null,
12878
+ examplesJson: params.examples ? JSON.stringify(params.examples) : "[]",
12879
+ extractedAt: now2
12880
+ };
12881
+ const saved = await accessor.addPattern(entry);
12882
+ return {
12883
+ ...saved,
12884
+ examples: JSON.parse(saved.examplesJson || "[]")
12885
+ };
12886
+ }
12887
+ async function searchPatterns(projectRoot, params = {}) {
12888
+ const accessor = await getBrainAccessor(projectRoot);
12889
+ let entries = await accessor.findPatterns({
12890
+ type: params.type,
12891
+ impact: params.impact,
12892
+ minFrequency: params.minFrequency,
12893
+ limit: params.limit
12894
+ });
12895
+ if (params.query) {
12896
+ const q = params.query.toLowerCase();
12897
+ entries = entries.filter(
12898
+ (e) => e.pattern.toLowerCase().includes(q) || e.context.toLowerCase().includes(q) || e.antiPattern?.toLowerCase().includes(q) || e.mitigation?.toLowerCase().includes(q)
12899
+ );
12900
+ }
12901
+ return entries.map((e) => ({
12902
+ ...e,
12903
+ examples: JSON.parse(e.examplesJson || "[]")
12904
+ }));
12905
+ }
12906
+ var init_patterns = __esm({
12907
+ "src/core/memory/patterns.ts"() {
12908
+ "use strict";
12909
+ init_brain_accessor();
12910
+ }
12911
+ });
12912
+
12714
12913
  // src/dispatch/engines/_error.ts
12715
12914
  function logLevel(exitCode) {
12716
12915
  if (exitCode === 0 || exitCode >= 100) return "debug";
@@ -19647,6 +19846,123 @@ var init_session_history = __esm({
19647
19846
  }
19648
19847
  });
19649
19848
 
19849
+ // src/core/memory/auto-extract.ts
19850
+ var auto_extract_exports = {};
19851
+ __export(auto_extract_exports, {
19852
+ extractSessionEndMemory: () => extractSessionEndMemory,
19853
+ extractTaskCompletionMemory: () => extractTaskCompletionMemory,
19854
+ resolveTaskDetails: () => resolveTaskDetails
19855
+ });
19856
+ async function extractTaskCompletionMemory(projectRoot, task, _parentTask) {
19857
+ try {
19858
+ await storeLearning(projectRoot, {
19859
+ insight: `Completed: ${task.title} \u2014 ${task.description ?? ""}`,
19860
+ source: `task-completion:${task.id}`,
19861
+ confidence: 0.7,
19862
+ actionable: true
19863
+ });
19864
+ const deps = task.depends ?? [];
19865
+ if (deps.length > 0) {
19866
+ await storeLearning(projectRoot, {
19867
+ insight: `Task ${task.id} depended on ${deps.join(", ")} \u2014 dependency chain completed successfully`,
19868
+ source: `task-completion:${task.id}`,
19869
+ confidence: 0.7
19870
+ });
19871
+ }
19872
+ const { getAccessor: getAccessor2 } = await Promise.resolve().then(() => (init_data_accessor(), data_accessor_exports));
19873
+ const accessor = await getAccessor2(projectRoot);
19874
+ let taskFile;
19875
+ try {
19876
+ taskFile = await accessor.loadTaskFile();
19877
+ } finally {
19878
+ await accessor.close();
19879
+ }
19880
+ const recentDone = taskFile.tasks.filter((t) => t.status === "done").slice(-50);
19881
+ const labelCounts = /* @__PURE__ */ new Map();
19882
+ for (const t of recentDone) {
19883
+ for (const label of t.labels ?? []) {
19884
+ const existing = labelCounts.get(label) ?? [];
19885
+ existing.push(t.id);
19886
+ labelCounts.set(label, existing);
19887
+ }
19888
+ }
19889
+ for (const [label, taskIds] of labelCounts.entries()) {
19890
+ if (taskIds.length >= 3) {
19891
+ await storePattern(projectRoot, {
19892
+ type: "success",
19893
+ pattern: `Recurring label "${label}" seen in ${taskIds.length} completed tasks`,
19894
+ context: `Auto-detected from task completion of ${task.id}`,
19895
+ impact: "medium",
19896
+ examples: taskIds
19897
+ });
19898
+ }
19899
+ }
19900
+ } catch {
19901
+ }
19902
+ }
19903
+ async function extractSessionEndMemory(projectRoot, sessionData, taskDetails) {
19904
+ try {
19905
+ if (taskDetails.length > 0) {
19906
+ await storeDecision(projectRoot, {
19907
+ type: "process",
19908
+ decision: `Session ${sessionData.sessionId} completed ${taskDetails.length} tasks: ${taskDetails.map((t) => t.id).join(", ")}`,
19909
+ rationale: `Session scope: ${sessionData.scope}. Duration: ${Math.round(sessionData.duration / 60)} min.`,
19910
+ confidence: "medium"
19911
+ });
19912
+ }
19913
+ for (const t of taskDetails) {
19914
+ await storeLearning(projectRoot, {
19915
+ insight: `Completed: ${t.title} \u2014 ${t.description ?? ""}`,
19916
+ source: `session-end:${sessionData.sessionId}`,
19917
+ confidence: 0.7,
19918
+ actionable: true
19919
+ });
19920
+ }
19921
+ const labelCounts = /* @__PURE__ */ new Map();
19922
+ for (const t of taskDetails) {
19923
+ for (const label of t.labels ?? []) {
19924
+ const existing = labelCounts.get(label) ?? [];
19925
+ existing.push(t.id);
19926
+ labelCounts.set(label, existing);
19927
+ }
19928
+ }
19929
+ for (const [label, taskIds] of labelCounts.entries()) {
19930
+ if (taskIds.length >= 2) {
19931
+ await storePattern(projectRoot, {
19932
+ type: "workflow",
19933
+ pattern: `Session ${sessionData.sessionId} completed ${taskIds.length} tasks with label "${label}"`,
19934
+ context: `Auto-detected from session end: ${sessionData.sessionId}`,
19935
+ impact: "medium",
19936
+ examples: taskIds
19937
+ });
19938
+ }
19939
+ }
19940
+ } catch {
19941
+ }
19942
+ }
19943
+ async function resolveTaskDetails(projectRoot, taskIds) {
19944
+ if (taskIds.length === 0) {
19945
+ return [];
19946
+ }
19947
+ const { getAccessor: getAccessor2 } = await Promise.resolve().then(() => (init_data_accessor(), data_accessor_exports));
19948
+ const accessor = await getAccessor2(projectRoot);
19949
+ try {
19950
+ const taskFile = await accessor.loadTaskFile();
19951
+ const idSet = new Set(taskIds);
19952
+ return taskFile.tasks.filter((t) => idSet.has(t.id));
19953
+ } finally {
19954
+ await accessor.close();
19955
+ }
19956
+ }
19957
+ var init_auto_extract = __esm({
19958
+ "src/core/memory/auto-extract.ts"() {
19959
+ "use strict";
19960
+ init_decisions2();
19961
+ init_learnings();
19962
+ init_patterns();
19963
+ }
19964
+ });
19965
+
19650
19966
  // src/core/sessions/session-memory-bridge.ts
19651
19967
  var session_memory_bridge_exports = {};
19652
19968
  __export(session_memory_bridge_exports, {
@@ -19669,6 +19985,12 @@ async function bridgeSessionToMemory(projectRoot, sessionData) {
19669
19985
  sourceSessionId: sessionData.sessionId,
19670
19986
  sourceType: "agent"
19671
19987
  });
19988
+ try {
19989
+ const { extractSessionEndMemory: extractSessionEndMemory2, resolveTaskDetails: resolveTaskDetails2 } = await Promise.resolve().then(() => (init_auto_extract(), auto_extract_exports));
19990
+ const taskDetails = await resolveTaskDetails2(projectRoot, sessionData.tasksCompleted);
19991
+ await extractSessionEndMemory2(projectRoot, sessionData, taskDetails);
19992
+ } catch {
19993
+ }
19672
19994
  } catch {
19673
19995
  }
19674
19996
  }
@@ -21988,6 +22310,10 @@ async function completeTask(options, cwd, accessor) {
21988
22310
  }
21989
22311
  Promise.resolve().then(() => (init_memory_bridge(), memory_bridge_exports)).then(({ refreshMemoryBridge: refreshMemoryBridge2 }) => refreshMemoryBridge2(cwd ?? process.cwd())).catch(() => {
21990
22312
  });
22313
+ Promise.resolve().then(() => (init_auto_extract(), auto_extract_exports)).then(
22314
+ ({ extractTaskCompletionMemory: extractTaskCompletionMemory2 }) => extractTaskCompletionMemory2(cwd ?? process.cwd(), task)
22315
+ ).catch(() => {
22316
+ });
21991
22317
  return {
21992
22318
  task,
21993
22319
  ...autoCompleted.length > 0 && { autoCompleted },
@@ -28441,140 +28767,9 @@ import { join as join20 } from "node:path";
28441
28767
  // src/core/memory/index.ts
28442
28768
  init_brain_retrieval();
28443
28769
  init_brain_search();
28444
-
28445
- // src/core/memory/decisions.ts
28446
- init_brain_accessor();
28447
- init_brain_schema();
28448
- init_brain_sqlite();
28449
- import { desc as desc3 } from "drizzle-orm";
28450
-
28451
- // src/core/memory/learnings.ts
28452
- init_brain_accessor();
28453
- import { randomBytes as randomBytes3 } from "node:crypto";
28454
- function generateLearningId() {
28455
- return `L-${randomBytes3(4).toString("hex")}`;
28456
- }
28457
- async function storeLearning(projectRoot, params) {
28458
- if (!params.insight || !params.insight.trim()) {
28459
- throw new Error("Insight text is required");
28460
- }
28461
- if (!params.source || !params.source.trim()) {
28462
- throw new Error("Source is required");
28463
- }
28464
- if (params.confidence < 0 || params.confidence > 1) {
28465
- throw new Error("Confidence must be between 0.0 and 1.0");
28466
- }
28467
- const accessor = await getBrainAccessor(projectRoot);
28468
- const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
28469
- const existingLearnings = await accessor.findLearnings();
28470
- const duplicate = existingLearnings.find(
28471
- (e) => e.insight.toLowerCase() === params.insight.toLowerCase()
28472
- );
28473
- if (duplicate) {
28474
- }
28475
- const entry = {
28476
- id: generateLearningId(),
28477
- insight: params.insight.trim(),
28478
- source: params.source.trim(),
28479
- confidence: params.confidence,
28480
- actionable: params.actionable ?? false,
28481
- application: params.application ?? null,
28482
- applicableTypesJson: params.applicableTypes ? JSON.stringify(params.applicableTypes) : "[]",
28483
- extractedAt: now2
28484
- };
28485
- const saved = await accessor.addLearning(entry);
28486
- return {
28487
- ...saved,
28488
- applicableTypes: JSON.parse(saved.applicableTypesJson || "[]")
28489
- };
28490
- }
28491
- async function searchLearnings(projectRoot, params = {}) {
28492
- const accessor = await getBrainAccessor(projectRoot);
28493
- let entries = await accessor.findLearnings({
28494
- minConfidence: params.minConfidence,
28495
- actionable: params.actionableOnly,
28496
- limit: params.limit
28497
- });
28498
- if (params.applicableType) {
28499
- entries = entries.filter((e) => {
28500
- const types = JSON.parse(e.applicableTypesJson || "[]");
28501
- return types.includes(params.applicableType);
28502
- });
28503
- }
28504
- if (params.query) {
28505
- const q = params.query.toLowerCase();
28506
- entries = entries.filter(
28507
- (e) => e.insight.toLowerCase().includes(q) || e.source.toLowerCase().includes(q) || e.application?.toLowerCase().includes(q)
28508
- );
28509
- }
28510
- entries.sort((a, b) => b.confidence - a.confidence);
28511
- return entries.map((e) => ({
28512
- ...e,
28513
- applicableTypes: JSON.parse(e.applicableTypesJson || "[]")
28514
- }));
28515
- }
28516
-
28517
- // src/core/memory/patterns.ts
28518
- init_brain_accessor();
28519
- import { randomBytes as randomBytes4 } from "node:crypto";
28520
- function generatePatternId() {
28521
- return `P-${randomBytes4(4).toString("hex")}`;
28522
- }
28523
- async function storePattern(projectRoot, params) {
28524
- if (!params.pattern || !params.pattern.trim()) {
28525
- throw new Error("Pattern description is required");
28526
- }
28527
- if (!params.context || !params.context.trim()) {
28528
- throw new Error("Pattern context is required");
28529
- }
28530
- const accessor = await getBrainAccessor(projectRoot);
28531
- const existingPatterns = await accessor.findPatterns({ type: params.type });
28532
- const duplicate = existingPatterns.find(
28533
- (e) => e.pattern.toLowerCase() === params.pattern.toLowerCase()
28534
- );
28535
- const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
28536
- if (duplicate) {
28537
- }
28538
- const entry = {
28539
- id: generatePatternId(),
28540
- type: params.type,
28541
- pattern: params.pattern.trim(),
28542
- context: params.context.trim(),
28543
- frequency: 1,
28544
- successRate: params.successRate ?? null,
28545
- impact: params.impact ?? null,
28546
- antiPattern: params.antiPattern ?? null,
28547
- mitigation: params.mitigation ?? null,
28548
- examplesJson: params.examples ? JSON.stringify(params.examples) : "[]",
28549
- extractedAt: now2
28550
- };
28551
- const saved = await accessor.addPattern(entry);
28552
- return {
28553
- ...saved,
28554
- examples: JSON.parse(saved.examplesJson || "[]")
28555
- };
28556
- }
28557
- async function searchPatterns(projectRoot, params = {}) {
28558
- const accessor = await getBrainAccessor(projectRoot);
28559
- let entries = await accessor.findPatterns({
28560
- type: params.type,
28561
- impact: params.impact,
28562
- minFrequency: params.minFrequency,
28563
- limit: params.limit
28564
- });
28565
- if (params.query) {
28566
- const q = params.query.toLowerCase();
28567
- entries = entries.filter(
28568
- (e) => e.pattern.toLowerCase().includes(q) || e.context.toLowerCase().includes(q) || e.antiPattern?.toLowerCase().includes(q) || e.mitigation?.toLowerCase().includes(q)
28569
- );
28570
- }
28571
- return entries.map((e) => ({
28572
- ...e,
28573
- examples: JSON.parse(e.examplesJson || "[]")
28574
- }));
28575
- }
28576
-
28577
- // src/core/memory/index.ts
28770
+ init_decisions2();
28771
+ init_learnings();
28772
+ init_patterns();
28578
28773
  function filterManifestEntries(entries, filter) {
28579
28774
  let filtered = entries;
28580
28775
  if (filter.taskId) {
@@ -30457,6 +30652,8 @@ init_data_accessor();
30457
30652
  init_paths();
30458
30653
  init_brain_links();
30459
30654
  init_brain_retrieval();
30655
+ init_learnings();
30656
+ init_patterns();
30460
30657
  function resolveRoot(projectRoot) {
30461
30658
  return projectRoot || getProjectRoot();
30462
30659
  }