memorix 1.2.2 → 1.2.4
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 +27 -0
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/TEAM.md +86 -86
- package/dist/cli/index.js +5199 -4726
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +428 -49
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.js +97 -18
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +27 -0
- package/dist/sdk.js +428 -49
- package/dist/sdk.js.map +1 -1
- package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +86 -0
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +13 -1
- package/docs/API_REFERENCE.md +13 -3
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/dev-log/progress.txt +60 -9
- package/package.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/capability-map.ts +1 -1
- package/src/cli/command-guide.ts +4 -1
- package/src/cli/commands/agent-integrations.ts +5 -1
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/codegraph.ts +1 -1
- package/src/cli/commands/context.ts +9 -1
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +54 -54
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +66 -66
- package/src/cli/commands/ingest-log.ts +180 -180
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +82 -82
- package/src/cli/commands/message.ts +104 -104
- package/src/cli/commands/poll.ts +58 -58
- package/src/cli/commands/purge-all-memory.ts +85 -85
- package/src/cli/commands/purge-project-memory.ts +83 -83
- package/src/cli/commands/reasoning.ts +118 -118
- package/src/cli/commands/resume.ts +31 -0
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/session.ts +15 -7
- package/src/cli/commands/skills.ts +114 -114
- package/src/cli/commands/task.ts +167 -167
- package/src/cli/commands/transfer.ts +47 -47
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/Sidebar.tsx +179 -179
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/session-service.ts +3 -2
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/update-checker.ts +211 -211
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/codegraph/auto-context.ts +54 -1
- package/src/codegraph/task-lens.ts +29 -0
- package/src/compact/token-budget.ts +89 -74
- package/src/config/toml-loader.ts +9 -5
- package/src/dashboard/project-classification.ts +64 -64
- package/src/embedding/fastembed-provider.ts +142 -142
- package/src/embedding/transformers-provider.ts +111 -111
- package/src/git/extractor.ts +209 -209
- package/src/git/hooks-path.ts +85 -85
- package/src/hooks/handler.ts +127 -66
- package/src/hooks/installers/index.ts +5 -4
- package/src/hooks/official-skills.ts +6 -4
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +9 -7
- package/src/hooks/significance-filter.ts +250 -250
- package/src/knowledge/context-assembly.ts +4 -1
- package/src/knowledge/workset.ts +89 -1
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +885 -885
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/disclosure-policy.ts +135 -135
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +361 -361
- package/src/memory/formation/index.ts +417 -417
- package/src/memory/formation/resolve.ts +344 -344
- package/src/memory/formation/types.ts +315 -315
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/refs.ts +94 -94
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +158 -9
- package/src/multimodal/image-loader.ts +143 -143
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/spawn-helper.ts +286 -286
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/context-compact.ts +188 -188
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +343 -343
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/orchestrate/worktree.ts +232 -232
- package/src/project/aliases.ts +374 -374
- package/src/project/detector.ts +268 -268
- package/src/rules/adapters/claude-code.ts +99 -99
- package/src/rules/adapters/codex.ts +97 -97
- package/src/rules/adapters/copilot.ts +124 -124
- package/src/rules/adapters/cursor.ts +114 -114
- package/src/rules/adapters/kiro.ts +126 -126
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/adapters/windsurf.ts +83 -83
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +299 -299
- package/src/search/intent-detector.ts +289 -289
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/server.ts +144 -10
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/bun-sqlite-compat.ts +118 -15
- package/src/store/chat-store.ts +119 -119
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/store/sqlite-db.ts +3 -3
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +161 -161
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
- package/src/workspace/workflow-sync.ts +131 -131
package/dist/index.js
CHANGED
|
@@ -35,36 +35,111 @@ var init_esm_shims = __esm({
|
|
|
35
35
|
|
|
36
36
|
// src/store/bun-sqlite-compat.ts
|
|
37
37
|
import { createRequire } from "module";
|
|
38
|
+
function loadNodeSqlite() {
|
|
39
|
+
const nodeSqlite = requireFromHere("node:sqlite");
|
|
40
|
+
return nodeSqlite.DatabaseSync;
|
|
41
|
+
}
|
|
42
|
+
function isNativeBindingFailure(error) {
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
44
|
+
return /could not locate the bindings file|better_sqlite3\.node|module did not self-register/i.test(message);
|
|
45
|
+
}
|
|
46
|
+
function addCompatibility(db2) {
|
|
47
|
+
if (!db2.pragma) {
|
|
48
|
+
db2.pragma = function(pragma, options) {
|
|
49
|
+
const statement = db2.prepare(`PRAGMA ${pragma}`);
|
|
50
|
+
if (options?.simple) {
|
|
51
|
+
const result = statement.get();
|
|
52
|
+
return result ? Object.values(result)[0] : void 0;
|
|
53
|
+
}
|
|
54
|
+
return statement.all();
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (!db2.transaction) {
|
|
58
|
+
let depth = 0;
|
|
59
|
+
let sequence = 0;
|
|
60
|
+
db2.transaction = function(fn) {
|
|
61
|
+
return (...args) => {
|
|
62
|
+
const outermost = depth === 0;
|
|
63
|
+
const savepoint = `memorix_tx_${++sequence}`;
|
|
64
|
+
if (outermost) {
|
|
65
|
+
db2.exec("BEGIN IMMEDIATE");
|
|
66
|
+
} else {
|
|
67
|
+
db2.exec(`SAVEPOINT ${savepoint}`);
|
|
68
|
+
}
|
|
69
|
+
depth += 1;
|
|
70
|
+
try {
|
|
71
|
+
const result = fn(...args);
|
|
72
|
+
if (result && typeof result.then === "function") {
|
|
73
|
+
throw new Error("[memorix] SQLite transactions must be synchronous");
|
|
74
|
+
}
|
|
75
|
+
depth -= 1;
|
|
76
|
+
if (outermost) {
|
|
77
|
+
db2.exec("COMMIT");
|
|
78
|
+
} else {
|
|
79
|
+
db2.exec(`RELEASE SAVEPOINT ${savepoint}`);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
depth -= 1;
|
|
84
|
+
try {
|
|
85
|
+
if (outermost) {
|
|
86
|
+
db2.exec("ROLLBACK");
|
|
87
|
+
} else {
|
|
88
|
+
db2.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
89
|
+
db2.exec(`RELEASE SAVEPOINT ${savepoint}`);
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return db2;
|
|
99
|
+
}
|
|
100
|
+
function instantiateDatabase(Sqlite, filePath, options) {
|
|
101
|
+
return driver === "node:sqlite" && options === void 0 ? new Sqlite(filePath) : new Sqlite(filePath, options);
|
|
102
|
+
}
|
|
38
103
|
function loadSqlite() {
|
|
39
104
|
if (Database) return Database;
|
|
105
|
+
if (process.env.MEMORIX_SQLITE_DRIVER === "node") {
|
|
106
|
+
Database = loadNodeSqlite();
|
|
107
|
+
driver = "node:sqlite";
|
|
108
|
+
return Database;
|
|
109
|
+
}
|
|
40
110
|
try {
|
|
41
111
|
Database = requireFromHere("better-sqlite3");
|
|
112
|
+
driver = "better-sqlite3";
|
|
113
|
+
return Database;
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
Database = loadNodeSqlite();
|
|
118
|
+
driver = "node:sqlite";
|
|
42
119
|
return Database;
|
|
43
120
|
} catch {
|
|
44
121
|
}
|
|
45
122
|
try {
|
|
46
123
|
const bunSqlite = requireFromHere("bun:sqlite");
|
|
47
124
|
Database = bunSqlite.Database;
|
|
125
|
+
driver = "bun:sqlite";
|
|
48
126
|
return Database;
|
|
49
127
|
} catch {
|
|
50
|
-
throw new Error("[memorix]
|
|
128
|
+
throw new Error("[memorix] SQLite is unavailable (better-sqlite3, node:sqlite, and bun:sqlite failed)");
|
|
51
129
|
}
|
|
52
130
|
}
|
|
53
131
|
function createDatabase(path25, options) {
|
|
54
132
|
const Sqlite = loadSqlite();
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return db2.prepare(`PRAGMA ${pragma}`).all();
|
|
63
|
-
};
|
|
133
|
+
try {
|
|
134
|
+
return addCompatibility(instantiateDatabase(Sqlite, path25, options));
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (driver !== "better-sqlite3" || !isNativeBindingFailure(error)) throw error;
|
|
137
|
+
Database = loadNodeSqlite();
|
|
138
|
+
driver = "node:sqlite";
|
|
139
|
+
return addCompatibility(instantiateDatabase(Database, path25, options));
|
|
64
140
|
}
|
|
65
|
-
return db2;
|
|
66
141
|
}
|
|
67
|
-
var Database, requireFromHere;
|
|
142
|
+
var Database, driver, requireFromHere;
|
|
68
143
|
var init_bun_sqlite_compat = __esm({
|
|
69
144
|
"src/store/bun-sqlite-compat.ts"() {
|
|
70
145
|
"use strict";
|
|
@@ -83,7 +158,7 @@ function loadBetterSqlite3() {
|
|
|
83
158
|
BetterSqlite3 = loadSqlite();
|
|
84
159
|
return BetterSqlite3;
|
|
85
160
|
} catch {
|
|
86
|
-
throw new Error("[memorix] SQLite is not available (
|
|
161
|
+
throw new Error("[memorix] SQLite is not available (better-sqlite3, node:sqlite, and bun:sqlite all failed)");
|
|
87
162
|
}
|
|
88
163
|
}
|
|
89
164
|
function hasColumn(db2, table, column) {
|
|
@@ -1886,7 +1961,16 @@ function truncateToTokenBudget(text, budget) {
|
|
|
1886
1961
|
result = result.slice(0, Math.floor(result.length * 0.9));
|
|
1887
1962
|
}
|
|
1888
1963
|
if (result.length < text.length) {
|
|
1889
|
-
|
|
1964
|
+
const nextCharacter = text.charAt(result.length);
|
|
1965
|
+
if (nextCharacter && !/[\s.,;:!?)}\]]/.test(nextCharacter)) {
|
|
1966
|
+
const boundary = result.search(/\s+\S*$/);
|
|
1967
|
+
result = boundary > 0 ? result.slice(0, boundary).trimEnd() : "";
|
|
1968
|
+
}
|
|
1969
|
+
while (result && fitsInBudget(result + "...", budget) === false) {
|
|
1970
|
+
const boundary = result.lastIndexOf(" ");
|
|
1971
|
+
result = boundary > 0 ? result.slice(0, boundary).trimEnd() : "";
|
|
1972
|
+
}
|
|
1973
|
+
result = result ? result + "..." : "...";
|
|
1890
1974
|
}
|
|
1891
1975
|
}
|
|
1892
1976
|
return result;
|
|
@@ -2591,6 +2675,9 @@ function parseTomlValue(raw, filePath, line) {
|
|
|
2591
2675
|
if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
2592
2676
|
return raw.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
2593
2677
|
}
|
|
2678
|
+
if (raw.startsWith("'") && raw.endsWith("'")) {
|
|
2679
|
+
return raw.slice(1, -1);
|
|
2680
|
+
}
|
|
2594
2681
|
if (raw === "true") return true;
|
|
2595
2682
|
if (raw === "false") return false;
|
|
2596
2683
|
if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
|
|
@@ -2603,7 +2690,7 @@ function parseTomlValue(raw, filePath, line) {
|
|
|
2603
2690
|
throw new Error(`Unsupported TOML value in ${filePath}:${line}`);
|
|
2604
2691
|
}
|
|
2605
2692
|
function stripComment(line) {
|
|
2606
|
-
let
|
|
2693
|
+
let quote = null;
|
|
2607
2694
|
let escaped = false;
|
|
2608
2695
|
for (let i = 0; i < line.length; i++) {
|
|
2609
2696
|
const char = line[i];
|
|
@@ -2611,15 +2698,16 @@ function stripComment(line) {
|
|
|
2611
2698
|
escaped = false;
|
|
2612
2699
|
continue;
|
|
2613
2700
|
}
|
|
2614
|
-
if (char === "\\" &&
|
|
2701
|
+
if (char === "\\" && quote === '"') {
|
|
2615
2702
|
escaped = true;
|
|
2616
2703
|
continue;
|
|
2617
2704
|
}
|
|
2618
|
-
if (char === '"') {
|
|
2619
|
-
|
|
2705
|
+
if (char === '"' || char === "'") {
|
|
2706
|
+
if (quote === char) quote = null;
|
|
2707
|
+
else if (quote === null) quote = char;
|
|
2620
2708
|
continue;
|
|
2621
2709
|
}
|
|
2622
|
-
if (char === "#" &&
|
|
2710
|
+
if (char === "#" && quote === null) {
|
|
2623
2711
|
return line.slice(0, i);
|
|
2624
2712
|
}
|
|
2625
2713
|
}
|
|
@@ -13691,6 +13779,7 @@ var init_workflow_store = __esm({
|
|
|
13691
13779
|
var task_lens_exports = {};
|
|
13692
13780
|
__export(task_lens_exports, {
|
|
13693
13781
|
containsTaskKeyword: () => containsTaskKeyword,
|
|
13782
|
+
isContinuationTask: () => isContinuationTask,
|
|
13694
13783
|
lensPathCandidates: () => lensPathCandidates,
|
|
13695
13784
|
lensVerificationHints: () => lensVerificationHints,
|
|
13696
13785
|
rankLensPaths: () => rankLensPaths,
|
|
@@ -13756,6 +13845,12 @@ function resolveTaskLens(task) {
|
|
|
13756
13845
|
}
|
|
13757
13846
|
return best.score > 0 ? LENSES[best.id] : LENSES.general;
|
|
13758
13847
|
}
|
|
13848
|
+
function isContinuationTask(task) {
|
|
13849
|
+
const normalized = (task ?? "").trim().toLowerCase();
|
|
13850
|
+
return normalized.length > 0 && CONTINUATION_KEYWORDS.some(
|
|
13851
|
+
(keyword) => containsTaskKeyword(normalized, keyword)
|
|
13852
|
+
);
|
|
13853
|
+
}
|
|
13759
13854
|
function pathKindScore(path25, lens) {
|
|
13760
13855
|
const normalized = normalizePath2(path25).toLowerCase();
|
|
13761
13856
|
const name = normalized.split("/").pop() ?? normalized;
|
|
@@ -13899,7 +13994,7 @@ function shouldShowLensSource(source, lens, task) {
|
|
|
13899
13994
|
if (lens.id === "onboarding" || lens.id === "release" || lens.id === "docs") return score >= 40;
|
|
13900
13995
|
return score > 0;
|
|
13901
13996
|
}
|
|
13902
|
-
var STOP_WORDS, LENSES, KEYWORDS, LENS_PRIORITY;
|
|
13997
|
+
var STOP_WORDS, LENSES, KEYWORDS, CONTINUATION_KEYWORDS, LENS_PRIORITY;
|
|
13903
13998
|
var init_task_lens = __esm({
|
|
13904
13999
|
"src/codegraph/task-lens.ts"() {
|
|
13905
14000
|
"use strict";
|
|
@@ -14002,6 +14097,7 @@ var init_task_lens = __esm({
|
|
|
14002
14097
|
"fail",
|
|
14003
14098
|
"failing",
|
|
14004
14099
|
"fix",
|
|
14100
|
+
"fixing",
|
|
14005
14101
|
"issue",
|
|
14006
14102
|
"regression",
|
|
14007
14103
|
"repro",
|
|
@@ -14019,6 +14115,18 @@ var init_task_lens = __esm({
|
|
|
14019
14115
|
docs: ["doc", "docs", "readme", "\u6587\u6863", "\u8BF4\u660E"],
|
|
14020
14116
|
test: ["coverage", "fixture", "smoke", "spec", "test", "tests", "testing", "vitest", "\u6D4B\u8BD5"]
|
|
14021
14117
|
};
|
|
14118
|
+
CONTINUATION_KEYWORDS = [
|
|
14119
|
+
"continue",
|
|
14120
|
+
"resume",
|
|
14121
|
+
"pick up",
|
|
14122
|
+
"carry on",
|
|
14123
|
+
"previous session",
|
|
14124
|
+
"\u7EE7\u7EED",
|
|
14125
|
+
"\u63A5\u624B",
|
|
14126
|
+
"\u6062\u590D",
|
|
14127
|
+
"\u5EF6\u7EED",
|
|
14128
|
+
"\u4E0A\u6B21\u4F1A\u8BDD"
|
|
14129
|
+
];
|
|
14022
14130
|
LENS_PRIORITY = [
|
|
14023
14131
|
"bugfix",
|
|
14024
14132
|
"release",
|
|
@@ -15229,6 +15337,7 @@ __export(session_exports, {
|
|
|
15229
15337
|
endSession: () => endSession,
|
|
15230
15338
|
getActiveSession: () => getActiveSession,
|
|
15231
15339
|
getSessionContext: () => getSessionContext,
|
|
15340
|
+
getSessionResumeBrief: () => getSessionResumeBrief,
|
|
15232
15341
|
listSessions: () => listSessions,
|
|
15233
15342
|
scoreObservationForSessionContext: () => scoreObservationForSessionContext,
|
|
15234
15343
|
startSession: () => startSession
|
|
@@ -15296,6 +15405,62 @@ function isSystemSelfObservation(obs) {
|
|
|
15296
15405
|
const text = stringifyObservation(obs, false);
|
|
15297
15406
|
return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text));
|
|
15298
15407
|
}
|
|
15408
|
+
function readerForAlias(reader, aliases, observation) {
|
|
15409
|
+
if (!reader) return void 0;
|
|
15410
|
+
return reader.projectId && aliases.has(observation.projectId) ? { ...reader, projectId: observation.projectId } : reader;
|
|
15411
|
+
}
|
|
15412
|
+
function readableAliasObservations(observations2, aliases, reader) {
|
|
15413
|
+
return reader ? observations2.filter((observation) => canReadObservation(
|
|
15414
|
+
observation,
|
|
15415
|
+
readerForAlias(reader, aliases, observation)
|
|
15416
|
+
)) : observations2;
|
|
15417
|
+
}
|
|
15418
|
+
function isUsefulSessionSummary(summary) {
|
|
15419
|
+
return Boolean(summary) && !NOISE_PATTERNS2.some((pattern) => pattern.test(summary)) && !SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(summary));
|
|
15420
|
+
}
|
|
15421
|
+
function continuationTaskTokens(task) {
|
|
15422
|
+
return [...new Set(
|
|
15423
|
+
(task?.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !["continue", "resume", "\u7EE7\u7EED", "\u63A5\u624B", "\u6062\u590D"].includes(token))
|
|
15424
|
+
)].slice(0, 8);
|
|
15425
|
+
}
|
|
15426
|
+
function continuationScore(observation, projectTokens, task) {
|
|
15427
|
+
let score = scoreObservationForSessionContext(observation, projectTokens);
|
|
15428
|
+
if (observation.type === "session-request" || observation.type === "what-changed") score += 1;
|
|
15429
|
+
const text = stringifyObservation(observation);
|
|
15430
|
+
const matches = continuationTaskTokens(task).filter((token) => text.includes(token)).length;
|
|
15431
|
+
score += Math.min(matches, 2) * 2;
|
|
15432
|
+
return score;
|
|
15433
|
+
}
|
|
15434
|
+
async function getSessionResumeBrief(projectId, task, reader) {
|
|
15435
|
+
const aliasSet = await resolveProjectIds(projectId);
|
|
15436
|
+
const [sessions, allObs] = await Promise.all([
|
|
15437
|
+
loadAliasSessions(aliasSet),
|
|
15438
|
+
loadAliasActiveObservations(aliasSet)
|
|
15439
|
+
]);
|
|
15440
|
+
const readableObs = readableAliasObservations(allObs, aliasSet, reader);
|
|
15441
|
+
const previous = sessions.filter((session) => session.status === "completed").sort((a, b) => new Date(b.endedAt || b.startedAt).getTime() - new Date(a.endedAt || a.startedAt).getTime()).find((session) => session.summary && session.summary !== "(session ended implicitly by new session start)" && isUsefulSessionSummary(session.summary));
|
|
15442
|
+
const projectTokens = tokenizeProjectId(projectId);
|
|
15443
|
+
const memories = readableObs.filter((observation) => RESUME_TYPES.has(observation.type)).filter((observation) => classifyLayer(observation) === "L2").filter((observation) => !isNoiseObservation(observation) && !isSystemSelfObservation(observation)).map((observation) => ({
|
|
15444
|
+
observation,
|
|
15445
|
+
score: continuationScore(observation, projectTokens, task)
|
|
15446
|
+
})).sort((a, b) => b.score - a.score || new Date(b.observation.createdAt).getTime() - new Date(a.observation.createdAt).getTime() || a.observation.id - b.observation.id).slice(0, 3).map(({ observation }) => ({
|
|
15447
|
+
id: observation.id,
|
|
15448
|
+
title: sanitizeCredentials(observation.title),
|
|
15449
|
+
type: observation.type,
|
|
15450
|
+
...observation.facts?.[0] ? { detail: sanitizeCredentials(observation.facts[0]) } : observation.narrative ? { detail: sanitizeCredentials(observation.narrative) } : {}
|
|
15451
|
+
}));
|
|
15452
|
+
return {
|
|
15453
|
+
...previous?.summary ? {
|
|
15454
|
+
previousSession: {
|
|
15455
|
+
id: previous.id,
|
|
15456
|
+
...previous.agent ? { agent: previous.agent } : {},
|
|
15457
|
+
...previous.endedAt ? { endedAt: previous.endedAt } : {},
|
|
15458
|
+
summary: sanitizeCredentials(previous.summary)
|
|
15459
|
+
}
|
|
15460
|
+
} : {},
|
|
15461
|
+
memories
|
|
15462
|
+
};
|
|
15463
|
+
}
|
|
15299
15464
|
function scoreObservationForSessionContext(obs, projectTokens, now3 = Date.now()) {
|
|
15300
15465
|
let score = TYPE_WEIGHTS2[obs.type] ?? 1;
|
|
15301
15466
|
const text = stringifyObservation(obs);
|
|
@@ -15342,7 +15507,7 @@ async function startSession(projectDir2, projectId, opts) {
|
|
|
15342
15507
|
status: "active",
|
|
15343
15508
|
agent: opts?.agent
|
|
15344
15509
|
};
|
|
15345
|
-
const previousContext = await getSessionContext(projectDir2, projectId);
|
|
15510
|
+
const previousContext = await getSessionContext(projectDir2, projectId, 3, opts?.reader);
|
|
15346
15511
|
const sessionStore = getSessionStore();
|
|
15347
15512
|
const aliasSet = await resolveProjectIds(projectId);
|
|
15348
15513
|
await sessionStore.atomicRolloverInsert(session, [...aliasSet], now3);
|
|
@@ -15360,23 +15525,24 @@ async function endSession(projectDir2, sessionId, summary) {
|
|
|
15360
15525
|
await sessionStore.update(session);
|
|
15361
15526
|
return session;
|
|
15362
15527
|
}
|
|
15363
|
-
async function getSessionContext(projectDir2, projectId, limit = 3) {
|
|
15528
|
+
async function getSessionContext(projectDir2, projectId, limit = 3, reader) {
|
|
15364
15529
|
const aliasSet = await resolveProjectIds(projectId);
|
|
15365
15530
|
const [sessions, allObs] = await Promise.all([
|
|
15366
15531
|
loadAliasSessions(aliasSet),
|
|
15367
15532
|
loadAliasActiveObservations(aliasSet)
|
|
15368
15533
|
]);
|
|
15534
|
+
const readableObs = readableAliasObservations(allObs, aliasSet, reader);
|
|
15369
15535
|
const isNoisySummary = (summary) => {
|
|
15370
15536
|
if (!summary) return false;
|
|
15371
15537
|
return NOISE_PATTERNS2.some((p) => p.test(summary)) || SYSTEM_SELF_PATTERNS.some((p) => p.test(summary));
|
|
15372
15538
|
};
|
|
15373
15539
|
const projectSessions = sessions.filter((session) => session.status === "completed").filter((session) => !isNoisySummary(session.summary)).sort((a, b) => new Date(b.endedAt || b.startedAt).getTime() - new Date(a.endedAt || a.startedAt).getTime()).slice(0, limit);
|
|
15374
|
-
if (projectSessions.length === 0 &&
|
|
15540
|
+
if (projectSessions.length === 0 && readableObs.length === 0) {
|
|
15375
15541
|
return "";
|
|
15376
15542
|
}
|
|
15377
15543
|
const lines = [];
|
|
15378
15544
|
const projectTokens = tokenizeProjectId(projectId);
|
|
15379
|
-
const projectObs =
|
|
15545
|
+
const projectObs = readableObs.filter((obs) => !isNoiseObservation(obs) && !isSystemSelfObservation(obs));
|
|
15380
15546
|
const l2Scored = projectObs.filter((obs) => PRIORITY_TYPES.has(obs.type) && classifyLayer(obs) === "L2").map((obs) => ({ obs, score: scoreObservationForSessionContext(obs, projectTokens) })).sort((a, b) => {
|
|
15381
15547
|
if (b.score !== a.score) return b.score - a.score;
|
|
15382
15548
|
return new Date(b.obs.createdAt).getTime() - new Date(a.obs.createdAt).getTime();
|
|
@@ -15402,7 +15568,7 @@ async function getSessionContext(projectDir2, projectId, limit = 3) {
|
|
|
15402
15568
|
const hasL1Content = l1HookObs.length > 0 || l3GitCount > 0;
|
|
15403
15569
|
if (hasL1Content) {
|
|
15404
15570
|
let graphNeighbors = [];
|
|
15405
|
-
if (activeEntities.length > 0) {
|
|
15571
|
+
if (!reader && activeEntities.length > 0) {
|
|
15406
15572
|
try {
|
|
15407
15573
|
const graphMgr = new KnowledgeGraphManager(projectDir2);
|
|
15408
15574
|
await graphMgr.init();
|
|
@@ -15516,7 +15682,7 @@ async function getActiveSession(projectDir2, projectId) {
|
|
|
15516
15682
|
const sessions = await loadAliasActiveSessions(aliasSet);
|
|
15517
15683
|
return sessions.sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime())[0] ?? null;
|
|
15518
15684
|
}
|
|
15519
|
-
var PRIORITY_TYPES, TYPE_EMOJI, TYPE_WEIGHTS2, NOISE_PATTERNS2, COMMAND_TRACE_PATTERNS, SYSTEM_SELF_PATTERNS;
|
|
15685
|
+
var PRIORITY_TYPES, RESUME_TYPES, TYPE_EMOJI, TYPE_WEIGHTS2, NOISE_PATTERNS2, COMMAND_TRACE_PATTERNS, SYSTEM_SELF_PATTERNS;
|
|
15520
15686
|
var init_session = __esm({
|
|
15521
15687
|
"src/memory/session.ts"() {
|
|
15522
15688
|
"use strict";
|
|
@@ -15528,7 +15694,19 @@ var init_session = __esm({
|
|
|
15528
15694
|
init_session_store();
|
|
15529
15695
|
init_graph();
|
|
15530
15696
|
init_secret_filter();
|
|
15697
|
+
init_visibility();
|
|
15531
15698
|
PRIORITY_TYPES = /* @__PURE__ */ new Set(["gotcha", "decision", "problem-solution", "trade-off", "discovery"]);
|
|
15699
|
+
RESUME_TYPES = /* @__PURE__ */ new Set([
|
|
15700
|
+
"gotcha",
|
|
15701
|
+
"decision",
|
|
15702
|
+
"problem-solution",
|
|
15703
|
+
"trade-off",
|
|
15704
|
+
"discovery",
|
|
15705
|
+
"how-it-works",
|
|
15706
|
+
"what-changed",
|
|
15707
|
+
"reasoning",
|
|
15708
|
+
"session-request"
|
|
15709
|
+
]);
|
|
15532
15710
|
TYPE_EMOJI = {
|
|
15533
15711
|
"gotcha": "[DISCOVERY]",
|
|
15534
15712
|
"decision": "[WHY]",
|
|
@@ -15689,6 +15867,7 @@ function freshnessForMemory(status) {
|
|
|
15689
15867
|
return "unknown";
|
|
15690
15868
|
}
|
|
15691
15869
|
function receiptOmissionKind(raw) {
|
|
15870
|
+
if (raw.includes("continuation")) return "continuation";
|
|
15692
15871
|
if (raw.includes("task")) return "task";
|
|
15693
15872
|
if (raw.includes("fact")) return "current-fact";
|
|
15694
15873
|
if (raw.includes("state")) return "code-state";
|
|
@@ -15738,6 +15917,48 @@ function renderTaskWorksetPrompt(input) {
|
|
|
15738
15917
|
trust: "source-backed"
|
|
15739
15918
|
});
|
|
15740
15919
|
appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
|
|
15920
|
+
const hasContinuation = Boolean(
|
|
15921
|
+
input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0
|
|
15922
|
+
);
|
|
15923
|
+
if (hasContinuation && input.continuation) {
|
|
15924
|
+
appendLine(lines, "", maxTokens, omitted, "continuation-heading");
|
|
15925
|
+
appendLine(lines, "Resume from prior work", maxTokens, omitted, "continuation-heading");
|
|
15926
|
+
if (input.continuation.previousSession) {
|
|
15927
|
+
const session = input.continuation.previousSession;
|
|
15928
|
+
const source = [session.agent, session.endedAt ? session.endedAt.slice(0, 10) : void 0].filter(Boolean).join(", ");
|
|
15929
|
+
appendLine(
|
|
15930
|
+
lines,
|
|
15931
|
+
"- Previous session" + (source ? ` (${source})` : "") + ": " + short(session.summary, 44),
|
|
15932
|
+
maxTokens,
|
|
15933
|
+
omitted,
|
|
15934
|
+
"continuation-session",
|
|
15935
|
+
selected,
|
|
15936
|
+
{
|
|
15937
|
+
kind: "continuation",
|
|
15938
|
+
id: "session:" + session.id,
|
|
15939
|
+
reason: "latest meaningful project session summary",
|
|
15940
|
+
trust: "historical"
|
|
15941
|
+
}
|
|
15942
|
+
);
|
|
15943
|
+
}
|
|
15944
|
+
for (const memory of input.continuation.memories.slice(0, 3)) {
|
|
15945
|
+
const detail = memory.detail ? ": " + short(memory.detail, CONTINUATION_DETAIL_TOKEN_BUDGET) : "";
|
|
15946
|
+
appendLine(
|
|
15947
|
+
lines,
|
|
15948
|
+
"- #" + memory.id + " " + memory.type + ": " + short(memory.title, 18) + detail,
|
|
15949
|
+
maxTokens,
|
|
15950
|
+
omitted,
|
|
15951
|
+
"continuation-memory",
|
|
15952
|
+
selected,
|
|
15953
|
+
{
|
|
15954
|
+
kind: "continuation",
|
|
15955
|
+
id: "memory:" + memory.id,
|
|
15956
|
+
reason: "durable prior-work memory",
|
|
15957
|
+
trust: "historical"
|
|
15958
|
+
}
|
|
15959
|
+
);
|
|
15960
|
+
}
|
|
15961
|
+
}
|
|
15741
15962
|
if (input.cautions.length > 0 || input.cautionMemory.length > 0) {
|
|
15742
15963
|
appendLine(lines, "", maxTokens, omitted, "caution-heading");
|
|
15743
15964
|
appendLine(lines, "Cautions", maxTokens, omitted, "caution-heading");
|
|
@@ -16006,11 +16227,25 @@ async function buildTaskWorkset(input) {
|
|
|
16006
16227
|
...input.verificationHints
|
|
16007
16228
|
]).slice(0, 4);
|
|
16008
16229
|
const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
|
|
16230
|
+
const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0) ? {
|
|
16231
|
+
...input.continuation.previousSession ? {
|
|
16232
|
+
previousSession: {
|
|
16233
|
+
...input.continuation.previousSession,
|
|
16234
|
+
summary: short(input.continuation.previousSession.summary, 52)
|
|
16235
|
+
}
|
|
16236
|
+
} : {},
|
|
16237
|
+
memories: input.continuation.memories.slice(0, 3).map((memory) => ({
|
|
16238
|
+
...memory,
|
|
16239
|
+
title: short(memory.title, 20),
|
|
16240
|
+
...memory.detail ? { detail: short(memory.detail, CONTINUATION_DETAIL_TOKEN_BUDGET) } : {}
|
|
16241
|
+
}))
|
|
16242
|
+
} : void 0;
|
|
16009
16243
|
const base = {
|
|
16010
16244
|
version: "1.2",
|
|
16011
16245
|
task,
|
|
16012
16246
|
lens: input.lens,
|
|
16013
16247
|
currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
|
|
16248
|
+
...continuation ? { continuation } : {},
|
|
16014
16249
|
...input.codeState ? { codeState: short(input.codeState, 28) } : {},
|
|
16015
16250
|
startHere: unique(input.startHere).slice(0, 5),
|
|
16016
16251
|
...input.semanticCode ? { semanticCode: input.semanticCode } : {},
|
|
@@ -16035,7 +16270,7 @@ async function buildTaskWorkset(input) {
|
|
|
16035
16270
|
budget: { maxTokens }
|
|
16036
16271
|
});
|
|
16037
16272
|
const receipt = {
|
|
16038
|
-
version: "1.2.
|
|
16273
|
+
version: "1.2.4",
|
|
16039
16274
|
target: input.deliveryTarget ?? "project-context",
|
|
16040
16275
|
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
16041
16276
|
budget: {
|
|
@@ -16057,6 +16292,7 @@ async function buildTaskWorkset(input) {
|
|
|
16057
16292
|
prompt: rendered.prompt
|
|
16058
16293
|
};
|
|
16059
16294
|
}
|
|
16295
|
+
var CONTINUATION_DETAIL_TOKEN_BUDGET;
|
|
16060
16296
|
var init_workset = __esm({
|
|
16061
16297
|
"src/knowledge/workset.ts"() {
|
|
16062
16298
|
"use strict";
|
|
@@ -16069,6 +16305,7 @@ var init_workset = __esm({
|
|
|
16069
16305
|
init_workspace();
|
|
16070
16306
|
init_workflow_store();
|
|
16071
16307
|
init_workflows();
|
|
16308
|
+
CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
|
|
16072
16309
|
}
|
|
16073
16310
|
});
|
|
16074
16311
|
|
|
@@ -16861,6 +17098,7 @@ async function buildAutoProjectContext(input) {
|
|
|
16861
17098
|
const now3 = input.now ?? /* @__PURE__ */ new Date();
|
|
16862
17099
|
const task = input.task?.trim();
|
|
16863
17100
|
const lens = resolveTaskLens(task);
|
|
17101
|
+
const continuationRequested = input.continuation === "always" || input.continuation !== "never" && isContinuationTask(task);
|
|
16864
17102
|
const codegraphConfig = getResolvedConfig({ projectRoot: input.project.rootPath }).codegraph;
|
|
16865
17103
|
const exclude = input.exclude ?? codegraphConfig.excludePatterns;
|
|
16866
17104
|
const maxFileBytes = input.maxFileBytes ?? codegraphConfig.maxFileBytes;
|
|
@@ -16997,6 +17235,11 @@ async function buildAutoProjectContext(input) {
|
|
|
16997
17235
|
if (externalCaution) {
|
|
16998
17236
|
runtimeCautions.push({ kind: "external-codegraph-fallback", message: externalCaution });
|
|
16999
17237
|
}
|
|
17238
|
+
let continuation;
|
|
17239
|
+
if (continuationRequested) {
|
|
17240
|
+
await initSessionStore(input.dataDir);
|
|
17241
|
+
continuation = await getSessionResumeBrief(input.project.id, task, input.reader);
|
|
17242
|
+
}
|
|
17000
17243
|
const workset = await buildTaskWorkset({
|
|
17001
17244
|
projectId: input.project.id,
|
|
17002
17245
|
dataDir: input.dataDir,
|
|
@@ -17006,6 +17249,7 @@ async function buildAutoProjectContext(input) {
|
|
|
17006
17249
|
...externalOutline ? { semanticCode: externalOutline } : {},
|
|
17007
17250
|
providerQuality: providerQuality2,
|
|
17008
17251
|
currentFacts: worksetFactLines(currentFacts),
|
|
17252
|
+
...continuation ? { continuation } : {},
|
|
17009
17253
|
codeState: codeStateLine(overview),
|
|
17010
17254
|
reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
|
|
17011
17255
|
id: source.observationId,
|
|
@@ -17050,12 +17294,19 @@ async function buildAutoProjectContext(input) {
|
|
|
17050
17294
|
explain,
|
|
17051
17295
|
refresh,
|
|
17052
17296
|
providerQuality: providerQuality2,
|
|
17297
|
+
...continuationRequested && workset.continuation ? { continuation: workset.continuation } : {},
|
|
17053
17298
|
workset
|
|
17054
17299
|
};
|
|
17055
17300
|
}
|
|
17056
17301
|
function formatLanguages(overview) {
|
|
17057
17302
|
return overview.code.languages.length > 0 ? overview.code.languages.map((item) => `${item.language} ${item.files}`).join(", ") : "none indexed yet";
|
|
17058
17303
|
}
|
|
17304
|
+
function compactContinuationText(text, budget) {
|
|
17305
|
+
return truncateToTokenBudget(
|
|
17306
|
+
sanitizeCredentials(text).replace(/\s+/g, " ").trim(),
|
|
17307
|
+
budget
|
|
17308
|
+
);
|
|
17309
|
+
}
|
|
17059
17310
|
function codeStateLine(overview) {
|
|
17060
17311
|
const snapshot = overview.code.latestSnapshot;
|
|
17061
17312
|
if (!snapshot) return "- Code state: no completed snapshot yet";
|
|
@@ -17195,6 +17446,23 @@ function formatAutoProjectContextSummary(context) {
|
|
|
17195
17446
|
"Reliable memory",
|
|
17196
17447
|
reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
|
|
17197
17448
|
);
|
|
17449
|
+
const continuation = context.workset.continuation;
|
|
17450
|
+
if (continuation?.previousSession || continuation?.memories.length) {
|
|
17451
|
+
lines.push("", "Resume from prior work");
|
|
17452
|
+
if (continuation.previousSession) {
|
|
17453
|
+
const session = continuation.previousSession;
|
|
17454
|
+
const source = [session.agent, session.endedAt ? session.endedAt.slice(0, 10) : void 0].filter(Boolean).join(", ");
|
|
17455
|
+
lines.push(
|
|
17456
|
+
"- Previous session" + (source ? ` (${source})` : "") + ": " + compactContinuationText(session.summary, 44)
|
|
17457
|
+
);
|
|
17458
|
+
}
|
|
17459
|
+
for (const memory of continuation.memories.slice(0, 3)) {
|
|
17460
|
+
const detail = memory.detail ? ": " + compactContinuationText(memory.detail, 20) : "";
|
|
17461
|
+
lines.push(
|
|
17462
|
+
"- #" + memory.id + " " + memory.type + ": " + compactContinuationText(memory.title, 18) + detail
|
|
17463
|
+
);
|
|
17464
|
+
}
|
|
17465
|
+
}
|
|
17198
17466
|
return lines.join("\n");
|
|
17199
17467
|
}
|
|
17200
17468
|
function formatAutoProjectContextPrompt(context) {
|
|
@@ -17265,8 +17533,10 @@ var init_auto_context = __esm({
|
|
|
17265
17533
|
"src/codegraph/auto-context.ts"() {
|
|
17266
17534
|
"use strict";
|
|
17267
17535
|
init_esm_shims();
|
|
17536
|
+
init_token_budget();
|
|
17268
17537
|
init_resolved_config();
|
|
17269
17538
|
init_workset();
|
|
17539
|
+
init_secret_filter();
|
|
17270
17540
|
init_binder();
|
|
17271
17541
|
init_current_facts();
|
|
17272
17542
|
init_lite_provider();
|
|
@@ -17274,6 +17544,8 @@ var init_auto_context = __esm({
|
|
|
17274
17544
|
init_project_context();
|
|
17275
17545
|
init_store();
|
|
17276
17546
|
init_admission();
|
|
17547
|
+
init_session();
|
|
17548
|
+
init_session_store();
|
|
17277
17549
|
init_task_lens();
|
|
17278
17550
|
DEFAULT_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
17279
17551
|
}
|
|
@@ -21468,7 +21740,8 @@ var init_official_skills = __esm({
|
|
|
21468
21740
|
"",
|
|
21469
21741
|
"| Situation | Prefer | CLI fallback |",
|
|
21470
21742
|
"|---|---|---|",
|
|
21471
|
-
'| Starting
|
|
21743
|
+
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --json` |',
|
|
21744
|
+
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --json` |',
|
|
21472
21745
|
'| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
|
|
21473
21746
|
'| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
|
|
21474
21747
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
@@ -21481,9 +21754,10 @@ var init_official_skills = __esm({
|
|
|
21481
21754
|
"",
|
|
21482
21755
|
"- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user's actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.",
|
|
21483
21756
|
"- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client's tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.",
|
|
21484
|
-
'-
|
|
21485
|
-
"-
|
|
21486
|
-
"-
|
|
21757
|
+
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --json` instead. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
21758
|
+
"- After a successful `memorix_project_context`, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use Context Pack, search, or detail only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
21759
|
+
"- If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
21760
|
+
"- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer. Fetch detail only for a result you still need after the brief.",
|
|
21487
21761
|
"- Treat current code-bound memory as a map. Treat stale, suspect, or unbound memory as a lead that must be verified against the current code.",
|
|
21488
21762
|
"- Skip memory lookup for greetings, tiny one-off edits, or questions fully answered by the current file.",
|
|
21489
21763
|
"- If a fresh project has no memories, proceed normally and do not repeat the same empty search in the same turn.",
|
|
@@ -22704,17 +22978,18 @@ alwaysApply: true
|
|
|
22704
22978
|
"",
|
|
22705
22979
|
"## Start with Memory Autopilot",
|
|
22706
22980
|
"",
|
|
22707
|
-
`Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
22981
|
+
`Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). When the task is continuing prior work, the same brief also includes a bounded prior-work projection. Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
22708
22982
|
"",
|
|
22709
|
-
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first.
|
|
22983
|
+
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --json`. For a new task, use `memorix context "<task>" --json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
22710
22984
|
"",
|
|
22711
|
-
"Use `memorix_context_pack` when
|
|
22985
|
+
"After a successful `memorix_project_context` result, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use `memorix_context_pack`, `memorix_search`, or `memorix_detail` only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
22986
|
+
"If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
22712
22987
|
"",
|
|
22713
22988
|
"## When to search memory",
|
|
22714
22989
|
"",
|
|
22715
22990
|
"Use `memorix_graph_context` for explicit memory graph questions or broad graph overview after the autopilot brief is not enough.",
|
|
22716
22991
|
"",
|
|
22717
|
-
`Use \`memorix_search\` when prior ${contextNoun} context would help \u2014 for example:`,
|
|
22992
|
+
`Use \`memorix_search\` when prior ${contextNoun} context would help and the Autopilot brief did not already answer the question \u2014 for example:`,
|
|
22718
22993
|
"- The user asks about a past decision, bug, or change",
|
|
22719
22994
|
"- You need to understand why something was designed a certain way",
|
|
22720
22995
|
"- You're continuing work that started in a previous session",
|
|
@@ -26729,6 +27004,8 @@ var BOOTSTRAP_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
26729
27004
|
"memorix_graph_context",
|
|
26730
27005
|
"memorix_context_pack"
|
|
26731
27006
|
]);
|
|
27007
|
+
var AUTOPILOT_RETRIEVAL_BOUNDARY_TTL_MS = 2 * 60 * 1e3;
|
|
27008
|
+
var READ_ONLY_TASK_PATTERN = /\b(?:do not|don't|never)\s+(?:modify|edit|change|write)\b|\bread[- ]only\b|(?:不要|不准|勿|禁止).{0,6}(?:修改|编辑|写入)|只读/i;
|
|
26732
27009
|
function shouldAwaitProjectRuntime(toolName) {
|
|
26733
27010
|
return !BOOTSTRAP_SAFE_TOOL_NAMES.has(toolName);
|
|
26734
27011
|
}
|
|
@@ -26999,7 +27276,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
26999
27276
|
};
|
|
27000
27277
|
const server = existingServer ?? new McpServer({
|
|
27001
27278
|
name: "memorix",
|
|
27002
|
-
version: true ? "1.2.
|
|
27279
|
+
version: true ? "1.2.4" : "1.0.1"
|
|
27003
27280
|
});
|
|
27004
27281
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
27005
27282
|
server.registerTool = ((name, ...args) => {
|
|
@@ -27034,11 +27311,52 @@ The path should point to a directory containing a .git folder.`
|
|
|
27034
27311
|
isTeamMember
|
|
27035
27312
|
};
|
|
27036
27313
|
};
|
|
27314
|
+
let autopilotRetrievalBoundary = null;
|
|
27315
|
+
const getActiveAutopilotRetrievalBoundary = () => {
|
|
27316
|
+
const boundary = autopilotRetrievalBoundary;
|
|
27317
|
+
if (!boundary) return null;
|
|
27318
|
+
if (boundary.projectId === project.id && Date.now() - boundary.issuedAt <= AUTOPILOT_RETRIEVAL_BOUNDARY_TTL_MS) {
|
|
27319
|
+
return boundary;
|
|
27320
|
+
}
|
|
27321
|
+
autopilotRetrievalBoundary = null;
|
|
27322
|
+
return null;
|
|
27323
|
+
};
|
|
27324
|
+
const requireExplicitAutopilotExpansion = (toolName, purpose) => {
|
|
27325
|
+
if (!getActiveAutopilotRetrievalBoundary() || purpose?.trim()) return null;
|
|
27326
|
+
return {
|
|
27327
|
+
content: [{
|
|
27328
|
+
type: "text",
|
|
27329
|
+
text: "Memorix Autopilot retrieval boundary: the latest `memorix_project_context` already supplied the default bounded brief for this coding turn, so no additional memory was retrieved. Verify the current project first. To intentionally expand beyond that brief, call `" + toolName + "` again with `purpose` naming the specific missing fact or the user's explicit request."
|
|
27330
|
+
}]
|
|
27331
|
+
};
|
|
27332
|
+
};
|
|
27333
|
+
const blockCoveredAutopilotEvidence = (toolName, observationIds, force) => {
|
|
27334
|
+
const boundary = getActiveAutopilotRetrievalBoundary();
|
|
27335
|
+
if (!boundary || force || observationIds.length === 0 || !observationIds.every((id) => boundary.coveredObservationIds.has(id))) {
|
|
27336
|
+
return null;
|
|
27337
|
+
}
|
|
27338
|
+
return {
|
|
27339
|
+
content: [{
|
|
27340
|
+
type: "text",
|
|
27341
|
+
text: "Memorix Autopilot retrieval boundary: every requested memory is already represented in the latest project brief, so no duplicate detail was retrieved. Inspect the current project or seek a new source. Retry with `force: true` only when the user explicitly asks to read the underlying record in full."
|
|
27342
|
+
}]
|
|
27343
|
+
};
|
|
27344
|
+
};
|
|
27345
|
+
const blockReadOnlyAutopilotWrite = (overrideReadOnly) => {
|
|
27346
|
+
const boundary = getActiveAutopilotRetrievalBoundary();
|
|
27347
|
+
if (!boundary?.readOnly || overrideReadOnly) return null;
|
|
27348
|
+
return {
|
|
27349
|
+
content: [{
|
|
27350
|
+
type: "text",
|
|
27351
|
+
text: "Memorix write boundary: the latest task is read-only or asks not to modify files, so no memory was stored. Persist a record only when the user explicitly asks to save it, then retry with `overrideReadOnly: true`."
|
|
27352
|
+
}]
|
|
27353
|
+
};
|
|
27354
|
+
};
|
|
27037
27355
|
server.registerTool(
|
|
27038
27356
|
"memorix_store",
|
|
27039
27357
|
{
|
|
27040
27358
|
title: "Store Memory",
|
|
27041
|
-
description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity.",
|
|
27359
|
+
description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity. For a read-only task, do not store unless the user explicitly asks to save a record.",
|
|
27042
27360
|
inputSchema: {
|
|
27043
27361
|
entityName: z2.string().describe('The entity this observation belongs to (e.g., "auth-module", "port-config")'),
|
|
27044
27362
|
type: z2.enum(OBSERVATION_TYPES).describe("Observation type for classification"),
|
|
@@ -27059,12 +27377,17 @@ The path should point to a directory containing a .git folder.`
|
|
|
27059
27377
|
relatedEntities: z2.array(z2.string()).optional().describe("Other entity names this memory cross-references"),
|
|
27060
27378
|
visibility: z2.enum(["personal", "project", "team"]).optional().describe(
|
|
27061
27379
|
"Retrieval scope. Project is the normal shared default; personal/team require memorix_session_start with joinTeam=true."
|
|
27380
|
+
),
|
|
27381
|
+
overrideReadOnly: z2.boolean().optional().describe(
|
|
27382
|
+
"Use only when the user explicitly asks to save memory during a read-only or no-modification task."
|
|
27062
27383
|
)
|
|
27063
27384
|
}
|
|
27064
27385
|
},
|
|
27065
|
-
async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities, visibility }) => {
|
|
27386
|
+
async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities, visibility, overrideReadOnly }) => {
|
|
27066
27387
|
const unresolved = requireResolvedProject("store memory in the current project");
|
|
27067
27388
|
if (unresolved) return unresolved;
|
|
27389
|
+
const readOnlyBoundary = blockReadOnlyAutopilotWrite(overrideReadOnly);
|
|
27390
|
+
if (readOnlyBoundary) return readOnlyBoundary;
|
|
27068
27391
|
const requestedVisibility = visibility ?? "project";
|
|
27069
27392
|
const reader = getObservationReader();
|
|
27070
27393
|
if (requestedVisibility !== "project" && !currentAgentId) {
|
|
@@ -27563,7 +27886,7 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
27563
27886
|
"memorix_search",
|
|
27564
27887
|
{
|
|
27565
27888
|
title: "Search Memory",
|
|
27566
|
-
description: "Search project memory. Returns a compact index (~50-100 tokens/result). Use memorix_detail to fetch full content for specific IDs. Use memorix_timeline to see chronological context. Searches across all observations stored from any IDE session \u2014 enabling cross-session and cross-agent context retrieval.",
|
|
27889
|
+
description: "Search project memory. Returns a compact index (~50-100 tokens/result). Do not use as a follow-up to a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Use memorix_detail to fetch full content for specific IDs. Use memorix_timeline to see chronological context. Searches across all observations stored from any IDE session \u2014 enabling cross-session and cross-agent context retrieval.",
|
|
27567
27890
|
inputSchema: {
|
|
27568
27891
|
query: z2.string().describe("Search query (natural language or keywords)"),
|
|
27569
27892
|
limit: z2.number().optional().describe("Max results (default: 20)"),
|
|
@@ -27579,14 +27902,24 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
27579
27902
|
),
|
|
27580
27903
|
source: z2.enum(["agent", "git", "manual"]).optional().describe(
|
|
27581
27904
|
'Filter by memory source. "git" returns only commit-derived ground truth memories. Omit for all sources.'
|
|
27905
|
+
),
|
|
27906
|
+
purpose: z2.string().optional().describe(
|
|
27907
|
+
"Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
|
|
27908
|
+
),
|
|
27909
|
+
force: z2.boolean().optional().describe(
|
|
27910
|
+
"Use only when the user explicitly asks to read a record already represented in the latest Autopilot brief."
|
|
27582
27911
|
)
|
|
27583
27912
|
}
|
|
27584
27913
|
},
|
|
27585
|
-
async ({ query, limit, type, maxTokens, scope, since, until, status, source }) => {
|
|
27914
|
+
async ({ query, limit, type, maxTokens, scope, since, until, status, source, purpose, force }) => {
|
|
27586
27915
|
if (scope !== "global") {
|
|
27587
27916
|
const unresolved = requireResolvedProject("search the current project");
|
|
27588
27917
|
if (unresolved) return unresolved;
|
|
27589
27918
|
}
|
|
27919
|
+
if (scope !== "global") {
|
|
27920
|
+
const boundary = requireExplicitAutopilotExpansion("memorix_search", purpose);
|
|
27921
|
+
if (boundary) return boundary;
|
|
27922
|
+
}
|
|
27590
27923
|
return withFreshIndex(async () => {
|
|
27591
27924
|
const safeLimit = limit != null ? coerceNumber(limit, 20) : void 0;
|
|
27592
27925
|
const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : void 0;
|
|
@@ -27625,6 +27958,11 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
27625
27958
|
}
|
|
27626
27959
|
throw error;
|
|
27627
27960
|
}
|
|
27961
|
+
const activeBoundary = getActiveAutopilotRetrievalBoundary();
|
|
27962
|
+
if (scope !== "global" && activeBoundary && !force && result.entries.length > 0 && result.entries.every((entry) => activeBoundary.coveredObservationIds.has(entry.id))) {
|
|
27963
|
+
const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
|
|
27964
|
+
if (duplicate) return duplicate;
|
|
27965
|
+
}
|
|
27628
27966
|
let text = result.formatted;
|
|
27629
27967
|
try {
|
|
27630
27968
|
const { getLastSearchMode: getLastSearchMode2 } = await Promise.resolve().then(() => (init_orama_store(), orama_store_exports));
|
|
@@ -27726,6 +28064,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
27726
28064
|
observations: observations2,
|
|
27727
28065
|
task,
|
|
27728
28066
|
refresh: refresh ?? "auto",
|
|
28067
|
+
reader: getObservationReader(),
|
|
27729
28068
|
enqueueRefresh: () => {
|
|
27730
28069
|
enqueueCodegraphRefresh2({
|
|
27731
28070
|
dataDir: projectDir2,
|
|
@@ -27737,6 +28076,16 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
27737
28076
|
}
|
|
27738
28077
|
});
|
|
27739
28078
|
const text = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
|
|
28079
|
+
autopilotRetrievalBoundary = {
|
|
28080
|
+
projectId: project.id,
|
|
28081
|
+
issuedAt: Date.now(),
|
|
28082
|
+
coveredObservationIds: /* @__PURE__ */ new Set([
|
|
28083
|
+
...context.workset.continuation?.memories.map((memory) => memory.id) ?? [],
|
|
28084
|
+
...context.workset.reliableMemory.map((memory) => memory.id),
|
|
28085
|
+
...context.workset.cautionMemory.map((memory) => memory.id)
|
|
28086
|
+
]),
|
|
28087
|
+
readOnly: READ_ONLY_TASK_PATTERN.test(task ?? "")
|
|
28088
|
+
};
|
|
27740
28089
|
return {
|
|
27741
28090
|
content: [{ type: "text", text }]
|
|
27742
28091
|
};
|
|
@@ -27776,18 +28125,23 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
27776
28125
|
"memorix_context_pack",
|
|
27777
28126
|
{
|
|
27778
28127
|
title: "Context Pack",
|
|
27779
|
-
description: "Build a prompt-ready working context pack for a coding task. Combines relevant memories, CodeGraph Memory facts, freshness warnings, suggested reads, and verification hints.",
|
|
28128
|
+
description: "Build a prompt-ready working context pack for a coding task. Combines relevant memories, CodeGraph Memory facts, freshness warnings, suggested reads, and verification hints. After a complete memorix_project_context brief, provide purpose only when deliberately expanding beyond it.",
|
|
27780
28129
|
inputSchema: {
|
|
27781
28130
|
task: z2.string().describe("Current coding task or question"),
|
|
27782
28131
|
limit: z2.preprocess(
|
|
27783
28132
|
(value) => typeof value === "string" && value.trim() !== "" ? Number(value) : value,
|
|
27784
28133
|
z2.number().int().positive().max(100)
|
|
27785
|
-
).optional().describe("Max active memories to inspect before code-ref filtering (default: 20)")
|
|
28134
|
+
).optional().describe("Max active memories to inspect before code-ref filtering (default: 20)"),
|
|
28135
|
+
purpose: z2.string().optional().describe(
|
|
28136
|
+
"Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
|
|
28137
|
+
)
|
|
27786
28138
|
}
|
|
27787
28139
|
},
|
|
27788
|
-
async ({ task, limit }) => {
|
|
28140
|
+
async ({ task, limit, purpose }) => {
|
|
27789
28141
|
const unresolved = requireResolvedProject("build a context pack for the current project");
|
|
27790
28142
|
if (unresolved) return unresolved;
|
|
28143
|
+
const boundary = requireExplicitAutopilotExpansion("memorix_context_pack", purpose);
|
|
28144
|
+
if (boundary) return boundary;
|
|
27791
28145
|
const [
|
|
27792
28146
|
{ CodeGraphStore: CodeGraphStore2 },
|
|
27793
28147
|
{ assembleContextPackForTask: assembleContextPackForTask2, attachTaskWorkset: attachTaskWorkset2, buildContextPackPrompt: buildContextPackPrompt2 },
|
|
@@ -28532,7 +28886,7 @@ ${actions.join("\n")}`
|
|
|
28532
28886
|
"memorix_detail",
|
|
28533
28887
|
{
|
|
28534
28888
|
title: "Memory Details",
|
|
28535
|
-
description: 'Fetch full observation or mini-skill details \u2014 includes source kind (explicit memory / hook trace / git evidence), value category, and cross-references (~500-1000 tokens each). Always use memorix_search first to find relevant IDs, then fetch only what you need. Accepts typed refs from search results (e.g. "obs:42", "skill:3") via the typedRefs field, or legacy numeric ids / object refs for backward compatibility.',
|
|
28889
|
+
description: 'Fetch full observation or mini-skill details \u2014 includes source kind (explicit memory / hook trace / git evidence), value category, and cross-references (~500-1000 tokens each). Do not re-fetch content already covered by a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Always use memorix_search first to find relevant IDs, then fetch only what you need. Accepts typed refs from search results (e.g. "obs:42", "skill:3") via the typedRefs field, or legacy numeric ids / object refs for backward compatibility.',
|
|
28536
28890
|
inputSchema: {
|
|
28537
28891
|
ids: z2.array(z2.number()).optional().describe("Observation IDs to fetch (legacy, from memorix_search results)"),
|
|
28538
28892
|
refs: z2.array(
|
|
@@ -28541,16 +28895,36 @@ ${actions.join("\n")}`
|
|
|
28541
28895
|
projectId: z2.string().optional().describe("Project ID for global-search disambiguation")
|
|
28542
28896
|
})
|
|
28543
28897
|
).optional().describe("Explicit observation refs. Prefer this for global search results."),
|
|
28544
|
-
typedRefs: z2.array(z2.string()).optional().describe('Typed memory refs from search results, e.g. "obs:42", "skill:3", "obs:42@org/proj"')
|
|
28898
|
+
typedRefs: z2.array(z2.string()).optional().describe('Typed memory refs from search results, e.g. "obs:42", "skill:3", "obs:42@org/proj"'),
|
|
28899
|
+
purpose: z2.string().optional().describe(
|
|
28900
|
+
"Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
|
|
28901
|
+
),
|
|
28902
|
+
force: z2.boolean().optional().describe(
|
|
28903
|
+
"Use only when the user explicitly asks to read a record already represented in the latest Autopilot brief."
|
|
28904
|
+
)
|
|
28545
28905
|
}
|
|
28546
28906
|
},
|
|
28547
|
-
async ({ ids, refs, typedRefs }) => {
|
|
28907
|
+
async ({ ids, refs, typedRefs, purpose, force }) => {
|
|
28548
28908
|
const safeIds = coerceNumberArray(ids);
|
|
28549
28909
|
const safeRefs = coerceObservationRefs(refs);
|
|
28550
28910
|
const safeTypedRefs = coerceStringArray(typedRefs);
|
|
28911
|
+
const hasCrossProjectRef = safeRefs.some((ref) => ref.projectId && ref.projectId !== project.id) || safeTypedRefs.some((ref) => ref.includes("@") && !ref.endsWith(`@${project.id}`));
|
|
28912
|
+
if (!hasCrossProjectRef) {
|
|
28913
|
+
const boundary = requireExplicitAutopilotExpansion("memorix_detail", purpose);
|
|
28914
|
+
if (boundary) return boundary;
|
|
28915
|
+
const requestedObservationIds = [
|
|
28916
|
+
...safeIds,
|
|
28917
|
+
...safeRefs.map((ref) => ref.id),
|
|
28918
|
+
...safeTypedRefs.flatMap((ref) => {
|
|
28919
|
+
const match = /^obs:(\d+)(?:@.+)?$/i.exec(ref.trim());
|
|
28920
|
+
return match ? [Number(match[1])] : [];
|
|
28921
|
+
})
|
|
28922
|
+
];
|
|
28923
|
+
const duplicate = blockCoveredAutopilotEvidence("memorix_detail", requestedObservationIds, force);
|
|
28924
|
+
if (duplicate) return duplicate;
|
|
28925
|
+
}
|
|
28551
28926
|
let result;
|
|
28552
28927
|
try {
|
|
28553
|
-
const hasCrossProjectRef = safeRefs.some((ref) => ref.projectId && ref.projectId !== project.id) || safeTypedRefs.some((ref) => ref.includes("@") && !ref.endsWith(`@${project.id}`));
|
|
28554
28928
|
const reader = getObservationReader(hasCrossProjectRef ? "global" : "project");
|
|
28555
28929
|
if (safeTypedRefs.length > 0) {
|
|
28556
28930
|
result = await compactDetail(safeTypedRefs, { reader });
|
|
@@ -29500,7 +29874,6 @@ Ensure the path points to a directory containing a .git folder (or a subdirector
|
|
|
29500
29874
|
const unresolved = requireResolvedProject("start a project session");
|
|
29501
29875
|
if (unresolved) return unresolved;
|
|
29502
29876
|
const { startSession: startSession2 } = await Promise.resolve().then(() => (init_session(), session_exports));
|
|
29503
|
-
const result = await startSession2(projectDir2, project.id, { sessionId, agent });
|
|
29504
29877
|
const llmStatus = isLLMEnabled() ? `LLM enhanced mode: ${getLLMConfig()?.provider}/${getLLMConfig()?.model} (fact extraction + auto-dedup active)` : "LLM mode: off (set MEMORIX_LLM_API_KEY to enable enhanced memory quality)";
|
|
29505
29878
|
const shouldJoinTeam = !!joinTeam;
|
|
29506
29879
|
let registeredAgent = null;
|
|
@@ -29557,6 +29930,11 @@ Ensure the path points to a directory containing a .git folder (or a subdirector
|
|
|
29557
29930
|
}
|
|
29558
29931
|
} catch {
|
|
29559
29932
|
}
|
|
29933
|
+
const result = await startSession2(projectDir2, project.id, {
|
|
29934
|
+
sessionId,
|
|
29935
|
+
agent,
|
|
29936
|
+
reader: getObservationReader()
|
|
29937
|
+
});
|
|
29560
29938
|
const lines = [
|
|
29561
29939
|
`[OK] Session started: ${result.session.id}`,
|
|
29562
29940
|
`Project: ${project.name} (${project.id})`,
|
|
@@ -29679,7 +30057,7 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
|
|
|
29679
30057
|
async ({ limit }) => {
|
|
29680
30058
|
const safeLimit = limit != null ? coerceNumber(limit, 3) : 3;
|
|
29681
30059
|
const { getSessionContext: getSessionContext2, listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session(), session_exports));
|
|
29682
|
-
const context = await getSessionContext2(projectDir2, project.id, safeLimit);
|
|
30060
|
+
const context = await getSessionContext2(projectDir2, project.id, safeLimit, getObservationReader());
|
|
29683
30061
|
const sessions = await listSessions2(projectDir2, project.id);
|
|
29684
30062
|
const activeSessions = sessions.filter((s) => s.status === "active");
|
|
29685
30063
|
const completedSessions = sessions.filter((s) => s.status === "completed");
|
|
@@ -30572,6 +30950,7 @@ fi
|
|
|
30572
30950
|
if (newCanonicalId === project.id && projectResolved) return false;
|
|
30573
30951
|
console.error(`[memorix] Switching project: ${project.id} \u2192 ${newCanonicalId}`);
|
|
30574
30952
|
currentAgentId = void 0;
|
|
30953
|
+
autopilotRetrievalBoundary = null;
|
|
30575
30954
|
const canonicalProjectDir = newCanonicalId !== newDetected.id ? await getProjectDataDir(newCanonicalId) : newProjectDir;
|
|
30576
30955
|
projectResolved = true;
|
|
30577
30956
|
projectResolutionError = null;
|