@cleocode/core 2026.4.50 → 2026.4.52

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 (52) hide show
  1. package/dist/index.js +511 -41
  2. package/dist/index.js.map +4 -4
  3. package/dist/internal.d.ts +4 -0
  4. package/dist/internal.d.ts.map +1 -1
  5. package/dist/internal.js +669 -45
  6. package/dist/internal.js.map +4 -4
  7. package/dist/memory/brain-export.d.ts +70 -0
  8. package/dist/memory/brain-export.d.ts.map +1 -0
  9. package/dist/memory/brain-lifecycle.d.ts +7 -0
  10. package/dist/memory/brain-lifecycle.d.ts.map +1 -1
  11. package/dist/memory/brain-retrieval.d.ts.map +1 -1
  12. package/dist/memory/brain-stdp.d.ts +122 -0
  13. package/dist/memory/brain-stdp.d.ts.map +1 -0
  14. package/dist/memory/decision-cross-link.d.ts +70 -0
  15. package/dist/memory/decision-cross-link.d.ts.map +1 -0
  16. package/dist/memory/decisions.d.ts.map +1 -1
  17. package/dist/memory/edge-types.d.ts +24 -0
  18. package/dist/memory/edge-types.d.ts.map +1 -0
  19. package/dist/memory/index.d.ts +1 -0
  20. package/dist/memory/index.d.ts.map +1 -1
  21. package/dist/store/brain-schema.d.ts +150 -3
  22. package/dist/store/brain-schema.d.ts.map +1 -1
  23. package/dist/store/brain-sqlite.d.ts.map +1 -1
  24. package/dist/store/validation-schemas.d.ts +1 -0
  25. package/dist/store/validation-schemas.d.ts.map +1 -1
  26. package/dist/validation/verification.d.ts.map +1 -1
  27. package/migrations/drizzle-brain/20260415000001_t626-normalize-co-retrieved-edge-type/migration.sql +14 -0
  28. package/package.json +8 -8
  29. package/src/internal.ts +14 -0
  30. package/src/memory/__tests__/brain-stdp.test.ts +452 -0
  31. package/src/memory/__tests__/decision-cross-link.test.ts +240 -0
  32. package/src/memory/brain-embedding.ts +1 -1
  33. package/src/memory/brain-export.ts +286 -0
  34. package/src/memory/brain-lifecycle.ts +23 -4
  35. package/src/memory/brain-retrieval.ts +80 -14
  36. package/src/memory/brain-similarity.ts +1 -1
  37. package/src/memory/brain-stdp.ts +448 -0
  38. package/src/memory/claude-mem-migration.ts +1 -1
  39. package/src/memory/decision-cross-link.ts +276 -0
  40. package/src/memory/decisions.ts +7 -0
  41. package/src/memory/edge-types.ts +31 -0
  42. package/src/memory/index.ts +2 -0
  43. package/src/sessions/briefing.ts +1 -1
  44. package/src/skills/dispatch.ts +1 -1
  45. package/src/skills/injection/subagent.ts +1 -1
  46. package/src/skills/orchestrator/spawn.ts +1 -1
  47. package/src/store/brain-schema.ts +54 -0
  48. package/src/store/brain-sqlite.ts +17 -0
  49. package/src/store/json.ts +2 -2
  50. package/src/system/archive-analytics.ts +1 -1
  51. package/src/tasks/task-ops.ts +2 -2
  52. package/src/validation/verification.ts +2 -6
package/dist/index.js CHANGED
@@ -9046,12 +9046,13 @@ __export(brain_schema_exports, {
9046
9046
  brainPageEdges: () => brainPageEdges,
9047
9047
  brainPageNodes: () => brainPageNodes,
9048
9048
  brainPatterns: () => brainPatterns,
9049
+ brainPlasticityEvents: () => brainPlasticityEvents,
9049
9050
  brainRetrievalLog: () => brainRetrievalLog,
9050
9051
  brainSchemaMeta: () => brainSchemaMeta,
9051
9052
  brainStickyNotes: () => brainStickyNotes
9052
9053
  });
9053
9054
  import { sql as sql2 } from "drizzle-orm";
9054
- var BRAIN_MEMORY_TIERS, BRAIN_COGNITIVE_TYPES, BRAIN_SOURCE_CONFIDENCE, BRAIN_DECISION_TYPES, BRAIN_CONFIDENCE_LEVELS, BRAIN_OUTCOME_TYPES, BRAIN_PATTERN_TYPES, BRAIN_IMPACT_LEVELS, BRAIN_LINK_TYPES, BRAIN_OBSERVATION_TYPES2, BRAIN_OBSERVATION_SOURCE_TYPES, BRAIN_MEMORY_TYPES, BRAIN_STICKY_STATUSES, BRAIN_STICKY_COLORS, BRAIN_STICKY_PRIORITIES, brainDecisions, brainPatterns, brainLearnings, brainObservations, brainStickyNotes, brainMemoryLinks, brainSchemaMeta, BRAIN_NODE_TYPES, BRAIN_EDGE_TYPES, brainPageNodes, brainPageEdges, brainRetrievalLog;
9055
+ var BRAIN_MEMORY_TIERS, BRAIN_COGNITIVE_TYPES, BRAIN_SOURCE_CONFIDENCE, BRAIN_DECISION_TYPES, BRAIN_CONFIDENCE_LEVELS, BRAIN_OUTCOME_TYPES, BRAIN_PATTERN_TYPES, BRAIN_IMPACT_LEVELS, BRAIN_LINK_TYPES, BRAIN_OBSERVATION_TYPES2, BRAIN_OBSERVATION_SOURCE_TYPES, BRAIN_MEMORY_TYPES, BRAIN_STICKY_STATUSES, BRAIN_STICKY_COLORS, BRAIN_STICKY_PRIORITIES, brainDecisions, brainPatterns, brainLearnings, brainObservations, brainStickyNotes, brainMemoryLinks, brainSchemaMeta, BRAIN_NODE_TYPES, BRAIN_EDGE_TYPES, brainPageNodes, brainPageEdges, brainRetrievalLog, brainPlasticityEvents;
9055
9056
  var init_brain_schema = __esm({
9056
9057
  "packages/core/src/store/brain-schema.ts"() {
9057
9058
  "use strict";
@@ -9480,8 +9481,11 @@ var init_brain_schema = __esm({
9480
9481
  // Graph bridging (memory ↔ code)
9481
9482
  "references",
9482
9483
  // observation → references → symbol
9483
- "modified_by"
9484
+ "modified_by",
9484
9485
  // file → modified_by → session
9486
+ // Plasticity (Hebbian + STDP co-retrieval)
9487
+ "co_retrieved"
9488
+ // A → co_retrieved → B (Hebbian: frequently retrieved together)
9485
9489
  ];
9486
9490
  brainPageNodes = sqliteTable(
9487
9491
  "brain_page_nodes",
@@ -9571,11 +9575,45 @@ var init_brain_schema = __esm({
9571
9575
  source: text("source").notNull(),
9572
9576
  /** Estimated tokens consumed by this retrieval. */
9573
9577
  tokensUsed: integer("tokens_used"),
9578
+ /** Session ID (soft FK to tasks.db sessions). Enables grouping retrievals by session for STDP analysis. */
9579
+ sessionId: text("session_id"),
9574
9580
  createdAt: text("created_at").notNull().default(sql2`(datetime('now'))`)
9575
9581
  },
9576
9582
  (table) => [
9577
9583
  index("idx_retrieval_log_created").on(table.createdAt),
9578
- index("idx_retrieval_log_source").on(table.source)
9584
+ index("idx_retrieval_log_source").on(table.source),
9585
+ index("idx_retrieval_log_session").on(table.sessionId)
9586
+ ]
9587
+ );
9588
+ brainPlasticityEvents = sqliteTable(
9589
+ "brain_plasticity_events",
9590
+ {
9591
+ id: integer("id").primaryKey({ autoIncrement: true }),
9592
+ /** from_id of the affected brain_page_edges row. */
9593
+ sourceNode: text("source_node").notNull(),
9594
+ /** to_id of the affected brain_page_edges row. */
9595
+ targetNode: text("target_node").notNull(),
9596
+ /**
9597
+ * Signed weight delta applied to the edge.
9598
+ * Positive = potentiation (LTP), negative = depression (LTD).
9599
+ */
9600
+ deltaW: real("delta_w").notNull(),
9601
+ /**
9602
+ * STDP event kind: `ltp` (Long-Term Potentiation) or `ltd` (Long-Term
9603
+ * Depression).
9604
+ */
9605
+ kind: text("kind", { enum: ["ltp", "ltd"] }).notNull(),
9606
+ /** ISO 8601 timestamp when this event was applied. */
9607
+ timestamp: text("timestamp").notNull().default(sql2`(datetime('now'))`),
9608
+ /** Session ID that triggered the STDP pass, if available. */
9609
+ sessionId: text("session_id")
9610
+ },
9611
+ (table) => [
9612
+ index("idx_plasticity_source").on(table.sourceNode),
9613
+ index("idx_plasticity_target").on(table.targetNode),
9614
+ index("idx_plasticity_timestamp").on(table.timestamp),
9615
+ index("idx_plasticity_session").on(table.sessionId),
9616
+ index("idx_plasticity_kind").on(table.kind)
9579
9617
  ]
9580
9618
  );
9581
9619
  }
@@ -14347,7 +14385,7 @@ function clearEmbeddingProvider() {
14347
14385
  currentProvider = null;
14348
14386
  }
14349
14387
  async function embedText(text3) {
14350
- if (!currentProvider || !currentProvider.isAvailable()) return null;
14388
+ if (!currentProvider?.isAvailable()) return null;
14351
14389
  return currentProvider.embed(text3);
14352
14390
  }
14353
14391
  function isEmbeddingAvailable() {
@@ -14444,6 +14482,14 @@ function runBrainMigrations(nativeDb, db) {
14444
14482
  );
14445
14483
  }
14446
14484
  ensureColumns(nativeDb, "brain_observations", [{ name: "agent", ddl: "text" }], "brain");
14485
+ if (tableExists(nativeDb, "brain_page_edges")) {
14486
+ nativeDb.prepare(
14487
+ `UPDATE brain_page_edges
14488
+ SET edge_type = 'co_retrieved'
14489
+ WHERE edge_type = 'relates_to'
14490
+ AND provenance LIKE 'consolidation:%'`
14491
+ ).run();
14492
+ }
14447
14493
  }
14448
14494
  function loadBrainVecExtension(nativeDb) {
14449
14495
  try {
@@ -19321,7 +19367,7 @@ function parseIdPrefix(id) {
19321
19367
  return null;
19322
19368
  }
19323
19369
  async function searchSimilar(query, projectRoot, limit) {
19324
- if (!query || !query.trim()) return [];
19370
+ if (!query?.trim()) return [];
19325
19371
  if (!isEmbeddingAvailable()) return [];
19326
19372
  const maxResults = limit ?? 10;
19327
19373
  const queryVector = await embedText(query);
@@ -20956,6 +21002,160 @@ var init_anthropic_key_resolver = __esm({
20956
21002
  }
20957
21003
  });
20958
21004
 
21005
+ // packages/core/src/memory/decision-cross-link.ts
21006
+ function extractReferencedSymbols(text3) {
21007
+ const seen = /* @__PURE__ */ new Set();
21008
+ const refs = [];
21009
+ for (const match of text3.matchAll(FILE_PATH_RE)) {
21010
+ const raw = match[1];
21011
+ if (!raw) continue;
21012
+ const nodeId = `file:${raw}`;
21013
+ if (seen.has(nodeId)) continue;
21014
+ seen.add(nodeId);
21015
+ refs.push({ raw, nodeId, nodeType: "file", label: raw });
21016
+ }
21017
+ for (const match of text3.matchAll(SYMBOL_RE)) {
21018
+ const raw = match[0];
21019
+ if (!raw || raw.length < 4) continue;
21020
+ if (SYMBOL_STOP_WORDS.has(raw.toLowerCase())) continue;
21021
+ const nodeId = `symbol:${raw}`;
21022
+ if (seen.has(nodeId)) continue;
21023
+ seen.add(nodeId);
21024
+ refs.push({ raw, nodeId, nodeType: "symbol", label: raw });
21025
+ }
21026
+ return refs;
21027
+ }
21028
+ async function linkDecisionToTargets(projectRoot, decisionId, refs) {
21029
+ const fromId = `decision:${decisionId}`;
21030
+ const writes = refs.map(async (ref) => {
21031
+ await upsertGraphNode(
21032
+ projectRoot,
21033
+ ref.nodeId,
21034
+ ref.nodeType,
21035
+ ref.label,
21036
+ 0.5,
21037
+ // placeholder quality until nexus indexes it
21038
+ ref.raw
21039
+ );
21040
+ await addGraphEdge(
21041
+ projectRoot,
21042
+ fromId,
21043
+ ref.nodeId,
21044
+ "applies_to",
21045
+ 1,
21046
+ "auto:decision-cross-link"
21047
+ );
21048
+ });
21049
+ await Promise.allSettled(writes);
21050
+ }
21051
+ async function autoCrossLinkDecision(projectRoot, decisionId, decisionText, rationale) {
21052
+ try {
21053
+ const combined = `${decisionText} ${rationale}`;
21054
+ const refs = extractReferencedSymbols(combined);
21055
+ if (refs.length === 0) return;
21056
+ await linkDecisionToTargets(projectRoot, decisionId, refs);
21057
+ } catch {
21058
+ }
21059
+ }
21060
+ var FILE_PATH_RE, SYMBOL_RE, SYMBOL_STOP_WORDS;
21061
+ var init_decision_cross_link = __esm({
21062
+ "packages/core/src/memory/decision-cross-link.ts"() {
21063
+ "use strict";
21064
+ init_graph_auto_populate();
21065
+ FILE_PATH_RE = /(?:^|[\s`"'([\]{,])((\/[\w.\-/]+|[\w.-]+(?:\/[\w.-]+)+)\.(ts|tsx|js|jsx|rs|json))(?=$|[\s`"')[\]{,])/gm;
21066
+ SYMBOL_RE = /(?<![`"'/\w.])(?:[A-Z][a-zA-Z0-9]{2,}|[a-z][a-zA-Z0-9]*(?:[A-Z][a-zA-Z0-9]*)+|[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){2,})(?![`"'/\w])/g;
21067
+ SYMBOL_STOP_WORDS = /* @__PURE__ */ new Set([
21068
+ "this",
21069
+ "that",
21070
+ "with",
21071
+ "from",
21072
+ "into",
21073
+ "when",
21074
+ "then",
21075
+ "also",
21076
+ "both",
21077
+ "each",
21078
+ "such",
21079
+ "over",
21080
+ "after",
21081
+ "before",
21082
+ "always",
21083
+ "never",
21084
+ "should",
21085
+ "must",
21086
+ "will",
21087
+ "would",
21088
+ "could",
21089
+ "have",
21090
+ "been",
21091
+ "there",
21092
+ "their",
21093
+ "they",
21094
+ "them",
21095
+ "these",
21096
+ "those",
21097
+ "some",
21098
+ "only",
21099
+ "just",
21100
+ "more",
21101
+ "most",
21102
+ "many",
21103
+ "much",
21104
+ "well",
21105
+ "very",
21106
+ "here",
21107
+ "where",
21108
+ "which",
21109
+ "what",
21110
+ "why",
21111
+ "how",
21112
+ "the",
21113
+ "and",
21114
+ "but",
21115
+ "for",
21116
+ "not",
21117
+ "are",
21118
+ "was",
21119
+ "were",
21120
+ "has",
21121
+ "had",
21122
+ "its",
21123
+ "the",
21124
+ "data",
21125
+ "true",
21126
+ "false",
21127
+ "null",
21128
+ "none",
21129
+ "type",
21130
+ "test",
21131
+ "spec",
21132
+ "todo",
21133
+ "fixme",
21134
+ "note",
21135
+ "example",
21136
+ "index",
21137
+ "config",
21138
+ "error",
21139
+ "value",
21140
+ "input",
21141
+ "output",
21142
+ "result",
21143
+ "return",
21144
+ "default",
21145
+ "source",
21146
+ "target",
21147
+ "import",
21148
+ "export",
21149
+ "class",
21150
+ "interface",
21151
+ "function",
21152
+ "const",
21153
+ "async",
21154
+ "await"
21155
+ ]);
21156
+ }
21157
+ });
21158
+
20959
21159
  // packages/core/src/memory/decisions.ts
20960
21160
  var decisions_exports = {};
20961
21161
  __export(decisions_exports, {
@@ -21094,6 +21294,8 @@ async function storeDecision(projectRoot, params) {
21094
21294
  "auto:store-decision"
21095
21295
  );
21096
21296
  }
21297
+ autoCrossLinkDecision(projectRoot, saved.id, saved.decision, saved.rationale).catch(() => {
21298
+ });
21097
21299
  } catch {
21098
21300
  }
21099
21301
  detectSupersession(projectRoot, {
@@ -21162,6 +21364,7 @@ var init_decisions2 = __esm({
21162
21364
  init_brain_accessor();
21163
21365
  init_cross_db_cleanup();
21164
21366
  init_sqlite2();
21367
+ init_decision_cross_link();
21165
21368
  init_graph_auto_populate();
21166
21369
  init_quality_scoring();
21167
21370
  init_temporal_supersession();
@@ -42232,6 +42435,30 @@ var init_auto_extract = __esm({
42232
42435
  }
42233
42436
  });
42234
42437
 
42438
+ // packages/core/src/memory/edge-types.ts
42439
+ var EDGE_TYPES;
42440
+ var init_edge_types = __esm({
42441
+ "packages/core/src/memory/edge-types.ts"() {
42442
+ "use strict";
42443
+ EDGE_TYPES = {
42444
+ // Plasticity (Hebbian / STDP co-retrieval)
42445
+ CO_RETRIEVED: "co_retrieved",
42446
+ // Temporal supersession
42447
+ SUPERSEDES: "supersedes",
42448
+ // Task / decision / pattern → target context
42449
+ APPLIES_TO: "applies_to",
42450
+ // Provenance
42451
+ DERIVED_FROM: "derived_from",
42452
+ // Observation → symbol/file impact
42453
+ AFFECTS: "affects",
42454
+ // Observation → symbol name mention
42455
+ MENTIONS: "mentions",
42456
+ // Observation → symbol/file structural link
42457
+ DOCUMENTS: "documents"
42458
+ };
42459
+ }
42460
+ });
42461
+
42235
42462
  // packages/core/src/memory/brain-consolidator.ts
42236
42463
  var brain_consolidator_exports = {};
42237
42464
  __export(brain_consolidator_exports, {
@@ -42465,7 +42692,7 @@ function extractSymbolCandidates(text3) {
42465
42692
  const syms = /* @__PURE__ */ new Set();
42466
42693
  for (const m of text3.matchAll(SYMBOL_PATTERN)) {
42467
42694
  const s = m[1];
42468
- if (s && s.length >= 4 && !SYMBOL_STOP_WORDS.has(s.toLowerCase())) {
42695
+ if (s && s.length >= 4 && !SYMBOL_STOP_WORDS2.has(s.toLowerCase())) {
42469
42696
  syms.add(s);
42470
42697
  }
42471
42698
  }
@@ -42774,7 +43001,7 @@ async function listCodeLinks(projectRoot, limit = 100) {
42774
43001
  }
42775
43002
  return entries;
42776
43003
  }
42777
- var FILE_PATH_PATTERN, SYMBOL_PATTERN, SYMBOL_STOP_WORDS;
43004
+ var FILE_PATH_PATTERN, SYMBOL_PATTERN, SYMBOL_STOP_WORDS2;
42778
43005
  var init_graph_memory_bridge = __esm({
42779
43006
  "packages/core/src/memory/graph-memory-bridge.ts"() {
42780
43007
  "use strict";
@@ -42784,7 +43011,7 @@ var init_graph_memory_bridge = __esm({
42784
43011
  init_typed_query();
42785
43012
  FILE_PATH_PATTERN = /(?:^|\s|['"`(])([a-zA-Z0-9_\-./]+\.(?:ts|tsx|js|jsx|rs|go|py|mjs|cjs))(?:$|\s|['"`)])/g;
42786
43013
  SYMBOL_PATTERN = /\b([a-zA-Z_][a-zA-Z0-9_]*(?:[A-Z][a-zA-Z0-9_]*)+|[a-zA-Z_]{4,}[a-zA-Z0-9_]*)\b/g;
42787
- SYMBOL_STOP_WORDS = /* @__PURE__ */ new Set([
43014
+ SYMBOL_STOP_WORDS2 = /* @__PURE__ */ new Set([
42788
43015
  "true",
42789
43016
  "false",
42790
43017
  "null",
@@ -42828,6 +43055,207 @@ var init_graph_memory_bridge = __esm({
42828
43055
  }
42829
43056
  });
42830
43057
 
43058
+ // packages/core/src/memory/brain-stdp.ts
43059
+ var brain_stdp_exports = {};
43060
+ __export(brain_stdp_exports, {
43061
+ applyStdpPlasticity: () => applyStdpPlasticity,
43062
+ getPlasticityStats: () => getPlasticityStats
43063
+ });
43064
+ async function applyStdpPlasticity(projectRoot, sessionWindowMs = 5 * 60 * 1e3) {
43065
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43066
+ await getBrainDb2(projectRoot);
43067
+ const nativeDb = getBrainNativeDb2();
43068
+ const result = {
43069
+ ltpEvents: 0,
43070
+ ltdEvents: 0,
43071
+ edgesCreated: 0,
43072
+ pairsExamined: 0
43073
+ };
43074
+ if (!nativeDb) return result;
43075
+ try {
43076
+ nativeDb.prepare("SELECT 1 FROM brain_retrieval_log LIMIT 1").get();
43077
+ } catch {
43078
+ return result;
43079
+ }
43080
+ try {
43081
+ nativeDb.prepare("SELECT 1 FROM brain_plasticity_events LIMIT 1").get();
43082
+ } catch {
43083
+ return result;
43084
+ }
43085
+ const now = Date.now();
43086
+ const cutoffMs = now - sessionWindowMs;
43087
+ const cutoffIso = new Date(cutoffMs).toISOString().replace("T", " ").slice(0, 19);
43088
+ const nowIso = new Date(now).toISOString().replace("T", " ").slice(0, 19);
43089
+ let logRows = [];
43090
+ try {
43091
+ logRows = typedAll(
43092
+ nativeDb.prepare(
43093
+ `SELECT id, entry_ids, created_at, retrieval_order, delta_ms
43094
+ FROM brain_retrieval_log
43095
+ WHERE created_at >= ?
43096
+ ORDER BY created_at ASC, id ASC
43097
+ LIMIT 2000`
43098
+ ),
43099
+ cutoffIso
43100
+ );
43101
+ } catch {
43102
+ return result;
43103
+ }
43104
+ if (logRows.length === 0) return result;
43105
+ const spikes = [];
43106
+ let globalOrder = 0;
43107
+ for (const row of logRows) {
43108
+ let ids;
43109
+ try {
43110
+ ids = JSON.parse(row.entry_ids);
43111
+ } catch {
43112
+ continue;
43113
+ }
43114
+ const rowTime = (/* @__PURE__ */ new Date(row.created_at.replace(" ", "T") + "Z")).getTime();
43115
+ for (const rawId of ids) {
43116
+ const entryId = rawId.includes(":") ? rawId : `observation:${rawId}`;
43117
+ spikes.push({
43118
+ entryId,
43119
+ rowId: row.id,
43120
+ retrievedAt: rowTime,
43121
+ order: row.retrieval_order ?? globalOrder
43122
+ });
43123
+ globalOrder++;
43124
+ }
43125
+ }
43126
+ spikes.sort((a, b) => a.retrievedAt - b.retrievedAt || a.order - b.order);
43127
+ const prepareGetEdge = nativeDb.prepare(
43128
+ `SELECT weight FROM brain_page_edges
43129
+ WHERE from_id = ? AND to_id = ? AND edge_type = 'co_retrieved'`
43130
+ );
43131
+ const prepareUpdateEdge = nativeDb.prepare(
43132
+ `UPDATE brain_page_edges
43133
+ SET weight = MAX(?, MIN(?, weight + ?))
43134
+ WHERE from_id = ? AND to_id = ? AND edge_type = 'co_retrieved'`
43135
+ );
43136
+ const prepareInsertEdge = nativeDb.prepare(
43137
+ `INSERT OR IGNORE INTO brain_page_edges
43138
+ (from_id, to_id, edge_type, weight, provenance, created_at)
43139
+ VALUES (?, ?, 'co_retrieved', ?, 'plasticity:stdp-ltp', ?)`
43140
+ );
43141
+ const prepareLogEvent = nativeDb.prepare(
43142
+ `INSERT INTO brain_plasticity_events
43143
+ (source_node, target_node, delta_w, kind, timestamp)
43144
+ VALUES (?, ?, ?, ?, ?)`
43145
+ );
43146
+ for (let i = 0; i < spikes.length; i++) {
43147
+ const spikeA = spikes[i];
43148
+ for (let j = i + 1; j < spikes.length; j++) {
43149
+ const spikeB = spikes[j];
43150
+ const deltaT = spikeB.retrievedAt - spikeA.retrievedAt;
43151
+ if (deltaT > sessionWindowMs) break;
43152
+ if (spikeA.entryId === spikeB.entryId) continue;
43153
+ result.pairsExamined++;
43154
+ const deltaW = A_PRE * Math.exp(-deltaT / TAU_PRE_MS);
43155
+ if (deltaW < 1e-6) continue;
43156
+ const existingEdge = prepareGetEdge.get(spikeA.entryId, spikeB.entryId);
43157
+ try {
43158
+ if (existingEdge !== void 0) {
43159
+ prepareUpdateEdge.run(WEIGHT_MIN, WEIGHT_MAX, deltaW, spikeA.entryId, spikeB.entryId);
43160
+ } else {
43161
+ const initialWeight = Math.min(WEIGHT_MAX, deltaW);
43162
+ prepareInsertEdge.run(spikeA.entryId, spikeB.entryId, initialWeight, nowIso);
43163
+ result.edgesCreated++;
43164
+ }
43165
+ prepareLogEvent.run(spikeA.entryId, spikeB.entryId, deltaW, "ltp", nowIso);
43166
+ result.ltpEvents++;
43167
+ } catch {
43168
+ }
43169
+ const deltaWNeg = -(A_POST * Math.exp(-deltaT / TAU_POST_MS));
43170
+ const existingReverseEdge = prepareGetEdge.get(spikeB.entryId, spikeA.entryId);
43171
+ if (existingReverseEdge !== void 0 && Math.abs(deltaWNeg) >= 1e-6) {
43172
+ try {
43173
+ prepareUpdateEdge.run(WEIGHT_MIN, WEIGHT_MAX, deltaWNeg, spikeB.entryId, spikeA.entryId);
43174
+ prepareLogEvent.run(spikeB.entryId, spikeA.entryId, deltaWNeg, "ltd", nowIso);
43175
+ result.ltdEvents++;
43176
+ } catch {
43177
+ }
43178
+ }
43179
+ }
43180
+ }
43181
+ return result;
43182
+ }
43183
+ async function getPlasticityStats(projectRoot, limit = 20) {
43184
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43185
+ await getBrainDb2(projectRoot);
43186
+ const nativeDb = getBrainNativeDb2();
43187
+ const empty = {
43188
+ totalEvents: 0,
43189
+ ltpCount: 0,
43190
+ ltdCount: 0,
43191
+ netDeltaW: 0,
43192
+ lastEventAt: null,
43193
+ recentEvents: []
43194
+ };
43195
+ if (!nativeDb) return empty;
43196
+ try {
43197
+ nativeDb.prepare("SELECT 1 FROM brain_plasticity_events LIMIT 1").get();
43198
+ } catch {
43199
+ return empty;
43200
+ }
43201
+ let agg;
43202
+ try {
43203
+ agg = nativeDb.prepare(
43204
+ `SELECT
43205
+ COUNT(*) AS total,
43206
+ SUM(CASE WHEN kind = 'ltp' THEN 1 ELSE 0 END) AS ltp_count,
43207
+ SUM(CASE WHEN kind = 'ltd' THEN 1 ELSE 0 END) AS ltd_count,
43208
+ SUM(delta_w) AS net_delta_w,
43209
+ MAX(timestamp) AS last_event_at
43210
+ FROM brain_plasticity_events`
43211
+ ).get();
43212
+ } catch {
43213
+ return empty;
43214
+ }
43215
+ let recentRows = [];
43216
+ try {
43217
+ recentRows = typedAll(
43218
+ nativeDb.prepare(
43219
+ `SELECT id, source_node, target_node, delta_w, kind, timestamp, session_id
43220
+ FROM brain_plasticity_events
43221
+ ORDER BY timestamp DESC, id DESC
43222
+ LIMIT ?`
43223
+ ),
43224
+ limit
43225
+ );
43226
+ } catch {
43227
+ }
43228
+ return {
43229
+ totalEvents: agg?.total ?? 0,
43230
+ ltpCount: agg?.ltp_count ?? 0,
43231
+ ltdCount: agg?.ltd_count ?? 0,
43232
+ netDeltaW: agg?.net_delta_w ?? 0,
43233
+ lastEventAt: agg?.last_event_at ?? null,
43234
+ recentEvents: recentRows.map((r) => ({
43235
+ id: r.id,
43236
+ sourceNode: r.source_node,
43237
+ targetNode: r.target_node,
43238
+ deltaW: r.delta_w,
43239
+ kind: r.kind,
43240
+ timestamp: r.timestamp,
43241
+ sessionId: r.session_id
43242
+ }))
43243
+ };
43244
+ }
43245
+ var TAU_PRE_MS, TAU_POST_MS, A_PRE, A_POST, WEIGHT_MIN, WEIGHT_MAX;
43246
+ var init_brain_stdp = __esm({
43247
+ "packages/core/src/memory/brain-stdp.ts"() {
43248
+ "use strict";
43249
+ init_typed_query();
43250
+ TAU_PRE_MS = 2e4;
43251
+ TAU_POST_MS = 2e4;
43252
+ A_PRE = 0.05;
43253
+ A_POST = 0.06;
43254
+ WEIGHT_MIN = 0;
43255
+ WEIGHT_MAX = 1;
43256
+ }
43257
+ });
43258
+
42831
43259
  // packages/core/src/memory/brain-lifecycle.ts
42832
43260
  var brain_lifecycle_exports = {};
42833
43261
  __export(brain_lifecycle_exports, {
@@ -43133,6 +43561,13 @@ async function runConsolidation(projectRoot) {
43133
43561
  } catch (err) {
43134
43562
  console.warn("[consolidation] Step 8 graph memory bridge failed:", err);
43135
43563
  }
43564
+ try {
43565
+ const { applyStdpPlasticity: applyStdpPlasticity2 } = await Promise.resolve().then(() => (init_brain_stdp(), brain_stdp_exports));
43566
+ const stdpResult = await applyStdpPlasticity2(projectRoot);
43567
+ result.stdpPlasticity = stdpResult;
43568
+ } catch (err) {
43569
+ console.warn("[consolidation] Step 9 STDP plasticity failed:", err);
43570
+ }
43136
43571
  return result;
43137
43572
  }
43138
43573
  async function deduplicateByEmbedding(projectRoot) {
@@ -43294,16 +43729,16 @@ async function strengthenCoRetrievedEdges(projectRoot) {
43294
43729
  const updateStmt = nativeDb.prepare(`
43295
43730
  UPDATE brain_page_edges
43296
43731
  SET weight = MIN(1.0, weight + 0.1)
43297
- WHERE from_id = ? AND to_id = ? AND edge_type = 'relates_to'
43732
+ WHERE from_id = ? AND to_id = ? AND edge_type = ?
43298
43733
  `);
43299
- const updateResult = updateStmt.run(nodeFrom, nodeTo);
43734
+ const updateResult = updateStmt.run(nodeFrom, nodeTo, EDGE_TYPES.CO_RETRIEVED);
43300
43735
  const changes = typeof updateResult.changes === "number" ? updateResult.changes : 0;
43301
43736
  if (changes === 0) {
43302
43737
  nativeDb.prepare(`
43303
43738
  INSERT OR IGNORE INTO brain_page_edges
43304
43739
  (from_id, to_id, edge_type, weight, provenance, created_at)
43305
- VALUES (?, ?, 'relates_to', 0.3, 'consolidation:co-retrieval', ?)
43306
- `).run(nodeFrom, nodeTo, now);
43740
+ VALUES (?, ?, ?, 0.3, 'consolidation:co-retrieval', ?)
43741
+ `).run(nodeFrom, nodeTo, EDGE_TYPES.CO_RETRIEVED, now);
43307
43742
  }
43308
43743
  strengthened++;
43309
43744
  } catch {
@@ -43317,6 +43752,7 @@ var init_brain_lifecycle = __esm({
43317
43752
  "use strict";
43318
43753
  init_brain_accessor();
43319
43754
  init_typed_query();
43755
+ init_edge_types();
43320
43756
  STOP_WORDS3 = /* @__PURE__ */ new Set([
43321
43757
  "the",
43322
43758
  "a",
@@ -46478,7 +46914,7 @@ async function computeLastSession(projectRoot, scopeFilter) {
46478
46914
  const accessor = await getAccessor(projectRoot);
46479
46915
  const allSessions = await accessor.loadSessions();
46480
46916
  const session = allSessions.find((s) => s.id === sessionId);
46481
- if (!session || !session.endedAt) return null;
46917
+ if (!session?.endedAt) return null;
46482
46918
  let duration3 = 0;
46483
46919
  if (session.startedAt) {
46484
46920
  duration3 = Math.round(
@@ -47665,10 +48101,17 @@ async function searchBrainCompact(projectRoot, params) {
47665
48101
  setImmediate(() => {
47666
48102
  incrementCitationCounts(projectRoot, returnedIds).catch(() => {
47667
48103
  });
47668
- logRetrieval(projectRoot, query, returnedIds, "find-rrf", results2.length * 50).catch(
47669
- () => {
47670
- }
47671
- );
48104
+ getCurrentSessionId(projectRoot).then((sessionId) => {
48105
+ return logRetrieval(
48106
+ projectRoot,
48107
+ query,
48108
+ returnedIds,
48109
+ "find-rrf",
48110
+ results2.length * 50,
48111
+ sessionId
48112
+ );
48113
+ }).catch(() => {
48114
+ });
47672
48115
  });
47673
48116
  }
47674
48117
  return { results: results2, total: results2.length, tokensEstimated: results2.length * 50 };
@@ -47731,7 +48174,16 @@ async function searchBrainCompact(projectRoot, params) {
47731
48174
  setImmediate(() => {
47732
48175
  incrementCitationCounts(projectRoot, returnedIds).catch(() => {
47733
48176
  });
47734
- logRetrieval(projectRoot, query, returnedIds, "find", results.length * 50).catch(() => {
48177
+ getCurrentSessionId(projectRoot).then((sessionId) => {
48178
+ return logRetrieval(
48179
+ projectRoot,
48180
+ query,
48181
+ returnedIds,
48182
+ "find",
48183
+ results.length * 50,
48184
+ sessionId
48185
+ );
48186
+ }).catch(() => {
47735
48187
  });
47736
48188
  });
47737
48189
  }
@@ -47919,13 +48371,16 @@ async function fetchBrainEntries(projectRoot, params) {
47919
48371
  setImmediate(() => {
47920
48372
  incrementCitationCounts(projectRoot, fetchedIds).catch(() => {
47921
48373
  });
47922
- logRetrieval(
47923
- projectRoot,
47924
- fetchedIds.join(","),
47925
- fetchedIds,
47926
- "fetch",
47927
- results.length * 500
47928
- ).catch(() => {
48374
+ getCurrentSessionId(projectRoot).then((sessionId) => {
48375
+ return logRetrieval(
48376
+ projectRoot,
48377
+ fetchedIds.join(","),
48378
+ fetchedIds,
48379
+ "fetch",
48380
+ results.length * 500,
48381
+ sessionId
48382
+ );
48383
+ }).catch(() => {
47929
48384
  });
47930
48385
  });
47931
48386
  }
@@ -48343,6 +48798,15 @@ async function retrieveWithBudget(projectRoot, query, tokenBudget = 500, options
48343
48798
  excluded
48344
48799
  };
48345
48800
  }
48801
+ async function getCurrentSessionId(projectRoot) {
48802
+ try {
48803
+ const { sessionStatus: sessionStatus2 } = await Promise.resolve().then(() => (init_sessions2(), sessions_exports2));
48804
+ const session = await sessionStatus2(projectRoot);
48805
+ return session?.id;
48806
+ } catch {
48807
+ return void 0;
48808
+ }
48809
+ }
48346
48810
  async function incrementCitationCounts(projectRoot, ids) {
48347
48811
  if (ids.length === 0) return;
48348
48812
  const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
@@ -48369,13 +48833,13 @@ async function incrementCitationCounts(projectRoot, ids) {
48369
48833
  }
48370
48834
  }
48371
48835
  }
48372
- async function logRetrieval(projectRoot, query, entryIds, source, tokensUsed) {
48836
+ async function logRetrieval(projectRoot, query, entryIds, source, tokensUsed, sessionId) {
48373
48837
  if (entryIds.length === 0) return;
48374
48838
  const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
48375
48839
  await getBrainDb2(projectRoot);
48376
48840
  const nativeDb = getBrainNativeDb2();
48377
48841
  if (!nativeDb) return;
48378
- const createSql = "CREATE TABLE IF NOT EXISTS brain_retrieval_log (id INTEGER PRIMARY KEY AUTOINCREMENT,query TEXT NOT NULL,entry_ids TEXT NOT NULL,entry_count INTEGER NOT NULL,source TEXT NOT NULL,tokens_used INTEGER,created_at TEXT NOT NULL DEFAULT (datetime('now')))";
48842
+ const createSql = "CREATE TABLE IF NOT EXISTS brain_retrieval_log (id INTEGER PRIMARY KEY AUTOINCREMENT,query TEXT NOT NULL,entry_ids TEXT NOT NULL,entry_count INTEGER NOT NULL,source TEXT NOT NULL,tokens_used INTEGER,session_id TEXT,created_at TEXT NOT NULL DEFAULT (datetime('now')))";
48379
48843
  try {
48380
48844
  nativeDb.prepare(createSql).run();
48381
48845
  } catch {
@@ -48383,8 +48847,15 @@ async function logRetrieval(projectRoot, query, entryIds, source, tokensUsed) {
48383
48847
  }
48384
48848
  try {
48385
48849
  nativeDb.prepare(
48386
- "INSERT INTO brain_retrieval_log (query, entry_ids, entry_count, source, tokens_used) VALUES (?, ?, ?, ?, ?)"
48387
- ).run(query, entryIds.join(","), entryIds.length, source, tokensUsed ?? null);
48850
+ "INSERT INTO brain_retrieval_log (query, entry_ids, entry_count, source, tokens_used, session_id) VALUES (?, ?, ?, ?, ?, ?)"
48851
+ ).run(
48852
+ query,
48853
+ entryIds.join(","),
48854
+ entryIds.length,
48855
+ source,
48856
+ tokensUsed ?? null,
48857
+ sessionId ?? null
48858
+ );
48388
48859
  } catch {
48389
48860
  }
48390
48861
  }
@@ -60958,7 +61429,7 @@ function prepareSpawnMulti(skillNames, tokenValues, cwd) {
60958
61429
  const skillName = skillNames[i];
60959
61430
  const isPrimary = i === 0;
60960
61431
  const skill = findSkill(skillName, cwd);
60961
- if (!skill || !skill.content) {
61432
+ if (!skill?.content) {
60962
61433
  continue;
60963
61434
  }
60964
61435
  let content = isPrimary ? skill.content : loadProgressive(skill.content);
@@ -61645,6 +62116,7 @@ async function listEpicsWithLifecycle(cwd) {
61645
62116
  // packages/core/src/memory/index.ts
61646
62117
  var memory_exports = {};
61647
62118
  __export(memory_exports, {
62119
+ EDGE_TYPES: () => EDGE_TYPES,
61648
62120
  RRF_K: () => RRF_K,
61649
62121
  addResearch: () => addResearch,
61650
62122
  appendExtendedManifest: () => appendExtendedManifest,
@@ -61842,6 +62314,7 @@ function mapImpact(impact) {
61842
62314
  init_brain_retrieval();
61843
62315
  init_brain_search();
61844
62316
  init_decisions2();
62317
+ init_edge_types();
61845
62318
 
61846
62319
  // packages/core/src/memory/extraction-gate.ts
61847
62320
  init_brain_embedding();
@@ -70734,6 +71207,7 @@ async function getSyncStatus(remote = "origin", cwd) {
70734
71207
  // packages/core/src/research/index.ts
70735
71208
  var research_exports = {};
70736
71209
  __export(research_exports, {
71210
+ EDGE_TYPES: () => EDGE_TYPES,
70737
71211
  RRF_K: () => RRF_K,
70738
71212
  addResearch: () => addResearch,
70739
71213
  appendExtendedManifest: () => appendExtendedManifest,
@@ -73124,7 +73598,7 @@ async function injectProtocol(skillContent, taskId, tokenValues, cwd, tier) {
73124
73598
  }
73125
73599
  async function orchestratorSpawnSkill(taskId, skillName, tokenValues, cwd, tier) {
73126
73600
  const skill = findSkill(skillName, cwd);
73127
- if (!skill || !skill.content) {
73601
+ if (!skill?.content) {
73128
73602
  throw new CleoError(4 /* NOT_FOUND */, `Skill not found: ${skillName}`, {
73129
73603
  fix: `Check skills directory for ${skillName}/SKILL.md`
73130
73604
  });
@@ -73660,7 +74134,7 @@ async function buildPrompt(taskId, templateName = "TASK-EXECUTOR", cwd, tier) {
73660
74134
  throw new CleoError(4 /* NOT_FOUND */, `Task ${taskId} not found`);
73661
74135
  }
73662
74136
  const skill = findSkill(templateName, cwd);
73663
- if (!skill || !skill.content) {
74137
+ if (!skill?.content) {
73664
74138
  const { canonical } = mapSkillName(templateName);
73665
74139
  throw new CleoError(4 /* NOT_FOUND */, `Skill template ${templateName} not found`, {
73666
74140
  fix: `Expected at skills/${canonical}/SKILL.md`
@@ -76218,7 +76692,7 @@ async function analyzeArchive(opts, accessor) {
76218
76692
  const acc = accessor ?? await getAccessor(opts.cwd);
76219
76693
  const data = await acc.loadArchive();
76220
76694
  const reportType = opts.report ?? "summary";
76221
- if (!data || !data.archivedTasks?.length) {
76695
+ if (!data?.archivedTasks?.length) {
76222
76696
  return {
76223
76697
  report: reportType,
76224
76698
  filters: null,
@@ -82758,16 +83232,12 @@ function allEpicChildrenVerified(epicId, tasks2) {
82758
83232
  if (children.length === 0) return false;
82759
83233
  const incomplete = children.filter((t) => t.status !== "done");
82760
83234
  if (incomplete.length > 0) return false;
82761
- const unverified = children.filter(
82762
- (t) => t.status === "done" && (!t.verification || !t.verification.passed)
82763
- );
83235
+ const unverified = children.filter((t) => t.status === "done" && !t.verification?.passed);
82764
83236
  return unverified.length === 0;
82765
83237
  }
82766
83238
  function allSiblingsVerified(parentId, tasks2) {
82767
83239
  const siblings = tasks2.filter((t) => t.parentId === parentId);
82768
- const unverifiedDone = siblings.filter(
82769
- (t) => t.status === "done" && (!t.verification || !t.verification.passed)
82770
- );
83240
+ const unverifiedDone = siblings.filter((t) => t.status === "done" && !t.verification?.passed);
82771
83241
  const incomplete = siblings.filter(
82772
83242
  (t) => t.status === "pending" || t.status === "active" || t.status === "blocked"
82773
83243
  );
@@ -83144,7 +83614,7 @@ import { randomUUID as randomUUID8 } from "node:crypto";
83144
83614
  init_paths();
83145
83615
  import { existsSync as existsSync107, readFileSync as readFileSync77, writeFileSync as writeFileSync20 } from "node:fs";
83146
83616
  import { join as join107 } from "node:path";
83147
- function getCurrentSessionId(cwd) {
83617
+ function getCurrentSessionId2(cwd) {
83148
83618
  if (process.env.CLEO_SESSION) return process.env.CLEO_SESSION;
83149
83619
  const sessionFile = join107(getCleoDir(cwd), ".current-session");
83150
83620
  if (existsSync107(sessionFile)) {
@@ -83172,7 +83642,7 @@ function createCliMeta(operation, duration_ms = 0) {
83172
83642
  duration_ms,
83173
83643
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
83174
83644
  };
83175
- const sessionId = getCurrentSessionId();
83645
+ const sessionId = getCurrentSessionId2();
83176
83646
  if (sessionId) {
83177
83647
  meta3["sessionId"] = sessionId;
83178
83648
  }