memorix 1.0.8 → 1.0.10
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/CHANGELOG.md +58 -4
- package/README.md +23 -21
- package/README.zh-CN.md +23 -8
- package/dist/cli/index.js +3894 -1191
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/app.js +934 -10
- package/dist/dashboard/static/index.html +24 -4
- package/dist/dashboard/static/style.css +663 -0
- package/dist/index.js +730 -37
- package/dist/index.js.map +1 -1
- package/dist/sdk.js +730 -37
- package/dist/sdk.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.js +2 -1
- package/dist/types.js.map +1 -1
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +28 -29
- package/docs/API_REFERENCE.md +19 -2
- package/docs/CONFIGURATION.md +80 -33
- package/docs/DEVELOPMENT.md +10 -10
- package/docs/README.md +2 -2
- package/docs/SETUP.md +147 -27
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -675,6 +675,13 @@ var init_persistence = __esm({
|
|
|
675
675
|
});
|
|
676
676
|
|
|
677
677
|
// src/store/graph-store.ts
|
|
678
|
+
var graph_store_exports = {};
|
|
679
|
+
__export(graph_store_exports, {
|
|
680
|
+
GraphSqliteStore: () => GraphSqliteStore,
|
|
681
|
+
getGraphStore: () => getGraphStore,
|
|
682
|
+
initGraphStore: () => initGraphStore,
|
|
683
|
+
resetGraphStore: () => resetGraphStore
|
|
684
|
+
});
|
|
678
685
|
import path6 from "path";
|
|
679
686
|
import fs5 from "fs";
|
|
680
687
|
function safeJsonParse(val, fallback) {
|
|
@@ -710,6 +717,16 @@ function getGraphStore() {
|
|
|
710
717
|
if (!_graphStore) throw new Error("[memorix] GraphStore not initialized \u2014 call initGraphStore() first");
|
|
711
718
|
return _graphStore;
|
|
712
719
|
}
|
|
720
|
+
function resetGraphStore() {
|
|
721
|
+
if (_graphStore) {
|
|
722
|
+
try {
|
|
723
|
+
_graphStore.close();
|
|
724
|
+
} catch {
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
_graphStore = null;
|
|
728
|
+
_graphDataDir = null;
|
|
729
|
+
}
|
|
713
730
|
var GraphSqliteStore, _graphStore, _graphDataDir;
|
|
714
731
|
var init_graph_store = __esm({
|
|
715
732
|
"src/store/graph-store.ts"() {
|
|
@@ -1041,7 +1058,8 @@ var init_types = __esm({
|
|
|
1041
1058
|
"why-it-exists": "[WHY]",
|
|
1042
1059
|
"decision": "[DECISION]",
|
|
1043
1060
|
"trade-off": "[TRADEOFF]",
|
|
1044
|
-
"reasoning": "[REASONING]"
|
|
1061
|
+
"reasoning": "[REASONING]",
|
|
1062
|
+
"probe": "[PROBE]"
|
|
1045
1063
|
};
|
|
1046
1064
|
TOPIC_KEY_FAMILIES = {
|
|
1047
1065
|
"architecture": ["architecture", "design", "adr", "structure", "pattern"],
|
|
@@ -1055,6 +1073,15 @@ var init_types = __esm({
|
|
|
1055
1073
|
});
|
|
1056
1074
|
|
|
1057
1075
|
// src/store/mini-skill-store.ts
|
|
1076
|
+
var mini_skill_store_exports = {};
|
|
1077
|
+
__export(mini_skill_store_exports, {
|
|
1078
|
+
MiniSkillGracefulDegrade: () => MiniSkillGracefulDegrade,
|
|
1079
|
+
MiniSkillSqliteStore: () => MiniSkillSqliteStore,
|
|
1080
|
+
getMiniSkillStore: () => getMiniSkillStore,
|
|
1081
|
+
initMiniSkillStore: () => initMiniSkillStore,
|
|
1082
|
+
isMiniSkillStoreInitialized: () => isMiniSkillStoreInitialized,
|
|
1083
|
+
resetMiniSkillStore: () => resetMiniSkillStore
|
|
1084
|
+
});
|
|
1058
1085
|
import path7 from "path";
|
|
1059
1086
|
import fs6 from "fs";
|
|
1060
1087
|
function skillToRow(skill) {
|
|
@@ -1108,6 +1135,10 @@ function getMiniSkillStore() {
|
|
|
1108
1135
|
}
|
|
1109
1136
|
return _store;
|
|
1110
1137
|
}
|
|
1138
|
+
function resetMiniSkillStore() {
|
|
1139
|
+
_store = null;
|
|
1140
|
+
_storeDataDir = null;
|
|
1141
|
+
}
|
|
1111
1142
|
async function initMiniSkillStore(dataDir) {
|
|
1112
1143
|
if (_store && _storeDataDir === dataDir) return _store;
|
|
1113
1144
|
_store = null;
|
|
@@ -1354,6 +1385,12 @@ async function promoteToMiniSkill(projectDir2, projectId, observations2, options
|
|
|
1354
1385
|
`Cannot promote: ${nonActive.length} observation(s) are not active. Blocked: ${nonActive.map((o) => `#${o.id} (${o.status ?? "unknown"})`).join(", ")}. Only active observations can be promoted to permanent knowledge.`
|
|
1355
1386
|
);
|
|
1356
1387
|
}
|
|
1388
|
+
const probes = observations2.filter((o) => o.type === "probe");
|
|
1389
|
+
if (probes.length > 0) {
|
|
1390
|
+
throw new Error(
|
|
1391
|
+
`Cannot promote probe observations \u2014 they are operational heartbeats, not durable knowledge. Blocked: ${probes.map((o) => `#${o.id} "${o.title.substring(0, 60)}"`).join(", ")}.`
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1357
1394
|
if (!options?.force) {
|
|
1358
1395
|
const commandLogs = observations2.filter((o) => COMMAND_LOG_TITLE.test(o.title));
|
|
1359
1396
|
if (commandLogs.length > 0) {
|
|
@@ -1570,6 +1607,7 @@ var init_mini_skills = __esm({
|
|
|
1570
1607
|
// src/config/yaml-loader.ts
|
|
1571
1608
|
var yaml_loader_exports = {};
|
|
1572
1609
|
__export(yaml_loader_exports, {
|
|
1610
|
+
clearProjectRoot: () => clearProjectRoot,
|
|
1573
1611
|
initProjectRoot: () => initProjectRoot,
|
|
1574
1612
|
loadYamlConfig: () => loadYamlConfig,
|
|
1575
1613
|
resetYamlConfigCache: () => resetYamlConfigCache
|
|
@@ -1581,6 +1619,9 @@ function initProjectRoot(root) {
|
|
|
1581
1619
|
globalProjectRoot = root;
|
|
1582
1620
|
configCache.delete(root);
|
|
1583
1621
|
}
|
|
1622
|
+
function clearProjectRoot() {
|
|
1623
|
+
globalProjectRoot = null;
|
|
1624
|
+
}
|
|
1584
1625
|
function loadYamlConfig(projectRoot) {
|
|
1585
1626
|
const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
|
|
1586
1627
|
const cached2 = configCache.get(resolvedRoot ?? null);
|
|
@@ -1608,6 +1649,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
1608
1649
|
...projectConfig,
|
|
1609
1650
|
// Deep merge for nested objects where both exist
|
|
1610
1651
|
llm: { ...userConfig.llm, ...projectConfig.llm },
|
|
1652
|
+
agent: { ...userConfig.agent, ...projectConfig.agent },
|
|
1611
1653
|
embedding: { ...userConfig.embedding, ...projectConfig.embedding },
|
|
1612
1654
|
git: { ...userConfig.git, ...projectConfig.git },
|
|
1613
1655
|
behavior: { ...userConfig.behavior, ...projectConfig.behavior },
|
|
@@ -1710,6 +1752,10 @@ var init_dotenv_loader = __esm({
|
|
|
1710
1752
|
// src/config.ts
|
|
1711
1753
|
var config_exports = {};
|
|
1712
1754
|
__export(config_exports, {
|
|
1755
|
+
getAgentLLMApiKey: () => getAgentLLMApiKey,
|
|
1756
|
+
getAgentLLMBaseUrl: () => getAgentLLMBaseUrl,
|
|
1757
|
+
getAgentLLMModel: () => getAgentLLMModel,
|
|
1758
|
+
getAgentLLMProvider: () => getAgentLLMProvider,
|
|
1713
1759
|
getEmbeddingApiKey: () => getEmbeddingApiKey,
|
|
1714
1760
|
getEmbeddingBaseUrl: () => getEmbeddingBaseUrl,
|
|
1715
1761
|
getEmbeddingDimensions: () => getEmbeddingDimensions,
|
|
@@ -1769,6 +1815,23 @@ function getLLMModel(providerDefault) {
|
|
|
1769
1815
|
function getLLMBaseUrl(providerDefault) {
|
|
1770
1816
|
return process.env.MEMORIX_LLM_BASE_URL || loadYamlConfig().llm?.baseUrl || loadFileConfig().llm?.baseUrl || providerDefault;
|
|
1771
1817
|
}
|
|
1818
|
+
function getAgentLLMApiKey() {
|
|
1819
|
+
return process.env.MEMORIX_AGENT_LLM_API_KEY || loadYamlConfig().agent?.apiKey || loadFileConfig().agent?.apiKey || getLLMApiKey();
|
|
1820
|
+
}
|
|
1821
|
+
function getAgentLLMProvider() {
|
|
1822
|
+
if (process.env.MEMORIX_AGENT_LLM_PROVIDER) return process.env.MEMORIX_AGENT_LLM_PROVIDER;
|
|
1823
|
+
const yml = loadYamlConfig();
|
|
1824
|
+
if (yml.agent?.provider) return yml.agent.provider;
|
|
1825
|
+
const cfg = loadFileConfig();
|
|
1826
|
+
if (cfg.agent?.provider) return cfg.agent.provider;
|
|
1827
|
+
return getLLMProvider();
|
|
1828
|
+
}
|
|
1829
|
+
function getAgentLLMModel(providerDefault) {
|
|
1830
|
+
return process.env.MEMORIX_AGENT_LLM_MODEL || loadYamlConfig().agent?.model || loadFileConfig().agent?.model || getLLMModel(providerDefault);
|
|
1831
|
+
}
|
|
1832
|
+
function getAgentLLMBaseUrl(providerDefault) {
|
|
1833
|
+
return process.env.MEMORIX_AGENT_LLM_BASE_URL || loadYamlConfig().agent?.baseUrl || loadFileConfig().agent?.baseUrl || getLLMBaseUrl(providerDefault);
|
|
1834
|
+
}
|
|
1772
1835
|
function getEmbeddingMode() {
|
|
1773
1836
|
const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();
|
|
1774
1837
|
if (env === "fastembed" || env === "transformers" || env === "api" || env === "auto") return env;
|
|
@@ -3058,20 +3121,20 @@ async function* callLLMWithToolsStream(messages, tools) {
|
|
|
3058
3121
|
}
|
|
3059
3122
|
yield* callOpenAIWithToolsStream(messages, tools);
|
|
3060
3123
|
}
|
|
3061
|
-
function initLLM() {
|
|
3062
|
-
const
|
|
3063
|
-
const apiKey =
|
|
3124
|
+
function initLLM(options = {}) {
|
|
3125
|
+
const scope = options.scope ?? "memory";
|
|
3126
|
+
const apiKey = scope === "agent" ? getAgentLLMApiKey() : getLLMApiKey();
|
|
3064
3127
|
if (!apiKey) {
|
|
3065
3128
|
currentConfig = null;
|
|
3066
3129
|
return null;
|
|
3067
3130
|
}
|
|
3068
|
-
const provider2 =
|
|
3131
|
+
const provider2 = scope === "agent" ? getAgentLLMProvider() : getLLMProvider();
|
|
3069
3132
|
const defaults = PROVIDER_DEFAULTS[provider2] ?? PROVIDER_DEFAULTS.openai;
|
|
3070
3133
|
currentConfig = {
|
|
3071
3134
|
provider: provider2,
|
|
3072
3135
|
apiKey,
|
|
3073
|
-
model:
|
|
3074
|
-
baseUrl:
|
|
3136
|
+
model: scope === "agent" ? getAgentLLMModel(defaults.model) : getLLMModel(defaults.model),
|
|
3137
|
+
baseUrl: scope === "agent" ? getAgentLLMBaseUrl(defaults.baseUrl) : getLLMBaseUrl(defaults.baseUrl)
|
|
3075
3138
|
};
|
|
3076
3139
|
return currentConfig;
|
|
3077
3140
|
}
|
|
@@ -3578,6 +3641,7 @@ var init_provider2 = __esm({
|
|
|
3578
3641
|
"src/llm/provider.ts"() {
|
|
3579
3642
|
"use strict";
|
|
3580
3643
|
init_esm_shims();
|
|
3644
|
+
init_config();
|
|
3581
3645
|
LLM_TIMEOUT_DEFAULT_MS = 3e4;
|
|
3582
3646
|
LLM_TIMEOUT_MIN_MS = 1e3;
|
|
3583
3647
|
LLM_TIMEOUT_MAX_MS = 3e5;
|
|
@@ -4407,6 +4471,10 @@ async function searchObservations(options) {
|
|
|
4407
4471
|
if (statusFilter === "all") return true;
|
|
4408
4472
|
const doc = hit.document;
|
|
4409
4473
|
return (doc.status || "active") === statusFilter;
|
|
4474
|
+
}).filter((hit) => {
|
|
4475
|
+
if (options.type === "probe") return true;
|
|
4476
|
+
const doc = hit.document;
|
|
4477
|
+
return doc.type !== "probe";
|
|
4410
4478
|
}).map((hit) => {
|
|
4411
4479
|
const doc = hit.document;
|
|
4412
4480
|
const obsType = doc.type;
|
|
@@ -6788,6 +6856,11 @@ function hasContradiction(oldText, newText) {
|
|
|
6788
6856
|
];
|
|
6789
6857
|
return negationPatterns.some((p) => p.test(newText));
|
|
6790
6858
|
}
|
|
6859
|
+
function normalizedSearchSimilarity(score) {
|
|
6860
|
+
if (!Number.isFinite(score) || score <= 0) return 0;
|
|
6861
|
+
if (score <= 1) return score;
|
|
6862
|
+
return 0;
|
|
6863
|
+
}
|
|
6791
6864
|
function mergeNarratives(oldNarrative, newNarrative) {
|
|
6792
6865
|
if (newNarrative.length > oldNarrative.length * 1.5) return newNarrative;
|
|
6793
6866
|
if (oldNarrative.length > newNarrative.length * 1.5) return oldNarrative;
|
|
@@ -6878,12 +6951,13 @@ function scoreCandidate(extracted, candidate) {
|
|
|
6878
6951
|
`${extracted.title} ${extracted.narrative}`,
|
|
6879
6952
|
`${candidate.title} ${candidate.narrative}`
|
|
6880
6953
|
);
|
|
6881
|
-
const
|
|
6954
|
+
const searchSimilarity = normalizedSearchSimilarity(candidate.score);
|
|
6955
|
+
const score = searchSimilarity * 0.6 + (entityMatch ? 0.2 : 0) + contentOverlap * 0.2;
|
|
6882
6956
|
const newLength = extracted.narrative.length + extracted.facts.join(" ").length;
|
|
6883
6957
|
const oldLength = candidate.narrative.length + candidate.facts.length;
|
|
6884
6958
|
const richer = newLength > oldLength * 1.15;
|
|
6885
6959
|
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
6886
|
-
return { score, entityMatch, richer, contradiction };
|
|
6960
|
+
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
6887
6961
|
}
|
|
6888
6962
|
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false) {
|
|
6889
6963
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
@@ -6906,7 +6980,7 @@ async function runResolve(extracted, projectId, searchMemories, getObservation2,
|
|
|
6906
6980
|
}));
|
|
6907
6981
|
scored.sort((a, b) => b.score - a.score);
|
|
6908
6982
|
const best = scored[0];
|
|
6909
|
-
if (best.
|
|
6983
|
+
if (best.searchSimilarity >= SIMILARITY_DUPLICATE) {
|
|
6910
6984
|
if (best.richer) {
|
|
6911
6985
|
const existing = getObservation2(best.hit.observationId);
|
|
6912
6986
|
const oldFacts = existing?.facts ?? best.hit.facts.split("\n").filter(Boolean);
|
|
@@ -7093,7 +7167,8 @@ var init_evaluate = __esm({
|
|
|
7093
7167
|
"how-it-works": 0.6,
|
|
7094
7168
|
"discovery": 0.55,
|
|
7095
7169
|
"what-changed": 0.45,
|
|
7096
|
-
"session-request": 0.4
|
|
7170
|
+
"session-request": 0.4,
|
|
7171
|
+
"probe": 0.1
|
|
7097
7172
|
};
|
|
7098
7173
|
SPECIFICITY_PATTERNS = [
|
|
7099
7174
|
/\b\d+\.\d+\.\d+\b/,
|
|
@@ -7557,6 +7632,9 @@ function scoreObservationForSessionContext(obs, projectTokens, now = Date.now())
|
|
|
7557
7632
|
if (obs.valueCategory === "core") {
|
|
7558
7633
|
score += 2;
|
|
7559
7634
|
}
|
|
7635
|
+
if (obs.type === "probe") {
|
|
7636
|
+
score -= 100;
|
|
7637
|
+
}
|
|
7560
7638
|
return score;
|
|
7561
7639
|
}
|
|
7562
7640
|
async function startSession(projectDir2, projectId, opts) {
|
|
@@ -7765,7 +7843,8 @@ var init_session = __esm({
|
|
|
7765
7843
|
"how-it-works": "[INFO]",
|
|
7766
7844
|
"what-changed": "[CHANGE]",
|
|
7767
7845
|
"why-it-exists": "[DECISION]",
|
|
7768
|
-
"session-request": "[SESSION]"
|
|
7846
|
+
"session-request": "[SESSION]",
|
|
7847
|
+
"probe": "[PROBE]"
|
|
7769
7848
|
};
|
|
7770
7849
|
TYPE_WEIGHTS2 = {
|
|
7771
7850
|
"gotcha": 6,
|
|
@@ -7844,11 +7923,17 @@ function getValueCategoryMultiplier(doc) {
|
|
|
7844
7923
|
return 1;
|
|
7845
7924
|
}
|
|
7846
7925
|
function getEffectiveRetentionDays(doc) {
|
|
7926
|
+
const typeOverride = TYPE_RETENTION_OVERRIDE[doc.type];
|
|
7927
|
+
if (typeOverride !== void 0) {
|
|
7928
|
+
const raw2 = typeOverride * getSourceRetentionMultiplier(doc);
|
|
7929
|
+
return Math.max(MIN_RETENTION_DAYS, raw2);
|
|
7930
|
+
}
|
|
7847
7931
|
const importance = getImportanceLevel(doc);
|
|
7848
7932
|
const raw = RETENTION_DAYS[importance] * getSourceRetentionMultiplier(doc) * getValueCategoryMultiplier(doc);
|
|
7849
7933
|
return Math.max(MIN_RETENTION_DAYS, raw);
|
|
7850
7934
|
}
|
|
7851
7935
|
function isImmune(doc) {
|
|
7936
|
+
if (doc.type === "probe") return false;
|
|
7852
7937
|
if (doc.valueCategory === "core") return true;
|
|
7853
7938
|
const importance = getImportanceLevel(doc);
|
|
7854
7939
|
if (importance === "critical") return true;
|
|
@@ -7857,6 +7942,7 @@ function isImmune(doc) {
|
|
|
7857
7942
|
return concepts.some((c) => PROTECTED_TAGS.has(c));
|
|
7858
7943
|
}
|
|
7859
7944
|
function getImmunityReason(doc) {
|
|
7945
|
+
if (doc.type === "probe") return null;
|
|
7860
7946
|
if (doc.valueCategory === "core") return "core valueCategory (formation-classified)";
|
|
7861
7947
|
const importance = getImportanceLevel(doc);
|
|
7862
7948
|
if (importance === "critical") return "critical importance";
|
|
@@ -8013,7 +8099,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap) {
|
|
|
8013
8099
|
return { archived: archivedCount, remaining: activeObs.length - archivedCount };
|
|
8014
8100
|
});
|
|
8015
8101
|
}
|
|
8016
|
-
var RETENTION_DAYS, BASE_IMPORTANCE, TYPE_IMPORTANCE, PROTECTED_TAGS, MIN_ACCESS_FOR_IMMUNITY, MIN_RETENTION_DAYS;
|
|
8102
|
+
var RETENTION_DAYS, BASE_IMPORTANCE, TYPE_IMPORTANCE, TYPE_RETENTION_OVERRIDE, PROTECTED_TAGS, MIN_ACCESS_FOR_IMMUNITY, MIN_RETENTION_DAYS;
|
|
8017
8103
|
var init_retention = __esm({
|
|
8018
8104
|
"src/memory/retention.ts"() {
|
|
8019
8105
|
"use strict";
|
|
@@ -8041,7 +8127,12 @@ var init_retention = __esm({
|
|
|
8041
8127
|
"what-changed": "low",
|
|
8042
8128
|
"why-it-exists": "medium",
|
|
8043
8129
|
discovery: "low",
|
|
8044
|
-
"session-request": "low"
|
|
8130
|
+
"session-request": "low",
|
|
8131
|
+
probe: "low"
|
|
8132
|
+
};
|
|
8133
|
+
TYPE_RETENTION_OVERRIDE = {
|
|
8134
|
+
probe: 7
|
|
8135
|
+
// Operational heartbeats: expire after ~7 days regardless of source/valueCategory
|
|
8045
8136
|
};
|
|
8046
8137
|
PROTECTED_TAGS = /* @__PURE__ */ new Set(["keep", "important", "pinned", "critical"]);
|
|
8047
8138
|
MIN_ACCESS_FOR_IMMUNITY = 3;
|
|
@@ -9769,9 +9860,453 @@ var init_project_classification = __esm({
|
|
|
9769
9860
|
}
|
|
9770
9861
|
});
|
|
9771
9862
|
|
|
9863
|
+
// src/wiki/generator.ts
|
|
9864
|
+
var generator_exports = {};
|
|
9865
|
+
__export(generator_exports, {
|
|
9866
|
+
contextualHasSubstance: () => contextualHasSubstance,
|
|
9867
|
+
generateKnowledgeBase: () => generateKnowledgeBase,
|
|
9868
|
+
isCommandLog: () => isCommandLog,
|
|
9869
|
+
isEligible: () => isEligible,
|
|
9870
|
+
isExcludedType: () => isExcludedType
|
|
9871
|
+
});
|
|
9872
|
+
function isExcludedType(o) {
|
|
9873
|
+
return o.type === "probe";
|
|
9874
|
+
}
|
|
9875
|
+
function isCommandLog(o) {
|
|
9876
|
+
return COMMAND_LOG_TITLE3.test(o.title || "");
|
|
9877
|
+
}
|
|
9878
|
+
function isInactive(o) {
|
|
9879
|
+
const status = o.status ?? "active";
|
|
9880
|
+
return status !== "active";
|
|
9881
|
+
}
|
|
9882
|
+
function isOtherProject(o, projectId) {
|
|
9883
|
+
return o.projectId !== projectId;
|
|
9884
|
+
}
|
|
9885
|
+
function contextualHasSubstance(o) {
|
|
9886
|
+
if (o.valueCategory !== "contextual") return true;
|
|
9887
|
+
const hasFacts = (o.facts?.length ?? 0) > 0;
|
|
9888
|
+
const hasConcepts = (o.concepts?.length ?? 0) > 0;
|
|
9889
|
+
const hasFiles = (o.filesModified?.length ?? 0) > 0;
|
|
9890
|
+
const hasEntity = !!(o.entityName && o.entityName !== "quick-note" && o.entityName !== "unknown");
|
|
9891
|
+
return hasFacts || hasConcepts || hasFiles || hasEntity;
|
|
9892
|
+
}
|
|
9893
|
+
function isEligible(o, projectId) {
|
|
9894
|
+
if (isExcludedType(o)) return false;
|
|
9895
|
+
if (isCommandLog(o)) return false;
|
|
9896
|
+
if (isInactive(o)) return false;
|
|
9897
|
+
if (isOtherProject(o, projectId)) return false;
|
|
9898
|
+
if (o.valueCategory === "ephemeral") return false;
|
|
9899
|
+
if (!contextualHasSubstance(o)) return false;
|
|
9900
|
+
return true;
|
|
9901
|
+
}
|
|
9902
|
+
function obsToItem(o) {
|
|
9903
|
+
const ref = {
|
|
9904
|
+
kind: o.source === "git" ? "git" : "observation",
|
|
9905
|
+
id: `obs:${o.id}`,
|
|
9906
|
+
title: o.title
|
|
9907
|
+
};
|
|
9908
|
+
return {
|
|
9909
|
+
title: o.title,
|
|
9910
|
+
summary: o.narrative?.slice(0, 200) || "",
|
|
9911
|
+
type: o.type,
|
|
9912
|
+
entityName: o.entityName || void 0,
|
|
9913
|
+
refs: [ref]
|
|
9914
|
+
};
|
|
9915
|
+
}
|
|
9916
|
+
function skillToItem(s) {
|
|
9917
|
+
const ref = {
|
|
9918
|
+
kind: "mini-skill",
|
|
9919
|
+
id: `skill:${s.id}`,
|
|
9920
|
+
title: s.title
|
|
9921
|
+
};
|
|
9922
|
+
const obsRefs = s.sourceObservationIds.map(
|
|
9923
|
+
(oid) => ({ kind: "observation", id: `obs:${oid}` })
|
|
9924
|
+
);
|
|
9925
|
+
return {
|
|
9926
|
+
title: s.title,
|
|
9927
|
+
summary: s.instruction?.slice(0, 200) || "",
|
|
9928
|
+
type: "mini-skill",
|
|
9929
|
+
entityName: s.sourceEntity || void 0,
|
|
9930
|
+
refs: [ref, ...obsRefs]
|
|
9931
|
+
};
|
|
9932
|
+
}
|
|
9933
|
+
function buildGitSection(observations2) {
|
|
9934
|
+
const gitObs = observations2.filter(
|
|
9935
|
+
(o) => o.source === "git" && o.sourceDetail === "git-ingest"
|
|
9936
|
+
);
|
|
9937
|
+
const items = gitObs.map(obsToItem);
|
|
9938
|
+
return {
|
|
9939
|
+
id: "git-backed-facts",
|
|
9940
|
+
title: "Git-backed Facts",
|
|
9941
|
+
items,
|
|
9942
|
+
empty: items.length === 0
|
|
9943
|
+
};
|
|
9944
|
+
}
|
|
9945
|
+
function buildSkillsSection(skills) {
|
|
9946
|
+
const items = skills.map(skillToItem);
|
|
9947
|
+
return {
|
|
9948
|
+
id: "promoted-skills",
|
|
9949
|
+
title: "Promoted Skills",
|
|
9950
|
+
items,
|
|
9951
|
+
empty: items.length === 0
|
|
9952
|
+
};
|
|
9953
|
+
}
|
|
9954
|
+
function buildProjectOverview(projectId, eligibleObs, skills) {
|
|
9955
|
+
const refs = [
|
|
9956
|
+
...eligibleObs.slice(0, 5).map((o) => ({
|
|
9957
|
+
kind: o.source === "git" ? "git" : "observation",
|
|
9958
|
+
id: `obs:${o.id}`,
|
|
9959
|
+
title: o.title
|
|
9960
|
+
})),
|
|
9961
|
+
...skills.slice(0, 5).map((s) => ({
|
|
9962
|
+
kind: "mini-skill",
|
|
9963
|
+
id: `skill:${s.id}`,
|
|
9964
|
+
title: s.title
|
|
9965
|
+
}))
|
|
9966
|
+
];
|
|
9967
|
+
if (refs.length === 0) {
|
|
9968
|
+
return {
|
|
9969
|
+
id: "project-overview",
|
|
9970
|
+
title: "Project Overview",
|
|
9971
|
+
items: [],
|
|
9972
|
+
empty: true
|
|
9973
|
+
};
|
|
9974
|
+
}
|
|
9975
|
+
const lines = [];
|
|
9976
|
+
lines.push(`Project: ${projectId}`);
|
|
9977
|
+
lines.push(`Observations in KB: ${eligibleObs.length}`);
|
|
9978
|
+
lines.push(`Promoted skills: ${skills.length}`);
|
|
9979
|
+
const entityCounts = /* @__PURE__ */ new Map();
|
|
9980
|
+
for (const o of eligibleObs) {
|
|
9981
|
+
if (o.entityName) {
|
|
9982
|
+
entityCounts.set(o.entityName, (entityCounts.get(o.entityName) || 0) + 1);
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
const topEntities = [...entityCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
9986
|
+
if (topEntities.length > 0) {
|
|
9987
|
+
lines.push(`Top entities: ${topEntities.map(([name, count2]) => `${name} (${count2})`).join(", ")}`);
|
|
9988
|
+
}
|
|
9989
|
+
return {
|
|
9990
|
+
id: "project-overview",
|
|
9991
|
+
title: "Project Overview",
|
|
9992
|
+
items: [{
|
|
9993
|
+
title: projectId,
|
|
9994
|
+
summary: lines.join("\n"),
|
|
9995
|
+
type: "overview",
|
|
9996
|
+
refs
|
|
9997
|
+
}]
|
|
9998
|
+
};
|
|
9999
|
+
}
|
|
10000
|
+
function generateKnowledgeBase(options) {
|
|
10001
|
+
const { projectId, observations: observations2, miniSkills } = options;
|
|
10002
|
+
const eligible = observations2.filter((o) => isEligible(o, projectId));
|
|
10003
|
+
const scopedMiniSkills = miniSkills.filter((s) => s.projectId === projectId);
|
|
10004
|
+
const typedSections = SECTION_DEFS.map((def) => {
|
|
10005
|
+
const matched = eligible.filter(def.typeMatch);
|
|
10006
|
+
const items = matched.map(obsToItem);
|
|
10007
|
+
return {
|
|
10008
|
+
id: def.id,
|
|
10009
|
+
title: def.title,
|
|
10010
|
+
items,
|
|
10011
|
+
empty: items.length === 0
|
|
10012
|
+
};
|
|
10013
|
+
});
|
|
10014
|
+
const projectOverview = buildProjectOverview(projectId, eligible, scopedMiniSkills);
|
|
10015
|
+
const gitSection = buildGitSection(eligible);
|
|
10016
|
+
const skillsSection = buildSkillsSection(scopedMiniSkills);
|
|
10017
|
+
const sections = [
|
|
10018
|
+
projectOverview,
|
|
10019
|
+
...typedSections,
|
|
10020
|
+
gitSection,
|
|
10021
|
+
skillsSection
|
|
10022
|
+
];
|
|
10023
|
+
const allRefs = sections.flatMap((s) => s.items.flatMap((i) => i.refs));
|
|
10024
|
+
const obsRefCount = allRefs.filter((r) => r.kind === "observation" || r.kind === "git").length;
|
|
10025
|
+
const skillRefCount = allRefs.filter((r) => r.kind === "mini-skill").length;
|
|
10026
|
+
return {
|
|
10027
|
+
title: "Knowledge Base",
|
|
10028
|
+
subtitle: "LLM Wiki",
|
|
10029
|
+
projectId,
|
|
10030
|
+
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
10031
|
+
sections,
|
|
10032
|
+
stats: {
|
|
10033
|
+
observationsUsed: eligible.length,
|
|
10034
|
+
miniSkillsUsed: scopedMiniSkills.length,
|
|
10035
|
+
refs: obsRefCount + skillRefCount
|
|
10036
|
+
}
|
|
10037
|
+
};
|
|
10038
|
+
}
|
|
10039
|
+
var COMMAND_LOG_TITLE3, SECTION_DEFS;
|
|
10040
|
+
var init_generator = __esm({
|
|
10041
|
+
"src/wiki/generator.ts"() {
|
|
10042
|
+
"use strict";
|
|
10043
|
+
init_esm_shims();
|
|
10044
|
+
COMMAND_LOG_TITLE3 = /^(Ran:|Command:|Executed:)\s/i;
|
|
10045
|
+
SECTION_DEFS = [
|
|
10046
|
+
{
|
|
10047
|
+
id: "core-decisions",
|
|
10048
|
+
title: "Core Decisions",
|
|
10049
|
+
typeMatch: (o) => o.type === "decision" || o.type === "trade-off" || o.type === "reasoning"
|
|
10050
|
+
},
|
|
10051
|
+
{
|
|
10052
|
+
id: "operational-knowledge",
|
|
10053
|
+
title: "Operational Knowledge",
|
|
10054
|
+
typeMatch: (o) => o.type === "how-it-works" || o.type === "what-changed" || o.type === "why-it-exists" || o.type === "discovery" || o.type === "session-request"
|
|
10055
|
+
},
|
|
10056
|
+
{
|
|
10057
|
+
id: "known-gotchas",
|
|
10058
|
+
title: "Known Gotchas",
|
|
10059
|
+
typeMatch: (o) => o.type === "gotcha" || o.type === "problem-solution"
|
|
10060
|
+
}
|
|
10061
|
+
];
|
|
10062
|
+
}
|
|
10063
|
+
});
|
|
10064
|
+
|
|
10065
|
+
// src/wiki/knowledge-graph.ts
|
|
10066
|
+
var knowledge_graph_exports = {};
|
|
10067
|
+
__export(knowledge_graph_exports, {
|
|
10068
|
+
generateKnowledgeGraph: () => generateKnowledgeGraph
|
|
10069
|
+
});
|
|
10070
|
+
function inferEdges(nodes, entityNameIndex) {
|
|
10071
|
+
const edges = [];
|
|
10072
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10073
|
+
const maxRelatesEdgesPerEntitySection = 8;
|
|
10074
|
+
function addEdge(source, target, edgeType) {
|
|
10075
|
+
const key = `${source}:${edgeType}:${target}`;
|
|
10076
|
+
if (seen.has(key)) return;
|
|
10077
|
+
if (source === target) return;
|
|
10078
|
+
seen.add(key);
|
|
10079
|
+
edges.push({
|
|
10080
|
+
id: `e_${edges.length}_${source}_${target}`,
|
|
10081
|
+
source,
|
|
10082
|
+
target,
|
|
10083
|
+
edgeType
|
|
10084
|
+
});
|
|
10085
|
+
}
|
|
10086
|
+
function rankNodesForEntity(a, b) {
|
|
10087
|
+
const evidenceDiff = (b.evidenceCount || 0) - (a.evidenceCount || 0);
|
|
10088
|
+
if (evidenceDiff !== 0) return evidenceDiff;
|
|
10089
|
+
return a.id.localeCompare(b.id);
|
|
10090
|
+
}
|
|
10091
|
+
for (const [, group] of entityNameIndex) {
|
|
10092
|
+
if (group.length < 2) continue;
|
|
10093
|
+
const bySection = /* @__PURE__ */ new Map();
|
|
10094
|
+
for (const node of group) {
|
|
10095
|
+
const sectionGroup = bySection.get(node.sectionId) || [];
|
|
10096
|
+
sectionGroup.push(node);
|
|
10097
|
+
bySection.set(node.sectionId, sectionGroup);
|
|
10098
|
+
}
|
|
10099
|
+
for (const sectionGroup of bySection.values()) {
|
|
10100
|
+
const ranked = [...sectionGroup].sort(rankNodesForEntity);
|
|
10101
|
+
if (ranked.length === 2) {
|
|
10102
|
+
addEdge(ranked[0].id, ranked[1].id, "relates_to");
|
|
10103
|
+
addEdge(ranked[1].id, ranked[0].id, "relates_to");
|
|
10104
|
+
continue;
|
|
10105
|
+
}
|
|
10106
|
+
const anchor = ranked[0];
|
|
10107
|
+
for (const node of ranked.slice(1, maxRelatesEdgesPerEntitySection + 1)) {
|
|
10108
|
+
addEdge(anchor.id, node.id, "relates_to");
|
|
10109
|
+
}
|
|
10110
|
+
}
|
|
10111
|
+
const sectionAnchors = [...bySection.entries()].map(([sectionId, sectionGroup]) => ({
|
|
10112
|
+
sectionId,
|
|
10113
|
+
anchor: [...sectionGroup].sort(rankNodesForEntity)[0]
|
|
10114
|
+
})).sort((a, b) => sectionPriority(a.sectionId) - sectionPriority(b.sectionId));
|
|
10115
|
+
for (let i = 0; i < sectionAnchors.length; i++) {
|
|
10116
|
+
for (let j = i + 1; j < sectionAnchors.length; j++) {
|
|
10117
|
+
const from = sectionAnchors[i].anchor;
|
|
10118
|
+
const to = sectionAnchors[j].anchor;
|
|
10119
|
+
const edgeType = sectionPriority(sectionAnchors[i].sectionId) === sectionPriority(sectionAnchors[j].sectionId) ? "relates_to" : "supports";
|
|
10120
|
+
addEdge(from.id, to.id, edgeType);
|
|
10121
|
+
}
|
|
10122
|
+
}
|
|
10123
|
+
}
|
|
10124
|
+
return edges;
|
|
10125
|
+
}
|
|
10126
|
+
function sectionPriority(sectionId) {
|
|
10127
|
+
const order = ["core-decisions", "known-gotchas", "operational-knowledge", "git-backed-facts", "promoted-skills"];
|
|
10128
|
+
const idx = order.indexOf(sectionId);
|
|
10129
|
+
return idx >= 0 ? idx : order.length;
|
|
10130
|
+
}
|
|
10131
|
+
function sectionIdForObs(o) {
|
|
10132
|
+
if (GIT_SECTION.typeMatch(o)) return GIT_SECTION.id;
|
|
10133
|
+
for (const def of SECTION_DEFS2) {
|
|
10134
|
+
if (def.typeMatch(o)) return def.id;
|
|
10135
|
+
}
|
|
10136
|
+
return "operational-knowledge";
|
|
10137
|
+
}
|
|
10138
|
+
function mapRelationType(relationType) {
|
|
10139
|
+
const lower = relationType.toLowerCase();
|
|
10140
|
+
if (lower.includes("support") || lower.includes("depend")) return "supports";
|
|
10141
|
+
if (lower.includes("relat") || lower.includes("connect") || lower.includes("associat")) return "relates_to";
|
|
10142
|
+
if (lower.includes("mention") || lower.includes("refer")) return "mentions";
|
|
10143
|
+
if (lower.includes("deriv") || lower.includes("origin") || lower.includes("source")) return "derived_from";
|
|
10144
|
+
return "relates_to";
|
|
10145
|
+
}
|
|
10146
|
+
function generateKnowledgeGraph(options) {
|
|
10147
|
+
const { projectId, observations: observations2, miniSkills, graphEntities, graphRelations } = options;
|
|
10148
|
+
const eligible = observations2.filter((o) => isEligible(o, projectId));
|
|
10149
|
+
const scopedMiniSkills = miniSkills.filter((s) => s.projectId === projectId);
|
|
10150
|
+
const nodes = [];
|
|
10151
|
+
const entityNameIndex = /* @__PURE__ */ new Map();
|
|
10152
|
+
for (const o of eligible) {
|
|
10153
|
+
const sectionId = sectionIdForObs(o);
|
|
10154
|
+
const ref = {
|
|
10155
|
+
kind: o.source === "git" ? "git" : "observation",
|
|
10156
|
+
id: `obs:${o.id}`,
|
|
10157
|
+
title: o.title
|
|
10158
|
+
};
|
|
10159
|
+
const node = {
|
|
10160
|
+
id: `obs:${o.id}`,
|
|
10161
|
+
label: o.title,
|
|
10162
|
+
nodeType: o.type,
|
|
10163
|
+
sectionId,
|
|
10164
|
+
entityName: o.entityName || void 0,
|
|
10165
|
+
evidenceCount: (o.facts?.length ?? 0) + (o.concepts?.length ?? 0) + (o.filesModified?.length ?? 0),
|
|
10166
|
+
summary: o.narrative?.slice(0, 200) || "",
|
|
10167
|
+
refs: [ref]
|
|
10168
|
+
};
|
|
10169
|
+
nodes.push(node);
|
|
10170
|
+
if (o.entityName) {
|
|
10171
|
+
const group = entityNameIndex.get(o.entityName) || [];
|
|
10172
|
+
group.push(node);
|
|
10173
|
+
entityNameIndex.set(o.entityName, group);
|
|
10174
|
+
}
|
|
10175
|
+
}
|
|
10176
|
+
for (const s of scopedMiniSkills) {
|
|
10177
|
+
const ref = {
|
|
10178
|
+
kind: "mini-skill",
|
|
10179
|
+
id: `skill:${s.id}`,
|
|
10180
|
+
title: s.title
|
|
10181
|
+
};
|
|
10182
|
+
const obsRefs = s.sourceObservationIds.map(
|
|
10183
|
+
(oid) => ({ kind: "observation", id: `obs:${oid}` })
|
|
10184
|
+
);
|
|
10185
|
+
const node = {
|
|
10186
|
+
id: `skill:${s.id}`,
|
|
10187
|
+
label: s.title,
|
|
10188
|
+
nodeType: "mini-skill",
|
|
10189
|
+
sectionId: "promoted-skills",
|
|
10190
|
+
entityName: s.sourceEntity || void 0,
|
|
10191
|
+
evidenceCount: obsRefs.length,
|
|
10192
|
+
summary: s.instruction?.slice(0, 200) || "",
|
|
10193
|
+
refs: [ref, ...obsRefs]
|
|
10194
|
+
};
|
|
10195
|
+
nodes.push(node);
|
|
10196
|
+
if (s.sourceEntity) {
|
|
10197
|
+
const group = entityNameIndex.get(s.sourceEntity) || [];
|
|
10198
|
+
group.push(node);
|
|
10199
|
+
entityNameIndex.set(s.sourceEntity, group);
|
|
10200
|
+
}
|
|
10201
|
+
}
|
|
10202
|
+
const edges = inferEdges(nodes, entityNameIndex);
|
|
10203
|
+
for (const s of scopedMiniSkills) {
|
|
10204
|
+
const skillNodeId = `skill:${s.id}`;
|
|
10205
|
+
for (const oid of s.sourceObservationIds) {
|
|
10206
|
+
const obsNodeId = `obs:${oid}`;
|
|
10207
|
+
if (nodes.some((n) => n.id === obsNodeId)) {
|
|
10208
|
+
edges.push({
|
|
10209
|
+
id: `e_${edges.length}_${skillNodeId}_${obsNodeId}`,
|
|
10210
|
+
source: skillNodeId,
|
|
10211
|
+
target: obsNodeId,
|
|
10212
|
+
edgeType: "derived_from"
|
|
10213
|
+
});
|
|
10214
|
+
}
|
|
10215
|
+
}
|
|
10216
|
+
}
|
|
10217
|
+
if (graphRelations && graphRelations.length > 0) {
|
|
10218
|
+
const entityNodeMap = /* @__PURE__ */ new Map();
|
|
10219
|
+
for (const n of nodes) {
|
|
10220
|
+
if (n.entityName && !entityNodeMap.has(n.entityName)) {
|
|
10221
|
+
entityNodeMap.set(n.entityName, n.id);
|
|
10222
|
+
}
|
|
10223
|
+
}
|
|
10224
|
+
const seen = new Set(edges.map((e) => `${e.source}:${e.edgeType}:${e.target}`));
|
|
10225
|
+
for (const rel of graphRelations) {
|
|
10226
|
+
const srcId = entityNodeMap.get(rel.from);
|
|
10227
|
+
const tgtId = entityNodeMap.get(rel.to);
|
|
10228
|
+
if (!srcId || !tgtId) continue;
|
|
10229
|
+
if (srcId === tgtId) continue;
|
|
10230
|
+
const edgeType = mapRelationType(rel.relationType);
|
|
10231
|
+
const key = `${srcId}:${edgeType}:${tgtId}`;
|
|
10232
|
+
if (seen.has(key)) continue;
|
|
10233
|
+
seen.add(key);
|
|
10234
|
+
edges.push({
|
|
10235
|
+
id: `e_gr_${edges.length}_${srcId}_${tgtId}`,
|
|
10236
|
+
source: srcId,
|
|
10237
|
+
target: tgtId,
|
|
10238
|
+
edgeType
|
|
10239
|
+
});
|
|
10240
|
+
}
|
|
10241
|
+
}
|
|
10242
|
+
const sectionCounts = {};
|
|
10243
|
+
for (const n of nodes) {
|
|
10244
|
+
sectionCounts[n.sectionId] = (sectionCounts[n.sectionId] || 0) + 1;
|
|
10245
|
+
}
|
|
10246
|
+
const clusters = ALL_SECTIONS.filter((def) => (sectionCounts[def.id] ?? 0) > 0).map((def) => ({
|
|
10247
|
+
id: `cluster:${def.id}`,
|
|
10248
|
+
label: def.label,
|
|
10249
|
+
sectionId: def.id,
|
|
10250
|
+
nodeCount: sectionCounts[def.id] ?? 0
|
|
10251
|
+
}));
|
|
10252
|
+
const stats = {
|
|
10253
|
+
totalNodes: nodes.length,
|
|
10254
|
+
totalEdges: edges.length,
|
|
10255
|
+
clusterCount: clusters.length,
|
|
10256
|
+
sectionCounts
|
|
10257
|
+
};
|
|
10258
|
+
return {
|
|
10259
|
+
title: "Knowledge Graph",
|
|
10260
|
+
projectId,
|
|
10261
|
+
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
10262
|
+
nodes,
|
|
10263
|
+
edges,
|
|
10264
|
+
clusters,
|
|
10265
|
+
stats
|
|
10266
|
+
};
|
|
10267
|
+
}
|
|
10268
|
+
var SECTION_DEFS2, GIT_SECTION, SKILLS_SECTION, ALL_SECTIONS;
|
|
10269
|
+
var init_knowledge_graph = __esm({
|
|
10270
|
+
"src/wiki/knowledge-graph.ts"() {
|
|
10271
|
+
"use strict";
|
|
10272
|
+
init_esm_shims();
|
|
10273
|
+
init_generator();
|
|
10274
|
+
SECTION_DEFS2 = [
|
|
10275
|
+
{
|
|
10276
|
+
id: "core-decisions",
|
|
10277
|
+
label: "Core Decisions",
|
|
10278
|
+
typeMatch: (o) => o.type === "decision" || o.type === "trade-off" || o.type === "reasoning"
|
|
10279
|
+
},
|
|
10280
|
+
{
|
|
10281
|
+
id: "operational-knowledge",
|
|
10282
|
+
label: "Operational Knowledge",
|
|
10283
|
+
typeMatch: (o) => o.type === "how-it-works" || o.type === "what-changed" || o.type === "why-it-exists" || o.type === "discovery" || o.type === "session-request"
|
|
10284
|
+
},
|
|
10285
|
+
{
|
|
10286
|
+
id: "known-gotchas",
|
|
10287
|
+
label: "Known Gotchas",
|
|
10288
|
+
typeMatch: (o) => o.type === "gotcha" || o.type === "problem-solution"
|
|
10289
|
+
}
|
|
10290
|
+
];
|
|
10291
|
+
GIT_SECTION = {
|
|
10292
|
+
id: "git-backed-facts",
|
|
10293
|
+
label: "Git-backed Facts",
|
|
10294
|
+
typeMatch: (o) => o.source === "git" && o.sourceDetail === "git-ingest"
|
|
10295
|
+
};
|
|
10296
|
+
SKILLS_SECTION = {
|
|
10297
|
+
id: "promoted-skills",
|
|
10298
|
+
label: "Promoted Skills",
|
|
10299
|
+
typeMatch: () => false
|
|
10300
|
+
// skills handled separately
|
|
10301
|
+
};
|
|
10302
|
+
ALL_SECTIONS = [...SECTION_DEFS2, GIT_SECTION, SKILLS_SECTION];
|
|
10303
|
+
}
|
|
10304
|
+
});
|
|
10305
|
+
|
|
9772
10306
|
// src/dashboard/server.ts
|
|
9773
10307
|
var server_exports = {};
|
|
9774
10308
|
__export(server_exports, {
|
|
10309
|
+
prepareDashboardConfig: () => prepareDashboardConfig,
|
|
9775
10310
|
startDashboard: () => startDashboard
|
|
9776
10311
|
});
|
|
9777
10312
|
import { createServer } from "http";
|
|
@@ -9797,6 +10332,25 @@ function isActiveStatus(status) {
|
|
|
9797
10332
|
function filterActiveByProject(items, projectId) {
|
|
9798
10333
|
return items.filter((item) => item.projectId === projectId && isActiveStatus(item.status));
|
|
9799
10334
|
}
|
|
10335
|
+
function prepareDashboardConfig(projectRoot) {
|
|
10336
|
+
if (!projectRoot) {
|
|
10337
|
+
if (preparedDashboardProjectRoot !== null) {
|
|
10338
|
+
resetDotenv();
|
|
10339
|
+
preparedDashboardProjectRoot = null;
|
|
10340
|
+
}
|
|
10341
|
+
clearProjectRoot();
|
|
10342
|
+
return;
|
|
10343
|
+
}
|
|
10344
|
+
try {
|
|
10345
|
+
if (preparedDashboardProjectRoot !== null && preparedDashboardProjectRoot !== projectRoot) {
|
|
10346
|
+
resetDotenv();
|
|
10347
|
+
}
|
|
10348
|
+
initProjectRoot(projectRoot);
|
|
10349
|
+
loadDotenv(projectRoot);
|
|
10350
|
+
preparedDashboardProjectRoot = projectRoot;
|
|
10351
|
+
} catch {
|
|
10352
|
+
}
|
|
10353
|
+
}
|
|
9800
10354
|
function computeProjectGraphCounts(allEntities, allRelations, projectObs) {
|
|
9801
10355
|
const entityNames = new Set(
|
|
9802
10356
|
projectObs.filter((o) => (o.status ?? "active") === "active" && o.entityName).map((o) => o.entityName)
|
|
@@ -9822,6 +10376,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9822
10376
|
effectiveProjectResolved = true;
|
|
9823
10377
|
effectiveProjectRoot = null;
|
|
9824
10378
|
}
|
|
10379
|
+
prepareDashboardConfig(effectiveProjectRoot);
|
|
9825
10380
|
try {
|
|
9826
10381
|
switch (apiPath) {
|
|
9827
10382
|
case "/projects": {
|
|
@@ -9910,6 +10465,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9910
10465
|
const typeCounts = {};
|
|
9911
10466
|
for (const obs of observations2) {
|
|
9912
10467
|
const t = obs.type || "unknown";
|
|
10468
|
+
if (t === "probe") continue;
|
|
9913
10469
|
typeCounts[t] = (typeCounts[t] || 0) + 1;
|
|
9914
10470
|
}
|
|
9915
10471
|
const sourceCounts = { git: 0, agent: 0, manual: 0 };
|
|
@@ -9951,7 +10507,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9951
10507
|
else if (score >= 1) retentionSummary.stale++;
|
|
9952
10508
|
else retentionSummary.archive++;
|
|
9953
10509
|
}
|
|
9954
|
-
const sorted = [...observations2].sort((a, b) => (b.id || 0) - (a.id || 0)).slice(0, 10);
|
|
10510
|
+
const sorted = [...observations2].filter((o) => o.type !== "probe").sort((a, b) => (b.id || 0) - (a.id || 0)).slice(0, 10);
|
|
9955
10511
|
let embeddingStatus = { enabled: false, provider: "", dimensions: 0 };
|
|
9956
10512
|
try {
|
|
9957
10513
|
const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
|
|
@@ -9991,7 +10547,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9991
10547
|
const allObs = await getObservationStore().loadAll();
|
|
9992
10548
|
const observations2 = filterActiveByProject(allObs, effectiveProjectId);
|
|
9993
10549
|
const now = Date.now();
|
|
9994
|
-
const scored = observations2.map((obs) => {
|
|
10550
|
+
const scored = observations2.filter((obs) => obs.type !== "probe").map((obs) => {
|
|
9995
10551
|
const age = now - new Date(obs.createdAt || now).getTime();
|
|
9996
10552
|
const ageHours = age / (1e3 * 60 * 60);
|
|
9997
10553
|
const importance = obs.importance ?? 5;
|
|
@@ -10023,6 +10579,50 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
10023
10579
|
});
|
|
10024
10580
|
break;
|
|
10025
10581
|
}
|
|
10582
|
+
case "/knowledge": {
|
|
10583
|
+
const { generateKnowledgeBase: generateKnowledgeBase2 } = await Promise.resolve().then(() => (init_generator(), generator_exports));
|
|
10584
|
+
const { initObservations: initObservations2, getAllObservations: getAllObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
10585
|
+
const { initMiniSkillStore: initMiniSkillStore2, getMiniSkillStore: getMiniSkillStore2 } = await Promise.resolve().then(() => (init_mini_skill_store(), mini_skill_store_exports));
|
|
10586
|
+
await initObservations2(effectiveDataDir);
|
|
10587
|
+
await initMiniSkillStore2(effectiveDataDir);
|
|
10588
|
+
const allObs = getAllObservations2();
|
|
10589
|
+
const skills = await getMiniSkillStore2().loadByProject(effectiveProjectId);
|
|
10590
|
+
const overview = generateKnowledgeBase2({
|
|
10591
|
+
projectId: effectiveProjectId,
|
|
10592
|
+
observations: allObs,
|
|
10593
|
+
miniSkills: skills
|
|
10594
|
+
});
|
|
10595
|
+
sendJson(res, overview);
|
|
10596
|
+
break;
|
|
10597
|
+
}
|
|
10598
|
+
case "/knowledge-graph": {
|
|
10599
|
+
const { generateKnowledgeGraph: generateKnowledgeGraph2 } = await Promise.resolve().then(() => (init_knowledge_graph(), knowledge_graph_exports));
|
|
10600
|
+
const { initObservations: initObservations2, getAllObservations: getAllObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
10601
|
+
const { initMiniSkillStore: initMiniSkillStore2, getMiniSkillStore: getMiniSkillStore2 } = await Promise.resolve().then(() => (init_mini_skill_store(), mini_skill_store_exports));
|
|
10602
|
+
const { initGraphStore: initGraphStore2, getGraphStore: getGraphStore2 } = await Promise.resolve().then(() => (init_graph_store(), graph_store_exports));
|
|
10603
|
+
await initObservations2(effectiveDataDir);
|
|
10604
|
+
await initMiniSkillStore2(effectiveDataDir);
|
|
10605
|
+
await initGraphStore2(effectiveDataDir);
|
|
10606
|
+
const allObs = getAllObservations2();
|
|
10607
|
+
const skills = await getMiniSkillStore2().loadByProject(effectiveProjectId);
|
|
10608
|
+
const fullGraph = { entities: getGraphStore2().loadEntities(), relations: getGraphStore2().loadRelations() };
|
|
10609
|
+
const graphObs = await getObservationStore().loadAll();
|
|
10610
|
+
const projectEntityNames = new Set(
|
|
10611
|
+
graphObs.filter((o) => o.projectId === effectiveProjectId && (o.status ?? "active") === "active" && o.entityName).map((o) => o.entityName)
|
|
10612
|
+
);
|
|
10613
|
+
const scopedEntities = fullGraph.entities.filter((e) => projectEntityNames.has(e.name));
|
|
10614
|
+
const scopedEntityNameSet = new Set(scopedEntities.map((e) => e.name));
|
|
10615
|
+
const scopedRelations = fullGraph.relations.filter((r) => scopedEntityNameSet.has(r.from) && scopedEntityNameSet.has(r.to));
|
|
10616
|
+
const graph = generateKnowledgeGraph2({
|
|
10617
|
+
projectId: effectiveProjectId,
|
|
10618
|
+
observations: allObs,
|
|
10619
|
+
miniSkills: skills,
|
|
10620
|
+
graphEntities: scopedEntities,
|
|
10621
|
+
graphRelations: scopedRelations
|
|
10622
|
+
});
|
|
10623
|
+
sendJson(res, graph);
|
|
10624
|
+
break;
|
|
10625
|
+
}
|
|
10026
10626
|
case "/config": {
|
|
10027
10627
|
const os4 = await import("os");
|
|
10028
10628
|
const { existsSync: existsSync10 } = await import("fs");
|
|
@@ -10031,7 +10631,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
10031
10631
|
const configProjectRoot = effectiveProjectRoot;
|
|
10032
10632
|
try {
|
|
10033
10633
|
const { loadYamlConfig: loadYamlConfig2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
|
|
10034
|
-
yml = loadYamlConfig2();
|
|
10634
|
+
yml = configProjectRoot ? loadYamlConfig2(configProjectRoot) : loadYamlConfig2(null);
|
|
10035
10635
|
} catch {
|
|
10036
10636
|
}
|
|
10037
10637
|
if (configProjectRoot) {
|
|
@@ -10094,6 +10694,19 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
10094
10694
|
} else {
|
|
10095
10695
|
values.push({ key: "llm.apiKey", value: "not set", source: "none" });
|
|
10096
10696
|
}
|
|
10697
|
+
const agentProvider = process.env.MEMORIX_AGENT_LLM_PROVIDER || yml.agent?.provider;
|
|
10698
|
+
if (agentProvider) values.push({ key: "agent.llm.provider", value: agentProvider, source: await getEnvSource("MEMORIX_AGENT_LLM_PROVIDER", yml.agent?.provider ? "memorix.yml" : void 0) });
|
|
10699
|
+
const agentModel = process.env.MEMORIX_AGENT_LLM_MODEL || yml.agent?.model;
|
|
10700
|
+
if (agentModel) values.push({ key: "agent.llm.model", value: agentModel, source: await getEnvSource("MEMORIX_AGENT_LLM_MODEL", yml.agent?.model ? "memorix.yml" : void 0) });
|
|
10701
|
+
const agentKey = process.env.MEMORIX_AGENT_LLM_API_KEY || yml.agent?.apiKey;
|
|
10702
|
+
if (agentKey) {
|
|
10703
|
+
let src = "unknown";
|
|
10704
|
+
if (process.env.MEMORIX_AGENT_LLM_API_KEY) src = await getEnvSource("MEMORIX_AGENT_LLM_API_KEY");
|
|
10705
|
+
else if (yml.agent?.apiKey) src = "memorix.yml (move to .env!)";
|
|
10706
|
+
values.push({ key: "agent.llm.apiKey", value: "****" + agentKey.slice(-4), source: src, sensitive: true });
|
|
10707
|
+
} else {
|
|
10708
|
+
values.push({ key: "agent.llm.apiKey", value: "fallback to llm.apiKey", source: "default" });
|
|
10709
|
+
}
|
|
10097
10710
|
const embProvider = process.env.MEMORIX_EMBEDDING || yml.embedding?.provider || "off";
|
|
10098
10711
|
values.push({ key: "embedding.provider", value: embProvider, source: await getEnvSource("MEMORIX_EMBEDDING", yml.embedding?.provider ? "memorix.yml" : void 0) });
|
|
10099
10712
|
values.push({ key: "git.autoHook", value: String(yml.git?.autoHook ?? false), source: yml.git?.autoHook !== void 0 ? "memorix.yml" : "default" });
|
|
@@ -10259,13 +10872,20 @@ async function serveStatic(req, res, staticDir) {
|
|
|
10259
10872
|
const ext = path14.extname(filePath);
|
|
10260
10873
|
res.writeHead(200, {
|
|
10261
10874
|
"Content-Type": MIME_TYPES[ext] || "application/octet-stream",
|
|
10262
|
-
"Cache-Control": "no-cache"
|
|
10875
|
+
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
10876
|
+
"Pragma": "no-cache",
|
|
10877
|
+
"Expires": "0"
|
|
10263
10878
|
});
|
|
10264
10879
|
res.end(data);
|
|
10265
10880
|
} catch {
|
|
10266
10881
|
try {
|
|
10267
10882
|
const indexData = await fs12.readFile(path14.join(staticDir, "index.html"));
|
|
10268
|
-
res.writeHead(200, {
|
|
10883
|
+
res.writeHead(200, {
|
|
10884
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
10885
|
+
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
10886
|
+
"Pragma": "no-cache",
|
|
10887
|
+
"Expires": "0"
|
|
10888
|
+
});
|
|
10269
10889
|
res.end(indexData);
|
|
10270
10890
|
} catch {
|
|
10271
10891
|
sendError(res, "Not found", 404);
|
|
@@ -10522,7 +11142,7 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
10522
11142
|
});
|
|
10523
11143
|
});
|
|
10524
11144
|
}
|
|
10525
|
-
var MIME_TYPES;
|
|
11145
|
+
var MIME_TYPES, preparedDashboardProjectRoot;
|
|
10526
11146
|
var init_server = __esm({
|
|
10527
11147
|
"src/dashboard/server.ts"() {
|
|
10528
11148
|
"use strict";
|
|
@@ -10531,6 +11151,10 @@ var init_server = __esm({
|
|
|
10531
11151
|
init_obs_store();
|
|
10532
11152
|
init_session_store();
|
|
10533
11153
|
init_graph_store();
|
|
11154
|
+
init_dotenv_loader();
|
|
11155
|
+
init_dotenv_loader();
|
|
11156
|
+
init_yaml_loader();
|
|
11157
|
+
init_yaml_loader();
|
|
10534
11158
|
MIME_TYPES = {
|
|
10535
11159
|
".html": "text/html; charset=utf-8",
|
|
10536
11160
|
".css": "text/css; charset=utf-8",
|
|
@@ -10540,6 +11164,7 @@ var init_server = __esm({
|
|
|
10540
11164
|
".png": "image/png",
|
|
10541
11165
|
".ico": "image/x-icon"
|
|
10542
11166
|
};
|
|
11167
|
+
preparedDashboardProjectRoot = null;
|
|
10543
11168
|
}
|
|
10544
11169
|
});
|
|
10545
11170
|
|
|
@@ -11696,7 +12321,7 @@ function generateKiroHookFiles() {
|
|
|
11696
12321
|
when: { type: "promptSubmit" },
|
|
11697
12322
|
then: {
|
|
11698
12323
|
type: "askAgent",
|
|
11699
|
-
prompt: "Before responding, load context:\n1. Call
|
|
12324
|
+
prompt: "Before responding, load useful project context:\n1. Call memorix_search with a query related to the user's prompt for relevant memories\n2. If search results are found, use memorix_detail to fetch the most relevant ones\n3. If memorix_search says this is a fresh project with no Memorix memories yet, do not repeat memorix_search again in the same turn unless the user explicitly asks for history/context or new memories were written\n4. Call memorix_session_start only when explicit session semantics are useful, such as handoff, long-running work, team coordination, or HTTP project binding\n5. Reference relevant memories naturally in your response"
|
|
11700
12325
|
}
|
|
11701
12326
|
}, null, 2)
|
|
11702
12327
|
},
|
|
@@ -11736,6 +12361,8 @@ import { spawnSync } from 'node:child_process';
|
|
|
11736
12361
|
export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
11737
12362
|
// Generate a stable session ID for this plugin lifetime
|
|
11738
12363
|
const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
|
|
12364
|
+
let pendingAssistantResponse = null;
|
|
12365
|
+
let lastDeliveredAssistantKey = '';
|
|
11739
12366
|
|
|
11740
12367
|
/**
|
|
11741
12368
|
* Send event JSON to \`memorix hook\` via child_process.spawnSync.
|
|
@@ -11768,6 +12395,33 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
11768
12395
|
}
|
|
11769
12396
|
}
|
|
11770
12397
|
|
|
12398
|
+
function extractMessageInfo(input) {
|
|
12399
|
+
if (input && typeof input === 'object') {
|
|
12400
|
+
if (input.info && typeof input.info === 'object') return input.info;
|
|
12401
|
+
if (input.message && typeof input.message === 'object') return input.message;
|
|
12402
|
+
if (input.properties && typeof input.properties === 'object') {
|
|
12403
|
+
if (input.properties.info && typeof input.properties.info === 'object') return input.properties.info;
|
|
12404
|
+
if (input.properties.message && typeof input.properties.message === 'object') return input.properties.message;
|
|
12405
|
+
}
|
|
12406
|
+
}
|
|
12407
|
+
return input;
|
|
12408
|
+
}
|
|
12409
|
+
|
|
12410
|
+
function extractMessageText(message) {
|
|
12411
|
+
if (!message || typeof message !== 'object') return '';
|
|
12412
|
+
if (typeof message.content === 'string') return message.content.trim();
|
|
12413
|
+
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
12414
|
+
return parts
|
|
12415
|
+
.map((part) => {
|
|
12416
|
+
if (!part || typeof part !== 'object') return '';
|
|
12417
|
+
if (typeof part.text === 'string') return part.text;
|
|
12418
|
+
if (typeof part.content === 'string') return part.content;
|
|
12419
|
+
return '';
|
|
12420
|
+
})
|
|
12421
|
+
.join('')
|
|
12422
|
+
.trim();
|
|
12423
|
+
}
|
|
12424
|
+
|
|
11771
12425
|
return {
|
|
11772
12426
|
/** Session created \u2014 record session start */
|
|
11773
12427
|
'session.created': async ({ session }) => {
|
|
@@ -11780,6 +12434,21 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
11780
12434
|
|
|
11781
12435
|
/** Session idle \u2014 record session end */
|
|
11782
12436
|
'session.idle': async ({ session }) => {
|
|
12437
|
+
if (pendingAssistantResponse?.text) {
|
|
12438
|
+
const deliveryKey = pendingAssistantResponse.id
|
|
12439
|
+
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
12440
|
+
: pendingAssistantResponse.text;
|
|
12441
|
+
if (deliveryKey !== lastDeliveredAssistantKey) {
|
|
12442
|
+
runHook({
|
|
12443
|
+
agent: 'opencode',
|
|
12444
|
+
hook_event_name: 'message.updated',
|
|
12445
|
+
ai_response: pendingAssistantResponse.text,
|
|
12446
|
+
message_id: pendingAssistantResponse.id,
|
|
12447
|
+
cwd: directory,
|
|
12448
|
+
});
|
|
12449
|
+
lastDeliveredAssistantKey = deliveryKey;
|
|
12450
|
+
}
|
|
12451
|
+
}
|
|
11783
12452
|
runHook({
|
|
11784
12453
|
agent: 'opencode',
|
|
11785
12454
|
hook_event_name: 'session.idle',
|
|
@@ -11808,6 +12477,19 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
11808
12477
|
});
|
|
11809
12478
|
},
|
|
11810
12479
|
|
|
12480
|
+
/** Message updated \u2014 cache the latest assistant response until session.idle */
|
|
12481
|
+
'message.updated': async (input, output) => {
|
|
12482
|
+
const message = extractMessageInfo(input);
|
|
12483
|
+
const role = message?.role ?? input?.role ?? input?.info?.role;
|
|
12484
|
+
if (role !== 'assistant') return;
|
|
12485
|
+
const text = extractMessageText(message);
|
|
12486
|
+
if (!text) return;
|
|
12487
|
+
pendingAssistantResponse = {
|
|
12488
|
+
id: message?.id ?? input?.id ?? input?.messageID,
|
|
12489
|
+
text,
|
|
12490
|
+
};
|
|
12491
|
+
},
|
|
12492
|
+
|
|
11811
12493
|
/** Session compacted \u2014 record post-compact event */
|
|
11812
12494
|
'session.compacted': async ({ session }) => {
|
|
11813
12495
|
runHook({
|
|
@@ -12057,7 +12739,7 @@ async function installHooks(agent, projectRoot, global = false) {
|
|
|
12057
12739
|
return {
|
|
12058
12740
|
agent,
|
|
12059
12741
|
configPath: pluginPath,
|
|
12060
|
-
events: ["session_start", "session_end", "post_tool", "post_edit", "post_compact", "post_command"],
|
|
12742
|
+
events: ["session_start", "session_end", "post_tool", "post_edit", "post_compact", "post_command", "post_response"],
|
|
12061
12743
|
generated: { note: "OpenCode plugin installed at " + pluginPath }
|
|
12062
12744
|
};
|
|
12063
12745
|
}
|
|
@@ -12250,20 +12932,18 @@ alwaysApply: true
|
|
|
12250
12932
|
|
|
12251
12933
|
You have access to Memorix memory tools. Follow these rules to maintain persistent context across sessions.
|
|
12252
12934
|
|
|
12253
|
-
## RULE 1:
|
|
12935
|
+
## RULE 1: Use Memory When Useful
|
|
12254
12936
|
|
|
12255
|
-
At the
|
|
12937
|
+
At the beginning of a conversation, use Memorix when prior project context would materially help the task. Do not require a session bind for every conversation.
|
|
12256
12938
|
|
|
12257
|
-
1. Call \`
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
3. If search results are found, use \`memorix_detail\` to fetch the most relevant ones
|
|
12263
|
-
4. Reference relevant memories naturally \u2014 the user should feel you "remember" them
|
|
12939
|
+
1. Call \`memorix_search\` with a query related to the user's first message or current task.
|
|
12940
|
+
2. If search results are found, use \`memorix_detail\` to fetch the most relevant ones.
|
|
12941
|
+
3. If \`memorix_search\` says this is a fresh project with no Memorix memories yet, treat that as a successful cold-start signal. Do not repeat \`memorix_search\` again in the same turn unless the user explicitly asks for history/context or new memories were written.
|
|
12942
|
+
4. Call \`memorix_session_start\` only when explicit session semantics are useful: handoff, long-running work, team coordination, restoring prior session context, or HTTP project binding.
|
|
12943
|
+
5. Reference relevant memories naturally \u2014 the user should feel you understand the project, not that you are following a ritual.
|
|
12264
12944
|
|
|
12265
12945
|
**Important:** \`projectRoot\` is a detection anchor only; Git remains the source of truth for project identity.
|
|
12266
|
-
In HTTP control-plane mode (\`memorix serve-http\` / \`memorix background start\`), explicit \`projectRoot\` binding is required for correct multi-project isolation.
|
|
12946
|
+
In HTTP control-plane mode (\`memorix serve-http\` / \`memorix background start\`), explicit \`projectRoot\` binding is recommended when the workspace path is available and required for correct multi-project isolation.
|
|
12267
12947
|
\`memorix_session_start\` is lightweight by default: it starts memory/session context only. Do not set \`joinTeam\` unless the user explicitly needs autonomous Agent Team tasks, messages, file locks, or orchestrated CLI-agent workflows.
|
|
12268
12948
|
|
|
12269
12949
|
## RULE 2: Store Important Context
|
|
@@ -12515,7 +13195,7 @@ var init_installers = __esm({
|
|
|
12515
13195
|
"src/hooks/installers/index.ts"() {
|
|
12516
13196
|
"use strict";
|
|
12517
13197
|
init_esm_shims();
|
|
12518
|
-
OPENCODE_PLUGIN_VERSION =
|
|
13198
|
+
OPENCODE_PLUGIN_VERSION = 6;
|
|
12519
13199
|
}
|
|
12520
13200
|
});
|
|
12521
13201
|
|
|
@@ -13046,7 +13726,8 @@ function getTypeIcon(type) {
|
|
|
13046
13726
|
"why-it-exists": "[WHY]",
|
|
13047
13727
|
"decision": "[DECISION]",
|
|
13048
13728
|
"trade-off": "[TRADEOFF]",
|
|
13049
|
-
"reasoning": "[REASONING]"
|
|
13729
|
+
"reasoning": "[REASONING]",
|
|
13730
|
+
"probe": "[PROBE]"
|
|
13050
13731
|
};
|
|
13051
13732
|
return icons[type] ?? "[UNKNOWN]";
|
|
13052
13733
|
}
|
|
@@ -13107,7 +13788,18 @@ init_mini_skills();
|
|
|
13107
13788
|
init_secret_filter();
|
|
13108
13789
|
async function compactSearch(options) {
|
|
13109
13790
|
const entries = await searchObservations(options);
|
|
13110
|
-
|
|
13791
|
+
let formatted = formatIndexTable(entries, options.query, !options.projectId);
|
|
13792
|
+
if (entries.length === 0 && options.projectId) {
|
|
13793
|
+
const allObservations = getAllObservations();
|
|
13794
|
+
const projectHasStoredMemory = allObservations.some((obs) => obs.projectId === options.projectId);
|
|
13795
|
+
if (!projectHasStoredMemory) {
|
|
13796
|
+
formatted = `This project does not have any Memorix memories yet.
|
|
13797
|
+
|
|
13798
|
+
It looks like a fresh project: the tool call worked, but there is nothing stored to retrieve yet.
|
|
13799
|
+
|
|
13800
|
+
Memories will start appearing after observations, session summaries, hook captures, or git-memory are written.`;
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13111
13803
|
const totalTokens = countTextTokens(formatted);
|
|
13112
13804
|
return { entries, formatted, totalTokens };
|
|
13113
13805
|
}
|
|
@@ -15545,7 +16237,8 @@ var OBSERVATION_TYPES = [
|
|
|
15545
16237
|
"discovery",
|
|
15546
16238
|
"why-it-exists",
|
|
15547
16239
|
"decision",
|
|
15548
|
-
"trade-off"
|
|
16240
|
+
"trade-off",
|
|
16241
|
+
"probe"
|
|
15549
16242
|
];
|
|
15550
16243
|
function coerceNumberArray(val) {
|
|
15551
16244
|
if (Array.isArray(val)) return val.map(Number);
|
|
@@ -15774,7 +16467,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
15774
16467
|
};
|
|
15775
16468
|
const server = existingServer ?? new McpServer({
|
|
15776
16469
|
name: "memorix",
|
|
15777
|
-
version: true ? "1.0.
|
|
16470
|
+
version: true ? "1.0.10" : "1.0.1"
|
|
15778
16471
|
});
|
|
15779
16472
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
15780
16473
|
server.registerTool = ((name, ...args) => {
|