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/sdk.js
CHANGED
|
@@ -674,6 +674,13 @@ var init_persistence = __esm({
|
|
|
674
674
|
});
|
|
675
675
|
|
|
676
676
|
// src/store/graph-store.ts
|
|
677
|
+
var graph_store_exports = {};
|
|
678
|
+
__export(graph_store_exports, {
|
|
679
|
+
GraphSqliteStore: () => GraphSqliteStore,
|
|
680
|
+
getGraphStore: () => getGraphStore,
|
|
681
|
+
initGraphStore: () => initGraphStore,
|
|
682
|
+
resetGraphStore: () => resetGraphStore
|
|
683
|
+
});
|
|
677
684
|
import path6 from "path";
|
|
678
685
|
import fs5 from "fs";
|
|
679
686
|
function safeJsonParse(val, fallback) {
|
|
@@ -709,6 +716,16 @@ function getGraphStore() {
|
|
|
709
716
|
if (!_graphStore) throw new Error("[memorix] GraphStore not initialized \u2014 call initGraphStore() first");
|
|
710
717
|
return _graphStore;
|
|
711
718
|
}
|
|
719
|
+
function resetGraphStore() {
|
|
720
|
+
if (_graphStore) {
|
|
721
|
+
try {
|
|
722
|
+
_graphStore.close();
|
|
723
|
+
} catch {
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
_graphStore = null;
|
|
727
|
+
_graphDataDir = null;
|
|
728
|
+
}
|
|
712
729
|
var GraphSqliteStore, _graphStore, _graphDataDir;
|
|
713
730
|
var init_graph_store = __esm({
|
|
714
731
|
"src/store/graph-store.ts"() {
|
|
@@ -1040,7 +1057,8 @@ var init_types = __esm({
|
|
|
1040
1057
|
"why-it-exists": "[WHY]",
|
|
1041
1058
|
"decision": "[DECISION]",
|
|
1042
1059
|
"trade-off": "[TRADEOFF]",
|
|
1043
|
-
"reasoning": "[REASONING]"
|
|
1060
|
+
"reasoning": "[REASONING]",
|
|
1061
|
+
"probe": "[PROBE]"
|
|
1044
1062
|
};
|
|
1045
1063
|
TOPIC_KEY_FAMILIES = {
|
|
1046
1064
|
"architecture": ["architecture", "design", "adr", "structure", "pattern"],
|
|
@@ -1059,6 +1077,15 @@ var init_types = __esm({
|
|
|
1059
1077
|
});
|
|
1060
1078
|
|
|
1061
1079
|
// src/store/mini-skill-store.ts
|
|
1080
|
+
var mini_skill_store_exports = {};
|
|
1081
|
+
__export(mini_skill_store_exports, {
|
|
1082
|
+
MiniSkillGracefulDegrade: () => MiniSkillGracefulDegrade,
|
|
1083
|
+
MiniSkillSqliteStore: () => MiniSkillSqliteStore,
|
|
1084
|
+
getMiniSkillStore: () => getMiniSkillStore,
|
|
1085
|
+
initMiniSkillStore: () => initMiniSkillStore,
|
|
1086
|
+
isMiniSkillStoreInitialized: () => isMiniSkillStoreInitialized,
|
|
1087
|
+
resetMiniSkillStore: () => resetMiniSkillStore
|
|
1088
|
+
});
|
|
1062
1089
|
import path7 from "path";
|
|
1063
1090
|
import fs6 from "fs";
|
|
1064
1091
|
function skillToRow(skill) {
|
|
@@ -1112,6 +1139,10 @@ function getMiniSkillStore() {
|
|
|
1112
1139
|
}
|
|
1113
1140
|
return _store;
|
|
1114
1141
|
}
|
|
1142
|
+
function resetMiniSkillStore() {
|
|
1143
|
+
_store = null;
|
|
1144
|
+
_storeDataDir = null;
|
|
1145
|
+
}
|
|
1115
1146
|
async function initMiniSkillStore(dataDir) {
|
|
1116
1147
|
if (_store && _storeDataDir === dataDir) return _store;
|
|
1117
1148
|
_store = null;
|
|
@@ -1358,6 +1389,12 @@ async function promoteToMiniSkill(projectDir2, projectId, observations2, options
|
|
|
1358
1389
|
`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.`
|
|
1359
1390
|
);
|
|
1360
1391
|
}
|
|
1392
|
+
const probes = observations2.filter((o) => o.type === "probe");
|
|
1393
|
+
if (probes.length > 0) {
|
|
1394
|
+
throw new Error(
|
|
1395
|
+
`Cannot promote probe observations \u2014 they are operational heartbeats, not durable knowledge. Blocked: ${probes.map((o) => `#${o.id} "${o.title.substring(0, 60)}"`).join(", ")}.`
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1361
1398
|
if (!options?.force) {
|
|
1362
1399
|
const commandLogs = observations2.filter((o) => COMMAND_LOG_TITLE.test(o.title));
|
|
1363
1400
|
if (commandLogs.length > 0) {
|
|
@@ -1574,6 +1611,7 @@ var init_mini_skills = __esm({
|
|
|
1574
1611
|
// src/config/yaml-loader.ts
|
|
1575
1612
|
var yaml_loader_exports = {};
|
|
1576
1613
|
__export(yaml_loader_exports, {
|
|
1614
|
+
clearProjectRoot: () => clearProjectRoot,
|
|
1577
1615
|
initProjectRoot: () => initProjectRoot,
|
|
1578
1616
|
loadYamlConfig: () => loadYamlConfig,
|
|
1579
1617
|
resetYamlConfigCache: () => resetYamlConfigCache
|
|
@@ -1585,6 +1623,9 @@ function initProjectRoot(root) {
|
|
|
1585
1623
|
globalProjectRoot = root;
|
|
1586
1624
|
configCache.delete(root);
|
|
1587
1625
|
}
|
|
1626
|
+
function clearProjectRoot() {
|
|
1627
|
+
globalProjectRoot = null;
|
|
1628
|
+
}
|
|
1588
1629
|
function loadYamlConfig(projectRoot) {
|
|
1589
1630
|
const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
|
|
1590
1631
|
const cached2 = configCache.get(resolvedRoot ?? null);
|
|
@@ -1612,6 +1653,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
1612
1653
|
...projectConfig,
|
|
1613
1654
|
// Deep merge for nested objects where both exist
|
|
1614
1655
|
llm: { ...userConfig.llm, ...projectConfig.llm },
|
|
1656
|
+
agent: { ...userConfig.agent, ...projectConfig.agent },
|
|
1615
1657
|
embedding: { ...userConfig.embedding, ...projectConfig.embedding },
|
|
1616
1658
|
git: { ...userConfig.git, ...projectConfig.git },
|
|
1617
1659
|
behavior: { ...userConfig.behavior, ...projectConfig.behavior },
|
|
@@ -1714,6 +1756,10 @@ var init_dotenv_loader = __esm({
|
|
|
1714
1756
|
// src/config.ts
|
|
1715
1757
|
var config_exports = {};
|
|
1716
1758
|
__export(config_exports, {
|
|
1759
|
+
getAgentLLMApiKey: () => getAgentLLMApiKey,
|
|
1760
|
+
getAgentLLMBaseUrl: () => getAgentLLMBaseUrl,
|
|
1761
|
+
getAgentLLMModel: () => getAgentLLMModel,
|
|
1762
|
+
getAgentLLMProvider: () => getAgentLLMProvider,
|
|
1717
1763
|
getEmbeddingApiKey: () => getEmbeddingApiKey,
|
|
1718
1764
|
getEmbeddingBaseUrl: () => getEmbeddingBaseUrl,
|
|
1719
1765
|
getEmbeddingDimensions: () => getEmbeddingDimensions,
|
|
@@ -1773,6 +1819,23 @@ function getLLMModel(providerDefault) {
|
|
|
1773
1819
|
function getLLMBaseUrl(providerDefault) {
|
|
1774
1820
|
return process.env.MEMORIX_LLM_BASE_URL || loadYamlConfig().llm?.baseUrl || loadFileConfig().llm?.baseUrl || providerDefault;
|
|
1775
1821
|
}
|
|
1822
|
+
function getAgentLLMApiKey() {
|
|
1823
|
+
return process.env.MEMORIX_AGENT_LLM_API_KEY || loadYamlConfig().agent?.apiKey || loadFileConfig().agent?.apiKey || getLLMApiKey();
|
|
1824
|
+
}
|
|
1825
|
+
function getAgentLLMProvider() {
|
|
1826
|
+
if (process.env.MEMORIX_AGENT_LLM_PROVIDER) return process.env.MEMORIX_AGENT_LLM_PROVIDER;
|
|
1827
|
+
const yml = loadYamlConfig();
|
|
1828
|
+
if (yml.agent?.provider) return yml.agent.provider;
|
|
1829
|
+
const cfg = loadFileConfig();
|
|
1830
|
+
if (cfg.agent?.provider) return cfg.agent.provider;
|
|
1831
|
+
return getLLMProvider();
|
|
1832
|
+
}
|
|
1833
|
+
function getAgentLLMModel(providerDefault) {
|
|
1834
|
+
return process.env.MEMORIX_AGENT_LLM_MODEL || loadYamlConfig().agent?.model || loadFileConfig().agent?.model || getLLMModel(providerDefault);
|
|
1835
|
+
}
|
|
1836
|
+
function getAgentLLMBaseUrl(providerDefault) {
|
|
1837
|
+
return process.env.MEMORIX_AGENT_LLM_BASE_URL || loadYamlConfig().agent?.baseUrl || loadFileConfig().agent?.baseUrl || getLLMBaseUrl(providerDefault);
|
|
1838
|
+
}
|
|
1776
1839
|
function getEmbeddingMode() {
|
|
1777
1840
|
const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();
|
|
1778
1841
|
if (env === "fastembed" || env === "transformers" || env === "api" || env === "auto") return env;
|
|
@@ -3062,20 +3125,20 @@ async function* callLLMWithToolsStream(messages, tools) {
|
|
|
3062
3125
|
}
|
|
3063
3126
|
yield* callOpenAIWithToolsStream(messages, tools);
|
|
3064
3127
|
}
|
|
3065
|
-
function initLLM() {
|
|
3066
|
-
const
|
|
3067
|
-
const apiKey =
|
|
3128
|
+
function initLLM(options = {}) {
|
|
3129
|
+
const scope = options.scope ?? "memory";
|
|
3130
|
+
const apiKey = scope === "agent" ? getAgentLLMApiKey() : getLLMApiKey();
|
|
3068
3131
|
if (!apiKey) {
|
|
3069
3132
|
currentConfig = null;
|
|
3070
3133
|
return null;
|
|
3071
3134
|
}
|
|
3072
|
-
const provider2 =
|
|
3135
|
+
const provider2 = scope === "agent" ? getAgentLLMProvider() : getLLMProvider();
|
|
3073
3136
|
const defaults = PROVIDER_DEFAULTS[provider2] ?? PROVIDER_DEFAULTS.openai;
|
|
3074
3137
|
currentConfig = {
|
|
3075
3138
|
provider: provider2,
|
|
3076
3139
|
apiKey,
|
|
3077
|
-
model:
|
|
3078
|
-
baseUrl:
|
|
3140
|
+
model: scope === "agent" ? getAgentLLMModel(defaults.model) : getLLMModel(defaults.model),
|
|
3141
|
+
baseUrl: scope === "agent" ? getAgentLLMBaseUrl(defaults.baseUrl) : getLLMBaseUrl(defaults.baseUrl)
|
|
3079
3142
|
};
|
|
3080
3143
|
return currentConfig;
|
|
3081
3144
|
}
|
|
@@ -3582,6 +3645,7 @@ var init_provider2 = __esm({
|
|
|
3582
3645
|
"src/llm/provider.ts"() {
|
|
3583
3646
|
"use strict";
|
|
3584
3647
|
init_esm_shims();
|
|
3648
|
+
init_config();
|
|
3585
3649
|
LLM_TIMEOUT_DEFAULT_MS = 3e4;
|
|
3586
3650
|
LLM_TIMEOUT_MIN_MS = 1e3;
|
|
3587
3651
|
LLM_TIMEOUT_MAX_MS = 3e5;
|
|
@@ -4411,6 +4475,10 @@ async function searchObservations(options) {
|
|
|
4411
4475
|
if (statusFilter === "all") return true;
|
|
4412
4476
|
const doc = hit.document;
|
|
4413
4477
|
return (doc.status || "active") === statusFilter;
|
|
4478
|
+
}).filter((hit) => {
|
|
4479
|
+
if (options.type === "probe") return true;
|
|
4480
|
+
const doc = hit.document;
|
|
4481
|
+
return doc.type !== "probe";
|
|
4414
4482
|
}).map((hit) => {
|
|
4415
4483
|
const doc = hit.document;
|
|
4416
4484
|
const obsType = doc.type;
|
|
@@ -6792,6 +6860,11 @@ function hasContradiction(oldText, newText) {
|
|
|
6792
6860
|
];
|
|
6793
6861
|
return negationPatterns.some((p) => p.test(newText));
|
|
6794
6862
|
}
|
|
6863
|
+
function normalizedSearchSimilarity(score) {
|
|
6864
|
+
if (!Number.isFinite(score) || score <= 0) return 0;
|
|
6865
|
+
if (score <= 1) return score;
|
|
6866
|
+
return 0;
|
|
6867
|
+
}
|
|
6795
6868
|
function mergeNarratives(oldNarrative, newNarrative) {
|
|
6796
6869
|
if (newNarrative.length > oldNarrative.length * 1.5) return newNarrative;
|
|
6797
6870
|
if (oldNarrative.length > newNarrative.length * 1.5) return oldNarrative;
|
|
@@ -6882,12 +6955,13 @@ function scoreCandidate(extracted, candidate) {
|
|
|
6882
6955
|
`${extracted.title} ${extracted.narrative}`,
|
|
6883
6956
|
`${candidate.title} ${candidate.narrative}`
|
|
6884
6957
|
);
|
|
6885
|
-
const
|
|
6958
|
+
const searchSimilarity = normalizedSearchSimilarity(candidate.score);
|
|
6959
|
+
const score = searchSimilarity * 0.6 + (entityMatch ? 0.2 : 0) + contentOverlap * 0.2;
|
|
6886
6960
|
const newLength = extracted.narrative.length + extracted.facts.join(" ").length;
|
|
6887
6961
|
const oldLength = candidate.narrative.length + candidate.facts.length;
|
|
6888
6962
|
const richer = newLength > oldLength * 1.15;
|
|
6889
6963
|
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
6890
|
-
return { score, entityMatch, richer, contradiction };
|
|
6964
|
+
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
6891
6965
|
}
|
|
6892
6966
|
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false) {
|
|
6893
6967
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
@@ -6910,7 +6984,7 @@ async function runResolve(extracted, projectId, searchMemories, getObservation2,
|
|
|
6910
6984
|
}));
|
|
6911
6985
|
scored.sort((a, b) => b.score - a.score);
|
|
6912
6986
|
const best = scored[0];
|
|
6913
|
-
if (best.
|
|
6987
|
+
if (best.searchSimilarity >= SIMILARITY_DUPLICATE) {
|
|
6914
6988
|
if (best.richer) {
|
|
6915
6989
|
const existing = getObservation2(best.hit.observationId);
|
|
6916
6990
|
const oldFacts = existing?.facts ?? best.hit.facts.split("\n").filter(Boolean);
|
|
@@ -7097,7 +7171,8 @@ var init_evaluate = __esm({
|
|
|
7097
7171
|
"how-it-works": 0.6,
|
|
7098
7172
|
"discovery": 0.55,
|
|
7099
7173
|
"what-changed": 0.45,
|
|
7100
|
-
"session-request": 0.4
|
|
7174
|
+
"session-request": 0.4,
|
|
7175
|
+
"probe": 0.1
|
|
7101
7176
|
};
|
|
7102
7177
|
SPECIFICITY_PATTERNS = [
|
|
7103
7178
|
/\b\d+\.\d+\.\d+\b/,
|
|
@@ -7561,6 +7636,9 @@ function scoreObservationForSessionContext(obs, projectTokens, now = Date.now())
|
|
|
7561
7636
|
if (obs.valueCategory === "core") {
|
|
7562
7637
|
score += 2;
|
|
7563
7638
|
}
|
|
7639
|
+
if (obs.type === "probe") {
|
|
7640
|
+
score -= 100;
|
|
7641
|
+
}
|
|
7564
7642
|
return score;
|
|
7565
7643
|
}
|
|
7566
7644
|
async function startSession(projectDir2, projectId, opts) {
|
|
@@ -7769,7 +7847,8 @@ var init_session = __esm({
|
|
|
7769
7847
|
"how-it-works": "[INFO]",
|
|
7770
7848
|
"what-changed": "[CHANGE]",
|
|
7771
7849
|
"why-it-exists": "[DECISION]",
|
|
7772
|
-
"session-request": "[SESSION]"
|
|
7850
|
+
"session-request": "[SESSION]",
|
|
7851
|
+
"probe": "[PROBE]"
|
|
7773
7852
|
};
|
|
7774
7853
|
TYPE_WEIGHTS2 = {
|
|
7775
7854
|
"gotcha": 6,
|
|
@@ -7848,11 +7927,17 @@ function getValueCategoryMultiplier(doc) {
|
|
|
7848
7927
|
return 1;
|
|
7849
7928
|
}
|
|
7850
7929
|
function getEffectiveRetentionDays(doc) {
|
|
7930
|
+
const typeOverride = TYPE_RETENTION_OVERRIDE[doc.type];
|
|
7931
|
+
if (typeOverride !== void 0) {
|
|
7932
|
+
const raw2 = typeOverride * getSourceRetentionMultiplier(doc);
|
|
7933
|
+
return Math.max(MIN_RETENTION_DAYS, raw2);
|
|
7934
|
+
}
|
|
7851
7935
|
const importance = getImportanceLevel(doc);
|
|
7852
7936
|
const raw = RETENTION_DAYS[importance] * getSourceRetentionMultiplier(doc) * getValueCategoryMultiplier(doc);
|
|
7853
7937
|
return Math.max(MIN_RETENTION_DAYS, raw);
|
|
7854
7938
|
}
|
|
7855
7939
|
function isImmune(doc) {
|
|
7940
|
+
if (doc.type === "probe") return false;
|
|
7856
7941
|
if (doc.valueCategory === "core") return true;
|
|
7857
7942
|
const importance = getImportanceLevel(doc);
|
|
7858
7943
|
if (importance === "critical") return true;
|
|
@@ -7861,6 +7946,7 @@ function isImmune(doc) {
|
|
|
7861
7946
|
return concepts.some((c) => PROTECTED_TAGS.has(c));
|
|
7862
7947
|
}
|
|
7863
7948
|
function getImmunityReason(doc) {
|
|
7949
|
+
if (doc.type === "probe") return null;
|
|
7864
7950
|
if (doc.valueCategory === "core") return "core valueCategory (formation-classified)";
|
|
7865
7951
|
const importance = getImportanceLevel(doc);
|
|
7866
7952
|
if (importance === "critical") return "critical importance";
|
|
@@ -8017,7 +8103,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap) {
|
|
|
8017
8103
|
return { archived: archivedCount, remaining: activeObs.length - archivedCount };
|
|
8018
8104
|
});
|
|
8019
8105
|
}
|
|
8020
|
-
var RETENTION_DAYS, BASE_IMPORTANCE, TYPE_IMPORTANCE, PROTECTED_TAGS, MIN_ACCESS_FOR_IMMUNITY, MIN_RETENTION_DAYS;
|
|
8106
|
+
var RETENTION_DAYS, BASE_IMPORTANCE, TYPE_IMPORTANCE, TYPE_RETENTION_OVERRIDE, PROTECTED_TAGS, MIN_ACCESS_FOR_IMMUNITY, MIN_RETENTION_DAYS;
|
|
8021
8107
|
var init_retention = __esm({
|
|
8022
8108
|
"src/memory/retention.ts"() {
|
|
8023
8109
|
"use strict";
|
|
@@ -8045,7 +8131,12 @@ var init_retention = __esm({
|
|
|
8045
8131
|
"what-changed": "low",
|
|
8046
8132
|
"why-it-exists": "medium",
|
|
8047
8133
|
discovery: "low",
|
|
8048
|
-
"session-request": "low"
|
|
8134
|
+
"session-request": "low",
|
|
8135
|
+
probe: "low"
|
|
8136
|
+
};
|
|
8137
|
+
TYPE_RETENTION_OVERRIDE = {
|
|
8138
|
+
probe: 7
|
|
8139
|
+
// Operational heartbeats: expire after ~7 days regardless of source/valueCategory
|
|
8049
8140
|
};
|
|
8050
8141
|
PROTECTED_TAGS = /* @__PURE__ */ new Set(["keep", "important", "pinned", "critical"]);
|
|
8051
8142
|
MIN_ACCESS_FOR_IMMUNITY = 3;
|
|
@@ -9773,9 +9864,453 @@ var init_project_classification = __esm({
|
|
|
9773
9864
|
}
|
|
9774
9865
|
});
|
|
9775
9866
|
|
|
9867
|
+
// src/wiki/generator.ts
|
|
9868
|
+
var generator_exports = {};
|
|
9869
|
+
__export(generator_exports, {
|
|
9870
|
+
contextualHasSubstance: () => contextualHasSubstance,
|
|
9871
|
+
generateKnowledgeBase: () => generateKnowledgeBase,
|
|
9872
|
+
isCommandLog: () => isCommandLog,
|
|
9873
|
+
isEligible: () => isEligible,
|
|
9874
|
+
isExcludedType: () => isExcludedType
|
|
9875
|
+
});
|
|
9876
|
+
function isExcludedType(o) {
|
|
9877
|
+
return o.type === "probe";
|
|
9878
|
+
}
|
|
9879
|
+
function isCommandLog(o) {
|
|
9880
|
+
return COMMAND_LOG_TITLE3.test(o.title || "");
|
|
9881
|
+
}
|
|
9882
|
+
function isInactive(o) {
|
|
9883
|
+
const status = o.status ?? "active";
|
|
9884
|
+
return status !== "active";
|
|
9885
|
+
}
|
|
9886
|
+
function isOtherProject(o, projectId) {
|
|
9887
|
+
return o.projectId !== projectId;
|
|
9888
|
+
}
|
|
9889
|
+
function contextualHasSubstance(o) {
|
|
9890
|
+
if (o.valueCategory !== "contextual") return true;
|
|
9891
|
+
const hasFacts = (o.facts?.length ?? 0) > 0;
|
|
9892
|
+
const hasConcepts = (o.concepts?.length ?? 0) > 0;
|
|
9893
|
+
const hasFiles = (o.filesModified?.length ?? 0) > 0;
|
|
9894
|
+
const hasEntity = !!(o.entityName && o.entityName !== "quick-note" && o.entityName !== "unknown");
|
|
9895
|
+
return hasFacts || hasConcepts || hasFiles || hasEntity;
|
|
9896
|
+
}
|
|
9897
|
+
function isEligible(o, projectId) {
|
|
9898
|
+
if (isExcludedType(o)) return false;
|
|
9899
|
+
if (isCommandLog(o)) return false;
|
|
9900
|
+
if (isInactive(o)) return false;
|
|
9901
|
+
if (isOtherProject(o, projectId)) return false;
|
|
9902
|
+
if (o.valueCategory === "ephemeral") return false;
|
|
9903
|
+
if (!contextualHasSubstance(o)) return false;
|
|
9904
|
+
return true;
|
|
9905
|
+
}
|
|
9906
|
+
function obsToItem(o) {
|
|
9907
|
+
const ref = {
|
|
9908
|
+
kind: o.source === "git" ? "git" : "observation",
|
|
9909
|
+
id: `obs:${o.id}`,
|
|
9910
|
+
title: o.title
|
|
9911
|
+
};
|
|
9912
|
+
return {
|
|
9913
|
+
title: o.title,
|
|
9914
|
+
summary: o.narrative?.slice(0, 200) || "",
|
|
9915
|
+
type: o.type,
|
|
9916
|
+
entityName: o.entityName || void 0,
|
|
9917
|
+
refs: [ref]
|
|
9918
|
+
};
|
|
9919
|
+
}
|
|
9920
|
+
function skillToItem(s) {
|
|
9921
|
+
const ref = {
|
|
9922
|
+
kind: "mini-skill",
|
|
9923
|
+
id: `skill:${s.id}`,
|
|
9924
|
+
title: s.title
|
|
9925
|
+
};
|
|
9926
|
+
const obsRefs = s.sourceObservationIds.map(
|
|
9927
|
+
(oid) => ({ kind: "observation", id: `obs:${oid}` })
|
|
9928
|
+
);
|
|
9929
|
+
return {
|
|
9930
|
+
title: s.title,
|
|
9931
|
+
summary: s.instruction?.slice(0, 200) || "",
|
|
9932
|
+
type: "mini-skill",
|
|
9933
|
+
entityName: s.sourceEntity || void 0,
|
|
9934
|
+
refs: [ref, ...obsRefs]
|
|
9935
|
+
};
|
|
9936
|
+
}
|
|
9937
|
+
function buildGitSection(observations2) {
|
|
9938
|
+
const gitObs = observations2.filter(
|
|
9939
|
+
(o) => o.source === "git" && o.sourceDetail === "git-ingest"
|
|
9940
|
+
);
|
|
9941
|
+
const items = gitObs.map(obsToItem);
|
|
9942
|
+
return {
|
|
9943
|
+
id: "git-backed-facts",
|
|
9944
|
+
title: "Git-backed Facts",
|
|
9945
|
+
items,
|
|
9946
|
+
empty: items.length === 0
|
|
9947
|
+
};
|
|
9948
|
+
}
|
|
9949
|
+
function buildSkillsSection(skills) {
|
|
9950
|
+
const items = skills.map(skillToItem);
|
|
9951
|
+
return {
|
|
9952
|
+
id: "promoted-skills",
|
|
9953
|
+
title: "Promoted Skills",
|
|
9954
|
+
items,
|
|
9955
|
+
empty: items.length === 0
|
|
9956
|
+
};
|
|
9957
|
+
}
|
|
9958
|
+
function buildProjectOverview(projectId, eligibleObs, skills) {
|
|
9959
|
+
const refs = [
|
|
9960
|
+
...eligibleObs.slice(0, 5).map((o) => ({
|
|
9961
|
+
kind: o.source === "git" ? "git" : "observation",
|
|
9962
|
+
id: `obs:${o.id}`,
|
|
9963
|
+
title: o.title
|
|
9964
|
+
})),
|
|
9965
|
+
...skills.slice(0, 5).map((s) => ({
|
|
9966
|
+
kind: "mini-skill",
|
|
9967
|
+
id: `skill:${s.id}`,
|
|
9968
|
+
title: s.title
|
|
9969
|
+
}))
|
|
9970
|
+
];
|
|
9971
|
+
if (refs.length === 0) {
|
|
9972
|
+
return {
|
|
9973
|
+
id: "project-overview",
|
|
9974
|
+
title: "Project Overview",
|
|
9975
|
+
items: [],
|
|
9976
|
+
empty: true
|
|
9977
|
+
};
|
|
9978
|
+
}
|
|
9979
|
+
const lines = [];
|
|
9980
|
+
lines.push(`Project: ${projectId}`);
|
|
9981
|
+
lines.push(`Observations in KB: ${eligibleObs.length}`);
|
|
9982
|
+
lines.push(`Promoted skills: ${skills.length}`);
|
|
9983
|
+
const entityCounts = /* @__PURE__ */ new Map();
|
|
9984
|
+
for (const o of eligibleObs) {
|
|
9985
|
+
if (o.entityName) {
|
|
9986
|
+
entityCounts.set(o.entityName, (entityCounts.get(o.entityName) || 0) + 1);
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9989
|
+
const topEntities = [...entityCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
9990
|
+
if (topEntities.length > 0) {
|
|
9991
|
+
lines.push(`Top entities: ${topEntities.map(([name, count2]) => `${name} (${count2})`).join(", ")}`);
|
|
9992
|
+
}
|
|
9993
|
+
return {
|
|
9994
|
+
id: "project-overview",
|
|
9995
|
+
title: "Project Overview",
|
|
9996
|
+
items: [{
|
|
9997
|
+
title: projectId,
|
|
9998
|
+
summary: lines.join("\n"),
|
|
9999
|
+
type: "overview",
|
|
10000
|
+
refs
|
|
10001
|
+
}]
|
|
10002
|
+
};
|
|
10003
|
+
}
|
|
10004
|
+
function generateKnowledgeBase(options) {
|
|
10005
|
+
const { projectId, observations: observations2, miniSkills } = options;
|
|
10006
|
+
const eligible = observations2.filter((o) => isEligible(o, projectId));
|
|
10007
|
+
const scopedMiniSkills = miniSkills.filter((s) => s.projectId === projectId);
|
|
10008
|
+
const typedSections = SECTION_DEFS.map((def) => {
|
|
10009
|
+
const matched = eligible.filter(def.typeMatch);
|
|
10010
|
+
const items = matched.map(obsToItem);
|
|
10011
|
+
return {
|
|
10012
|
+
id: def.id,
|
|
10013
|
+
title: def.title,
|
|
10014
|
+
items,
|
|
10015
|
+
empty: items.length === 0
|
|
10016
|
+
};
|
|
10017
|
+
});
|
|
10018
|
+
const projectOverview = buildProjectOverview(projectId, eligible, scopedMiniSkills);
|
|
10019
|
+
const gitSection = buildGitSection(eligible);
|
|
10020
|
+
const skillsSection = buildSkillsSection(scopedMiniSkills);
|
|
10021
|
+
const sections = [
|
|
10022
|
+
projectOverview,
|
|
10023
|
+
...typedSections,
|
|
10024
|
+
gitSection,
|
|
10025
|
+
skillsSection
|
|
10026
|
+
];
|
|
10027
|
+
const allRefs = sections.flatMap((s) => s.items.flatMap((i) => i.refs));
|
|
10028
|
+
const obsRefCount = allRefs.filter((r) => r.kind === "observation" || r.kind === "git").length;
|
|
10029
|
+
const skillRefCount = allRefs.filter((r) => r.kind === "mini-skill").length;
|
|
10030
|
+
return {
|
|
10031
|
+
title: "Knowledge Base",
|
|
10032
|
+
subtitle: "LLM Wiki",
|
|
10033
|
+
projectId,
|
|
10034
|
+
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
10035
|
+
sections,
|
|
10036
|
+
stats: {
|
|
10037
|
+
observationsUsed: eligible.length,
|
|
10038
|
+
miniSkillsUsed: scopedMiniSkills.length,
|
|
10039
|
+
refs: obsRefCount + skillRefCount
|
|
10040
|
+
}
|
|
10041
|
+
};
|
|
10042
|
+
}
|
|
10043
|
+
var COMMAND_LOG_TITLE3, SECTION_DEFS;
|
|
10044
|
+
var init_generator = __esm({
|
|
10045
|
+
"src/wiki/generator.ts"() {
|
|
10046
|
+
"use strict";
|
|
10047
|
+
init_esm_shims();
|
|
10048
|
+
COMMAND_LOG_TITLE3 = /^(Ran:|Command:|Executed:)\s/i;
|
|
10049
|
+
SECTION_DEFS = [
|
|
10050
|
+
{
|
|
10051
|
+
id: "core-decisions",
|
|
10052
|
+
title: "Core Decisions",
|
|
10053
|
+
typeMatch: (o) => o.type === "decision" || o.type === "trade-off" || o.type === "reasoning"
|
|
10054
|
+
},
|
|
10055
|
+
{
|
|
10056
|
+
id: "operational-knowledge",
|
|
10057
|
+
title: "Operational Knowledge",
|
|
10058
|
+
typeMatch: (o) => o.type === "how-it-works" || o.type === "what-changed" || o.type === "why-it-exists" || o.type === "discovery" || o.type === "session-request"
|
|
10059
|
+
},
|
|
10060
|
+
{
|
|
10061
|
+
id: "known-gotchas",
|
|
10062
|
+
title: "Known Gotchas",
|
|
10063
|
+
typeMatch: (o) => o.type === "gotcha" || o.type === "problem-solution"
|
|
10064
|
+
}
|
|
10065
|
+
];
|
|
10066
|
+
}
|
|
10067
|
+
});
|
|
10068
|
+
|
|
10069
|
+
// src/wiki/knowledge-graph.ts
|
|
10070
|
+
var knowledge_graph_exports = {};
|
|
10071
|
+
__export(knowledge_graph_exports, {
|
|
10072
|
+
generateKnowledgeGraph: () => generateKnowledgeGraph
|
|
10073
|
+
});
|
|
10074
|
+
function inferEdges(nodes, entityNameIndex) {
|
|
10075
|
+
const edges = [];
|
|
10076
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10077
|
+
const maxRelatesEdgesPerEntitySection = 8;
|
|
10078
|
+
function addEdge(source, target, edgeType) {
|
|
10079
|
+
const key = `${source}:${edgeType}:${target}`;
|
|
10080
|
+
if (seen.has(key)) return;
|
|
10081
|
+
if (source === target) return;
|
|
10082
|
+
seen.add(key);
|
|
10083
|
+
edges.push({
|
|
10084
|
+
id: `e_${edges.length}_${source}_${target}`,
|
|
10085
|
+
source,
|
|
10086
|
+
target,
|
|
10087
|
+
edgeType
|
|
10088
|
+
});
|
|
10089
|
+
}
|
|
10090
|
+
function rankNodesForEntity(a, b) {
|
|
10091
|
+
const evidenceDiff = (b.evidenceCount || 0) - (a.evidenceCount || 0);
|
|
10092
|
+
if (evidenceDiff !== 0) return evidenceDiff;
|
|
10093
|
+
return a.id.localeCompare(b.id);
|
|
10094
|
+
}
|
|
10095
|
+
for (const [, group] of entityNameIndex) {
|
|
10096
|
+
if (group.length < 2) continue;
|
|
10097
|
+
const bySection = /* @__PURE__ */ new Map();
|
|
10098
|
+
for (const node of group) {
|
|
10099
|
+
const sectionGroup = bySection.get(node.sectionId) || [];
|
|
10100
|
+
sectionGroup.push(node);
|
|
10101
|
+
bySection.set(node.sectionId, sectionGroup);
|
|
10102
|
+
}
|
|
10103
|
+
for (const sectionGroup of bySection.values()) {
|
|
10104
|
+
const ranked = [...sectionGroup].sort(rankNodesForEntity);
|
|
10105
|
+
if (ranked.length === 2) {
|
|
10106
|
+
addEdge(ranked[0].id, ranked[1].id, "relates_to");
|
|
10107
|
+
addEdge(ranked[1].id, ranked[0].id, "relates_to");
|
|
10108
|
+
continue;
|
|
10109
|
+
}
|
|
10110
|
+
const anchor = ranked[0];
|
|
10111
|
+
for (const node of ranked.slice(1, maxRelatesEdgesPerEntitySection + 1)) {
|
|
10112
|
+
addEdge(anchor.id, node.id, "relates_to");
|
|
10113
|
+
}
|
|
10114
|
+
}
|
|
10115
|
+
const sectionAnchors = [...bySection.entries()].map(([sectionId, sectionGroup]) => ({
|
|
10116
|
+
sectionId,
|
|
10117
|
+
anchor: [...sectionGroup].sort(rankNodesForEntity)[0]
|
|
10118
|
+
})).sort((a, b) => sectionPriority(a.sectionId) - sectionPriority(b.sectionId));
|
|
10119
|
+
for (let i = 0; i < sectionAnchors.length; i++) {
|
|
10120
|
+
for (let j = i + 1; j < sectionAnchors.length; j++) {
|
|
10121
|
+
const from = sectionAnchors[i].anchor;
|
|
10122
|
+
const to = sectionAnchors[j].anchor;
|
|
10123
|
+
const edgeType = sectionPriority(sectionAnchors[i].sectionId) === sectionPriority(sectionAnchors[j].sectionId) ? "relates_to" : "supports";
|
|
10124
|
+
addEdge(from.id, to.id, edgeType);
|
|
10125
|
+
}
|
|
10126
|
+
}
|
|
10127
|
+
}
|
|
10128
|
+
return edges;
|
|
10129
|
+
}
|
|
10130
|
+
function sectionPriority(sectionId) {
|
|
10131
|
+
const order = ["core-decisions", "known-gotchas", "operational-knowledge", "git-backed-facts", "promoted-skills"];
|
|
10132
|
+
const idx = order.indexOf(sectionId);
|
|
10133
|
+
return idx >= 0 ? idx : order.length;
|
|
10134
|
+
}
|
|
10135
|
+
function sectionIdForObs(o) {
|
|
10136
|
+
if (GIT_SECTION.typeMatch(o)) return GIT_SECTION.id;
|
|
10137
|
+
for (const def of SECTION_DEFS2) {
|
|
10138
|
+
if (def.typeMatch(o)) return def.id;
|
|
10139
|
+
}
|
|
10140
|
+
return "operational-knowledge";
|
|
10141
|
+
}
|
|
10142
|
+
function mapRelationType(relationType) {
|
|
10143
|
+
const lower = relationType.toLowerCase();
|
|
10144
|
+
if (lower.includes("support") || lower.includes("depend")) return "supports";
|
|
10145
|
+
if (lower.includes("relat") || lower.includes("connect") || lower.includes("associat")) return "relates_to";
|
|
10146
|
+
if (lower.includes("mention") || lower.includes("refer")) return "mentions";
|
|
10147
|
+
if (lower.includes("deriv") || lower.includes("origin") || lower.includes("source")) return "derived_from";
|
|
10148
|
+
return "relates_to";
|
|
10149
|
+
}
|
|
10150
|
+
function generateKnowledgeGraph(options) {
|
|
10151
|
+
const { projectId, observations: observations2, miniSkills, graphEntities, graphRelations } = options;
|
|
10152
|
+
const eligible = observations2.filter((o) => isEligible(o, projectId));
|
|
10153
|
+
const scopedMiniSkills = miniSkills.filter((s) => s.projectId === projectId);
|
|
10154
|
+
const nodes = [];
|
|
10155
|
+
const entityNameIndex = /* @__PURE__ */ new Map();
|
|
10156
|
+
for (const o of eligible) {
|
|
10157
|
+
const sectionId = sectionIdForObs(o);
|
|
10158
|
+
const ref = {
|
|
10159
|
+
kind: o.source === "git" ? "git" : "observation",
|
|
10160
|
+
id: `obs:${o.id}`,
|
|
10161
|
+
title: o.title
|
|
10162
|
+
};
|
|
10163
|
+
const node = {
|
|
10164
|
+
id: `obs:${o.id}`,
|
|
10165
|
+
label: o.title,
|
|
10166
|
+
nodeType: o.type,
|
|
10167
|
+
sectionId,
|
|
10168
|
+
entityName: o.entityName || void 0,
|
|
10169
|
+
evidenceCount: (o.facts?.length ?? 0) + (o.concepts?.length ?? 0) + (o.filesModified?.length ?? 0),
|
|
10170
|
+
summary: o.narrative?.slice(0, 200) || "",
|
|
10171
|
+
refs: [ref]
|
|
10172
|
+
};
|
|
10173
|
+
nodes.push(node);
|
|
10174
|
+
if (o.entityName) {
|
|
10175
|
+
const group = entityNameIndex.get(o.entityName) || [];
|
|
10176
|
+
group.push(node);
|
|
10177
|
+
entityNameIndex.set(o.entityName, group);
|
|
10178
|
+
}
|
|
10179
|
+
}
|
|
10180
|
+
for (const s of scopedMiniSkills) {
|
|
10181
|
+
const ref = {
|
|
10182
|
+
kind: "mini-skill",
|
|
10183
|
+
id: `skill:${s.id}`,
|
|
10184
|
+
title: s.title
|
|
10185
|
+
};
|
|
10186
|
+
const obsRefs = s.sourceObservationIds.map(
|
|
10187
|
+
(oid) => ({ kind: "observation", id: `obs:${oid}` })
|
|
10188
|
+
);
|
|
10189
|
+
const node = {
|
|
10190
|
+
id: `skill:${s.id}`,
|
|
10191
|
+
label: s.title,
|
|
10192
|
+
nodeType: "mini-skill",
|
|
10193
|
+
sectionId: "promoted-skills",
|
|
10194
|
+
entityName: s.sourceEntity || void 0,
|
|
10195
|
+
evidenceCount: obsRefs.length,
|
|
10196
|
+
summary: s.instruction?.slice(0, 200) || "",
|
|
10197
|
+
refs: [ref, ...obsRefs]
|
|
10198
|
+
};
|
|
10199
|
+
nodes.push(node);
|
|
10200
|
+
if (s.sourceEntity) {
|
|
10201
|
+
const group = entityNameIndex.get(s.sourceEntity) || [];
|
|
10202
|
+
group.push(node);
|
|
10203
|
+
entityNameIndex.set(s.sourceEntity, group);
|
|
10204
|
+
}
|
|
10205
|
+
}
|
|
10206
|
+
const edges = inferEdges(nodes, entityNameIndex);
|
|
10207
|
+
for (const s of scopedMiniSkills) {
|
|
10208
|
+
const skillNodeId = `skill:${s.id}`;
|
|
10209
|
+
for (const oid of s.sourceObservationIds) {
|
|
10210
|
+
const obsNodeId = `obs:${oid}`;
|
|
10211
|
+
if (nodes.some((n) => n.id === obsNodeId)) {
|
|
10212
|
+
edges.push({
|
|
10213
|
+
id: `e_${edges.length}_${skillNodeId}_${obsNodeId}`,
|
|
10214
|
+
source: skillNodeId,
|
|
10215
|
+
target: obsNodeId,
|
|
10216
|
+
edgeType: "derived_from"
|
|
10217
|
+
});
|
|
10218
|
+
}
|
|
10219
|
+
}
|
|
10220
|
+
}
|
|
10221
|
+
if (graphRelations && graphRelations.length > 0) {
|
|
10222
|
+
const entityNodeMap = /* @__PURE__ */ new Map();
|
|
10223
|
+
for (const n of nodes) {
|
|
10224
|
+
if (n.entityName && !entityNodeMap.has(n.entityName)) {
|
|
10225
|
+
entityNodeMap.set(n.entityName, n.id);
|
|
10226
|
+
}
|
|
10227
|
+
}
|
|
10228
|
+
const seen = new Set(edges.map((e) => `${e.source}:${e.edgeType}:${e.target}`));
|
|
10229
|
+
for (const rel of graphRelations) {
|
|
10230
|
+
const srcId = entityNodeMap.get(rel.from);
|
|
10231
|
+
const tgtId = entityNodeMap.get(rel.to);
|
|
10232
|
+
if (!srcId || !tgtId) continue;
|
|
10233
|
+
if (srcId === tgtId) continue;
|
|
10234
|
+
const edgeType = mapRelationType(rel.relationType);
|
|
10235
|
+
const key = `${srcId}:${edgeType}:${tgtId}`;
|
|
10236
|
+
if (seen.has(key)) continue;
|
|
10237
|
+
seen.add(key);
|
|
10238
|
+
edges.push({
|
|
10239
|
+
id: `e_gr_${edges.length}_${srcId}_${tgtId}`,
|
|
10240
|
+
source: srcId,
|
|
10241
|
+
target: tgtId,
|
|
10242
|
+
edgeType
|
|
10243
|
+
});
|
|
10244
|
+
}
|
|
10245
|
+
}
|
|
10246
|
+
const sectionCounts = {};
|
|
10247
|
+
for (const n of nodes) {
|
|
10248
|
+
sectionCounts[n.sectionId] = (sectionCounts[n.sectionId] || 0) + 1;
|
|
10249
|
+
}
|
|
10250
|
+
const clusters = ALL_SECTIONS.filter((def) => (sectionCounts[def.id] ?? 0) > 0).map((def) => ({
|
|
10251
|
+
id: `cluster:${def.id}`,
|
|
10252
|
+
label: def.label,
|
|
10253
|
+
sectionId: def.id,
|
|
10254
|
+
nodeCount: sectionCounts[def.id] ?? 0
|
|
10255
|
+
}));
|
|
10256
|
+
const stats = {
|
|
10257
|
+
totalNodes: nodes.length,
|
|
10258
|
+
totalEdges: edges.length,
|
|
10259
|
+
clusterCount: clusters.length,
|
|
10260
|
+
sectionCounts
|
|
10261
|
+
};
|
|
10262
|
+
return {
|
|
10263
|
+
title: "Knowledge Graph",
|
|
10264
|
+
projectId,
|
|
10265
|
+
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
10266
|
+
nodes,
|
|
10267
|
+
edges,
|
|
10268
|
+
clusters,
|
|
10269
|
+
stats
|
|
10270
|
+
};
|
|
10271
|
+
}
|
|
10272
|
+
var SECTION_DEFS2, GIT_SECTION, SKILLS_SECTION, ALL_SECTIONS;
|
|
10273
|
+
var init_knowledge_graph = __esm({
|
|
10274
|
+
"src/wiki/knowledge-graph.ts"() {
|
|
10275
|
+
"use strict";
|
|
10276
|
+
init_esm_shims();
|
|
10277
|
+
init_generator();
|
|
10278
|
+
SECTION_DEFS2 = [
|
|
10279
|
+
{
|
|
10280
|
+
id: "core-decisions",
|
|
10281
|
+
label: "Core Decisions",
|
|
10282
|
+
typeMatch: (o) => o.type === "decision" || o.type === "trade-off" || o.type === "reasoning"
|
|
10283
|
+
},
|
|
10284
|
+
{
|
|
10285
|
+
id: "operational-knowledge",
|
|
10286
|
+
label: "Operational Knowledge",
|
|
10287
|
+
typeMatch: (o) => o.type === "how-it-works" || o.type === "what-changed" || o.type === "why-it-exists" || o.type === "discovery" || o.type === "session-request"
|
|
10288
|
+
},
|
|
10289
|
+
{
|
|
10290
|
+
id: "known-gotchas",
|
|
10291
|
+
label: "Known Gotchas",
|
|
10292
|
+
typeMatch: (o) => o.type === "gotcha" || o.type === "problem-solution"
|
|
10293
|
+
}
|
|
10294
|
+
];
|
|
10295
|
+
GIT_SECTION = {
|
|
10296
|
+
id: "git-backed-facts",
|
|
10297
|
+
label: "Git-backed Facts",
|
|
10298
|
+
typeMatch: (o) => o.source === "git" && o.sourceDetail === "git-ingest"
|
|
10299
|
+
};
|
|
10300
|
+
SKILLS_SECTION = {
|
|
10301
|
+
id: "promoted-skills",
|
|
10302
|
+
label: "Promoted Skills",
|
|
10303
|
+
typeMatch: () => false
|
|
10304
|
+
// skills handled separately
|
|
10305
|
+
};
|
|
10306
|
+
ALL_SECTIONS = [...SECTION_DEFS2, GIT_SECTION, SKILLS_SECTION];
|
|
10307
|
+
}
|
|
10308
|
+
});
|
|
10309
|
+
|
|
9776
10310
|
// src/dashboard/server.ts
|
|
9777
10311
|
var server_exports = {};
|
|
9778
10312
|
__export(server_exports, {
|
|
10313
|
+
prepareDashboardConfig: () => prepareDashboardConfig,
|
|
9779
10314
|
startDashboard: () => startDashboard
|
|
9780
10315
|
});
|
|
9781
10316
|
import { createServer } from "http";
|
|
@@ -9801,6 +10336,25 @@ function isActiveStatus(status) {
|
|
|
9801
10336
|
function filterActiveByProject(items, projectId) {
|
|
9802
10337
|
return items.filter((item) => item.projectId === projectId && isActiveStatus(item.status));
|
|
9803
10338
|
}
|
|
10339
|
+
function prepareDashboardConfig(projectRoot) {
|
|
10340
|
+
if (!projectRoot) {
|
|
10341
|
+
if (preparedDashboardProjectRoot !== null) {
|
|
10342
|
+
resetDotenv();
|
|
10343
|
+
preparedDashboardProjectRoot = null;
|
|
10344
|
+
}
|
|
10345
|
+
clearProjectRoot();
|
|
10346
|
+
return;
|
|
10347
|
+
}
|
|
10348
|
+
try {
|
|
10349
|
+
if (preparedDashboardProjectRoot !== null && preparedDashboardProjectRoot !== projectRoot) {
|
|
10350
|
+
resetDotenv();
|
|
10351
|
+
}
|
|
10352
|
+
initProjectRoot(projectRoot);
|
|
10353
|
+
loadDotenv(projectRoot);
|
|
10354
|
+
preparedDashboardProjectRoot = projectRoot;
|
|
10355
|
+
} catch {
|
|
10356
|
+
}
|
|
10357
|
+
}
|
|
9804
10358
|
function computeProjectGraphCounts(allEntities, allRelations, projectObs) {
|
|
9805
10359
|
const entityNames = new Set(
|
|
9806
10360
|
projectObs.filter((o) => (o.status ?? "active") === "active" && o.entityName).map((o) => o.entityName)
|
|
@@ -9826,6 +10380,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9826
10380
|
effectiveProjectResolved = true;
|
|
9827
10381
|
effectiveProjectRoot = null;
|
|
9828
10382
|
}
|
|
10383
|
+
prepareDashboardConfig(effectiveProjectRoot);
|
|
9829
10384
|
try {
|
|
9830
10385
|
switch (apiPath) {
|
|
9831
10386
|
case "/projects": {
|
|
@@ -9914,6 +10469,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9914
10469
|
const typeCounts = {};
|
|
9915
10470
|
for (const obs of observations2) {
|
|
9916
10471
|
const t = obs.type || "unknown";
|
|
10472
|
+
if (t === "probe") continue;
|
|
9917
10473
|
typeCounts[t] = (typeCounts[t] || 0) + 1;
|
|
9918
10474
|
}
|
|
9919
10475
|
const sourceCounts = { git: 0, agent: 0, manual: 0 };
|
|
@@ -9955,7 +10511,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9955
10511
|
else if (score >= 1) retentionSummary.stale++;
|
|
9956
10512
|
else retentionSummary.archive++;
|
|
9957
10513
|
}
|
|
9958
|
-
const sorted = [...observations2].sort((a, b) => (b.id || 0) - (a.id || 0)).slice(0, 10);
|
|
10514
|
+
const sorted = [...observations2].filter((o) => o.type !== "probe").sort((a, b) => (b.id || 0) - (a.id || 0)).slice(0, 10);
|
|
9959
10515
|
let embeddingStatus = { enabled: false, provider: "", dimensions: 0 };
|
|
9960
10516
|
try {
|
|
9961
10517
|
const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
|
|
@@ -9995,7 +10551,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
9995
10551
|
const allObs = await getObservationStore().loadAll();
|
|
9996
10552
|
const observations2 = filterActiveByProject(allObs, effectiveProjectId);
|
|
9997
10553
|
const now = Date.now();
|
|
9998
|
-
const scored = observations2.map((obs) => {
|
|
10554
|
+
const scored = observations2.filter((obs) => obs.type !== "probe").map((obs) => {
|
|
9999
10555
|
const age = now - new Date(obs.createdAt || now).getTime();
|
|
10000
10556
|
const ageHours = age / (1e3 * 60 * 60);
|
|
10001
10557
|
const importance = obs.importance ?? 5;
|
|
@@ -10027,6 +10583,50 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
10027
10583
|
});
|
|
10028
10584
|
break;
|
|
10029
10585
|
}
|
|
10586
|
+
case "/knowledge": {
|
|
10587
|
+
const { generateKnowledgeBase: generateKnowledgeBase2 } = await Promise.resolve().then(() => (init_generator(), generator_exports));
|
|
10588
|
+
const { initObservations: initObservations2, getAllObservations: getAllObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
10589
|
+
const { initMiniSkillStore: initMiniSkillStore2, getMiniSkillStore: getMiniSkillStore2 } = await Promise.resolve().then(() => (init_mini_skill_store(), mini_skill_store_exports));
|
|
10590
|
+
await initObservations2(effectiveDataDir);
|
|
10591
|
+
await initMiniSkillStore2(effectiveDataDir);
|
|
10592
|
+
const allObs = getAllObservations2();
|
|
10593
|
+
const skills = await getMiniSkillStore2().loadByProject(effectiveProjectId);
|
|
10594
|
+
const overview = generateKnowledgeBase2({
|
|
10595
|
+
projectId: effectiveProjectId,
|
|
10596
|
+
observations: allObs,
|
|
10597
|
+
miniSkills: skills
|
|
10598
|
+
});
|
|
10599
|
+
sendJson(res, overview);
|
|
10600
|
+
break;
|
|
10601
|
+
}
|
|
10602
|
+
case "/knowledge-graph": {
|
|
10603
|
+
const { generateKnowledgeGraph: generateKnowledgeGraph2 } = await Promise.resolve().then(() => (init_knowledge_graph(), knowledge_graph_exports));
|
|
10604
|
+
const { initObservations: initObservations2, getAllObservations: getAllObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
10605
|
+
const { initMiniSkillStore: initMiniSkillStore2, getMiniSkillStore: getMiniSkillStore2 } = await Promise.resolve().then(() => (init_mini_skill_store(), mini_skill_store_exports));
|
|
10606
|
+
const { initGraphStore: initGraphStore2, getGraphStore: getGraphStore2 } = await Promise.resolve().then(() => (init_graph_store(), graph_store_exports));
|
|
10607
|
+
await initObservations2(effectiveDataDir);
|
|
10608
|
+
await initMiniSkillStore2(effectiveDataDir);
|
|
10609
|
+
await initGraphStore2(effectiveDataDir);
|
|
10610
|
+
const allObs = getAllObservations2();
|
|
10611
|
+
const skills = await getMiniSkillStore2().loadByProject(effectiveProjectId);
|
|
10612
|
+
const fullGraph = { entities: getGraphStore2().loadEntities(), relations: getGraphStore2().loadRelations() };
|
|
10613
|
+
const graphObs = await getObservationStore().loadAll();
|
|
10614
|
+
const projectEntityNames = new Set(
|
|
10615
|
+
graphObs.filter((o) => o.projectId === effectiveProjectId && (o.status ?? "active") === "active" && o.entityName).map((o) => o.entityName)
|
|
10616
|
+
);
|
|
10617
|
+
const scopedEntities = fullGraph.entities.filter((e) => projectEntityNames.has(e.name));
|
|
10618
|
+
const scopedEntityNameSet = new Set(scopedEntities.map((e) => e.name));
|
|
10619
|
+
const scopedRelations = fullGraph.relations.filter((r) => scopedEntityNameSet.has(r.from) && scopedEntityNameSet.has(r.to));
|
|
10620
|
+
const graph = generateKnowledgeGraph2({
|
|
10621
|
+
projectId: effectiveProjectId,
|
|
10622
|
+
observations: allObs,
|
|
10623
|
+
miniSkills: skills,
|
|
10624
|
+
graphEntities: scopedEntities,
|
|
10625
|
+
graphRelations: scopedRelations
|
|
10626
|
+
});
|
|
10627
|
+
sendJson(res, graph);
|
|
10628
|
+
break;
|
|
10629
|
+
}
|
|
10030
10630
|
case "/config": {
|
|
10031
10631
|
const os4 = await import("os");
|
|
10032
10632
|
const { existsSync: existsSync10 } = await import("fs");
|
|
@@ -10035,7 +10635,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
10035
10635
|
const configProjectRoot = effectiveProjectRoot;
|
|
10036
10636
|
try {
|
|
10037
10637
|
const { loadYamlConfig: loadYamlConfig2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
|
|
10038
|
-
yml = loadYamlConfig2();
|
|
10638
|
+
yml = configProjectRoot ? loadYamlConfig2(configProjectRoot) : loadYamlConfig2(null);
|
|
10039
10639
|
} catch {
|
|
10040
10640
|
}
|
|
10041
10641
|
if (configProjectRoot) {
|
|
@@ -10098,6 +10698,19 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
10098
10698
|
} else {
|
|
10099
10699
|
values.push({ key: "llm.apiKey", value: "not set", source: "none" });
|
|
10100
10700
|
}
|
|
10701
|
+
const agentProvider = process.env.MEMORIX_AGENT_LLM_PROVIDER || yml.agent?.provider;
|
|
10702
|
+
if (agentProvider) values.push({ key: "agent.llm.provider", value: agentProvider, source: await getEnvSource("MEMORIX_AGENT_LLM_PROVIDER", yml.agent?.provider ? "memorix.yml" : void 0) });
|
|
10703
|
+
const agentModel = process.env.MEMORIX_AGENT_LLM_MODEL || yml.agent?.model;
|
|
10704
|
+
if (agentModel) values.push({ key: "agent.llm.model", value: agentModel, source: await getEnvSource("MEMORIX_AGENT_LLM_MODEL", yml.agent?.model ? "memorix.yml" : void 0) });
|
|
10705
|
+
const agentKey = process.env.MEMORIX_AGENT_LLM_API_KEY || yml.agent?.apiKey;
|
|
10706
|
+
if (agentKey) {
|
|
10707
|
+
let src = "unknown";
|
|
10708
|
+
if (process.env.MEMORIX_AGENT_LLM_API_KEY) src = await getEnvSource("MEMORIX_AGENT_LLM_API_KEY");
|
|
10709
|
+
else if (yml.agent?.apiKey) src = "memorix.yml (move to .env!)";
|
|
10710
|
+
values.push({ key: "agent.llm.apiKey", value: "****" + agentKey.slice(-4), source: src, sensitive: true });
|
|
10711
|
+
} else {
|
|
10712
|
+
values.push({ key: "agent.llm.apiKey", value: "fallback to llm.apiKey", source: "default" });
|
|
10713
|
+
}
|
|
10101
10714
|
const embProvider = process.env.MEMORIX_EMBEDDING || yml.embedding?.provider || "off";
|
|
10102
10715
|
values.push({ key: "embedding.provider", value: embProvider, source: await getEnvSource("MEMORIX_EMBEDDING", yml.embedding?.provider ? "memorix.yml" : void 0) });
|
|
10103
10716
|
values.push({ key: "git.autoHook", value: String(yml.git?.autoHook ?? false), source: yml.git?.autoHook !== void 0 ? "memorix.yml" : "default" });
|
|
@@ -10263,13 +10876,20 @@ async function serveStatic(req, res, staticDir) {
|
|
|
10263
10876
|
const ext = path14.extname(filePath);
|
|
10264
10877
|
res.writeHead(200, {
|
|
10265
10878
|
"Content-Type": MIME_TYPES[ext] || "application/octet-stream",
|
|
10266
|
-
"Cache-Control": "no-cache"
|
|
10879
|
+
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
10880
|
+
"Pragma": "no-cache",
|
|
10881
|
+
"Expires": "0"
|
|
10267
10882
|
});
|
|
10268
10883
|
res.end(data);
|
|
10269
10884
|
} catch {
|
|
10270
10885
|
try {
|
|
10271
10886
|
const indexData = await fs12.readFile(path14.join(staticDir, "index.html"));
|
|
10272
|
-
res.writeHead(200, {
|
|
10887
|
+
res.writeHead(200, {
|
|
10888
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
10889
|
+
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
10890
|
+
"Pragma": "no-cache",
|
|
10891
|
+
"Expires": "0"
|
|
10892
|
+
});
|
|
10273
10893
|
res.end(indexData);
|
|
10274
10894
|
} catch {
|
|
10275
10895
|
sendError(res, "Not found", 404);
|
|
@@ -10526,7 +11146,7 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
10526
11146
|
});
|
|
10527
11147
|
});
|
|
10528
11148
|
}
|
|
10529
|
-
var MIME_TYPES;
|
|
11149
|
+
var MIME_TYPES, preparedDashboardProjectRoot;
|
|
10530
11150
|
var init_server = __esm({
|
|
10531
11151
|
"src/dashboard/server.ts"() {
|
|
10532
11152
|
"use strict";
|
|
@@ -10535,6 +11155,10 @@ var init_server = __esm({
|
|
|
10535
11155
|
init_obs_store();
|
|
10536
11156
|
init_session_store();
|
|
10537
11157
|
init_graph_store();
|
|
11158
|
+
init_dotenv_loader();
|
|
11159
|
+
init_dotenv_loader();
|
|
11160
|
+
init_yaml_loader();
|
|
11161
|
+
init_yaml_loader();
|
|
10538
11162
|
MIME_TYPES = {
|
|
10539
11163
|
".html": "text/html; charset=utf-8",
|
|
10540
11164
|
".css": "text/css; charset=utf-8",
|
|
@@ -10544,6 +11168,7 @@ var init_server = __esm({
|
|
|
10544
11168
|
".png": "image/png",
|
|
10545
11169
|
".ico": "image/x-icon"
|
|
10546
11170
|
};
|
|
11171
|
+
preparedDashboardProjectRoot = null;
|
|
10547
11172
|
}
|
|
10548
11173
|
});
|
|
10549
11174
|
|
|
@@ -11700,7 +12325,7 @@ function generateKiroHookFiles() {
|
|
|
11700
12325
|
when: { type: "promptSubmit" },
|
|
11701
12326
|
then: {
|
|
11702
12327
|
type: "askAgent",
|
|
11703
|
-
prompt: "Before responding, load context:\n1. Call
|
|
12328
|
+
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"
|
|
11704
12329
|
}
|
|
11705
12330
|
}, null, 2)
|
|
11706
12331
|
},
|
|
@@ -11740,6 +12365,8 @@ import { spawnSync } from 'node:child_process';
|
|
|
11740
12365
|
export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
11741
12366
|
// Generate a stable session ID for this plugin lifetime
|
|
11742
12367
|
const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
|
|
12368
|
+
let pendingAssistantResponse = null;
|
|
12369
|
+
let lastDeliveredAssistantKey = '';
|
|
11743
12370
|
|
|
11744
12371
|
/**
|
|
11745
12372
|
* Send event JSON to \`memorix hook\` via child_process.spawnSync.
|
|
@@ -11772,6 +12399,33 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
11772
12399
|
}
|
|
11773
12400
|
}
|
|
11774
12401
|
|
|
12402
|
+
function extractMessageInfo(input) {
|
|
12403
|
+
if (input && typeof input === 'object') {
|
|
12404
|
+
if (input.info && typeof input.info === 'object') return input.info;
|
|
12405
|
+
if (input.message && typeof input.message === 'object') return input.message;
|
|
12406
|
+
if (input.properties && typeof input.properties === 'object') {
|
|
12407
|
+
if (input.properties.info && typeof input.properties.info === 'object') return input.properties.info;
|
|
12408
|
+
if (input.properties.message && typeof input.properties.message === 'object') return input.properties.message;
|
|
12409
|
+
}
|
|
12410
|
+
}
|
|
12411
|
+
return input;
|
|
12412
|
+
}
|
|
12413
|
+
|
|
12414
|
+
function extractMessageText(message) {
|
|
12415
|
+
if (!message || typeof message !== 'object') return '';
|
|
12416
|
+
if (typeof message.content === 'string') return message.content.trim();
|
|
12417
|
+
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
12418
|
+
return parts
|
|
12419
|
+
.map((part) => {
|
|
12420
|
+
if (!part || typeof part !== 'object') return '';
|
|
12421
|
+
if (typeof part.text === 'string') return part.text;
|
|
12422
|
+
if (typeof part.content === 'string') return part.content;
|
|
12423
|
+
return '';
|
|
12424
|
+
})
|
|
12425
|
+
.join('')
|
|
12426
|
+
.trim();
|
|
12427
|
+
}
|
|
12428
|
+
|
|
11775
12429
|
return {
|
|
11776
12430
|
/** Session created \u2014 record session start */
|
|
11777
12431
|
'session.created': async ({ session }) => {
|
|
@@ -11784,6 +12438,21 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
11784
12438
|
|
|
11785
12439
|
/** Session idle \u2014 record session end */
|
|
11786
12440
|
'session.idle': async ({ session }) => {
|
|
12441
|
+
if (pendingAssistantResponse?.text) {
|
|
12442
|
+
const deliveryKey = pendingAssistantResponse.id
|
|
12443
|
+
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
12444
|
+
: pendingAssistantResponse.text;
|
|
12445
|
+
if (deliveryKey !== lastDeliveredAssistantKey) {
|
|
12446
|
+
runHook({
|
|
12447
|
+
agent: 'opencode',
|
|
12448
|
+
hook_event_name: 'message.updated',
|
|
12449
|
+
ai_response: pendingAssistantResponse.text,
|
|
12450
|
+
message_id: pendingAssistantResponse.id,
|
|
12451
|
+
cwd: directory,
|
|
12452
|
+
});
|
|
12453
|
+
lastDeliveredAssistantKey = deliveryKey;
|
|
12454
|
+
}
|
|
12455
|
+
}
|
|
11787
12456
|
runHook({
|
|
11788
12457
|
agent: 'opencode',
|
|
11789
12458
|
hook_event_name: 'session.idle',
|
|
@@ -11812,6 +12481,19 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
11812
12481
|
});
|
|
11813
12482
|
},
|
|
11814
12483
|
|
|
12484
|
+
/** Message updated \u2014 cache the latest assistant response until session.idle */
|
|
12485
|
+
'message.updated': async (input, output) => {
|
|
12486
|
+
const message = extractMessageInfo(input);
|
|
12487
|
+
const role = message?.role ?? input?.role ?? input?.info?.role;
|
|
12488
|
+
if (role !== 'assistant') return;
|
|
12489
|
+
const text = extractMessageText(message);
|
|
12490
|
+
if (!text) return;
|
|
12491
|
+
pendingAssistantResponse = {
|
|
12492
|
+
id: message?.id ?? input?.id ?? input?.messageID,
|
|
12493
|
+
text,
|
|
12494
|
+
};
|
|
12495
|
+
},
|
|
12496
|
+
|
|
11815
12497
|
/** Session compacted \u2014 record post-compact event */
|
|
11816
12498
|
'session.compacted': async ({ session }) => {
|
|
11817
12499
|
runHook({
|
|
@@ -12061,7 +12743,7 @@ async function installHooks(agent, projectRoot, global = false) {
|
|
|
12061
12743
|
return {
|
|
12062
12744
|
agent,
|
|
12063
12745
|
configPath: pluginPath,
|
|
12064
|
-
events: ["session_start", "session_end", "post_tool", "post_edit", "post_compact", "post_command"],
|
|
12746
|
+
events: ["session_start", "session_end", "post_tool", "post_edit", "post_compact", "post_command", "post_response"],
|
|
12065
12747
|
generated: { note: "OpenCode plugin installed at " + pluginPath }
|
|
12066
12748
|
};
|
|
12067
12749
|
}
|
|
@@ -12254,20 +12936,18 @@ alwaysApply: true
|
|
|
12254
12936
|
|
|
12255
12937
|
You have access to Memorix memory tools. Follow these rules to maintain persistent context across sessions.
|
|
12256
12938
|
|
|
12257
|
-
## RULE 1:
|
|
12939
|
+
## RULE 1: Use Memory When Useful
|
|
12258
12940
|
|
|
12259
|
-
At the
|
|
12941
|
+
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.
|
|
12260
12942
|
|
|
12261
|
-
1. Call \`
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
3. If search results are found, use \`memorix_detail\` to fetch the most relevant ones
|
|
12267
|
-
4. Reference relevant memories naturally \u2014 the user should feel you "remember" them
|
|
12943
|
+
1. Call \`memorix_search\` with a query related to the user's first message or current task.
|
|
12944
|
+
2. If search results are found, use \`memorix_detail\` to fetch the most relevant ones.
|
|
12945
|
+
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.
|
|
12946
|
+
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.
|
|
12947
|
+
5. Reference relevant memories naturally \u2014 the user should feel you understand the project, not that you are following a ritual.
|
|
12268
12948
|
|
|
12269
12949
|
**Important:** \`projectRoot\` is a detection anchor only; Git remains the source of truth for project identity.
|
|
12270
|
-
In HTTP control-plane mode (\`memorix serve-http\` / \`memorix background start\`), explicit \`projectRoot\` binding is required for correct multi-project isolation.
|
|
12950
|
+
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.
|
|
12271
12951
|
\`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.
|
|
12272
12952
|
|
|
12273
12953
|
## RULE 2: Store Important Context
|
|
@@ -12519,7 +13199,7 @@ var init_installers = __esm({
|
|
|
12519
13199
|
"src/hooks/installers/index.ts"() {
|
|
12520
13200
|
"use strict";
|
|
12521
13201
|
init_esm_shims();
|
|
12522
|
-
OPENCODE_PLUGIN_VERSION =
|
|
13202
|
+
OPENCODE_PLUGIN_VERSION = 6;
|
|
12523
13203
|
}
|
|
12524
13204
|
});
|
|
12525
13205
|
|
|
@@ -12961,7 +13641,8 @@ function getTypeIcon(type) {
|
|
|
12961
13641
|
"why-it-exists": "[WHY]",
|
|
12962
13642
|
"decision": "[DECISION]",
|
|
12963
13643
|
"trade-off": "[TRADEOFF]",
|
|
12964
|
-
"reasoning": "[REASONING]"
|
|
13644
|
+
"reasoning": "[REASONING]",
|
|
13645
|
+
"probe": "[PROBE]"
|
|
12965
13646
|
};
|
|
12966
13647
|
return icons[type] ?? "[UNKNOWN]";
|
|
12967
13648
|
}
|
|
@@ -13022,7 +13703,18 @@ init_mini_skills();
|
|
|
13022
13703
|
init_secret_filter();
|
|
13023
13704
|
async function compactSearch(options) {
|
|
13024
13705
|
const entries = await searchObservations(options);
|
|
13025
|
-
|
|
13706
|
+
let formatted = formatIndexTable(entries, options.query, !options.projectId);
|
|
13707
|
+
if (entries.length === 0 && options.projectId) {
|
|
13708
|
+
const allObservations = getAllObservations();
|
|
13709
|
+
const projectHasStoredMemory = allObservations.some((obs) => obs.projectId === options.projectId);
|
|
13710
|
+
if (!projectHasStoredMemory) {
|
|
13711
|
+
formatted = `This project does not have any Memorix memories yet.
|
|
13712
|
+
|
|
13713
|
+
It looks like a fresh project: the tool call worked, but there is nothing stored to retrieve yet.
|
|
13714
|
+
|
|
13715
|
+
Memories will start appearing after observations, session summaries, hook captures, or git-memory are written.`;
|
|
13716
|
+
}
|
|
13717
|
+
}
|
|
13026
13718
|
const totalTokens = countTextTokens(formatted);
|
|
13027
13719
|
return { entries, formatted, totalTokens };
|
|
13028
13720
|
}
|
|
@@ -15460,7 +16152,8 @@ var OBSERVATION_TYPES = [
|
|
|
15460
16152
|
"discovery",
|
|
15461
16153
|
"why-it-exists",
|
|
15462
16154
|
"decision",
|
|
15463
|
-
"trade-off"
|
|
16155
|
+
"trade-off",
|
|
16156
|
+
"probe"
|
|
15464
16157
|
];
|
|
15465
16158
|
function coerceNumberArray(val) {
|
|
15466
16159
|
if (Array.isArray(val)) return val.map(Number);
|
|
@@ -15689,7 +16382,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
15689
16382
|
};
|
|
15690
16383
|
const server = existingServer ?? new McpServer({
|
|
15691
16384
|
name: "memorix",
|
|
15692
|
-
version: true ? "1.0.
|
|
16385
|
+
version: true ? "1.0.10" : "1.0.1"
|
|
15693
16386
|
});
|
|
15694
16387
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
15695
16388
|
server.registerTool = ((name, ...args) => {
|