@cleocode/cleo 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.
- package/dist/cli/index.js +1019 -45
- package/dist/cli/index.js.map +4 -4
- package/package.json +8 -8
package/dist/cli/index.js
CHANGED
|
@@ -9071,12 +9071,13 @@ __export(brain_schema_exports, {
|
|
|
9071
9071
|
brainPageEdges: () => brainPageEdges,
|
|
9072
9072
|
brainPageNodes: () => brainPageNodes,
|
|
9073
9073
|
brainPatterns: () => brainPatterns,
|
|
9074
|
+
brainPlasticityEvents: () => brainPlasticityEvents,
|
|
9074
9075
|
brainRetrievalLog: () => brainRetrievalLog,
|
|
9075
9076
|
brainSchemaMeta: () => brainSchemaMeta,
|
|
9076
9077
|
brainStickyNotes: () => brainStickyNotes
|
|
9077
9078
|
});
|
|
9078
9079
|
import { sql as sql2 } from "drizzle-orm";
|
|
9079
|
-
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;
|
|
9080
|
+
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;
|
|
9080
9081
|
var init_brain_schema = __esm({
|
|
9081
9082
|
"packages/core/src/store/brain-schema.ts"() {
|
|
9082
9083
|
"use strict";
|
|
@@ -9505,8 +9506,11 @@ var init_brain_schema = __esm({
|
|
|
9505
9506
|
// Graph bridging (memory ↔ code)
|
|
9506
9507
|
"references",
|
|
9507
9508
|
// observation → references → symbol
|
|
9508
|
-
"modified_by"
|
|
9509
|
+
"modified_by",
|
|
9509
9510
|
// file → modified_by → session
|
|
9511
|
+
// Plasticity (Hebbian + STDP co-retrieval)
|
|
9512
|
+
"co_retrieved"
|
|
9513
|
+
// A → co_retrieved → B (Hebbian: frequently retrieved together)
|
|
9510
9514
|
];
|
|
9511
9515
|
brainPageNodes = sqliteTable(
|
|
9512
9516
|
"brain_page_nodes",
|
|
@@ -9596,11 +9600,45 @@ var init_brain_schema = __esm({
|
|
|
9596
9600
|
source: text("source").notNull(),
|
|
9597
9601
|
/** Estimated tokens consumed by this retrieval. */
|
|
9598
9602
|
tokensUsed: integer("tokens_used"),
|
|
9603
|
+
/** Session ID (soft FK to tasks.db sessions). Enables grouping retrievals by session for STDP analysis. */
|
|
9604
|
+
sessionId: text("session_id"),
|
|
9599
9605
|
createdAt: text("created_at").notNull().default(sql2`(datetime('now'))`)
|
|
9600
9606
|
},
|
|
9601
9607
|
(table) => [
|
|
9602
9608
|
index("idx_retrieval_log_created").on(table.createdAt),
|
|
9603
|
-
index("idx_retrieval_log_source").on(table.source)
|
|
9609
|
+
index("idx_retrieval_log_source").on(table.source),
|
|
9610
|
+
index("idx_retrieval_log_session").on(table.sessionId)
|
|
9611
|
+
]
|
|
9612
|
+
);
|
|
9613
|
+
brainPlasticityEvents = sqliteTable(
|
|
9614
|
+
"brain_plasticity_events",
|
|
9615
|
+
{
|
|
9616
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
9617
|
+
/** from_id of the affected brain_page_edges row. */
|
|
9618
|
+
sourceNode: text("source_node").notNull(),
|
|
9619
|
+
/** to_id of the affected brain_page_edges row. */
|
|
9620
|
+
targetNode: text("target_node").notNull(),
|
|
9621
|
+
/**
|
|
9622
|
+
* Signed weight delta applied to the edge.
|
|
9623
|
+
* Positive = potentiation (LTP), negative = depression (LTD).
|
|
9624
|
+
*/
|
|
9625
|
+
deltaW: real("delta_w").notNull(),
|
|
9626
|
+
/**
|
|
9627
|
+
* STDP event kind: `ltp` (Long-Term Potentiation) or `ltd` (Long-Term
|
|
9628
|
+
* Depression).
|
|
9629
|
+
*/
|
|
9630
|
+
kind: text("kind", { enum: ["ltp", "ltd"] }).notNull(),
|
|
9631
|
+
/** ISO 8601 timestamp when this event was applied. */
|
|
9632
|
+
timestamp: text("timestamp").notNull().default(sql2`(datetime('now'))`),
|
|
9633
|
+
/** Session ID that triggered the STDP pass, if available. */
|
|
9634
|
+
sessionId: text("session_id")
|
|
9635
|
+
},
|
|
9636
|
+
(table) => [
|
|
9637
|
+
index("idx_plasticity_source").on(table.sourceNode),
|
|
9638
|
+
index("idx_plasticity_target").on(table.targetNode),
|
|
9639
|
+
index("idx_plasticity_timestamp").on(table.timestamp),
|
|
9640
|
+
index("idx_plasticity_session").on(table.sessionId),
|
|
9641
|
+
index("idx_plasticity_kind").on(table.kind)
|
|
9604
9642
|
]
|
|
9605
9643
|
);
|
|
9606
9644
|
}
|
|
@@ -14917,7 +14955,7 @@ function clearEmbeddingProvider() {
|
|
|
14917
14955
|
currentProvider = null;
|
|
14918
14956
|
}
|
|
14919
14957
|
async function embedText(text3) {
|
|
14920
|
-
if (!currentProvider
|
|
14958
|
+
if (!currentProvider?.isAvailable()) return null;
|
|
14921
14959
|
return currentProvider.embed(text3);
|
|
14922
14960
|
}
|
|
14923
14961
|
function isEmbeddingAvailable() {
|
|
@@ -15014,6 +15052,14 @@ function runBrainMigrations(nativeDb, db) {
|
|
|
15014
15052
|
);
|
|
15015
15053
|
}
|
|
15016
15054
|
ensureColumns(nativeDb, "brain_observations", [{ name: "agent", ddl: "text" }], "brain");
|
|
15055
|
+
if (tableExists(nativeDb, "brain_page_edges")) {
|
|
15056
|
+
nativeDb.prepare(
|
|
15057
|
+
`UPDATE brain_page_edges
|
|
15058
|
+
SET edge_type = 'co_retrieved'
|
|
15059
|
+
WHERE edge_type = 'relates_to'
|
|
15060
|
+
AND provenance LIKE 'consolidation:%'`
|
|
15061
|
+
).run();
|
|
15062
|
+
}
|
|
15017
15063
|
}
|
|
15018
15064
|
function loadBrainVecExtension(nativeDb) {
|
|
15019
15065
|
try {
|
|
@@ -22780,7 +22826,7 @@ function parseIdPrefix(id) {
|
|
|
22780
22826
|
return null;
|
|
22781
22827
|
}
|
|
22782
22828
|
async function searchSimilar(query, projectRoot, limit) {
|
|
22783
|
-
if (!query
|
|
22829
|
+
if (!query?.trim()) return [];
|
|
22784
22830
|
if (!isEmbeddingAvailable()) return [];
|
|
22785
22831
|
const maxResults = limit ?? 10;
|
|
22786
22832
|
const queryVector = await embedText(query);
|
|
@@ -24415,6 +24461,160 @@ var init_anthropic_key_resolver = __esm({
|
|
|
24415
24461
|
}
|
|
24416
24462
|
});
|
|
24417
24463
|
|
|
24464
|
+
// packages/core/src/memory/decision-cross-link.ts
|
|
24465
|
+
function extractReferencedSymbols(text3) {
|
|
24466
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24467
|
+
const refs = [];
|
|
24468
|
+
for (const match of text3.matchAll(FILE_PATH_RE)) {
|
|
24469
|
+
const raw = match[1];
|
|
24470
|
+
if (!raw) continue;
|
|
24471
|
+
const nodeId = `file:${raw}`;
|
|
24472
|
+
if (seen.has(nodeId)) continue;
|
|
24473
|
+
seen.add(nodeId);
|
|
24474
|
+
refs.push({ raw, nodeId, nodeType: "file", label: raw });
|
|
24475
|
+
}
|
|
24476
|
+
for (const match of text3.matchAll(SYMBOL_RE)) {
|
|
24477
|
+
const raw = match[0];
|
|
24478
|
+
if (!raw || raw.length < 4) continue;
|
|
24479
|
+
if (SYMBOL_STOP_WORDS.has(raw.toLowerCase())) continue;
|
|
24480
|
+
const nodeId = `symbol:${raw}`;
|
|
24481
|
+
if (seen.has(nodeId)) continue;
|
|
24482
|
+
seen.add(nodeId);
|
|
24483
|
+
refs.push({ raw, nodeId, nodeType: "symbol", label: raw });
|
|
24484
|
+
}
|
|
24485
|
+
return refs;
|
|
24486
|
+
}
|
|
24487
|
+
async function linkDecisionToTargets(projectRoot, decisionId, refs) {
|
|
24488
|
+
const fromId = `decision:${decisionId}`;
|
|
24489
|
+
const writes = refs.map(async (ref) => {
|
|
24490
|
+
await upsertGraphNode(
|
|
24491
|
+
projectRoot,
|
|
24492
|
+
ref.nodeId,
|
|
24493
|
+
ref.nodeType,
|
|
24494
|
+
ref.label,
|
|
24495
|
+
0.5,
|
|
24496
|
+
// placeholder quality until nexus indexes it
|
|
24497
|
+
ref.raw
|
|
24498
|
+
);
|
|
24499
|
+
await addGraphEdge(
|
|
24500
|
+
projectRoot,
|
|
24501
|
+
fromId,
|
|
24502
|
+
ref.nodeId,
|
|
24503
|
+
"applies_to",
|
|
24504
|
+
1,
|
|
24505
|
+
"auto:decision-cross-link"
|
|
24506
|
+
);
|
|
24507
|
+
});
|
|
24508
|
+
await Promise.allSettled(writes);
|
|
24509
|
+
}
|
|
24510
|
+
async function autoCrossLinkDecision(projectRoot, decisionId, decisionText, rationale) {
|
|
24511
|
+
try {
|
|
24512
|
+
const combined = `${decisionText} ${rationale}`;
|
|
24513
|
+
const refs = extractReferencedSymbols(combined);
|
|
24514
|
+
if (refs.length === 0) return;
|
|
24515
|
+
await linkDecisionToTargets(projectRoot, decisionId, refs);
|
|
24516
|
+
} catch {
|
|
24517
|
+
}
|
|
24518
|
+
}
|
|
24519
|
+
var FILE_PATH_RE, SYMBOL_RE, SYMBOL_STOP_WORDS;
|
|
24520
|
+
var init_decision_cross_link = __esm({
|
|
24521
|
+
"packages/core/src/memory/decision-cross-link.ts"() {
|
|
24522
|
+
"use strict";
|
|
24523
|
+
init_graph_auto_populate();
|
|
24524
|
+
FILE_PATH_RE = /(?:^|[\s`"'([\]{,])((\/[\w.\-/]+|[\w.-]+(?:\/[\w.-]+)+)\.(ts|tsx|js|jsx|rs|json))(?=$|[\s`"')[\]{,])/gm;
|
|
24525
|
+
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;
|
|
24526
|
+
SYMBOL_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
24527
|
+
"this",
|
|
24528
|
+
"that",
|
|
24529
|
+
"with",
|
|
24530
|
+
"from",
|
|
24531
|
+
"into",
|
|
24532
|
+
"when",
|
|
24533
|
+
"then",
|
|
24534
|
+
"also",
|
|
24535
|
+
"both",
|
|
24536
|
+
"each",
|
|
24537
|
+
"such",
|
|
24538
|
+
"over",
|
|
24539
|
+
"after",
|
|
24540
|
+
"before",
|
|
24541
|
+
"always",
|
|
24542
|
+
"never",
|
|
24543
|
+
"should",
|
|
24544
|
+
"must",
|
|
24545
|
+
"will",
|
|
24546
|
+
"would",
|
|
24547
|
+
"could",
|
|
24548
|
+
"have",
|
|
24549
|
+
"been",
|
|
24550
|
+
"there",
|
|
24551
|
+
"their",
|
|
24552
|
+
"they",
|
|
24553
|
+
"them",
|
|
24554
|
+
"these",
|
|
24555
|
+
"those",
|
|
24556
|
+
"some",
|
|
24557
|
+
"only",
|
|
24558
|
+
"just",
|
|
24559
|
+
"more",
|
|
24560
|
+
"most",
|
|
24561
|
+
"many",
|
|
24562
|
+
"much",
|
|
24563
|
+
"well",
|
|
24564
|
+
"very",
|
|
24565
|
+
"here",
|
|
24566
|
+
"where",
|
|
24567
|
+
"which",
|
|
24568
|
+
"what",
|
|
24569
|
+
"why",
|
|
24570
|
+
"how",
|
|
24571
|
+
"the",
|
|
24572
|
+
"and",
|
|
24573
|
+
"but",
|
|
24574
|
+
"for",
|
|
24575
|
+
"not",
|
|
24576
|
+
"are",
|
|
24577
|
+
"was",
|
|
24578
|
+
"were",
|
|
24579
|
+
"has",
|
|
24580
|
+
"had",
|
|
24581
|
+
"its",
|
|
24582
|
+
"the",
|
|
24583
|
+
"data",
|
|
24584
|
+
"true",
|
|
24585
|
+
"false",
|
|
24586
|
+
"null",
|
|
24587
|
+
"none",
|
|
24588
|
+
"type",
|
|
24589
|
+
"test",
|
|
24590
|
+
"spec",
|
|
24591
|
+
"todo",
|
|
24592
|
+
"fixme",
|
|
24593
|
+
"note",
|
|
24594
|
+
"example",
|
|
24595
|
+
"index",
|
|
24596
|
+
"config",
|
|
24597
|
+
"error",
|
|
24598
|
+
"value",
|
|
24599
|
+
"input",
|
|
24600
|
+
"output",
|
|
24601
|
+
"result",
|
|
24602
|
+
"return",
|
|
24603
|
+
"default",
|
|
24604
|
+
"source",
|
|
24605
|
+
"target",
|
|
24606
|
+
"import",
|
|
24607
|
+
"export",
|
|
24608
|
+
"class",
|
|
24609
|
+
"interface",
|
|
24610
|
+
"function",
|
|
24611
|
+
"const",
|
|
24612
|
+
"async",
|
|
24613
|
+
"await"
|
|
24614
|
+
]);
|
|
24615
|
+
}
|
|
24616
|
+
});
|
|
24617
|
+
|
|
24418
24618
|
// packages/core/src/memory/decisions.ts
|
|
24419
24619
|
var decisions_exports = {};
|
|
24420
24620
|
__export(decisions_exports, {
|
|
@@ -24553,6 +24753,8 @@ async function storeDecision(projectRoot, params) {
|
|
|
24553
24753
|
"auto:store-decision"
|
|
24554
24754
|
);
|
|
24555
24755
|
}
|
|
24756
|
+
autoCrossLinkDecision(projectRoot, saved.id, saved.decision, saved.rationale).catch(() => {
|
|
24757
|
+
});
|
|
24556
24758
|
} catch {
|
|
24557
24759
|
}
|
|
24558
24760
|
detectSupersession(projectRoot, {
|
|
@@ -24621,6 +24823,7 @@ var init_decisions2 = __esm({
|
|
|
24621
24823
|
init_brain_accessor();
|
|
24622
24824
|
init_cross_db_cleanup();
|
|
24623
24825
|
init_sqlite2();
|
|
24826
|
+
init_decision_cross_link();
|
|
24624
24827
|
init_graph_auto_populate();
|
|
24625
24828
|
init_quality_scoring();
|
|
24626
24829
|
init_temporal_supersession();
|
|
@@ -45691,6 +45894,30 @@ var init_auto_extract = __esm({
|
|
|
45691
45894
|
}
|
|
45692
45895
|
});
|
|
45693
45896
|
|
|
45897
|
+
// packages/core/src/memory/edge-types.ts
|
|
45898
|
+
var EDGE_TYPES;
|
|
45899
|
+
var init_edge_types = __esm({
|
|
45900
|
+
"packages/core/src/memory/edge-types.ts"() {
|
|
45901
|
+
"use strict";
|
|
45902
|
+
EDGE_TYPES = {
|
|
45903
|
+
// Plasticity (Hebbian / STDP co-retrieval)
|
|
45904
|
+
CO_RETRIEVED: "co_retrieved",
|
|
45905
|
+
// Temporal supersession
|
|
45906
|
+
SUPERSEDES: "supersedes",
|
|
45907
|
+
// Task / decision / pattern → target context
|
|
45908
|
+
APPLIES_TO: "applies_to",
|
|
45909
|
+
// Provenance
|
|
45910
|
+
DERIVED_FROM: "derived_from",
|
|
45911
|
+
// Observation → symbol/file impact
|
|
45912
|
+
AFFECTS: "affects",
|
|
45913
|
+
// Observation → symbol name mention
|
|
45914
|
+
MENTIONS: "mentions",
|
|
45915
|
+
// Observation → symbol/file structural link
|
|
45916
|
+
DOCUMENTS: "documents"
|
|
45917
|
+
};
|
|
45918
|
+
}
|
|
45919
|
+
});
|
|
45920
|
+
|
|
45694
45921
|
// packages/core/src/memory/brain-consolidator.ts
|
|
45695
45922
|
var brain_consolidator_exports = {};
|
|
45696
45923
|
__export(brain_consolidator_exports, {
|
|
@@ -45924,7 +46151,7 @@ function extractSymbolCandidates(text3) {
|
|
|
45924
46151
|
const syms = /* @__PURE__ */ new Set();
|
|
45925
46152
|
for (const m2 of text3.matchAll(SYMBOL_PATTERN)) {
|
|
45926
46153
|
const s3 = m2[1];
|
|
45927
|
-
if (s3 && s3.length >= 4 && !
|
|
46154
|
+
if (s3 && s3.length >= 4 && !SYMBOL_STOP_WORDS2.has(s3.toLowerCase())) {
|
|
45928
46155
|
syms.add(s3);
|
|
45929
46156
|
}
|
|
45930
46157
|
}
|
|
@@ -46233,7 +46460,7 @@ async function listCodeLinks(projectRoot, limit = 100) {
|
|
|
46233
46460
|
}
|
|
46234
46461
|
return entries;
|
|
46235
46462
|
}
|
|
46236
|
-
var FILE_PATH_PATTERN, SYMBOL_PATTERN,
|
|
46463
|
+
var FILE_PATH_PATTERN, SYMBOL_PATTERN, SYMBOL_STOP_WORDS2;
|
|
46237
46464
|
var init_graph_memory_bridge = __esm({
|
|
46238
46465
|
"packages/core/src/memory/graph-memory-bridge.ts"() {
|
|
46239
46466
|
"use strict";
|
|
@@ -46243,7 +46470,7 @@ var init_graph_memory_bridge = __esm({
|
|
|
46243
46470
|
init_typed_query();
|
|
46244
46471
|
FILE_PATH_PATTERN = /(?:^|\s|['"`(])([a-zA-Z0-9_\-./]+\.(?:ts|tsx|js|jsx|rs|go|py|mjs|cjs))(?:$|\s|['"`)])/g;
|
|
46245
46472
|
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;
|
|
46246
|
-
|
|
46473
|
+
SYMBOL_STOP_WORDS2 = /* @__PURE__ */ new Set([
|
|
46247
46474
|
"true",
|
|
46248
46475
|
"false",
|
|
46249
46476
|
"null",
|
|
@@ -46287,6 +46514,207 @@ var init_graph_memory_bridge = __esm({
|
|
|
46287
46514
|
}
|
|
46288
46515
|
});
|
|
46289
46516
|
|
|
46517
|
+
// packages/core/src/memory/brain-stdp.ts
|
|
46518
|
+
var brain_stdp_exports = {};
|
|
46519
|
+
__export(brain_stdp_exports, {
|
|
46520
|
+
applyStdpPlasticity: () => applyStdpPlasticity,
|
|
46521
|
+
getPlasticityStats: () => getPlasticityStats
|
|
46522
|
+
});
|
|
46523
|
+
async function applyStdpPlasticity(projectRoot, sessionWindowMs = 5 * 60 * 1e3) {
|
|
46524
|
+
const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
|
|
46525
|
+
await getBrainDb2(projectRoot);
|
|
46526
|
+
const nativeDb = getBrainNativeDb2();
|
|
46527
|
+
const result = {
|
|
46528
|
+
ltpEvents: 0,
|
|
46529
|
+
ltdEvents: 0,
|
|
46530
|
+
edgesCreated: 0,
|
|
46531
|
+
pairsExamined: 0
|
|
46532
|
+
};
|
|
46533
|
+
if (!nativeDb) return result;
|
|
46534
|
+
try {
|
|
46535
|
+
nativeDb.prepare("SELECT 1 FROM brain_retrieval_log LIMIT 1").get();
|
|
46536
|
+
} catch {
|
|
46537
|
+
return result;
|
|
46538
|
+
}
|
|
46539
|
+
try {
|
|
46540
|
+
nativeDb.prepare("SELECT 1 FROM brain_plasticity_events LIMIT 1").get();
|
|
46541
|
+
} catch {
|
|
46542
|
+
return result;
|
|
46543
|
+
}
|
|
46544
|
+
const now2 = Date.now();
|
|
46545
|
+
const cutoffMs = now2 - sessionWindowMs;
|
|
46546
|
+
const cutoffIso = new Date(cutoffMs).toISOString().replace("T", " ").slice(0, 19);
|
|
46547
|
+
const nowIso = new Date(now2).toISOString().replace("T", " ").slice(0, 19);
|
|
46548
|
+
let logRows = [];
|
|
46549
|
+
try {
|
|
46550
|
+
logRows = typedAll(
|
|
46551
|
+
nativeDb.prepare(
|
|
46552
|
+
`SELECT id, entry_ids, created_at, retrieval_order, delta_ms
|
|
46553
|
+
FROM brain_retrieval_log
|
|
46554
|
+
WHERE created_at >= ?
|
|
46555
|
+
ORDER BY created_at ASC, id ASC
|
|
46556
|
+
LIMIT 2000`
|
|
46557
|
+
),
|
|
46558
|
+
cutoffIso
|
|
46559
|
+
);
|
|
46560
|
+
} catch {
|
|
46561
|
+
return result;
|
|
46562
|
+
}
|
|
46563
|
+
if (logRows.length === 0) return result;
|
|
46564
|
+
const spikes = [];
|
|
46565
|
+
let globalOrder = 0;
|
|
46566
|
+
for (const row of logRows) {
|
|
46567
|
+
let ids;
|
|
46568
|
+
try {
|
|
46569
|
+
ids = JSON.parse(row.entry_ids);
|
|
46570
|
+
} catch {
|
|
46571
|
+
continue;
|
|
46572
|
+
}
|
|
46573
|
+
const rowTime = (/* @__PURE__ */ new Date(row.created_at.replace(" ", "T") + "Z")).getTime();
|
|
46574
|
+
for (const rawId of ids) {
|
|
46575
|
+
const entryId = rawId.includes(":") ? rawId : `observation:${rawId}`;
|
|
46576
|
+
spikes.push({
|
|
46577
|
+
entryId,
|
|
46578
|
+
rowId: row.id,
|
|
46579
|
+
retrievedAt: rowTime,
|
|
46580
|
+
order: row.retrieval_order ?? globalOrder
|
|
46581
|
+
});
|
|
46582
|
+
globalOrder++;
|
|
46583
|
+
}
|
|
46584
|
+
}
|
|
46585
|
+
spikes.sort((a, b2) => a.retrievedAt - b2.retrievedAt || a.order - b2.order);
|
|
46586
|
+
const prepareGetEdge = nativeDb.prepare(
|
|
46587
|
+
`SELECT weight FROM brain_page_edges
|
|
46588
|
+
WHERE from_id = ? AND to_id = ? AND edge_type = 'co_retrieved'`
|
|
46589
|
+
);
|
|
46590
|
+
const prepareUpdateEdge = nativeDb.prepare(
|
|
46591
|
+
`UPDATE brain_page_edges
|
|
46592
|
+
SET weight = MAX(?, MIN(?, weight + ?))
|
|
46593
|
+
WHERE from_id = ? AND to_id = ? AND edge_type = 'co_retrieved'`
|
|
46594
|
+
);
|
|
46595
|
+
const prepareInsertEdge = nativeDb.prepare(
|
|
46596
|
+
`INSERT OR IGNORE INTO brain_page_edges
|
|
46597
|
+
(from_id, to_id, edge_type, weight, provenance, created_at)
|
|
46598
|
+
VALUES (?, ?, 'co_retrieved', ?, 'plasticity:stdp-ltp', ?)`
|
|
46599
|
+
);
|
|
46600
|
+
const prepareLogEvent = nativeDb.prepare(
|
|
46601
|
+
`INSERT INTO brain_plasticity_events
|
|
46602
|
+
(source_node, target_node, delta_w, kind, timestamp)
|
|
46603
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
46604
|
+
);
|
|
46605
|
+
for (let i = 0; i < spikes.length; i++) {
|
|
46606
|
+
const spikeA = spikes[i];
|
|
46607
|
+
for (let j2 = i + 1; j2 < spikes.length; j2++) {
|
|
46608
|
+
const spikeB = spikes[j2];
|
|
46609
|
+
const deltaT = spikeB.retrievedAt - spikeA.retrievedAt;
|
|
46610
|
+
if (deltaT > sessionWindowMs) break;
|
|
46611
|
+
if (spikeA.entryId === spikeB.entryId) continue;
|
|
46612
|
+
result.pairsExamined++;
|
|
46613
|
+
const deltaW = A_PRE * Math.exp(-deltaT / TAU_PRE_MS);
|
|
46614
|
+
if (deltaW < 1e-6) continue;
|
|
46615
|
+
const existingEdge = prepareGetEdge.get(spikeA.entryId, spikeB.entryId);
|
|
46616
|
+
try {
|
|
46617
|
+
if (existingEdge !== void 0) {
|
|
46618
|
+
prepareUpdateEdge.run(WEIGHT_MIN, WEIGHT_MAX, deltaW, spikeA.entryId, spikeB.entryId);
|
|
46619
|
+
} else {
|
|
46620
|
+
const initialWeight = Math.min(WEIGHT_MAX, deltaW);
|
|
46621
|
+
prepareInsertEdge.run(spikeA.entryId, spikeB.entryId, initialWeight, nowIso);
|
|
46622
|
+
result.edgesCreated++;
|
|
46623
|
+
}
|
|
46624
|
+
prepareLogEvent.run(spikeA.entryId, spikeB.entryId, deltaW, "ltp", nowIso);
|
|
46625
|
+
result.ltpEvents++;
|
|
46626
|
+
} catch {
|
|
46627
|
+
}
|
|
46628
|
+
const deltaWNeg = -(A_POST * Math.exp(-deltaT / TAU_POST_MS));
|
|
46629
|
+
const existingReverseEdge = prepareGetEdge.get(spikeB.entryId, spikeA.entryId);
|
|
46630
|
+
if (existingReverseEdge !== void 0 && Math.abs(deltaWNeg) >= 1e-6) {
|
|
46631
|
+
try {
|
|
46632
|
+
prepareUpdateEdge.run(WEIGHT_MIN, WEIGHT_MAX, deltaWNeg, spikeB.entryId, spikeA.entryId);
|
|
46633
|
+
prepareLogEvent.run(spikeB.entryId, spikeA.entryId, deltaWNeg, "ltd", nowIso);
|
|
46634
|
+
result.ltdEvents++;
|
|
46635
|
+
} catch {
|
|
46636
|
+
}
|
|
46637
|
+
}
|
|
46638
|
+
}
|
|
46639
|
+
}
|
|
46640
|
+
return result;
|
|
46641
|
+
}
|
|
46642
|
+
async function getPlasticityStats(projectRoot, limit = 20) {
|
|
46643
|
+
const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
|
|
46644
|
+
await getBrainDb2(projectRoot);
|
|
46645
|
+
const nativeDb = getBrainNativeDb2();
|
|
46646
|
+
const empty = {
|
|
46647
|
+
totalEvents: 0,
|
|
46648
|
+
ltpCount: 0,
|
|
46649
|
+
ltdCount: 0,
|
|
46650
|
+
netDeltaW: 0,
|
|
46651
|
+
lastEventAt: null,
|
|
46652
|
+
recentEvents: []
|
|
46653
|
+
};
|
|
46654
|
+
if (!nativeDb) return empty;
|
|
46655
|
+
try {
|
|
46656
|
+
nativeDb.prepare("SELECT 1 FROM brain_plasticity_events LIMIT 1").get();
|
|
46657
|
+
} catch {
|
|
46658
|
+
return empty;
|
|
46659
|
+
}
|
|
46660
|
+
let agg;
|
|
46661
|
+
try {
|
|
46662
|
+
agg = nativeDb.prepare(
|
|
46663
|
+
`SELECT
|
|
46664
|
+
COUNT(*) AS total,
|
|
46665
|
+
SUM(CASE WHEN kind = 'ltp' THEN 1 ELSE 0 END) AS ltp_count,
|
|
46666
|
+
SUM(CASE WHEN kind = 'ltd' THEN 1 ELSE 0 END) AS ltd_count,
|
|
46667
|
+
SUM(delta_w) AS net_delta_w,
|
|
46668
|
+
MAX(timestamp) AS last_event_at
|
|
46669
|
+
FROM brain_plasticity_events`
|
|
46670
|
+
).get();
|
|
46671
|
+
} catch {
|
|
46672
|
+
return empty;
|
|
46673
|
+
}
|
|
46674
|
+
let recentRows = [];
|
|
46675
|
+
try {
|
|
46676
|
+
recentRows = typedAll(
|
|
46677
|
+
nativeDb.prepare(
|
|
46678
|
+
`SELECT id, source_node, target_node, delta_w, kind, timestamp, session_id
|
|
46679
|
+
FROM brain_plasticity_events
|
|
46680
|
+
ORDER BY timestamp DESC, id DESC
|
|
46681
|
+
LIMIT ?`
|
|
46682
|
+
),
|
|
46683
|
+
limit
|
|
46684
|
+
);
|
|
46685
|
+
} catch {
|
|
46686
|
+
}
|
|
46687
|
+
return {
|
|
46688
|
+
totalEvents: agg?.total ?? 0,
|
|
46689
|
+
ltpCount: agg?.ltp_count ?? 0,
|
|
46690
|
+
ltdCount: agg?.ltd_count ?? 0,
|
|
46691
|
+
netDeltaW: agg?.net_delta_w ?? 0,
|
|
46692
|
+
lastEventAt: agg?.last_event_at ?? null,
|
|
46693
|
+
recentEvents: recentRows.map((r) => ({
|
|
46694
|
+
id: r.id,
|
|
46695
|
+
sourceNode: r.source_node,
|
|
46696
|
+
targetNode: r.target_node,
|
|
46697
|
+
deltaW: r.delta_w,
|
|
46698
|
+
kind: r.kind,
|
|
46699
|
+
timestamp: r.timestamp,
|
|
46700
|
+
sessionId: r.session_id
|
|
46701
|
+
}))
|
|
46702
|
+
};
|
|
46703
|
+
}
|
|
46704
|
+
var TAU_PRE_MS, TAU_POST_MS, A_PRE, A_POST, WEIGHT_MIN, WEIGHT_MAX;
|
|
46705
|
+
var init_brain_stdp = __esm({
|
|
46706
|
+
"packages/core/src/memory/brain-stdp.ts"() {
|
|
46707
|
+
"use strict";
|
|
46708
|
+
init_typed_query();
|
|
46709
|
+
TAU_PRE_MS = 2e4;
|
|
46710
|
+
TAU_POST_MS = 2e4;
|
|
46711
|
+
A_PRE = 0.05;
|
|
46712
|
+
A_POST = 0.06;
|
|
46713
|
+
WEIGHT_MIN = 0;
|
|
46714
|
+
WEIGHT_MAX = 1;
|
|
46715
|
+
}
|
|
46716
|
+
});
|
|
46717
|
+
|
|
46290
46718
|
// packages/core/src/memory/brain-lifecycle.ts
|
|
46291
46719
|
var brain_lifecycle_exports = {};
|
|
46292
46720
|
__export(brain_lifecycle_exports, {
|
|
@@ -46592,6 +47020,13 @@ async function runConsolidation(projectRoot) {
|
|
|
46592
47020
|
} catch (err) {
|
|
46593
47021
|
console.warn("[consolidation] Step 8 graph memory bridge failed:", err);
|
|
46594
47022
|
}
|
|
47023
|
+
try {
|
|
47024
|
+
const { applyStdpPlasticity: applyStdpPlasticity2 } = await Promise.resolve().then(() => (init_brain_stdp(), brain_stdp_exports));
|
|
47025
|
+
const stdpResult = await applyStdpPlasticity2(projectRoot);
|
|
47026
|
+
result.stdpPlasticity = stdpResult;
|
|
47027
|
+
} catch (err) {
|
|
47028
|
+
console.warn("[consolidation] Step 9 STDP plasticity failed:", err);
|
|
47029
|
+
}
|
|
46595
47030
|
return result;
|
|
46596
47031
|
}
|
|
46597
47032
|
async function deduplicateByEmbedding(projectRoot) {
|
|
@@ -46753,16 +47188,16 @@ async function strengthenCoRetrievedEdges(projectRoot) {
|
|
|
46753
47188
|
const updateStmt = nativeDb.prepare(`
|
|
46754
47189
|
UPDATE brain_page_edges
|
|
46755
47190
|
SET weight = MIN(1.0, weight + 0.1)
|
|
46756
|
-
WHERE from_id = ? AND to_id = ? AND edge_type =
|
|
47191
|
+
WHERE from_id = ? AND to_id = ? AND edge_type = ?
|
|
46757
47192
|
`);
|
|
46758
|
-
const updateResult = updateStmt.run(nodeFrom, nodeTo);
|
|
47193
|
+
const updateResult = updateStmt.run(nodeFrom, nodeTo, EDGE_TYPES.CO_RETRIEVED);
|
|
46759
47194
|
const changes = typeof updateResult.changes === "number" ? updateResult.changes : 0;
|
|
46760
47195
|
if (changes === 0) {
|
|
46761
47196
|
nativeDb.prepare(`
|
|
46762
47197
|
INSERT OR IGNORE INTO brain_page_edges
|
|
46763
47198
|
(from_id, to_id, edge_type, weight, provenance, created_at)
|
|
46764
|
-
VALUES (?, ?,
|
|
46765
|
-
`).run(nodeFrom, nodeTo, now2);
|
|
47199
|
+
VALUES (?, ?, ?, 0.3, 'consolidation:co-retrieval', ?)
|
|
47200
|
+
`).run(nodeFrom, nodeTo, EDGE_TYPES.CO_RETRIEVED, now2);
|
|
46766
47201
|
}
|
|
46767
47202
|
strengthened++;
|
|
46768
47203
|
} catch {
|
|
@@ -46776,6 +47211,7 @@ var init_brain_lifecycle = __esm({
|
|
|
46776
47211
|
"use strict";
|
|
46777
47212
|
init_brain_accessor();
|
|
46778
47213
|
init_typed_query();
|
|
47214
|
+
init_edge_types();
|
|
46779
47215
|
STOP_WORDS3 = /* @__PURE__ */ new Set([
|
|
46780
47216
|
"the",
|
|
46781
47217
|
"a",
|
|
@@ -49937,7 +50373,7 @@ async function computeLastSession(projectRoot, scopeFilter) {
|
|
|
49937
50373
|
const accessor = await getAccessor(projectRoot);
|
|
49938
50374
|
const allSessions = await accessor.loadSessions();
|
|
49939
50375
|
const session = allSessions.find((s3) => s3.id === sessionId);
|
|
49940
|
-
if (!session
|
|
50376
|
+
if (!session?.endedAt) return null;
|
|
49941
50377
|
let duration3 = 0;
|
|
49942
50378
|
if (session.startedAt) {
|
|
49943
50379
|
duration3 = Math.round(
|
|
@@ -51124,10 +51560,17 @@ async function searchBrainCompact(projectRoot, params) {
|
|
|
51124
51560
|
setImmediate(() => {
|
|
51125
51561
|
incrementCitationCounts(projectRoot, returnedIds).catch(() => {
|
|
51126
51562
|
});
|
|
51127
|
-
|
|
51128
|
-
(
|
|
51129
|
-
|
|
51130
|
-
|
|
51563
|
+
getCurrentSessionId(projectRoot).then((sessionId) => {
|
|
51564
|
+
return logRetrieval(
|
|
51565
|
+
projectRoot,
|
|
51566
|
+
query,
|
|
51567
|
+
returnedIds,
|
|
51568
|
+
"find-rrf",
|
|
51569
|
+
results2.length * 50,
|
|
51570
|
+
sessionId
|
|
51571
|
+
);
|
|
51572
|
+
}).catch(() => {
|
|
51573
|
+
});
|
|
51131
51574
|
});
|
|
51132
51575
|
}
|
|
51133
51576
|
return { results: results2, total: results2.length, tokensEstimated: results2.length * 50 };
|
|
@@ -51190,7 +51633,16 @@ async function searchBrainCompact(projectRoot, params) {
|
|
|
51190
51633
|
setImmediate(() => {
|
|
51191
51634
|
incrementCitationCounts(projectRoot, returnedIds).catch(() => {
|
|
51192
51635
|
});
|
|
51193
|
-
|
|
51636
|
+
getCurrentSessionId(projectRoot).then((sessionId) => {
|
|
51637
|
+
return logRetrieval(
|
|
51638
|
+
projectRoot,
|
|
51639
|
+
query,
|
|
51640
|
+
returnedIds,
|
|
51641
|
+
"find",
|
|
51642
|
+
results.length * 50,
|
|
51643
|
+
sessionId
|
|
51644
|
+
);
|
|
51645
|
+
}).catch(() => {
|
|
51194
51646
|
});
|
|
51195
51647
|
});
|
|
51196
51648
|
}
|
|
@@ -51378,13 +51830,16 @@ async function fetchBrainEntries(projectRoot, params) {
|
|
|
51378
51830
|
setImmediate(() => {
|
|
51379
51831
|
incrementCitationCounts(projectRoot, fetchedIds).catch(() => {
|
|
51380
51832
|
});
|
|
51381
|
-
|
|
51382
|
-
|
|
51383
|
-
|
|
51384
|
-
|
|
51385
|
-
|
|
51386
|
-
|
|
51387
|
-
|
|
51833
|
+
getCurrentSessionId(projectRoot).then((sessionId) => {
|
|
51834
|
+
return logRetrieval(
|
|
51835
|
+
projectRoot,
|
|
51836
|
+
fetchedIds.join(","),
|
|
51837
|
+
fetchedIds,
|
|
51838
|
+
"fetch",
|
|
51839
|
+
results.length * 500,
|
|
51840
|
+
sessionId
|
|
51841
|
+
);
|
|
51842
|
+
}).catch(() => {
|
|
51388
51843
|
});
|
|
51389
51844
|
});
|
|
51390
51845
|
}
|
|
@@ -51802,6 +52257,15 @@ async function retrieveWithBudget(projectRoot, query, tokenBudget = 500, options
|
|
|
51802
52257
|
excluded
|
|
51803
52258
|
};
|
|
51804
52259
|
}
|
|
52260
|
+
async function getCurrentSessionId(projectRoot) {
|
|
52261
|
+
try {
|
|
52262
|
+
const { sessionStatus: sessionStatus3 } = await Promise.resolve().then(() => (init_sessions2(), sessions_exports2));
|
|
52263
|
+
const session = await sessionStatus3(projectRoot);
|
|
52264
|
+
return session?.id;
|
|
52265
|
+
} catch {
|
|
52266
|
+
return void 0;
|
|
52267
|
+
}
|
|
52268
|
+
}
|
|
51805
52269
|
async function incrementCitationCounts(projectRoot, ids) {
|
|
51806
52270
|
if (ids.length === 0) return;
|
|
51807
52271
|
const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
|
|
@@ -51828,13 +52292,13 @@ async function incrementCitationCounts(projectRoot, ids) {
|
|
|
51828
52292
|
}
|
|
51829
52293
|
}
|
|
51830
52294
|
}
|
|
51831
|
-
async function logRetrieval(projectRoot, query, entryIds, source, tokensUsed) {
|
|
52295
|
+
async function logRetrieval(projectRoot, query, entryIds, source, tokensUsed, sessionId) {
|
|
51832
52296
|
if (entryIds.length === 0) return;
|
|
51833
52297
|
const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
|
|
51834
52298
|
await getBrainDb2(projectRoot);
|
|
51835
52299
|
const nativeDb = getBrainNativeDb2();
|
|
51836
52300
|
if (!nativeDb) return;
|
|
51837
|
-
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')))";
|
|
52301
|
+
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')))";
|
|
51838
52302
|
try {
|
|
51839
52303
|
nativeDb.prepare(createSql).run();
|
|
51840
52304
|
} catch {
|
|
@@ -51842,8 +52306,15 @@ async function logRetrieval(projectRoot, query, entryIds, source, tokensUsed) {
|
|
|
51842
52306
|
}
|
|
51843
52307
|
try {
|
|
51844
52308
|
nativeDb.prepare(
|
|
51845
|
-
"INSERT INTO brain_retrieval_log (query, entry_ids, entry_count, source, tokens_used) VALUES (?, ?, ?, ?, ?)"
|
|
51846
|
-
).run(
|
|
52309
|
+
"INSERT INTO brain_retrieval_log (query, entry_ids, entry_count, source, tokens_used, session_id) VALUES (?, ?, ?, ?, ?, ?)"
|
|
52310
|
+
).run(
|
|
52311
|
+
query,
|
|
52312
|
+
entryIds.join(","),
|
|
52313
|
+
entryIds.length,
|
|
52314
|
+
source,
|
|
52315
|
+
tokensUsed ?? null,
|
|
52316
|
+
sessionId ?? null
|
|
52317
|
+
);
|
|
51847
52318
|
} catch {
|
|
51848
52319
|
}
|
|
51849
52320
|
}
|
|
@@ -58418,7 +58889,7 @@ function prepareSpawnMulti(skillNames, tokenValues, cwd) {
|
|
|
58418
58889
|
const skillName = skillNames[i];
|
|
58419
58890
|
const isPrimary = i === 0;
|
|
58420
58891
|
const skill = findSkill(skillName, cwd);
|
|
58421
|
-
if (!skill
|
|
58892
|
+
if (!skill?.content) {
|
|
58422
58893
|
continue;
|
|
58423
58894
|
}
|
|
58424
58895
|
let content = isPrimary ? skill.content : loadProgressive(skill.content);
|
|
@@ -60729,6 +61200,7 @@ var init_extraction_gate = __esm({
|
|
|
60729
61200
|
// packages/core/src/memory/index.ts
|
|
60730
61201
|
var memory_exports = {};
|
|
60731
61202
|
__export(memory_exports, {
|
|
61203
|
+
EDGE_TYPES: () => EDGE_TYPES,
|
|
60732
61204
|
RRF_K: () => RRF_K,
|
|
60733
61205
|
addResearch: () => addResearch,
|
|
60734
61206
|
appendExtendedManifest: () => appendExtendedManifest,
|
|
@@ -61412,6 +61884,7 @@ var init_memory = __esm({
|
|
|
61412
61884
|
init_brain_retrieval();
|
|
61413
61885
|
init_brain_search();
|
|
61414
61886
|
init_decisions2();
|
|
61887
|
+
init_edge_types();
|
|
61415
61888
|
init_extraction_gate();
|
|
61416
61889
|
init_learnings();
|
|
61417
61890
|
init_patterns();
|
|
@@ -71602,6 +72075,7 @@ var init_remote = __esm({
|
|
|
71602
72075
|
// packages/core/src/research/index.ts
|
|
71603
72076
|
var research_exports = {};
|
|
71604
72077
|
__export(research_exports, {
|
|
72078
|
+
EDGE_TYPES: () => EDGE_TYPES,
|
|
71605
72079
|
RRF_K: () => RRF_K,
|
|
71606
72080
|
addResearch: () => addResearch,
|
|
71607
72081
|
appendExtendedManifest: () => appendExtendedManifest,
|
|
@@ -73931,7 +74405,7 @@ async function injectProtocol(skillContent, taskId, tokenValues, cwd, tier) {
|
|
|
73931
74405
|
}
|
|
73932
74406
|
async function orchestratorSpawnSkill(taskId, skillName, tokenValues, cwd, tier) {
|
|
73933
74407
|
const skill = findSkill(skillName, cwd);
|
|
73934
|
-
if (!skill
|
|
74408
|
+
if (!skill?.content) {
|
|
73935
74409
|
throw new CleoError(4 /* NOT_FOUND */, `Skill not found: ${skillName}`, {
|
|
73936
74410
|
fix: `Check skills directory for ${skillName}/SKILL.md`
|
|
73937
74411
|
});
|
|
@@ -74501,7 +74975,7 @@ async function buildPrompt(taskId, templateName = "TASK-EXECUTOR", cwd, tier) {
|
|
|
74501
74975
|
throw new CleoError(4 /* NOT_FOUND */, `Task ${taskId} not found`);
|
|
74502
74976
|
}
|
|
74503
74977
|
const skill = findSkill(templateName, cwd);
|
|
74504
|
-
if (!skill
|
|
74978
|
+
if (!skill?.content) {
|
|
74505
74979
|
const { canonical } = mapSkillName(templateName);
|
|
74506
74980
|
throw new CleoError(4 /* NOT_FOUND */, `Skill template ${templateName} not found`, {
|
|
74507
74981
|
fix: `Expected at skills/${canonical}/SKILL.md`
|
|
@@ -77296,7 +77770,7 @@ async function analyzeArchive(opts, accessor) {
|
|
|
77296
77770
|
const acc = accessor ?? await getAccessor(opts.cwd);
|
|
77297
77771
|
const data = await acc.loadArchive();
|
|
77298
77772
|
const reportType = opts.report ?? "summary";
|
|
77299
|
-
if (!data
|
|
77773
|
+
if (!data?.archivedTasks?.length) {
|
|
77300
77774
|
return {
|
|
77301
77775
|
report: reportType,
|
|
77302
77776
|
filters: null,
|
|
@@ -85357,16 +85831,12 @@ function allEpicChildrenVerified(epicId, tasks2) {
|
|
|
85357
85831
|
if (children.length === 0) return false;
|
|
85358
85832
|
const incomplete = children.filter((t) => t.status !== "done");
|
|
85359
85833
|
if (incomplete.length > 0) return false;
|
|
85360
|
-
const unverified = children.filter(
|
|
85361
|
-
(t) => t.status === "done" && (!t.verification || !t.verification.passed)
|
|
85362
|
-
);
|
|
85834
|
+
const unverified = children.filter((t) => t.status === "done" && !t.verification?.passed);
|
|
85363
85835
|
return unverified.length === 0;
|
|
85364
85836
|
}
|
|
85365
85837
|
function allSiblingsVerified(parentId, tasks2) {
|
|
85366
85838
|
const siblings = tasks2.filter((t) => t.parentId === parentId);
|
|
85367
|
-
const unverifiedDone = siblings.filter(
|
|
85368
|
-
(t) => t.status === "done" && (!t.verification || !t.verification.passed)
|
|
85369
|
-
);
|
|
85839
|
+
const unverifiedDone = siblings.filter((t) => t.status === "done" && !t.verification?.passed);
|
|
85370
85840
|
const incomplete = siblings.filter(
|
|
85371
85841
|
(t) => t.status === "pending" || t.status === "active" || t.status === "blocked"
|
|
85372
85842
|
);
|
|
@@ -86772,7 +87242,7 @@ var init_init = __esm({
|
|
|
86772
87242
|
// packages/core/src/sessions/context-alert.ts
|
|
86773
87243
|
import { existsSync as existsSync109, readFileSync as readFileSync80, writeFileSync as writeFileSync20 } from "node:fs";
|
|
86774
87244
|
import { join as join109 } from "node:path";
|
|
86775
|
-
function
|
|
87245
|
+
function getCurrentSessionId2(cwd) {
|
|
86776
87246
|
if (process.env.CLEO_SESSION) return process.env.CLEO_SESSION;
|
|
86777
87247
|
const sessionFile = join109(getCleoDir(cwd), ".current-session");
|
|
86778
87248
|
if (existsSync109(sessionFile)) {
|
|
@@ -86806,7 +87276,7 @@ function createCliMeta(operation, duration_ms = 0) {
|
|
|
86806
87276
|
duration_ms,
|
|
86807
87277
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
86808
87278
|
};
|
|
86809
|
-
const sessionId =
|
|
87279
|
+
const sessionId = getCurrentSessionId2();
|
|
86810
87280
|
if (sessionId) {
|
|
86811
87281
|
meta3["sessionId"] = sessionId;
|
|
86812
87282
|
}
|
|
@@ -90476,6 +90946,160 @@ var init_brain_backfill = __esm({
|
|
|
90476
90946
|
}
|
|
90477
90947
|
});
|
|
90478
90948
|
|
|
90949
|
+
// packages/core/src/memory/brain-export.ts
|
|
90950
|
+
async function exportBrainAsGexf(projectRoot) {
|
|
90951
|
+
const db = await getBrainDb(projectRoot);
|
|
90952
|
+
let nodes = [];
|
|
90953
|
+
let edges = [];
|
|
90954
|
+
try {
|
|
90955
|
+
nodes = await db.select({
|
|
90956
|
+
id: brainPageNodes.id,
|
|
90957
|
+
nodeType: brainPageNodes.nodeType,
|
|
90958
|
+
label: brainPageNodes.label,
|
|
90959
|
+
qualityScore: brainPageNodes.qualityScore,
|
|
90960
|
+
contentHash: brainPageNodes.contentHash,
|
|
90961
|
+
lastActivityAt: brainPageNodes.lastActivityAt,
|
|
90962
|
+
metadataJson: brainPageNodes.metadataJson,
|
|
90963
|
+
createdAt: brainPageNodes.createdAt,
|
|
90964
|
+
updatedAt: brainPageNodes.updatedAt
|
|
90965
|
+
}).from(brainPageNodes);
|
|
90966
|
+
} catch {
|
|
90967
|
+
nodes = [];
|
|
90968
|
+
}
|
|
90969
|
+
try {
|
|
90970
|
+
const rawEdges = await db.select({
|
|
90971
|
+
fromId: brainPageEdges.fromId,
|
|
90972
|
+
toId: brainPageEdges.toId,
|
|
90973
|
+
edgeType: brainPageEdges.edgeType,
|
|
90974
|
+
weight: brainPageEdges.weight,
|
|
90975
|
+
createdAt: brainPageEdges.createdAt
|
|
90976
|
+
}).from(brainPageEdges);
|
|
90977
|
+
edges = rawEdges.map((e) => ({ ...e, provenance: null }));
|
|
90978
|
+
} catch {
|
|
90979
|
+
edges = [];
|
|
90980
|
+
}
|
|
90981
|
+
const gexf = buildGexfDocument(nodes, edges);
|
|
90982
|
+
return {
|
|
90983
|
+
success: true,
|
|
90984
|
+
format: "gexf",
|
|
90985
|
+
nodeCount: nodes.length,
|
|
90986
|
+
edgeCount: edges.length,
|
|
90987
|
+
content: gexf,
|
|
90988
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
90989
|
+
};
|
|
90990
|
+
}
|
|
90991
|
+
async function exportBrainAsJson(projectRoot) {
|
|
90992
|
+
const db = await getBrainDb(projectRoot);
|
|
90993
|
+
let nodes = [];
|
|
90994
|
+
let edges = [];
|
|
90995
|
+
try {
|
|
90996
|
+
nodes = await db.select({
|
|
90997
|
+
id: brainPageNodes.id,
|
|
90998
|
+
nodeType: brainPageNodes.nodeType,
|
|
90999
|
+
label: brainPageNodes.label,
|
|
91000
|
+
qualityScore: brainPageNodes.qualityScore,
|
|
91001
|
+
contentHash: brainPageNodes.contentHash,
|
|
91002
|
+
lastActivityAt: brainPageNodes.lastActivityAt,
|
|
91003
|
+
metadataJson: brainPageNodes.metadataJson,
|
|
91004
|
+
createdAt: brainPageNodes.createdAt,
|
|
91005
|
+
updatedAt: brainPageNodes.updatedAt
|
|
91006
|
+
}).from(brainPageNodes);
|
|
91007
|
+
} catch {
|
|
91008
|
+
nodes = [];
|
|
91009
|
+
}
|
|
91010
|
+
try {
|
|
91011
|
+
const rawEdges = await db.select({
|
|
91012
|
+
fromId: brainPageEdges.fromId,
|
|
91013
|
+
toId: brainPageEdges.toId,
|
|
91014
|
+
edgeType: brainPageEdges.edgeType,
|
|
91015
|
+
weight: brainPageEdges.weight,
|
|
91016
|
+
createdAt: brainPageEdges.createdAt
|
|
91017
|
+
}).from(brainPageEdges);
|
|
91018
|
+
edges = rawEdges.map((e) => ({ ...e, provenance: null }));
|
|
91019
|
+
} catch {
|
|
91020
|
+
edges = [];
|
|
91021
|
+
}
|
|
91022
|
+
return {
|
|
91023
|
+
success: true,
|
|
91024
|
+
format: "json",
|
|
91025
|
+
nodeCount: nodes.length,
|
|
91026
|
+
edgeCount: edges.length,
|
|
91027
|
+
nodes,
|
|
91028
|
+
edges,
|
|
91029
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
91030
|
+
};
|
|
91031
|
+
}
|
|
91032
|
+
function buildGexfDocument(nodes, edges) {
|
|
91033
|
+
const lines = [
|
|
91034
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
91035
|
+
'<gexf xmlns="http://www.gexf.net/1.3draft" version="1.3">',
|
|
91036
|
+
' <meta lastmodifieddate="' + (/* @__PURE__ */ new Date()).toISOString() + '">',
|
|
91037
|
+
" <creator>CLEO Brain Export (T626-M6)</creator>",
|
|
91038
|
+
" <description>Living brain knowledge graph (brain_page_nodes + brain_page_edges)</description>",
|
|
91039
|
+
" </meta>",
|
|
91040
|
+
' <graph mode="static" defaultedgetype="directed">'
|
|
91041
|
+
];
|
|
91042
|
+
lines.push(' <attributes class="node">');
|
|
91043
|
+
lines.push(' <attribute id="node_type" title="Node Type" type="string"/>');
|
|
91044
|
+
lines.push(' <attribute id="quality_score" title="Quality Score" type="double"/>');
|
|
91045
|
+
lines.push(' <attribute id="content_hash" title="Content Hash" type="string"/>');
|
|
91046
|
+
lines.push(' <attribute id="last_activity_at" title="Last Activity" type="string"/>');
|
|
91047
|
+
lines.push(' <attribute id="created_at" title="Created At" type="string"/>');
|
|
91048
|
+
lines.push(" </attributes>");
|
|
91049
|
+
lines.push(' <attributes class="edge">');
|
|
91050
|
+
lines.push(' <attribute id="edge_type" title="Edge Type" type="string"/>');
|
|
91051
|
+
lines.push(' <attribute id="provenance" title="Provenance" type="string"/>');
|
|
91052
|
+
lines.push(' <attribute id="created_at" title="Created At" type="string"/>');
|
|
91053
|
+
lines.push(" </attributes>");
|
|
91054
|
+
lines.push(" <nodes>");
|
|
91055
|
+
for (const node of nodes) {
|
|
91056
|
+
lines.push(` <node id="${escapeXml(node.id)}" label="${escapeXml(node.label)}">`);
|
|
91057
|
+
lines.push(" <attvalues>");
|
|
91058
|
+
lines.push(` <attvalue for="node_type" value="${escapeXml(node.nodeType)}"/>`);
|
|
91059
|
+
lines.push(` <attvalue for="quality_score" value="${node.qualityScore ?? 0.5}"/>`);
|
|
91060
|
+
if (node.contentHash) {
|
|
91061
|
+
lines.push(` <attvalue for="content_hash" value="${escapeXml(node.contentHash)}"/>`);
|
|
91062
|
+
}
|
|
91063
|
+
lines.push(
|
|
91064
|
+
` <attvalue for="last_activity_at" value="${escapeXml(node.lastActivityAt)}"/>`
|
|
91065
|
+
);
|
|
91066
|
+
lines.push(` <attvalue for="created_at" value="${escapeXml(node.createdAt)}"/>`);
|
|
91067
|
+
lines.push(" </attvalues>");
|
|
91068
|
+
lines.push(" </node>");
|
|
91069
|
+
}
|
|
91070
|
+
lines.push(" </nodes>");
|
|
91071
|
+
lines.push(" <edges>");
|
|
91072
|
+
for (let i = 0; i < edges.length; i++) {
|
|
91073
|
+
const edge = edges[i];
|
|
91074
|
+
const weight = edge.weight ?? 1;
|
|
91075
|
+
lines.push(
|
|
91076
|
+
` <edge id="${i}" source="${escapeXml(edge.fromId)}" target="${escapeXml(edge.toId)}" weight="${weight}">`
|
|
91077
|
+
);
|
|
91078
|
+
lines.push(" <attvalues>");
|
|
91079
|
+
lines.push(` <attvalue for="edge_type" value="${escapeXml(edge.edgeType)}"/>`);
|
|
91080
|
+
if (edge.provenance) {
|
|
91081
|
+
lines.push(` <attvalue for="provenance" value="${escapeXml(edge.provenance)}"/>`);
|
|
91082
|
+
}
|
|
91083
|
+
lines.push(` <attvalue for="created_at" value="${escapeXml(edge.createdAt)}"/>`);
|
|
91084
|
+
lines.push(" </attvalues>");
|
|
91085
|
+
lines.push(" </edge>");
|
|
91086
|
+
}
|
|
91087
|
+
lines.push(" </edges>");
|
|
91088
|
+
lines.push(" </graph>");
|
|
91089
|
+
lines.push("</gexf>");
|
|
91090
|
+
return lines.join("\n");
|
|
91091
|
+
}
|
|
91092
|
+
function escapeXml(text3) {
|
|
91093
|
+
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
91094
|
+
}
|
|
91095
|
+
var init_brain_export = __esm({
|
|
91096
|
+
"packages/core/src/memory/brain-export.ts"() {
|
|
91097
|
+
"use strict";
|
|
91098
|
+
init_brain_schema();
|
|
91099
|
+
init_brain_sqlite();
|
|
91100
|
+
}
|
|
91101
|
+
});
|
|
91102
|
+
|
|
90479
91103
|
// packages/core/src/memory/brain-maintenance.ts
|
|
90480
91104
|
async function runBrainMaintenance(projectRoot, options) {
|
|
90481
91105
|
const {
|
|
@@ -90885,7 +91509,7 @@ Use --source <path> to specify a custom location.`
|
|
|
90885
91509
|
}
|
|
90886
91510
|
try {
|
|
90887
91511
|
for (const row of batch) {
|
|
90888
|
-
if (!row.learned
|
|
91512
|
+
if (!row.learned?.trim()) {
|
|
90889
91513
|
continue;
|
|
90890
91514
|
}
|
|
90891
91515
|
const learnId = `CML-${row.id}`;
|
|
@@ -98265,7 +98889,7 @@ function measureDependencyDepth(taskId, taskMap, visited = /* @__PURE__ */ new S
|
|
|
98265
98889
|
if (visited.has(taskId)) return 0;
|
|
98266
98890
|
visited.add(taskId);
|
|
98267
98891
|
const task = taskMap.get(taskId);
|
|
98268
|
-
if (!task
|
|
98892
|
+
if (!task?.depends || task.depends.length === 0) return 0;
|
|
98269
98893
|
let maxDepth = 0;
|
|
98270
98894
|
for (const depId of task.depends) {
|
|
98271
98895
|
const depth = 1 + measureDependencyDepth(depId, taskMap, visited);
|
|
@@ -98619,7 +99243,7 @@ async function coreTaskUnarchive(projectRoot, taskId, params) {
|
|
|
98619
99243
|
throw new Error(`Task '${taskId}' already exists in active tasks`);
|
|
98620
99244
|
}
|
|
98621
99245
|
const archive = await accessor.loadArchive();
|
|
98622
|
-
if (!archive
|
|
99246
|
+
if (!archive?.archivedTasks) {
|
|
98623
99247
|
throw new Error("No archive file found");
|
|
98624
99248
|
}
|
|
98625
99249
|
const taskIndex = archive.archivedTasks.findIndex((t) => t.id === taskId);
|
|
@@ -112790,6 +113414,7 @@ __export(internal_exports, {
|
|
|
112790
113414
|
analyzeDependencies: () => analyzeDependencies2,
|
|
112791
113415
|
analyzeEpic: () => analyzeEpic,
|
|
112792
113416
|
analyzeTaskImpact: () => analyzeTaskImpact,
|
|
113417
|
+
applyStdpPlasticity: () => applyStdpPlasticity,
|
|
112793
113418
|
applyStrictnessPreset: () => applyStrictnessPreset,
|
|
112794
113419
|
applyTemporalDecay: () => applyTemporalDecay,
|
|
112795
113420
|
archiveSessions: () => archiveSessions,
|
|
@@ -113003,6 +113628,8 @@ __export(internal_exports, {
|
|
|
113003
113628
|
ensureSqliteDb: () => ensureSqliteDb,
|
|
113004
113629
|
estimateContext: () => estimateContext,
|
|
113005
113630
|
executeTransfer: () => executeTransfer,
|
|
113631
|
+
exportBrainAsGexf: () => exportBrainAsGexf,
|
|
113632
|
+
exportBrainAsJson: () => exportBrainAsJson,
|
|
113006
113633
|
exportSnapshot: () => exportSnapshot,
|
|
113007
113634
|
exportTasks: () => exportTasks,
|
|
113008
113635
|
exportTasksPackage: () => exportTasksPackage,
|
|
@@ -113072,7 +113699,7 @@ __export(internal_exports, {
|
|
|
113072
113699
|
getConfigValue: () => getConfigValue,
|
|
113073
113700
|
getContextDrift: () => getContextDrift,
|
|
113074
113701
|
getCriticalPath: () => getCriticalPath,
|
|
113075
|
-
getCurrentSessionId: () =>
|
|
113702
|
+
getCurrentSessionId: () => getCurrentSessionId2,
|
|
113076
113703
|
getDashboard: () => getDashboard,
|
|
113077
113704
|
getDb: () => getDb,
|
|
113078
113705
|
getDecisionLog: () => getDecisionLog,
|
|
@@ -113117,6 +113744,7 @@ __export(internal_exports, {
|
|
|
113117
113744
|
getPackageRoot: () => getPackageRoot,
|
|
113118
113745
|
getParallelStatus: () => getParallelStatus,
|
|
113119
113746
|
getPipelineStageOrder: () => getPipelineStageOrder,
|
|
113747
|
+
getPlasticityStats: () => getPlasticityStats,
|
|
113120
113748
|
getProjectAgentRef: () => getProjectAgentRef2,
|
|
113121
113749
|
getProjectInfo: () => getProjectInfo,
|
|
113122
113750
|
getProjectInfoSync: () => getProjectInfoSync,
|
|
@@ -113579,10 +114207,12 @@ var init_internal = __esm({
|
|
|
113579
114207
|
init_stages();
|
|
113580
114208
|
init_tessera_engine();
|
|
113581
114209
|
init_brain_backfill();
|
|
114210
|
+
init_brain_export();
|
|
113582
114211
|
init_brain_lifecycle();
|
|
113583
114212
|
init_brain_maintenance();
|
|
113584
114213
|
init_brain_purge();
|
|
113585
114214
|
init_brain_retrieval();
|
|
114215
|
+
init_brain_stdp();
|
|
113586
114216
|
init_claude_mem_migration();
|
|
113587
114217
|
init_engine_compat();
|
|
113588
114218
|
init_pipeline_manifest_sqlite();
|
|
@@ -135777,6 +136407,62 @@ function registerBrainCommand(program) {
|
|
|
135777
136407
|
process.exit(1);
|
|
135778
136408
|
}
|
|
135779
136409
|
});
|
|
136410
|
+
const plasticity = brain.command("plasticity").description("STDP timing-dependent plasticity operations (T626 phase 5)");
|
|
136411
|
+
plasticity.command("stats").description(
|
|
136412
|
+
"Show recent STDP plasticity events: LTP/LTD counts, net weight delta, and most recent events."
|
|
136413
|
+
).option("--limit <n>", "Maximum recent events to show (default 20)", "20").option("--json", "Output results as JSON").action(async (opts) => {
|
|
136414
|
+
const root = getProjectRoot();
|
|
136415
|
+
const isJson = !!opts.json;
|
|
136416
|
+
const limit = Number(opts.limit ?? "20") || 20;
|
|
136417
|
+
try {
|
|
136418
|
+
const stats2 = await getPlasticityStats(root, limit);
|
|
136419
|
+
if (isJson) {
|
|
136420
|
+
console.log(
|
|
136421
|
+
JSON.stringify(
|
|
136422
|
+
{
|
|
136423
|
+
success: true,
|
|
136424
|
+
data: stats2,
|
|
136425
|
+
meta: { operation: "brain.plasticity.stats", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
136426
|
+
},
|
|
136427
|
+
null,
|
|
136428
|
+
2
|
|
136429
|
+
)
|
|
136430
|
+
);
|
|
136431
|
+
return;
|
|
136432
|
+
}
|
|
136433
|
+
console.log("\nBrain Plasticity Stats (STDP)");
|
|
136434
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
136435
|
+
console.log(` Total events: ${stats2.totalEvents}`);
|
|
136436
|
+
console.log(` LTP (potentiation): ${stats2.ltpCount}`);
|
|
136437
|
+
console.log(` LTD (depression): ${stats2.ltdCount}`);
|
|
136438
|
+
const sign = stats2.netDeltaW >= 0 ? "+" : "";
|
|
136439
|
+
console.log(` Net \u0394w: ${sign}${stats2.netDeltaW.toFixed(4)}`);
|
|
136440
|
+
console.log(` Last event: ${stats2.lastEventAt ?? "(none)"}`);
|
|
136441
|
+
if (stats2.recentEvents.length > 0) {
|
|
136442
|
+
console.log(`
|
|
136443
|
+
Recent Events (newest first, limit=${limit})`);
|
|
136444
|
+
for (const ev of stats2.recentEvents) {
|
|
136445
|
+
const evSign = ev.deltaW >= 0 ? "+" : "";
|
|
136446
|
+
const src = ev.sourceNode.slice(0, 30).padEnd(30);
|
|
136447
|
+
const tgt = ev.targetNode.slice(0, 30).padEnd(30);
|
|
136448
|
+
console.log(
|
|
136449
|
+
` [${ev.kind.toUpperCase()}] ${src} \u2192 ${tgt} \u0394w=${evSign}${ev.deltaW.toFixed(4)} ${ev.timestamp}`
|
|
136450
|
+
);
|
|
136451
|
+
}
|
|
136452
|
+
} else {
|
|
136453
|
+
console.log("\n No plasticity events recorded yet.");
|
|
136454
|
+
console.log(" Run `cleo brain maintenance` or `cleo session end` to trigger STDP.");
|
|
136455
|
+
}
|
|
136456
|
+
} catch (err) {
|
|
136457
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
136458
|
+
if (isJson) {
|
|
136459
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
136460
|
+
} else {
|
|
136461
|
+
console.error(`Brain plasticity stats failed: ${message}`);
|
|
136462
|
+
}
|
|
136463
|
+
process.exit(1);
|
|
136464
|
+
}
|
|
136465
|
+
});
|
|
135780
136466
|
brain.command("quality").description(
|
|
135781
136467
|
"Show memory quality metrics: retrieval rates, top/never-retrieved entries, quality distribution, and noise ratio."
|
|
135782
136468
|
).option("--json", "Output results as JSON").action(async (opts) => {
|
|
@@ -135837,6 +136523,47 @@ function registerBrainCommand(program) {
|
|
|
135837
136523
|
process.exit(1);
|
|
135838
136524
|
}
|
|
135839
136525
|
});
|
|
136526
|
+
brain.command("export").description("Export brain graph as GEXF (Gephi) or JSON format").option(
|
|
136527
|
+
"--format <format>",
|
|
136528
|
+
"Export format: gexf (Gephi standard) or json (flat arrays)",
|
|
136529
|
+
"gexf"
|
|
136530
|
+
).option("--output <file>", "Write to file instead of stdout (optional)").action(async (opts) => {
|
|
136531
|
+
const root = getProjectRoot();
|
|
136532
|
+
const format = opts.format ?? "gexf";
|
|
136533
|
+
if (format !== "gexf" && format !== "json") {
|
|
136534
|
+
console.error(`Invalid format: ${format}. Use 'gexf' or 'json'.`);
|
|
136535
|
+
process.exit(1);
|
|
136536
|
+
}
|
|
136537
|
+
try {
|
|
136538
|
+
let content;
|
|
136539
|
+
let nodeCount;
|
|
136540
|
+
let edgeCount;
|
|
136541
|
+
if (format === "gexf") {
|
|
136542
|
+
const result = await exportBrainAsGexf(root);
|
|
136543
|
+
content = result.content;
|
|
136544
|
+
nodeCount = result.nodeCount;
|
|
136545
|
+
edgeCount = result.edgeCount;
|
|
136546
|
+
} else {
|
|
136547
|
+
const result = await exportBrainAsJson(root);
|
|
136548
|
+
content = JSON.stringify(result, null, 2);
|
|
136549
|
+
nodeCount = result.nodeCount;
|
|
136550
|
+
edgeCount = result.edgeCount;
|
|
136551
|
+
}
|
|
136552
|
+
if (opts.output) {
|
|
136553
|
+
const fs11 = await import("node:fs");
|
|
136554
|
+
fs11.writeFileSync(opts.output, content, "utf-8");
|
|
136555
|
+
console.log(
|
|
136556
|
+
`Exported to ${opts.output}: ${nodeCount} nodes, ${edgeCount} edges (${format.toUpperCase()})`
|
|
136557
|
+
);
|
|
136558
|
+
} else {
|
|
136559
|
+
console.log(content);
|
|
136560
|
+
}
|
|
136561
|
+
} catch (err) {
|
|
136562
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
136563
|
+
console.error(`Brain export failed: ${message}`);
|
|
136564
|
+
process.exit(1);
|
|
136565
|
+
}
|
|
136566
|
+
});
|
|
135840
136567
|
}
|
|
135841
136568
|
|
|
135842
136569
|
// packages/cleo/src/cli/commands/briefing.ts
|
|
@@ -139148,6 +139875,175 @@ var NODE_KIND_PRIORITY = {
|
|
|
139148
139875
|
file: 40,
|
|
139149
139876
|
folder: 41
|
|
139150
139877
|
};
|
|
139878
|
+
function generateGexf(nodes, relations) {
|
|
139879
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
139880
|
+
for (const n of nodes) {
|
|
139881
|
+
nodeById.set(String(n["id"]), n);
|
|
139882
|
+
}
|
|
139883
|
+
const kindColors = {
|
|
139884
|
+
function: "#3498db",
|
|
139885
|
+
// blue
|
|
139886
|
+
method: "#2980b9",
|
|
139887
|
+
// darker blue
|
|
139888
|
+
class: "#e74c3c",
|
|
139889
|
+
// red
|
|
139890
|
+
interface: "#e67e22",
|
|
139891
|
+
// orange
|
|
139892
|
+
file: "#95a5a6",
|
|
139893
|
+
// gray
|
|
139894
|
+
folder: "#34495e",
|
|
139895
|
+
// dark gray
|
|
139896
|
+
community: "#9b59b6",
|
|
139897
|
+
// purple
|
|
139898
|
+
process: "#1abc9c",
|
|
139899
|
+
// teal
|
|
139900
|
+
import: "#f39c12",
|
|
139901
|
+
// amber
|
|
139902
|
+
default: "#7f8c8d"
|
|
139903
|
+
// medium gray
|
|
139904
|
+
};
|
|
139905
|
+
const getNodeColor = (kind) => {
|
|
139906
|
+
return kindColors[kind] ?? kindColors["default"];
|
|
139907
|
+
};
|
|
139908
|
+
let gexf = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
139909
|
+
gexf += '<gexf xmlns="http://www.gexf.net/1.2draft" xmlns:viz="http://www.gexf.net/1.2draft/viz" version="1.2">\n';
|
|
139910
|
+
gexf += ' <meta lastmodifieddate="' + (/* @__PURE__ */ new Date()).toISOString().split("T")[0] + '">\n';
|
|
139911
|
+
gexf += " <creator>CLEO nexus export</creator>\n";
|
|
139912
|
+
gexf += " <description>Code intelligence graph from CLEO nexus</description>\n";
|
|
139913
|
+
gexf += " </meta>\n";
|
|
139914
|
+
gexf += ' <graph mode="static" defaultedgetype="directed">\n';
|
|
139915
|
+
gexf += ' <attributes class="node">\n';
|
|
139916
|
+
gexf += ' <attribute id="kind" title="Node Kind" type="string" />\n';
|
|
139917
|
+
gexf += ' <attribute id="filePath" title="File Path" type="string" />\n';
|
|
139918
|
+
gexf += ' <attribute id="language" title="Language" type="string" />\n';
|
|
139919
|
+
gexf += ' <attribute id="startLine" title="Start Line" type="integer" />\n';
|
|
139920
|
+
gexf += ' <attribute id="endLine" title="End Line" type="integer" />\n';
|
|
139921
|
+
gexf += ' <attribute id="isExported" title="Is Exported" type="boolean" />\n';
|
|
139922
|
+
gexf += ' <attribute id="projectId" title="Project ID" type="string" />\n';
|
|
139923
|
+
gexf += " </attributes>\n";
|
|
139924
|
+
gexf += ' <attributes class="edge">\n';
|
|
139925
|
+
gexf += ' <attribute id="relationType" title="Relation Type" type="string" />\n';
|
|
139926
|
+
gexf += ' <attribute id="confidence" title="Confidence" type="double" />\n';
|
|
139927
|
+
gexf += ' <attribute id="reason" title="Reason" type="string" />\n';
|
|
139928
|
+
gexf += " </attributes>\n";
|
|
139929
|
+
gexf += " <nodes>\n";
|
|
139930
|
+
for (const node of nodes) {
|
|
139931
|
+
const nodeId = String(node["id"]).replace(/[<>"'&]/g, (c) => {
|
|
139932
|
+
const map2 = {
|
|
139933
|
+
"<": "<",
|
|
139934
|
+
">": ">",
|
|
139935
|
+
'"': """,
|
|
139936
|
+
"'": "'",
|
|
139937
|
+
"&": "&"
|
|
139938
|
+
};
|
|
139939
|
+
return map2[c];
|
|
139940
|
+
});
|
|
139941
|
+
const label = String(node["label"] ?? node["id"]);
|
|
139942
|
+
const kind = String(node["kind"] ?? "unknown");
|
|
139943
|
+
const color = getNodeColor(kind);
|
|
139944
|
+
gexf += ` <node id="${nodeId}" label="${escapeXml2(label)}">
|
|
139945
|
+
`;
|
|
139946
|
+
gexf += ` <viz:color r="${hexToRgb(color).r}" g="${hexToRgb(color).g}" b="${hexToRgb(color).b}" />
|
|
139947
|
+
`;
|
|
139948
|
+
gexf += " <attvalues>\n";
|
|
139949
|
+
gexf += ` <attvalue id="kind" value="${escapeXml2(kind)}" />
|
|
139950
|
+
`;
|
|
139951
|
+
if (node["filePath"]) {
|
|
139952
|
+
gexf += ` <attvalue id="filePath" value="${escapeXml2(String(node["filePath"]))}" />
|
|
139953
|
+
`;
|
|
139954
|
+
}
|
|
139955
|
+
if (node["language"]) {
|
|
139956
|
+
gexf += ` <attvalue id="language" value="${escapeXml2(String(node["language"]))}" />
|
|
139957
|
+
`;
|
|
139958
|
+
}
|
|
139959
|
+
if (node["startLine"] != null) {
|
|
139960
|
+
gexf += ` <attvalue id="startLine" value="${node["startLine"]}" />
|
|
139961
|
+
`;
|
|
139962
|
+
}
|
|
139963
|
+
if (node["endLine"] != null) {
|
|
139964
|
+
gexf += ` <attvalue id="endLine" value="${node["endLine"]}" />
|
|
139965
|
+
`;
|
|
139966
|
+
}
|
|
139967
|
+
if (node["isExported"] != null) {
|
|
139968
|
+
gexf += ` <attvalue id="isExported" value="${node["isExported"] ? "true" : "false"}" />
|
|
139969
|
+
`;
|
|
139970
|
+
}
|
|
139971
|
+
if (node["projectId"]) {
|
|
139972
|
+
gexf += ` <attvalue id="projectId" value="${escapeXml2(String(node["projectId"]))}" />
|
|
139973
|
+
`;
|
|
139974
|
+
}
|
|
139975
|
+
gexf += " </attvalues>\n";
|
|
139976
|
+
gexf += " </node>\n";
|
|
139977
|
+
}
|
|
139978
|
+
gexf += " </nodes>\n";
|
|
139979
|
+
gexf += " <edges>\n";
|
|
139980
|
+
for (let i = 0; i < relations.length; i++) {
|
|
139981
|
+
const rel = relations[i];
|
|
139982
|
+
const sourceId = String(rel["sourceId"]).replace(/[<>"'&]/g, (c) => {
|
|
139983
|
+
const map2 = {
|
|
139984
|
+
"<": "<",
|
|
139985
|
+
">": ">",
|
|
139986
|
+
'"': """,
|
|
139987
|
+
"'": "'",
|
|
139988
|
+
"&": "&"
|
|
139989
|
+
};
|
|
139990
|
+
return map2[c];
|
|
139991
|
+
});
|
|
139992
|
+
const targetId = String(rel["targetId"]).replace(/[<>"'&]/g, (c) => {
|
|
139993
|
+
const map2 = {
|
|
139994
|
+
"<": "<",
|
|
139995
|
+
">": ">",
|
|
139996
|
+
'"': """,
|
|
139997
|
+
"'": "'",
|
|
139998
|
+
"&": "&"
|
|
139999
|
+
};
|
|
140000
|
+
return map2[c];
|
|
140001
|
+
});
|
|
140002
|
+
if (!nodeById.has(String(rel["sourceId"])) || !nodeById.has(String(rel["targetId"]))) {
|
|
140003
|
+
continue;
|
|
140004
|
+
}
|
|
140005
|
+
const confidence = typeof rel["confidence"] === "number" ? rel["confidence"] : 1;
|
|
140006
|
+
const relationType = String(rel["type"] ?? "unknown");
|
|
140007
|
+
const reason = rel["reason"] ? String(rel["reason"]) : "";
|
|
140008
|
+
gexf += ` <edge id="e${i}" source="${sourceId}" target="${targetId}" weight="${confidence}">
|
|
140009
|
+
`;
|
|
140010
|
+
gexf += " <attvalues>\n";
|
|
140011
|
+
gexf += ` <attvalue id="relationType" value="${escapeXml2(relationType)}" />
|
|
140012
|
+
`;
|
|
140013
|
+
gexf += ` <attvalue id="confidence" value="${confidence}" />
|
|
140014
|
+
`;
|
|
140015
|
+
if (reason) {
|
|
140016
|
+
gexf += ` <attvalue id="reason" value="${escapeXml2(reason)}" />
|
|
140017
|
+
`;
|
|
140018
|
+
}
|
|
140019
|
+
gexf += " </attvalues>\n";
|
|
140020
|
+
gexf += " </edge>\n";
|
|
140021
|
+
}
|
|
140022
|
+
gexf += " </edges>\n";
|
|
140023
|
+
gexf += " </graph>\n";
|
|
140024
|
+
gexf += "</gexf>\n";
|
|
140025
|
+
return gexf;
|
|
140026
|
+
}
|
|
140027
|
+
function escapeXml2(str) {
|
|
140028
|
+
return String(str).replace(/[<>"'&]/g, (c) => {
|
|
140029
|
+
const map2 = {
|
|
140030
|
+
"<": "<",
|
|
140031
|
+
">": ">",
|
|
140032
|
+
'"': """,
|
|
140033
|
+
"'": "'",
|
|
140034
|
+
"&": "&"
|
|
140035
|
+
};
|
|
140036
|
+
return map2[c];
|
|
140037
|
+
});
|
|
140038
|
+
}
|
|
140039
|
+
function hexToRgb(hex3) {
|
|
140040
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex3);
|
|
140041
|
+
return result ? {
|
|
140042
|
+
r: parseInt(result[1], 16),
|
|
140043
|
+
g: parseInt(result[2], 16),
|
|
140044
|
+
b: parseInt(result[3], 16)
|
|
140045
|
+
} : { r: 127, g: 140, b: 141 };
|
|
140046
|
+
}
|
|
139151
140047
|
function sortMatchingNodes(nodes, symbolName) {
|
|
139152
140048
|
const lowerSymbol = symbolName.toLowerCase();
|
|
139153
140049
|
return [...nodes].sort((a, b2) => {
|
|
@@ -140382,6 +141278,84 @@ function registerNexusCommand(program) {
|
|
|
140382
141278
|
process.exitCode = 1;
|
|
140383
141279
|
}
|
|
140384
141280
|
});
|
|
141281
|
+
nexus.command("export").description("Export nexus graph to GEXF (Gephi) or JSON format").option("--format <format>", "Output format: gexf, json", "gexf").option("--output <file>", "Output file path (stdout if omitted)").option("--project <id>", "Filter by project ID (exports all projects if omitted)").action(async (opts) => {
|
|
141282
|
+
const startTime = Date.now();
|
|
141283
|
+
const format = opts["format"] ?? "gexf";
|
|
141284
|
+
const outputFile = opts["output"];
|
|
141285
|
+
const projectFilter = opts["project"];
|
|
141286
|
+
try {
|
|
141287
|
+
const { getNexusDb: getNexusDb2, nexusSchema } = await import("@cleocode/core/store/nexus-sqlite");
|
|
141288
|
+
const db = await getNexusDb2();
|
|
141289
|
+
let allNodes = [];
|
|
141290
|
+
let allRelations = [];
|
|
141291
|
+
try {
|
|
141292
|
+
allNodes = db.select().from(nexusSchema.nexusNodes).all();
|
|
141293
|
+
allRelations = db.select().from(nexusSchema.nexusRelations).all();
|
|
141294
|
+
} catch {
|
|
141295
|
+
}
|
|
141296
|
+
const nodes = projectFilter ? allNodes.filter((n) => n["projectId"] === projectFilter) : allNodes;
|
|
141297
|
+
const relations = projectFilter ? allRelations.filter((r) => r["projectId"] === projectFilter) : allRelations;
|
|
141298
|
+
let output = "";
|
|
141299
|
+
if (format === "json") {
|
|
141300
|
+
output = JSON.stringify(
|
|
141301
|
+
{
|
|
141302
|
+
nodes: nodes.map((n) => ({
|
|
141303
|
+
id: n["id"],
|
|
141304
|
+
kind: n["kind"],
|
|
141305
|
+
label: n["label"],
|
|
141306
|
+
name: n["name"],
|
|
141307
|
+
filePath: n["filePath"],
|
|
141308
|
+
language: n["language"],
|
|
141309
|
+
isExported: n["isExported"],
|
|
141310
|
+
startLine: n["startLine"],
|
|
141311
|
+
endLine: n["endLine"],
|
|
141312
|
+
projectId: n["projectId"]
|
|
141313
|
+
})),
|
|
141314
|
+
edges: relations.map((r) => ({
|
|
141315
|
+
id: r["id"],
|
|
141316
|
+
source: r["sourceId"],
|
|
141317
|
+
target: r["targetId"],
|
|
141318
|
+
type: r["type"],
|
|
141319
|
+
confidence: r["confidence"],
|
|
141320
|
+
reason: r["reason"]
|
|
141321
|
+
}))
|
|
141322
|
+
},
|
|
141323
|
+
null,
|
|
141324
|
+
2
|
|
141325
|
+
);
|
|
141326
|
+
} else if (format === "gexf") {
|
|
141327
|
+
output = generateGexf(nodes, relations);
|
|
141328
|
+
} else {
|
|
141329
|
+
process.stderr.write(
|
|
141330
|
+
`[nexus] Error: Unknown format '${format}'. Supported: gexf, json
|
|
141331
|
+
`
|
|
141332
|
+
);
|
|
141333
|
+
process.exitCode = 1;
|
|
141334
|
+
return;
|
|
141335
|
+
}
|
|
141336
|
+
if (outputFile) {
|
|
141337
|
+
const { writeFileSync: writeFileSync26 } = await import("node:fs");
|
|
141338
|
+
writeFileSync26(outputFile, output, "utf-8");
|
|
141339
|
+
process.stdout.write(
|
|
141340
|
+
`[nexus] Exported to ${outputFile} (${nodes.length} nodes, ${relations.length} edges)
|
|
141341
|
+
`
|
|
141342
|
+
);
|
|
141343
|
+
} else {
|
|
141344
|
+
process.stdout.write(output);
|
|
141345
|
+
if (!output.endsWith("\n")) process.stdout.write("\n");
|
|
141346
|
+
}
|
|
141347
|
+
const durationMs = Date.now() - startTime;
|
|
141348
|
+
if (outputFile) {
|
|
141349
|
+
process.stderr.write(`[nexus] Export completed in ${durationMs}ms
|
|
141350
|
+
`);
|
|
141351
|
+
}
|
|
141352
|
+
} catch (err) {
|
|
141353
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
141354
|
+
process.stderr.write(`[nexus] Error: ${msg}
|
|
141355
|
+
`);
|
|
141356
|
+
process.exitCode = 1;
|
|
141357
|
+
}
|
|
141358
|
+
});
|
|
140385
141359
|
nexus.command("diff").description(
|
|
140386
141360
|
"Compare NEXUS index state between two git commits \u2014 shows new/removed relations and broken call chains"
|
|
140387
141361
|
).option("--before <sha>", 'Git SHA or ref for the "before" snapshot (default: HEAD~1)').option("--after <sha>", 'Git SHA or ref for the "after" snapshot (default: HEAD)', "HEAD").option("--path <dir>", "Repository directory to analyze (default: cwd)").option("--json", "Output result as JSON (LAFS envelope format)").option("--project-id <id>", "Override the project ID (default: auto-detected from path)").action(async (opts) => {
|